diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-07-10 14:07:25 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-07-10 15:05:25 -0400 |
commit | 1d31a2531ae91f8a89c0fffa883ef922c0dbb74d (patch) | |
tree | 8c68acb7b5472803ccd8cbf1ffab9b467a377904 | |
parent | d6c249b4d4cfef894cbda224a7a063d17aacb60a (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.c | 21 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 |
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 | ||
709 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | 709 | static 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 | ||
2813 | static void | 2820 | static 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; |
2924 | out: | 2932 | out: |
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. */ |
378 | struct nfs4_file { | 378 | struct 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; |