Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/nfs kern/5591: Fix race in the NFS socket code during um...



details:   https://anonhg.NetBSD.org/src/rev/9705f3e08fae
branches:  trunk
changeset: 474376:9705f3e08fae
user:      sommerfeld <sommerfeld%NetBSD.org@localhost>
date:      Sun Jul 04 19:56:00 1999 +0000

description:
kern/5591: Fix race in the NFS socket code during umount -f and system
shutdown:

During an unmount, wake up all the processes which are waiting to lock
the socket for receive, and wait for them (and the process blocked in
soreceive, if any) to go away before blowing away the socket and the
mount structure.

diffstat:

 sys/nfs/nfs_socket.c |  46 +++++++++++++++++++++++++++++++++++++++++++---
 sys/nfs/nfsmount.h   |   3 ++-
 2 files changed, 45 insertions(+), 4 deletions(-)

diffs (129 lines):

diff -r 4ec7de3047da -r 9705f3e08fae sys/nfs/nfs_socket.c
--- a/sys/nfs/nfs_socket.c      Sun Jul 04 16:20:12 1999 +0000
+++ b/sys/nfs/nfs_socket.c      Sun Jul 04 19:56:00 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nfs_socket.c,v 1.50 1999/03/06 05:34:41 fair Exp $     */
+/*     $NetBSD: nfs_socket.c,v 1.51 1999/07/04 19:56:00 sommerfeld Exp $       */
 
 /*
  * Copyright (c) 1989, 1991, 1993, 1995
@@ -329,8 +329,25 @@
                so = nmp->nm_so;
                nmp->nm_so = (struct socket *)0;
                soshutdown(so, 2);
+               if (nmp->nm_iflag & NFSMNT_DISMNT) {
+                       /*
+                        * soshutdown() above should wake up the current
+                        * listener.
+                        * Now wake up those waiting for the recive lock, and
+                        * wait for them to go away unhappy, to prevent *nmp
+                        * from evaporating while they're sleeping.
+                        */
+                       while (nmp->nm_waiters > 0) {
+                               wakeup (&nmp->nm_iflag);
+                               sleep(&nmp->nm_waiters, PVFS);
+                       }
+               }
                soclose(so);
        }
+#ifdef DIAGNOSTIC
+       if (nmp->nm_waiters > 0)
+               panic("nfs_disconnect: waiters left after drain?\n");
+#endif
 }
 
 void
@@ -341,7 +358,7 @@
 
        memset(&dummyreq, 0, sizeof(dummyreq));
        dummyreq.r_nmp = nmp;
-       nfs_rcvlock(&dummyreq);
+       nfs_rcvlock(&dummyreq); /* XXX ignored error return */
        nfs_disconnect(nmp);
        nfs_rcvunlock(&nmp->nm_iflag);
 }
@@ -628,6 +645,8 @@
                                return (EINTR);
                } while (error == EWOULDBLOCK);
                len -= auio.uio_resid;
+               if (!error && *mp == NULL)
+                       error = EPIPE;
        }
        if (error) {
                m_freem(*mp);
@@ -672,10 +691,20 @@
                /*
                 * Get the next Rpc reply off the socket
                 */
+               nmp->nm_waiters++;
                error = nfs_receive(myrep, &nam, &mrep);
                nfs_rcvunlock(&nmp->nm_iflag);
                if (error) {
 
+                       if (nmp->nm_iflag & NFSMNT_DISMNT) {
+                               /*
+                                * Oops, we're going away now..
+                                */
+                               nmp->nm_waiters--;
+                               wakeup (&nmp->nm_waiters);
+                               return error;
+                       }
+                       nmp->nm_waiters--;
                        /*
                         * Ignore routing errors on connectionless protocols??
                         */
@@ -690,6 +719,7 @@
                        }
                        return (error);
                }
+               nmp->nm_waiters--;                      
                if (nam)
                        m_freem(nam);
        
@@ -1466,9 +1496,13 @@
 nfs_rcvlock(rep)
        register struct nfsreq *rep;
 {
-       register int *flagp = &rep->r_nmp->nm_iflag;
+       struct nfsmount *nmp = rep->r_nmp;
+       register int *flagp = &nmp->nm_iflag;
        int slpflag, slptimeo = 0;
 
+       if (*flagp & NFSMNT_DISMNT)
+               return EIO;
+       
        if (*flagp & NFSMNT_INT)
                slpflag = PCATCH;
        else
@@ -1477,8 +1511,14 @@
                if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp))
                        return (EINTR);
                *flagp |= NFSMNT_WANTRCV;
+               nmp->nm_waiters++;
                (void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsrcvlk",
                        slptimeo);
+               nmp->nm_waiters--;
+               if (*flagp & NFSMNT_DISMNT) {
+                       wakeup(&nmp->nm_waiters);
+                       return EIO;
+               }
                /* If our reply was received while we were sleeping,
                 * then just return without taking the lock to avoid a
                 * situation where a single iod could 'capture' the
diff -r 4ec7de3047da -r 9705f3e08fae sys/nfs/nfsmount.h
--- a/sys/nfs/nfsmount.h        Sun Jul 04 16:20:12 1999 +0000
+++ b/sys/nfs/nfsmount.h        Sun Jul 04 19:56:00 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nfsmount.h,v 1.17 1999/02/26 23:44:48 wrstuden Exp $   */
+/*     $NetBSD: nfsmount.h,v 1.18 1999/07/04 19:56:00 sommerfeld Exp $ */
 
 /*
  * Copyright (c) 1989, 1993
@@ -158,6 +158,7 @@
        int     nm_bufqiods;            /* number of iods processing queue */
        u_int64_t nm_maxfilesize;       /* maximum file size */
        int     nm_iflag;               /* internal flags */
+       int     nm_waiters;             /* number of waiting listeners.. */
 };
 
 /*



Home | Main Index | Thread Index | Old Index