Module Name: src
Committed By: riz
Date: Wed Nov 4 17:32:00 UTC 2015
Modified Files:
src/sbin/umount [netbsd-7]: umount.c
src/sys/nfs [netbsd-7]: nfs_bio.c nfs_clntsocket.c nfs_iod.c
nfs_socket.c nfs_var.h nfs_vfsops.c nfsmount.h
Log Message:
Pull up following revision(s) (requested by manu in ticket #882):
sbin/umount/umount.c: revision 1.48
sys/nfs/nfsmount.h: revision 1.53
sys/nfs/nfs_var.h: revision 1.94
sys/nfs/nfs_iod.c: revision 1.7
sys/nfs/nfs_socket.c: revision 1.197
sys/nfs/nfs_bio.c: revision 1.191
sys/nfs/nfs_vfsops.c: revision 1.230
sys/nfs/nfs_clntsocket.c: revision 1.3
Remove useless and harmful sync(2) call in umount(8)
Remove sync(2) call before unmount(2) in umount(8). This sync(2) is useless
since unmount(2) will perform a VFS_SYNC anyway.
But moreover, this sync(2) may be harmful, as there are some situation where
it cannot return (unreachable NFS server, for instance), causing umount -f
to be uneffective.
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.
To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.47.6.1 src/sbin/umount/umount.c
cvs rdiff -u -r1.189 -r1.189.4.1 src/sys/nfs/nfs_bio.c
cvs rdiff -u -r1.1 -r1.1.40.1 src/sys/nfs/nfs_clntsocket.c
cvs rdiff -u -r1.6 -r1.6.4.1 src/sys/nfs/nfs_iod.c
cvs rdiff -u -r1.192 -r1.192.2.1 src/sys/nfs/nfs_socket.c
cvs rdiff -u -r1.92 -r1.92.2.1 src/sys/nfs/nfs_var.h
cvs rdiff -u -r1.229 -r1.229.2.1 src/sys/nfs/nfs_vfsops.c
cvs rdiff -u -r1.52 -r1.52.2.1 src/sys/nfs/nfsmount.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sbin/umount/umount.c
diff -u src/sbin/umount/umount.c:1.47 src/sbin/umount/umount.c:1.47.6.1
--- src/sbin/umount/umount.c:1.47 Tue Jul 2 01:39:17 2013
+++ src/sbin/umount/umount.c Wed Nov 4 17:32:00 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: umount.c,v 1.47 2013/07/02 01:39:17 christos Exp $ */
+/* $NetBSD: umount.c,v 1.47.6.1 2015/11/04 17:32:00 riz Exp $ */
/*-
* Copyright (c) 1980, 1989, 1993
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 19
#if 0
static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95";
#else
-__RCSID("$NetBSD: umount.c,v 1.47 2013/07/02 01:39:17 christos Exp $");
+__RCSID("$NetBSD: umount.c,v 1.47.6.1 2015/11/04 17:32:00 riz Exp $");
#endif
#endif /* not lint */
@@ -96,9 +96,6 @@ main(int argc, char *argv[])
#endif /* SMALL */
const char **typelist = NULL;
- /* Start disks transferring immediately. */
- sync();
-
#ifdef SMALL
#define OPTS "fR"
#else
Index: src/sys/nfs/nfs_bio.c
diff -u src/sys/nfs/nfs_bio.c:1.189 src/sys/nfs/nfs_bio.c:1.189.4.1
--- src/sys/nfs/nfs_bio.c:1.189 Mon Aug 12 17:46:38 2013
+++ src/sys/nfs/nfs_bio.c Wed Nov 4 17:32:00 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_bio.c,v 1.189 2013/08/12 17:46:38 hannken Exp $ */
+/* $NetBSD: nfs_bio.c,v 1.189.4.1 2015/11/04 17:32:00 riz Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.189 2013/08/12 17:46:38 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.189.4.1 2015/11/04 17:32:00 riz Exp $");
#ifdef _KERNEL_OPT
#include "opt_nfs.h"
@@ -624,7 +624,10 @@ nfs_vinvalbuf(struct vnode *vp, int flag
slptimeo = 2 * hz;
} else {
catch = 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 @@ nfs_asyncio(struct buf *bp)
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 = true;
@@ -804,6 +814,13 @@ again:
&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);
Index: src/sys/nfs/nfs_clntsocket.c
diff -u src/sys/nfs/nfs_clntsocket.c:1.1 src/sys/nfs/nfs_clntsocket.c:1.1.40.1
--- src/sys/nfs/nfs_clntsocket.c:1.1 Tue Mar 2 23:19:09 2010
+++ src/sys/nfs/nfs_clntsocket.c Wed Nov 4 17:32:00 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_clntsocket.c,v 1.1 2010/03/02 23:19:09 pooka Exp $ */
+/* $NetBSD: nfs_clntsocket.c,v 1.1.40.1 2015/11/04 17:32:00 riz Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1995
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_clntsocket.c,v 1.1 2010/03/02 23:19:09 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_clntsocket.c,v 1.1.40.1 2015/11/04 17:32:00 riz Exp $");
#ifdef _KERNEL_OPT
#include "opt_nfs.h"
@@ -967,6 +967,12 @@ nfs_sndlock(struct nfsmount *nmp, struct
bool catch = 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 @@ nfs_sndlock(struct nfsmount *nmp, struct
goto quit;
}
if (catch) {
- 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) {
catch = false;
Index: src/sys/nfs/nfs_iod.c
diff -u src/sys/nfs/nfs_iod.c:1.6 src/sys/nfs/nfs_iod.c:1.6.4.1
--- src/sys/nfs/nfs_iod.c:1.6 Fri Oct 25 16:01:56 2013
+++ src/sys/nfs/nfs_iod.c Wed Nov 4 17:32:00 2015
@@ -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.6.4.1 2015/11/04 17:32:00 riz 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.6.4.1 2015/11/04 17:32:00 riz Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -202,6 +202,22 @@ nfs_iodfini(void)
}
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;
Index: src/sys/nfs/nfs_socket.c
diff -u src/sys/nfs/nfs_socket.c:1.192 src/sys/nfs/nfs_socket.c:1.192.2.1
--- src/sys/nfs/nfs_socket.c:1.192 Tue Aug 5 07:55:32 2014
+++ src/sys/nfs/nfs_socket.c Wed Nov 4 17:32:00 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_socket.c,v 1.192 2014/08/05 07:55:32 rtr Exp $ */
+/* $NetBSD: nfs_socket.c,v 1.192.2.1 2015/11/04 17:32:00 riz Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1995
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.192 2014/08/05 07:55:32 rtr Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.192.2.1 2015/11/04 17:32:00 riz Exp $");
#ifdef _KERNEL_OPT
#include "opt_nfs.h"
@@ -66,6 +66,7 @@ __KERNEL_RCSID(0, "$NetBSD: nfs_socket.c
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/kauth.h>
+#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -358,11 +359,33 @@ nfs_reconnect(struct nfsreq *rep)
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);
}
@@ -894,6 +917,12 @@ nfs_rcvlock(struct nfsmount *nmp, struct
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 = (nmp->nm_flag & NFSMNT_INT) != 0;
mutex_enter(&nmp->nm_lock);
while (/* CONSTCOND */ true) {
@@ -922,12 +951,20 @@ nfs_rcvlock(struct nfsmount *nmp, struct
break;
}
if (catch) {
- 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) {
catch = false;
slptimeo = 2 * hz;
Index: src/sys/nfs/nfs_var.h
diff -u src/sys/nfs/nfs_var.h:1.92 src/sys/nfs/nfs_var.h:1.92.2.1
--- src/sys/nfs/nfs_var.h:1.92 Fri May 30 08:47:45 2014
+++ src/sys/nfs/nfs_var.h Wed Nov 4 17:32:00 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_var.h,v 1.92 2014/05/30 08:47:45 hannken Exp $ */
+/* $NetBSD: nfs_var.h,v 1.92.2.1 2015/11/04 17:32:00 riz Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -330,6 +330,7 @@ void nfsrv_init(int);
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);
Index: src/sys/nfs/nfs_vfsops.c
diff -u src/sys/nfs/nfs_vfsops.c:1.229 src/sys/nfs/nfs_vfsops.c:1.229.2.1
--- src/sys/nfs/nfs_vfsops.c:1.229 Fri May 30 08:47:45 2014
+++ src/sys/nfs/nfs_vfsops.c Wed Nov 4 17:32:00 2015
@@ -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.229.2.1 2015/11/04 17:32:00 riz 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.229.2.1 2015/11/04 17:32:00 riz Exp $");
#if defined(_KERNEL_OPT)
#include "opt_nfs.h"
@@ -841,13 +841,18 @@ bad:
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);
+
+ }
+
/*
* Goes something like this..
* - Check for activity on the root vnode (other than ourselves).
@@ -864,17 +869,18 @@ nfs_unmount(struct mount *mp, int mntfla
vp = nmp->nm_vnode;
error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (error != 0)
- return error;
+ goto err;
if ((mntflags & MNT_FORCE) == 0 && vp->v_usecount > 1) {
VOP_UNLOCK(vp);
- return (EBUSY);
+ error = EBUSY;
+ goto err;
}
error = vflush(mp, vp, flags);
if (error) {
VOP_UNLOCK(vp);
- return (error);
+ goto err;
}
/*
@@ -885,6 +891,13 @@ nfs_unmount(struct mount *mp, int mntfla
nmp->nm_iflag |= NFSMNT_DISMNT;
/*
+ * No new async I/O will be added, but await for pending
+ * ones to drain.
+ */
+ while (nfs_iodbusy(nmp))
+ kpause("nfsumnt", false, hz, NULL);
+
+ /*
* Clean up the stats... note that we carefully avoid decrementing
* nfs_mount_count here for good reason - we may not be unmounting
* the last thing mounted.
@@ -908,6 +921,15 @@ nfs_unmount(struct mount *mp, int mntfla
cv_destroy(&nmp->nm_disconcv);
kmem_free(nmp, sizeof(*nmp));
return (0);
+
+err:
+ if (mntflags & MNT_FORCE) {
+ mutex_enter(&nmp->nm_lock);
+ nmp->nm_iflag &= ~NFSMNT_DISMNTFORCE;
+ mutex_exit(&nmp->nm_lock);
+ }
+
+ return error;
}
/*
Index: src/sys/nfs/nfsmount.h
diff -u src/sys/nfs/nfsmount.h:1.52 src/sys/nfs/nfsmount.h:1.52.2.1
--- src/sys/nfs/nfsmount.h:1.52 Fri May 30 08:47:45 2014
+++ src/sys/nfs/nfsmount.h Wed Nov 4 17:32:00 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: nfsmount.h,v 1.52 2014/05/30 08:47:45 hannken Exp $ */
+/* $NetBSD: nfsmount.h,v 1.52.2.1 2015/11/04 17:32:00 riz Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -120,6 +120,7 @@ struct nfs_args {
#define NFSMNT_SWAPCOOKIE 0x00004000 /* XDR encode dir cookies */
#define NFSMNT_STALEWRITEVERF 0x00008000 /* Write verifier is changing */
#define NFSMNT_WCCKLUDGE 0x00010000 /* see nfs_check_wccdata() */
+#define NFSMNT_DISMNTFORCE 0x00020000 /* force unmount requested */
#if defined(_KERNEL) && !defined(NFS_ARGS_ONLY)
/*