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: stable/10/sys/fs/ext2fs/ext2_inode.c 311232 2017-01-04 02:43:33Z pfg $ 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; 84311232Spfg if (fs->e2fs_ronly) 8512115Sdyson return (0); 8643301Sdillon if ((error = bread(ip->i_devvp, 8712115Sdyson fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 88311232Spfg (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 m_ext2fs *fs; 11912115Sdyson struct buf *bp; 12012115Sdyson int offset, size, level; 121254283Spfg e4fs_daddr_t count, nblocks, blocksreleased = 0; 122221166Sjhb int error, i, allerror; 12312115Sdyson off_t osize; 124278096Spfg#ifdef INVARIANTS 125278096Spfg struct bufobj *bo; 126278096Spfg#endif 127202283Slulf 128202283Slulf oip = VTOI(ovp); 129278096Spfg#ifdef INVARIANTS 130202283Slulf bo = &ovp->v_bufobj; 131278096Spfg#endif 132202283Slulf 133311232Spfg ASSERT_VOP_LOCKED(vp, "ext2_truncate"); 134202283Slulf 13512115Sdyson if (length < 0) 136311232Spfg return (EINVAL); 13712115Sdyson 13812115Sdyson if (ovp->v_type == VLNK && 13912115Sdyson oip->i_size < ovp->v_mount->mnt_maxsymlinklen) { 140251658Spfg#ifdef INVARIANTS 14112115Sdyson if (length != 0) 14212115Sdyson panic("ext2_truncate: partial truncate of symlink"); 14312115Sdyson#endif 14412115Sdyson bzero((char *)&oip->i_shortlink, (u_int)oip->i_size); 14512115Sdyson oip->i_size = 0; 14612115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 14796749Siedowse return (ext2_update(ovp, 1)); 14812115Sdyson } 14912115Sdyson if (oip->i_size == length) { 15012115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 15196749Siedowse return (ext2_update(ovp, 0)); 15212115Sdyson } 15312115Sdyson fs = oip->i_e2fs; 15412115Sdyson osize = oip->i_size; 15512115Sdyson /* 15612115Sdyson * Lengthen the size of the file. We must ensure that the 15712115Sdyson * last byte of the file is allocated. Since the smallest 158202283Slulf * value of osize is 0, length will be at least 1. 15912115Sdyson */ 16012115Sdyson if (osize < length) { 161202283Slulf if (length > oip->i_e2fs->e2fs_maxfilesize) 162125962Stjr return (EFBIG); 163202283Slulf vnode_pager_setsize(ovp, length); 16412115Sdyson offset = blkoff(fs, length - 1); 16512115Sdyson lbn = lblkno(fs, length - 1); 166221166Sjhb flags |= BA_CLRBUF; 167221166Sjhb error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, flags); 168202283Slulf if (error) { 169202283Slulf vnode_pager_setsize(vp, osize); 17012115Sdyson return (error); 171202283Slulf } 17212115Sdyson oip->i_size = length; 173202283Slulf if (bp->b_bufsize == fs->e2fs_bsize) 174202283Slulf bp->b_flags |= B_CLUSTEROK; 175221166Sjhb if (flags & IO_SYNC) 17612115Sdyson bwrite(bp); 177221166Sjhb else if (DOINGASYNC(ovp)) 178202283Slulf bdwrite(bp); 17912115Sdyson else 18012115Sdyson bawrite(bp); 18112115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 182245612Spfg return (ext2_update(ovp, !DOINGASYNC(ovp))); 18312115Sdyson } 18412115Sdyson /* 18512115Sdyson * Shorten the size of the file. If the file is not being 18612115Sdyson * truncated to a block boundry, the contents of the 18712115Sdyson * partial block following the end of the file must be 18861686Salex * zero'ed in case it ever become accessible again because 18912115Sdyson * of subsequent file growth. 19012115Sdyson */ 19112115Sdyson /* I don't understand the comment above */ 19212115Sdyson offset = blkoff(fs, length); 19312115Sdyson if (offset == 0) { 19412115Sdyson oip->i_size = length; 19512115Sdyson } else { 19612115Sdyson lbn = lblkno(fs, length); 197221166Sjhb flags |= BA_CLRBUF; 198221166Sjhb error = ext2_balloc(oip, lbn, offset, cred, &bp, flags); 199202283Slulf if (error) 20012115Sdyson return (error); 20112115Sdyson oip->i_size = length; 20212115Sdyson size = blksize(fs, oip, lbn); 20312115Sdyson bzero((char *)bp->b_data + offset, (u_int)(size - offset)); 20412115Sdyson allocbuf(bp, size); 205202283Slulf if (bp->b_bufsize == fs->e2fs_bsize) 206202283Slulf bp->b_flags |= B_CLUSTEROK; 207221166Sjhb if (flags & IO_SYNC) 20812115Sdyson bwrite(bp); 209221166Sjhb else if (DOINGASYNC(ovp)) 210202283Slulf bdwrite(bp); 21112115Sdyson else 21212115Sdyson bawrite(bp); 21312115Sdyson } 21412115Sdyson /* 21512115Sdyson * Calculate index into inode's block list of 21612115Sdyson * last direct and indirect blocks (if any) 21712115Sdyson * which we want to keep. Lastblock is -1 when 21812115Sdyson * the file is truncated to 0. 21912115Sdyson */ 220202283Slulf lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1; 22112115Sdyson lastiblock[SINGLE] = lastblock - NDADDR; 22212115Sdyson lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 22312115Sdyson lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 224202283Slulf nblocks = btodb(fs->e2fs_bsize); 22512115Sdyson /* 22612115Sdyson * Update file and block pointers on disk before we start freeing 22712115Sdyson * blocks. If we crash before free'ing blocks below, the blocks 22812115Sdyson * will be returned to the free list. lastiblock values are also 22912115Sdyson * normalized to -1 for calls to ext2_indirtrunc below. 23012115Sdyson */ 231275834Spfg for (level = TRIPLE; level >= SINGLE; level--) { 232275834Spfg oldblks[NDADDR + level] = oip->i_ib[level]; 23312115Sdyson if (lastiblock[level] < 0) { 23412115Sdyson oip->i_ib[level] = 0; 23512115Sdyson lastiblock[level] = -1; 23612115Sdyson } 237275834Spfg } 238275834Spfg for (i = 0; i < NDADDR; i++) { 239275834Spfg oldblks[i] = oip->i_db[i]; 240275834Spfg if (i > lastblock) 241275834Spfg oip->i_db[i] = 0; 242275834Spfg } 24312115Sdyson oip->i_flag |= IN_CHANGE | IN_UPDATE; 244245612Spfg allerror = ext2_update(ovp, !DOINGASYNC(ovp)); 24540721Speter 24612115Sdyson /* 24712115Sdyson * Having written the new inode to disk, save its new configuration 24812115Sdyson * and put back the old block pointers long enough to process them. 24912115Sdyson * Note that we save the new block configuration so we can check it 25012115Sdyson * when we are done. 25112115Sdyson */ 252275834Spfg for (i = 0; i < NDADDR; i++) { 253275834Spfg newblks[i] = oip->i_db[i]; 254275834Spfg oip->i_db[i] = oldblks[i]; 255275834Spfg } 256275834Spfg for (i = 0; i < NIADDR; i++) { 257275834Spfg newblks[NDADDR + i] = oip->i_ib[i]; 258275834Spfg oip->i_ib[i] = oldblks[NDADDR + i]; 259275834Spfg } 26012115Sdyson oip->i_size = osize; 261234605Strasz error = vtruncbuf(ovp, cred, length, (int)fs->e2fs_bsize); 26240718Speter if (error && (allerror == 0)) 26340718Speter allerror = error; 264202283Slulf vnode_pager_setsize(ovp, length); 265262723Spfg 26612115Sdyson /* 26712115Sdyson * Indirect blocks first. 26812115Sdyson */ 26912115Sdyson indir_lbn[SINGLE] = -NDADDR; 27012115Sdyson indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; 27112115Sdyson indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 27212115Sdyson for (level = TRIPLE; level >= SINGLE; level--) { 27312115Sdyson bn = oip->i_ib[level]; 27412115Sdyson if (bn != 0) { 27512115Sdyson error = ext2_indirtrunc(oip, indir_lbn[level], 27612115Sdyson fsbtodb(fs, bn), lastiblock[level], level, &count); 27712115Sdyson if (error) 27812115Sdyson allerror = error; 27912115Sdyson blocksreleased += count; 28012115Sdyson if (lastiblock[level] < 0) { 28112115Sdyson oip->i_ib[level] = 0; 282202283Slulf ext2_blkfree(oip, bn, fs->e2fs_fsize); 28312115Sdyson blocksreleased += nblocks; 28412115Sdyson } 28512115Sdyson } 28612115Sdyson if (lastiblock[level] >= 0) 28712115Sdyson goto done; 28812115Sdyson } 28912115Sdyson 29012115Sdyson /* 29112115Sdyson * All whole direct blocks or frags. 29212115Sdyson */ 29312115Sdyson for (i = NDADDR - 1; i > lastblock; i--) { 29496752Siedowse long bsize; 29512115Sdyson 29612115Sdyson bn = oip->i_db[i]; 29712115Sdyson if (bn == 0) 29812115Sdyson continue; 29912115Sdyson oip->i_db[i] = 0; 30012115Sdyson bsize = blksize(fs, oip, i); 30112115Sdyson ext2_blkfree(oip, bn, bsize); 30212115Sdyson blocksreleased += btodb(bsize); 30312115Sdyson } 30412115Sdyson if (lastblock < 0) 30512115Sdyson goto done; 30612115Sdyson 30712115Sdyson /* 30812115Sdyson * Finally, look for a change in size of the 30912115Sdyson * last direct block; release any frags. 31012115Sdyson */ 31112115Sdyson bn = oip->i_db[lastblock]; 31212115Sdyson if (bn != 0) { 31312115Sdyson long oldspace, newspace; 31412115Sdyson 31512115Sdyson /* 31612115Sdyson * Calculate amount of space we're giving 31712115Sdyson * back as old block size minus new block size. 31812115Sdyson */ 31912115Sdyson oldspace = blksize(fs, oip, lastblock); 32012115Sdyson oip->i_size = length; 32112115Sdyson newspace = blksize(fs, oip, lastblock); 32212115Sdyson if (newspace == 0) 323246258Spfg panic("ext2_truncate: newspace"); 32412115Sdyson if (oldspace - newspace > 0) { 32512115Sdyson /* 32612115Sdyson * Block number of space to be free'd is 32712115Sdyson * the old block # plus the number of frags 32812115Sdyson * required for the storage we're keeping. 32912115Sdyson */ 33012115Sdyson bn += numfrags(fs, newspace); 33112115Sdyson ext2_blkfree(oip, bn, oldspace - newspace); 33212115Sdyson blocksreleased += btodb(oldspace - newspace); 33312115Sdyson } 33412115Sdyson } 33512115Sdysondone: 336251658Spfg#ifdef INVARIANTS 33712115Sdyson for (level = SINGLE; level <= TRIPLE; level++) 33812115Sdyson if (newblks[NDADDR + level] != oip->i_ib[level]) 33912115Sdyson panic("itrunc1"); 34012115Sdyson for (i = 0; i < NDADDR; i++) 34112115Sdyson if (newblks[i] != oip->i_db[i]) 34212115Sdyson panic("itrunc2"); 343202283Slulf BO_LOCK(bo); 344202283Slulf if (length == 0 && (bo->bo_dirty.bv_cnt != 0 || 345202283Slulf bo->bo_clean.bv_cnt != 0)) 34612115Sdyson panic("itrunc3"); 347202283Slulf BO_UNLOCK(bo); 348311232Spfg#endif /* INVARIANTS */ 34912115Sdyson /* 35012115Sdyson * Put back the real size. 35112115Sdyson */ 35212115Sdyson oip->i_size = length; 353245950Spfg if (oip->i_blocks >= blocksreleased) 354245820Spfg oip->i_blocks -= blocksreleased; 355245950Spfg else /* sanity */ 35612115Sdyson oip->i_blocks = 0; 35712115Sdyson oip->i_flag |= IN_CHANGE; 35813490Sdyson vnode_pager_setsize(ovp, length); 35912115Sdyson return (allerror); 36012115Sdyson} 36112115Sdyson 36212115Sdyson/* 36312115Sdyson * Release blocks associated with the inode ip and stored in the indirect 36412115Sdyson * block bn. Blocks are free'd in LIFO order up to (but not including) 36512115Sdyson * lastbn. If level is greater than SINGLE, the block is an indirect block 36612115Sdyson * and recursive calls to indirtrunc must be used to cleanse other indirect 36712115Sdyson * blocks. 36812115Sdyson * 36912115Sdyson * NB: triple indirect blocks are untested. 37012115Sdyson */ 37112115Sdyson 37212115Sdysonstatic int 373254283Spfgext2_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, 374254283Spfg daddr_t lastbn, int level, e4fs_daddr_t *countp) 37512115Sdyson{ 37612115Sdyson struct buf *bp; 377202283Slulf struct m_ext2fs *fs = ip->i_e2fs; 37812115Sdyson struct vnode *vp; 379254283Spfg e2fs_daddr_t *bap, *copy; 380254283Spfg int i, nblocks, error = 0, allerror = 0; 381254283Spfg e2fs_lbn_t nb, nlbn, last; 382254283Spfg e4fs_daddr_t blkcount, factor, blocksreleased = 0; 38312115Sdyson 38412115Sdyson /* 38512115Sdyson * Calculate index in current block of last 38612115Sdyson * block to be kept. -1 indicates the entire 38712115Sdyson * block so we need not calculate the index. 38812115Sdyson */ 38912115Sdyson factor = 1; 39012115Sdyson for (i = SINGLE; i < level; i++) 39112115Sdyson factor *= NINDIR(fs); 39212115Sdyson last = lastbn; 39312115Sdyson if (lastbn > 0) 39412115Sdyson last /= factor; 395202283Slulf nblocks = btodb(fs->e2fs_bsize); 39612115Sdyson /* 39712115Sdyson * Get buffer of block pointers, zero those entries corresponding 39812115Sdyson * to blocks to be free'd, and update on disk copy first. Since 39912115Sdyson * double(triple) indirect before single(double) indirect, calls 40012115Sdyson * to bmap on these blocks will fail. However, we already have 40112115Sdyson * the on disk address, so we have to set the b_blkno field 40212115Sdyson * explicitly instead of letting bread do everything for us. 40312115Sdyson */ 40412115Sdyson vp = ITOV(ip); 405202283Slulf bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0, 0); 406240355Skevlo if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0) { 40758345Sphk bp->b_iocmd = BIO_READ; 40812115Sdyson if (bp->b_bcount > bp->b_bufsize) 40912115Sdyson panic("ext2_indirtrunc: bad buffer size"); 41012115Sdyson bp->b_blkno = dbn; 41112115Sdyson vfs_busy_pages(bp, 0); 412121205Sphk bp->b_iooffset = dbtob(bp->b_blkno); 413136927Sphk bstrategy(bp); 41459762Sphk error = bufwait(bp); 41512115Sdyson } 41612115Sdyson if (error) { 41712115Sdyson brelse(bp); 41812115Sdyson *countp = 0; 41912115Sdyson return (error); 42012115Sdyson } 421254283Spfg bap = (e2fs_daddr_t *)bp->b_data; 422202283Slulf copy = malloc(fs->e2fs_bsize, M_TEMP, M_WAITOK); 423202283Slulf bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->e2fs_bsize); 42412115Sdyson bzero((caddr_t)&bap[last + 1], 425311232Spfg (NINDIR(fs) - (last + 1)) * sizeof(e2fs_daddr_t)); 42612115Sdyson if (last == -1) 42712115Sdyson bp->b_flags |= B_INVAL; 428245612Spfg if (DOINGASYNC(vp)) { 429245612Spfg bdwrite(bp); 430245612Spfg } else { 431245612Spfg error = bwrite(bp); 432245612Spfg if (error) 433245612Spfg allerror = error; 434245612Spfg } 43512115Sdyson bap = copy; 43612115Sdyson 43712115Sdyson /* 43812115Sdyson * Recursively free totally unused blocks. 43912115Sdyson */ 44012115Sdyson for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; 44112115Sdyson i--, nlbn += factor) { 44212115Sdyson nb = bap[i]; 44312115Sdyson if (nb == 0) 44412115Sdyson continue; 44512115Sdyson if (level > SINGLE) { 44643301Sdillon if ((error = ext2_indirtrunc(ip, nlbn, 44796877Siedowse fsbtodb(fs, nb), (int32_t)-1, level - 1, &blkcount)) != 0) 44812115Sdyson allerror = error; 44912115Sdyson blocksreleased += blkcount; 45012115Sdyson } 451202283Slulf ext2_blkfree(ip, nb, fs->e2fs_bsize); 45212115Sdyson blocksreleased += nblocks; 45312115Sdyson } 45412115Sdyson 45512115Sdyson /* 45612115Sdyson * Recursively free last partial block. 45712115Sdyson */ 45812115Sdyson if (level > SINGLE && lastbn >= 0) { 45912115Sdyson last = lastbn % factor; 46012115Sdyson nb = bap[i]; 46112115Sdyson if (nb != 0) { 46243301Sdillon if ((error = ext2_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 46343301Sdillon last, level - 1, &blkcount)) != 0) 46412115Sdyson allerror = error; 46512115Sdyson blocksreleased += blkcount; 46612115Sdyson } 46712115Sdyson } 468184205Sdes free(copy, M_TEMP); 46912115Sdyson *countp = blocksreleased; 47012115Sdyson return (allerror); 47112115Sdyson} 47212115Sdyson 47312115Sdyson/* 47412115Sdyson * discard preallocated blocks 47512115Sdyson */ 47612115Sdysonint 477246634Spfgext2_inactive(struct vop_inactive_args *ap) 47812115Sdyson{ 47996749Siedowse struct vnode *vp = ap->a_vp; 48096749Siedowse struct inode *ip = VTOI(vp); 48196749Siedowse struct thread *td = ap->a_td; 48296749Siedowse int mode, error = 0; 48396749Siedowse 48496749Siedowse /* 48596749Siedowse * Ignore inodes related to stale file handles. 48696749Siedowse */ 48796749Siedowse if (ip->i_mode == 0) 48896749Siedowse goto out; 48996749Siedowse if (ip->i_nlink <= 0) { 49096749Siedowse error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td); 49196749Siedowse ip->i_rdev = 0; 49296749Siedowse mode = ip->i_mode; 49396749Siedowse ip->i_mode = 0; 49496749Siedowse ip->i_flag |= IN_CHANGE | IN_UPDATE; 49596749Siedowse ext2_vfree(vp, ip->i_number, mode); 49696749Siedowse } 497183071Skib if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) 498183071Skib ext2_update(vp, 0); 49996749Siedowseout: 50096749Siedowse /* 50196749Siedowse * If we are done with the inode, reclaim it 50296749Siedowse * so that it can be reused immediately. 50396749Siedowse */ 50496749Siedowse if (ip->i_mode == 0) 505234607Strasz vrecycle(vp); 50696749Siedowse return (error); 50712115Sdyson} 50812115Sdyson 50996749Siedowse/* 51096749Siedowse * Reclaim an inode so that it can be used for other purposes. 51196749Siedowse */ 51296749Siedowseint 513246634Spfgext2_reclaim(struct vop_reclaim_args *ap) 51496749Siedowse{ 51596749Siedowse struct inode *ip; 51696749Siedowse struct vnode *vp = ap->a_vp; 51796749Siedowse 51896749Siedowse ip = VTOI(vp); 51996749Siedowse if (ip->i_flag & IN_LAZYMOD) { 52096749Siedowse ip->i_flag |= IN_MODIFIED; 52196749Siedowse ext2_update(vp, 0); 52296749Siedowse } 523143578Sphk vfs_hash_remove(vp); 524184205Sdes free(vp->v_data, M_EXT2NODE); 52596749Siedowse vp->v_data = 0; 526140939Sphk vnode_destroy_vobject(vp); 52796749Siedowse return (0); 52896749Siedowse} 529