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) ...@@ -54,6 +54,24 @@ static void nfs_delegation_claim_opens(struct inode *inode)
spin_unlock(&inode->i_lock); 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 * Set up a delegation on an inode
*/ */
...@@ -258,3 +276,37 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf ...@@ -258,3 +276,37 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
return res; 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 { ...@@ -17,15 +17,22 @@ struct nfs_delegation {
struct inode *inode; struct inode *inode;
nfs4_stateid stateid; nfs4_stateid stateid;
int type; int type;
#define NFS_DELEGATION_NEED_RECLAIM 1
long flags;
loff_t maxsize; loff_t maxsize;
}; };
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 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_inode_return_delegation(struct inode *inode);
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); 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); 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_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 */ /* NFSv4 delegation-related procedures */
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); 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); 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 ...@@ -196,6 +196,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct nfs_delegation *delegation = NFS_I(inode)->delegation;
struct nfs_openargs o_arg = { struct nfs_openargs o_arg = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
.seqid = sp->so_seqid, .seqid = sp->so_seqid,
...@@ -216,17 +217,27 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st ...@@ -216,17 +217,27 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
}; };
int status; 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); status = rpc_call_sync(server->client, &msg, 0);
nfs4_increment_seqid(status, sp); nfs4_increment_seqid(status, sp);
if (status == 0) { if (status == 0) {
memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
if (o_res.delegation_type != 0) { 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? */ /* Did the server issue an immediate delegation recall? */
if (o_res.do_recall) if (o_res.do_recall)
nfs_async_inode_return_delegation(inode, &o_res.stateid); nfs_async_inode_return_delegation(inode, &o_res.stateid);
} }
} }
clear_bit(NFS_DELEGATED_STATE, &state->flags);
/* Ensure we update the inode attributes */ /* Ensure we update the inode attributes */
NFS_CACHEINV(inode); NFS_CACHEINV(inode);
return status; return status;
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include "callback.h" #include "callback.h"
#include "delegation.h"
#define OPENOWNER_POOL_SIZE 8 #define OPENOWNER_POOL_SIZE 8
...@@ -862,6 +863,8 @@ static int reclaimer(void *ptr) ...@@ -862,6 +863,8 @@ static int reclaimer(void *ptr)
status = nfs4_init_client(clp); status = nfs4_init_client(clp);
if (status) if (status)
goto out_error; goto out_error;
/* Mark all delagations for reclaim */
nfs_delegation_mark_reclaim(clp);
/* Note: list is protected by exclusive lock on cl->cl_sem */ /* Note: list is protected by exclusive lock on cl->cl_sem */
list_for_each_entry(sp, &clp->cl_state_owners, so_list) { list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
status = nfs4_reclaim_open_state(sp); status = nfs4_reclaim_open_state(sp);
...@@ -871,6 +874,7 @@ static int reclaimer(void *ptr) ...@@ -871,6 +874,7 @@ static int reclaimer(void *ptr)
goto out_error; goto out_error;
} }
} }
nfs_delegation_reap_unclaimed(clp);
out: out:
set_bit(NFS4CLNT_OK, &clp->cl_state); set_bit(NFS4CLNT_OK, &clp->cl_state);
up_write(&clp->cl_sem); 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