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 "[EMAIL PROTECTED]"



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

_______________________________________________
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to