summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2010-07-06 07:11:04 +0000
committerjeff <jeff@FreeBSD.org>2010-07-06 07:11:04 +0000
commit285c3f355cf6129d252b690ee2d17bc7d0964d7a (patch)
treecd17a559671a6f62e7bb6f03a3b2db2ba9afa573
parent26f5c3232149076d97f1f1ef9e8c339400f0a8be (diff)
downloadFreeBSD-src-285c3f355cf6129d252b690ee2d17bc7d0964d7a.zip
FreeBSD-src-285c3f355cf6129d252b690ee2d17bc7d0964d7a.tar.gz
- Handle the truncation of an inode with an effective link count of 0 in
the context of the process that reduced the effective count. Previously all truncation as a result of unlink happened in the softdep flush thread. This had the effect of being impossible to rate limit properly with the journal code. Now the process issuing unlinks is suspended when the journal files. This has a side-effect of improving rm performance by allowing more concurrent work. - Handle two cases in inactive, one for effnlink == 0 and another when nlink finally reaches 0. - Eliminate the SPACECOUNTED related code since the truncation is no longer delayed. Discussed with: mckusick
-rw-r--r--sys/ufs/ffs/ffs_alloc.c20
-rw-r--r--sys/ufs/ffs/ffs_inode.c6
-rw-r--r--sys/ufs/ffs/ffs_softdep.c82
-rw-r--r--sys/ufs/ffs/ffs_vnops.c3
-rw-r--r--sys/ufs/ffs/softdep.h2
-rw-r--r--sys/ufs/ufs/inode.h1
-rw-r--r--sys/ufs/ufs/ufs_inode.c14
-rw-r--r--sys/ufs/ufs/ufs_lookup.c2
-rw-r--r--sys/ufs/ufs/ufs_vnops.c32
9 files changed, 34 insertions, 128 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index b1f7ba0..b740bbb 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -191,11 +191,6 @@ retry:
bno = ffs_hashalloc(ip, cg, bpref, size, size, ffs_alloccg);
if (bno > 0) {
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);
if (flags & IO_EXT)
ip->i_flag |= IN_CHANGE;
@@ -321,11 +316,6 @@ retry:
if (bp->b_blkno != fsbtodb(fs, bno))
panic("ffs_realloccg: bad blockno");
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);
if (flags & IO_EXT)
ip->i_flag |= IN_CHANGE;
@@ -394,11 +384,6 @@ retry:
ffs_blkfree(ump, fs, ip->i_devvp, bprev, (long)osize,
ip->i_number, NULL);
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);
if (flags & IO_EXT)
ip->i_flag |= IN_CHANGE;
@@ -2422,11 +2407,6 @@ 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_inode.c b/sys/ufs/ffs/ffs_inode.c
index 3b69832..ffbe16e 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -180,6 +180,8 @@ ffs_truncate(vp, length, flags, cred, td)
*/
if ((flags & (IO_EXT | IO_NORMAL)) == 0)
flags |= IO_NORMAL;
+ if (!DOINGSOFTDEP(vp) && !DOINGASYNC(vp))
+ flags |= IO_SYNC;
/*
* If we are truncating the extended-attributes, and cannot
* do it with soft updates, then do it slowly here. If we are
@@ -310,10 +312,6 @@ ffs_truncate(vp, length, flags, cred, td)
*/
if ((error = ffs_syncvnode(vp, MNT_WAIT)) != 0)
goto out;
- UFS_LOCK(ump);
- if (ip->i_flag & IN_SPACECOUNTED)
- fs->fs_pendingblocks -= datablocks;
- UFS_UNLOCK(ump);
/*
* We have to journal the truncation before we change
* any blocks so we don't leave the file partially
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 0a62000..1977d60 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -5183,16 +5183,9 @@ softdep_setup_freeblocks(ip, length, flags)
fs->fs_frag, needj);
lbn += tmpval;
}
- /*
- * If the file was removed, then the space being freed was
- * 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) {
- UFS_LOCK(ip->i_ump);
- fs->fs_pendingblocks += datablocks;
- UFS_UNLOCK(ip->i_ump);
- }
+ UFS_LOCK(ip->i_ump);
+ fs->fs_pendingblocks += datablocks;
+ UFS_UNLOCK(ip->i_ump);
}
if ((flags & IO_EXT) != 0) {
oldextsize = ip->i_din2->di_extsize;
@@ -5674,11 +5667,9 @@ softdep_freefile(pvp, ino, mode)
freefile->fx_oldinum = ino;
freefile->fx_devvp = ip->i_devvp;
LIST_INIT(&freefile->fx_jwork);
- if ((ip->i_flag & IN_SPACECOUNTED) == 0) {
- UFS_LOCK(ip->i_ump);
- ip->i_fs->fs_pendinginodes += 1;
- UFS_UNLOCK(ip->i_ump);
- }
+ UFS_LOCK(ip->i_ump);
+ ip->i_fs->fs_pendinginodes += 1;
+ UFS_UNLOCK(ip->i_ump);
/*
* If the inodedep does not exist, then the zero'ed inode has
@@ -7379,55 +7370,6 @@ softdep_change_linkcnt(ip)
}
/*
- * Called when the effective link count and the reference count
- * on an inode drops to zero. At this point there are no names
- * referencing the file in the filesystem and no active file
- * references. The space associated with the file will be freed
- * as soon as the necessary soft dependencies are cleared.
- */
-void
-softdep_releasefile(ip)
- struct inode *ip; /* inode with the zero effective link count */
-{
- struct inodedep *inodedep;
- struct fs *fs;
- int extblocks;
-
- if (ip->i_effnlink > 0)
- panic("softdep_releasefile: file still referenced");
- /*
- * 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)
- return;
- /*
- * We have to deactivate a snapshot otherwise copyonwrites may
- * add blocks and the cleanup may remove blocks after we have
- * tried to account for them.
- */
- if ((ip->i_flags & SF_SNAPSHOT) != 0)
- ffs_snapremove(ITOV(ip));
- /*
- * If we are tracking an nlinkdelta, we have to also remember
- * whether we accounted for the freed space yet.
- */
- ACQUIRE_LOCK(&lk);
- if ((inodedep_lookup(UFSTOVFS(ip->i_ump), ip->i_number, 0, &inodedep)))
- inodedep->id_state |= SPACECOUNTED;
- FREE_LOCK(&lk);
- fs = ip->i_fs;
- extblocks = 0;
- if (fs->fs_magic == FS_UFS2_MAGIC)
- extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize));
- UFS_LOCK(ip->i_ump);
- ip->i_fs->fs_pendingblocks += DIP(ip, i_blocks) - extblocks;
- ip->i_fs->fs_pendinginodes += 1;
- UFS_UNLOCK(ip->i_ump);
- ip->i_flag |= IN_SPACECOUNTED;
-}
-
-/*
* Attach a sbdep dependency to the superblock buf so that we can keep
* track of the head of the linked list of referenced but unlinked inodes.
*/
@@ -7735,7 +7677,6 @@ handle_workitem_remove(dirrem, xp)
struct dirrem *dirrem;
struct vnode *xp;
{
- struct thread *td = curthread;
struct inodedep *inodedep;
struct workhead dotdotwk;
struct worklist *wk;
@@ -7808,9 +7749,8 @@ handle_workitem_remove(dirrem, xp)
/*
* Directory deletion. Decrement reference count for both the
* just deleted parent directory entry and the reference for ".".
- * Next truncate the directory to length zero. When the
- * truncation completes, arrange to have the reference count on
- * the parent decremented to account for the loss of "..".
+ * Arrange to have the reference count on the parent decremented
+ * to account for the loss of "..".
*/
ip->i_nlink -= 2;
DIP_SET(ip, i_nlink, ip->i_nlink);
@@ -7820,10 +7760,6 @@ handle_workitem_remove(dirrem, xp)
if (ip->i_nlink == 0)
unlinked_inodedep(mp, inodedep);
inodedep->id_nlinkdelta = ip->i_nlink - ip->i_effnlink;
- FREE_LOCK(&lk);
- if ((error = ffs_truncate(vp, (off_t)0, 0, td->td_ucred, td)) != 0)
- softdep_error("handle_workitem_remove: truncate", error);
- ACQUIRE_LOCK(&lk);
/*
* Rename a directory to a new parent. Since, we are both deleting
* and creating a new directory entry, the link count on the new
@@ -9899,8 +9835,6 @@ softdep_load_inodeblock(ip)
return;
}
ip->i_effnlink -= inodedep->id_nlinkdelta;
- if (inodedep->id_state & SPACECOUNTED)
- ip->i_flag |= IN_SPACECOUNTED;
FREE_LOCK(&lk);
}
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 96d0c7a..15c3f9f 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -1036,9 +1036,6 @@ ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *ucred)
fs = ip->i_fs;
dp = ip->i_din2;
- KASSERT(!(ip->i_flag & IN_SPACECOUNTED), ("inode %u: inode is dead",
- ip->i_number));
-
#ifdef INVARIANTS
if (uio->uio_rw != UIO_WRITE || fs->fs_magic != FS_UFS2_MAGIC)
panic("ffs_extwrite: mode");
diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h
index e61b81b..23afbf7 100644
--- a/sys/ufs/ffs/softdep.h
+++ b/sys/ufs/ffs/softdep.h
@@ -118,7 +118,7 @@
#define DIRCHG 0x000080 /* diradd, dirrem only */
#define GOINGAWAY 0x000100 /* indirdep, jremref only */
#define IOSTARTED 0x000200 /* inodedep, pagedep, bmsafemap only */
-#define SPACECOUNTED 0x000400 /* inodedep only */
+#define UNUSED400 0x000400 /* currently available. */
#define NEWBLOCK 0x000800 /* pagedep, jaddref only */
#define INPROGRESS 0x001000 /* dirrem, freeblks, freefrag, freefile only */
#define UFS1FMT 0x002000 /* indirdep only */
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
index 295b129..f6c4bb5 100644
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -122,7 +122,6 @@ struct inode {
#define IN_MODIFIED 0x0008 /* Inode has been modified. */
#define IN_NEEDSYNC 0x0010 /* Inode requires fsync. */
#define IN_LAZYMOD 0x0040 /* Modified, but don't write yet. */
-#define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */
#define IN_LAZYACCESS 0x0100 /* Process IN_ACCESS after the
suspension finished */
#define IN_EA_LOCKED 0x0200
diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c
index 17ec28e..a281ae5 100644
--- a/sys/ufs/ufs/ufs_inode.c
+++ b/sys/ufs/ufs/ufs_inode.c
@@ -76,6 +76,7 @@ ufs_inactive(ap)
struct thread *td = ap->a_td;
mode_t mode;
int error = 0;
+ int isize;
struct mount *mp;
mp = NULL;
@@ -118,18 +119,21 @@ ufs_inactive(ap)
}
}
}
- if (ip->i_effnlink == 0 && DOINGSOFTDEP(vp))
- softdep_releasefile(ip);
- if (ip->i_nlink <= 0 && !UFS_RDONLY(ip)) {
+ isize = ip->i_size;
+ if (ip->i_ump->um_fstype == UFS2)
+ isize += ip->i_din2->di_extsize;
+ if (ip->i_effnlink <= 0 && isize && !UFS_RDONLY(ip)) {
#ifdef QUOTA
if (!getinoquota(ip))
(void)chkiq(ip, -1, NOCRED, FORCE);
#endif
+ error = UFS_TRUNCATE(vp, (off_t)0, IO_EXT | IO_NORMAL,
+ NOCRED, td);
+ }
+ if (ip->i_nlink <= 0 && ip->i_mode && !UFS_RDONLY(ip)) {
#ifdef UFS_EXTATTR
ufs_extattr_vnode_inactive(vp, td);
#endif
- error = UFS_TRUNCATE(vp, (off_t)0, IO_EXT | IO_NORMAL,
- NOCRED, td);
/*
* Setting the mode to zero needs to wait for the inode
* to be written just as does a change to the link count.
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index c779491..e997718 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -248,6 +248,8 @@ ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
*vpp = NULL;
dp = VTOI(vdp);
+ if (dp->i_effnlink == 0)
+ return (ENOENT);
/*
* Create a vm object if vmiodirenable is enabled.
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index f8d45cf..9c8bc1b 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1119,7 +1119,7 @@ ufs_rename(ap)
struct direct newdir;
off_t endoff;
int doingdirectory, newparent;
- int error = 0, ioflag;
+ int error = 0;
struct mount *mp;
ino_t ino;
@@ -1443,8 +1443,8 @@ relock:
}
if (doingdirectory && !DOINGSOFTDEP(tvp)) {
/*
- * Truncate inode. The only stuff left in the directory
- * is "." and "..". The "." reference is inconsequential
+ * The only stuff left in the directory is "."
+ * and "..". The "." reference is inconsequential
* since we are quashing it. We have removed the "."
* reference and the reference in the parent directory,
* but there may be other hard links. The soft
@@ -1461,13 +1461,6 @@ relock:
tip->i_nlink--;
DIP_SET(tip, i_nlink, tip->i_nlink);
tip->i_flag |= IN_CHANGE;
- ioflag = IO_NORMAL;
- if (!DOINGASYNC(tvp))
- ioflag |= IO_SYNC;
- /* Don't go to bad here as the new link exists. */
- if ((error = UFS_TRUNCATE(tvp, (off_t)0, ioflag,
- tcnp->cn_cred, tcnp->cn_thread)) != 0)
- goto unlockout;
}
}
@@ -1993,7 +1986,7 @@ ufs_rmdir(ap)
struct vnode *dvp = ap->a_dvp;
struct componentname *cnp = ap->a_cnp;
struct inode *ip, *dp;
- int error, ioflag;
+ int error;
ip = VTOI(vp);
dp = VTOI(dvp);
@@ -2049,10 +2042,10 @@ ufs_rmdir(ap)
}
cache_purge(dvp);
/*
- * Truncate inode. The only stuff left in the directory is "." and
- * "..". The "." reference is inconsequential since we are quashing
- * it. The soft dependency code will arrange to do these operations
- * after the parent directory entry has been deleted on disk, so
+ * The only stuff left in the directory is "." and "..". The "."
+ * reference is inconsequential since we are quashing it. The soft
+ * dependency code will arrange to do these operations after
+ * the parent directory entry has been deleted on disk, so
* when running with that code we avoid doing them now.
*/
if (!DOINGSOFTDEP(vp)) {
@@ -2062,11 +2055,6 @@ ufs_rmdir(ap)
ip->i_nlink--;
DIP_SET(ip, i_nlink, ip->i_nlink);
ip->i_flag |= IN_CHANGE;
- ioflag = IO_NORMAL;
- if (!DOINGASYNC(vp))
- ioflag |= IO_SYNC;
- error = UFS_TRUNCATE(vp, (off_t)0, ioflag, cnp->cn_cred,
- cnp->cn_thread);
}
cache_purge(vp);
#ifdef UFS_DIRHASH
@@ -2137,6 +2125,7 @@ ufs_readdir(ap)
} */ *ap;
{
struct uio *uio = ap->a_uio;
+ struct inode *ip;
int error;
size_t count, lost;
off_t off;
@@ -2147,6 +2136,9 @@ ufs_readdir(ap)
* the cookies to determine where in the block to start.
*/
uio->uio_offset &= ~(DIRBLKSIZ - 1);
+ ip = VTOI(ap->a_vp);
+ if (ip->i_effnlink == 0)
+ return (0);
off = uio->uio_offset;
count = uio->uio_resid;
/* Make sure we don't return partial entries. */
OpenPOWER on IntegriCloud