-#endif
- }
- /*
- * Update file and block pointers
- * on disk before we start freeing blocks.
- * If we crash before free'ing blocks below,
- * the blocks will be returned to the free list.
- * lastiblock values are also normalized to -1
- * for calls to indirtrunc below.
- */
- /* Will need to modify the segment usage information */ /* LFS */
- tip = *oip;
- tip.i_size = osize;
- for (level = TRIPLE; level >= SINGLE; level--)
- if (lastiblock[level] < 0) {
- oip->i_ib[level] = 0;
- lastiblock[level] = -1;
- }
- for (i = NDADDR - 1; i > lastblock; i--)
- oip->i_db[i] = 0;
- oip->i_flag |= ICHG|IUPD;
-#ifdef NOTLFS
- vinvalbuf(ITOV(oip), (length > 0));
- allerror = ITIMES(oip, &time, &time);
-#else
- /* Need lfs_vinvalbuf to get rid of invalid buffers in the cache */
- ITIMES(oip, &time, &time);
- allerror = 0;
-#endif
-
-#ifdef NOTLFS
- /*
- * Indirect blocks first.
- */
- ip = &tip;
- for (level = TRIPLE; level >= SINGLE; level--) {
- bn = ip->i_ib[level];
- if (bn != 0) {
- error = indirtrunc(ip, bn, lastiblock[level], level,
- &count);
- if (error)
- allerror = error;
- blocksreleased += count;
- if (lastiblock[level] < 0) {
- ip->i_ib[level] = 0;
- blkfree(ip, bn, (off_t)fs->fs_bsize);
- blocksreleased += nblocks;
- }
- }
- if (lastiblock[level] >= 0)
- goto done;
- }
-#else
- /* LFS -- not yet implemented. Need to rewrite indirect blocks */
- panic("lfs_itrunc: not yet implemented");
-#endif
-
- /*
- * All whole direct blocks or frags.
- */
- for (i = NDADDR - 1; i > lastblock; i--) {
- register off_t bsize;
-
- bn = ip->i_db[i];
- if (bn == 0)
- continue;
- ip->i_db[i] = 0;
- bsize = (off_t)blksize(fs); /* LFS */
-#ifdef NOTLFS
- blkfree(ip, bn, bsize);
-#else
- /* LFS Update segment usage information */
-#endif
- blocksreleased += btodb(bsize);
- }
- if (lastblock < 0)
- goto done;
-
- /*
- * Finally, look for a change in size of the
- * last direct block; release any frags.
- */
- bn = ip->i_db[lastblock];
- if (bn != 0) {
- off_t oldspace, newspace;
-
- /*
- * Calculate amount of space we're giving
- * back as old block size minus new block size.
- */
- oldspace = blksize(fs); /* LFS */
- ip->i_size = length;
- newspace = blksize(fs); /* LFS */
- if (newspace == 0)
- panic("lfs_itrunc: newspace");
- if (oldspace - newspace > 0) {
- /*
- * Block number of space to be free'd is
- * the old block # plus the number of frags
- * required for the storage we're keeping.
- */
- bn += numfrags(fs, newspace);
- blkfree(ip, bn, oldspace - newspace);
- blocksreleased += btodb(oldspace - newspace);
- }
- }
-done:
-/* BEGIN PARANOIA */
- for (level = SINGLE; level <= TRIPLE; level++)
- if (ip->i_ib[level] != oip->i_ib[level])
- panic("lfs_itrunc1");
- for (i = 0; i < NDADDR; i++)
- if (ip->i_db[i] != oip->i_db[i])
- panic("lfs_itrunc2");
-/* END PARANOIA */
- oip->i_blocks -= blocksreleased;
- if (oip->i_blocks < 0) /* sanity */
- oip->i_blocks = 0;
- oip->i_flag |= ICHG;
-#ifdef QUOTA
- if (!getinoquota(oip))
- (void) chkdq(oip, -blocksreleased, NOCRED, 0);
-#endif
- return (allerror);
-}
-
-/*
- * Release blocks associated with the inode ip and
- * stored in the indirect block bn. Blocks are free'd
- * in LIFO order up to (but not including) lastbn. If
- * level is greater than SINGLE, the block is an indirect
- * block and recursive calls to indirtrunc must be used to
- * cleanse other indirect blocks.
- *
- * NB: triple indirect blocks are untested.
- */
-lfs_indirtrunc(ip, bn, lastbn, level, countp)
- register struct inode *ip;
- daddr_t bn, lastbn;
- int level;
- long *countp;
-{
-#ifdef NOTLFS
- register int i;
- struct buf *bp;
- register struct fs *fs = ip->i_fs;
- register daddr_t *bap;
- daddr_t *copy, nb, last;
- long blkcount, factor;
- int nblocks, blocksreleased = 0;
- int error, allerror = 0;
-
- /*
- * Calculate index in current block of last
- * block to be kept. -1 indicates the entire
- * block so we need not calculate the index.
- */
- factor = 1;
- for (i = SINGLE; i < level; i++)
- factor *= NINDIR(fs);
- last = lastbn;
- if (lastbn > 0)
- last /= factor;
- nblocks = btodb(fs->fs_bsize);
- /*
- * Get buffer of block pointers, zero those
- * entries corresponding to blocks to be free'd,
- * and update on disk copy first.
- */
-#ifdef SECSIZE
- bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
- fs->fs_dbsize);
-#else SECSIZE
- error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize,
- NOCRED, &bp);
- if (error) {
- brelse(bp);
- *countp = 0;
- return (error);
- }
- bap = bp->b_un.b_daddr;
- MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
- bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
- bzero((caddr_t)&bap[last + 1],
- (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
- if (last == -1)
- bp->b_flags |= B_INVAL;
- error = bwrite(bp);
- if (error)
- allerror = error;
- bap = copy;
-
- /*
- * Recursively free totally unused blocks.
- */
- for (i = NINDIR(fs) - 1; i > last; i--) {
- nb = bap[i];
- if (nb == 0)
- continue;
- if (level > SINGLE) {
- error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
- &blkcount);
- if (error)
- allerror = error;
- blocksreleased += blkcount;
- }
- blkfree(ip, nb, (off_t)fs->fs_bsize);
- blocksreleased += nblocks;
- }
-
- /*
- * Recursively free last partial block.
- */
- if (level > SINGLE && lastbn >= 0) {
- last = lastbn % factor;
- nb = bap[i];
- if (nb != 0) {
- error = indirtrunc(ip, nb, last, level - 1, &blkcount);
- if (error)
- allerror = error;
- blocksreleased += blkcount;
- }