Unable to unmount idle filesystem on 6.2
Kris Kennaway
kris at FreeBSD.org
Sat Jan 12 04:02:19 PST 2008
Darren Pilgrim wrote:
> Kris Kennaway wrote:
>> Darren Pilgrim wrote:
>>> I'm unable to unmount an idle filesystem (or even drop it to
>>> read-only):
>>>
>>> # mount
>>> /dev/da0s1a on / (ufs, local, noatime)
>>> devfs on /dev (devfs, local)
>>> /dev/da0s1d on /var (ufs, local, noatime, soft-updates)
>>> /dev/da0s1e on /usr (ufs, local, noatime, soft-updates)
>>> /dev/da0s1fp1 on /usr/obj (ufs, asynchronous, local, noatime)
>>> /dev/da0s1fp2 on /usr/ports (ufs, local, soft-updates)
>>> /dev/da0s1fp3 on /usr/src (ufs, local, soft-updates)
>>> /dev/da0s2d on /data (ufs, local, noatime, soft-updates)
>>>
>>> # fstat -f /usr/ports
>>> USER CMD PID FD MOUNT INUM MODE SZ|DV R/W
>>>
>>> # umount /usr/ports
>>> umount: unmount of /usr/ports failed: Device busy
>>>
>>> # umount -f /usr/ports
>>> umount: unmount of /usr/ports failed: Device busy
>>>
>>> # mount -o ro /usr/ports
>>> mount: /dev/da0s1fp2: Operation not permitted
>>>
>>> # uname -r
>>> 6.2-RELEASE-p8
>>> _______________________________________________
>>> freebsd-questions at freebsd.org mailing list
>>> http://lists.freebsd.org/mailman/listinfo/freebsd-questions
>>> To unsubscribe, send any mail to
>>> "freebsd-questions-unsubscribe at freebsd.org"
>>>
>>>
>>
>> Strange, can you break to DDB and do 'show lockedvnods'?
>
> I haven't done that yet; however, I did find 12 instances of the
> following in the log:
>
> softdep_waitidle: Failed to flush worklist for 0xc66e5298
>
> A quick check and that message gets spit out whenever I issue any of the
> following commands:
>
> # mount -uo ro /usr/ports
> # umount /usr/ports
> # umount -f /usr/ports
>
> A bit of searching on that error message tells me I've hit some kind of
> a corner case with soft-updates. The filesystem was mounted read-only,
> then upgraded to rw so I could update the ports tree. After cvsup was
> done, I tried to take the filesystem back down to read-only. The common
> case seems to be that the mount change is followed too quickly after the
> large number of writes and it somehow wedges soft-updates.
>
> Unfortunately, I haven't been able to find a fix other than rebooting
> the machine. The problem is that the search results[1] also tell me the
> filesystem may well be hosed and the reboot won't be clean. Luckily for
> me, I can just drop the FS from /etc/fstab and newfs the partition after
> the box comes back up.
As luck would have it I ran into this in my own testing yesterday, and
Kostik Belousov has a proposed fix (apply it with patch -p2). This is
against 8.0 but should also appy to 7.0. Don't know about 6.x.
Kris
-------------- next part --------------
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index c4d2346..ba99e8a 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -1020,9 +1020,15 @@ insmntque1(struct vnode *vp, struct mount *mp,
KASSERT(vp->v_mount == NULL,
("insmntque: vnode already on per mount vnode list"));
VNASSERT(mp != NULL, vp, ("Don't call insmntque(foo, NULL)"));
+#ifdef DEBUG_VFS_LOCKS
+ if (!VFS_NEEDSGIANT(mp))
+ ASSERT_VOP_ELOCKED(vp,
+ "insmntque: mp-safe fs and non-locked vp");
+#endif
MNT_ILOCK(mp);
if ((mp->mnt_kern_flag & MNTK_NOINSMNTQ) != 0 &&
- mp->mnt_nvnodelistsize == 0) {
+ mp->mnt_nvnodelistsize == 0 &&
+ VOP_ISLOCKED(vp, curthread) && !(vp->v_vflag & VV_FORCEINSMQ)) {
MNT_IUNLOCK(mp);
if (dtr != NULL)
dtr(vp, dtr_arg);
@@ -3133,9 +3139,13 @@ vfs_allocate_syncvnode(struct mount *mp)
return (error);
}
vp->v_type = VNON;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ vp->v_vflag |= VV_FORCEINSMQ;
error = insmntque(vp, mp);
if (error != 0)
panic("vfs_allocate_syncvnode: insmntque failed");
+ vp->v_vflag &= ~VV_FORCEINSMQ;
+ VOP_UNLOCK(vp, 0, curthread);
/*
* Place the vnode onto the syncer worklist. We attempt to
* scatter them about on the list so that they will go off
diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h
index fcbb187..d4e0c9b 100644
--- a/sys/sys/lockmgr.h
+++ b/sys/sys/lockmgr.h
@@ -125,6 +125,10 @@ struct lock {
* unlock passed mutex after getting
* lk_interlock
*/
+#define LK_FORCE 0x00004000 /*
+ * fsops_vget: try hard to success;
+ * in particular, force insmntque
+ */
/*
* Internal lock flags.
*
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 0525a43..4b95233 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -255,6 +255,7 @@ struct xvnode {
#define VV_NOKNOTE 0x0200 /* don't activate knotes on this vnode */
#define VV_DELETED 0x0400 /* should be removed */
#define VV_MD 0x0800 /* vnode backs the md device */
+#define VV_FORCEINSMQ 0x1000 /* force the insmntque to succeed */
/*
* Vnode attributes. A field value of VNOVAL represents a field whose value
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index a221b66..da91f8b 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -920,7 +920,7 @@ process_worklist_item(mp, flags)
ump->softdep_on_worklist_inprogress++;
FREE_LOCK(&lk);
ffs_vget(mp, WK_DIRREM(wk)->dm_oldinum,
- LK_NOWAIT | LK_EXCLUSIVE, &vp);
+ LK_NOWAIT | LK_EXCLUSIVE | LK_FORCE, &vp);
ACQUIRE_LOCK(&lk);
wk->wk_state &= ~INPROGRESS;
ump->softdep_on_worklist_inprogress--;
@@ -2771,7 +2771,7 @@ handle_workitem_freeblocks(freeblks, flags)
if (freeblks->fb_chkcnt != blocksreleased &&
(fs->fs_flags & FS_UNCLEAN) != 0 &&
ffs_vget(freeblks->fb_list.wk_mp, freeblks->fb_previousinum,
- (flags & LK_NOWAIT) | LK_EXCLUSIVE, &vp) == 0) {
+ (flags & LK_NOWAIT) | LK_EXCLUSIVE | LK_FORCE, &vp) == 0) {
ip = VTOI(vp);
DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + \
freeblks->fb_chkcnt - blocksreleased);
@@ -3559,7 +3559,7 @@ handle_workitem_remove(dirrem, xp)
if ((vp = xp) == NULL &&
(error = ffs_vget(dirrem->dm_list.wk_mp,
- dirrem->dm_oldinum, LK_EXCLUSIVE, &vp)) != 0) {
+ dirrem->dm_oldinum, LK_EXCLUSIVE | LK_FORCE, &vp)) != 0) {
softdep_error("handle_workitem_remove: vget", error);
return;
}
@@ -5074,9 +5074,11 @@ softdep_fsync(vp)
* for details on possible races.
*/
FREE_LOCK(&lk);
- if (ffs_vget(mp, parentino, LK_NOWAIT | LK_EXCLUSIVE, &pvp)) {
+ if (ffs_vget(mp, parentino, LK_NOWAIT | LK_EXCLUSIVE | LK_FORCE,
+ &pvp)) {
VOP_UNLOCK(vp, 0, td);
- error = ffs_vget(mp, parentino, LK_EXCLUSIVE, &pvp);
+ error = ffs_vget(mp, parentino, LK_EXCLUSIVE | LK_FORCE,
+ &pvp);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (error != 0)
return (error);
@@ -5576,7 +5578,8 @@ flush_pagedep_deps(pvp, mp, diraddhdp)
inum = dap->da_newinum;
if (dap->da_state & MKDIR_BODY) {
FREE_LOCK(&lk);
- if ((error = ffs_vget(mp, inum, LK_EXCLUSIVE, &vp)))
+ if ((error = ffs_vget(mp, inum, LK_EXCLUSIVE | LK_FORCE,
+ &vp)))
break;
if ((error=ffs_syncvnode(vp, MNT_NOWAIT)) ||
(error=ffs_syncvnode(vp, MNT_NOWAIT))) {
@@ -5911,7 +5914,8 @@ clear_remove(td)
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
continue;
FREE_LOCK(&lk);
- if ((error = ffs_vget(mp, ino, LK_EXCLUSIVE, &vp))) {
+ if ((error = ffs_vget(mp, ino, LK_EXCLUSIVE | LK_FORCE,
+ &vp))) {
softdep_error("clear_remove: vget", error);
vn_finished_write(mp);
ACQUIRE_LOCK(&lk);
@@ -5982,7 +5986,8 @@ clear_inodedeps(td)
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
continue;
FREE_LOCK(&lk);
- if ((error = ffs_vget(mp, ino, LK_EXCLUSIVE, &vp)) != 0) {
+ if ((error = ffs_vget(mp, ino, LK_EXCLUSIVE | LK_FORCE,
+ &vp)) != 0) {
softdep_error("clear_inodedeps: vget", error);
vn_finished_write(mp);
ACQUIRE_LOCK(&lk);
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 14ffd0b..95fe60b 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1382,12 +1382,15 @@ ffs_vget(mp, ino, flags, vpp)
td = curthread;
lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ if (flags & LK_FORCE)
+ vp->v_vflag |= VV_FORCEINSMQ;
error = insmntque(vp, mp);
if (error != 0) {
uma_zfree(uma_inode, ip);
*vpp = NULL;
return (error);
}
+ vp->v_vflag &= ~VV_FORCEINSMQ;
error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);
More information about the freebsd-questions
mailing list