Commit 082d4bd7 authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: "backfill" using write_bytes_to_xdr_buf

Normally xdr encoding proceeds in a single pass from start of a buffer
to end, but sometimes we have to write a few bytes to an earlier
position.

Use write_bytes_to_xdr_buf for these cases rather than saving a pointer
to write to.  We plan to rewrite xdr_reserve_space to handle encoding
across page boundaries using a scratch buffer, and don't want to risk
writing to a pointer that was contained in a scratch buffer.

Also it will no longer be safe to calculate lengths by subtracting two
pointers, so use xdr_buf offsets instead.
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 1fcea5b2
...@@ -1759,16 +1759,19 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep, ...@@ -1759,16 +1759,19 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
char esc_exit) char esc_exit)
{ {
__be32 *p; __be32 *p;
__be32 *countp; __be32 pathlen;
int pathlen_offset;
int strlen, count=0; int strlen, count=0;
char *str, *end, *next; char *str, *end, *next;
dprintk("nfsd4_encode_components(%s)\n", components); dprintk("nfsd4_encode_components(%s)\n", components);
pathlen_offset = xdr->buf->len;
p = xdr_reserve_space(xdr, 4); p = xdr_reserve_space(xdr, 4);
if (!p) if (!p)
return nfserr_resource; return nfserr_resource;
countp = p; p++; /* We will fill this in with @count later */
WRITE32(0); /* We will fill this in with @count later */
end = str = components; end = str = components;
while (*end) { while (*end) {
bool found_esc = false; bool found_esc = false;
...@@ -1801,8 +1804,8 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep, ...@@ -1801,8 +1804,8 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
end++; end++;
str = end; str = end;
} }
p = countp; pathlen = htonl(xdr->buf->len - pathlen_offset);
WRITE32(count); write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4);
return 0; return 0;
} }
...@@ -2054,7 +2057,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, ...@@ -2054,7 +2057,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
struct kstatfs statfs; struct kstatfs statfs;
__be32 *p; __be32 *p;
int starting_len = xdr->buf->len; int starting_len = xdr->buf->len;
__be32 *attrlenp; int attrlen_offset;
__be32 attrlen;
u32 dummy; u32 dummy;
u64 dummy64; u64 dummy64;
u32 rdattr_err = 0; u32 rdattr_err = 0;
...@@ -2159,10 +2163,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, ...@@ -2159,10 +2163,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
WRITE32(1); WRITE32(1);
WRITE32(bmval0); WRITE32(bmval0);
} }
attrlen_offset = xdr->buf->len;
p = xdr_reserve_space(xdr, 4); p = xdr_reserve_space(xdr, 4);
if (!p) if (!p)
goto out_resource; goto out_resource;
attrlenp = p++; /* to be backfilled later */ p++; /* to be backfilled later */
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
u32 word0 = nfsd_suppattrs0(minorversion); u32 word0 = nfsd_suppattrs0(minorversion);
...@@ -2534,7 +2540,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, ...@@ -2534,7 +2540,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD2); WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD2);
} }
*attrlenp = htonl((char *)xdr->p - (char *)attrlenp - 4); attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
status = nfs_ok; status = nfs_ok;
out: out:
...@@ -3664,15 +3671,16 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) ...@@ -3664,15 +3671,16 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
void void
nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
{ {
struct xdr_stream *xdr = &resp->xdr;
struct nfs4_stateowner *so = resp->cstate.replay_owner; struct nfs4_stateowner *so = resp->cstate.replay_owner;
struct svc_rqst *rqstp = resp->rqstp; struct svc_rqst *rqstp = resp->rqstp;
__be32 *statp; int post_err_offset;
nfsd4_enc encoder; nfsd4_enc encoder;
__be32 *p; __be32 *p;
RESERVE_SPACE(8); RESERVE_SPACE(8);
WRITE32(op->opnum); WRITE32(op->opnum);
statp = p++; /* to be backfilled at the end */ post_err_offset = xdr->buf->len;
if (op->opnum == OP_ILLEGAL) if (op->opnum == OP_ILLEGAL)
goto status; goto status;
...@@ -3698,20 +3706,19 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) ...@@ -3698,20 +3706,19 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
* bug if we had to do this on a non-idempotent op: * bug if we had to do this on a non-idempotent op:
*/ */
warn_on_nonidempotent_op(op); warn_on_nonidempotent_op(op);
resp->xdr.p = statp + 1; xdr_truncate_encode(xdr, post_err_offset);
} }
if (so) { if (so) {
int len = xdr->buf->len - post_err_offset;
so->so_replay.rp_status = op->status; so->so_replay.rp_status = op->status;
so->so_replay.rp_buflen = (char *)resp->xdr.p so->so_replay.rp_buflen = len;
- (char *)(statp+1); read_bytes_from_xdr_buf(xdr->buf, post_err_offset,
memcpy(so->so_replay.rp_buf, statp+1, so->so_replay.rp_buflen); so->so_replay.rp_buf, len);
} }
status: status:
/* /* Note that op->status is already in network byte order: */
* Note: We write the status directly, instead of using WRITE32(), write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4);
* since it is already in network byte order.
*/
*statp = op->status;
} }
/* /*
......
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