Commit e85c40cd authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Preparation for the server reboot recovery code.

parent 2d5e9ebc
...@@ -458,6 +458,54 @@ process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr) ...@@ -458,6 +458,54 @@ process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
} }
} }
/*
* OPEN_RECLAIM:
* reclaim state on the server after a reboot.
* Assumes caller is holding the sp->so_sem
*/
int
nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
{
struct inode *inode = state->inode;
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_fattr fattr = {
.valid = 0,
};
struct nfs4_change_info d_cinfo;
struct nfs4_getattr f_getattr = {
.gt_bmval = nfs4_fattr_bitmap,
.gt_attrs = &fattr,
};
struct nfs_open_reclaimargs o_arg = {
.fh = NFS_FH(inode),
.seqid = sp->so_seqid,
.id = sp->so_id,
.share_access = state->state,
.clientid = server->nfs4_state->cl_clientid,
.claim = NFS4_OPEN_CLAIM_PREVIOUS,
.f_getattr = &f_getattr,
};
struct nfs_openres o_res = {
.cinfo = &d_cinfo,
.f_getattr = &f_getattr,
.server = server, /* Grrr */
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_RECLAIM],
.rpc_argp = &o_arg,
.rpc_resp = &o_res,
.rpc_cred = sp->so_cred,
};
int status;
status = rpc_call_sync(server->client, &msg, 0);
nfs4_increment_seqid(status, sp);
/* Update the inode attributes */
nfs_refresh_inode(inode, &fattr);
return status;
}
struct nfs4_state * struct nfs4_state *
nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred) nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred)
{ {
...@@ -523,10 +571,9 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt ...@@ -523,10 +571,9 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
o_arg.id = sp->so_id; o_arg.id = sp->so_id;
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, 0);
if (status) {
goto out_up;
}
nfs4_increment_seqid(status, sp); nfs4_increment_seqid(status, sp);
if (status)
goto out_up;
process_cinfo(&d_cinfo, &d_attr); process_cinfo(&d_cinfo, &d_attr);
nfs_refresh_inode(dir, &d_attr); nfs_refresh_inode(dir, &d_attr);
...@@ -555,9 +602,9 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt ...@@ -555,9 +602,9 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
memcpy(&oc_arg.stateid, &o_res.stateid, sizeof(oc_arg.stateid)); memcpy(&oc_arg.stateid, &o_res.stateid, sizeof(oc_arg.stateid));
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, 0);
nfs4_increment_seqid(status, sp);
if (status) if (status)
goto out_up; goto out_up;
nfs4_increment_seqid(status, sp);
memcpy(&state->stateid, &oc_res.stateid, sizeof(state->stateid)); memcpy(&state->stateid, &oc_res.stateid, sizeof(state->stateid));
} else } else
memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
......
...@@ -382,6 +382,95 @@ nfs4_increment_seqid(int status, struct nfs4_state_owner *sp) ...@@ -382,6 +382,95 @@ nfs4_increment_seqid(int status, struct nfs4_state_owner *sp)
sp->so_seqid++; sp->so_seqid++;
} }
static int reclaimer(void *);
struct reclaimer_args {
struct nfs4_client *clp;
struct completion complete;
};
/*
* State recovery routine
*/
void
nfs4_recover_state(struct nfs4_client *clp)
{
struct reclaimer_args args = {
.clp = clp,
};
init_completion(&args.complete);
down_read(&clp->cl_sem);
if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0)
goto out_failed;
wait_for_completion(&args.complete);
return;
out_failed:
up_read(&clp->cl_sem);
}
static void
nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
{
struct nfs4_state *state;
int status;
list_for_each_entry(state, &sp->so_states, open_states) {
status = nfs4_open_reclaim(sp, state);
if (status) {
/*
* Open state on this file cannot be recovered
* All we can do is revert to using the zero stateid.
*/
memset(state->stateid.data, 0,
sizeof(state->stateid.data));
/* Mark the file as being 'closed' */
state->state = 0;
}
}
}
static int
reclaimer(void *ptr)
{
struct reclaimer_args *args = (struct reclaimer_args *)ptr;
struct nfs4_client *clp = args->clp;
struct nfs4_state_owner *sp;
int status;
daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
allow_signal(SIGKILL);
complete(&args->complete);
/* Are there any NFS mounts out there? */
if (list_empty(&clp->cl_superblocks))
goto out;
status = nfs4_proc_setclientid(clp, 0, 0);
if (status)
goto out_error;
status = nfs4_proc_setclientid_confirm(clp);
if (status)
goto out_error;
spin_lock(&clp->cl_lock);
list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
atomic_inc(&sp->so_count);
spin_unlock(&clp->cl_lock);
down(&sp->so_sema);
nfs4_reclaim_open_state(sp);
up(&sp->so_sema);
nfs4_put_state_owner(sp);
spin_lock(&clp->cl_lock);
}
spin_unlock(&clp->cl_lock);
out:
up_read(&clp->cl_sem);
return 0;
out_error:
printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u\n",
NIPQUAD(clp->cl_addr.s_addr));
goto out;
}
/* /*
* Local variables: * Local variables:
* c-basic-offset: 8 * c-basic-offset: 8
......
...@@ -166,6 +166,16 @@ static int nfs_stat_to_errno(int); ...@@ -166,6 +166,16 @@ static int nfs_stat_to_errno(int);
#define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \ #define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \ decode_putfh_maxsz + \
op_decode_hdr_maxsz + 4 op_decode_hdr_maxsz + 4
#define NFS4_enc_open_reclaim_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
op_encode_hdr_maxsz + \
11 + \
encode_getattr_maxsz
#define NFS4_dec_open_reclaim_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
op_decode_hdr_maxsz + \
4 + 5 + 2 + 3 + \
decode_getattr_maxsz
#define NFS4_enc_close_sz compound_encode_hdr_maxsz + \ #define NFS4_enc_close_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \ encode_putfh_maxsz + \
op_encode_hdr_maxsz + 5 op_encode_hdr_maxsz + 5
...@@ -666,6 +676,41 @@ encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg) ...@@ -666,6 +676,41 @@ encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg)
} }
static int
encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg)
{
uint32_t *p;
/*
* opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
* owner 4, opentype 4, claim 4, delegation_type 4 = 44
*/
RESERVE_SPACE(44);
WRITE32(OP_OPEN);
WRITE32(arg->seqid);
switch (arg->share_access) {
case FMODE_READ:
WRITE32(NFS4_SHARE_ACCESS_READ);
break;
case FMODE_WRITE:
WRITE32(NFS4_SHARE_ACCESS_WRITE);
break;
case FMODE_READ|FMODE_WRITE:
WRITE32(NFS4_SHARE_ACCESS_BOTH);
break;
default:
BUG();
}
WRITE32(0); /* for linux, share_deny = 0 always */
WRITE64(arg->clientid);
WRITE32(4);
WRITE32(arg->id);
WRITE32(NFS4_OPEN_NOCREATE);
WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
WRITE32(NFS4_OPEN_DELEGATE_NONE);
return 0;
}
static int static int
encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh) encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{ {
...@@ -1058,6 +1103,32 @@ nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_con ...@@ -1058,6 +1103,32 @@ nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_con
return status; return status;
} }
/*
* Encode an OPEN request
*/
static int
nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
struct nfs_open_reclaimargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
.nops = 3,
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh);
if (status)
goto out;
status = encode_open_reclaim(&xdr, args);
if (status)
goto out;
status = encode_getattr(&xdr, args->f_getattr);
out:
return status;
}
/* /*
* Encode a READ request * Encode a READ request
...@@ -2417,6 +2488,31 @@ nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_c ...@@ -2417,6 +2488,31 @@ nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_c
return status; return status;
} }
/*
* Decode OPEN_RECLAIM response
*/
static int
nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
status = decode_putfh(&xdr);
if (status)
goto out;
status = decode_open(&xdr, res);
if (status)
goto out;
status = decode_getattr(&xdr, res->f_getattr, res->server);
out:
return status;
}
/* /*
* Decode SETATTR response * Decode SETATTR response
*/ */
...@@ -2730,6 +2826,7 @@ struct rpc_procinfo nfs4_procedures[] = { ...@@ -2730,6 +2826,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(COMMIT, enc_commit, dec_commit), PROC(COMMIT, enc_commit, dec_commit),
PROC(OPEN, enc_open, dec_open), PROC(OPEN, enc_open, dec_open),
PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm), PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm),
PROC(OPEN_RECLAIM, enc_open_reclaim, dec_open_reclaim),
PROC(CLOSE, enc_close, dec_close), PROC(CLOSE, enc_close, dec_close),
PROC(SETATTR, enc_setattr, dec_setattr), PROC(SETATTR, enc_setattr, dec_setattr),
PROC(FSINFO, enc_fsinfo, dec_fsinfo), PROC(FSINFO, enc_fsinfo, dec_fsinfo),
......
...@@ -289,6 +289,7 @@ enum { ...@@ -289,6 +289,7 @@ enum {
NFSPROC4_CLNT_COMMIT, NFSPROC4_CLNT_COMMIT,
NFSPROC4_CLNT_OPEN, NFSPROC4_CLNT_OPEN,
NFSPROC4_CLNT_OPEN_CONFIRM, NFSPROC4_CLNT_OPEN_CONFIRM,
NFSPROC4_CLNT_OPEN_RECLAIM,
NFSPROC4_CLNT_CLOSE, NFSPROC4_CLNT_CLOSE,
NFSPROC4_CLNT_SETATTR, NFSPROC4_CLNT_SETATTR,
NFSPROC4_CLNT_FSINFO, NFSPROC4_CLNT_FSINFO,
......
...@@ -554,6 +554,7 @@ struct nfs4_state { ...@@ -554,6 +554,7 @@ struct nfs4_state {
/* nfs4proc.c */ /* nfs4proc.c */
extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); extern int nfs4_proc_setclientid_confirm(struct nfs4_client *);
extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *);
extern int nfs4_proc_async_renew(struct nfs4_client *); extern int nfs4_proc_async_renew(struct nfs4_client *);
extern int nfs4_do_close(struct inode *, struct nfs4_state *); extern int nfs4_do_close(struct inode *, struct nfs4_state *);
...@@ -572,6 +573,7 @@ extern void nfs4_put_state_owner(struct nfs4_state_owner *); ...@@ -572,6 +573,7 @@ extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);
extern void nfs4_recover_state(struct nfs4_client *);
struct nfs4_mount_data; struct nfs4_mount_data;
#else #else
......
...@@ -133,6 +133,19 @@ struct nfs_open_confirmres { ...@@ -133,6 +133,19 @@ struct nfs_open_confirmres {
nfs4_stateid stateid; nfs4_stateid stateid;
}; };
/*
* Arguments to the open_reclaim call.
*/
struct nfs_open_reclaimargs {
struct nfs_fh * fh;
__u64 clientid;
__u32 seqid;
__u32 id;
__u32 share_access;
__u32 claim;
struct nfs4_getattr * f_getattr;
};
/* /*
* Arguments to the close call. * Arguments to the close call.
*/ */
......
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