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*51183Sbostic * @(#)lfs_inode.c 7.42 (Berkeley) 09/25/91 823399Smckusick */ 924Sbill 1017099Sbloom #include "param.h" 1117099Sbloom #include "systm.h" 1217099Sbloom #include "mount.h" 1339795Smckusick #include "proc.h" 1437736Smckusick #include "file.h" 1517099Sbloom #include "buf.h" 1637736Smckusick #include "vnode.h" 1717099Sbloom #include "kernel.h" 1831661Smckusick #include "malloc.h" 1924Sbill 2051155Sbostic #include "../ufs/quota.h" 2151155Sbostic #include "../ufs/inode.h" 2251155Sbostic #include "../ufs/ufsmount.h" 2351155Sbostic #include "lfs.h" 2451155Sbostic #include "lfs_extern.h" 2547571Skarels 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 3351155Sbostic union lfsihead { /* LFS */ 3451155Sbostic union lfsihead *ih_head[2]; 357334Skre struct inode *ih_chain[2]; 3651155Sbostic } lfsihead[INOHSZ]; 377334Skre 3851155Sbostic /* LFS */ 3951155Sbostic extern int prtactive; /* 1 => print out reclaim of active vnodes */ 4039574Smckusick 4124Sbill /* 4239392Smckusick * Initialize hash links for inodes. 4324Sbill */ 4451155Sbostic lfs_init() 4524Sbill { 4624Sbill register int i; 4751155Sbostic register union lfsihead *ih = lfsihead; 4824Sbill 4951155Sbostic printf("lfs_init\n"); 5039492Smckusick #ifndef lint 5139392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 5239392Smckusick panic("ihinit: too small"); 5339492Smckusick #endif /* not lint */ 547334Skre for (i = INOHSZ; --i >= 0; ih++) { 557334Skre ih->ih_head[0] = ih; 567334Skre ih->ih_head[1] = ih; 577334Skre } 5851155Sbostic #ifdef NOTLFS /* LFS */ 5941313Smckusick #ifdef QUOTA 6041313Smckusick dqinit(); 6141313Smckusick #endif /* QUOTA */ 6251155Sbostic #endif 6324Sbill } 6424Sbill 6551155Sbostic lfs_hqueue(ip) 6651155Sbostic struct inode *ip; 6751155Sbostic { 6851155Sbostic union lfsihead *ih; 6951155Sbostic 7051155Sbostic printf("lfs_hqueue ino %d\n", ip->i_number); 7151155Sbostic ih = &lfsihead[INOHASH(ip->i_dev, ip->i_number)]; 7251155Sbostic insque(ip, ih); 7351155Sbostic ILOCK(ip); 7451155Sbostic } 7551155Sbostic 7651155Sbostic 7724Sbill /* 7849451Smckusick * Look up a UFS dinode number to find its incore vnode. 7949451Smckusick * If it is not in core, read it in from the specified device. 8049451Smckusick * If it is in core, wait for the lock bit to clear, then 8149451Smckusick * return the inode locked. Detection and handling of mount 8249451Smckusick * points must be done by the calling routine. 8324Sbill */ 8451155Sbostic lfs_iget(xp, ino, ipp) 8537736Smckusick struct inode *xp; 864818Swnj ino_t ino; 8737736Smckusick struct inode **ipp; 8824Sbill { 8937736Smckusick dev_t dev = xp->i_dev; 9037736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 91*51183Sbostic register LFS *fs = VFSTOUFS(mntp)->um_lfs; /* LFS */ 9239440Smckusick extern struct vnodeops ufs_vnodeops, spec_inodeops; 9337736Smckusick register struct inode *ip, *iq; 9437736Smckusick register struct vnode *vp; 9539440Smckusick struct vnode *nvp; 9637736Smckusick struct buf *bp; 9751155Sbostic union lfsihead *ih; 9841313Smckusick int i, error; 9924Sbill 10051155Sbostic printf("lfs_iget ino %d\n", ino); 10151155Sbostic ih = &lfsihead[INOHASH(dev, ino)]; 10224Sbill loop: 10339392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 10439392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 10539392Smckusick continue; 10639392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 10739392Smckusick ip->i_flag |= IWANT; 10839392Smckusick sleep((caddr_t)ip, PINOD); 10939392Smckusick goto loop; 11039392Smckusick } 11139440Smckusick if (vget(ITOV(ip))) 11239440Smckusick goto loop; 11339392Smckusick *ipp = ip; 11439392Smckusick return(0); 11539392Smckusick } 11651155Sbostic 11751155Sbostic /* Allocate new vnode/inode. */ 11851155Sbostic error = lfs_vcreate(mntp, ino, &nvp); 11951155Sbostic if (error) { 12037736Smckusick *ipp = 0; 12137736Smckusick return (error); 12237736Smckusick } 12339440Smckusick ip = VTOI(nvp); 12451155Sbostic 12537736Smckusick /* 12639440Smckusick * Put it onto its hash chain and lock it so that other requests for 12739440Smckusick * this inode will block if they arrive while we are sleeping waiting 12839440Smckusick * for old data structures to be purged or for the contents of the 12939440Smckusick * disk portion of this inode to be read. 13039440Smckusick */ 13139440Smckusick insque(ip, ih); 13239440Smckusick ILOCK(ip); 13351155Sbostic 13451155Sbostic /* Read in the disk contents for the inode, copy into the vnode. */ 13551155Sbostic if (error = bread(VFSTOUFS(mntp)->um_devvp, itod(fs, ino), 13651155Sbostic (int)fs->lfs_bsize, NOCRED, &bp)) { /* LFS */ 13737736Smckusick /* 13841334Smckusick * The inode does not contain anything useful, so it would 13941334Smckusick * be misleading to leave it on its hash chain. 14041334Smckusick * Iput() will take care of putting it back on the free list. 14141334Smckusick */ 14241334Smckusick remque(ip); 14341334Smckusick ip->i_forw = ip; 14441334Smckusick ip->i_back = ip; 14541334Smckusick /* 14639392Smckusick * Unlock and discard unneeded inode. 14737736Smckusick */ 14839440Smckusick iput(ip); 14937736Smckusick brelse(bp); 15037736Smckusick *ipp = 0; 15139440Smckusick return (error); 15237736Smckusick } 15351155Sbostic ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino); 15439440Smckusick brelse(bp); 15551155Sbostic 15637736Smckusick /* 15739440Smckusick * Initialize the associated vnode 15837736Smckusick */ 15939440Smckusick vp = ITOV(ip); 16039440Smckusick vp->v_type = IFTOVT(ip->i_mode); 16140289Smckusick if (vp->v_type == VFIFO) { 16240289Smckusick #ifdef FIFO 16340289Smckusick extern struct vnodeops fifo_inodeops; 16440289Smckusick vp->v_op = &fifo_inodeops; 16540289Smckusick #else 16640289Smckusick iput(ip); 16740289Smckusick *ipp = 0; 16840289Smckusick return (EOPNOTSUPP); 16940289Smckusick #endif /* FIFO */ 17040289Smckusick } 17139440Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 17239440Smckusick vp->v_op = &spec_inodeops; 17339617Smckusick if (nvp = checkalias(vp, ip->i_rdev, mntp)) { 17437736Smckusick /* 17539440Smckusick * Reinitialize aliased inode. 17637736Smckusick */ 17739440Smckusick vp = nvp; 17839440Smckusick iq = VTOI(vp); 17939440Smckusick iq->i_vnode = vp; 18039517Smckusick iq->i_flag = 0; 18139440Smckusick ILOCK(iq); 18239440Smckusick iq->i_din = ip->i_din; 18339440Smckusick iq->i_dev = dev; 18439440Smckusick iq->i_number = ino; 18539440Smckusick insque(iq, ih); 18637736Smckusick /* 18739440Smckusick * Discard unneeded vnode 18837736Smckusick */ 18939440Smckusick ip->i_mode = 0; 19039440Smckusick iput(ip); 19137736Smckusick ip = iq; 19237736Smckusick } 19337736Smckusick } 19439440Smckusick if (ino == ROOTINO) 19539440Smckusick vp->v_flag |= VROOT; 19651155Sbostic 19738345Smckusick VREF(ip->i_devvp); 19851155Sbostic 19937736Smckusick *ipp = ip; 20037736Smckusick return (0); 20137736Smckusick } 2027334Skre 20337736Smckusick /* 20439392Smckusick * Last reference to an inode, write the inode out and if necessary, 20539392Smckusick * truncate and deallocate the file. 20639392Smckusick */ 20751155Sbostic lfs_inactive(vp, p) 20837736Smckusick struct vnode *vp; 20948037Smckusick struct proc *p; 2107118Smckusick { 21137736Smckusick register struct inode *ip = VTOI(vp); 21239392Smckusick int mode, error = 0; 21324Sbill 21451155Sbostic printf("lfs_inactive: ino %d mode %d nlink %d\n", 21551155Sbostic ip->i_number, ip->i_mode, ip->i_nlink); 21651155Sbostic 21739816Smckusick if (prtactive && vp->v_usecount != 0) 21839676Smckusick vprint("ufs_inactive: pushing active", vp); 21938452Smckusick /* 22038452Smckusick * Get rid of inodes related to stale file handles. 22138452Smckusick */ 22239440Smckusick if (ip->i_mode == 0) { 22339676Smckusick if ((vp->v_flag & VXLOCK) == 0) 22439676Smckusick vgone(vp); 22539440Smckusick return (0); 22639440Smckusick } 22738226Smckusick ILOCK(ip); 22841397Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 22941313Smckusick #ifdef QUOTA 23041313Smckusick if (!getinoquota(ip)) 23141313Smckusick (void) chkiq(ip, -1, NOCRED, 0); 23241313Smckusick #endif 23351155Sbostic error = lfs_itrunc(ip, (u_long)0, 0); /* LFS */ 23437736Smckusick mode = ip->i_mode; 23537736Smckusick ip->i_mode = 0; 23644893Strent ip->i_rdev = 0; 23737736Smckusick ip->i_flag |= IUPD|ICHG; 23851155Sbostic #ifdef NOTLFS /* LFS */ 23937736Smckusick ifree(ip, ip->i_number, mode); 24051155Sbostic #else 24151155Sbostic lfs_ifree(ip); 24251155Sbostic #endif 24337736Smckusick } 24451155Sbostic ITIMES(ip, &time, &time); 24540033Smckusick IUNLOCK(ip); 24640033Smckusick ip->i_flag = 0; 24737736Smckusick /* 24839392Smckusick * If we are done with the inode, reclaim it 24939392Smckusick * so that it can be reused immediately. 25037736Smckusick */ 25141313Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 25240033Smckusick vgone(vp); 25337736Smckusick return (error); 25424Sbill } 25524Sbill 25610736Ssam #define SINGLE 0 /* index of single indirect block */ 25710736Ssam #define DOUBLE 1 /* index of double indirect block */ 25810736Ssam #define TRIPLE 2 /* index of triple indirect block */ 25924Sbill /* 26039392Smckusick * Truncate the inode ip to at most length size. Free affected disk 26139392Smckusick * blocks -- the blocks of the file are removed in reverse order. 26210736Ssam * 26310736Ssam * NB: triple indirect blocks are untested. 26424Sbill */ 26551155Sbostic lfs_itrunc(oip, length, flags) 26617942Smckusick register struct inode *oip; 2679165Ssam u_long length; 26839676Smckusick int flags; 26924Sbill { 2709165Ssam register daddr_t lastblock; 27126272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 272*51183Sbostic register LFS *fs; /* LFS */ 27310736Ssam register struct inode *ip; 27417942Smckusick struct buf *bp; 27537736Smckusick int offset, osize, size, level; 27637736Smckusick long count, nblocks, blocksreleased = 0; 27717942Smckusick register int i; 27839676Smckusick int aflags, error, allerror; 27910736Ssam struct inode tip; 2809165Ssam 28145721Smckusick vnode_pager_setsize(ITOV(oip), length); 28213000Ssam if (oip->i_size <= length) { 28313000Ssam oip->i_flag |= ICHG|IUPD; 284*51183Sbostic ITIMES(oip, &time, &time); 285*51183Sbostic return (0); 28613000Ssam } 2871203Sbill /* 28810736Ssam * Calculate index into inode's block list of 28910736Ssam * last direct and indirect blocks (if any) 29010736Ssam * which we want to keep. Lastblock is -1 when 29110736Ssam * the file is truncated to 0. 2921203Sbill */ 293*51183Sbostic fs = oip->i_lfs; /* LFS */ 294*51183Sbostic lastblock = lblkno(fs, length + fs->lfs_bsize - 1) - 1; /* LFS */ 29510736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 29610736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 29710736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 298*51183Sbostic nblocks = btodb(fs->lfs_bsize); /* LFS */ 2996569Smckusic /* 30017942Smckusick * Update the size of the file. If the file is not being 30117942Smckusick * truncated to a block boundry, the contents of the 30217942Smckusick * partial block following the end of the file must be 30317942Smckusick * zero'ed in case it ever become accessable again because 30417942Smckusick * of subsequent file growth. 30517942Smckusick */ 30617942Smckusick osize = oip->i_size; 30717942Smckusick offset = blkoff(fs, length); 30817942Smckusick if (offset == 0) { 30917942Smckusick oip->i_size = length; 31017942Smckusick } else { 31117942Smckusick lbn = lblkno(fs, length); 31239676Smckusick aflags = B_CLRBUF; 31339676Smckusick if (flags & IO_SYNC) 31439676Smckusick aflags |= B_SYNC; 31541313Smckusick #ifdef QUOTA 31641313Smckusick if (error = getinoquota(oip)) 31741313Smckusick return (error); 318*51183Sbostic #endif 319*51183Sbostic if (error = bread(ITOV(oip), lbn, fs->lfs_bsize, NOCRED, &bp)) 32037736Smckusick return (error); 32117942Smckusick oip->i_size = length; 32251155Sbostic size = blksize(fs); /* LFS */ 32345721Smckusick (void) vnode_pager_uncache(ITOV(oip)); 32426272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 32545112Smckusick allocbuf(bp, size); 326*51183Sbostic #ifdef NOTLFS 327*51183Sbostic if (flags & IO_SYNC) /* LFS */ 32839676Smckusick bwrite(bp); 32939676Smckusick else 33039676Smckusick bdwrite(bp); 331*51183Sbostic #else 332*51183Sbostic lfs_bwrite(bp); 333*51183Sbostic #endif 33417942Smckusick } 33517942Smckusick /* 33617942Smckusick * Update file and block pointers 33710736Ssam * on disk before we start freeing blocks. 33810736Ssam * If we crash before free'ing blocks below, 33910736Ssam * the blocks will be returned to the free list. 34010736Ssam * lastiblock values are also normalized to -1 34110736Ssam * for calls to indirtrunc below. 3426569Smckusic */ 343*51183Sbostic /* Will need to modify the segment usage information */ /* LFS */ 34410736Ssam tip = *oip; 34517942Smckusick tip.i_size = osize; 34610736Ssam for (level = TRIPLE; level >= SINGLE; level--) 34710736Ssam if (lastiblock[level] < 0) { 34810736Ssam oip->i_ib[level] = 0; 34910736Ssam lastiblock[level] = -1; 3509165Ssam } 35110736Ssam for (i = NDADDR - 1; i > lastblock; i--) 35210736Ssam oip->i_db[i] = 0; 35310736Ssam oip->i_flag |= ICHG|IUPD; 354*51183Sbostic #ifdef NOTLFS 35539676Smckusick vinvalbuf(ITOV(oip), (length > 0)); 356*51183Sbostic allerror = ITIMES(oip, &time, &time); 357*51183Sbostic #else 358*51183Sbostic /* Need lfs_vinvalbuf to get rid of invalid buffers in the cache */ 359*51183Sbostic ITIMES(oip, &time, &time); 360*51183Sbostic allerror = 0; 361*51183Sbostic #endif 36210736Ssam 363*51183Sbostic #ifdef NOTLFS 3646569Smckusic /* 36510736Ssam * Indirect blocks first. 3666569Smckusic */ 36717942Smckusick ip = &tip; 36810736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 36910736Ssam bn = ip->i_ib[level]; 3709165Ssam if (bn != 0) { 37137736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 37237736Smckusick &count); 37337736Smckusick if (error) 37437736Smckusick allerror = error; 37537736Smckusick blocksreleased += count; 37610736Ssam if (lastiblock[level] < 0) { 37710736Ssam ip->i_ib[level] = 0; 37831402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 37910736Ssam blocksreleased += nblocks; 38010736Ssam } 38110736Ssam } 38210736Ssam if (lastiblock[level] >= 0) 38310736Ssam goto done; 3849165Ssam } 385*51183Sbostic #else 386*51183Sbostic /* LFS -- not yet implemented. Need to rewrite indirect blocks */ 387*51183Sbostic panic("lfs_itrunc: not yet implemented"); 388*51183Sbostic #endif 38910736Ssam 3906569Smckusic /* 39110736Ssam * All whole direct blocks or frags. 3926569Smckusic */ 3939165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 39426359Skarels register off_t bsize; 3959165Ssam 3966569Smckusic bn = ip->i_db[i]; 3979165Ssam if (bn == 0) 39824Sbill continue; 3999165Ssam ip->i_db[i] = 0; 40051155Sbostic bsize = (off_t)blksize(fs); /* LFS */ 401*51183Sbostic #ifdef NOTLFS 40231402Smckusick blkfree(ip, bn, bsize); 403*51183Sbostic #else 404*51183Sbostic /* LFS Update segment usage information */ 405*51183Sbostic #endif 40624525Sbloom blocksreleased += btodb(bsize); 40724Sbill } 40810736Ssam if (lastblock < 0) 40910736Ssam goto done; 41010736Ssam 4111203Sbill /* 4129165Ssam * Finally, look for a change in size of the 4139165Ssam * last direct block; release any frags. 4141203Sbill */ 41510736Ssam bn = ip->i_db[lastblock]; 41610736Ssam if (bn != 0) { 41726359Skarels off_t oldspace, newspace; 41810736Ssam 4199165Ssam /* 4209165Ssam * Calculate amount of space we're giving 4219165Ssam * back as old block size minus new block size. 4229165Ssam */ 42351155Sbostic oldspace = blksize(fs); /* LFS */ 4249165Ssam ip->i_size = length; 42551155Sbostic newspace = blksize(fs); /* LFS */ 42610736Ssam if (newspace == 0) 42751155Sbostic panic("lfs_itrunc: newspace"); 42810736Ssam if (oldspace - newspace > 0) { 4299165Ssam /* 4309165Ssam * Block number of space to be free'd is 4319165Ssam * the old block # plus the number of frags 4329165Ssam * required for the storage we're keeping. 4339165Ssam */ 43410736Ssam bn += numfrags(fs, newspace); 43531402Smckusick blkfree(ip, bn, oldspace - newspace); 43612645Ssam blocksreleased += btodb(oldspace - newspace); 4379165Ssam } 4389165Ssam } 4399165Ssam done: 44010736Ssam /* BEGIN PARANOIA */ 44110736Ssam for (level = SINGLE; level <= TRIPLE; level++) 44210736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 44351155Sbostic panic("lfs_itrunc1"); 44410736Ssam for (i = 0; i < NDADDR; i++) 44510736Ssam if (ip->i_db[i] != oip->i_db[i]) 44651155Sbostic panic("lfs_itrunc2"); 44710736Ssam /* END PARANOIA */ 44812645Ssam oip->i_blocks -= blocksreleased; 44912645Ssam if (oip->i_blocks < 0) /* sanity */ 45012645Ssam oip->i_blocks = 0; 45112645Ssam oip->i_flag |= ICHG; 4529165Ssam #ifdef QUOTA 45341313Smckusick if (!getinoquota(oip)) 45441313Smckusick (void) chkdq(oip, -blocksreleased, NOCRED, 0); 4559165Ssam #endif 45637736Smckusick return (allerror); 45724Sbill } 45824Sbill 4599165Ssam /* 4609165Ssam * Release blocks associated with the inode ip and 4619165Ssam * stored in the indirect block bn. Blocks are free'd 4629165Ssam * in LIFO order up to (but not including) lastbn. If 46310736Ssam * level is greater than SINGLE, the block is an indirect 46410736Ssam * block and recursive calls to indirtrunc must be used to 46510736Ssam * cleanse other indirect blocks. 46610736Ssam * 46710736Ssam * NB: triple indirect blocks are untested. 4689165Ssam */ 46951155Sbostic lfs_indirtrunc(ip, bn, lastbn, level, countp) 4706569Smckusic register struct inode *ip; 4719165Ssam daddr_t bn, lastbn; 47210736Ssam int level; 47337736Smckusick long *countp; 47424Sbill { 47551155Sbostic #ifdef NOTLFS 4769165Ssam register int i; 47731661Smckusick struct buf *bp; 47831661Smckusick register struct fs *fs = ip->i_fs; 47924Sbill register daddr_t *bap; 48031661Smckusick daddr_t *copy, nb, last; 48137736Smckusick long blkcount, factor; 48237736Smckusick int nblocks, blocksreleased = 0; 48337736Smckusick int error, allerror = 0; 48424Sbill 48510736Ssam /* 48610736Ssam * Calculate index in current block of last 48710736Ssam * block to be kept. -1 indicates the entire 48810736Ssam * block so we need not calculate the index. 48910736Ssam */ 49010736Ssam factor = 1; 49110736Ssam for (i = SINGLE; i < level; i++) 49210736Ssam factor *= NINDIR(fs); 4939165Ssam last = lastbn; 49410736Ssam if (lastbn > 0) 49510736Ssam last /= factor; 49612645Ssam nblocks = btodb(fs->fs_bsize); 49710736Ssam /* 49810736Ssam * Get buffer of block pointers, zero those 49910736Ssam * entries corresponding to blocks to be free'd, 50010736Ssam * and update on disk copy first. 50110736Ssam */ 50238776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 50338776Smckusick NOCRED, &bp); 50437736Smckusick if (error) { 50510736Ssam brelse(bp); 50637736Smckusick *countp = 0; 50737736Smckusick return (error); 50810736Ssam } 50910736Ssam bap = bp->b_un.b_daddr; 51031661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 51131661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 51210736Ssam bzero((caddr_t)&bap[last + 1], 51310736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 51439676Smckusick if (last == -1) 51539676Smckusick bp->b_flags |= B_INVAL; 51637736Smckusick error = bwrite(bp); 51737736Smckusick if (error) 51837736Smckusick allerror = error; 51931661Smckusick bap = copy; 52010736Ssam 52110736Ssam /* 52210736Ssam * Recursively free totally unused blocks. 52310736Ssam */ 5249165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 52524Sbill nb = bap[i]; 5269165Ssam if (nb == 0) 52724Sbill continue; 52837736Smckusick if (level > SINGLE) { 52937736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 53037736Smckusick &blkcount); 53137736Smckusick if (error) 53237736Smckusick allerror = error; 53337736Smckusick blocksreleased += blkcount; 53437736Smckusick } 53531402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 5369165Ssam blocksreleased += nblocks; 53724Sbill } 53810736Ssam 53910736Ssam /* 54010736Ssam * Recursively free last partial block. 54110736Ssam */ 54210736Ssam if (level > SINGLE && lastbn >= 0) { 54310736Ssam last = lastbn % factor; 5449165Ssam nb = bap[i]; 54537736Smckusick if (nb != 0) { 54637736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 54737736Smckusick if (error) 54837736Smckusick allerror = error; 54937736Smckusick blocksreleased += blkcount; 55037736Smckusick } 5519165Ssam } 55231661Smckusick FREE(copy, M_TEMP); 55337736Smckusick *countp = blocksreleased; 55437736Smckusick return (allerror); 55551155Sbostic #else 55651155Sbostic /* LFS IMPLEMENT -- lfs_indirtrunc */ 55751155Sbostic panic("lfs_indirtrunc not implemented"); 55851155Sbostic #endif 55924Sbill } 560