aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-07-29 21:34:34 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-07-31 14:20:24 -0400
commit7ffb588086e941aa0a46a33e2bf2bf3c0963ed98 (patch)
treeea15185306219711d7e5d7b7546ac1d03bb61a1f /fs/nfsd/nfs4state.c
parentb401be22b5cf059290ee98106bc780e087407d45 (diff)
nfsd: Protect adding/removing open state owners using client_lock
Once we remove client mutex protection, we'll need to ensure that stateowner lookup and creation are atomic between concurrent compounds. Ensure that alloc_init_open_stateowner checks the hashtable under the client_lock before adding a new element. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c118
1 files changed, 80 insertions, 38 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6d26d26751f5..c4bb7f2b29d9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -239,6 +239,53 @@ static void nfsd4_put_session(struct nfsd4_session *ses)
239 spin_unlock(&nn->client_lock); 239 spin_unlock(&nn->client_lock);
240} 240}
241 241
242static int
243same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
244 clientid_t *clid)
245{
246 return (sop->so_owner.len == owner->len) &&
247 0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
248 (sop->so_client->cl_clientid.cl_id == clid->cl_id);
249}
250
251static struct nfs4_openowner *
252find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
253 bool sessions, struct nfsd_net *nn)
254{
255 struct nfs4_stateowner *so;
256 struct nfs4_openowner *oo;
257 struct nfs4_client *clp;
258
259 lockdep_assert_held(&nn->client_lock);
260
261 list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) {
262 if (!so->so_is_open_owner)
263 continue;
264 if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
265 oo = openowner(so);
266 clp = oo->oo_owner.so_client;
267 if ((bool)clp->cl_minorversion != sessions)
268 break;
269 renew_client_locked(clp);
270 atomic_inc(&so->so_count);
271 return oo;
272 }
273 }
274 return NULL;
275}
276
277static struct nfs4_openowner *
278find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
279 bool sessions, struct nfsd_net *nn)
280{
281 struct nfs4_openowner *oo;
282
283 spin_lock(&nn->client_lock);
284 oo = find_openstateowner_str_locked(hashval, open, sessions, nn);
285 spin_unlock(&nn->client_lock);
286 return oo;
287}
288
242 289
243static inline u32 290static inline u32
244opaque_hashval(const void *ptr, int nbytes) 291opaque_hashval(const void *ptr, int nbytes)
@@ -1005,8 +1052,13 @@ static void release_open_stateid(struct nfs4_ol_stateid *stp)
1005 nfs4_put_stid(&stp->st_stid); 1052 nfs4_put_stid(&stp->st_stid);
1006} 1053}
1007 1054
1008static void unhash_openowner(struct nfs4_openowner *oo) 1055static void unhash_openowner_locked(struct nfs4_openowner *oo)
1009{ 1056{
1057 struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1058 nfsd_net_id);
1059
1060 lockdep_assert_held(&nn->client_lock);
1061
1010 list_del_init(&oo->oo_owner.so_strhash); 1062 list_del_init(&oo->oo_owner.so_strhash);
1011 list_del_init(&oo->oo_perclient); 1063 list_del_init(&oo->oo_perclient);
1012} 1064}
@@ -1025,18 +1077,29 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
1025static void release_openowner_stateids(struct nfs4_openowner *oo) 1077static void release_openowner_stateids(struct nfs4_openowner *oo)
1026{ 1078{
1027 struct nfs4_ol_stateid *stp; 1079 struct nfs4_ol_stateid *stp;
1080 struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1081 nfsd_net_id);
1082
1083 lockdep_assert_held(&nn->client_lock);
1028 1084
1029 while (!list_empty(&oo->oo_owner.so_stateids)) { 1085 while (!list_empty(&oo->oo_owner.so_stateids)) {
1030 stp = list_first_entry(&oo->oo_owner.so_stateids, 1086 stp = list_first_entry(&oo->oo_owner.so_stateids,
1031 struct nfs4_ol_stateid, st_perstateowner); 1087 struct nfs4_ol_stateid, st_perstateowner);
1088 spin_unlock(&nn->client_lock);
1032 release_open_stateid(stp); 1089 release_open_stateid(stp);
1090 spin_lock(&nn->client_lock);
1033 } 1091 }
1034} 1092}
1035 1093
1036static void release_openowner(struct nfs4_openowner *oo) 1094static void release_openowner(struct nfs4_openowner *oo)
1037{ 1095{
1038 unhash_openowner(oo); 1096 struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1097 nfsd_net_id);
1098
1099 spin_lock(&nn->client_lock);
1100 unhash_openowner_locked(oo);
1039 release_openowner_stateids(oo); 1101 release_openowner_stateids(oo);
1102 spin_unlock(&nn->client_lock);
1040 release_last_closed_stateid(oo); 1103 release_last_closed_stateid(oo);
1041 nfs4_put_stateowner(&oo->oo_owner); 1104 nfs4_put_stateowner(&oo->oo_owner);
1042} 1105}
@@ -3004,8 +3067,11 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
3004static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 3067static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
3005{ 3068{
3006 struct nfs4_openowner *oo = openowner(so); 3069 struct nfs4_openowner *oo = openowner(so);
3070 struct nfsd_net *nn = net_generic(so->so_client->net, nfsd_net_id);
3007 3071
3008 unhash_openowner(oo); 3072 spin_lock(&nn->client_lock);
3073 unhash_openowner_locked(oo);
3074 spin_unlock(&nn->client_lock);
3009} 3075}
3010 3076
3011static void nfs4_free_openowner(struct nfs4_stateowner *so) 3077static void nfs4_free_openowner(struct nfs4_stateowner *so)
@@ -3025,7 +3091,8 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3025 struct nfsd4_compound_state *cstate) 3091 struct nfsd4_compound_state *cstate)
3026{ 3092{
3027 struct nfs4_client *clp = cstate->clp; 3093 struct nfs4_client *clp = cstate->clp;
3028 struct nfs4_openowner *oo; 3094 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
3095 struct nfs4_openowner *oo, *ret;
3029 3096
3030 oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 3097 oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
3031 if (!oo) 3098 if (!oo)
@@ -3039,7 +3106,15 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3039 oo->oo_time = 0; 3106 oo->oo_time = 0;
3040 oo->oo_last_closed_stid = NULL; 3107 oo->oo_last_closed_stid = NULL;
3041 INIT_LIST_HEAD(&oo->oo_close_lru); 3108 INIT_LIST_HEAD(&oo->oo_close_lru);
3042 hash_openowner(oo, clp, strhashval); 3109 spin_lock(&nn->client_lock);
3110 ret = find_openstateowner_str_locked(strhashval,
3111 open, clp->cl_minorversion, nn);
3112 if (ret == NULL) {
3113 hash_openowner(oo, clp, strhashval);
3114 ret = oo;
3115 } else
3116 nfs4_free_openowner(&oo->oo_owner);
3117 spin_unlock(&nn->client_lock);
3043 return oo; 3118 return oo;
3044} 3119}
3045 3120
@@ -3100,39 +3175,6 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
3100 oo->oo_time = get_seconds(); 3175 oo->oo_time = get_seconds();
3101} 3176}
3102 3177
3103static int
3104same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
3105 clientid_t *clid)
3106{
3107 return (sop->so_owner.len == owner->len) &&
3108 0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
3109 (sop->so_client->cl_clientid.cl_id == clid->cl_id);
3110}
3111
3112static struct nfs4_openowner *
3113find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
3114 bool sessions, struct nfsd_net *nn)
3115{
3116 struct nfs4_stateowner *so;
3117 struct nfs4_openowner *oo;
3118 struct nfs4_client *clp;
3119
3120 list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) {
3121 if (!so->so_is_open_owner)
3122 continue;
3123 if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
3124 oo = openowner(so);
3125 clp = oo->oo_owner.so_client;
3126 if ((bool)clp->cl_minorversion != sessions)
3127 return NULL;
3128 renew_client(oo->oo_owner.so_client);
3129 atomic_inc(&oo->oo_owner.so_count);
3130 return oo;
3131 }
3132 }
3133 return NULL;
3134}
3135
3136/* search file_hashtbl[] for file */ 3178/* search file_hashtbl[] for file */
3137static struct nfs4_file * 3179static struct nfs4_file *
3138find_file_locked(struct knfsd_fh *fh) 3180find_file_locked(struct knfsd_fh *fh)