]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
NFSv4: Return unreferenced delegations more promptly
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 23 Dec 2008 20:21:52 +0000 (15:21 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 23 Dec 2008 20:21:52 +0000 (15:21 -0500)
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>
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4renewd.c

index 00c350c031b40832d54864b3b5f7dcc8bb40a6b3..e75f2f8c5245a64a86f14aed22354f2da8c0004b 100644 (file)
@@ -43,6 +43,27 @@ static void nfs_free_delegation(struct nfs_delegation *delegation)
                put_rpccred(cred);
 }
 
+void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
+{
+       set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
+}
+
+int nfs_have_delegation(struct inode *inode, int flags)
+{
+       struct nfs_delegation *delegation;
+       int ret = 0;
+
+       flags &= FMODE_READ|FMODE_WRITE;
+       rcu_read_lock();
+       delegation = rcu_dereference(NFS_I(inode)->delegation);
+       if (delegation != NULL && (delegation->type & flags) == flags) {
+               nfs_mark_delegation_referenced(delegation);
+               ret = 1;
+       }
+       rcu_read_unlock();
+       return ret;
+}
+
 static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
        struct inode *inode = state->inode;
@@ -188,6 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        delegation->change_attr = nfsi->change_attr;
        delegation->cred = get_rpccred(cred);
        delegation->inode = inode;
+       delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
        spin_lock_init(&delegation->lock);
 
        spin_lock(&clp->cl_lock);
@@ -382,6 +404,26 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp)
        nfs_client_mark_return_all_delegations(clp);
 }
 
+static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *clp)
+{
+       struct nfs_delegation *delegation;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
+               if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
+                       continue;
+               set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
+               set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
+       }
+       rcu_read_unlock();
+}
+
+void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
+{
+       nfs_client_mark_return_unreferenced_delegations(clp);
+       nfs_delegation_run_state_manager(clp);
+}
+
 /*
  * Asynchronous delegation recall!
  */
index 56f3eb558ef4b2e723b4b3e220a28fa5e3a5014e..2a74882e5d500ebff4400b4b653e010be2146138 100644 (file)
@@ -28,6 +28,7 @@ struct nfs_delegation {
 enum {
        NFS_DELEGATION_NEED_RECLAIM = 0,
        NFS_DELEGATION_RETURN,
+       NFS_DELEGATION_REFERENCED,
 };
 
 int 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);
 struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
 void nfs_super_return_all_delegations(struct super_block *sb);
 void nfs_expire_all_delegations(struct nfs_client *clp);
+void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
 void nfs_handle_cb_pathdown(struct nfs_client *clp);
 void nfs_client_return_marked_delegations(struct nfs_client *clp);
 
@@ -51,19 +53,8 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
 int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
 int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
 
-static inline int nfs_have_delegation(struct inode *inode, int flags)
-{
-       struct nfs_delegation *delegation;
-       int ret = 0;
-
-       flags &= FMODE_READ|FMODE_WRITE;
-       rcu_read_lock();
-       delegation = rcu_dereference(NFS_I(inode)->delegation);
-       if (delegation != NULL && (delegation->type & flags) == flags)
-               ret = 1;
-       rcu_read_unlock();
-       return ret;
-}
+void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
+int nfs_have_delegation(struct inode *inode, int flags);
 
 #else
 static inline int nfs_have_delegation(struct inode *inode, int flags)
index 2a347d47e38c02c5352a5cc96de9ecdac83068d1..fc0c9d255cf79778dd47b68f19468f5e9afef750 100644 (file)
@@ -421,6 +421,7 @@ static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_fla
                return 0;
        if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
                return 0;
+       nfs_mark_delegation_referenced(delegation);
        return 1;
 }
 
@@ -505,6 +506,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat
        else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0)
                goto no_delegation_unlock;
 
+       nfs_mark_delegation_referenced(deleg_cur);
        __update_open_stateid(state, open_stateid, &deleg_cur->stateid, open_flags);
        ret = 1;
 no_delegation_unlock:
index ca557e677d9ed56965af7eb7f14ad62583c08eb9..f524e932ff7b295f8bf0adce947f058f2d8ede73 100644 (file)
@@ -101,6 +101,7 @@ nfs4_renew_state(struct work_struct *work)
        cancel_delayed_work(&clp->cl_renewd);
        schedule_delayed_work(&clp->cl_renewd, timeout);
        spin_unlock(&clp->cl_lock);
+       nfs_expire_unreferenced_delegations(clp);
 out:
        dprintk("%s: done\n", __func__);
 }