diff options
author | rmacklem <rmacklem@FreeBSD.org> | 2016-04-23 01:22:04 +0000 |
---|---|---|
committer | rmacklem <rmacklem@FreeBSD.org> | 2016-04-23 01:22:04 +0000 |
commit | dc6a2918e18b2187f858d458f372662a66b2795b (patch) | |
tree | 683bbe2f22023e8d0cef090c2f36de16ce6ae776 /sys/fs | |
parent | 4b68f838a5c9711bda03ee8228cbef80410986f0 (diff) | |
download | FreeBSD-src-dc6a2918e18b2187f858d458f372662a66b2795b.zip FreeBSD-src-dc6a2918e18b2187f858d458f372662a66b2795b.tar.gz |
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.
MFC after: 2 weeks
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/nfs/nfsrvstate.h | 2 | ||||
-rw-r--r-- | sys/fs/nfsserver/nfs_nfsdstate.c | 10 |
2 files changed, 6 insertions, 6 deletions
diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h index 6d32244..42254ab 100644 --- a/sys/fs/nfs/nfsrvstate.h +++ b/sys/fs/nfs/nfsrvstate.h @@ -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. diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 0e8a743..c0a5a6e 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -624,13 +624,13 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp, 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) { @@ -5923,6 +5923,7 @@ nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid) struct nfssessionhash *shp; int i; + NFSLOCKSTATE(); if (sep == NULL) { shp = NFSSESSIONHASH(sessionid); NFSLOCKSESSION(shp); @@ -5932,18 +5933,17 @@ nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid) 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++) |