diff options
author | Steve Dickson <steved@redhat.com> | 2014-09-18 09:13:17 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-09-18 13:04:21 -0400 |
commit | 080af20cc945d110f9912d01cf6b66f94a375b8d (patch) | |
tree | cd54ec58f700903855505a200834bf51761bd4b8 /fs/nfs/nfs4client.c | |
parent | f39c01047994e66e7f3d89ddb4c6141f23349d8d (diff) |
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 <stable@vger.kernel.org>
Signed-off-by: Steve Dickson <steved@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/nfs4client.c')
-rw-r--r-- | fs/nfs/nfs4client.c | 38 |
1 files changed, 20 insertions, 18 deletions
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 53e435a95260..ffdb28d86cf8 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -482,6 +482,16 @@ int nfs40_walk_client_list(struct nfs_client *new, | |||
482 | 482 | ||
483 | spin_lock(&nn->nfs_client_lock); | 483 | spin_lock(&nn->nfs_client_lock); |
484 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { | 484 | 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 | |||
485 | /* If "pos" isn't marked ready, we can't trust the | 495 | /* If "pos" isn't marked ready, we can't trust the |
486 | * remaining fields in "pos" */ | 496 | * remaining fields in "pos" */ |
487 | if (pos->cl_cons_state > NFS_CS_READY) { | 497 | if (pos->cl_cons_state > NFS_CS_READY) { |
@@ -501,15 +511,6 @@ int nfs40_walk_client_list(struct nfs_client *new, | |||
501 | if (pos->cl_cons_state != NFS_CS_READY) | 511 | if (pos->cl_cons_state != NFS_CS_READY) |
502 | continue; | 512 | continue; |
503 | 513 | ||
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 | |||
513 | if (pos->cl_clientid != new->cl_clientid) | 514 | if (pos->cl_clientid != new->cl_clientid) |
514 | continue; | 515 | continue; |
515 | 516 | ||
@@ -622,6 +623,16 @@ int nfs41_walk_client_list(struct nfs_client *new, | |||
622 | 623 | ||
623 | spin_lock(&nn->nfs_client_lock); | 624 | spin_lock(&nn->nfs_client_lock); |
624 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { | 625 | 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 | |||
625 | /* If "pos" isn't marked ready, we can't trust the | 636 | /* If "pos" isn't marked ready, we can't trust the |
626 | * remaining fields in "pos", especially the client | 637 | * remaining fields in "pos", especially the client |
627 | * ID and serverowner fields. Wait for CREATE_SESSION | 638 | * ID and serverowner fields. Wait for CREATE_SESSION |
@@ -647,15 +658,6 @@ int nfs41_walk_client_list(struct nfs_client *new, | |||
647 | if (pos->cl_cons_state != NFS_CS_READY) | 658 | if (pos->cl_cons_state != NFS_CS_READY) |
648 | continue; | 659 | continue; |
649 | 660 | ||
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 | |||
659 | if (!nfs4_match_clientids(pos, new)) | 661 | if (!nfs4_match_clientids(pos, new)) |
660 | continue; | 662 | continue; |
661 | 663 | ||