From 98fff6b57c66c4cdfb6d74220fff58471fdbcf69 Mon Sep 17 00:00:00 2001 From: Brian Somers Date: Fri, 23 Feb 2007 20:23:35 +0000 Subject: [PATCH] Account for di_blocks allocations when IN_SPACECOUNTED is set in an inode's i_flag. It's possible that after ufs_infactive() calls softdep_releasefile(), i_nlink stays >0 for a considerable amount of time (> 60 seconds here). During this period, any ffs allocation routines that alter di_blocks must also account for the blocks in the filesystem's fs_pendingblocks value. This change fixes an eventual df/du discrepency that will happen as the result of fs_pendingblocks being reduced to <0. The only manifestation of this that people may recognise is the following message on boot: /somefs: update error: blocks -N files M at which point the negative pending block count is adjusted to zero. Reviewed by: tegge MFC after: 3 weeks --- sys/ufs/ffs/ffs_alloc.c | 31 ++++++++++++++++++++++++++++--- sys/ufs/ffs/ffs_softdep.c | 8 ++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index a746a69a2de5..67c8fc3bdd03 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -143,6 +143,7 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp) int cg, reclaimed; static struct timeval lastfail; static int curfail; + int64_t delta; #ifdef QUOTA int error; #endif @@ -183,7 +184,13 @@ retry: cg = dtog(fs, bpref); bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg); if (bno > 0) { - DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + btodb(size)); + delta = btodb(size); + if (ip->i_flag & IN_SPACECOUNTED) { + UFS_LOCK(ump); + fs->fs_pendingblocks += delta; + UFS_UNLOCK(ump); + } + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bnp = bno; return (0); @@ -237,6 +244,7 @@ ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, cred, bpp) ufs2_daddr_t bno; static struct timeval lastfail; static int curfail; + int64_t delta; *bpp = 0; vp = ITOV(ip); @@ -302,7 +310,13 @@ retry: if (bno) { if (bp->b_blkno != fsbtodb(fs, bno)) panic("ffs_realloccg: bad blockno"); - DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + btodb(nsize - osize)); + delta = btodb(nsize - osize); + if (ip->i_flag & IN_SPACECOUNTED) { + UFS_LOCK(ump); + fs->fs_pendingblocks += delta; + UFS_UNLOCK(ump); + } + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); ip->i_flag |= IN_CHANGE | IN_UPDATE; allocbuf(bp, nsize); bp->b_flags |= B_DONE; @@ -371,7 +385,13 @@ retry: ffs_blkfree(ump, fs, ip->i_devvp, bno + numfrags(fs, nsize), (long)(request - nsize), ip->i_number); - DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + btodb(nsize - osize)); + delta = btodb(nsize - osize); + if (ip->i_flag & IN_SPACECOUNTED) { + UFS_LOCK(ump); + fs->fs_pendingblocks += delta; + UFS_UNLOCK(ump); + } + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); ip->i_flag |= IN_CHANGE | IN_UPDATE; allocbuf(bp, nsize); bp->b_flags |= B_DONE; @@ -2431,6 +2451,11 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) break; ip = VTOI(vp); + if (ip->i_flag & IN_SPACECOUNTED) { + UFS_LOCK(ump); + fs->fs_pendingblocks += cmd.size; + UFS_UNLOCK(ump); + } DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + cmd.size); ip->i_flag |= IN_CHANGE; vput(vp); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 4ae9980e2da9..6d13610aeca9 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -2229,7 +2229,7 @@ softdep_setup_freeblocks(ip, length, flags) } /* * If the file was removed, then the space being freed was - * accounted for then (see softdep_filereleased()). If the + * accounted for then (see softdep_releasefile()). If the * file is merely being truncated, then we account for it now. */ if ((ip->i_flag & IN_SPACECOUNTED) == 0) { @@ -2747,7 +2747,7 @@ handle_workitem_freeblocks(freeblks, flags) if ((bn = freeblks->fb_iblks[level]) == 0) continue; if ((error = indir_trunc(freeblks, fsbtodb(fs, bn), - level, baselbns[level], &blocksreleased)) == 0) + level, baselbns[level], &blocksreleased)) != 0) allerror = error; ffs_blkfree(ump, fs, freeblks->fb_devvp, bn, fs->fs_bsize, freeblks->fb_previousinum); @@ -3514,9 +3514,9 @@ softdep_releasefile(ip) int extblocks; if (ip->i_effnlink > 0) - panic("softdep_filerelease: file still referenced"); + panic("softdep_releasefile: file still referenced"); /* - * We may be called several times as the real reference count + * We may be called several times as the on-disk link count * drops to zero. We only want to account for the space once. */ if (ip->i_flag & IN_SPACECOUNTED)