aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-07-10 14:07:25 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-07-10 15:05:25 -0400
commit1d31a2531ae91f8a89c0fffa883ef922c0dbb74d (patch)
tree8c68acb7b5472803ccd8cbf1ffab9b467a377904
parentd6c249b4d4cfef894cbda224a7a063d17aacb60a (diff)
nfsd: Add fine grained protection for the nfs4_file->fi_stateids list
Access to this list is currently serialized by the client_mutex. Add finer grained locking around this list in preparation for its removal. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c21
-rw-r--r--fs/nfsd/state.h1
2 files changed, 19 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3704789ca4b7..cfb10d060c83 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -708,7 +708,11 @@ release_all_access(struct nfs4_ol_stateid *stp)
708 708
709static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) 709static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
710{ 710{
711 struct nfs4_file *fp = stp->st_file;
712
713 spin_lock(&fp->fi_lock);
711 list_del(&stp->st_perfile); 714 list_del(&stp->st_perfile);
715 spin_unlock(&fp->fi_lock);
712 list_del(&stp->st_perstateowner); 716 list_del(&stp->st_perstateowner);
713} 717}
714 718
@@ -2676,6 +2680,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
2676 lockdep_assert_held(&state_lock); 2680 lockdep_assert_held(&state_lock);
2677 2681
2678 atomic_set(&fp->fi_ref, 1); 2682 atomic_set(&fp->fi_ref, 1);
2683 spin_lock_init(&fp->fi_lock);
2679 INIT_LIST_HEAD(&fp->fi_stateids); 2684 INIT_LIST_HEAD(&fp->fi_stateids);
2680 INIT_LIST_HEAD(&fp->fi_delegations); 2685 INIT_LIST_HEAD(&fp->fi_delegations);
2681 ihold(ino); 2686 ihold(ino);
@@ -2799,7 +2804,6 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
2799 stp->st_stid.sc_type = NFS4_OPEN_STID; 2804 stp->st_stid.sc_type = NFS4_OPEN_STID;
2800 INIT_LIST_HEAD(&stp->st_locks); 2805 INIT_LIST_HEAD(&stp->st_locks);
2801 list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 2806 list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
2802 list_add(&stp->st_perfile, &fp->fi_stateids);
2803 stp->st_stateowner = &oo->oo_owner; 2807 stp->st_stateowner = &oo->oo_owner;
2804 get_nfs4_file(fp); 2808 get_nfs4_file(fp);
2805 stp->st_file = fp; 2809 stp->st_file = fp;
@@ -2808,6 +2812,9 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
2808 set_access(open->op_share_access, stp); 2812 set_access(open->op_share_access, stp);
2809 set_deny(open->op_share_deny, stp); 2813 set_deny(open->op_share_deny, stp);
2810 stp->st_openstp = NULL; 2814 stp->st_openstp = NULL;
2815 spin_lock(&fp->fi_lock);
2816 list_add(&stp->st_perfile, &fp->fi_stateids);
2817 spin_unlock(&fp->fi_lock);
2811} 2818}
2812 2819
2813static void 2820static void
@@ -2915,6 +2922,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
2915 return nfs_ok; 2922 return nfs_ok;
2916 ret = nfserr_locked; 2923 ret = nfserr_locked;
2917 /* Search for conflicting share reservations */ 2924 /* Search for conflicting share reservations */
2925 spin_lock(&fp->fi_lock);
2918 list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { 2926 list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
2919 if (test_deny(deny_type, stp) || 2927 if (test_deny(deny_type, stp) ||
2920 test_deny(NFS4_SHARE_DENY_BOTH, stp)) 2928 test_deny(NFS4_SHARE_DENY_BOTH, stp))
@@ -2922,6 +2930,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
2922 } 2930 }
2923 ret = nfs_ok; 2931 ret = nfs_ok;
2924out: 2932out:
2933 spin_unlock(&fp->fi_lock);
2925 put_nfs4_file(fp); 2934 put_nfs4_file(fp);
2926 return ret; 2935 return ret;
2927} 2936}
@@ -3150,6 +3159,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st
3150 struct nfs4_ol_stateid *local; 3159 struct nfs4_ol_stateid *local;
3151 struct nfs4_openowner *oo = open->op_openowner; 3160 struct nfs4_openowner *oo = open->op_openowner;
3152 3161
3162 spin_lock(&fp->fi_lock);
3153 list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 3163 list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
3154 /* ignore lock owners */ 3164 /* ignore lock owners */
3155 if (local->st_stateowner->so_is_open_owner == 0) 3165 if (local->st_stateowner->so_is_open_owner == 0)
@@ -3158,9 +3168,12 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st
3158 if (local->st_stateowner == &oo->oo_owner) 3168 if (local->st_stateowner == &oo->oo_owner)
3159 *stpp = local; 3169 *stpp = local;
3160 /* check for conflicting share reservations */ 3170 /* check for conflicting share reservations */
3161 if (!test_share(local, open)) 3171 if (!test_share(local, open)) {
3172 spin_unlock(&fp->fi_lock);
3162 return nfserr_share_denied; 3173 return nfserr_share_denied;
3174 }
3163 } 3175 }
3176 spin_unlock(&fp->fi_lock);
3164 return nfs_ok; 3177 return nfs_ok;
3165} 3178}
3166 3179
@@ -4408,7 +4421,6 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
4408 if (stp == NULL) 4421 if (stp == NULL)
4409 return NULL; 4422 return NULL;
4410 stp->st_stid.sc_type = NFS4_LOCK_STID; 4423 stp->st_stid.sc_type = NFS4_LOCK_STID;
4411 list_add(&stp->st_perfile, &fp->fi_stateids);
4412 list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 4424 list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
4413 stp->st_stateowner = &lo->lo_owner; 4425 stp->st_stateowner = &lo->lo_owner;
4414 get_nfs4_file(fp); 4426 get_nfs4_file(fp);
@@ -4417,6 +4429,9 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
4417 stp->st_deny_bmap = open_stp->st_deny_bmap; 4429 stp->st_deny_bmap = open_stp->st_deny_bmap;
4418 stp->st_openstp = open_stp; 4430 stp->st_openstp = open_stp;
4419 list_add(&stp->st_locks, &open_stp->st_locks); 4431 list_add(&stp->st_locks, &open_stp->st_locks);
4432 spin_lock(&fp->fi_lock);
4433 list_add(&stp->st_perfile, &fp->fi_stateids);
4434 spin_unlock(&fp->fi_lock);
4420 return stp; 4435 return stp;
4421} 4436}
4422 4437
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 06d1a908a58e..04737b3ed363 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -377,6 +377,7 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
377/* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */ 377/* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */
378struct nfs4_file { 378struct nfs4_file {
379 atomic_t fi_ref; 379 atomic_t fi_ref;
380 spinlock_t fi_lock;
380 struct hlist_node fi_hash; /* hash by "struct inode *" */ 381 struct hlist_node fi_hash; /* hash by "struct inode *" */
381 struct list_head fi_stateids; 382 struct list_head fi_stateids;
382 struct list_head fi_delegations; 383 struct list_head fi_delegations;