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