Author: rmacklem
Date: Sat May  7 20:09:15 2016
New Revision: 299222
URL: https://svnweb.freebsd.org/changeset/base/299222

Log:
  MFC: r298495
  Fix a LOR in the NFSv4.1 server.
  
  The ordering of acquisition of the state and session mutexes was
  reversed in two cases executed when an NFSv4.1 client created/freed
  a session. Since clients will typically do this only when mounting
  and dismounting, the likelyhood of causing a deadlock was low but possible.
  This can only occur for NFSv4.1 mounts, since the others do not
  use sessions.
  This was detected while testing the pNFS server/client where the
  client crashed during dismounting.
  The patch also reorders the unlocks, although that isn't necessary
  for correct operation.

Modified:
  stable/10/sys/fs/nfs/nfsrvstate.h
  stable/10/sys/fs/nfsserver/nfs_nfsdstate.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/fs/nfs/nfsrvstate.h
==============================================================================
--- stable/10/sys/fs/nfs/nfsrvstate.h   Sat May  7 19:05:39 2016        
(r299221)
+++ stable/10/sys/fs/nfs/nfsrvstate.h   Sat May  7 20:09:15 2016        
(r299222)
@@ -113,7 +113,7 @@ struct nfsclient {
  * Structure for an NFSv4.1 session.
  * Locking rules for this structure.
  * To add/delete one of these structures from the lists, you must lock
- * both: NFSLOCKSESSION(session hashhead) and NFSLOCKSTATE() in that order.
+ * both: NFSLOCKSTATE() and NFSLOCKSESSION(session hashhead) in that order.
  * To traverse the lists looking for one of these, you must hold one
  * of these two locks.
  * The exception is if the thread holds the exclusive root sleep lock.

Modified: stable/10/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- stable/10/sys/fs/nfsserver/nfs_nfsdstate.c  Sat May  7 19:05:39 2016        
(r299221)
+++ stable/10/sys/fs/nfsserver/nfs_nfsdstate.c  Sat May  7 20:09:15 2016        
(r299222)
@@ -629,13 +629,13 @@ nfsrv_getclient(nfsquad_t clientid, int 
                        NFSBCOPY(sessid, nsep->sess_cbsess.nfsess_sessionid,
                            NFSX_V4SESSIONID);
                        shp = NFSSESSIONHASH(nsep->sess_sessionid);
+                       NFSLOCKSTATE();
                        NFSLOCKSESSION(shp);
                        LIST_INSERT_HEAD(&shp->list, nsep, sess_hash);
-                       NFSLOCKSTATE();
                        LIST_INSERT_HEAD(&clp->lc_session, nsep, sess_list);
                        nsep->sess_clp = clp;
-                       NFSUNLOCKSTATE();
                        NFSUNLOCKSESSION(shp);
+                       NFSUNLOCKSTATE();
                    }
                }
        } else if (clp->lc_flags & LCL_NEEDSCONFIRM) {
@@ -5915,6 +5915,7 @@ nfsrv_freesession(struct nfsdsession *se
        struct nfssessionhash *shp;
        int i;
 
+       NFSLOCKSTATE();
        if (sep == NULL) {
                shp = NFSSESSIONHASH(sessionid);
                NFSLOCKSESSION(shp);
@@ -5924,18 +5925,17 @@ nfsrv_freesession(struct nfsdsession *se
                NFSLOCKSESSION(shp);
        }
        if (sep != NULL) {
-               NFSLOCKSTATE();
                sep->sess_refcnt--;
                if (sep->sess_refcnt > 0) {
-                       NFSUNLOCKSTATE();
                        NFSUNLOCKSESSION(shp);
+                       NFSUNLOCKSTATE();
                        return (0);
                }
                LIST_REMOVE(sep, sess_hash);
                LIST_REMOVE(sep, sess_list);
-               NFSUNLOCKSTATE();
        }
        NFSUNLOCKSESSION(shp);
+       NFSUNLOCKSTATE();
        if (sep == NULL)
                return (NFSERR_BADSESSION);
        for (i = 0; i < NFSV4_SLOTS; i++)
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to