Commit ef2a1b3e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by J. Bruce Fields

nfsd: split transport vs operation errors for callbacks

We must only increment the sequence id if the client has seen and responded
to a request.  If we failed to deliver it to the client we must resend with
the same sequence id.  So just like the client track errors at the transport
level differently from those returned in the XDR.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 9507271d
...@@ -224,7 +224,7 @@ static int nfs_cb_stat_to_errno(int status) ...@@ -224,7 +224,7 @@ static int nfs_cb_stat_to_errno(int status)
} }
static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
enum nfsstat4 *status) int *status)
{ {
__be32 *p; __be32 *p;
u32 op; u32 op;
...@@ -235,7 +235,7 @@ static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, ...@@ -235,7 +235,7 @@ static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
op = be32_to_cpup(p++); op = be32_to_cpup(p++);
if (unlikely(op != expected)) if (unlikely(op != expected))
goto out_unexpected; goto out_unexpected;
*status = be32_to_cpup(p); *status = nfs_cb_stat_to_errno(be32_to_cpup(p));
return 0; return 0;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr); print_overflow_msg(__func__, xdr);
...@@ -446,22 +446,16 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr, ...@@ -446,22 +446,16 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr,
static int decode_cb_sequence4res(struct xdr_stream *xdr, static int decode_cb_sequence4res(struct xdr_stream *xdr,
struct nfsd4_callback *cb) struct nfsd4_callback *cb)
{ {
enum nfsstat4 nfserr;
int status; int status;
if (cb->cb_minorversion == 0) if (cb->cb_minorversion == 0)
return 0; return 0;
status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr); status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &cb->cb_status);
if (unlikely(status)) if (unlikely(status || cb->cb_status))
goto out; return status;
if (unlikely(nfserr != NFS4_OK))
goto out_default; return decode_cb_sequence4resok(xdr, cb);
status = decode_cb_sequence4resok(xdr, cb);
out:
return status;
out_default:
return nfs_cb_stat_to_errno(nfserr);
} }
/* /*
...@@ -524,26 +518,19 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, ...@@ -524,26 +518,19 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
struct nfsd4_callback *cb) struct nfsd4_callback *cb)
{ {
struct nfs4_cb_compound_hdr hdr; struct nfs4_cb_compound_hdr hdr;
enum nfsstat4 nfserr;
int status; int status;
status = decode_cb_compound4res(xdr, &hdr); status = decode_cb_compound4res(xdr, &hdr);
if (unlikely(status)) if (unlikely(status))
goto out; return status;
if (cb != NULL) { if (cb != NULL) {
status = decode_cb_sequence4res(xdr, cb); status = decode_cb_sequence4res(xdr, cb);
if (unlikely(status)) if (unlikely(status || cb->cb_status))
goto out; return status;
} }
status = decode_cb_op_status(xdr, OP_CB_RECALL, &nfserr); return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status);
if (unlikely(status))
goto out;
if (unlikely(nfserr != NFS4_OK))
status = nfs_cb_stat_to_errno(nfserr);
out:
return status;
} }
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
...@@ -621,24 +608,18 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp, ...@@ -621,24 +608,18 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp,
struct nfsd4_callback *cb) struct nfsd4_callback *cb)
{ {
struct nfs4_cb_compound_hdr hdr; struct nfs4_cb_compound_hdr hdr;
enum nfsstat4 nfserr;
int status; int status;
status = decode_cb_compound4res(xdr, &hdr); status = decode_cb_compound4res(xdr, &hdr);
if (unlikely(status)) if (unlikely(status))
goto out; return status;
if (cb) { if (cb) {
status = decode_cb_sequence4res(xdr, cb); status = decode_cb_sequence4res(xdr, cb);
if (unlikely(status)) if (unlikely(status || cb->cb_status))
goto out; return status;
} }
status = decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &nfserr); return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status);
if (unlikely(status))
goto out;
if (unlikely(nfserr != NFS4_OK))
status = nfs_cb_stat_to_errno(nfserr);
out:
return status;
} }
#endif /* CONFIG_NFSD_PNFS */ #endif /* CONFIG_NFSD_PNFS */
...@@ -918,7 +899,8 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) ...@@ -918,7 +899,8 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
if (clp->cl_minorversion) { if (clp->cl_minorversion) {
/* No need for lock, access serialized in nfsd4_cb_prepare */ /* No need for lock, access serialized in nfsd4_cb_prepare */
++clp->cl_cb_session->se_cb_seq_nr; if (!task->tk_status)
++clp->cl_cb_session->se_cb_seq_nr;
clear_bit(0, &clp->cl_cb_slot_busy); clear_bit(0, &clp->cl_cb_slot_busy);
rpc_wake_up_next(&clp->cl_cb_waitq); rpc_wake_up_next(&clp->cl_cb_waitq);
dprintk("%s: freed slot, new seqid=%d\n", __func__, dprintk("%s: freed slot, new seqid=%d\n", __func__,
...@@ -935,6 +917,11 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) ...@@ -935,6 +917,11 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
if (cb->cb_done) if (cb->cb_done)
return; return;
if (cb->cb_status) {
WARN_ON_ONCE(task->tk_status);
task->tk_status = cb->cb_status;
}
switch (cb->cb_ops->done(cb, task)) { switch (cb->cb_ops->done(cb, task)) {
case 0: case 0:
task->tk_status = 0; task->tk_status = 0;
...@@ -1099,6 +1086,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, ...@@ -1099,6 +1086,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
cb->cb_ops = ops; cb->cb_ops = ops;
INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); INIT_WORK(&cb->cb_work, nfsd4_run_cb_work);
INIT_LIST_HEAD(&cb->cb_per_client); INIT_LIST_HEAD(&cb->cb_per_client);
cb->cb_status = 0;
cb->cb_done = true; cb->cb_done = true;
} }
......
...@@ -68,6 +68,7 @@ struct nfsd4_callback { ...@@ -68,6 +68,7 @@ struct nfsd4_callback {
struct rpc_message cb_msg; struct rpc_message cb_msg;
struct nfsd4_callback_ops *cb_ops; struct nfsd4_callback_ops *cb_ops;
struct work_struct cb_work; struct work_struct cb_work;
int cb_status;
bool cb_done; bool cb_done;
}; };
......
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