--- //depot/vendor/freebsd/src/sys/kern/vfs_lookup.c 2008/11/17 20:55:47 +++ //depot/user/attilio/attilio_vfs/sys/kern/vfs_lookup.c 2008/12/14 18:36:51 @@ -698,8 +698,10 @@ */ while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && (cnp->cn_flags & NOCROSSMOUNT) == 0) { - if (vfs_busy(mp, 0)) - continue; + if (vfs_busy(mp, MBF_NOWAIT)) { + dpunlocked = 0; + goto bad2; + } vput(dp); VFS_UNLOCK_GIANT(vfslocked); vfslocked = VFS_LOCK_GIANT(mp); --- //depot/vendor/freebsd/src/sys/kern/vfs_mount.c 2008/12/01 03:05:24 +++ //depot/user/attilio/attilio_vfs/sys/kern/vfs_mount.c 2008/12/14 18:36:51 @@ -507,29 +507,20 @@ { MNT_ILOCK(mp); + mp->mnt_kern_flag |= MNTK_REFEXPIRE; + if (mp->mnt_kern_flag & MNTK_MWAIT) { + mp->mnt_kern_flag &= ~MNTK_MWAIT; + wakeup(mp); + } while (mp->mnt_ref) msleep(mp, MNT_MTX(mp), PVFS, "mntref", 0); - if (mp->mnt_writeopcount > 0) { - printf("Waiting for mount point write ops\n"); - while (mp->mnt_writeopcount > 0) { - mp->mnt_kern_flag |= MNTK_SUSPEND; - msleep(&mp->mnt_writeopcount, - MNT_MTX(mp), - PZERO, "mntdestroy2", 0); - } - printf("mount point write ops completed\n"); - } - if (mp->mnt_secondary_writes > 0) { - printf("Waiting for mount point secondary write ops\n"); - while (mp->mnt_secondary_writes > 0) { - mp->mnt_kern_flag |= MNTK_SUSPEND; - msleep(&mp->mnt_secondary_writes, - MNT_MTX(mp), - PZERO, "mntdestroy3", 0); - } - printf("mount point secondary write ops completed\n"); - } - MNT_IUNLOCK(mp); + KASSERT(mp->mnt_ref == 0, + ("%s: invalid refcount in the drain path @ %s:%d", __func__, + __FILE__, __LINE__)); + if (mp->mnt_writeopcount != 0) + panic("vfs_mount_destroy: nonzero writeopcount"); + if (mp->mnt_secondary_writes != 0) + panic("vfs_mount_destroy: nonzero secondary_writes"); mp->mnt_vfc->vfc_refcount--; if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) { struct vnode *vp; @@ -538,18 +529,10 @@ vprint("", vp); panic("unmount: dangling vnode"); } - MNT_ILOCK(mp); - if (mp->mnt_kern_flag & MNTK_MWAIT) - wakeup(mp); - if (mp->mnt_writeopcount != 0) - panic("vfs_mount_destroy: nonzero writeopcount"); - if (mp->mnt_secondary_writes != 0) - panic("vfs_mount_destroy: nonzero secondary_writes"); if (mp->mnt_nvnodelistsize != 0) panic("vfs_mount_destroy: nonzero nvnodelistsize"); - mp->mnt_writeopcount = -1000; - mp->mnt_nvnodelistsize = -1000; - mp->mnt_secondary_writes = -1000; + if (mp->mnt_lockref != 0) + panic("vfs_mount_destroy: nonzero lock refcount"); MNT_IUNLOCK(mp); #ifdef MAC mac_mount_destroy(mp); @@ -1200,41 +1183,20 @@ mtx_assert(&Giant, MA_OWNED); - if ((coveredvp = mp->mnt_vnodecovered) != NULL) { - mnt_gen_r = mp->mnt_gen; - VI_LOCK(coveredvp); - vholdl(coveredvp); - vn_lock(coveredvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY); - vdrop(coveredvp); - /* - * Check for mp being unmounted while waiting for the - * covered vnode lock. - */ - if (coveredvp->v_mountedhere != mp || - coveredvp->v_mountedhere->mnt_gen != mnt_gen_r) { - VOP_UNLOCK(coveredvp, 0); - return (EBUSY); - } - } /* * Only privileged root, or (if MNT_USER is set) the user that did the * original mount is permitted to unmount this filesystem. */ error = vfs_suser(mp, td); - if (error) { - if (coveredvp) - VOP_UNLOCK(coveredvp, 0); + if (error) return (error); - } - MNT_ILOCK(mp); if (mp->mnt_kern_flag & MNTK_UNMOUNT) { MNT_IUNLOCK(mp); - if (coveredvp) - VOP_UNLOCK(coveredvp, 0); return (EBUSY); } mp->mnt_kern_flag |= MNTK_UNMOUNT | MNTK_NOINSMNTQ; + /* Allow filesystems to detect that a forced unmount is in progress. */ if (flags & MNT_FORCE) mp->mnt_kern_flag |= MNTK_UNMOUNTF; @@ -1248,8 +1210,6 @@ wakeup(mp); } MNT_IUNLOCK(mp); - if (coveredvp) - VOP_UNLOCK(coveredvp, 0); return (EBUSY); } mp->mnt_kern_flag |= MNTK_DRAINING; @@ -1263,6 +1223,30 @@ KASSERT(error == 0, ("%s: invalid return value for msleep in the drain path @ %s:%d", __func__, __FILE__, __LINE__)); + if ((coveredvp = mp->mnt_vnodecovered) != NULL) { + mnt_gen_r = mp->mnt_gen; + VI_LOCK(coveredvp); + vholdl(coveredvp); + vn_lock(coveredvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY); + vdrop(coveredvp); + /* + * Check for mp being unmounted while waiting for the + * covered vnode lock. + */ + if (coveredvp->v_mountedhere != mp || + coveredvp->v_mountedhere->mnt_gen != mnt_gen_r) { + VOP_UNLOCK(coveredvp, 0); + MNT_ILOCK(mp); + mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_NOINSMNTQ | + MNTK_UNMOUNTF); + if (mp->mnt_kern_flag & MNTK_MWAIT) { + mp->mnt_kern_flag &= ~MNTK_MWAIT; + wakeup(mp); + } + MNT_IUNLOCK(mp); + return (EBUSY); + } + } vn_start_write(NULL, &mp, V_WAIT); if (mp->mnt_flag & MNT_EXPUBLIC) --- //depot/vendor/freebsd/src/sys/kern/vfs_subr.c 2008/11/29 13:37:40 +++ //depot/user/attilio/attilio_vfs/sys/kern/vfs_subr.c 2008/12/02 15:09:44 @@ -345,7 +345,7 @@ MNT_ILOCK(mp); MNT_REF(mp); if (mp->mnt_kern_flag & MNTK_UNMOUNT) { - if (flags & MBF_NOWAIT) { + if (flags & MBF_NOWAIT || mp->mnt_kern_flag & MNTK_REFEXPIRE) { MNT_REL(mp); MNT_IUNLOCK(mp); return (ENOENT); --- //depot/vendor/freebsd/src/sys/kern/vfs_syscalls.c 2008/11/29 13:37:40 +++ //depot/user/attilio/attilio_vfs/sys/kern/vfs_syscalls.c 2008/12/14 18:36:51 @@ -751,8 +751,9 @@ error = change_dir(vp, td); while (!error && (mp = vp->v_mountedhere) != NULL) { int tvfslocked; - if (vfs_busy(mp, 0)) - continue; + error = vfs_busy(mp, MBF_NOWAIT); + if (error != 0) + break; tvfslocked = VFS_LOCK_GIANT(mp); error = VFS_ROOT(mp, LK_EXCLUSIVE, &tdp, td); vfs_unbusy(mp); --- //depot/vendor/freebsd/src/sys/sys/mount.h 2008/11/29 13:37:40 +++ //depot/user/attilio/attilio_vfs/sys/sys/mount.h 2008/12/02 15:09:44 @@ -316,6 +316,7 @@ #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_REFEXPIRE 0x00000020 /* refcount expiring 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 */