Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 Jan 2008 13:02:15 +0100
From:      Kris Kennaway <kris@FreeBSD.org>
To:        Darren Pilgrim <freebsd@bitfreak.org>
Cc:        freebsd-questions@freebsd.org
Subject:   Re: Unable to unmount idle filesystem on 6.2
Message-ID:  <4788AC47.5060404@FreeBSD.org>
In-Reply-To: <47882812.1010403@bitfreak.org>
References:  <47871856.2070505@bitfreak.org> <47874B18.5020408@FreeBSD.org> <47882812.1010403@bitfreak.org>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------080708010808070208070809
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

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@freebsd.org mailing list
>>> http://lists.freebsd.org/mailman/listinfo/freebsd-questions
>>> To unsubscribe, send any mail to 
>>> "freebsd-questions-unsubscribe@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

--------------080708010808070208070809
Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0"; name="mntq.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="mntq.diff"

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);


--------------080708010808070208070809--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4788AC47.5060404>