diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 157f6bef3f34..68b392a6eb7d 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -1103,11 +1103,18 @@ dounmount(mp, flags, td) int async_flag; mtx_lock(&mountlist_mtx); + if (mp->mnt_kern_flag & MNTK_UNMOUNT) { + mtx_unlock(&mountlist_mtx); + return (EBUSY); + } mp->mnt_kern_flag |= MNTK_UNMOUNT; + /* 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), &mountlist_mtx, td); if (error) { - mp->mnt_kern_flag &= ~MNTK_UNMOUNT; + mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); if (mp->mnt_kern_flag & MNTK_MWAIT) wakeup((caddr_t)mp); return (error); @@ -1153,7 +1160,7 @@ dounmount(mp, flags, td) if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) (void) vfs_allocate_syncvnode(mp); mtx_lock(&mountlist_mtx); - mp->mnt_kern_flag &= ~MNTK_UNMOUNT; + mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); mp->mnt_flag |= async_flag; lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 157f6bef3f34..68b392a6eb7d 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1103,11 +1103,18 @@ dounmount(mp, flags, td) int async_flag; mtx_lock(&mountlist_mtx); + if (mp->mnt_kern_flag & MNTK_UNMOUNT) { + mtx_unlock(&mountlist_mtx); + return (EBUSY); + } mp->mnt_kern_flag |= MNTK_UNMOUNT; + /* 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), &mountlist_mtx, td); if (error) { - mp->mnt_kern_flag &= ~MNTK_UNMOUNT; + mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); if (mp->mnt_kern_flag & MNTK_MWAIT) wakeup((caddr_t)mp); return (error); @@ -1153,7 +1160,7 @@ dounmount(mp, flags, td) if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) (void) vfs_allocate_syncvnode(mp); mtx_lock(&mountlist_mtx); - mp->mnt_kern_flag &= ~MNTK_UNMOUNT; + mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); mp->mnt_flag |= async_flag; lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td); diff --git a/sys/nfsclient/nfs_socket.c b/sys/nfsclient/nfs_socket.c index 73ecf473fcbc..0a4f849765f9 100644 --- a/sys/nfsclient/nfs_socket.c +++ b/sys/nfsclient/nfs_socket.c @@ -850,8 +850,8 @@ nfs_request(struct vnode *vp, struct mbuf *mrest, int procnum, int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0; u_int32_t xid; - /* Reject requests while attempting to unmount. */ - if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNT) { + /* Reject requests while attempting a forced unmount. */ + if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) { m_freem(mrest); return (ESTALE); } @@ -1230,8 +1230,8 @@ nfs_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct proc *p) if (rep && (rep->r_flags & R_SOFTTERM)) return (EINTR); - /* Terminate all requests while attempting to unmount. */ - if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNT) + /* Terminate all requests while attempting a forced unmount. */ + if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) return (EINTR); if (!(nmp->nm_flag & NFSMNT_INT)) return (0); diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 7cb8031af6ee..ca9bdcc4d8c6 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -240,7 +240,13 @@ struct mount { * MNTK_UNMOUNT locks the mount entry so that name lookup cannot proceed * past the mount point. This keeps the subtree stable during mounts * and unmounts. + * + * MNTK_UNMOUNTF permits filesystems to detect a forced unmount while + * dounmount() is still waiting to lock the mountpoint. This allows + * the filesystem to cancel operations that might otherwise deadlock + * with the unmount attempt (used by NFS). */ +#define MNTK_UNMOUNTF 0x00000001 /* forced unmount in progress */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ #define MNTK_WANTRDWR 0x04000000 /* upgrade to read/write requested */