123399Smckusick /* 237736Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337736Smckusick * All rights reserved. 423399Smckusick * 5*44537Sbostic * %sccs.include.redist.c% 637736Smckusick * 7*44537Sbostic * @(#)lfs_inode.c 7.33 (Berkeley) 06/28/90 823399Smckusick */ 924Sbill 1017099Sbloom #include "param.h" 1117099Sbloom #include "systm.h" 1217099Sbloom #include "mount.h" 1317099Sbloom #include "user.h" 1439795Smckusick #include "proc.h" 1537736Smckusick #include "file.h" 1617099Sbloom #include "buf.h" 1724525Sbloom #include "cmap.h" 1837736Smckusick #include "vnode.h" 1941313Smckusick #include "../ufs/quota.h" 2037736Smckusick #include "../ufs/inode.h" 2137736Smckusick #include "../ufs/fs.h" 2237736Smckusick #include "../ufs/ufsmount.h" 2317099Sbloom #include "kernel.h" 2431661Smckusick #include "malloc.h" 2524Sbill 2616840Smckusick #define INOHSZ 512 277334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 287334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 297334Skre #else 3010852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 317334Skre #endif 3224Sbill 3339392Smckusick union ihead { 347334Skre union ihead *ih_head[2]; 357334Skre struct inode *ih_chain[2]; 367334Skre } ihead[INOHSZ]; 377334Skre 3839574Smckusick int prtactive; /* 1 => print out reclaim of active vnodes */ 3939574Smckusick 4024Sbill /* 4139392Smckusick * Initialize hash links for inodes. 4224Sbill */ 4339440Smckusick ufs_init() 4424Sbill { 4524Sbill register int i; 4639392Smckusick register union ihead *ih = ihead; 4724Sbill 4839492Smckusick #ifndef lint 4939392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 5039392Smckusick panic("ihinit: too small"); 5139492Smckusick #endif /* not lint */ 527334Skre for (i = INOHSZ; --i >= 0; ih++) { 537334Skre ih->ih_head[0] = ih; 547334Skre ih->ih_head[1] = ih; 557334Skre } 5641313Smckusick #ifdef QUOTA 5741313Smckusick dqinit(); 5841313Smckusick #endif /* QUOTA */ 5924Sbill } 6024Sbill 6124Sbill /* 6237736Smckusick * Look up an vnode/inode by device,inumber. 6324Sbill * If it is in core (in the inode structure), 6424Sbill * honor the locking protocol. 6524Sbill * If it is not in core, read it in from the 6624Sbill * specified device. 6737736Smckusick * Callers must check for mount points!! 6824Sbill * In all cases, a pointer to a locked 6924Sbill * inode structure is returned. 7024Sbill */ 7137736Smckusick iget(xp, ino, ipp) 7237736Smckusick struct inode *xp; 734818Swnj ino_t ino; 7437736Smckusick struct inode **ipp; 7524Sbill { 7637736Smckusick dev_t dev = xp->i_dev; 7737736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 7837736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 7939440Smckusick extern struct vnodeops ufs_vnodeops, spec_inodeops; 8037736Smckusick register struct inode *ip, *iq; 8137736Smckusick register struct vnode *vp; 8239440Smckusick struct vnode *nvp; 8337736Smckusick struct buf *bp; 8439440Smckusick struct dinode *dp; 8541313Smckusick union ihead *ih; 8641313Smckusick int i, error; 8724Sbill 8839440Smckusick ih = &ihead[INOHASH(dev, ino)]; 8924Sbill loop: 9039392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 9139392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 9239392Smckusick continue; 9339392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 9439392Smckusick ip->i_flag |= IWANT; 9539392Smckusick sleep((caddr_t)ip, PINOD); 9639392Smckusick goto loop; 9739392Smckusick } 9839440Smckusick if (vget(ITOV(ip))) 9939440Smckusick goto loop; 10039392Smckusick *ipp = ip; 10139392Smckusick return(0); 10239392Smckusick } 10339440Smckusick /* 10439440Smckusick * Allocate a new inode. 10539440Smckusick */ 10639440Smckusick if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) { 10737736Smckusick *ipp = 0; 10837736Smckusick return (error); 10937736Smckusick } 11039440Smckusick ip = VTOI(nvp); 11139440Smckusick ip->i_vnode = nvp; 11239440Smckusick ip->i_flag = 0; 11339440Smckusick ip->i_devvp = 0; 11439440Smckusick ip->i_mode = 0; 11539879Smckusick ip->i_diroff = 0; 11639440Smckusick #ifdef QUOTA 11741313Smckusick for (i = 0; i < MAXQUOTAS; i++) 11841313Smckusick ip->i_dquot[i] = NODQUOT; 11939440Smckusick #endif 12037736Smckusick /* 12139440Smckusick * Put it onto its hash chain and lock it so that other requests for 12239440Smckusick * this inode will block if they arrive while we are sleeping waiting 12339440Smckusick * for old data structures to be purged or for the contents of the 12439440Smckusick * disk portion of this inode to be read. 12539440Smckusick */ 12639440Smckusick ip->i_dev = dev; 12739440Smckusick ip->i_number = ino; 12839440Smckusick insque(ip, ih); 12939440Smckusick ILOCK(ip); 13039440Smckusick /* 13137736Smckusick * Read in the disk contents for the inode. 13237736Smckusick */ 13337736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 13438776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 13537736Smckusick /* 13641334Smckusick * The inode does not contain anything useful, so it would 13741334Smckusick * be misleading to leave it on its hash chain. 13841334Smckusick * Iput() will take care of putting it back on the free list. 13941334Smckusick */ 14041334Smckusick remque(ip); 14141334Smckusick ip->i_forw = ip; 14241334Smckusick ip->i_back = ip; 14341334Smckusick /* 14439392Smckusick * Unlock and discard unneeded inode. 14537736Smckusick */ 14639440Smckusick iput(ip); 14737736Smckusick brelse(bp); 14837736Smckusick *ipp = 0; 14939440Smckusick return (error); 15037736Smckusick } 15139440Smckusick dp = bp->b_un.b_dino; 15239440Smckusick dp += itoo(fs, ino); 15339440Smckusick ip->i_din = *dp; 15439440Smckusick brelse(bp); 15537736Smckusick /* 15639440Smckusick * Initialize the associated vnode 15737736Smckusick */ 15839440Smckusick vp = ITOV(ip); 15939440Smckusick vp->v_type = IFTOVT(ip->i_mode); 16040289Smckusick if (vp->v_type == VFIFO) { 16140289Smckusick #ifdef FIFO 16240289Smckusick extern struct vnodeops fifo_inodeops; 16340289Smckusick vp->v_op = &fifo_inodeops; 16440289Smckusick #else 16540289Smckusick iput(ip); 16640289Smckusick *ipp = 0; 16740289Smckusick return (EOPNOTSUPP); 16840289Smckusick #endif /* FIFO */ 16940289Smckusick } 17039440Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 17139440Smckusick vp->v_op = &spec_inodeops; 17239617Smckusick if (nvp = checkalias(vp, ip->i_rdev, mntp)) { 17337736Smckusick /* 17439440Smckusick * Reinitialize aliased inode. 17537736Smckusick */ 17639440Smckusick vp = nvp; 17739440Smckusick iq = VTOI(vp); 17839440Smckusick iq->i_vnode = vp; 17939517Smckusick iq->i_flag = 0; 18039440Smckusick ILOCK(iq); 18139440Smckusick iq->i_din = ip->i_din; 18239440Smckusick iq->i_dev = dev; 18339440Smckusick iq->i_number = ino; 18439440Smckusick insque(iq, ih); 18537736Smckusick /* 18639440Smckusick * Discard unneeded vnode 18737736Smckusick */ 18839440Smckusick ip->i_mode = 0; 18939440Smckusick iput(ip); 19037736Smckusick ip = iq; 19137736Smckusick } 19237736Smckusick } 19339440Smckusick if (ino == ROOTINO) 19439440Smckusick vp->v_flag |= VROOT; 19537736Smckusick /* 19637736Smckusick * Finish inode initialization. 19737736Smckusick */ 19837736Smckusick ip->i_fs = fs; 19937736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 20038345Smckusick VREF(ip->i_devvp); 20138256Smckusick /* 20238256Smckusick * Set up a generation number for this inode if it does not 20338256Smckusick * already have one. This should only happen on old filesystems. 20438256Smckusick */ 20538256Smckusick if (ip->i_gen == 0) { 20638256Smckusick if (++nextgennumber < (u_long)time.tv_sec) 20738256Smckusick nextgennumber = time.tv_sec; 20838256Smckusick ip->i_gen = nextgennumber; 20941397Smckusick if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 21038256Smckusick ip->i_flag |= IMOD; 21138256Smckusick } 21237736Smckusick *ipp = ip; 21337736Smckusick return (0); 21437736Smckusick } 2157334Skre 21637736Smckusick /* 21739392Smckusick * Unlock and decrement the reference count of an inode structure. 21824Sbill */ 21924Sbill iput(ip) 2204818Swnj register struct inode *ip; 22124Sbill { 2227118Smckusick 2238452Sroot if ((ip->i_flag & ILOCKED) == 0) 2247118Smckusick panic("iput"); 22516665Smckusick IUNLOCK(ip); 22637736Smckusick vrele(ITOV(ip)); 2277118Smckusick } 2287118Smckusick 22939392Smckusick /* 23039392Smckusick * Last reference to an inode, write the inode out and if necessary, 23139392Smckusick * truncate and deallocate the file. 23239392Smckusick */ 23337736Smckusick ufs_inactive(vp) 23437736Smckusick struct vnode *vp; 2357118Smckusick { 23637736Smckusick register struct inode *ip = VTOI(vp); 23739392Smckusick int mode, error = 0; 23824Sbill 23939816Smckusick if (prtactive && vp->v_usecount != 0) 24039676Smckusick vprint("ufs_inactive: pushing active", vp); 24138452Smckusick /* 24238452Smckusick * Get rid of inodes related to stale file handles. 24338452Smckusick */ 24439440Smckusick if (ip->i_mode == 0) { 24539676Smckusick if ((vp->v_flag & VXLOCK) == 0) 24639676Smckusick vgone(vp); 24739440Smckusick return (0); 24839440Smckusick } 24938226Smckusick ILOCK(ip); 25041397Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 25141313Smckusick #ifdef QUOTA 25241313Smckusick if (!getinoquota(ip)) 25341313Smckusick (void) chkiq(ip, -1, NOCRED, 0); 25441313Smckusick #endif 25539676Smckusick error = itrunc(ip, (u_long)0, 0); 25637736Smckusick mode = ip->i_mode; 25737736Smckusick ip->i_mode = 0; 25837736Smckusick ip->i_flag |= IUPD|ICHG; 25937736Smckusick ifree(ip, ip->i_number, mode); 26037736Smckusick } 26137736Smckusick IUPDAT(ip, &time, &time, 0); 26240033Smckusick IUNLOCK(ip); 26340033Smckusick ip->i_flag = 0; 26437736Smckusick /* 26539392Smckusick * If we are done with the inode, reclaim it 26639392Smckusick * so that it can be reused immediately. 26737736Smckusick */ 26841313Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 26940033Smckusick vgone(vp); 27037736Smckusick return (error); 27124Sbill } 27224Sbill 27324Sbill /* 27439392Smckusick * Reclaim an inode so that it can be used for other purposes. 27524Sbill */ 27639392Smckusick ufs_reclaim(vp) 27739392Smckusick register struct vnode *vp; 27839392Smckusick { 27939492Smckusick register struct inode *ip = VTOI(vp); 28041313Smckusick int i; 28139392Smckusick 28239816Smckusick if (prtactive && vp->v_usecount != 0) 28339676Smckusick vprint("ufs_reclaim: pushing active", vp); 28439392Smckusick /* 28539392Smckusick * Remove the inode from its hash chain. 28639392Smckusick */ 28739392Smckusick remque(ip); 28839392Smckusick ip->i_forw = ip; 28939392Smckusick ip->i_back = ip; 29039392Smckusick /* 29139392Smckusick * Purge old data structures associated with the inode. 29239392Smckusick */ 29339392Smckusick cache_purge(vp); 29439392Smckusick if (ip->i_devvp) { 29539392Smckusick vrele(ip->i_devvp); 29639392Smckusick ip->i_devvp = 0; 29739392Smckusick } 29839392Smckusick #ifdef QUOTA 29941313Smckusick for (i = 0; i < MAXQUOTAS; i++) { 30041313Smckusick if (ip->i_dquot[i] != NODQUOT) { 30141313Smckusick dqrele(vp, ip->i_dquot[i]); 30241313Smckusick ip->i_dquot[i] = NODQUOT; 30341313Smckusick } 30441313Smckusick } 30539392Smckusick #endif 30639392Smckusick ip->i_flag = 0; 30739392Smckusick return (0); 30839392Smckusick } 30939392Smckusick 31039392Smckusick /* 31139392Smckusick * Check accessed and update flags on an inode structure. 31239392Smckusick * If any is on, update the inode with the current time. 31339392Smckusick * If waitfor is given, then must ensure I/O order, 31439392Smckusick * so wait for write to complete. 31539392Smckusick */ 3161203Sbill iupdat(ip, ta, tm, waitfor) 3174818Swnj register struct inode *ip; 3188630Sroot struct timeval *ta, *tm; 3194818Swnj int waitfor; 32024Sbill { 32137736Smckusick struct buf *bp; 32237736Smckusick struct vnode *vp = ITOV(ip); 32324Sbill struct dinode *dp; 32430749Skarels register struct fs *fs; 32537736Smckusick int error; 32624Sbill 32730749Skarels fs = ip->i_fs; 32837736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 32937736Smckusick return (0); 33041397Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) 33137736Smckusick return (0); 33237736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 33338776Smckusick (int)fs->fs_bsize, NOCRED, &bp); 33437736Smckusick if (error) { 33537736Smckusick brelse(bp); 33637736Smckusick return (error); 33724Sbill } 33837736Smckusick if (ip->i_flag&IACC) 33937736Smckusick ip->i_atime = ta->tv_sec; 34037736Smckusick if (ip->i_flag&IUPD) 34137736Smckusick ip->i_mtime = tm->tv_sec; 34237736Smckusick if (ip->i_flag&ICHG) 34337736Smckusick ip->i_ctime = time.tv_sec; 34437736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 34537736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 34639392Smckusick *dp = ip->i_din; 34737736Smckusick if (waitfor) { 34837736Smckusick return (bwrite(bp)); 34937736Smckusick } else { 35037736Smckusick bdwrite(bp); 35137736Smckusick return (0); 35237736Smckusick } 35324Sbill } 35424Sbill 35510736Ssam #define SINGLE 0 /* index of single indirect block */ 35610736Ssam #define DOUBLE 1 /* index of double indirect block */ 35710736Ssam #define TRIPLE 2 /* index of triple indirect block */ 35824Sbill /* 35939392Smckusick * Truncate the inode ip to at most length size. Free affected disk 36039392Smckusick * blocks -- the blocks of the file are removed in reverse order. 36110736Ssam * 36210736Ssam * NB: triple indirect blocks are untested. 36324Sbill */ 36439676Smckusick itrunc(oip, length, flags) 36517942Smckusick register struct inode *oip; 3669165Ssam u_long length; 36739676Smckusick int flags; 36824Sbill { 3699165Ssam register daddr_t lastblock; 37026272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 3716569Smckusic register struct fs *fs; 37210736Ssam register struct inode *ip; 37317942Smckusick struct buf *bp; 37437736Smckusick int offset, osize, size, level; 37537736Smckusick long count, nblocks, blocksreleased = 0; 37617942Smckusick register int i; 37739676Smckusick int aflags, error, allerror; 37810736Ssam struct inode tip; 3799165Ssam 38013000Ssam if (oip->i_size <= length) { 38113000Ssam oip->i_flag |= ICHG|IUPD; 38237736Smckusick error = iupdat(oip, &time, &time, 1); 38337736Smckusick return (error); 38413000Ssam } 3851203Sbill /* 38610736Ssam * Calculate index into inode's block list of 38710736Ssam * last direct and indirect blocks (if any) 38810736Ssam * which we want to keep. Lastblock is -1 when 38910736Ssam * the file is truncated to 0. 3901203Sbill */ 39110736Ssam fs = oip->i_fs; 3929165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 39310736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 39410736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 39510736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 39612645Ssam nblocks = btodb(fs->fs_bsize); 3976569Smckusic /* 39817942Smckusick * Update the size of the file. If the file is not being 39917942Smckusick * truncated to a block boundry, the contents of the 40017942Smckusick * partial block following the end of the file must be 40117942Smckusick * zero'ed in case it ever become accessable again because 40217942Smckusick * of subsequent file growth. 40317942Smckusick */ 40417942Smckusick osize = oip->i_size; 40517942Smckusick offset = blkoff(fs, length); 40617942Smckusick if (offset == 0) { 40717942Smckusick oip->i_size = length; 40817942Smckusick } else { 40917942Smckusick lbn = lblkno(fs, length); 41039676Smckusick aflags = B_CLRBUF; 41139676Smckusick if (flags & IO_SYNC) 41239676Smckusick aflags |= B_SYNC; 41341313Smckusick #ifdef QUOTA 41441313Smckusick if (error = getinoquota(oip)) 41541313Smckusick return (error); 41641313Smckusick #endif 41739676Smckusick if (error = balloc(oip, lbn, offset, &bp, aflags)) 41837736Smckusick return (error); 41917942Smckusick oip->i_size = length; 42017942Smckusick size = blksize(fs, oip, lbn); 42139676Smckusick bn = bp->b_blkno; 42230749Skarels count = howmany(size, CLBYTES); 42330749Skarels for (i = 0; i < count; i++) 42437736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 42526272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 42639676Smckusick brealloc(bp, size); 42739676Smckusick if (flags & IO_SYNC) 42839676Smckusick bwrite(bp); 42939676Smckusick else 43039676Smckusick bdwrite(bp); 43117942Smckusick } 43217942Smckusick /* 43317942Smckusick * Update file and block pointers 43410736Ssam * on disk before we start freeing blocks. 43510736Ssam * If we crash before free'ing blocks below, 43610736Ssam * the blocks will be returned to the free list. 43710736Ssam * lastiblock values are also normalized to -1 43810736Ssam * for calls to indirtrunc below. 4396569Smckusic */ 44010736Ssam tip = *oip; 44117942Smckusick tip.i_size = osize; 44210736Ssam for (level = TRIPLE; level >= SINGLE; level--) 44310736Ssam if (lastiblock[level] < 0) { 44410736Ssam oip->i_ib[level] = 0; 44510736Ssam lastiblock[level] = -1; 4469165Ssam } 44710736Ssam for (i = NDADDR - 1; i > lastblock; i--) 44810736Ssam oip->i_db[i] = 0; 44910736Ssam oip->i_flag |= ICHG|IUPD; 45039676Smckusick vinvalbuf(ITOV(oip), (length > 0)); 45139740Smckusick allerror = iupdat(oip, &time, &time, MNT_WAIT); 45210736Ssam 4536569Smckusic /* 45410736Ssam * Indirect blocks first. 4556569Smckusic */ 45617942Smckusick ip = &tip; 45710736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 45810736Ssam bn = ip->i_ib[level]; 4599165Ssam if (bn != 0) { 46037736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 46137736Smckusick &count); 46237736Smckusick if (error) 46337736Smckusick allerror = error; 46437736Smckusick blocksreleased += count; 46510736Ssam if (lastiblock[level] < 0) { 46610736Ssam ip->i_ib[level] = 0; 46731402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 46810736Ssam blocksreleased += nblocks; 46910736Ssam } 47010736Ssam } 47110736Ssam if (lastiblock[level] >= 0) 47210736Ssam goto done; 4739165Ssam } 47410736Ssam 4756569Smckusic /* 47610736Ssam * All whole direct blocks or frags. 4776569Smckusic */ 4789165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 47926359Skarels register off_t bsize; 4809165Ssam 4816569Smckusic bn = ip->i_db[i]; 4829165Ssam if (bn == 0) 48324Sbill continue; 4849165Ssam ip->i_db[i] = 0; 48524525Sbloom bsize = (off_t)blksize(fs, ip, i); 48631402Smckusick blkfree(ip, bn, bsize); 48724525Sbloom blocksreleased += btodb(bsize); 48824Sbill } 48910736Ssam if (lastblock < 0) 49010736Ssam goto done; 49110736Ssam 4921203Sbill /* 4939165Ssam * Finally, look for a change in size of the 4949165Ssam * last direct block; release any frags. 4951203Sbill */ 49610736Ssam bn = ip->i_db[lastblock]; 49710736Ssam if (bn != 0) { 49826359Skarels off_t oldspace, newspace; 49910736Ssam 5009165Ssam /* 5019165Ssam * Calculate amount of space we're giving 5029165Ssam * back as old block size minus new block size. 5039165Ssam */ 50410736Ssam oldspace = blksize(fs, ip, lastblock); 5059165Ssam ip->i_size = length; 50610736Ssam newspace = blksize(fs, ip, lastblock); 50710736Ssam if (newspace == 0) 50810736Ssam panic("itrunc: newspace"); 50910736Ssam if (oldspace - newspace > 0) { 5109165Ssam /* 5119165Ssam * Block number of space to be free'd is 5129165Ssam * the old block # plus the number of frags 5139165Ssam * required for the storage we're keeping. 5149165Ssam */ 51510736Ssam bn += numfrags(fs, newspace); 51631402Smckusick blkfree(ip, bn, oldspace - newspace); 51712645Ssam blocksreleased += btodb(oldspace - newspace); 5189165Ssam } 5199165Ssam } 5209165Ssam done: 52110736Ssam /* BEGIN PARANOIA */ 52210736Ssam for (level = SINGLE; level <= TRIPLE; level++) 52310736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 52410736Ssam panic("itrunc1"); 52510736Ssam for (i = 0; i < NDADDR; i++) 52610736Ssam if (ip->i_db[i] != oip->i_db[i]) 52710736Ssam panic("itrunc2"); 52810736Ssam /* END PARANOIA */ 52912645Ssam oip->i_blocks -= blocksreleased; 53012645Ssam if (oip->i_blocks < 0) /* sanity */ 53112645Ssam oip->i_blocks = 0; 53212645Ssam oip->i_flag |= ICHG; 5339165Ssam #ifdef QUOTA 53441313Smckusick if (!getinoquota(oip)) 53541313Smckusick (void) chkdq(oip, -blocksreleased, NOCRED, 0); 5369165Ssam #endif 53737736Smckusick return (allerror); 53824Sbill } 53924Sbill 5409165Ssam /* 5419165Ssam * Release blocks associated with the inode ip and 5429165Ssam * stored in the indirect block bn. Blocks are free'd 5439165Ssam * in LIFO order up to (but not including) lastbn. If 54410736Ssam * level is greater than SINGLE, the block is an indirect 54510736Ssam * block and recursive calls to indirtrunc must be used to 54610736Ssam * cleanse other indirect blocks. 54710736Ssam * 54810736Ssam * NB: triple indirect blocks are untested. 5499165Ssam */ 55037736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 5516569Smckusic register struct inode *ip; 5529165Ssam daddr_t bn, lastbn; 55310736Ssam int level; 55437736Smckusick long *countp; 55524Sbill { 5569165Ssam register int i; 55731661Smckusick struct buf *bp; 55831661Smckusick register struct fs *fs = ip->i_fs; 55924Sbill register daddr_t *bap; 56031661Smckusick daddr_t *copy, nb, last; 56137736Smckusick long blkcount, factor; 56237736Smckusick int nblocks, blocksreleased = 0; 56337736Smckusick int error, allerror = 0; 56424Sbill 56510736Ssam /* 56610736Ssam * Calculate index in current block of last 56710736Ssam * block to be kept. -1 indicates the entire 56810736Ssam * block so we need not calculate the index. 56910736Ssam */ 57010736Ssam factor = 1; 57110736Ssam for (i = SINGLE; i < level; i++) 57210736Ssam factor *= NINDIR(fs); 5739165Ssam last = lastbn; 57410736Ssam if (lastbn > 0) 57510736Ssam last /= factor; 57612645Ssam nblocks = btodb(fs->fs_bsize); 57710736Ssam /* 57810736Ssam * Get buffer of block pointers, zero those 57910736Ssam * entries corresponding to blocks to be free'd, 58010736Ssam * and update on disk copy first. 58110736Ssam */ 58238776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 58338776Smckusick NOCRED, &bp); 58437736Smckusick if (error) { 58510736Ssam brelse(bp); 58637736Smckusick *countp = 0; 58737736Smckusick return (error); 58810736Ssam } 58910736Ssam bap = bp->b_un.b_daddr; 59031661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 59131661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 59210736Ssam bzero((caddr_t)&bap[last + 1], 59310736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 59439676Smckusick if (last == -1) 59539676Smckusick bp->b_flags |= B_INVAL; 59637736Smckusick error = bwrite(bp); 59737736Smckusick if (error) 59837736Smckusick allerror = error; 59931661Smckusick bap = copy; 60010736Ssam 60110736Ssam /* 60210736Ssam * Recursively free totally unused blocks. 60310736Ssam */ 6049165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 60524Sbill nb = bap[i]; 6069165Ssam if (nb == 0) 60724Sbill continue; 60837736Smckusick if (level > SINGLE) { 60937736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 61037736Smckusick &blkcount); 61137736Smckusick if (error) 61237736Smckusick allerror = error; 61337736Smckusick blocksreleased += blkcount; 61437736Smckusick } 61531402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 6169165Ssam blocksreleased += nblocks; 61724Sbill } 61810736Ssam 61910736Ssam /* 62010736Ssam * Recursively free last partial block. 62110736Ssam */ 62210736Ssam if (level > SINGLE && lastbn >= 0) { 62310736Ssam last = lastbn % factor; 6249165Ssam nb = bap[i]; 62537736Smckusick if (nb != 0) { 62637736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 62737736Smckusick if (error) 62837736Smckusick allerror = error; 62937736Smckusick blocksreleased += blkcount; 63037736Smckusick } 6319165Ssam } 63231661Smckusick FREE(copy, M_TEMP); 63337736Smckusick *countp = blocksreleased; 63437736Smckusick return (allerror); 63524Sbill } 63624Sbill 63724Sbill /* 6384818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6393617Sroot */ 6404818Swnj ilock(ip) 6414818Swnj register struct inode *ip; 6423617Sroot { 6433617Sroot 64437736Smckusick while (ip->i_flag & ILOCKED) { 64537736Smckusick ip->i_flag |= IWANT; 64639795Smckusick if (ip->i_spare0 == u.u_procp->p_pid) 64739795Smckusick panic("locking against myself"); 64839795Smckusick ip->i_spare1 = u.u_procp->p_pid; 64937736Smckusick (void) sleep((caddr_t)ip, PINOD); 65037736Smckusick } 65139795Smckusick ip->i_spare1 = 0; 65239795Smckusick ip->i_spare0 = u.u_procp->p_pid; 65339795Smckusick u.u_spare[0]++; 65437736Smckusick ip->i_flag |= ILOCKED; 6553617Sroot } 6563617Sroot 6573617Sroot /* 6584818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6593617Sroot */ 6607118Smckusick iunlock(ip) 6614818Swnj register struct inode *ip; 6623617Sroot { 6633617Sroot 66437736Smckusick if ((ip->i_flag & ILOCKED) == 0) 66539676Smckusick vprint("iunlock: unlocked inode", ITOV(ip)); 66639795Smckusick ip->i_spare0 = 0; 66739795Smckusick u.u_spare[0]--; 66837736Smckusick ip->i_flag &= ~ILOCKED; 66937736Smckusick if (ip->i_flag&IWANT) { 67037736Smckusick ip->i_flag &= ~IWANT; 67137736Smckusick wakeup((caddr_t)ip); 67237736Smckusick } 6733617Sroot } 674