Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/nfs Fix soft NFS force unmount
details: https://anonhg.NetBSD.org/src/rev/c6c96518b601
branches: trunk
changeset: 809476:c6c96518b601
user: manu <manu%NetBSD.org@localhost>
date: Wed Jul 15 03:28:55 2015 +0000
description:
Fix soft NFS force unmount
For many reasons, forcibly unmounting a soft NFS mount could hang forever.
Here are the fixes:
- Introduce decents timeouts in operation that awaited NFS server reply.
- On timeout, fails operations on soft mounts with EIO.
- Introduce NFSMNT_DISMNTFORCE to let the filesystem know that a
force unmount is ongoing. This causes timeouts to be reduced and
prevents the NFS client to attempt reconnecting to the NFS server.
Also fix a race condition where some asynchronous I/O could reference
destroyed mount structures. We fix this by awaiting asynchronous I/O
to drain before proceeding.
Reviewed by Chuck Silvers.
diffstat:
sys/nfs/nfs_bio.c | 23 ++++++++++++++++++++---
sys/nfs/nfs_clntsocket.c | 25 +++++++++++++++++++++----
sys/nfs/nfs_iod.c | 20 ++++++++++++++++++--
sys/nfs/nfs_socket.c | 45 +++++++++++++++++++++++++++++++++++++++++----
sys/nfs/nfs_var.h | 3 ++-
sys/nfs/nfs_vfsops.c | 38 ++++++++++++++++++++++++++++++--------
sys/nfs/nfsmount.h | 3 ++-
7 files changed, 134 insertions(+), 23 deletions(-)
diffs (truncated from 375 to 300 lines):
diff -r 097497a6be35 -r c6c96518b601 sys/nfs/nfs_bio.c
--- a/sys/nfs/nfs_bio.c Tue Jul 14 18:07:17 2015 +0000
+++ b/sys/nfs/nfs_bio.c Wed Jul 15 03:28:55 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_bio.c,v 1.190 2014/09/05 05:34:57 matt Exp $ */
+/* $NetBSD: nfs_bio.c,v 1.191 2015/07/15 03:28:55 manu Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.190 2014/09/05 05:34:57 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.191 2015/07/15 03:28:55 manu Exp $");
#ifdef _KERNEL_OPT
#include "opt_nfs.h"
@@ -624,7 +624,10 @@
slptimeo = 2 * hz;
} else {
catch_p = false;
- slptimeo = 0;
+ if (nmp->nm_flag & NFSMNT_SOFT)
+ slptimeo = nmp->nm_retry * nmp->nm_timeo;
+ else
+ slptimeo = 0;
}
/*
* First wait for any other process doing a flush to complete.
@@ -743,6 +746,13 @@
return (EIO);
nmp = VFSTONFS(bp->b_vp->v_mount);
+
+ if (nmp->nm_flag & NFSMNT_SOFT)
+ slptimeo = nmp->nm_retry * nmp->nm_timeo;
+
+ if (nmp->nm_iflag & NFSMNT_DISMNTFORCE)
+ slptimeo = hz;
+
again:
if (nmp->nm_flag & NFSMNT_INT)
catch_p = true;
@@ -804,6 +814,13 @@
&nmp->nm_lock, slptimeo);
}
if (error) {
+ if (error == EWOULDBLOCK &&
+ nmp->nm_flag & NFSMNT_SOFT) {
+ mutex_exit(&nmp->nm_lock);
+ bp->b_error = EIO;
+ return (EIO);
+ }
+
if (nfs_sigintr(nmp, NULL, curlwp)) {
mutex_exit(&nmp->nm_lock);
return (EINTR);
diff -r 097497a6be35 -r c6c96518b601 sys/nfs/nfs_clntsocket.c
--- a/sys/nfs/nfs_clntsocket.c Tue Jul 14 18:07:17 2015 +0000
+++ b/sys/nfs/nfs_clntsocket.c Wed Jul 15 03:28:55 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_clntsocket.c,v 1.2 2014/09/05 05:34:57 matt Exp $ */
+/* $NetBSD: nfs_clntsocket.c,v 1.3 2015/07/15 03:28:55 manu Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1995
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_clntsocket.c,v 1.2 2014/09/05 05:34:57 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_clntsocket.c,v 1.3 2015/07/15 03:28:55 manu Exp $");
#ifdef _KERNEL_OPT
#include "opt_nfs.h"
@@ -967,6 +967,12 @@
bool catch_p = false;
int error = 0;
+ if (nmp->nm_flag & NFSMNT_SOFT)
+ timeo = nmp->nm_retry * nmp->nm_timeo;
+
+ if (nmp->nm_iflag & NFSMNT_DISMNTFORCE)
+ timeo = hz;
+
if (rep) {
l = rep->r_lwp;
if (rep->r_nmp->nm_flag & NFSMNT_INT)
@@ -980,9 +986,20 @@
goto quit;
}
if (catch_p) {
- cv_timedwait_sig(&nmp->nm_sndcv, &nmp->nm_lock, timeo);
+ error = cv_timedwait_sig(&nmp->nm_sndcv,
+ &nmp->nm_lock, timeo);
} else {
- cv_timedwait(&nmp->nm_sndcv, &nmp->nm_lock, timeo);
+ error = cv_timedwait(&nmp->nm_sndcv,
+ &nmp->nm_lock, timeo);
+ }
+
+ if (error) {
+ if ((error == EWOULDBLOCK) &&
+ (nmp->nm_flag & NFSMNT_SOFT)) {
+ error = EIO;
+ goto quit;
+ }
+ error = 0;
}
if (catch_p) {
catch_p = false;
diff -r 097497a6be35 -r c6c96518b601 sys/nfs/nfs_iod.c
--- a/sys/nfs/nfs_iod.c Tue Jul 14 18:07:17 2015 +0000
+++ b/sys/nfs/nfs_iod.c Wed Jul 15 03:28:55 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_iod.c,v 1.6 2013/10/25 16:01:56 martin Exp $ */
+/* $NetBSD: nfs_iod.c,v 1.7 2015/07/15 03:28:55 manu Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_iod.c,v 1.6 2013/10/25 16:01:56 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_iod.c,v 1.7 2015/07/15 03:28:55 manu Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -202,6 +202,22 @@
}
int
+nfs_iodbusy(struct nfsmount *nmp)
+{
+ struct nfs_iod *iod;
+ int ret = 0;
+
+ mutex_enter(&nfs_iodlist_lock);
+ LIST_FOREACH(iod, &nfs_iodlist_all, nid_all) {
+ if (iod->nid_mount == nmp)
+ ret++;
+ }
+ mutex_exit(&nfs_iodlist_lock);
+
+ return ret;
+}
+
+int
nfs_set_niothreads(int newval)
{
struct nfs_iod *nid;
diff -r 097497a6be35 -r c6c96518b601 sys/nfs/nfs_socket.c
--- a/sys/nfs/nfs_socket.c Tue Jul 14 18:07:17 2015 +0000
+++ b/sys/nfs/nfs_socket.c Wed Jul 15 03:28:55 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_socket.c,v 1.196 2015/05/09 15:22:47 rtr Exp $ */
+/* $NetBSD: nfs_socket.c,v 1.197 2015/07/15 03:28:55 manu Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1995
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.196 2015/05/09 15:22:47 rtr Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.197 2015/07/15 03:28:55 manu Exp $");
#ifdef _KERNEL_OPT
#include "opt_nfs.h"
@@ -66,6 +66,7 @@
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/kauth.h>
+#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -349,11 +350,33 @@
struct nfsreq *rp;
struct nfsmount *nmp = rep->r_nmp;
int error;
+ time_t before_ts;
nfs_disconnect(nmp);
+
+ /*
+ * Force unmount: do not try to reconnect
+ */
+ if (nmp->nm_iflag & NFSMNT_DISMNTFORCE)
+ return EIO;
+
+ before_ts = time_uptime;
while ((error = nfs_connect(nmp, rep, &lwp0)) != 0) {
if (error == EINTR || error == ERESTART)
return (EINTR);
+
+ if (rep->r_flags & R_SOFTTERM)
+ return (EIO);
+
+ /*
+ * Soft mount can fail here, but not too fast:
+ * we want to make sure we at least honoured
+ * NFS timeout.
+ */
+ if ((nmp->nm_flag & NFSMNT_SOFT) &&
+ (time_uptime - before_ts > nmp->nm_timeo / NFS_HZ))
+ return (EIO);
+
kpause("nfscn2", false, hz, NULL);
}
@@ -886,6 +909,12 @@
KASSERT(nmp == rep->r_nmp);
+ if (nmp->nm_flag & NFSMNT_SOFT)
+ slptimeo = nmp->nm_retry * nmp->nm_timeo;
+
+ if (nmp->nm_iflag & NFSMNT_DISMNTFORCE)
+ slptimeo = hz;
+
catch_p = (nmp->nm_flag & NFSMNT_INT) != 0;
mutex_enter(&nmp->nm_lock);
while (/* CONSTCOND */ true) {
@@ -914,12 +943,20 @@
break;
}
if (catch_p) {
- cv_timedwait_sig(&nmp->nm_rcvcv, &nmp->nm_lock,
+ error = cv_timedwait_sig(&nmp->nm_rcvcv, &nmp->nm_lock,
slptimeo);
} else {
- cv_timedwait(&nmp->nm_rcvcv, &nmp->nm_lock,
+ error = cv_timedwait(&nmp->nm_rcvcv, &nmp->nm_lock,
slptimeo);
}
+ if (error) {
+ if ((error == EWOULDBLOCK) &&
+ (nmp->nm_flag & NFSMNT_SOFT)) {
+ error = EIO;
+ break;
+ }
+ error = 0;
+ }
if (catch_p) {
catch_p = false;
slptimeo = 2 * hz;
diff -r 097497a6be35 -r c6c96518b601 sys/nfs/nfs_var.h
--- a/sys/nfs/nfs_var.h Tue Jul 14 18:07:17 2015 +0000
+++ b/sys/nfs/nfs_var.h Wed Jul 15 03:28:55 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_var.h,v 1.93 2015/06/22 10:35:00 mrg Exp $ */
+/* $NetBSD: nfs_var.h,v 1.94 2015/07/15 03:28:55 manu Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -329,6 +329,7 @@
void nfsrv_fini(void);
void nfs_iodinit(void);
void nfs_iodfini(void);
+int nfs_iodbusy(struct nfsmount *);
int nfs_set_niothreads(int);
int nfs_getauth(struct nfsmount *, struct nfsreq *, kauth_cred_t, char **,
int *, char *, int *, NFSKERBKEY_T);
diff -r 097497a6be35 -r c6c96518b601 sys/nfs/nfs_vfsops.c
--- a/sys/nfs/nfs_vfsops.c Tue Jul 14 18:07:17 2015 +0000
+++ b/sys/nfs/nfs_vfsops.c Wed Jul 15 03:28:55 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_vfsops.c,v 1.229 2014/05/30 08:47:45 hannken Exp $ */
+/* $NetBSD: nfs_vfsops.c,v 1.230 2015/07/15 03:28:55 manu Exp $ */
/*
* Copyright (c) 1989, 1993, 1995
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_vfsops.c,v 1.229 2014/05/30 08:47:45 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_vfsops.c,v 1.230 2015/07/15 03:28:55 manu Exp $");
#if defined(_KERNEL_OPT)
#include "opt_nfs.h"
@@ -841,13 +841,18 @@
int
nfs_unmount(struct mount *mp, int mntflags)
{
- struct nfsmount *nmp;
+ struct nfsmount *nmp = VFSTONFS(mp);
struct vnode *vp;
int error, flags = 0;
- if (mntflags & MNT_FORCE)
+ if (mntflags & MNT_FORCE) {
+ mutex_enter(&nmp->nm_lock);
flags |= FORCECLOSE;
- nmp = VFSTONFS(mp);
+ nmp->nm_iflag |= NFSMNT_DISMNTFORCE;
+ mutex_exit(&nmp->nm_lock);
Home |
Main Index |
Thread Index |
Old Index