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)
 /*

Reply via email to