diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-04-03 19:04:58 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-04-05 17:03:56 -0400 |
commit | 5c31e2368f39aee062cb697d4b8857c64c7cef7c (patch) | |
tree | 99ce8f55797be64962c30a843666a0089e051665 | |
parent | b757144fd77cf5512f5b60179ba5ca8dcc5184b4 (diff) |
NFSv4: Fix nfs_server_return_all_delegations
If the state manager thread is already running, we may end up
racing with it in nfs_client_return_marked_delegations. Better to
just allow the state manager thread to do the job.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/delegation.c | 24 |
1 files changed, 17 insertions, 7 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index a377ea36381e..213f1bbeb828 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -502,6 +502,18 @@ static void nfs_mark_return_delegation(struct nfs_server *server, | |||
502 | set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); | 502 | set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); |
503 | } | 503 | } |
504 | 504 | ||
505 | static bool nfs_server_mark_return_all_delegations(struct nfs_server *server) | ||
506 | { | ||
507 | struct nfs_delegation *delegation; | ||
508 | bool ret = false; | ||
509 | |||
510 | list_for_each_entry_rcu(delegation, &server->delegations, super_list) { | ||
511 | nfs_mark_return_delegation(server, delegation); | ||
512 | ret = true; | ||
513 | } | ||
514 | return ret; | ||
515 | } | ||
516 | |||
505 | /** | 517 | /** |
506 | * nfs_super_return_all_delegations - return delegations for one superblock | 518 | * nfs_super_return_all_delegations - return delegations for one superblock |
507 | * @sb: sb to process | 519 | * @sb: sb to process |
@@ -510,21 +522,19 @@ static void nfs_mark_return_delegation(struct nfs_server *server, | |||
510 | void nfs_server_return_all_delegations(struct nfs_server *server) | 522 | void nfs_server_return_all_delegations(struct nfs_server *server) |
511 | { | 523 | { |
512 | struct nfs_client *clp = server->nfs_client; | 524 | struct nfs_client *clp = server->nfs_client; |
513 | struct nfs_delegation *delegation; | 525 | bool need_wait; |
514 | 526 | ||
515 | if (clp == NULL) | 527 | if (clp == NULL) |
516 | return; | 528 | return; |
517 | 529 | ||
518 | rcu_read_lock(); | 530 | rcu_read_lock(); |
519 | list_for_each_entry_rcu(delegation, &server->delegations, super_list) { | 531 | need_wait = nfs_server_mark_return_all_delegations(server); |
520 | spin_lock(&delegation->lock); | ||
521 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | ||
522 | spin_unlock(&delegation->lock); | ||
523 | } | ||
524 | rcu_read_unlock(); | 532 | rcu_read_unlock(); |
525 | 533 | ||
526 | if (nfs_client_return_marked_delegations(clp) != 0) | 534 | if (need_wait) { |
527 | nfs4_schedule_state_manager(clp); | 535 | nfs4_schedule_state_manager(clp); |
536 | nfs4_wait_clnt_recover(clp); | ||
537 | } | ||
528 | } | 538 | } |
529 | 539 | ||
530 | static void nfs_mark_return_all_delegation_types(struct nfs_server *server, | 540 | static void nfs_mark_return_all_delegation_types(struct nfs_server *server, |