aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorStanislav Kinsbursky <skinsbursky@parallels.com>2012-05-25 10:38:50 -0400
committerJ. Bruce Fields <bfields@redhat.com>2012-07-25 09:18:27 -0400
commita6d88f293ecd1b7444e128777f4a893e7a998852 (patch)
treecb8e65d7b24192bc8cdbe2afa4aad506c0e99db7 /fs/nfsd
parent5559b50acdcdcad7e362882d3261bf934c9436f6 (diff)
NFSd: fix locking in nfsd_forget_delegations()
This patch adds recall_lock hold to nfsd_forget_delegations() to protect nfsd_process_n_delegations() call. Also, looks like it would be better to collect delegations to some local on-stack list, and then unhash collected list. This split allows to simplify locking, because delegation traversing is protected by recall_lock, when delegation unhash is protected by client_mutex. Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fe96015fbfc..d10ad8bc47a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4575,7 +4575,7 @@ void nfsd_forget_openowners(u64 num)
4575 printk(KERN_INFO "NFSD: Forgot %d open owners", count); 4575 printk(KERN_INFO "NFSD: Forgot %d open owners", count);
4576} 4576}
4577 4577
4578int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *)) 4578int nfsd_process_n_delegations(u64 num, struct list_head *list)
4579{ 4579{
4580 int i, count = 0; 4580 int i, count = 0;
4581 struct nfs4_file *fp, *fnext; 4581 struct nfs4_file *fp, *fnext;
@@ -4584,7 +4584,7 @@ int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegatio
4584 for (i = 0; i < FILE_HASH_SIZE; i++) { 4584 for (i = 0; i < FILE_HASH_SIZE; i++) {
4585 list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) { 4585 list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) {
4586 list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) { 4586 list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) {
4587 deleg_func(dp); 4587 list_move(&dp->dl_recall_lru, list);
4588 if (++count == num) 4588 if (++count == num)
4589 return count; 4589 return count;
4590 } 4590 }
@@ -4597,9 +4597,16 @@ int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegatio
4597void nfsd_forget_delegations(u64 num) 4597void nfsd_forget_delegations(u64 num)
4598{ 4598{
4599 unsigned int count; 4599 unsigned int count;
4600 LIST_HEAD(victims);
4601 struct nfs4_delegation *dp, *dnext;
4602
4603 spin_lock(&recall_lock);
4604 count = nfsd_process_n_delegations(num, &victims);
4605 spin_unlock(&recall_lock);
4600 4606
4601 nfs4_lock_state(); 4607 nfs4_lock_state();
4602 count = nfsd_process_n_delegations(num, unhash_delegation); 4608 list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru)
4609 unhash_delegation(dp);
4603 nfs4_unlock_state(); 4610 nfs4_unlock_state();
4604 4611
4605 printk(KERN_INFO "NFSD: Forgot %d delegations", count); 4612 printk(KERN_INFO "NFSD: Forgot %d delegations", count);
@@ -4608,12 +4615,16 @@ void nfsd_forget_delegations(u64 num)
4608void nfsd_recall_delegations(u64 num) 4615void nfsd_recall_delegations(u64 num)
4609{ 4616{
4610 unsigned int count; 4617 unsigned int count;
4618 LIST_HEAD(victims);
4619 struct nfs4_delegation *dp, *dnext;
4611 4620
4612 nfs4_lock_state();
4613 spin_lock(&recall_lock); 4621 spin_lock(&recall_lock);
4614 count = nfsd_process_n_delegations(num, nfsd_break_one_deleg); 4622 count = nfsd_process_n_delegations(num, &victims);
4623 list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) {
4624 list_del(&dp->dl_recall_lru);
4625 nfsd_break_one_deleg(dp);
4626 }
4615 spin_unlock(&recall_lock); 4627 spin_unlock(&recall_lock);
4616 nfs4_unlock_state();
4617 4628
4618 printk(KERN_INFO "NFSD: Recalled %d delegations", count); 4629 printk(KERN_INFO "NFSD: Recalled %d delegations", count);
4619} 4630}