spin_unlock(&inode->i_lock);
}
+/*
+ * 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
*/
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);
+ }
+}
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);
{
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,
};
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;
#include <linux/bitops.h>
#include "callback.h"
+#include "delegation.h"
#define OPENOWNER_POOL_SIZE 8
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);
goto out_error;
}
}
+ nfs_delegation_reap_unclaimed(clp);
out:
set_bit(NFS4CLNT_OK, &clp->cl_state);
up_write(&clp->cl_sem);