313 lines
9.6 KiB
Diff
313 lines
9.6 KiB
Diff
Index: sys/ufs/ffs/ffs_softdep.c
|
|
===================================================================
|
|
--- sys/ufs/ffs/ffs_softdep.c (revision 282245)
|
|
+++ sys/ufs/ffs/ffs_softdep.c (working copy)
|
|
@@ -735,9 +735,10 @@ static struct malloc_type *memtype[] = {
|
|
static void check_clear_deps(struct mount *);
|
|
static void softdep_error(char *, int);
|
|
static int softdep_process_worklist(struct mount *, int);
|
|
-static int softdep_waitidle(struct mount *);
|
|
+static int softdep_waitidle(struct mount *, int);
|
|
static void drain_output(struct vnode *);
|
|
static struct buf *getdirtybuf(struct buf *, struct rwlock *, int);
|
|
+static int check_inodedep_free(struct inodedep *);
|
|
static void clear_remove(struct mount *);
|
|
static void clear_inodedeps(struct mount *);
|
|
static void unlinked_inodedep(struct mount *, struct inodedep *);
|
|
@@ -1377,6 +1378,10 @@ softdep_flush(addr)
|
|
mp = (struct mount *)addr;
|
|
ump = VFSTOUFS(mp);
|
|
atomic_add_int(&stat_flush_threads, 1);
|
|
+ ACQUIRE_LOCK(ump);
|
|
+ ump->softdep_flags &= ~FLUSH_STARTING;
|
|
+ wakeup(&ump->softdep_flushtd);
|
|
+ FREE_LOCK(ump);
|
|
if (print_threads) {
|
|
if (stat_flush_threads == 1)
|
|
printf("Running %s at pid %d\n", bufdaemonproc->p_comm,
|
|
@@ -1389,7 +1394,7 @@ softdep_flush(addr)
|
|
VFSTOUFS(mp)->softdep_jblocks->jb_suspended))
|
|
kthread_suspend_check();
|
|
ACQUIRE_LOCK(ump);
|
|
- if ((ump->softdep_flags & FLUSH_CLEANUP) == 0)
|
|
+ if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0)
|
|
msleep(&ump->softdep_flushtd, LOCK_PTR(ump), PVM,
|
|
"sdflush", hz / 2);
|
|
ump->softdep_flags &= ~FLUSH_CLEANUP;
|
|
@@ -1419,11 +1424,9 @@ worklist_speedup(mp)
|
|
|
|
ump = VFSTOUFS(mp);
|
|
LOCK_OWNED(ump);
|
|
- if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0) {
|
|
+ if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0)
|
|
ump->softdep_flags |= FLUSH_CLEANUP;
|
|
- if (ump->softdep_flushtd->td_wchan == &ump->softdep_flushtd)
|
|
- wakeup(&ump->softdep_flushtd);
|
|
- }
|
|
+ wakeup(&ump->softdep_flushtd);
|
|
}
|
|
|
|
static int
|
|
@@ -1468,14 +1471,10 @@ softdep_speedup(ump)
|
|
TAILQ_INSERT_TAIL(&softdepmounts, sdp, sd_next);
|
|
FREE_GBLLOCK(&lk);
|
|
if ((altump->softdep_flags &
|
|
- (FLUSH_CLEANUP | FLUSH_EXIT)) == 0) {
|
|
+ (FLUSH_CLEANUP | FLUSH_EXIT)) == 0)
|
|
altump->softdep_flags |= FLUSH_CLEANUP;
|
|
- altump->um_softdep->sd_cleanups++;
|
|
- if (altump->softdep_flushtd->td_wchan ==
|
|
- &altump->softdep_flushtd) {
|
|
- wakeup(&altump->softdep_flushtd);
|
|
- }
|
|
- }
|
|
+ altump->um_softdep->sd_cleanups++;
|
|
+ wakeup(&altump->softdep_flushtd);
|
|
FREE_LOCK(altump);
|
|
}
|
|
}
|
|
@@ -1887,8 +1886,8 @@ softdep_flushworklist(oldmnt, countp, td
|
|
struct thread *td;
|
|
{
|
|
struct vnode *devvp;
|
|
- int count, error = 0;
|
|
struct ufsmount *ump;
|
|
+ int count, error;
|
|
|
|
/*
|
|
* Alternately flush the block device associated with the mount
|
|
@@ -1897,6 +1896,7 @@ softdep_flushworklist(oldmnt, countp, td
|
|
* are found.
|
|
*/
|
|
*countp = 0;
|
|
+ error = 0;
|
|
ump = VFSTOUFS(oldmnt);
|
|
devvp = ump->um_devvp;
|
|
while ((count = softdep_process_worklist(oldmnt, 1)) > 0) {
|
|
@@ -1904,36 +1904,47 @@ softdep_flushworklist(oldmnt, countp, td
|
|
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
|
|
error = VOP_FSYNC(devvp, MNT_WAIT, td);
|
|
VOP_UNLOCK(devvp, 0);
|
|
- if (error)
|
|
+ if (error != 0)
|
|
break;
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
+#define SU_WAITIDLE_RETRIES 20
|
|
static int
|
|
-softdep_waitidle(struct mount *mp)
|
|
+softdep_waitidle(struct mount *mp, int flags __unused)
|
|
{
|
|
struct ufsmount *ump;
|
|
- int error;
|
|
- int i;
|
|
+ struct vnode *devvp;
|
|
+ struct thread *td;
|
|
+ int error, i;
|
|
|
|
ump = VFSTOUFS(mp);
|
|
+ devvp = ump->um_devvp;
|
|
+ td = curthread;
|
|
+ error = 0;
|
|
ACQUIRE_LOCK(ump);
|
|
- for (i = 0; i < 10 && ump->softdep_deps; i++) {
|
|
+ for (i = 0; i < SU_WAITIDLE_RETRIES && ump->softdep_deps != 0; i++) {
|
|
ump->softdep_req = 1;
|
|
- if (ump->softdep_on_worklist)
|
|
- panic("softdep_waitidle: work added after flush.");
|
|
- msleep(&ump->softdep_deps, LOCK_PTR(ump), PVM, "softdeps", 1);
|
|
+ KASSERT((flags & FORCECLOSE) == 0 ||
|
|
+ ump->softdep_on_worklist == 0,
|
|
+ ("softdep_waitidle: work added after flush"));
|
|
+ msleep(&ump->softdep_deps, LOCK_PTR(ump), PVM | PDROP,
|
|
+ "softdeps", 10 * hz);
|
|
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
|
|
+ error = VOP_FSYNC(devvp, MNT_WAIT, td);
|
|
+ VOP_UNLOCK(devvp, 0);
|
|
+ if (error != 0)
|
|
+ break;
|
|
+ ACQUIRE_LOCK(ump);
|
|
}
|
|
ump->softdep_req = 0;
|
|
- FREE_LOCK(ump);
|
|
- error = 0;
|
|
- if (i == 10) {
|
|
+ if (i == SU_WAITIDLE_RETRIES && error == 0 && ump->softdep_deps != 0) {
|
|
error = EBUSY;
|
|
printf("softdep_waitidle: Failed to flush worklist for %p\n",
|
|
mp);
|
|
}
|
|
-
|
|
+ FREE_LOCK(ump);
|
|
return (error);
|
|
}
|
|
|
|
@@ -1990,7 +2001,7 @@ retry_flush:
|
|
error = EBUSY;
|
|
}
|
|
if (!error)
|
|
- error = softdep_waitidle(oldmnt);
|
|
+ error = softdep_waitidle(oldmnt, flags);
|
|
if (!error) {
|
|
if (oldmnt->mnt_kern_flag & MNTK_UNMOUNT) {
|
|
retry = 0;
|
|
@@ -2490,9 +2501,18 @@ softdep_mount(devvp, mp, fs, cred)
|
|
/*
|
|
* Start our flushing thread in the bufdaemon process.
|
|
*/
|
|
+ ACQUIRE_LOCK(ump);
|
|
+ ump->softdep_flags |= FLUSH_STARTING;
|
|
+ FREE_LOCK(ump);
|
|
kproc_kthread_add(&softdep_flush, mp, &bufdaemonproc,
|
|
&ump->softdep_flushtd, 0, 0, "softdepflush", "%s worker",
|
|
mp->mnt_stat.f_mntonname);
|
|
+ ACQUIRE_LOCK(ump);
|
|
+ while ((ump->softdep_flags & FLUSH_STARTING) != 0) {
|
|
+ msleep(&ump->softdep_flushtd, LOCK_PTR(ump), PVM, "sdstart",
|
|
+ hz / 2);
|
|
+ }
|
|
+ FREE_LOCK(ump);
|
|
/*
|
|
* When doing soft updates, the counters in the
|
|
* superblock may have gotten out of sync. Recomputation
|
|
@@ -7629,17 +7649,13 @@ check_inode_unwritten(inodedep)
|
|
return (1);
|
|
}
|
|
|
|
-/*
|
|
- * Try to free an inodedep structure. Return 1 if it could be freed.
|
|
- */
|
|
static int
|
|
-free_inodedep(inodedep)
|
|
+check_inodedep_free(inodedep)
|
|
struct inodedep *inodedep;
|
|
{
|
|
|
|
LOCK_OWNED(VFSTOUFS(inodedep->id_list.wk_mp));
|
|
- if ((inodedep->id_state & (ONWORKLIST | UNLINKED)) != 0 ||
|
|
- (inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
|
|
+ if ((inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
|
|
!LIST_EMPTY(&inodedep->id_dirremhd) ||
|
|
!LIST_EMPTY(&inodedep->id_pendinghd) ||
|
|
!LIST_EMPTY(&inodedep->id_bufwait) ||
|
|
@@ -7654,6 +7670,21 @@ free_inodedep(inodedep)
|
|
inodedep->id_nlinkdelta != 0 ||
|
|
inodedep->id_savedino1 != NULL)
|
|
return (0);
|
|
+ return (1);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Try to free an inodedep structure. Return 1 if it could be freed.
|
|
+ */
|
|
+static int
|
|
+free_inodedep(inodedep)
|
|
+ struct inodedep *inodedep;
|
|
+{
|
|
+
|
|
+ LOCK_OWNED(VFSTOUFS(inodedep->id_list.wk_mp));
|
|
+ if ((inodedep->id_state & (ONWORKLIST | UNLINKED)) != 0 ||
|
|
+ !check_inodedep_free(inodedep))
|
|
+ return (0);
|
|
if (inodedep->id_state & ONDEPLIST)
|
|
LIST_REMOVE(inodedep, id_deps);
|
|
LIST_REMOVE(inodedep, id_hash);
|
|
@@ -13838,7 +13869,8 @@ softdep_check_suspend(struct mount *mp,
|
|
{
|
|
struct bufobj *bo;
|
|
struct ufsmount *ump;
|
|
- int error;
|
|
+ struct inodedep *inodedep;
|
|
+ int error, unlinked;
|
|
|
|
bo = &devvp->v_bufobj;
|
|
ASSERT_BO_WLOCKED(bo);
|
|
@@ -13899,6 +13931,20 @@ softdep_check_suspend(struct mount *mp,
|
|
break;
|
|
}
|
|
|
|
+ unlinked = 0;
|
|
+ if (MOUNTEDSUJ(mp)) {
|
|
+ for (inodedep = TAILQ_FIRST(&ump->softdep_unlinked);
|
|
+ inodedep != NULL;
|
|
+ inodedep = TAILQ_NEXT(inodedep, id_unlinked)) {
|
|
+ if ((inodedep->id_state & (UNLINKED | UNLINKLINKS |
|
|
+ UNLINKONLIST)) != (UNLINKED | UNLINKLINKS |
|
|
+ UNLINKONLIST) ||
|
|
+ !check_inodedep_free(inodedep))
|
|
+ continue;
|
|
+ unlinked++;
|
|
+ }
|
|
+ }
|
|
+
|
|
/*
|
|
* Reasons for needing more work before suspend:
|
|
* - Dirty buffers on devvp.
|
|
@@ -13908,8 +13954,8 @@ softdep_check_suspend(struct mount *mp,
|
|
error = 0;
|
|
if (bo->bo_numoutput > 0 ||
|
|
bo->bo_dirty.bv_cnt > 0 ||
|
|
- softdep_depcnt != 0 ||
|
|
- ump->softdep_deps != 0 ||
|
|
+ softdep_depcnt != unlinked ||
|
|
+ ump->softdep_deps != unlinked ||
|
|
softdep_accdepcnt != ump->softdep_accdeps ||
|
|
secondary_writes != 0 ||
|
|
mp->mnt_secondary_writes != 0 ||
|
|
Index: sys/ufs/ffs/ffs_vfsops.c
|
|
===================================================================
|
|
--- sys/ufs/ffs/ffs_vfsops.c (revision 282245)
|
|
+++ sys/ufs/ffs/ffs_vfsops.c (working copy)
|
|
@@ -1502,8 +1502,11 @@ ffs_sync(mp, waitfor)
|
|
if (fs->fs_fmod != 0 && fs->fs_ronly != 0 && ump->um_fsckpid == 0)
|
|
panic("%s: ffs_sync: modification on read-only filesystem",
|
|
fs->fs_fsmnt);
|
|
- if (waitfor == MNT_LAZY)
|
|
- return (ffs_sync_lazy(mp));
|
|
+ if (waitfor == MNT_LAZY) {
|
|
+ if (!rebooting)
|
|
+ return (ffs_sync_lazy(mp));
|
|
+ waitfor = MNT_NOWAIT;
|
|
+ }
|
|
|
|
/*
|
|
* Write back each (modified) inode.
|
|
@@ -1560,7 +1563,7 @@ loop:
|
|
/*
|
|
* Force stale filesystem control information to be flushed.
|
|
*/
|
|
- if (waitfor == MNT_WAIT) {
|
|
+ if (waitfor == MNT_WAIT || rebooting) {
|
|
if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
|
|
allerror = error;
|
|
/* Flushed work items may create new vnodes to clean */
|
|
@@ -1577,9 +1580,12 @@ loop:
|
|
if (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0) {
|
|
BO_UNLOCK(bo);
|
|
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
|
|
- if ((error = VOP_FSYNC(devvp, waitfor, td)) != 0)
|
|
- allerror = error;
|
|
+ error = VOP_FSYNC(devvp, waitfor, td);
|
|
VOP_UNLOCK(devvp, 0);
|
|
+ if (MOUNTEDSOFTDEP(mp) && (error == 0 || error == EAGAIN))
|
|
+ error = ffs_sbupdate(ump, waitfor, 0);
|
|
+ if (error != 0)
|
|
+ allerror = error;
|
|
if (allerror == 0 && waitfor == MNT_WAIT)
|
|
goto loop;
|
|
} else if (suspend != 0) {
|
|
Index: sys/ufs/ffs/softdep.h
|
|
===================================================================
|
|
--- sys/ufs/ffs/softdep.h (revision 282245)
|
|
+++ sys/ufs/ffs/softdep.h (working copy)
|
|
@@ -1063,6 +1063,8 @@ struct mount_softdeps {
|
|
*/
|
|
#define FLUSH_EXIT 0x0001 /* time to exit */
|
|
#define FLUSH_CLEANUP 0x0002 /* need to clear out softdep structures */
|
|
+#define FLUSH_STARTING 0x0004 /* flush thread not yet started */
|
|
+
|
|
/*
|
|
* Keep the old names from when these were in the ufsmount structure.
|
|
*/
|