delegation.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ delegation.h | 7 +++++++ nfs4proc.c | 13 ++++++++++++- nfs4state.c | 4 ++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff -u --recursive --new-file --show-c-function linux-2.6.7-16-delegation_recall2/fs/nfs/delegation.c linux-2.6.7-17-delegation_reclaim/fs/nfs/delegation.c --- linux-2.6.7-16-delegation_recall2/fs/nfs/delegation.c 2004-06-15 02:45:12.000000000 -0400 +++ linux-2.6.7-17-delegation_reclaim/fs/nfs/delegation.c 2004-06-15 03:33:57.000000000 -0400 @@ -57,6 +57,24 @@ again: /* * Set up a delegation on an inode */ +void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) +{ + struct nfs_delegation *delegation = NFS_I(inode)->delegation; + + if (delegation == NULL) + return; + memcpy(delegation->stateid.data, res->delegation.data, + sizeof(delegation->stateid.data)); + delegation->type = res->delegation_type; + delegation->maxsize = res->maxsize; + put_rpccred(cred); + delegation->cred = get_rpccred(cred); + delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM; +} + +/* + * Set up a delegation on an inode + */ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) { struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; @@ -250,3 +268,37 @@ struct inode *nfs_delegation_find_inode( spin_unlock(&clp->cl_lock); return res; } + +/* + * Mark all delegations as needing to be reclaimed + */ +void nfs_delegation_mark_reclaim(struct nfs4_client *clp) +{ + struct nfs_delegation *delegation; + spin_lock(&clp->cl_lock); + list_for_each_entry(delegation, &clp->cl_delegations, super_list) + delegation->flags |= NFS_DELEGATION_NEED_RECLAIM; + spin_unlock(&clp->cl_lock); +} + +/* + * Reap all unclaimed delegations after reboot recovery is done + */ +void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) +{ + struct nfs_delegation *delegation, *n; + LIST_HEAD(head); + spin_lock(&clp->cl_lock); + list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) { + if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) + continue; + list_move(&delegation->super_list, &head); + NFS_I(delegation->inode)->delegation = NULL; + } + spin_unlock(&clp->cl_lock); + while(!list_empty(&head)) { + delegation = list_entry(head.next, struct nfs_delegation, super_list); + list_del(&delegation->super_list); + nfs_free_delegation(delegation); + } +} diff -u --recursive --new-file --show-c-function linux-2.6.7-16-delegation_recall2/fs/nfs/delegation.h linux-2.6.7-17-delegation_reclaim/fs/nfs/delegation.h --- linux-2.6.7-16-delegation_recall2/fs/nfs/delegation.h 2004-06-15 02:45:06.000000000 -0400 +++ linux-2.6.7-17-delegation_reclaim/fs/nfs/delegation.h 2004-06-15 02:45:18.000000000 -0400 @@ -17,15 +17,22 @@ struct nfs_delegation { struct inode *inode; nfs4_stateid stateid; int type; +#define NFS_DELEGATION_NEED_RECLAIM 1 + long flags; loff_t maxsize; }; int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); +void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); int nfs_inode_return_delegation(struct inode *inode); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); void nfs_return_all_delegations(struct super_block *sb); + +void nfs_delegation_mark_reclaim(struct nfs4_client *clp); +void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); + /* NFSv4 delegation-related procedures */ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); diff -u --recursive --new-file --show-c-function linux-2.6.7-16-delegation_recall2/fs/nfs/nfs4proc.c linux-2.6.7-17-delegation_reclaim/fs/nfs/nfs4proc.c --- linux-2.6.7-16-delegation_recall2/fs/nfs/nfs4proc.c 2004-06-15 02:45:06.000000000 -0400 +++ linux-2.6.7-17-delegation_reclaim/fs/nfs/nfs4proc.c 2004-06-15 02:45:18.000000000 -0400 @@ -196,6 +196,7 @@ static int _nfs4_open_reclaim(struct nfs { struct inode *inode = state->inode; struct nfs_server *server = NFS_SERVER(inode); + struct nfs_delegation *delegation = NFS_I(inode)->delegation; struct nfs_openargs o_arg = { .fh = NFS_FH(inode), .seqid = sp->so_seqid, @@ -216,17 +217,27 @@ static int _nfs4_open_reclaim(struct nfs }; int status; + if (delegation != NULL) { + if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { + memcpy(&state->stateid, &delegation->stateid, + sizeof(state->stateid)); + set_bit(NFS_DELEGATED_STATE, &state->flags); + return 0; + } + o_arg.u.delegation_type = delegation->type; + } status = rpc_call_sync(server->client, &msg, 0); nfs4_increment_seqid(status, sp); if (status == 0) { memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); if (o_res.delegation_type != 0) { - nfs_inode_set_delegation(inode, sp->so_cred, &o_res); + nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); /* Did the server issue an immediate delegation recall? */ if (o_res.do_recall) nfs_async_inode_return_delegation(inode, &o_res.stateid); } } + clear_bit(NFS_DELEGATED_STATE, &state->flags); /* Ensure we update the inode attributes */ NFS_CACHEINV(inode); return status; diff -u --recursive --new-file --show-c-function linux-2.6.7-16-delegation_recall2/fs/nfs/nfs4state.c linux-2.6.7-17-delegation_reclaim/fs/nfs/nfs4state.c --- linux-2.6.7-16-delegation_recall2/fs/nfs/nfs4state.c 2004-06-15 02:44:44.000000000 -0400 +++ linux-2.6.7-17-delegation_reclaim/fs/nfs/nfs4state.c 2004-06-15 02:45:18.000000000 -0400 @@ -46,6 +46,7 @@ #include #include "callback.h" +#include "delegation.h" #define OPENOWNER_POOL_SIZE 8 @@ -858,6 +859,8 @@ restart_loop: status = nfs4_init_client(clp); if (status) goto out_error; + /* Mark all delagations for reclaim */ + nfs_delegation_mark_reclaim(clp); /* Note: list is protected by exclusive lock on cl->cl_sem */ list_for_each_entry(sp, &clp->cl_state_owners, so_list) { status = nfs4_reclaim_open_state(sp); @@ -867,6 +870,7 @@ restart_loop: goto out_error; } } + nfs_delegation_reap_unclaimed(clp); out: set_bit(NFS4CLNT_OK, &clp->cl_state); up_write(&clp->cl_sem);