1139778Simp/*- 212115Sdyson * modified for Lites 1.1 312115Sdyson * 412115Sdyson * Aug 1995, Godmar Back (gback@cs.utah.edu) 512115Sdyson * University of Utah, Department of Computer Science 612115Sdyson */ 7139778Simp/*- 812115Sdyson * Copyright (c) 1982, 1986, 1989, 1993 912115Sdyson * The Regents of the University of California. All rights reserved. 1012115Sdyson * 1112115Sdyson * Redistribution and use in source and binary forms, with or without 1212115Sdyson * modification, are permitted provided that the following conditions 1312115Sdyson * are met: 1412115Sdyson * 1. Redistributions of source code must retain the above copyright 1512115Sdyson * notice, this list of conditions and the following disclaimer. 1612115Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1712115Sdyson * notice, this list of conditions and the following disclaimer in the 1812115Sdyson * documentation and/or other materials provided with the distribution. 1912115Sdyson * 4. Neither the name of the University nor the names of its contributors 2012115Sdyson * may be used to endorse or promote products derived from this software 2112115Sdyson * without specific prior written permission. 2212115Sdyson * 2312115Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2412115Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2512115Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2612115Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2712115Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2812115Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2912115Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3012115Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3112115Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3212115Sdyson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3312115Sdyson * SUCH DAMAGE. 3412115Sdyson * 3593015Sbde * @(#)ffs_inode.c 8.5 (Berkeley) 12/30/93 3658345Sphk * $FreeBSD$ 3712115Sdyson */ 3812115Sdyson 3912115Sdyson#include <sys/param.h> 4012115Sdyson#include <sys/systm.h> 4112115Sdyson#include <sys/mount.h> 4260041Sphk#include <sys/bio.h> 4312115Sdyson#include <sys/buf.h> 4412115Sdyson#include <sys/vnode.h> 4512115Sdyson#include <sys/malloc.h> 46251171Sjeff#include <sys/rwlock.h> 4712115Sdyson 4812115Sdyson#include <vm/vm.h> 4912726Sbde#include <vm/vm_extern.h> 5012115Sdyson 51202283Slulf#include <fs/ext2fs/inode.h> 52202283Slulf#include <fs/ext2fs/ext2_mount.h> 53202283Slulf#include <fs/ext2fs/ext2fs.h> 54202283Slulf#include <fs/ext2fs/fs.h> 55202283Slulf#include <fs/ext2fs/ext2_extern.h> 5612115Sdyson 57254283Spfgstatic int ext2_indirtrunc(struct inode *, daddr_t, daddr_t, 58254283Spfg daddr_t, int, e4fs_daddr_t *); 5912115Sdyson 6012115Sdyson/* 6112115Sdyson * Update the access, modified, and inode change times as specified by the 6237363Sbde * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode 6337363Sbde * to disk if the IN_MODIFIED flag is set (it may be set initially, or by 6437363Sbde * the timestamp update). The IN_LAZYMOD flag is set to force a write 6537363Sbde * later if not now. If we write now, then clear both IN_MODIFIED and 6637363Sbde * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is 6737363Sbde * set, then wait for the write to complete. 6812115Sdyson */ 6912115Sdysonint 70246634Spfgext2_update(struct vnode *vp, int waitfor) 7112115Sdyson{ 72202283Slulf struct m_ext2fs *fs; 7312115Sdyson struct buf *bp; 7412115Sdyson struct inode *ip; 7512115Sdyson int error; 7612115Sdyson 77202283Slulf ASSERT_VOP_ELOCKED(vp, "ext2_update"); 7896749Siedowse ext2_itimes(vp); 7930492Sphk ip = VTOI(vp); 80202283Slulf if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0) 8112115Sdyson return (0); 82202283Slulf ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED); 83202283Slulf fs = ip->i_e2fs; 84202283Slulf if(fs->e2fs_ronly) 8512115Sdyson return (0); 8643301Sdillon if ((error = bread(ip->i_devvp, 8712115Sdyson fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 88202283Slulf (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 8912115Sdyson brelse(bp); 9012115Sdyson return (error); 9112115Sdyson } 92202283Slulf ext2_i2ei(ip, (struct ext2fs_dinode *)((char *)bp->b_data + 93187395Sstas EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number))); 94221166Sjhb if (waitfor && !DOINGASYNC(vp)) 9512115Sdyson return (bwrite(bp)); 9612115Sdyson else { 9712115Sdyson bdwrite(bp); 9812115Sdyson return (0); 9912115Sdyson } 10012115Sdyson} 10112115Sdyson 10212115Sdyson#define SINGLE 0 /* index of single indirect block */ 10312115Sdyson#define DOUBLE 1 /* index of double indirect block */ 10412115Sdyson#define TRIPLE 2 /* index of triple indirect block */ 10512115Sdyson/* 10612115Sdyson * Truncate the inode oip to at most length size, freeing the 10712115Sdyson * disk blocks. 10812115Sdyson */ 10912115Sdysonint 110246634Spfgext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred, 111246634Spfg struct thread *td) 11212115Sdyson{ 11396752Siedowse struct vnode *ovp = vp; 11496877Siedowse int32_t lastblock; 11596752Siedowse struct inode *oip; 11696877Siedowse int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; 117245820Spfg uint32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; 118202283Slulf struct bufobj *bo; 119202283Slulf struct m_ext2fs *fs; 12012115Sdyson struct buf *bp; 12112115Sdyson int offset, size, level; 122254283Spfg e4fs_daddr_t count, nblocks, blocksreleased = 0; 123221166Sjhb int error, i, allerror; 12412115Sdyson off_t osize; 125202283Slulf 126202283Slulf oip = VTOI(ovp); 127202283Slulf bo = &ovp->v_bufobj; 128202283Slulf 129202283Slulf ASSERT_VOP_LOCKED(vp, "ext2_truncate"); 130202283Slulf 13112115Sdyson if (length < 0) 132202283Slulf return (EINVAL); 13312115Sdyson 13412115Sdyson if (ovp->v_type == VLNK && 13512115Sdyson oip->i_size < ovp->v_mount->mnt_maxsymlinklen) { 136251658Spfg#ifdef INVARIANTS 13712115Sdyson if (length != 0) 13812115Sdyson panic("ext2_truncate: partial truncate of symlink"); 13912115Sdyson#endif 14012115Sdyson bzero((char *)&oip->i_shortlink, (u_int)oip->i_size); 14112115Sdyson oip->i_size = 0; 14212115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 14396749Siedowse return (ext2_update(ovp, 1)); 14412115Sdyson } 14512115Sdyson if (oip->i_size == length) { 14612115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 14796749Siedowse return (ext2_update(ovp, 0)); 14812115Sdyson } 14912115Sdyson fs = oip->i_e2fs; 15012115Sdyson osize = oip->i_size; 15112115Sdyson /* 15212115Sdyson * Lengthen the size of the file. We must ensure that the 15312115Sdyson * last byte of the file is allocated. Since the smallest 154202283Slulf * value of osize is 0, length will be at least 1. 15512115Sdyson */ 15612115Sdyson if (osize < length) { 157202283Slulf if (length > oip->i_e2fs->e2fs_maxfilesize) 158125962Stjr return (EFBIG); 159202283Slulf vnode_pager_setsize(ovp, length); 16012115Sdyson offset = blkoff(fs, length - 1); 16112115Sdyson lbn = lblkno(fs, length - 1); 162221166Sjhb flags |= BA_CLRBUF; 163221166Sjhb error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, flags); 164202283Slulf if (error) { 165202283Slulf vnode_pager_setsize(vp, osize); 16612115Sdyson return (error); 167202283Slulf } 16812115Sdyson oip->i_size = length; 169202283Slulf if (bp->b_bufsize == fs->e2fs_bsize) 170202283Slulf bp->b_flags |= B_CLUSTEROK; 171221166Sjhb if (flags & IO_SYNC) 17212115Sdyson bwrite(bp); 173221166Sjhb else if (DOINGASYNC(ovp)) 174202283Slulf bdwrite(bp); 17512115Sdyson else 17612115Sdyson bawrite(bp); 17712115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 178245612Spfg return (ext2_update(ovp, !DOINGASYNC(ovp))); 17912115Sdyson } 18012115Sdyson /* 18112115Sdyson * Shorten the size of the file. If the file is not being 18212115Sdyson * truncated to a block boundry, the contents of the 18312115Sdyson * partial block following the end of the file must be 18461686Salex * zero'ed in case it ever become accessible again because 18512115Sdyson * of subsequent file growth. 18612115Sdyson */ 18712115Sdyson /* I don't understand the comment above */ 18812115Sdyson offset = blkoff(fs, length); 18912115Sdyson if (offset == 0) { 19012115Sdyson oip->i_size = length; 19112115Sdyson } else { 19212115Sdyson lbn = lblkno(fs, length); 193221166Sjhb flags |= BA_CLRBUF; 194221166Sjhb error = ext2_balloc(oip, lbn, offset, cred, &bp, flags); 195202283Slulf if (error) 19612115Sdyson return (error); 19712115Sdyson oip->i_size = length; 19812115Sdyson size = blksize(fs, oip, lbn); 19912115Sdyson bzero((char *)bp->b_data + offset, (u_int)(size - offset)); 20012115Sdyson allocbuf(bp, size); 201202283Slulf if (bp->b_bufsize == fs->e2fs_bsize) 202202283Slulf bp->b_flags |= B_CLUSTEROK; 203221166Sjhb if (flags & IO_SYNC) 20412115Sdyson bwrite(bp); 205221166Sjhb else if (DOINGASYNC(ovp)) 206202283Slulf bdwrite(bp); 20712115Sdyson else 20812115Sdyson bawrite(bp); 20912115Sdyson } 21012115Sdyson /* 21112115Sdyson * Calculate index into inode's block list of 21212115Sdyson * last direct and indirect blocks (if any) 21312115Sdyson * which we want to keep. Lastblock is -1 when 21412115Sdyson * the file is truncated to 0. 21512115Sdyson */ 216202283Slulf lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1; 21712115Sdyson lastiblock[SINGLE] = lastblock - NDADDR; 21812115Sdyson lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 21912115Sdyson lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 220202283Slulf nblocks = btodb(fs->e2fs_bsize); 22112115Sdyson /* 22212115Sdyson * Update file and block pointers on disk before we start freeing 22312115Sdyson * blocks. If we crash before free'ing blocks below, the blocks 22412115Sdyson * will be returned to the free list. lastiblock values are also 22512115Sdyson * normalized to -1 for calls to ext2_indirtrunc below. 22612115Sdyson */ 227228583Spfg bcopy((caddr_t)&oip->i_db[0], (caddr_t)oldblks, sizeof(oldblks)); 22812115Sdyson for (level = TRIPLE; level >= SINGLE; level--) 22912115Sdyson if (lastiblock[level] < 0) { 23012115Sdyson oip->i_ib[level] = 0; 23112115Sdyson lastiblock[level] = -1; 23212115Sdyson } 23312115Sdyson for (i = NDADDR - 1; i > lastblock; i--) 23412115Sdyson oip->i_db[i] = 0; 23512115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 236245612Spfg allerror = ext2_update(ovp, !DOINGASYNC(ovp)); 23740721Speter 23812115Sdyson /* 23912115Sdyson * Having written the new inode to disk, save its new configuration 24012115Sdyson * and put back the old block pointers long enough to process them. 24112115Sdyson * Note that we save the new block configuration so we can check it 24212115Sdyson * when we are done. 24312115Sdyson */ 244228583Spfg bcopy((caddr_t)&oip->i_db[0], (caddr_t)newblks, sizeof(newblks)); 245228583Spfg bcopy((caddr_t)oldblks, (caddr_t)&oip->i_db[0], sizeof(oldblks)); 24612115Sdyson oip->i_size = osize; 247234605Strasz error = vtruncbuf(ovp, cred, length, (int)fs->e2fs_bsize); 24840718Speter if (error && (allerror == 0)) 24940718Speter allerror = error; 250202283Slulf vnode_pager_setsize(ovp, length); 251202283Slulf 25212115Sdyson /* 25312115Sdyson * Indirect blocks first. 25412115Sdyson */ 25512115Sdyson indir_lbn[SINGLE] = -NDADDR; 25612115Sdyson indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; 25712115Sdyson indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 25812115Sdyson for (level = TRIPLE; level >= SINGLE; level--) { 25912115Sdyson bn = oip->i_ib[level]; 26012115Sdyson if (bn != 0) { 26112115Sdyson error = ext2_indirtrunc(oip, indir_lbn[level], 26212115Sdyson fsbtodb(fs, bn), lastiblock[level], level, &count); 26312115Sdyson if (error) 26412115Sdyson allerror = error; 26512115Sdyson blocksreleased += count; 26612115Sdyson if (lastiblock[level] < 0) { 26712115Sdyson oip->i_ib[level] = 0; 268202283Slulf ext2_blkfree(oip, bn, fs->e2fs_fsize); 26912115Sdyson blocksreleased += nblocks; 27012115Sdyson } 27112115Sdyson } 27212115Sdyson if (lastiblock[level] >= 0) 27312115Sdyson goto done; 27412115Sdyson } 27512115Sdyson 27612115Sdyson /* 27712115Sdyson * All whole direct blocks or frags. 27812115Sdyson */ 27912115Sdyson for (i = NDADDR - 1; i > lastblock; i--) { 28096752Siedowse long bsize; 28112115Sdyson 28212115Sdyson bn = oip->i_db[i]; 28312115Sdyson if (bn == 0) 28412115Sdyson continue; 28512115Sdyson oip->i_db[i] = 0; 28612115Sdyson bsize = blksize(fs, oip, i); 28712115Sdyson ext2_blkfree(oip, bn, bsize); 28812115Sdyson blocksreleased += btodb(bsize); 28912115Sdyson } 29012115Sdyson if (lastblock < 0) 29112115Sdyson goto done; 29212115Sdyson 29312115Sdyson /* 29412115Sdyson * Finally, look for a change in size of the 29512115Sdyson * last direct block; release any frags. 29612115Sdyson */ 29712115Sdyson bn = oip->i_db[lastblock]; 29812115Sdyson if (bn != 0) { 29912115Sdyson long oldspace, newspace; 30012115Sdyson 30112115Sdyson /* 30212115Sdyson * Calculate amount of space we're giving 30312115Sdyson * back as old block size minus new block size. 30412115Sdyson */ 30512115Sdyson oldspace = blksize(fs, oip, lastblock); 30612115Sdyson oip->i_size = length; 30712115Sdyson newspace = blksize(fs, oip, lastblock); 30812115Sdyson if (newspace == 0) 309246258Spfg panic("ext2_truncate: newspace"); 31012115Sdyson if (oldspace - newspace > 0) { 31112115Sdyson /* 31212115Sdyson * Block number of space to be free'd is 31312115Sdyson * the old block # plus the number of frags 31412115Sdyson * required for the storage we're keeping. 31512115Sdyson */ 31612115Sdyson bn += numfrags(fs, newspace); 31712115Sdyson ext2_blkfree(oip, bn, oldspace - newspace); 31812115Sdyson blocksreleased += btodb(oldspace - newspace); 31912115Sdyson } 32012115Sdyson } 32112115Sdysondone: 322251658Spfg#ifdef INVARIANTS 32312115Sdyson for (level = SINGLE; level <= TRIPLE; level++) 32412115Sdyson if (newblks[NDADDR + level] != oip->i_ib[level]) 32512115Sdyson panic("itrunc1"); 32612115Sdyson for (i = 0; i < NDADDR; i++) 32712115Sdyson if (newblks[i] != oip->i_db[i]) 32812115Sdyson panic("itrunc2"); 329202283Slulf BO_LOCK(bo); 330202283Slulf if (length == 0 && (bo->bo_dirty.bv_cnt != 0 || 331202283Slulf bo->bo_clean.bv_cnt != 0)) 33212115Sdyson panic("itrunc3"); 333202283Slulf BO_UNLOCK(bo); 334251658Spfg#endif /* INVARIANTS */ 33512115Sdyson /* 33612115Sdyson * Put back the real size. 33712115Sdyson */ 33812115Sdyson oip->i_size = length; 339245950Spfg if (oip->i_blocks >= blocksreleased) 340245820Spfg oip->i_blocks -= blocksreleased; 341245950Spfg else /* sanity */ 34212115Sdyson oip->i_blocks = 0; 34312115Sdyson oip->i_flag |= IN_CHANGE; 34413490Sdyson vnode_pager_setsize(ovp, length); 34512115Sdyson return (allerror); 34612115Sdyson} 34712115Sdyson 34812115Sdyson/* 34912115Sdyson * Release blocks associated with the inode ip and stored in the indirect 35012115Sdyson * block bn. Blocks are free'd in LIFO order up to (but not including) 35112115Sdyson * lastbn. If level is greater than SINGLE, the block is an indirect block 35212115Sdyson * and recursive calls to indirtrunc must be used to cleanse other indirect 35312115Sdyson * blocks. 35412115Sdyson * 35512115Sdyson * NB: triple indirect blocks are untested. 35612115Sdyson */ 35712115Sdyson 35812115Sdysonstatic int 359254283Spfgext2_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, 360254283Spfg daddr_t lastbn, int level, e4fs_daddr_t *countp) 36112115Sdyson{ 36212115Sdyson struct buf *bp; 363202283Slulf struct m_ext2fs *fs = ip->i_e2fs; 36412115Sdyson struct vnode *vp; 365254283Spfg e2fs_daddr_t *bap, *copy; 366254283Spfg int i, nblocks, error = 0, allerror = 0; 367254283Spfg e2fs_lbn_t nb, nlbn, last; 368254283Spfg e4fs_daddr_t blkcount, factor, blocksreleased = 0; 36912115Sdyson 37012115Sdyson /* 37112115Sdyson * Calculate index in current block of last 37212115Sdyson * block to be kept. -1 indicates the entire 37312115Sdyson * block so we need not calculate the index. 37412115Sdyson */ 37512115Sdyson factor = 1; 37612115Sdyson for (i = SINGLE; i < level; i++) 37712115Sdyson factor *= NINDIR(fs); 37812115Sdyson last = lastbn; 37912115Sdyson if (lastbn > 0) 38012115Sdyson last /= factor; 381202283Slulf nblocks = btodb(fs->e2fs_bsize); 38212115Sdyson /* 38312115Sdyson * Get buffer of block pointers, zero those entries corresponding 38412115Sdyson * to blocks to be free'd, and update on disk copy first. Since 38512115Sdyson * double(triple) indirect before single(double) indirect, calls 38612115Sdyson * to bmap on these blocks will fail. However, we already have 38712115Sdyson * the on disk address, so we have to set the b_blkno field 38812115Sdyson * explicitly instead of letting bread do everything for us. 38912115Sdyson */ 39012115Sdyson vp = ITOV(ip); 391202283Slulf bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0, 0); 392240355Skevlo if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0) { 39358345Sphk bp->b_iocmd = BIO_READ; 39412115Sdyson if (bp->b_bcount > bp->b_bufsize) 39512115Sdyson panic("ext2_indirtrunc: bad buffer size"); 39612115Sdyson bp->b_blkno = dbn; 39712115Sdyson vfs_busy_pages(bp, 0); 398121205Sphk bp->b_iooffset = dbtob(bp->b_blkno); 399136927Sphk bstrategy(bp); 40059762Sphk error = bufwait(bp); 40112115Sdyson } 40212115Sdyson if (error) { 40312115Sdyson brelse(bp); 40412115Sdyson *countp = 0; 40512115Sdyson return (error); 40612115Sdyson } 40712115Sdyson 408254283Spfg bap = (e2fs_daddr_t *)bp->b_data; 409202283Slulf copy = malloc(fs->e2fs_bsize, M_TEMP, M_WAITOK); 410202283Slulf bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->e2fs_bsize); 41112115Sdyson bzero((caddr_t)&bap[last + 1], 412254283Spfg (NINDIR(fs) - (last + 1)) * sizeof(e2fs_daddr_t)); 41312115Sdyson if (last == -1) 41412115Sdyson bp->b_flags |= B_INVAL; 415245612Spfg if (DOINGASYNC(vp)) { 416245612Spfg bdwrite(bp); 417245612Spfg } else { 418245612Spfg error = bwrite(bp); 419245612Spfg if (error) 420245612Spfg allerror = error; 421245612Spfg } 42212115Sdyson bap = copy; 42312115Sdyson 42412115Sdyson /* 42512115Sdyson * Recursively free totally unused blocks. 42612115Sdyson */ 42712115Sdyson for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; 42812115Sdyson i--, nlbn += factor) { 42912115Sdyson nb = bap[i]; 43012115Sdyson if (nb == 0) 43112115Sdyson continue; 43212115Sdyson if (level > SINGLE) { 43343301Sdillon if ((error = ext2_indirtrunc(ip, nlbn, 43496877Siedowse fsbtodb(fs, nb), (int32_t)-1, level - 1, &blkcount)) != 0) 43512115Sdyson allerror = error; 43612115Sdyson blocksreleased += blkcount; 43712115Sdyson } 438202283Slulf ext2_blkfree(ip, nb, fs->e2fs_bsize); 43912115Sdyson blocksreleased += nblocks; 44012115Sdyson } 44112115Sdyson 44212115Sdyson /* 44312115Sdyson * Recursively free last partial block. 44412115Sdyson */ 44512115Sdyson if (level > SINGLE && lastbn >= 0) { 44612115Sdyson last = lastbn % factor; 44712115Sdyson nb = bap[i]; 44812115Sdyson if (nb != 0) { 44943301Sdillon if ((error = ext2_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 45043301Sdillon last, level - 1, &blkcount)) != 0) 45112115Sdyson allerror = error; 45212115Sdyson blocksreleased += blkcount; 45312115Sdyson } 45412115Sdyson } 455184205Sdes free(copy, M_TEMP); 45612115Sdyson *countp = blocksreleased; 45712115Sdyson return (allerror); 45812115Sdyson} 45912115Sdyson 46012115Sdyson/* 46112115Sdyson * discard preallocated blocks 46212115Sdyson */ 46312115Sdysonint 464246634Spfgext2_inactive(struct vop_inactive_args *ap) 46512115Sdyson{ 46696749Siedowse struct vnode *vp = ap->a_vp; 46796749Siedowse struct inode *ip = VTOI(vp); 46896749Siedowse struct thread *td = ap->a_td; 46996749Siedowse int mode, error = 0; 47096749Siedowse 47196749Siedowse /* 47296749Siedowse * Ignore inodes related to stale file handles. 47396749Siedowse */ 47496749Siedowse if (ip->i_mode == 0) 47596749Siedowse goto out; 47696749Siedowse if (ip->i_nlink <= 0) { 47796749Siedowse error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td); 47896749Siedowse ip->i_rdev = 0; 47996749Siedowse mode = ip->i_mode; 48096749Siedowse ip->i_mode = 0; 48196749Siedowse ip->i_flag |= IN_CHANGE | IN_UPDATE; 48296749Siedowse ext2_vfree(vp, ip->i_number, mode); 48396749Siedowse } 484183071Skib if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) 485183071Skib ext2_update(vp, 0); 48696749Siedowseout: 48796749Siedowse /* 48896749Siedowse * If we are done with the inode, reclaim it 48996749Siedowse * so that it can be reused immediately. 49096749Siedowse */ 49196749Siedowse if (ip->i_mode == 0) 492234607Strasz vrecycle(vp); 49396749Siedowse return (error); 49412115Sdyson} 49512115Sdyson 49696749Siedowse/* 49796749Siedowse * Reclaim an inode so that it can be used for other purposes. 49896749Siedowse */ 49996749Siedowseint 500246634Spfgext2_reclaim(struct vop_reclaim_args *ap) 50196749Siedowse{ 50296749Siedowse struct inode *ip; 50396749Siedowse struct vnode *vp = ap->a_vp; 50496749Siedowse 50596749Siedowse ip = VTOI(vp); 50696749Siedowse if (ip->i_flag & IN_LAZYMOD) { 50796749Siedowse ip->i_flag |= IN_MODIFIED; 50896749Siedowse ext2_update(vp, 0); 50996749Siedowse } 510143578Sphk vfs_hash_remove(vp); 511184205Sdes free(vp->v_data, M_EXT2NODE); 51296749Siedowse vp->v_data = 0; 513140939Sphk vnode_destroy_vobject(vp); 51496749Siedowse return (0); 51596749Siedowse} 516