diff options
| author | hannken <hannken@NetBSD.org> | 2004-01-10 16:23:36 +0000 |
|---|---|---|
| committer | hannken <hannken@NetBSD.org> | 2004-01-10 16:23:36 +0000 |
| commit | 8308a4868d9900cbffdcdef06dc34d8171da67dc (patch) | |
| tree | 6729e838308f21d31aad0254396c952439c6b96a /sys | |
| parent | 42fd51da28f50124a22b58cff097cdf21419dd89 (diff) | |
Split out softdep_flushworklist() from softdep_flushfiles() so that
it can be used to clear the work queue.
Cleanup ffs_sync() which did not synchronously wait when MNT_WAIT
was specified. Clear the work queue when MNT_WAIT is specified.
Result is a clean on-disk file system after ffs_sync(.., MNT_WAIT, ..)
From FreeBSD.
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 3 | ||||
| -rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 104 | ||||
| -rw-r--r-- | sys/ufs/ffs/ffs_softdep.stub.c | 14 | ||||
| -rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 24 |
4 files changed, 103 insertions, 42 deletions
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 00d8b65aab3..8c6109edeca 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_extern.h,v 1.35 2004/01/02 05:08:57 dbj Exp $ */ +/* $NetBSD: ffs_extern.h,v 1.36 2004/01/10 16:23:36 hannken Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -161,6 +161,7 @@ void softdep_initialize __P((void)); void softdep_reinitialize __P((void)); int softdep_mount __P((struct vnode *, struct mount *, struct fs *, struct ucred *)); +int softdep_flushworklist __P((struct mount *, int *, struct proc *)); int softdep_flushfiles __P((struct mount *, int, struct proc *)); void softdep_update_inodeblock __P((struct inode *, struct buf *, int)); void softdep_load_inodeblock __P((struct inode *)); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 3038ca0dc4a..58b1c42d26c 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_softdep.c,v 1.53 2003/10/15 11:29:01 hannken Exp $ */ +/* $NetBSD: ffs_softdep.c,v 1.54 2004/01/10 16:23:36 hannken Exp $ */ /* * Copyright 1998 Marshall Kirk McKusick. All Rights Reserved. @@ -33,7 +33,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.c,v 1.53 2003/10/15 11:29:01 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.c,v 1.54 2004/01/10 16:23:36 hannken Exp $"); #include <sys/param.h> #include <sys/buf.h> @@ -551,7 +551,8 @@ workitem_free(item, type) */ static struct workhead softdep_workitem_pending; static struct worklist *worklist_tail; -static int softdep_worklist_busy; +static int softdep_worklist_busy; /* 1 => trying to do unmount */ +static int softdep_worklist_req; /* serialized waiters */ static int max_softdeps; /* maximum number of structs before slowdown */ static int tickdelay = 2; /* number of ticks to pause during slowdown */ static int proc_waiting; /* tracks whether we have a timeout posted */ @@ -648,8 +649,12 @@ softdep_process_worklist(matchmnt) * (below) can get an accurate count of the number of items * related to its mount point that are in the list. */ - if (softdep_worklist_busy && matchmnt == NULL) - return (-1); + if (matchmnt == NULL) { + if (softdep_worklist_busy < 0) + return (-1); + softdep_worklist_busy += 1; + } + /* * If requested, try removing inode or removal dependencies. */ @@ -727,8 +732,16 @@ softdep_process_worklist(matchmnt) TYPENAME(wk->wk_type)); /* NOTREACHED */ } - if (softdep_worklist_busy && matchmnt == NULL) - return (-1); + + /* + * If a umount operation wants to run the worklist + * accurately, abort. + */ + if (softdep_worklist_req && matchmnt == NULL) { + ACQUIRE_LOCK(&lk); + matchcnt = -1; + break; + } /* * If requested, try removing inode or removal dependencies. */ @@ -750,6 +763,11 @@ softdep_process_worklist(matchmnt) ACQUIRE_LOCK(&lk); softdep_freequeue_process(); } + if (matchmnt == NULL) { + softdep_worklist_busy -= 1; + if (softdep_worklist_req && softdep_worklist_busy == 0) + wakeup(&softdep_worklist_req); + } FREE_LOCK(&lk); return (matchcnt); } @@ -783,46 +801,33 @@ softdep_move_dependencies(oldbp, newbp) * Purge the work list of all items associated with a particular mount point. */ int -softdep_flushfiles(oldmnt, flags, p) +softdep_flushworklist(oldmnt, countp, p) struct mount *oldmnt; - int flags; + int *countp; struct proc *p; { struct vnode *devvp; - int error, loopcnt; + int count, error = 0; /* * Await our turn to clear out the queue. */ - while (softdep_worklist_busy) - tsleep(&lbolt, PRIBIO, "softflush", 0); - softdep_worklist_busy = 1; - if ((error = ffs_flushfiles(oldmnt, flags, p)) != 0) { - softdep_worklist_busy = 0; - return (error); + while (softdep_worklist_busy) { + softdep_worklist_req += 1; + tsleep(&softdep_worklist_req, PRIBIO, "softflush", 0); + softdep_worklist_req -= 1; } + softdep_worklist_busy = -1; /* * Alternately flush the block device associated with the mount * point and process any dependencies that the flushing - * creates. In theory, this loop can happen at most twice, - * but we give it a few extra just to be sure. + * creates. We continue until no more worklist dependencies + * are found. */ + *countp = 0; devvp = VFSTOUFS(oldmnt)->um_devvp; - for (loopcnt = 10; loopcnt > 0; ) { - if (softdep_process_worklist(oldmnt) == 0) { - loopcnt--; - /* - * Do another flush in case any vnodes were brought in - * as part of the cleanup operations. - */ - if ((error = ffs_flushfiles(oldmnt, flags, p)) != 0) - break; - /* - * If we still found nothing to do, we are really done. - */ - if (softdep_process_worklist(oldmnt) == 0) - break; - } + while ((count = softdep_process_worklist(oldmnt)) > 0) { + *countp += count; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_FSYNC(devvp, p->p_ucred, FSYNC_WAIT, 0, 0, p); VOP_UNLOCK(devvp, 0); @@ -830,6 +835,39 @@ softdep_flushfiles(oldmnt, flags, p) break; } softdep_worklist_busy = 0; + if (softdep_worklist_req) + wakeup(&softdep_worklist_req); + return (error); +} + +/* + * Flush all vnodes and worklist items associated with a specified mount point. + */ +int +softdep_flushfiles(oldmnt, flags, p) + struct mount *oldmnt; + int flags; + struct proc *p; +{ + int error, count, loopcnt; + + /* + * Alternately flush the vnodes associated with the mount + * point and process any dependencies that the flushing + * creates. In theory, this loop can happen at most twice, + * but we give it a few extra just to be sure. + */ + for (loopcnt = 10; loopcnt > 0; loopcnt--) { + /* + * Do another flush in case any vnodes were brought in + * as part of the cleanup operations. + */ + if ((error = ffs_flushfiles(oldmnt, flags, p)) != 0) + break; + if ((error = softdep_flushworklist(oldmnt, &count, p)) != 0 || + count == 0) + break; + } /* * If we are unmounting then it is an error to fail. If we * are simply trying to downgrade to read-only, then filesystem diff --git a/sys/ufs/ffs/ffs_softdep.stub.c b/sys/ufs/ffs/ffs_softdep.stub.c index 090bd4a93db..d9bbce0a8e7 100644 --- a/sys/ufs/ffs/ffs_softdep.stub.c +++ b/sys/ufs/ffs/ffs_softdep.stub.c @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_softdep.stub.c,v 1.12 2003/06/29 22:32:36 fvdl Exp $ */ +/* $NetBSD: ffs_softdep.stub.c,v 1.13 2004/01/10 16:23:36 hannken Exp $ */ /* * Copyright 1997 Marshall Kirk McKusick. All Rights Reserved. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.stub.c,v 1.12 2003/06/29 22:32:36 fvdl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.stub.c,v 1.13 2004/01/10 16:23:36 hannken Exp $"); #include <sys/param.h> #include <sys/vnode.h> @@ -45,6 +45,16 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_softdep.stub.c,v 1.12 2003/06/29 22:32:36 fvdl E #include <ufs/ufs/ufs_extern.h> int +softdep_flushworklist(oldmnt, countp, p) + struct mount *oldmnt; + int *countp; + struct proc *p; +{ + + panic("softdep_flushworklist called"); +} + +int softdep_flushfiles(oldmnt, flags, p) struct mount *oldmnt; int flags; diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 2055d1dfc83..72a940d07d4 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_vfsops.c,v 1.131 2004/01/09 19:10:22 dbj Exp $ */ +/* $NetBSD: ffs_vfsops.c,v 1.132 2004/01/10 16:23:36 hannken Exp $ */ /* * Copyright (c) 1989, 1991, 1993, 1994 @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.131 2004/01/09 19:10:22 dbj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.132 2004/01/10 16:23:36 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -1221,7 +1221,7 @@ ffs_sync(mp, waitfor, cred, p) struct inode *ip; struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs; - int error, allerror = 0; + int error, count, allerror = 0; fs = ump->um_fs; if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ @@ -1270,14 +1270,26 @@ loop: /* * Force stale file system control information to be flushed. */ - if (waitfor != MNT_LAZY) { - if (ump->um_mountp->mnt_flag & MNT_SOFTDEP) - waitfor = MNT_NOWAIT; + if (waitfor == MNT_WAIT && (ump->um_mountp->mnt_flag & MNT_SOFTDEP)) { + if ((error = softdep_flushworklist(ump->um_mountp, &count, p))) + allerror = error; + /* Flushed work items may create new vnodes to clean */ + if (allerror == 0 && count) { + simple_lock(&mntvnode_slock); + goto loop; + } + } + if (waitfor != MNT_LAZY && (ump->um_devvp->v_numoutput > 0 || + !LIST_EMPTY(&ump->um_devvp->v_dirtyblkhd))) { vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, p)) != 0) allerror = error; VOP_UNLOCK(ump->um_devvp, 0); + if (allerror == 0 && waitfor == MNT_WAIT) { + simple_lock(&mntvnode_slock); + goto loop; + } } #ifdef QUOTA qsync(mp); |
