aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-06 15:12:04 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:41 -0400
commit8383e4602c89857ef926f29ca61ac0a83a614443 (patch)
treec60d44dbbfccfa6976d61fb7b10f9f97cc6cda06
parent13437e12fb43cb7e285ff59248f781c91578eafe (diff)
NFSv4: Use RCU to protect delegations
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/delegation.c114
-rw-r--r--fs/nfs/delegation.h14
2 files changed, 73 insertions, 55 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 93a9f4bd9bd0..56f4f6a99d4e 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -27,6 +27,13 @@ static void nfs_free_delegation(struct nfs_delegation *delegation)
27 kfree(delegation); 27 kfree(delegation);
28} 28}
29 29
30static void nfs_free_delegation_callback(struct rcu_head *head)
31{
32 struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu);
33
34 nfs_free_delegation(delegation);
35}
36
30static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) 37static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
31{ 38{
32 struct inode *inode = state->inode; 39 struct inode *inode = state->inode;
@@ -133,10 +140,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
133 delegation->inode = inode; 140 delegation->inode = inode;
134 141
135 spin_lock(&clp->cl_lock); 142 spin_lock(&clp->cl_lock);
136 if (nfsi->delegation == NULL) { 143 if (rcu_dereference(nfsi->delegation) == NULL) {
137 list_add(&delegation->super_list, &clp->cl_delegations); 144 list_add_rcu(&delegation->super_list, &clp->cl_delegations);
138 nfsi->delegation = delegation;
139 nfsi->delegation_state = delegation->type; 145 nfsi->delegation_state = delegation->type;
146 rcu_assign_pointer(nfsi->delegation, delegation);
140 delegation = NULL; 147 delegation = NULL;
141 } else { 148 } else {
142 if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, 149 if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
@@ -157,7 +164,7 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
157 int res = 0; 164 int res = 0;
158 165
159 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); 166 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid);
160 nfs_free_delegation(delegation); 167 call_rcu(&delegation->rcu, nfs_free_delegation_callback);
161 return res; 168 return res;
162} 169}
163 170
@@ -191,16 +198,16 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
191 198
192static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) 199static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
193{ 200{
194 struct nfs_delegation *delegation = nfsi->delegation; 201 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
195 202
196 if (delegation == NULL) 203 if (delegation == NULL)
197 goto nomatch; 204 goto nomatch;
198 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, 205 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
199 sizeof(delegation->stateid.data)) != 0) 206 sizeof(delegation->stateid.data)) != 0)
200 goto nomatch; 207 goto nomatch;
201 list_del_init(&delegation->super_list); 208 list_del_rcu(&delegation->super_list);
202 nfsi->delegation = NULL;
203 nfsi->delegation_state = 0; 209 nfsi->delegation_state = 0;
210 rcu_assign_pointer(nfsi->delegation, NULL);
204 return delegation; 211 return delegation;
205nomatch: 212nomatch:
206 return NULL; 213 return NULL;
@@ -213,7 +220,7 @@ int nfs_inode_return_delegation(struct inode *inode)
213 struct nfs_delegation *delegation; 220 struct nfs_delegation *delegation;
214 int err = 0; 221 int err = 0;
215 222
216 if (nfsi->delegation_state != 0) { 223 if (rcu_dereference(nfsi->delegation) != NULL) {
217 spin_lock(&clp->cl_lock); 224 spin_lock(&clp->cl_lock);
218 delegation = nfs_detach_delegation_locked(nfsi, NULL); 225 delegation = nfs_detach_delegation_locked(nfsi, NULL);
219 spin_unlock(&clp->cl_lock); 226 spin_unlock(&clp->cl_lock);
@@ -235,20 +242,23 @@ void nfs_return_all_delegations(struct super_block *sb)
235 if (clp == NULL) 242 if (clp == NULL)
236 return; 243 return;
237restart: 244restart:
238 spin_lock(&clp->cl_lock); 245 rcu_read_lock();
239 list_for_each_entry(delegation, &clp->cl_delegations, super_list) { 246 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
240 if (delegation->inode->i_sb != sb) 247 if (delegation->inode->i_sb != sb)
241 continue; 248 continue;
242 inode = igrab(delegation->inode); 249 inode = igrab(delegation->inode);
243 if (inode == NULL) 250 if (inode == NULL)
244 continue; 251 continue;
245 nfs_detach_delegation_locked(NFS_I(inode), NULL); 252 spin_lock(&clp->cl_lock);
253 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
246 spin_unlock(&clp->cl_lock); 254 spin_unlock(&clp->cl_lock);
247 __nfs_inode_return_delegation(inode, delegation); 255 rcu_read_unlock();
256 if (delegation != NULL)
257 __nfs_inode_return_delegation(inode, delegation);
248 iput(inode); 258 iput(inode);
249 goto restart; 259 goto restart;
250 } 260 }
251 spin_unlock(&clp->cl_lock); 261 rcu_read_unlock();
252} 262}
253 263
254static int nfs_do_expire_all_delegations(void *ptr) 264static int nfs_do_expire_all_delegations(void *ptr)
@@ -259,23 +269,26 @@ static int nfs_do_expire_all_delegations(void *ptr)
259 269
260 allow_signal(SIGKILL); 270 allow_signal(SIGKILL);
261restart: 271restart:
262 spin_lock(&clp->cl_lock);
263 if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) 272 if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
264 goto out; 273 goto out;
265 if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) 274 if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
266 goto out; 275 goto out;
267 list_for_each_entry(delegation, &clp->cl_delegations, super_list) { 276 rcu_read_lock();
277 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
268 inode = igrab(delegation->inode); 278 inode = igrab(delegation->inode);
269 if (inode == NULL) 279 if (inode == NULL)
270 continue; 280 continue;
271 nfs_detach_delegation_locked(NFS_I(inode), NULL); 281 spin_lock(&clp->cl_lock);
282 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
272 spin_unlock(&clp->cl_lock); 283 spin_unlock(&clp->cl_lock);
273 __nfs_inode_return_delegation(inode, delegation); 284 rcu_read_unlock();
285 if (delegation)
286 __nfs_inode_return_delegation(inode, delegation);
274 iput(inode); 287 iput(inode);
275 goto restart; 288 goto restart;
276 } 289 }
290 rcu_read_unlock();
277out: 291out:
278 spin_unlock(&clp->cl_lock);
279 nfs_put_client(clp); 292 nfs_put_client(clp);
280 module_put_and_exit(0); 293 module_put_and_exit(0);
281} 294}
@@ -306,18 +319,21 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp)
306 if (clp == NULL) 319 if (clp == NULL)
307 return; 320 return;
308restart: 321restart:
309 spin_lock(&clp->cl_lock); 322 rcu_read_lock();
310 list_for_each_entry(delegation, &clp->cl_delegations, super_list) { 323 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
311 inode = igrab(delegation->inode); 324 inode = igrab(delegation->inode);
312 if (inode == NULL) 325 if (inode == NULL)
313 continue; 326 continue;
314 nfs_detach_delegation_locked(NFS_I(inode), NULL); 327 spin_lock(&clp->cl_lock);
328 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
315 spin_unlock(&clp->cl_lock); 329 spin_unlock(&clp->cl_lock);
316 __nfs_inode_return_delegation(inode, delegation); 330 rcu_read_unlock();
331 if (delegation != NULL)
332 __nfs_inode_return_delegation(inode, delegation);
317 iput(inode); 333 iput(inode);
318 goto restart; 334 goto restart;
319 } 335 }
320 spin_unlock(&clp->cl_lock); 336 rcu_read_unlock();
321} 337}
322 338
323struct recall_threadargs { 339struct recall_threadargs {
@@ -391,14 +407,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
391{ 407{
392 struct nfs_delegation *delegation; 408 struct nfs_delegation *delegation;
393 struct inode *res = NULL; 409 struct inode *res = NULL;
394 spin_lock(&clp->cl_lock); 410 rcu_read_lock();
395 list_for_each_entry(delegation, &clp->cl_delegations, super_list) { 411 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
396 if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { 412 if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
397 res = igrab(delegation->inode); 413 res = igrab(delegation->inode);
398 break; 414 break;
399 } 415 }
400 } 416 }
401 spin_unlock(&clp->cl_lock); 417 rcu_read_unlock();
402 return res; 418 return res;
403} 419}
404 420
@@ -408,10 +424,10 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
408void nfs_delegation_mark_reclaim(struct nfs_client *clp) 424void nfs_delegation_mark_reclaim(struct nfs_client *clp)
409{ 425{
410 struct nfs_delegation *delegation; 426 struct nfs_delegation *delegation;
411 spin_lock(&clp->cl_lock); 427 rcu_read_lock();
412 list_for_each_entry(delegation, &clp->cl_delegations, super_list) 428 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list)
413 delegation->flags |= NFS_DELEGATION_NEED_RECLAIM; 429 delegation->flags |= NFS_DELEGATION_NEED_RECLAIM;
414 spin_unlock(&clp->cl_lock); 430 rcu_read_unlock();
415} 431}
416 432
417/* 433/*
@@ -419,39 +435,35 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp)
419 */ 435 */
420void nfs_delegation_reap_unclaimed(struct nfs_client *clp) 436void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
421{ 437{
422 struct nfs_delegation *delegation, *n; 438 struct nfs_delegation *delegation;
423 LIST_HEAD(head); 439restart:
424 spin_lock(&clp->cl_lock); 440 rcu_read_lock();
425 list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) { 441 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
426 if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) 442 if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0)
427 continue; 443 continue;
428 list_move(&delegation->super_list, &head); 444 spin_lock(&clp->cl_lock);
429 NFS_I(delegation->inode)->delegation = NULL; 445 delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL);
430 NFS_I(delegation->inode)->delegation_state = 0; 446 spin_unlock(&clp->cl_lock);
431 } 447 rcu_read_unlock();
432 spin_unlock(&clp->cl_lock); 448 if (delegation != NULL)
433 while(!list_empty(&head)) { 449 call_rcu(&delegation->rcu, nfs_free_delegation_callback);
434 delegation = list_entry(head.next, struct nfs_delegation, super_list); 450 goto restart;
435 list_del(&delegation->super_list);
436 nfs_free_delegation(delegation);
437 } 451 }
452 rcu_read_unlock();
438} 453}
439 454
440int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) 455int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
441{ 456{
442 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
443 struct nfs_inode *nfsi = NFS_I(inode); 457 struct nfs_inode *nfsi = NFS_I(inode);
444 struct nfs_delegation *delegation; 458 struct nfs_delegation *delegation;
445 int res = 0; 459 int ret = 0;
446 460
447 if (nfsi->delegation_state == 0) 461 rcu_read_lock();
448 return 0; 462 delegation = rcu_dereference(nfsi->delegation);
449 spin_lock(&clp->cl_lock);
450 delegation = nfsi->delegation;
451 if (delegation != NULL) { 463 if (delegation != NULL) {
452 memcpy(dst->data, delegation->stateid.data, sizeof(dst->data)); 464 memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
453 res = 1; 465 ret = 1;
454 } 466 }
455 spin_unlock(&clp->cl_lock); 467 rcu_read_unlock();
456 return res; 468 return ret;
457} 469}
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 8f79a3135167..5874ce7fdbae 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -22,6 +22,7 @@ struct nfs_delegation {
22 long flags; 22 long flags;
23 loff_t maxsize; 23 loff_t maxsize;
24 __u64 change_attr; 24 __u64 change_attr;
25 struct rcu_head rcu;
25}; 26};
26 27
27int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 28int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
@@ -45,11 +46,16 @@ int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
45 46
46static inline int nfs_have_delegation(struct inode *inode, int flags) 47static inline int nfs_have_delegation(struct inode *inode, int flags)
47{ 48{
49 struct nfs_delegation *delegation;
50 int ret = 0;
51
48 flags &= FMODE_READ|FMODE_WRITE; 52 flags &= FMODE_READ|FMODE_WRITE;
49 smp_rmb(); 53 rcu_read_lock();
50 if ((NFS_I(inode)->delegation_state & flags) == flags) 54 delegation = rcu_dereference(NFS_I(inode)->delegation);
51 return 1; 55 if (delegation != NULL && (delegation->type & flags) == flags)
52 return 0; 56 ret = 1;
57 rcu_read_unlock();
58 return ret;
53} 59}
54 60
55#else 61#else