Commit 2ac2de8d authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Recover delegations on server reboot.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
parent 0a3b5d3b
......@@ -54,6 +54,24 @@ static void nfs_delegation_claim_opens(struct inode *inode)
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
*/
......@@ -258,3 +276,37 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf
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);
}
}
......@@ -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);
......
......@@ -196,6 +196,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
{
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 nfs4_state_owner *sp, struct nfs4_state *st
};
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;
......
......@@ -47,6 +47,7 @@
#include <linux/bitops.h>
#include "callback.h"
#include "delegation.h"
#define OPENOWNER_POOL_SIZE 8
......@@ -862,6 +863,8 @@ static int reclaimer(void *ptr)
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);
......@@ -871,6 +874,7 @@ static int reclaimer(void *ptr)
goto out_error;
}
}
nfs_delegation_reap_unclaimed(clp);
out:
set_bit(NFS4CLNT_OK, &clp->cl_state);
up_write(&clp->cl_sem);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment