Skip to content

Commit 080af20

Browse files
steveddtrondmypd
authored andcommitted
NFSv4: nfs4_state_manager() vs. nfs_server_remove_lists()
There is a race between nfs4_state_manager() and nfs_server_remove_lists() that happens during a nfsv3 mount. The v3 mount notices there is already a supper block so nfs_server_remove_lists() called which uses the nfs_client_lock spin lock to synchronize access to the client list. At the same time nfs4_state_manager() is running through the client list looking for work to do, using the same lock. When nfs4_state_manager() wins the race to the list, a v3 client pointer is found and not ignored properly which causes the panic. Moving some protocol checks before the state checking avoids the panic. CC: Stable Tree <[email protected]> Signed-off-by: Steve Dickson <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent f39c010 commit 080af20

File tree

1 file changed

+20
-18
lines changed

1 file changed

+20
-18
lines changed

fs/nfs/nfs4client.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,16 @@ int nfs40_walk_client_list(struct nfs_client *new,
482482

483483
spin_lock(&nn->nfs_client_lock);
484484
list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
485+
486+
if (pos->rpc_ops != new->rpc_ops)
487+
continue;
488+
489+
if (pos->cl_proto != new->cl_proto)
490+
continue;
491+
492+
if (pos->cl_minorversion != new->cl_minorversion)
493+
continue;
494+
485495
/* If "pos" isn't marked ready, we can't trust the
486496
* remaining fields in "pos" */
487497
if (pos->cl_cons_state > NFS_CS_READY) {
@@ -501,15 +511,6 @@ int nfs40_walk_client_list(struct nfs_client *new,
501511
if (pos->cl_cons_state != NFS_CS_READY)
502512
continue;
503513

504-
if (pos->rpc_ops != new->rpc_ops)
505-
continue;
506-
507-
if (pos->cl_proto != new->cl_proto)
508-
continue;
509-
510-
if (pos->cl_minorversion != new->cl_minorversion)
511-
continue;
512-
513514
if (pos->cl_clientid != new->cl_clientid)
514515
continue;
515516

@@ -622,6 +623,16 @@ int nfs41_walk_client_list(struct nfs_client *new,
622623

623624
spin_lock(&nn->nfs_client_lock);
624625
list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
626+
627+
if (pos->rpc_ops != new->rpc_ops)
628+
continue;
629+
630+
if (pos->cl_proto != new->cl_proto)
631+
continue;
632+
633+
if (pos->cl_minorversion != new->cl_minorversion)
634+
continue;
635+
625636
/* If "pos" isn't marked ready, we can't trust the
626637
* remaining fields in "pos", especially the client
627638
* ID and serverowner fields. Wait for CREATE_SESSION
@@ -647,15 +658,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
647658
if (pos->cl_cons_state != NFS_CS_READY)
648659
continue;
649660

650-
if (pos->rpc_ops != new->rpc_ops)
651-
continue;
652-
653-
if (pos->cl_proto != new->cl_proto)
654-
continue;
655-
656-
if (pos->cl_minorversion != new->cl_minorversion)
657-
continue;
658-
659661
if (!nfs4_match_clientids(pos, new))
660662
continue;
661663

0 commit comments

Comments
 (0)