Skip to content

Commit 082d4bd

Browse files
author
J. Bruce Fields
committed
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: J. Bruce Fields <bfields@redhat.com>
1 parent 1fcea5b commit 082d4bd

File tree

1 file changed

+26
-19
lines changed

1 file changed

+26
-19
lines changed

fs/nfsd/nfs4xdr.c

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,16 +1759,19 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
17591759
char esc_exit)
17601760
{
17611761
__be32 *p;
1762-
__be32 *countp;
1762+
__be32 pathlen;
1763+
int pathlen_offset;
17631764
int strlen, count=0;
17641765
char *str, *end, *next;
17651766

17661767
dprintk("nfsd4_encode_components(%s)\n", components);
1768+
1769+
pathlen_offset = xdr->buf->len;
17671770
p = xdr_reserve_space(xdr, 4);
17681771
if (!p)
17691772
return nfserr_resource;
1770-
countp = p;
1771-
WRITE32(0); /* We will fill this in with @count later */
1773+
p++; /* We will fill this in with @count later */
1774+
17721775
end = str = components;
17731776
while (*end) {
17741777
bool found_esc = false;
@@ -1801,8 +1804,8 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
18011804
end++;
18021805
str = end;
18031806
}
1804-
p = countp;
1805-
WRITE32(count);
1807+
pathlen = htonl(xdr->buf->len - pathlen_offset);
1808+
write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4);
18061809
return 0;
18071810
}
18081811

@@ -2054,7 +2057,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
20542057
struct kstatfs statfs;
20552058
__be32 *p;
20562059
int starting_len = xdr->buf->len;
2057-
__be32 *attrlenp;
2060+
int attrlen_offset;
2061+
__be32 attrlen;
20582062
u32 dummy;
20592063
u64 dummy64;
20602064
u32 rdattr_err = 0;
@@ -2159,10 +2163,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
21592163
WRITE32(1);
21602164
WRITE32(bmval0);
21612165
}
2166+
2167+
attrlen_offset = xdr->buf->len;
21622168
p = xdr_reserve_space(xdr, 4);
21632169
if (!p)
21642170
goto out_resource;
2165-
attrlenp = p++; /* to be backfilled later */
2171+
p++; /* to be backfilled later */
21662172

21672173
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
21682174
u32 word0 = nfsd_suppattrs0(minorversion);
@@ -2534,7 +2540,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
25342540
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD2);
25352541
}
25362542

2537-
*attrlenp = htonl((char *)xdr->p - (char *)attrlenp - 4);
2543+
attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
2544+
write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
25382545
status = nfs_ok;
25392546

25402547
out:
@@ -3664,15 +3671,16 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
36643671
void
36653672
nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
36663673
{
3674+
struct xdr_stream *xdr = &resp->xdr;
36673675
struct nfs4_stateowner *so = resp->cstate.replay_owner;
36683676
struct svc_rqst *rqstp = resp->rqstp;
3669-
__be32 *statp;
3677+
int post_err_offset;
36703678
nfsd4_enc encoder;
36713679
__be32 *p;
36723680

36733681
RESERVE_SPACE(8);
36743682
WRITE32(op->opnum);
3675-
statp = p++; /* to be backfilled at the end */
3683+
post_err_offset = xdr->buf->len;
36763684

36773685
if (op->opnum == OP_ILLEGAL)
36783686
goto status;
@@ -3698,20 +3706,19 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
36983706
* bug if we had to do this on a non-idempotent op:
36993707
*/
37003708
warn_on_nonidempotent_op(op);
3701-
resp->xdr.p = statp + 1;
3709+
xdr_truncate_encode(xdr, post_err_offset);
37023710
}
37033711
if (so) {
3712+
int len = xdr->buf->len - post_err_offset;
3713+
37043714
so->so_replay.rp_status = op->status;
3705-
so->so_replay.rp_buflen = (char *)resp->xdr.p
3706-
- (char *)(statp+1);
3707-
memcpy(so->so_replay.rp_buf, statp+1, so->so_replay.rp_buflen);
3715+
so->so_replay.rp_buflen = len;
3716+
read_bytes_from_xdr_buf(xdr->buf, post_err_offset,
3717+
so->so_replay.rp_buf, len);
37083718
}
37093719
status:
3710-
/*
3711-
* Note: We write the status directly, instead of using WRITE32(),
3712-
* since it is already in network byte order.
3713-
*/
3714-
*statp = op->status;
3720+
/* Note that op->status is already in network byte order: */
3721+
write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4);
37153722
}
37163723

37173724
/*

0 commit comments

Comments
 (0)