Index: kern/vfs_mount.c =================================================================== --- kern/vfs_mount.c (revision 184100) +++ kern/vfs_mount.c (working copy) @@ -1245,19 +1245,16 @@ /* Allow filesystems to detect that a forced unmount is in progress. */ if (flags & MNT_FORCE) mp->mnt_kern_flag |= MNTK_UNMOUNTF; - error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK | - ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), MNT_MTX(mp)); - if (error) { - MNT_ILOCK(mp); - mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_NOINSMNTQ | - MNTK_UNMOUNTF); - if (mp->mnt_kern_flag & MNTK_MWAIT) - wakeup(mp); + error = 0; + if (mp->mnt_lockref) { + mp->mnt_kern_flag |= MNTK_DRAINING; + error = msleep(&mp->mnt_lockref, MNT_MTX(mp), PVFS, + "mount drain", 0); + } else MNT_IUNLOCK(mp); - if (coveredvp) - VOP_UNLOCK(coveredvp, 0); - return (error); - } + KASSERT(error == 0, + ("%s: invalid return value for msleep in the drain path @ %s:%d", + __func__, __FILE__, __LINE__)); vn_start_write(NULL, &mp, V_WAIT); if (mp->mnt_flag & MNT_EXPUBLIC) @@ -1321,7 +1318,6 @@ mp->mnt_flag |= async_flag; if ((mp->mnt_flag & MNT_ASYNC) != 0 && mp->mnt_noasync == 0) mp->mnt_kern_flag |= MNTK_ASYNC; - lockmgr(&mp->mnt_lock, LK_RELEASE, NULL); if (mp->mnt_kern_flag & MNTK_MWAIT) wakeup(mp); MNT_IUNLOCK(mp); @@ -1337,7 +1333,6 @@ vput(coveredvp); } vfs_event_signal(NULL, VQ_UNMOUNT, 0); - lockmgr(&mp->mnt_lock, LK_RELEASE, NULL); vfs_mount_destroy(mp); return (0); } @@ -2070,7 +2065,6 @@ wakeup(&mp->mnt_holdcnt); return (NULL); } - mp->mnt_markercnt++; (*mvp)->v_mount = mp; TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes); return (vp); @@ -2093,7 +2087,6 @@ MNT_ILOCK(mp); *mvp = NULL; - mp->mnt_markercnt--; mp->mnt_holdcnt--; if (mp->mnt_holdcnt == 0 && mp->mnt_holdcntwaiters != 0) wakeup(&mp->mnt_holdcnt); Index: kern/vfs_subr.c =================================================================== --- kern/vfs_subr.c (revision 184100) +++ kern/vfs_subr.c (working copy) @@ -369,8 +369,16 @@ if (interlkp) mtx_unlock(interlkp); lkflags = LK_SHARED | LK_INTERLOCK | LK_NOWAIT; - if (lockmgr(&mp->mnt_lock, lkflags, MNT_MTX(mp))) + mp->mnt_lockref++; + if (lockmgr(&mp->mnt_lock, lkflags, MNT_MTX(mp))) { + + /* + * It does not matter that we modify lockcount while the + * interlock is not held as long as we are going to panic. + */ + mp->mnt_lockref--; panic("vfs_busy: unexpected lock failure"); + } return (0); } @@ -380,9 +388,19 @@ void vfs_unbusy(struct mount *mp) { + int wakedrainers; - lockmgr(&mp->mnt_lock, LK_RELEASE, NULL); - vfs_rel(mp); + wakedrainers = 0; + MNT_ILOCK(mp); + mp->mnt_lockref--; + if (mp->mnt_lockref == 0 && (mp->mnt_kern_flag & MNTK_DRAINING)) { + MPASS(mp->mnt_kern_flag & MNTK_UNMOUNT); + mp->mnt_kern_flag &= ~MNTK_DRAINING; + wakedrainers = 1; + } + lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, MNT_MTX(mp)); + if (wakedrainers) + wakeup(&mp->mnt_lockref); } /* @@ -2840,7 +2859,6 @@ db_printf(" mnt_maxsymlinklen = %d\n", mp->mnt_maxsymlinklen); db_printf(" mnt_iosize_max = %d\n", mp->mnt_iosize_max); db_printf(" mnt_hashseed = %u\n", mp->mnt_hashseed); - db_printf(" mnt_markercnt = %d\n", mp->mnt_markercnt); db_printf(" mnt_holdcnt = %d\n", mp->mnt_holdcnt); db_printf(" mnt_holdcntwaiters = %d\n", mp->mnt_holdcntwaiters); db_printf(" mnt_secondary_writes = %d\n", mp->mnt_secondary_writes); Index: sys/mount.h =================================================================== --- sys/mount.h (revision 184100) +++ sys/mount.h (working copy) @@ -175,7 +175,7 @@ struct netexport *mnt_export; /* export list */ struct label *mnt_label; /* MAC label for the fs */ u_int mnt_hashseed; /* Random seed for vfs_hash */ - int mnt_markercnt; /* marker vnodes in use */ + int mnt_lockref; /* (i) Lock reference count */ int mnt_holdcnt; /* hold count */ int mnt_holdcntwaiters; /* waits on hold count */ int mnt_secondary_writes; /* (i) # of secondary writes */ @@ -319,6 +319,7 @@ #define MNTK_ASYNC 0x00000002 /* filtered async flag */ #define MNTK_SOFTDEP 0x00000004 /* async disabled by softdep */ #define MNTK_NOINSMNTQ 0x00000008 /* insmntque is not allowed */ +#define MNTK_DRAINING 0x00000010 /* lock draining is happening */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ #define MNTK_SUSPEND 0x08000000 /* request write suspension */