aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/delegation.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/delegation.c')
-rw-r--r--fs/nfs/delegation.c260
1 files changed, 132 insertions, 128 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index cc563cfa6940..968225a88015 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -43,6 +43,27 @@ static void nfs_free_delegation(struct nfs_delegation *delegation)
43 put_rpccred(cred); 43 put_rpccred(cred);
44} 44}
45 45
46void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
47{
48 set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
49}
50
51int nfs_have_delegation(struct inode *inode, fmode_t flags)
52{
53 struct nfs_delegation *delegation;
54 int ret = 0;
55
56 flags &= FMODE_READ|FMODE_WRITE;
57 rcu_read_lock();
58 delegation = rcu_dereference(NFS_I(inode)->delegation);
59 if (delegation != NULL && (delegation->type & flags) == flags) {
60 nfs_mark_delegation_referenced(delegation);
61 ret = 1;
62 }
63 rcu_read_unlock();
64 return ret;
65}
66
46static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) 67static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
47{ 68{
48 struct inode *inode = state->inode; 69 struct inode *inode = state->inode;
@@ -119,7 +140,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
119 delegation->maxsize = res->maxsize; 140 delegation->maxsize = res->maxsize;
120 oldcred = delegation->cred; 141 oldcred = delegation->cred;
121 delegation->cred = get_rpccred(cred); 142 delegation->cred = get_rpccred(cred);
122 delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM; 143 clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
123 NFS_I(inode)->delegation_state = delegation->type; 144 NFS_I(inode)->delegation_state = delegation->type;
124 smp_wmb(); 145 smp_wmb();
125 put_rpccred(oldcred); 146 put_rpccred(oldcred);
@@ -134,19 +155,35 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
134 return res; 155 return res;
135} 156}
136 157
158static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
159{
160 struct inode *inode = NULL;
161
162 spin_lock(&delegation->lock);
163 if (delegation->inode != NULL)
164 inode = igrab(delegation->inode);
165 spin_unlock(&delegation->lock);
166 return inode;
167}
168
137static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) 169static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
138{ 170{
139 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); 171 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
140 172
141 if (delegation == NULL) 173 if (delegation == NULL)
142 goto nomatch; 174 goto nomatch;
175 spin_lock(&delegation->lock);
143 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, 176 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
144 sizeof(delegation->stateid.data)) != 0) 177 sizeof(delegation->stateid.data)) != 0)
145 goto nomatch; 178 goto nomatch_unlock;
146 list_del_rcu(&delegation->super_list); 179 list_del_rcu(&delegation->super_list);
180 delegation->inode = NULL;
147 nfsi->delegation_state = 0; 181 nfsi->delegation_state = 0;
148 rcu_assign_pointer(nfsi->delegation, NULL); 182 rcu_assign_pointer(nfsi->delegation, NULL);
183 spin_unlock(&delegation->lock);
149 return delegation; 184 return delegation;
185nomatch_unlock:
186 spin_unlock(&delegation->lock);
150nomatch: 187nomatch:
151 return NULL; 188 return NULL;
152} 189}
@@ -172,6 +209,8 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
172 delegation->change_attr = nfsi->change_attr; 209 delegation->change_attr = nfsi->change_attr;
173 delegation->cred = get_rpccred(cred); 210 delegation->cred = get_rpccred(cred);
174 delegation->inode = inode; 211 delegation->inode = inode;
212 delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
213 spin_lock_init(&delegation->lock);
175 214
176 spin_lock(&clp->cl_lock); 215 spin_lock(&clp->cl_lock);
177 if (rcu_dereference(nfsi->delegation) != NULL) { 216 if (rcu_dereference(nfsi->delegation) != NULL) {
@@ -226,22 +265,47 @@ static void nfs_msync_inode(struct inode *inode)
226 */ 265 */
227static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) 266static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
228{ 267{
229 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
230 struct nfs_inode *nfsi = NFS_I(inode); 268 struct nfs_inode *nfsi = NFS_I(inode);
231 269
232 nfs_msync_inode(inode); 270 nfs_msync_inode(inode);
233 down_read(&clp->cl_sem);
234 /* Guard against new delegated open calls */ 271 /* Guard against new delegated open calls */
235 down_write(&nfsi->rwsem); 272 down_write(&nfsi->rwsem);
236 nfs_delegation_claim_opens(inode, &delegation->stateid); 273 nfs_delegation_claim_opens(inode, &delegation->stateid);
237 up_write(&nfsi->rwsem); 274 up_write(&nfsi->rwsem);
238 up_read(&clp->cl_sem);
239 nfs_msync_inode(inode); 275 nfs_msync_inode(inode);
240 276
241 return nfs_do_return_delegation(inode, delegation, 1); 277 return nfs_do_return_delegation(inode, delegation, 1);
242} 278}
243 279
244/* 280/*
281 * Return all delegations that have been marked for return
282 */
283void nfs_client_return_marked_delegations(struct nfs_client *clp)
284{
285 struct nfs_delegation *delegation;
286 struct inode *inode;
287
288restart:
289 rcu_read_lock();
290 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
291 if (!test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
292 continue;
293 inode = nfs_delegation_grab_inode(delegation);
294 if (inode == NULL)
295 continue;
296 spin_lock(&clp->cl_lock);
297 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
298 spin_unlock(&clp->cl_lock);
299 rcu_read_unlock();
300 if (delegation != NULL)
301 __nfs_inode_return_delegation(inode, delegation);
302 iput(inode);
303 goto restart;
304 }
305 rcu_read_unlock();
306}
307
308/*
245 * This function returns the delegation without reclaiming opens 309 * This function returns the delegation without reclaiming opens
246 * or protecting against delegation reclaims. 310 * or protecting against delegation reclaims.
247 * It is therefore really only safe to be called from 311 * It is therefore really only safe to be called from
@@ -279,83 +343,55 @@ int nfs_inode_return_delegation(struct inode *inode)
279 return err; 343 return err;
280} 344}
281 345
346static void nfs_mark_return_delegation(struct nfs_client *clp, struct nfs_delegation *delegation)
347{
348 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
349 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
350}
351
282/* 352/*
283 * Return all delegations associated to a super block 353 * Return all delegations associated to a super block
284 */ 354 */
285void nfs_return_all_delegations(struct super_block *sb) 355void nfs_super_return_all_delegations(struct super_block *sb)
286{ 356{
287 struct nfs_client *clp = NFS_SB(sb)->nfs_client; 357 struct nfs_client *clp = NFS_SB(sb)->nfs_client;
288 struct nfs_delegation *delegation; 358 struct nfs_delegation *delegation;
289 struct inode *inode;
290 359
291 if (clp == NULL) 360 if (clp == NULL)
292 return; 361 return;
293restart:
294 rcu_read_lock(); 362 rcu_read_lock();
295 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { 363 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
296 if (delegation->inode->i_sb != sb) 364 spin_lock(&delegation->lock);
297 continue; 365 if (delegation->inode != NULL && delegation->inode->i_sb == sb)
298 inode = igrab(delegation->inode); 366 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
299 if (inode == NULL) 367 spin_unlock(&delegation->lock);
300 continue;
301 spin_lock(&clp->cl_lock);
302 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
303 spin_unlock(&clp->cl_lock);
304 rcu_read_unlock();
305 if (delegation != NULL)
306 __nfs_inode_return_delegation(inode, delegation);
307 iput(inode);
308 goto restart;
309 } 368 }
310 rcu_read_unlock(); 369 rcu_read_unlock();
370 nfs_client_return_marked_delegations(clp);
311} 371}
312 372
313static int nfs_do_expire_all_delegations(void *ptr) 373static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
314{ 374{
315 struct nfs_client *clp = ptr;
316 struct nfs_delegation *delegation; 375 struct nfs_delegation *delegation;
317 struct inode *inode;
318 376
319 allow_signal(SIGKILL);
320restart:
321 if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
322 goto out;
323 if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
324 goto out;
325 rcu_read_lock(); 377 rcu_read_lock();
326 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { 378 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
327 inode = igrab(delegation->inode); 379 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
328 if (inode == NULL) 380 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
329 continue;
330 spin_lock(&clp->cl_lock);
331 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
332 spin_unlock(&clp->cl_lock);
333 rcu_read_unlock();
334 if (delegation)
335 __nfs_inode_return_delegation(inode, delegation);
336 iput(inode);
337 goto restart;
338 } 381 }
339 rcu_read_unlock(); 382 rcu_read_unlock();
340out: 383}
341 nfs_put_client(clp); 384
342 module_put_and_exit(0); 385static void nfs_delegation_run_state_manager(struct nfs_client *clp)
386{
387 if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
388 nfs4_schedule_state_manager(clp);
343} 389}
344 390
345void nfs_expire_all_delegations(struct nfs_client *clp) 391void nfs_expire_all_delegations(struct nfs_client *clp)
346{ 392{
347 struct task_struct *task; 393 nfs_client_mark_return_all_delegations(clp);
348 394 nfs_delegation_run_state_manager(clp);
349 __module_get(THIS_MODULE);
350 atomic_inc(&clp->cl_count);
351 task = kthread_run(nfs_do_expire_all_delegations, clp,
352 "%s-delegreturn",
353 rpc_peeraddr2str(clp->cl_rpcclient,
354 RPC_DISPLAY_ADDR));
355 if (!IS_ERR(task))
356 return;
357 nfs_put_client(clp);
358 module_put(THIS_MODULE);
359} 395}
360 396
361/* 397/*
@@ -363,68 +399,29 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
363 */ 399 */
364void nfs_handle_cb_pathdown(struct nfs_client *clp) 400void nfs_handle_cb_pathdown(struct nfs_client *clp)
365{ 401{
366 struct nfs_delegation *delegation;
367 struct inode *inode;
368
369 if (clp == NULL) 402 if (clp == NULL)
370 return; 403 return;
371restart: 404 nfs_client_mark_return_all_delegations(clp);
405}
406
407static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *clp)
408{
409 struct nfs_delegation *delegation;
410
372 rcu_read_lock(); 411 rcu_read_lock();
373 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { 412 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
374 inode = igrab(delegation->inode); 413 if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
375 if (inode == NULL)
376 continue; 414 continue;
377 spin_lock(&clp->cl_lock); 415 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
378 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); 416 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
379 spin_unlock(&clp->cl_lock);
380 rcu_read_unlock();
381 if (delegation != NULL)
382 __nfs_inode_return_delegation(inode, delegation);
383 iput(inode);
384 goto restart;
385 } 417 }
386 rcu_read_unlock(); 418 rcu_read_unlock();
387} 419}
388 420
389struct recall_threadargs { 421void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
390 struct inode *inode;
391 struct nfs_client *clp;
392 const nfs4_stateid *stateid;
393
394 struct completion started;
395 int result;
396};
397
398static int recall_thread(void *data)
399{ 422{
400 struct recall_threadargs *args = (struct recall_threadargs *)data; 423 nfs_client_mark_return_unreferenced_delegations(clp);
401 struct inode *inode = igrab(args->inode); 424 nfs_delegation_run_state_manager(clp);
402 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
403 struct nfs_inode *nfsi = NFS_I(inode);
404 struct nfs_delegation *delegation;
405
406 daemonize("nfsv4-delegreturn");
407
408 nfs_msync_inode(inode);
409 down_read(&clp->cl_sem);
410 down_write(&nfsi->rwsem);
411 spin_lock(&clp->cl_lock);
412 delegation = nfs_detach_delegation_locked(nfsi, args->stateid);
413 if (delegation != NULL)
414 args->result = 0;
415 else
416 args->result = -ENOENT;
417 spin_unlock(&clp->cl_lock);
418 complete(&args->started);
419 nfs_delegation_claim_opens(inode, args->stateid);
420 up_write(&nfsi->rwsem);
421 up_read(&clp->cl_sem);
422 nfs_msync_inode(inode);
423
424 if (delegation != NULL)
425 nfs_do_return_delegation(inode, delegation, 1);
426 iput(inode);
427 module_put_and_exit(0);
428} 425}
429 426
430/* 427/*
@@ -432,22 +429,20 @@ static int recall_thread(void *data)
432 */ 429 */
433int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) 430int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
434{ 431{
435 struct recall_threadargs data = { 432 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
436 .inode = inode, 433 struct nfs_delegation *delegation;
437 .stateid = stateid,
438 };
439 int status;
440 434
441 init_completion(&data.started); 435 rcu_read_lock();
442 __module_get(THIS_MODULE); 436 delegation = rcu_dereference(NFS_I(inode)->delegation);
443 status = kernel_thread(recall_thread, &data, CLONE_KERNEL); 437 if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
444 if (status < 0) 438 sizeof(delegation->stateid.data)) != 0) {
445 goto out_module_put; 439 rcu_read_unlock();
446 wait_for_completion(&data.started); 440 return -ENOENT;
447 return data.result; 441 }
448out_module_put: 442 nfs_mark_return_delegation(clp, delegation);
449 module_put(THIS_MODULE); 443 rcu_read_unlock();
450 return status; 444 nfs_delegation_run_state_manager(clp);
445 return 0;
451} 446}
452 447
453/* 448/*
@@ -459,10 +454,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
459 struct inode *res = NULL; 454 struct inode *res = NULL;
460 rcu_read_lock(); 455 rcu_read_lock();
461 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { 456 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
462 if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { 457 spin_lock(&delegation->lock);
458 if (delegation->inode != NULL &&
459 nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
463 res = igrab(delegation->inode); 460 res = igrab(delegation->inode);
464 break;
465 } 461 }
462 spin_unlock(&delegation->lock);
463 if (res != NULL)
464 break;
466 } 465 }
467 rcu_read_unlock(); 466 rcu_read_unlock();
468 return res; 467 return res;
@@ -476,7 +475,7 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp)
476 struct nfs_delegation *delegation; 475 struct nfs_delegation *delegation;
477 rcu_read_lock(); 476 rcu_read_lock();
478 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) 477 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list)
479 delegation->flags |= NFS_DELEGATION_NEED_RECLAIM; 478 set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
480 rcu_read_unlock(); 479 rcu_read_unlock();
481} 480}
482 481
@@ -486,17 +485,22 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp)
486void nfs_delegation_reap_unclaimed(struct nfs_client *clp) 485void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
487{ 486{
488 struct nfs_delegation *delegation; 487 struct nfs_delegation *delegation;
488 struct inode *inode;
489restart: 489restart:
490 rcu_read_lock(); 490 rcu_read_lock();
491 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { 491 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
492 if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) 492 if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0)
493 continue;
494 inode = nfs_delegation_grab_inode(delegation);
495 if (inode == NULL)
493 continue; 496 continue;
494 spin_lock(&clp->cl_lock); 497 spin_lock(&clp->cl_lock);
495 delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL); 498 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
496 spin_unlock(&clp->cl_lock); 499 spin_unlock(&clp->cl_lock);
497 rcu_read_unlock(); 500 rcu_read_unlock();
498 if (delegation != NULL) 501 if (delegation != NULL)
499 nfs_free_delegation(delegation); 502 nfs_free_delegation(delegation);
503 iput(inode);
500 goto restart; 504 goto restart;
501 } 505 }
502 rcu_read_unlock(); 506 rcu_read_unlock();