123399Smckusick /* 237736Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337736Smckusick * All rights reserved. 423399Smckusick * 544537Sbostic * %sccs.include.redist.c% 637736Smckusick * 7*51346Sbostic * @(#)lfs_inode.c 7.44 (Berkeley) 10/09/91 823399Smckusick */ 924Sbill 1051215Sbostic #ifdef LOGFS 1117099Sbloom #include "param.h" 1217099Sbloom #include "systm.h" 1317099Sbloom #include "mount.h" 1439795Smckusick #include "proc.h" 1537736Smckusick #include "file.h" 1617099Sbloom #include "buf.h" 1737736Smckusick #include "vnode.h" 1817099Sbloom #include "kernel.h" 1931661Smckusick #include "malloc.h" 2024Sbill 2151155Sbostic #include "../ufs/quota.h" 2251155Sbostic #include "../ufs/inode.h" 2351155Sbostic #include "../ufs/ufsmount.h" 2451215Sbostic #include "../vm/vm_param.h" 2551215Sbostic #include "../vm/lock.h" 2651155Sbostic #include "lfs.h" 2751155Sbostic #include "lfs_extern.h" 2847571Skarels 2916840Smckusick #define INOHSZ 512 307334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 317334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 327334Skre #else 3310852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 347334Skre #endif 3524Sbill 3651155Sbostic union lfsihead { /* LFS */ 3751155Sbostic union lfsihead *ih_head[2]; 387334Skre struct inode *ih_chain[2]; 3951155Sbostic } lfsihead[INOHSZ]; 407334Skre 4151155Sbostic /* LFS */ 4251155Sbostic extern int prtactive; /* 1 => print out reclaim of active vnodes */ 4339574Smckusick 4451215Sbostic lock_data_t lfs_sync_lock; 4551215Sbostic 4624Sbill /* 4739392Smckusick * Initialize hash links for inodes. 4824Sbill */ 49*51346Sbostic int 5051155Sbostic lfs_init() 5124Sbill { 5224Sbill register int i; 5351155Sbostic register union lfsihead *ih = lfsihead; 5424Sbill 5551155Sbostic printf("lfs_init\n"); 5651215Sbostic 5739492Smckusick #ifndef lint 5839392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 5939392Smckusick panic("ihinit: too small"); 6051215Sbostic #endif 6151215Sbostic lock_init(&lfs_sync_lock, 1); 6251215Sbostic 637334Skre for (i = INOHSZ; --i >= 0; ih++) { 647334Skre ih->ih_head[0] = ih; 657334Skre ih->ih_head[1] = ih; 667334Skre } 6751155Sbostic #ifdef NOTLFS /* LFS */ 6841313Smckusick #ifdef QUOTA 6941313Smckusick dqinit(); 7041313Smckusick #endif /* QUOTA */ 7151155Sbostic #endif 72*51346Sbostic return (0); 7324Sbill } 7424Sbill 75*51346Sbostic void 7651155Sbostic lfs_hqueue(ip) 7751155Sbostic struct inode *ip; 7851155Sbostic { 7951155Sbostic union lfsihead *ih; 8051155Sbostic 8151155Sbostic ih = &lfsihead[INOHASH(ip->i_dev, ip->i_number)]; 8251155Sbostic insque(ip, ih); 8351155Sbostic ILOCK(ip); 8451155Sbostic } 8551155Sbostic 8651155Sbostic 8724Sbill /* 8849451Smckusick * Look up a UFS dinode number to find its incore vnode. 8949451Smckusick * If it is not in core, read it in from the specified device. 9049451Smckusick * If it is in core, wait for the lock bit to clear, then 9149451Smckusick * return the inode locked. Detection and handling of mount 9249451Smckusick * points must be done by the calling routine. 9324Sbill */ 94*51346Sbostic int 9551155Sbostic lfs_iget(xp, ino, ipp) 9637736Smckusick struct inode *xp; 974818Swnj ino_t ino; 9837736Smckusick struct inode **ipp; 9924Sbill { 10037736Smckusick dev_t dev = xp->i_dev; 10137736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 10251183Sbostic register LFS *fs = VFSTOUFS(mntp)->um_lfs; /* LFS */ 103*51346Sbostic extern struct vnodeops spec_inodeops; 10437736Smckusick register struct inode *ip, *iq; 10537736Smckusick register struct vnode *vp; 10639440Smckusick struct vnode *nvp; 10737736Smckusick struct buf *bp; 10851155Sbostic union lfsihead *ih; 109*51346Sbostic int error; 11024Sbill 11151155Sbostic printf("lfs_iget ino %d\n", ino); 11251155Sbostic ih = &lfsihead[INOHASH(dev, ino)]; 11324Sbill loop: 11439392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 11539392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 11639392Smckusick continue; 11739392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 11839392Smckusick ip->i_flag |= IWANT; 11939392Smckusick sleep((caddr_t)ip, PINOD); 12039392Smckusick goto loop; 12139392Smckusick } 12239440Smckusick if (vget(ITOV(ip))) 12339440Smckusick goto loop; 12439392Smckusick *ipp = ip; 12539392Smckusick return(0); 12639392Smckusick } 12751155Sbostic 12851155Sbostic /* Allocate new vnode/inode. */ 12951155Sbostic error = lfs_vcreate(mntp, ino, &nvp); 13051155Sbostic if (error) { 13137736Smckusick *ipp = 0; 13237736Smckusick return (error); 13337736Smckusick } 13439440Smckusick ip = VTOI(nvp); 13551155Sbostic 13637736Smckusick /* 13739440Smckusick * Put it onto its hash chain and lock it so that other requests for 13839440Smckusick * this inode will block if they arrive while we are sleeping waiting 13939440Smckusick * for old data structures to be purged or for the contents of the 14039440Smckusick * disk portion of this inode to be read. 14139440Smckusick */ 14239440Smckusick insque(ip, ih); 14339440Smckusick ILOCK(ip); 14451155Sbostic 14551155Sbostic /* Read in the disk contents for the inode, copy into the vnode. */ 14651155Sbostic if (error = bread(VFSTOUFS(mntp)->um_devvp, itod(fs, ino), 14751155Sbostic (int)fs->lfs_bsize, NOCRED, &bp)) { /* LFS */ 14837736Smckusick /* 14941334Smckusick * The inode does not contain anything useful, so it would 15041334Smckusick * be misleading to leave it on its hash chain. 15141334Smckusick * Iput() will take care of putting it back on the free list. 15241334Smckusick */ 15341334Smckusick remque(ip); 15441334Smckusick ip->i_forw = ip; 15541334Smckusick ip->i_back = ip; 15641334Smckusick /* 15739392Smckusick * Unlock and discard unneeded inode. 15837736Smckusick */ 15939440Smckusick iput(ip); 16037736Smckusick brelse(bp); 16137736Smckusick *ipp = 0; 16239440Smckusick return (error); 16337736Smckusick } 16451155Sbostic ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino); 16539440Smckusick brelse(bp); 16651155Sbostic 16737736Smckusick /* 16839440Smckusick * Initialize the associated vnode 16937736Smckusick */ 17039440Smckusick vp = ITOV(ip); 17139440Smckusick vp->v_type = IFTOVT(ip->i_mode); 17240289Smckusick if (vp->v_type == VFIFO) { 17340289Smckusick #ifdef FIFO 17440289Smckusick extern struct vnodeops fifo_inodeops; 17540289Smckusick vp->v_op = &fifo_inodeops; 17640289Smckusick #else 17740289Smckusick iput(ip); 17840289Smckusick *ipp = 0; 17940289Smckusick return (EOPNOTSUPP); 18040289Smckusick #endif /* FIFO */ 18140289Smckusick } 18239440Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 18339440Smckusick vp->v_op = &spec_inodeops; 18439617Smckusick if (nvp = checkalias(vp, ip->i_rdev, mntp)) { 18537736Smckusick /* 18639440Smckusick * Reinitialize aliased inode. 18737736Smckusick */ 18839440Smckusick vp = nvp; 18939440Smckusick iq = VTOI(vp); 19039440Smckusick iq->i_vnode = vp; 19139517Smckusick iq->i_flag = 0; 19239440Smckusick ILOCK(iq); 19339440Smckusick iq->i_din = ip->i_din; 19439440Smckusick iq->i_dev = dev; 19539440Smckusick iq->i_number = ino; 19639440Smckusick insque(iq, ih); 19737736Smckusick /* 19839440Smckusick * Discard unneeded vnode 19937736Smckusick */ 20039440Smckusick ip->i_mode = 0; 20139440Smckusick iput(ip); 20237736Smckusick ip = iq; 20337736Smckusick } 20437736Smckusick } 20539440Smckusick if (ino == ROOTINO) 20639440Smckusick vp->v_flag |= VROOT; 20751155Sbostic 20838345Smckusick VREF(ip->i_devvp); 20951155Sbostic 21037736Smckusick *ipp = ip; 21137736Smckusick return (0); 21237736Smckusick } 2137334Skre 21437736Smckusick /* 21539392Smckusick * Last reference to an inode, write the inode out and if necessary, 21639392Smckusick * truncate and deallocate the file. 21739392Smckusick */ 218*51346Sbostic int 21951155Sbostic lfs_inactive(vp, p) 22037736Smckusick struct vnode *vp; 22148037Smckusick struct proc *p; 2227118Smckusick { 22337736Smckusick register struct inode *ip = VTOI(vp); 22439392Smckusick int mode, error = 0; 22524Sbill 22651155Sbostic printf("lfs_inactive: ino %d mode %d nlink %d\n", 22751155Sbostic ip->i_number, ip->i_mode, ip->i_nlink); 22851155Sbostic 22939816Smckusick if (prtactive && vp->v_usecount != 0) 23039676Smckusick vprint("ufs_inactive: pushing active", vp); 23138452Smckusick /* 23238452Smckusick * Get rid of inodes related to stale file handles. 23338452Smckusick */ 23439440Smckusick if (ip->i_mode == 0) { 23539676Smckusick if ((vp->v_flag & VXLOCK) == 0) 23639676Smckusick vgone(vp); 23739440Smckusick return (0); 23839440Smckusick } 23938226Smckusick ILOCK(ip); 24041397Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 24141313Smckusick #ifdef QUOTA 24241313Smckusick if (!getinoquota(ip)) 24341313Smckusick (void) chkiq(ip, -1, NOCRED, 0); 24441313Smckusick #endif 24551155Sbostic error = lfs_itrunc(ip, (u_long)0, 0); /* LFS */ 24637736Smckusick mode = ip->i_mode; 24737736Smckusick ip->i_mode = 0; 24844893Strent ip->i_rdev = 0; 24937736Smckusick ip->i_flag |= IUPD|ICHG; 25051155Sbostic #ifdef NOTLFS /* LFS */ 25137736Smckusick ifree(ip, ip->i_number, mode); 25251155Sbostic #else 25351155Sbostic lfs_ifree(ip); 25451155Sbostic #endif 25537736Smckusick } 25651155Sbostic ITIMES(ip, &time, &time); 25740033Smckusick IUNLOCK(ip); 25840033Smckusick ip->i_flag = 0; 25937736Smckusick /* 26039392Smckusick * If we are done with the inode, reclaim it 26139392Smckusick * so that it can be reused immediately. 26237736Smckusick */ 26341313Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 26440033Smckusick vgone(vp); 26537736Smckusick return (error); 26624Sbill } 26724Sbill 26810736Ssam #define SINGLE 0 /* index of single indirect block */ 26910736Ssam #define DOUBLE 1 /* index of double indirect block */ 27010736Ssam #define TRIPLE 2 /* index of triple indirect block */ 27124Sbill /* 27239392Smckusick * Truncate the inode ip to at most length size. Free affected disk 27339392Smckusick * blocks -- the blocks of the file are removed in reverse order. 27410736Ssam * 27510736Ssam * NB: triple indirect blocks are untested. 27624Sbill */ 27751155Sbostic lfs_itrunc(oip, length, flags) 27817942Smckusick register struct inode *oip; 2799165Ssam u_long length; 28039676Smckusick int flags; 28124Sbill { 2829165Ssam register daddr_t lastblock; 28326272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 28451183Sbostic register LFS *fs; /* LFS */ 28510736Ssam register struct inode *ip; 28617942Smckusick struct buf *bp; 28737736Smckusick int offset, osize, size, level; 28837736Smckusick long count, nblocks, blocksreleased = 0; 28917942Smckusick register int i; 29039676Smckusick int aflags, error, allerror; 29110736Ssam struct inode tip; 2929165Ssam 29345721Smckusick vnode_pager_setsize(ITOV(oip), length); 29413000Ssam if (oip->i_size <= length) { 29513000Ssam oip->i_flag |= ICHG|IUPD; 29651183Sbostic ITIMES(oip, &time, &time); 29751183Sbostic return (0); 29813000Ssam } 2991203Sbill /* 30010736Ssam * Calculate index into inode's block list of 30110736Ssam * last direct and indirect blocks (if any) 30210736Ssam * which we want to keep. Lastblock is -1 when 30310736Ssam * the file is truncated to 0. 3041203Sbill */ 30551183Sbostic fs = oip->i_lfs; /* LFS */ 30651183Sbostic lastblock = lblkno(fs, length + fs->lfs_bsize - 1) - 1; /* LFS */ 30710736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 30810736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 30910736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 31051183Sbostic nblocks = btodb(fs->lfs_bsize); /* LFS */ 3116569Smckusic /* 31217942Smckusick * Update the size of the file. If the file is not being 31317942Smckusick * truncated to a block boundry, the contents of the 31417942Smckusick * partial block following the end of the file must be 31517942Smckusick * zero'ed in case it ever become accessable again because 31617942Smckusick * of subsequent file growth. 31717942Smckusick */ 31817942Smckusick osize = oip->i_size; 31917942Smckusick offset = blkoff(fs, length); 32017942Smckusick if (offset == 0) { 32117942Smckusick oip->i_size = length; 32217942Smckusick } else { 32317942Smckusick lbn = lblkno(fs, length); 32439676Smckusick aflags = B_CLRBUF; 32539676Smckusick if (flags & IO_SYNC) 32639676Smckusick aflags |= B_SYNC; 32741313Smckusick #ifdef QUOTA 32841313Smckusick if (error = getinoquota(oip)) 32941313Smckusick return (error); 33051183Sbostic #endif 33151183Sbostic if (error = bread(ITOV(oip), lbn, fs->lfs_bsize, NOCRED, &bp)) 33237736Smckusick return (error); 33317942Smckusick oip->i_size = length; 33451155Sbostic size = blksize(fs); /* LFS */ 33545721Smckusick (void) vnode_pager_uncache(ITOV(oip)); 33626272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 33745112Smckusick allocbuf(bp, size); 33851183Sbostic #ifdef NOTLFS 33951183Sbostic if (flags & IO_SYNC) /* LFS */ 34039676Smckusick bwrite(bp); 34139676Smckusick else 34239676Smckusick bdwrite(bp); 34351183Sbostic #else 34451183Sbostic lfs_bwrite(bp); 34551183Sbostic #endif 34617942Smckusick } 34717942Smckusick /* 34817942Smckusick * Update file and block pointers 34910736Ssam * on disk before we start freeing blocks. 35010736Ssam * If we crash before free'ing blocks below, 35110736Ssam * the blocks will be returned to the free list. 35210736Ssam * lastiblock values are also normalized to -1 35310736Ssam * for calls to indirtrunc below. 3546569Smckusic */ 35551183Sbostic /* Will need to modify the segment usage information */ /* LFS */ 35610736Ssam tip = *oip; 35717942Smckusick tip.i_size = osize; 35810736Ssam for (level = TRIPLE; level >= SINGLE; level--) 35910736Ssam if (lastiblock[level] < 0) { 36010736Ssam oip->i_ib[level] = 0; 36110736Ssam lastiblock[level] = -1; 3629165Ssam } 36310736Ssam for (i = NDADDR - 1; i > lastblock; i--) 36410736Ssam oip->i_db[i] = 0; 36510736Ssam oip->i_flag |= ICHG|IUPD; 36651183Sbostic #ifdef NOTLFS 36739676Smckusick vinvalbuf(ITOV(oip), (length > 0)); 36851183Sbostic allerror = ITIMES(oip, &time, &time); 36951183Sbostic #else 37051183Sbostic /* Need lfs_vinvalbuf to get rid of invalid buffers in the cache */ 37151183Sbostic ITIMES(oip, &time, &time); 37251183Sbostic allerror = 0; 37351183Sbostic #endif 37410736Ssam 37551183Sbostic #ifdef NOTLFS 3766569Smckusic /* 37710736Ssam * Indirect blocks first. 3786569Smckusic */ 37917942Smckusick ip = &tip; 38010736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 38110736Ssam bn = ip->i_ib[level]; 3829165Ssam if (bn != 0) { 38337736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 38437736Smckusick &count); 38537736Smckusick if (error) 38637736Smckusick allerror = error; 38737736Smckusick blocksreleased += count; 38810736Ssam if (lastiblock[level] < 0) { 38910736Ssam ip->i_ib[level] = 0; 39031402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 39110736Ssam blocksreleased += nblocks; 39210736Ssam } 39310736Ssam } 39410736Ssam if (lastiblock[level] >= 0) 39510736Ssam goto done; 3969165Ssam } 39751183Sbostic #else 39851183Sbostic /* LFS -- not yet implemented. Need to rewrite indirect blocks */ 39951183Sbostic panic("lfs_itrunc: not yet implemented"); 40051183Sbostic #endif 40110736Ssam 4026569Smckusic /* 40310736Ssam * All whole direct blocks or frags. 4046569Smckusic */ 4059165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 40626359Skarels register off_t bsize; 4079165Ssam 4086569Smckusic bn = ip->i_db[i]; 4099165Ssam if (bn == 0) 41024Sbill continue; 4119165Ssam ip->i_db[i] = 0; 41251155Sbostic bsize = (off_t)blksize(fs); /* LFS */ 41351183Sbostic #ifdef NOTLFS 41431402Smckusick blkfree(ip, bn, bsize); 41551183Sbostic #else 41651183Sbostic /* LFS Update segment usage information */ 41751183Sbostic #endif 41824525Sbloom blocksreleased += btodb(bsize); 41924Sbill } 42010736Ssam if (lastblock < 0) 42110736Ssam goto done; 42210736Ssam 4231203Sbill /* 4249165Ssam * Finally, look for a change in size of the 4259165Ssam * last direct block; release any frags. 4261203Sbill */ 42710736Ssam bn = ip->i_db[lastblock]; 42810736Ssam if (bn != 0) { 42926359Skarels off_t oldspace, newspace; 43010736Ssam 4319165Ssam /* 4329165Ssam * Calculate amount of space we're giving 4339165Ssam * back as old block size minus new block size. 4349165Ssam */ 43551155Sbostic oldspace = blksize(fs); /* LFS */ 4369165Ssam ip->i_size = length; 43751155Sbostic newspace = blksize(fs); /* LFS */ 43810736Ssam if (newspace == 0) 43951155Sbostic panic("lfs_itrunc: newspace"); 44010736Ssam if (oldspace - newspace > 0) { 4419165Ssam /* 4429165Ssam * Block number of space to be free'd is 4439165Ssam * the old block # plus the number of frags 4449165Ssam * required for the storage we're keeping. 4459165Ssam */ 44610736Ssam bn += numfrags(fs, newspace); 44731402Smckusick blkfree(ip, bn, oldspace - newspace); 44812645Ssam blocksreleased += btodb(oldspace - newspace); 4499165Ssam } 4509165Ssam } 4519165Ssam done: 45210736Ssam /* BEGIN PARANOIA */ 45310736Ssam for (level = SINGLE; level <= TRIPLE; level++) 45410736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 45551155Sbostic panic("lfs_itrunc1"); 45610736Ssam for (i = 0; i < NDADDR; i++) 45710736Ssam if (ip->i_db[i] != oip->i_db[i]) 45851155Sbostic panic("lfs_itrunc2"); 45910736Ssam /* END PARANOIA */ 46012645Ssam oip->i_blocks -= blocksreleased; 46112645Ssam if (oip->i_blocks < 0) /* sanity */ 46212645Ssam oip->i_blocks = 0; 46312645Ssam oip->i_flag |= ICHG; 4649165Ssam #ifdef QUOTA 46541313Smckusick if (!getinoquota(oip)) 46641313Smckusick (void) chkdq(oip, -blocksreleased, NOCRED, 0); 4679165Ssam #endif 46837736Smckusick return (allerror); 46924Sbill } 47024Sbill 4719165Ssam /* 4729165Ssam * Release blocks associated with the inode ip and 4739165Ssam * stored in the indirect block bn. Blocks are free'd 4749165Ssam * in LIFO order up to (but not including) lastbn. If 47510736Ssam * level is greater than SINGLE, the block is an indirect 47610736Ssam * block and recursive calls to indirtrunc must be used to 47710736Ssam * cleanse other indirect blocks. 47810736Ssam * 47910736Ssam * NB: triple indirect blocks are untested. 4809165Ssam */ 48151155Sbostic lfs_indirtrunc(ip, bn, lastbn, level, countp) 4826569Smckusic register struct inode *ip; 4839165Ssam daddr_t bn, lastbn; 48410736Ssam int level; 48537736Smckusick long *countp; 48624Sbill { 48751155Sbostic #ifdef NOTLFS 4889165Ssam register int i; 48931661Smckusick struct buf *bp; 49031661Smckusick register struct fs *fs = ip->i_fs; 49124Sbill register daddr_t *bap; 49231661Smckusick daddr_t *copy, nb, last; 49337736Smckusick long blkcount, factor; 49437736Smckusick int nblocks, blocksreleased = 0; 49537736Smckusick int error, allerror = 0; 49624Sbill 49710736Ssam /* 49810736Ssam * Calculate index in current block of last 49910736Ssam * block to be kept. -1 indicates the entire 50010736Ssam * block so we need not calculate the index. 50110736Ssam */ 50210736Ssam factor = 1; 50310736Ssam for (i = SINGLE; i < level; i++) 50410736Ssam factor *= NINDIR(fs); 5059165Ssam last = lastbn; 50610736Ssam if (lastbn > 0) 50710736Ssam last /= factor; 50812645Ssam nblocks = btodb(fs->fs_bsize); 50910736Ssam /* 51010736Ssam * Get buffer of block pointers, zero those 51110736Ssam * entries corresponding to blocks to be free'd, 51210736Ssam * and update on disk copy first. 51310736Ssam */ 51438776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 51538776Smckusick NOCRED, &bp); 51637736Smckusick if (error) { 51710736Ssam brelse(bp); 51837736Smckusick *countp = 0; 51937736Smckusick return (error); 52010736Ssam } 52110736Ssam bap = bp->b_un.b_daddr; 52231661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 52331661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 52410736Ssam bzero((caddr_t)&bap[last + 1], 52510736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 52639676Smckusick if (last == -1) 52739676Smckusick bp->b_flags |= B_INVAL; 52837736Smckusick error = bwrite(bp); 52937736Smckusick if (error) 53037736Smckusick allerror = error; 53131661Smckusick bap = copy; 53210736Ssam 53310736Ssam /* 53410736Ssam * Recursively free totally unused blocks. 53510736Ssam */ 5369165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 53724Sbill nb = bap[i]; 5389165Ssam if (nb == 0) 53924Sbill continue; 54037736Smckusick if (level > SINGLE) { 54137736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 54237736Smckusick &blkcount); 54337736Smckusick if (error) 54437736Smckusick allerror = error; 54537736Smckusick blocksreleased += blkcount; 54637736Smckusick } 54731402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 5489165Ssam blocksreleased += nblocks; 54924Sbill } 55010736Ssam 55110736Ssam /* 55210736Ssam * Recursively free last partial block. 55310736Ssam */ 55410736Ssam if (level > SINGLE && lastbn >= 0) { 55510736Ssam last = lastbn % factor; 5569165Ssam nb = bap[i]; 55737736Smckusick if (nb != 0) { 55837736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 55937736Smckusick if (error) 56037736Smckusick allerror = error; 56137736Smckusick blocksreleased += blkcount; 56237736Smckusick } 5639165Ssam } 56431661Smckusick FREE(copy, M_TEMP); 56537736Smckusick *countp = blocksreleased; 56637736Smckusick return (allerror); 56751155Sbostic #else 56851155Sbostic /* LFS IMPLEMENT -- lfs_indirtrunc */ 56951155Sbostic panic("lfs_indirtrunc not implemented"); 57051155Sbostic #endif 57124Sbill } 57251215Sbostic #endif /* LOGFS */ 573