123399Smckusick /* 237736Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337736Smckusick * All rights reserved. 423399Smckusick * 537736Smckusick * Redistribution and use in source and binary forms are permitted 637736Smckusick * provided that the above copyright notice and this paragraph are 737736Smckusick * duplicated in all such forms and that any documentation, 837736Smckusick * advertising materials, and other materials related to such 937736Smckusick * distribution and use acknowledge that the software was developed 1037736Smckusick * by the University of California, Berkeley. The name of the 1137736Smckusick * University may not be used to endorse or promote products derived 1237736Smckusick * from this software without specific prior written permission. 1337736Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437736Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537736Smckusick * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637736Smckusick * 17*41313Smckusick * @(#)lfs_inode.c 7.30 (Berkeley) 05/02/90 1823399Smckusick */ 1924Sbill 2017099Sbloom #include "param.h" 2117099Sbloom #include "systm.h" 2217099Sbloom #include "mount.h" 2317099Sbloom #include "user.h" 2439795Smckusick #include "proc.h" 2537736Smckusick #include "file.h" 2617099Sbloom #include "buf.h" 2724525Sbloom #include "cmap.h" 2837736Smckusick #include "vnode.h" 29*41313Smckusick #include "../ufs/quota.h" 3037736Smckusick #include "../ufs/inode.h" 3137736Smckusick #include "../ufs/fs.h" 3237736Smckusick #include "../ufs/ufsmount.h" 3317099Sbloom #include "kernel.h" 3431661Smckusick #include "malloc.h" 3524Sbill 3616840Smckusick #define INOHSZ 512 377334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 387334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 397334Skre #else 4010852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 417334Skre #endif 4224Sbill 4339392Smckusick union ihead { 447334Skre union ihead *ih_head[2]; 457334Skre struct inode *ih_chain[2]; 467334Skre } ihead[INOHSZ]; 477334Skre 4839574Smckusick int prtactive; /* 1 => print out reclaim of active vnodes */ 4939574Smckusick 5024Sbill /* 5139392Smckusick * Initialize hash links for inodes. 5224Sbill */ 5339440Smckusick ufs_init() 5424Sbill { 5524Sbill register int i; 5639392Smckusick register union ihead *ih = ihead; 5724Sbill 5839492Smckusick #ifndef lint 5939392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 6039392Smckusick panic("ihinit: too small"); 6139492Smckusick #endif /* not lint */ 627334Skre for (i = INOHSZ; --i >= 0; ih++) { 637334Skre ih->ih_head[0] = ih; 647334Skre ih->ih_head[1] = ih; 657334Skre } 66*41313Smckusick #ifdef QUOTA 67*41313Smckusick dqinit(); 68*41313Smckusick #endif /* QUOTA */ 6924Sbill } 7024Sbill 7124Sbill /* 7237736Smckusick * Look up an vnode/inode by device,inumber. 7324Sbill * If it is in core (in the inode structure), 7424Sbill * honor the locking protocol. 7524Sbill * If it is not in core, read it in from the 7624Sbill * specified device. 7737736Smckusick * Callers must check for mount points!! 7824Sbill * In all cases, a pointer to a locked 7924Sbill * inode structure is returned. 8024Sbill */ 8137736Smckusick iget(xp, ino, ipp) 8237736Smckusick struct inode *xp; 834818Swnj ino_t ino; 8437736Smckusick struct inode **ipp; 8524Sbill { 8637736Smckusick dev_t dev = xp->i_dev; 8737736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 8837736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 8939440Smckusick extern struct vnodeops ufs_vnodeops, spec_inodeops; 9037736Smckusick register struct inode *ip, *iq; 9137736Smckusick register struct vnode *vp; 9239440Smckusick struct vnode *nvp; 9337736Smckusick struct buf *bp; 9439440Smckusick struct dinode *dp; 95*41313Smckusick union ihead *ih; 96*41313Smckusick int i, error; 9724Sbill 9839440Smckusick ih = &ihead[INOHASH(dev, ino)]; 9924Sbill loop: 10039392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 10139392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 10239392Smckusick continue; 10339392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 10439392Smckusick ip->i_flag |= IWANT; 10539392Smckusick sleep((caddr_t)ip, PINOD); 10639392Smckusick goto loop; 10739392Smckusick } 10839440Smckusick if (vget(ITOV(ip))) 10939440Smckusick goto loop; 11039392Smckusick *ipp = ip; 11139392Smckusick return(0); 11239392Smckusick } 11339440Smckusick /* 11439440Smckusick * Allocate a new inode. 11539440Smckusick */ 11639440Smckusick if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) { 11737736Smckusick *ipp = 0; 11837736Smckusick return (error); 11937736Smckusick } 12039440Smckusick ip = VTOI(nvp); 12139440Smckusick ip->i_vnode = nvp; 12239440Smckusick ip->i_flag = 0; 12339440Smckusick ip->i_devvp = 0; 12439440Smckusick ip->i_mode = 0; 12539879Smckusick ip->i_diroff = 0; 12639440Smckusick #ifdef QUOTA 127*41313Smckusick for (i = 0; i < MAXQUOTAS; i++) 128*41313Smckusick ip->i_dquot[i] = NODQUOT; 12939440Smckusick #endif 13037736Smckusick /* 13139440Smckusick * Put it onto its hash chain and lock it so that other requests for 13239440Smckusick * this inode will block if they arrive while we are sleeping waiting 13339440Smckusick * for old data structures to be purged or for the contents of the 13439440Smckusick * disk portion of this inode to be read. 13539440Smckusick */ 13639440Smckusick ip->i_dev = dev; 13739440Smckusick ip->i_number = ino; 13839440Smckusick insque(ip, ih); 13939440Smckusick ILOCK(ip); 14039440Smckusick /* 14137736Smckusick * Read in the disk contents for the inode. 14237736Smckusick */ 14337736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 14438776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 14537736Smckusick /* 14639392Smckusick * Unlock and discard unneeded inode. 14737736Smckusick */ 14839440Smckusick iput(ip); 14937736Smckusick brelse(bp); 15037736Smckusick *ipp = 0; 15139440Smckusick return (error); 15237736Smckusick } 15339440Smckusick dp = bp->b_un.b_dino; 15439440Smckusick dp += itoo(fs, ino); 15539440Smckusick ip->i_din = *dp; 15639440Smckusick brelse(bp); 15737736Smckusick /* 15839440Smckusick * Initialize the associated vnode 15937736Smckusick */ 16039440Smckusick vp = ITOV(ip); 16139440Smckusick vp->v_type = IFTOVT(ip->i_mode); 16240289Smckusick if (vp->v_type == VFIFO) { 16340289Smckusick #ifdef FIFO 16440289Smckusick extern struct vnodeops fifo_inodeops; 16540289Smckusick vp->v_op = &fifo_inodeops; 16640289Smckusick #else 16740289Smckusick iput(ip); 16840289Smckusick *ipp = 0; 16940289Smckusick return (EOPNOTSUPP); 17040289Smckusick #endif /* FIFO */ 17140289Smckusick } 17239440Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 17339440Smckusick vp->v_op = &spec_inodeops; 17439617Smckusick if (nvp = checkalias(vp, ip->i_rdev, mntp)) { 17537736Smckusick /* 17639440Smckusick * Reinitialize aliased inode. 17737736Smckusick */ 17839440Smckusick vp = nvp; 17939440Smckusick iq = VTOI(vp); 18039440Smckusick iq->i_vnode = vp; 18139517Smckusick iq->i_flag = 0; 18239440Smckusick ILOCK(iq); 18339440Smckusick iq->i_din = ip->i_din; 18439440Smckusick iq->i_dev = dev; 18539440Smckusick iq->i_number = ino; 18639440Smckusick insque(iq, ih); 18737736Smckusick /* 18839440Smckusick * Discard unneeded vnode 18937736Smckusick */ 19039440Smckusick ip->i_mode = 0; 19139440Smckusick iput(ip); 19237736Smckusick ip = iq; 19337736Smckusick } 19437736Smckusick } 19539440Smckusick if (ino == ROOTINO) 19639440Smckusick vp->v_flag |= VROOT; 19737736Smckusick /* 19837736Smckusick * Finish inode initialization. 19937736Smckusick */ 20037736Smckusick ip->i_fs = fs; 20137736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 20238345Smckusick VREF(ip->i_devvp); 20338256Smckusick /* 20438256Smckusick * Set up a generation number for this inode if it does not 20538256Smckusick * already have one. This should only happen on old filesystems. 20638256Smckusick */ 20738256Smckusick if (ip->i_gen == 0) { 20838256Smckusick if (++nextgennumber < (u_long)time.tv_sec) 20938256Smckusick nextgennumber = time.tv_sec; 21038256Smckusick ip->i_gen = nextgennumber; 21138256Smckusick if ((vp->v_mount->m_flag & M_RDONLY) == 0) 21238256Smckusick ip->i_flag |= IMOD; 21338256Smckusick } 21437736Smckusick *ipp = ip; 21537736Smckusick return (0); 21637736Smckusick } 2177334Skre 21837736Smckusick /* 21939392Smckusick * Unlock and decrement the reference count of an inode structure. 22024Sbill */ 22124Sbill iput(ip) 2224818Swnj register struct inode *ip; 22324Sbill { 2247118Smckusick 2258452Sroot if ((ip->i_flag & ILOCKED) == 0) 2267118Smckusick panic("iput"); 22716665Smckusick IUNLOCK(ip); 22837736Smckusick vrele(ITOV(ip)); 2297118Smckusick } 2307118Smckusick 23139392Smckusick /* 23239392Smckusick * Last reference to an inode, write the inode out and if necessary, 23339392Smckusick * truncate and deallocate the file. 23439392Smckusick */ 23537736Smckusick ufs_inactive(vp) 23637736Smckusick struct vnode *vp; 2377118Smckusick { 23837736Smckusick register struct inode *ip = VTOI(vp); 23939392Smckusick int mode, error = 0; 24024Sbill 24139816Smckusick if (prtactive && vp->v_usecount != 0) 24239676Smckusick vprint("ufs_inactive: pushing active", vp); 24338452Smckusick /* 24438452Smckusick * Get rid of inodes related to stale file handles. 24538452Smckusick */ 24639440Smckusick if (ip->i_mode == 0) { 24739676Smckusick if ((vp->v_flag & VXLOCK) == 0) 24839676Smckusick vgone(vp); 24939440Smckusick return (0); 25039440Smckusick } 25138226Smckusick ILOCK(ip); 25239364Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->m_flag & M_RDONLY) == 0) { 253*41313Smckusick #ifdef QUOTA 254*41313Smckusick if (!getinoquota(ip)) 255*41313Smckusick (void) chkiq(ip, -1, NOCRED, 0); 256*41313Smckusick #endif 25739676Smckusick error = itrunc(ip, (u_long)0, 0); 25837736Smckusick mode = ip->i_mode; 25937736Smckusick ip->i_mode = 0; 26037736Smckusick ip->i_flag |= IUPD|ICHG; 26137736Smckusick ifree(ip, ip->i_number, mode); 26237736Smckusick } 26337736Smckusick IUPDAT(ip, &time, &time, 0); 26440033Smckusick IUNLOCK(ip); 26540033Smckusick ip->i_flag = 0; 26637736Smckusick /* 26739392Smckusick * If we are done with the inode, reclaim it 26839392Smckusick * so that it can be reused immediately. 26937736Smckusick */ 270*41313Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 27140033Smckusick vgone(vp); 27237736Smckusick return (error); 27324Sbill } 27424Sbill 27524Sbill /* 27639392Smckusick * Reclaim an inode so that it can be used for other purposes. 27724Sbill */ 27839392Smckusick ufs_reclaim(vp) 27939392Smckusick register struct vnode *vp; 28039392Smckusick { 28139492Smckusick register struct inode *ip = VTOI(vp); 282*41313Smckusick int i; 28339392Smckusick 28439816Smckusick if (prtactive && vp->v_usecount != 0) 28539676Smckusick vprint("ufs_reclaim: pushing active", vp); 28639392Smckusick /* 28739392Smckusick * Remove the inode from its hash chain. 28839392Smckusick */ 28939392Smckusick remque(ip); 29039392Smckusick ip->i_forw = ip; 29139392Smckusick ip->i_back = ip; 29239392Smckusick /* 29339392Smckusick * Purge old data structures associated with the inode. 29439392Smckusick */ 29539392Smckusick cache_purge(vp); 29639392Smckusick if (ip->i_devvp) { 29739392Smckusick vrele(ip->i_devvp); 29839392Smckusick ip->i_devvp = 0; 29939392Smckusick } 30039392Smckusick #ifdef QUOTA 301*41313Smckusick for (i = 0; i < MAXQUOTAS; i++) { 302*41313Smckusick if (ip->i_dquot[i] != NODQUOT) { 303*41313Smckusick dqrele(vp, ip->i_dquot[i]); 304*41313Smckusick ip->i_dquot[i] = NODQUOT; 305*41313Smckusick } 306*41313Smckusick } 30739392Smckusick #endif 30839392Smckusick ip->i_flag = 0; 30939392Smckusick return (0); 31039392Smckusick } 31139392Smckusick 31239392Smckusick /* 31339392Smckusick * Check accessed and update flags on an inode structure. 31439392Smckusick * If any is on, update the inode with the current time. 31539392Smckusick * If waitfor is given, then must ensure I/O order, 31639392Smckusick * so wait for write to complete. 31739392Smckusick */ 3181203Sbill iupdat(ip, ta, tm, waitfor) 3194818Swnj register struct inode *ip; 3208630Sroot struct timeval *ta, *tm; 3214818Swnj int waitfor; 32224Sbill { 32337736Smckusick struct buf *bp; 32437736Smckusick struct vnode *vp = ITOV(ip); 32524Sbill struct dinode *dp; 32630749Skarels register struct fs *fs; 32737736Smckusick int error; 32824Sbill 32930749Skarels fs = ip->i_fs; 33037736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 33137736Smckusick return (0); 33237736Smckusick if (vp->v_mount->m_flag & M_RDONLY) 33337736Smckusick return (0); 33437736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 33538776Smckusick (int)fs->fs_bsize, NOCRED, &bp); 33637736Smckusick if (error) { 33737736Smckusick brelse(bp); 33837736Smckusick return (error); 33924Sbill } 34037736Smckusick if (ip->i_flag&IACC) 34137736Smckusick ip->i_atime = ta->tv_sec; 34237736Smckusick if (ip->i_flag&IUPD) 34337736Smckusick ip->i_mtime = tm->tv_sec; 34437736Smckusick if (ip->i_flag&ICHG) 34537736Smckusick ip->i_ctime = time.tv_sec; 34637736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 34737736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 34839392Smckusick *dp = ip->i_din; 34937736Smckusick if (waitfor) { 35037736Smckusick return (bwrite(bp)); 35137736Smckusick } else { 35237736Smckusick bdwrite(bp); 35337736Smckusick return (0); 35437736Smckusick } 35524Sbill } 35624Sbill 35710736Ssam #define SINGLE 0 /* index of single indirect block */ 35810736Ssam #define DOUBLE 1 /* index of double indirect block */ 35910736Ssam #define TRIPLE 2 /* index of triple indirect block */ 36024Sbill /* 36139392Smckusick * Truncate the inode ip to at most length size. Free affected disk 36239392Smckusick * blocks -- the blocks of the file are removed in reverse order. 36310736Ssam * 36410736Ssam * NB: triple indirect blocks are untested. 36524Sbill */ 36639676Smckusick itrunc(oip, length, flags) 36717942Smckusick register struct inode *oip; 3689165Ssam u_long length; 36939676Smckusick int flags; 37024Sbill { 3719165Ssam register daddr_t lastblock; 37226272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 3736569Smckusic register struct fs *fs; 37410736Ssam register struct inode *ip; 37517942Smckusick struct buf *bp; 37637736Smckusick int offset, osize, size, level; 37737736Smckusick long count, nblocks, blocksreleased = 0; 37817942Smckusick register int i; 37939676Smckusick int aflags, error, allerror; 38010736Ssam struct inode tip; 3819165Ssam 38213000Ssam if (oip->i_size <= length) { 38313000Ssam oip->i_flag |= ICHG|IUPD; 38437736Smckusick error = iupdat(oip, &time, &time, 1); 38537736Smckusick return (error); 38613000Ssam } 3871203Sbill /* 38810736Ssam * Calculate index into inode's block list of 38910736Ssam * last direct and indirect blocks (if any) 39010736Ssam * which we want to keep. Lastblock is -1 when 39110736Ssam * the file is truncated to 0. 3921203Sbill */ 39310736Ssam fs = oip->i_fs; 3949165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 39510736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 39610736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 39710736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 39812645Ssam nblocks = btodb(fs->fs_bsize); 3996569Smckusic /* 40017942Smckusick * Update the size of the file. If the file is not being 40117942Smckusick * truncated to a block boundry, the contents of the 40217942Smckusick * partial block following the end of the file must be 40317942Smckusick * zero'ed in case it ever become accessable again because 40417942Smckusick * of subsequent file growth. 40517942Smckusick */ 40617942Smckusick osize = oip->i_size; 40717942Smckusick offset = blkoff(fs, length); 40817942Smckusick if (offset == 0) { 40917942Smckusick oip->i_size = length; 41017942Smckusick } else { 41117942Smckusick lbn = lblkno(fs, length); 41239676Smckusick aflags = B_CLRBUF; 41339676Smckusick if (flags & IO_SYNC) 41439676Smckusick aflags |= B_SYNC; 415*41313Smckusick #ifdef QUOTA 416*41313Smckusick if (error = getinoquota(oip)) 417*41313Smckusick return (error); 418*41313Smckusick #endif 41939676Smckusick if (error = balloc(oip, lbn, offset, &bp, aflags)) 42037736Smckusick return (error); 42117942Smckusick oip->i_size = length; 42217942Smckusick size = blksize(fs, oip, lbn); 42339676Smckusick bn = bp->b_blkno; 42430749Skarels count = howmany(size, CLBYTES); 42530749Skarels for (i = 0; i < count; i++) 42637736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 42726272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 42839676Smckusick brealloc(bp, size); 42939676Smckusick if (flags & IO_SYNC) 43039676Smckusick bwrite(bp); 43139676Smckusick else 43239676Smckusick bdwrite(bp); 43317942Smckusick } 43417942Smckusick /* 43517942Smckusick * Update file and block pointers 43610736Ssam * on disk before we start freeing blocks. 43710736Ssam * If we crash before free'ing blocks below, 43810736Ssam * the blocks will be returned to the free list. 43910736Ssam * lastiblock values are also normalized to -1 44010736Ssam * for calls to indirtrunc below. 4416569Smckusic */ 44210736Ssam tip = *oip; 44317942Smckusick tip.i_size = osize; 44410736Ssam for (level = TRIPLE; level >= SINGLE; level--) 44510736Ssam if (lastiblock[level] < 0) { 44610736Ssam oip->i_ib[level] = 0; 44710736Ssam lastiblock[level] = -1; 4489165Ssam } 44910736Ssam for (i = NDADDR - 1; i > lastblock; i--) 45010736Ssam oip->i_db[i] = 0; 45110736Ssam oip->i_flag |= ICHG|IUPD; 45239676Smckusick vinvalbuf(ITOV(oip), (length > 0)); 45339740Smckusick allerror = iupdat(oip, &time, &time, MNT_WAIT); 45410736Ssam 4556569Smckusic /* 45610736Ssam * Indirect blocks first. 4576569Smckusic */ 45817942Smckusick ip = &tip; 45910736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 46010736Ssam bn = ip->i_ib[level]; 4619165Ssam if (bn != 0) { 46237736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 46337736Smckusick &count); 46437736Smckusick if (error) 46537736Smckusick allerror = error; 46637736Smckusick blocksreleased += count; 46710736Ssam if (lastiblock[level] < 0) { 46810736Ssam ip->i_ib[level] = 0; 46931402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 47010736Ssam blocksreleased += nblocks; 47110736Ssam } 47210736Ssam } 47310736Ssam if (lastiblock[level] >= 0) 47410736Ssam goto done; 4759165Ssam } 47610736Ssam 4776569Smckusic /* 47810736Ssam * All whole direct blocks or frags. 4796569Smckusic */ 4809165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 48126359Skarels register off_t bsize; 4829165Ssam 4836569Smckusic bn = ip->i_db[i]; 4849165Ssam if (bn == 0) 48524Sbill continue; 4869165Ssam ip->i_db[i] = 0; 48724525Sbloom bsize = (off_t)blksize(fs, ip, i); 48831402Smckusick blkfree(ip, bn, bsize); 48924525Sbloom blocksreleased += btodb(bsize); 49024Sbill } 49110736Ssam if (lastblock < 0) 49210736Ssam goto done; 49310736Ssam 4941203Sbill /* 4959165Ssam * Finally, look for a change in size of the 4969165Ssam * last direct block; release any frags. 4971203Sbill */ 49810736Ssam bn = ip->i_db[lastblock]; 49910736Ssam if (bn != 0) { 50026359Skarels off_t oldspace, newspace; 50110736Ssam 5029165Ssam /* 5039165Ssam * Calculate amount of space we're giving 5049165Ssam * back as old block size minus new block size. 5059165Ssam */ 50610736Ssam oldspace = blksize(fs, ip, lastblock); 5079165Ssam ip->i_size = length; 50810736Ssam newspace = blksize(fs, ip, lastblock); 50910736Ssam if (newspace == 0) 51010736Ssam panic("itrunc: newspace"); 51110736Ssam if (oldspace - newspace > 0) { 5129165Ssam /* 5139165Ssam * Block number of space to be free'd is 5149165Ssam * the old block # plus the number of frags 5159165Ssam * required for the storage we're keeping. 5169165Ssam */ 51710736Ssam bn += numfrags(fs, newspace); 51831402Smckusick blkfree(ip, bn, oldspace - newspace); 51912645Ssam blocksreleased += btodb(oldspace - newspace); 5209165Ssam } 5219165Ssam } 5229165Ssam done: 52310736Ssam /* BEGIN PARANOIA */ 52410736Ssam for (level = SINGLE; level <= TRIPLE; level++) 52510736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 52610736Ssam panic("itrunc1"); 52710736Ssam for (i = 0; i < NDADDR; i++) 52810736Ssam if (ip->i_db[i] != oip->i_db[i]) 52910736Ssam panic("itrunc2"); 53010736Ssam /* END PARANOIA */ 53112645Ssam oip->i_blocks -= blocksreleased; 53212645Ssam if (oip->i_blocks < 0) /* sanity */ 53312645Ssam oip->i_blocks = 0; 53412645Ssam oip->i_flag |= ICHG; 5359165Ssam #ifdef QUOTA 536*41313Smckusick if (!getinoquota(oip)) 537*41313Smckusick (void) chkdq(oip, -blocksreleased, NOCRED, 0); 5389165Ssam #endif 53937736Smckusick return (allerror); 54024Sbill } 54124Sbill 5429165Ssam /* 5439165Ssam * Release blocks associated with the inode ip and 5449165Ssam * stored in the indirect block bn. Blocks are free'd 5459165Ssam * in LIFO order up to (but not including) lastbn. If 54610736Ssam * level is greater than SINGLE, the block is an indirect 54710736Ssam * block and recursive calls to indirtrunc must be used to 54810736Ssam * cleanse other indirect blocks. 54910736Ssam * 55010736Ssam * NB: triple indirect blocks are untested. 5519165Ssam */ 55237736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 5536569Smckusic register struct inode *ip; 5549165Ssam daddr_t bn, lastbn; 55510736Ssam int level; 55637736Smckusick long *countp; 55724Sbill { 5589165Ssam register int i; 55931661Smckusick struct buf *bp; 56031661Smckusick register struct fs *fs = ip->i_fs; 56124Sbill register daddr_t *bap; 56231661Smckusick daddr_t *copy, nb, last; 56337736Smckusick long blkcount, factor; 56437736Smckusick int nblocks, blocksreleased = 0; 56537736Smckusick int error, allerror = 0; 56624Sbill 56710736Ssam /* 56810736Ssam * Calculate index in current block of last 56910736Ssam * block to be kept. -1 indicates the entire 57010736Ssam * block so we need not calculate the index. 57110736Ssam */ 57210736Ssam factor = 1; 57310736Ssam for (i = SINGLE; i < level; i++) 57410736Ssam factor *= NINDIR(fs); 5759165Ssam last = lastbn; 57610736Ssam if (lastbn > 0) 57710736Ssam last /= factor; 57812645Ssam nblocks = btodb(fs->fs_bsize); 57910736Ssam /* 58010736Ssam * Get buffer of block pointers, zero those 58110736Ssam * entries corresponding to blocks to be free'd, 58210736Ssam * and update on disk copy first. 58310736Ssam */ 58438776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 58538776Smckusick NOCRED, &bp); 58637736Smckusick if (error) { 58710736Ssam brelse(bp); 58837736Smckusick *countp = 0; 58937736Smckusick return (error); 59010736Ssam } 59110736Ssam bap = bp->b_un.b_daddr; 59231661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 59331661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 59410736Ssam bzero((caddr_t)&bap[last + 1], 59510736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 59639676Smckusick if (last == -1) 59739676Smckusick bp->b_flags |= B_INVAL; 59837736Smckusick error = bwrite(bp); 59937736Smckusick if (error) 60037736Smckusick allerror = error; 60131661Smckusick bap = copy; 60210736Ssam 60310736Ssam /* 60410736Ssam * Recursively free totally unused blocks. 60510736Ssam */ 6069165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 60724Sbill nb = bap[i]; 6089165Ssam if (nb == 0) 60924Sbill continue; 61037736Smckusick if (level > SINGLE) { 61137736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 61237736Smckusick &blkcount); 61337736Smckusick if (error) 61437736Smckusick allerror = error; 61537736Smckusick blocksreleased += blkcount; 61637736Smckusick } 61731402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 6189165Ssam blocksreleased += nblocks; 61924Sbill } 62010736Ssam 62110736Ssam /* 62210736Ssam * Recursively free last partial block. 62310736Ssam */ 62410736Ssam if (level > SINGLE && lastbn >= 0) { 62510736Ssam last = lastbn % factor; 6269165Ssam nb = bap[i]; 62737736Smckusick if (nb != 0) { 62837736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 62937736Smckusick if (error) 63037736Smckusick allerror = error; 63137736Smckusick blocksreleased += blkcount; 63237736Smckusick } 6339165Ssam } 63431661Smckusick FREE(copy, M_TEMP); 63537736Smckusick *countp = blocksreleased; 63637736Smckusick return (allerror); 63724Sbill } 63824Sbill 63924Sbill /* 6404818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6413617Sroot */ 6424818Swnj ilock(ip) 6434818Swnj register struct inode *ip; 6443617Sroot { 6453617Sroot 64637736Smckusick while (ip->i_flag & ILOCKED) { 64737736Smckusick ip->i_flag |= IWANT; 64839795Smckusick if (ip->i_spare0 == u.u_procp->p_pid) 64939795Smckusick panic("locking against myself"); 65039795Smckusick ip->i_spare1 = u.u_procp->p_pid; 65137736Smckusick (void) sleep((caddr_t)ip, PINOD); 65237736Smckusick } 65339795Smckusick ip->i_spare1 = 0; 65439795Smckusick ip->i_spare0 = u.u_procp->p_pid; 65539795Smckusick u.u_spare[0]++; 65637736Smckusick ip->i_flag |= ILOCKED; 6573617Sroot } 6583617Sroot 6593617Sroot /* 6604818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6613617Sroot */ 6627118Smckusick iunlock(ip) 6634818Swnj register struct inode *ip; 6643617Sroot { 6653617Sroot 66637736Smckusick if ((ip->i_flag & ILOCKED) == 0) 66739676Smckusick vprint("iunlock: unlocked inode", ITOV(ip)); 66839795Smckusick ip->i_spare0 = 0; 66939795Smckusick u.u_spare[0]--; 67037736Smckusick ip->i_flag &= ~ILOCKED; 67137736Smckusick if (ip->i_flag&IWANT) { 67237736Smckusick ip->i_flag &= ~IWANT; 67337736Smckusick wakeup((caddr_t)ip); 67437736Smckusick } 6753617Sroot } 676