summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2002-04-17 01:07:29 +0000
committeriedowse <iedowse@FreeBSD.org>2002-04-17 01:07:29 +0000
commit64322dabea69a0542951fed96cb8bb7c81602b56 (patch)
treefd4db1996177f18b62183e61df1a1e3dae92eb51 /sys
parent366464c33c243b21ec0040bc08c326d02b8630a9 (diff)
downloadFreeBSD-src-64322dabea69a0542951fed96cb8bb7c81602b56.zip
FreeBSD-src-64322dabea69a0542951fed96cb8bb7c81602b56.tar.gz
The recent NFS forced unmount improvements introduced a side-effect
where some client operations might be unexpectedly cancelled during an unsuccessful non-forced unmount attempt. This causes problems for amd(8), because it periodically attempts a non-forced unmount to check if the filesystem is still in use. Fix this by adding a new mountpoint flag MNTK_UNMOUNTF that is set only during the operation of a forced unmount. Use this instead of MNTK_UNMOUNT to trigger the cancellation of hung NFS operations. Also correct a problem where dounmount() might inadvertently clear the MNTK_UNMOUNT flag. Reported by: simokawa MFC after: 1 week
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_extattr.c11
-rw-r--r--sys/kern/vfs_syscalls.c11
-rw-r--r--sys/nfsclient/nfs_socket.c8
-rw-r--r--sys/sys/mount.h6
4 files changed, 28 insertions, 8 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 157f6be..68b392a 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 157f6be..68b392a 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 73ecf47..0a4f849 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 7cb8031..ca9bdcc 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 */
OpenPOWER on IntegriCloud