summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2011-07-04 22:08:04 +0000
committerjeff <jeff@FreeBSD.org>2011-07-04 22:08:04 +0000
commit74e3f8c8c5340964133a54778690ea0235f2290f (patch)
tree76a6564bbd91c2f7f2ae92e6deae57a0042ca7c4 /sys/ufs
parent0a80dd60a68d71df7e33093d19fe5bf69b02617f (diff)
downloadFreeBSD-src-74e3f8c8c5340964133a54778690ea0235f2290f.zip
FreeBSD-src-74e3f8c8c5340964133a54778690ea0235f2290f.tar.gz
- Speed up pendingblock processing again. Having too much delay between
ffs_blkfree() and the pending adjustment causes all kinds of space related problems.
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_softdep.c53
-rw-r--r--sys/ufs/ffs/softdep.h3
2 files changed, 41 insertions, 15 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 273f3ad..5fa8e64 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -880,6 +880,7 @@ static inline void setup_freeext(struct freeblks *, struct inode *, int, int);
static inline void setup_freeindir(struct freeblks *, struct inode *, int,
ufs_lbn_t, int);
static inline struct freeblks *newfreeblks(struct mount *, struct inode *);
+static void freeblks_free(struct ufsmount *, struct freeblks *, int);
static void indir_trunc(struct freework *, ufs2_daddr_t, ufs_lbn_t);
ufs2_daddr_t blkcount(struct fs *, ufs2_daddr_t, off_t);
static int trunc_check_buf(struct buf *, int *, ufs_lbn_t, int, int);
@@ -5751,7 +5752,6 @@ newfreeblks(mp, ip)
freeblks->fb_modrev = DIP(ip, i_modrev);
freeblks->fb_devvp = ip->i_devvp;
freeblks->fb_chkcnt = 0;
- freeblks->fb_freecnt = 0;
freeblks->fb_len = 0;
return (freeblks);
@@ -6199,7 +6199,7 @@ softdep_journal_freeblocks(ip, cred, length, flags)
quotaref(vp, freeblks->fb_quota);
(void) chkdq(ip, -datablocks, NOCRED, 0);
#endif
- freeblks->fb_chkcnt = datablocks;
+ freeblks->fb_chkcnt = -datablocks;
UFS_LOCK(ip->i_ump);
fs->fs_pendingblocks += datablocks;
UFS_UNLOCK(ip->i_ump);
@@ -6429,7 +6429,7 @@ softdep_setup_freeblocks(ip, length, flags)
quotaref(vp, freeblks->fb_quota);
(void) chkdq(ip, -datablocks, NOCRED, 0);
#endif
- freeblks->fb_chkcnt = datablocks;
+ freeblks->fb_chkcnt = -datablocks;
UFS_LOCK(ip->i_ump);
fs->fs_pendingblocks += datablocks;
UFS_UNLOCK(ip->i_ump);
@@ -7284,8 +7284,8 @@ freework_freeblock(freework)
freeblks->fb_cgwait++;
WORKLIST_INSERT(&wkhd, &freework->fw_list);
}
- freeblks->fb_freecnt += btodb(bsize);
FREE_LOCK(&lk);
+ freeblks_free(ump, freeblks, btodb(bsize));
ffs_blkfree(ump, fs, freeblks->fb_devvp, freework->fw_blkno, bsize,
freeblks->fb_inum, freeblks->fb_vtype, &wkhd);
ACQUIRE_LOCK(&lk);
@@ -7459,6 +7459,33 @@ handle_workitem_freeblocks(freeblks, flags)
}
/*
+ * Handle completion of block free via truncate. This allows fs_pending
+ * to track the actual free block count more closely than if we only updated
+ * it at the end. We must be careful to handle cases where the block count
+ * on free was incorrect.
+ */
+static void
+freeblks_free(ump, freeblks, blocks)
+ struct ufsmount *ump;
+ struct freeblks *freeblks;
+ int blocks;
+{
+ struct fs *fs;
+ ufs2_daddr_t remain;
+
+ UFS_LOCK(ump);
+ remain = -freeblks->fb_chkcnt;
+ freeblks->fb_chkcnt += blocks;
+ if (remain > 0) {
+ if (remain < blocks)
+ blocks = remain;
+ fs = ump->um_fs;
+ fs->fs_pendingblocks -= blocks;
+ }
+ UFS_UNLOCK(ump);
+}
+
+/*
* Once all of the freework workitems are complete we can retire the
* freeblocks dependency and any journal work awaiting completion. This
* can not be called until all other dependencies are stable on disk.
@@ -7478,7 +7505,7 @@ handle_complete_freeblocks(freeblks, flags)
ump = VFSTOUFS(freeblks->fb_list.wk_mp);
fs = ump->um_fs;
flags = LK_EXCLUSIVE | flags;
- spare = freeblks->fb_freecnt - freeblks->fb_chkcnt;
+ spare = freeblks->fb_chkcnt;
/*
* If we did not release the expected number of blocks we may have
@@ -7501,9 +7528,9 @@ handle_complete_freeblocks(freeblks, flags)
}
vput(vp);
}
- if (freeblks->fb_chkcnt) {
+ if (spare < 0) {
UFS_LOCK(ump);
- fs->fs_pendingblocks -= freeblks->fb_chkcnt;
+ fs->fs_pendingblocks += spare;
UFS_UNLOCK(ump);
}
#ifdef QUOTA
@@ -7559,7 +7586,7 @@ indir_trunc(freework, dbn, lbn)
ufs2_daddr_t nb, nnb, *bap2 = 0;
ufs_lbn_t lbnadd, nlbn;
int i, nblocks, ufs1fmt;
- int fs_pendingblocks;
+ int freedblocks;
int goingaway;
int freedeps;
int needj;
@@ -7701,16 +7728,18 @@ indir_trunc(freework, dbn, lbn)
bp->b_flags |= B_INVAL | B_NOCACHE;
brelse(bp);
}
- fs_pendingblocks = 0;
+ freedblocks = 0;
if (level == 0)
- fs_pendingblocks = (nblocks * cnt);
+ freedblocks = (nblocks * cnt);
+ if (needj == 0)
+ freedblocks += nblocks;
+ freeblks_free(ump, freeblks, freedblocks);
/*
* If we are journaling set up the ref counts and offset so this
* indirect can be completed when its children are free.
*/
if (needj) {
ACQUIRE_LOCK(&lk);
- freeblks->fb_freecnt += fs_pendingblocks;
freework->fw_off = i;
freework->fw_ref += freedeps;
freework->fw_ref -= NINDIR(fs) + 1;
@@ -7724,12 +7753,10 @@ indir_trunc(freework, dbn, lbn)
/*
* If we're not journaling we can free the indirect now.
*/
- fs_pendingblocks += nblocks;
dbn = dbtofsb(fs, dbn);
ffs_blkfree(ump, fs, freeblks->fb_devvp, dbn, fs->fs_bsize,
freeblks->fb_inum, freeblks->fb_vtype, NULL);
/* Non SUJ softdep does single-threaded truncations. */
- freeblks->fb_freecnt += fs_pendingblocks;
if (freework->fw_blkno == dbn) {
freework->fw_state |= ALLCOMPLETE;
ACQUIRE_LOCK(&lk);
diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h
index 80c7315..b251ba8 100644
--- a/sys/ufs/ffs/softdep.h
+++ b/sys/ufs/ffs/softdep.h
@@ -536,8 +536,7 @@ struct freeblks {
#endif
uint64_t fb_modrev; /* Inode revision at start of trunc. */
off_t fb_len; /* Length we're truncating to. */
- ufs2_daddr_t fb_chkcnt; /* Expected blks released. */
- ufs2_daddr_t fb_freecnt; /* Actual blocks released. */
+ ufs2_daddr_t fb_chkcnt; /* Blocks released. */
ino_t fb_inum; /* inode owner of blocks */
enum vtype fb_vtype; /* inode owner's file type */
uid_t fb_uid; /* uid of previous owner of blocks */
OpenPOWER on IntegriCloud