aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs
diff options
context:
space:
mode:
authorJeff Roberson <jeff@FreeBSD.org>2010-07-06 07:11:04 +0000
committerJeff Roberson <jeff@FreeBSD.org>2010-07-06 07:11:04 +0000
commit9f9c8c59ae393bb282c4e58b448fa38f93bcea52 (patch)
treecd17a559671a6f62e7bb6f03a3b2db2ba9afa573 /sys/ufs
parent24d37c1eec746441b10ecae68305f57602cd0da3 (diff)
downloadsrc-9f9c8c59ae393bb282c4e58b448fa38f93bcea52.tar.gz
src-9f9c8c59ae393bb282c4e58b448fa38f93bcea52.zip
- 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
Notes
Notes: svn path=/head/; revision=209717
Diffstat (limited to 'sys/ufs')
-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 b1f7ba0127f7..b740bbbb8683 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 3b6983258b93..ffbe16e56dd7 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 0a6200006ded..1977d609afc7 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 96d0c7a3e8da..15c3f9f05907 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 e61b81b15bb8..23afbf789a13 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 295b12975e25..f6c4bb5aa07c 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 17ec28e706e6..a281ae50cbc8 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 c7794915a8bb..e9977183cb6b 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 f8d45cfceb8e..9c8bc1b98f32 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. */