aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-08-09 10:22:40 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-08-17 12:00:13 -0400
commit6bcc034eac79873468cdfd1ccea9f25ee67c4500 (patch)
treeb3996e0662afc5bc709a9ec286e1f5034952f320
parentef9b16dc6de692865e898a35e750119b5b9c82c5 (diff)
nfsd: protect lease-related nfs4_file fields with fi_lock
Currently these fields are protected with the state_lock, but that doesn't really make a lot of sense. These fields are "private" to the nfs4_file, and can be protected with the more granular fi_lock. The fi_lock is already held when setting these fields. Make the code hold the fp->fi_lock when clearing the lease-related fields in the nfs4_file, and no longer require that the state_lock be held when calling into this function. To prevent lock inversion with the i_lock, we also move the vfs_setlease and fput calls outside of the fi_lock. This also sets us up for allowing vfs_setlease calls to block in the future. Finally, remove a redundant NULL pointer check. unhash_delegation_locked locks the fp->fi_lock prior to that check, so fp in that function must never be NULL. Signed-off-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2e80a59e7e91..309ec3b1090a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -673,15 +673,20 @@ nfs4_put_stid(struct nfs4_stid *s)
673 673
674static void nfs4_put_deleg_lease(struct nfs4_file *fp) 674static void nfs4_put_deleg_lease(struct nfs4_file *fp)
675{ 675{
676 lockdep_assert_held(&state_lock); 676 struct file *filp = NULL;
677 struct file_lock *fl;
677 678
678 if (!fp->fi_lease) 679 spin_lock(&fp->fi_lock);
679 return; 680 if (fp->fi_lease && atomic_dec_and_test(&fp->fi_delegees)) {
680 if (atomic_dec_and_test(&fp->fi_delegees)) { 681 swap(filp, fp->fi_deleg_file);
681 vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); 682 fl = fp->fi_lease;
682 fp->fi_lease = NULL; 683 fp->fi_lease = NULL;
683 fput(fp->fi_deleg_file); 684 }
684 fp->fi_deleg_file = NULL; 685 spin_unlock(&fp->fi_lock);
686
687 if (filp) {
688 vfs_setlease(filp, F_UNLCK, &fl);
689 fput(filp);
685 } 690 }
686} 691}
687 692
@@ -717,8 +722,7 @@ unhash_delegation_locked(struct nfs4_delegation *dp)
717 list_del_init(&dp->dl_recall_lru); 722 list_del_init(&dp->dl_recall_lru);
718 list_del_init(&dp->dl_perfile); 723 list_del_init(&dp->dl_perfile);
719 spin_unlock(&fp->fi_lock); 724 spin_unlock(&fp->fi_lock);
720 if (fp) 725 nfs4_put_deleg_lease(fp);
721 nfs4_put_deleg_lease(fp);
722} 726}
723 727
724static void destroy_delegation(struct nfs4_delegation *dp) 728static void destroy_delegation(struct nfs4_delegation *dp)