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.c73
1 files changed, 19 insertions, 54 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 21eda6c083d0..00c350c031b4 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -321,6 +321,12 @@ int nfs_inode_return_delegation(struct inode *inode)
321 return err; 321 return err;
322} 322}
323 323
324static void nfs_mark_return_delegation(struct nfs_client *clp, struct nfs_delegation *delegation)
325{
326 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
327 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
328}
329
324/* 330/*
325 * Return all delegations associated to a super block 331 * Return all delegations associated to a super block
326 */ 332 */
@@ -376,66 +382,25 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp)
376 nfs_client_mark_return_all_delegations(clp); 382 nfs_client_mark_return_all_delegations(clp);
377} 383}
378 384
379struct recall_threadargs {
380 struct inode *inode;
381 struct nfs_client *clp;
382 const nfs4_stateid *stateid;
383
384 struct completion started;
385 int result;
386};
387
388static int recall_thread(void *data)
389{
390 struct recall_threadargs *args = (struct recall_threadargs *)data;
391 struct inode *inode = igrab(args->inode);
392 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
393 struct nfs_inode *nfsi = NFS_I(inode);
394 struct nfs_delegation *delegation;
395
396 daemonize("nfsv4-delegreturn");
397
398 nfs_msync_inode(inode);
399 down_write(&nfsi->rwsem);
400 spin_lock(&clp->cl_lock);
401 delegation = nfs_detach_delegation_locked(nfsi, args->stateid);
402 if (delegation != NULL)
403 args->result = 0;
404 else
405 args->result = -ENOENT;
406 spin_unlock(&clp->cl_lock);
407 complete(&args->started);
408 nfs_delegation_claim_opens(inode, args->stateid);
409 up_write(&nfsi->rwsem);
410 nfs_msync_inode(inode);
411
412 if (delegation != NULL)
413 nfs_do_return_delegation(inode, delegation, 1);
414 iput(inode);
415 module_put_and_exit(0);
416}
417
418/* 385/*
419 * Asynchronous delegation recall! 386 * Asynchronous delegation recall!
420 */ 387 */
421int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) 388int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
422{ 389{
423 struct recall_threadargs data = { 390 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
424 .inode = inode, 391 struct nfs_delegation *delegation;
425 .stateid = stateid,
426 };
427 int status;
428 392
429 init_completion(&data.started); 393 rcu_read_lock();
430 __module_get(THIS_MODULE); 394 delegation = rcu_dereference(NFS_I(inode)->delegation);
431 status = kernel_thread(recall_thread, &data, CLONE_KERNEL); 395 if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
432 if (status < 0) 396 sizeof(delegation->stateid.data)) != 0) {
433 goto out_module_put; 397 rcu_read_unlock();
434 wait_for_completion(&data.started); 398 return -ENOENT;
435 return data.result; 399 }
436out_module_put: 400 nfs_mark_return_delegation(clp, delegation);
437 module_put(THIS_MODULE); 401 rcu_read_unlock();
438 return status; 402 nfs_delegation_run_state_manager(clp);
403 return 0;
439} 404}
440 405
441/* 406/*