- dqrele(ip->i_dquot);
- ip->i_dquot = NODQUOT;
-#endif
- ip->i_flag = 0;
- return (0);
-}
-
-/*
- * Check accessed and update flags on an inode structure.
- * If any is on, update the inode with the current time.
- * If waitfor is given, then must ensure I/O order,
- * so wait for write to complete.
- */
-iupdat(ip, ta, tm, waitfor)
- register struct inode *ip;
- struct timeval *ta, *tm;
- int waitfor;
-{
- struct buf *bp;
- struct vnode *vp = ITOV(ip);
- struct dinode *dp;
- register struct fs *fs;
-
- fs = ip->i_fs;
- if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
- return (0);
- if (vp->v_mount->m_flag & M_RDONLY)
- return (0);
- error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
- (int)fs->fs_bsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (error);
- }
- if (ip->i_flag&IACC)
- ip->i_atime = ta->tv_sec;
- if (ip->i_flag&IUPD)
- ip->i_mtime = tm->tv_sec;
- if (ip->i_flag&ICHG)
- ip->i_ctime = time.tv_sec;
- ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
- dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
- *dp = ip->i_din;
- if (waitfor) {
- return (bwrite(bp));
- } else {
- bdwrite(bp);
- return (0);
- }
-}
-
-#define SINGLE 0 /* index of single indirect block */
-#define DOUBLE 1 /* index of double indirect block */
-#define TRIPLE 2 /* index of triple indirect block */
-/*
- * Truncate the inode ip to at most length size. Free affected disk
- * blocks -- the blocks of the file are removed in reverse order.
- *
- * NB: triple indirect blocks are untested.
- */
-itrunc(oip, length)
- register struct inode *oip;
- u_long length;
-{
- register daddr_t lastblock;
- daddr_t bn, lbn, lastiblock[NIADDR];
- register struct fs *fs;
- register struct inode *ip;
- struct buf *bp;
- int offset, osize, size, level;
- long count, nblocks, blocksreleased = 0;
- register int i;
- int error, allerror = 0;
- struct inode tip;
-
- if (oip->i_size <= length) {
- oip->i_flag |= ICHG|IUPD;
- error = iupdat(oip, &time, &time, 1);
- return (error);
- }
- /*
- * Calculate index into inode's block list of
- * last direct and indirect blocks (if any)
- * which we want to keep. Lastblock is -1 when
- * the file is truncated to 0.
- */
- fs = oip->i_fs;
- lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
- lastiblock[SINGLE] = lastblock - NDADDR;
- lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
- lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
- nblocks = btodb(fs->fs_bsize);
- /*
- * Update the size of the file. If the file is not being
- * truncated to a block boundry, the contents of the
- * partial block following the end of the file must be
- * zero'ed in case it ever become accessable again because
- * of subsequent file growth.
- */
- osize = oip->i_size;
- offset = blkoff(fs, length);
- if (offset == 0) {
- oip->i_size = length;
- } else {
- lbn = lblkno(fs, length);
- error = balloc(oip, lbn, offset, &bn, B_CLRBUF);
- if (error)
- return (error);
- if ((long)bn < 0)
- panic("itrunc: hole");
- oip->i_size = length;
- size = blksize(fs, oip, lbn);
- count = howmany(size, CLBYTES);
- munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
- error = bread(oip->i_devvp, bn, size, NOCRED, &bp);
- if (error) {
- oip->i_size = osize;
- brelse(bp);
- return (error);
- }
- bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
- bdwrite(bp);
- }
- /*
- * 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.
- */
- 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;
- allerror = syncip(oip);
-
- /*
- * 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;
- }
-
- /*
- * 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, ip, i);
- blkfree(ip, bn, bsize);
- 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, ip, lastblock);
- ip->i_size = length;
- newspace = blksize(fs, ip, lastblock);
- if (newspace == 0)
- panic("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("itrunc1");
- for (i = 0; i < NDADDR; i++)
- if (ip->i_db[i] != oip->i_db[i])
- panic("itrunc2");
-/* END PARANOIA */
- oip->i_blocks -= blocksreleased;
- if (oip->i_blocks < 0) /* sanity */
- oip->i_blocks = 0;
- oip->i_flag |= ICHG;
-#ifdef QUOTA
- (void) chkdq(oip, -blocksreleased, 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.
- */
-indirtrunc(ip, bn, lastbn, level, countp)
- register struct inode *ip;
- daddr_t bn, lastbn;
- int level;
- long *countp;
-{
- 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));
- 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;