aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:52 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:52 -0500
commitb7391f44f26b17ad25c7183a3d6ad50f0a9305ff (patch)
tree8e09a5714587a8bde2a805819501d10bae4787b7
parent6411bd4a471893ab2af103d96253ba97c92d4777 (diff)
NFSv4: Return unreferenced delegations more promptly
If the client is not using a delegation, the right thing to do is to return it as soon as possible. This helps reduce the amount of state the server has to track, as well as reducing the potential for conflicts with other clients. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/delegation.c42
-rw-r--r--fs/nfs/delegation.h17
-rw-r--r--fs/nfs/nfs4proc.c2
-rw-r--r--fs/nfs/nfs4renewd.c1
4 files changed, 49 insertions, 13 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 00c350c031b4..e75f2f8c5245 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, int 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;
@@ -188,6 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
188 delegation->change_attr = nfsi->change_attr; 209 delegation->change_attr = nfsi->change_attr;
189 delegation->cred = get_rpccred(cred); 210 delegation->cred = get_rpccred(cred);
190 delegation->inode = inode; 211 delegation->inode = inode;
212 delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
191 spin_lock_init(&delegation->lock); 213 spin_lock_init(&delegation->lock);
192 214
193 spin_lock(&clp->cl_lock); 215 spin_lock(&clp->cl_lock);
@@ -382,6 +404,26 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp)
382 nfs_client_mark_return_all_delegations(clp); 404 nfs_client_mark_return_all_delegations(clp);
383} 405}
384 406
407static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *clp)
408{
409 struct nfs_delegation *delegation;
410
411 rcu_read_lock();
412 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
413 if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
414 continue;
415 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
416 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
417 }
418 rcu_read_unlock();
419}
420
421void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
422{
423 nfs_client_mark_return_unreferenced_delegations(clp);
424 nfs_delegation_run_state_manager(clp);
425}
426
385/* 427/*
386 * Asynchronous delegation recall! 428 * Asynchronous delegation recall!
387 */ 429 */
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 56f3eb558ef4..2a74882e5d50 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -28,6 +28,7 @@ struct nfs_delegation {
28enum { 28enum {
29 NFS_DELEGATION_NEED_RECLAIM = 0, 29 NFS_DELEGATION_NEED_RECLAIM = 0,
30 NFS_DELEGATION_RETURN, 30 NFS_DELEGATION_RETURN,
31 NFS_DELEGATION_REFERENCED,
31}; 32};
32 33
33int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 34int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
@@ -39,6 +40,7 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode);
39struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); 40struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
40void nfs_super_return_all_delegations(struct super_block *sb); 41void nfs_super_return_all_delegations(struct super_block *sb);
41void nfs_expire_all_delegations(struct nfs_client *clp); 42void nfs_expire_all_delegations(struct nfs_client *clp);
43void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
42void nfs_handle_cb_pathdown(struct nfs_client *clp); 44void nfs_handle_cb_pathdown(struct nfs_client *clp);
43void nfs_client_return_marked_delegations(struct nfs_client *clp); 45void nfs_client_return_marked_delegations(struct nfs_client *clp);
44 46
@@ -51,19 +53,8 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
51int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); 53int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
52int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); 54int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
53 55
54static inline int nfs_have_delegation(struct inode *inode, int flags) 56void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
55{ 57int nfs_have_delegation(struct inode *inode, int flags);
56 struct nfs_delegation *delegation;
57 int ret = 0;
58
59 flags &= FMODE_READ|FMODE_WRITE;
60 rcu_read_lock();
61 delegation = rcu_dereference(NFS_I(inode)->delegation);
62 if (delegation != NULL && (delegation->type & flags) == flags)
63 ret = 1;
64 rcu_read_unlock();
65 return ret;
66}
67 58
68#else 59#else
69static inline int nfs_have_delegation(struct inode *inode, int flags) 60static inline int nfs_have_delegation(struct inode *inode, int flags)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 2a347d47e38c..fc0c9d255cf7 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -421,6 +421,7 @@ static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_fla
421 return 0; 421 return 0;
422 if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) 422 if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
423 return 0; 423 return 0;
424 nfs_mark_delegation_referenced(delegation);
424 return 1; 425 return 1;
425} 426}
426 427
@@ -505,6 +506,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat
505 else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0) 506 else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0)
506 goto no_delegation_unlock; 507 goto no_delegation_unlock;
507 508
509 nfs_mark_delegation_referenced(deleg_cur);
508 __update_open_stateid(state, open_stateid, &deleg_cur->stateid, open_flags); 510 __update_open_stateid(state, open_stateid, &deleg_cur->stateid, open_flags);
509 ret = 1; 511 ret = 1;
510no_delegation_unlock: 512no_delegation_unlock:
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index ca557e677d9e..f524e932ff7b 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -101,6 +101,7 @@ nfs4_renew_state(struct work_struct *work)
101 cancel_delayed_work(&clp->cl_renewd); 101 cancel_delayed_work(&clp->cl_renewd);
102 schedule_delayed_work(&clp->cl_renewd, timeout); 102 schedule_delayed_work(&clp->cl_renewd, timeout);
103 spin_unlock(&clp->cl_lock); 103 spin_unlock(&clp->cl_lock);
104 nfs_expire_unreferenced_delegations(clp);
104out: 105out:
105 dprintk("%s: done\n", __func__); 106 dprintk("%s: done\n", __func__);
106} 107}