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/010ea7ecf5ee
branches:  trunk
changeset: 339334:010ea7ecf5ee
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 1779843e054e -r 010ea7ecf5ee 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 1779843e054e -r 010ea7ecf5ee 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 1779843e054e -r 010ea7ecf5ee 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 1779843e054e -r 010ea7ecf5ee 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 1779843e054e -r 010ea7ecf5ee 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 1779843e054e -r 010ea7ecf5ee 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