summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-04-10 02:23:44 +0000
committerkib <kib@FreeBSD.org>2015-04-10 02:23:44 +0000
commit6b6e486121afe6203d138c1089582dbb4617e997 (patch)
treed8da6296f235e1f41a45ffd5b4900bca4345e664 /sys/ufs
parent036979b3f8248aa22f93a69ead97446775b48e26 (diff)
downloadFreeBSD-src-6b6e486121afe6203d138c1089582dbb4617e997.zip
FreeBSD-src-6b6e486121afe6203d138c1089582dbb4617e997.tar.gz
MFC r280760:
Fix the hand after the immediate reboot after the init binary is unlinked. MFC r280763: Fix build (with gcc).
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_softdep.c76
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c16
2 files changed, 68 insertions, 24 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 3cf0ab3..2ce5cac 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -738,6 +738,7 @@ static int softdep_process_worklist(struct mount *, int);
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 *);
@@ -1885,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
@@ -1895,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) {
@@ -1902,37 +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, 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;
KASSERT((flags & FORCECLOSE) == 0 ||
ump->softdep_on_worklist == 0,
("softdep_waitidle: work added after flush"));
- msleep(&ump->softdep_deps, LOCK_PTR(ump), PVM, "softdeps", 1);
+ 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);
}
@@ -7637,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) ||
@@ -7662,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);
@@ -13846,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);
@@ -13907,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.
@@ -13916,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 ||
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 41e29c0..881da62 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -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) {
OpenPOWER on IntegriCloud