aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-04-03 19:04:58 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-04-05 17:03:56 -0400
commit5c31e2368f39aee062cb697d4b8857c64c7cef7c (patch)
tree99ce8f55797be64962c30a843666a0089e051665
parentb757144fd77cf5512f5b60179ba5ca8dcc5184b4 (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.c24
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
505static 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,
510void nfs_server_return_all_delegations(struct nfs_server *server) 522void 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
530static void nfs_mark_return_all_delegation_types(struct nfs_server *server, 540static void nfs_mark_return_all_delegation_types(struct nfs_server *server,