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
This commit is contained in:
parent
366464c33c
commit
64322dabea
@ -1103,11 +1103,18 @@ dounmount(mp, flags, td)
|
|||||||
int async_flag;
|
int async_flag;
|
||||||
|
|
||||||
mtx_lock(&mountlist_mtx);
|
mtx_lock(&mountlist_mtx);
|
||||||
|
if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
|
||||||
|
mtx_unlock(&mountlist_mtx);
|
||||||
|
return (EBUSY);
|
||||||
|
}
|
||||||
mp->mnt_kern_flag |= MNTK_UNMOUNT;
|
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 |
|
error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK |
|
||||||
((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td);
|
((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td);
|
||||||
if (error) {
|
if (error) {
|
||||||
mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
|
mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
|
||||||
if (mp->mnt_kern_flag & MNTK_MWAIT)
|
if (mp->mnt_kern_flag & MNTK_MWAIT)
|
||||||
wakeup((caddr_t)mp);
|
wakeup((caddr_t)mp);
|
||||||
return (error);
|
return (error);
|
||||||
@ -1153,7 +1160,7 @@ dounmount(mp, flags, td)
|
|||||||
if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
|
if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
|
||||||
(void) vfs_allocate_syncvnode(mp);
|
(void) vfs_allocate_syncvnode(mp);
|
||||||
mtx_lock(&mountlist_mtx);
|
mtx_lock(&mountlist_mtx);
|
||||||
mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
|
mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
|
||||||
mp->mnt_flag |= async_flag;
|
mp->mnt_flag |= async_flag;
|
||||||
lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
|
lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
|
||||||
&mountlist_mtx, td);
|
&mountlist_mtx, td);
|
||||||
|
@ -1103,11 +1103,18 @@ dounmount(mp, flags, td)
|
|||||||
int async_flag;
|
int async_flag;
|
||||||
|
|
||||||
mtx_lock(&mountlist_mtx);
|
mtx_lock(&mountlist_mtx);
|
||||||
|
if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
|
||||||
|
mtx_unlock(&mountlist_mtx);
|
||||||
|
return (EBUSY);
|
||||||
|
}
|
||||||
mp->mnt_kern_flag |= MNTK_UNMOUNT;
|
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 |
|
error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK |
|
||||||
((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td);
|
((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td);
|
||||||
if (error) {
|
if (error) {
|
||||||
mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
|
mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
|
||||||
if (mp->mnt_kern_flag & MNTK_MWAIT)
|
if (mp->mnt_kern_flag & MNTK_MWAIT)
|
||||||
wakeup((caddr_t)mp);
|
wakeup((caddr_t)mp);
|
||||||
return (error);
|
return (error);
|
||||||
@ -1153,7 +1160,7 @@ dounmount(mp, flags, td)
|
|||||||
if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
|
if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
|
||||||
(void) vfs_allocate_syncvnode(mp);
|
(void) vfs_allocate_syncvnode(mp);
|
||||||
mtx_lock(&mountlist_mtx);
|
mtx_lock(&mountlist_mtx);
|
||||||
mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
|
mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
|
||||||
mp->mnt_flag |= async_flag;
|
mp->mnt_flag |= async_flag;
|
||||||
lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
|
lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
|
||||||
&mountlist_mtx, td);
|
&mountlist_mtx, td);
|
||||||
|
@ -850,8 +850,8 @@ nfs_request(struct vnode *vp, struct mbuf *mrest, int procnum,
|
|||||||
int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0;
|
int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0;
|
||||||
u_int32_t xid;
|
u_int32_t xid;
|
||||||
|
|
||||||
/* Reject requests while attempting to unmount. */
|
/* Reject requests while attempting a forced unmount. */
|
||||||
if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNT) {
|
if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) {
|
||||||
m_freem(mrest);
|
m_freem(mrest);
|
||||||
return (ESTALE);
|
return (ESTALE);
|
||||||
}
|
}
|
||||||
@ -1230,8 +1230,8 @@ nfs_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct proc *p)
|
|||||||
|
|
||||||
if (rep && (rep->r_flags & R_SOFTTERM))
|
if (rep && (rep->r_flags & R_SOFTTERM))
|
||||||
return (EINTR);
|
return (EINTR);
|
||||||
/* Terminate all requests while attempting to unmount. */
|
/* Terminate all requests while attempting a forced unmount. */
|
||||||
if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNT)
|
if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
|
||||||
return (EINTR);
|
return (EINTR);
|
||||||
if (!(nmp->nm_flag & NFSMNT_INT))
|
if (!(nmp->nm_flag & NFSMNT_INT))
|
||||||
return (0);
|
return (0);
|
||||||
|
@ -240,7 +240,13 @@ struct mount {
|
|||||||
* MNTK_UNMOUNT locks the mount entry so that name lookup cannot proceed
|
* MNTK_UNMOUNT locks the mount entry so that name lookup cannot proceed
|
||||||
* past the mount point. This keeps the subtree stable during mounts
|
* past the mount point. This keeps the subtree stable during mounts
|
||||||
* and unmounts.
|
* 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_UNMOUNT 0x01000000 /* unmount in progress */
|
||||||
#define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */
|
#define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */
|
||||||
#define MNTK_WANTRDWR 0x04000000 /* upgrade to read/write requested */
|
#define MNTK_WANTRDWR 0x04000000 /* upgrade to read/write requested */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user