Commit f49b68dd authored by Chuck Lever's avatar Chuck Lever Committed by J. Bruce Fields

SUNRPC: xdr_stream_subsegment() must handle non-zero page_bases

xdr_stream_subsegment() was introduced in commit c1346a12
("NFSD: Replace the internals of the READ_BUF() macro").

There are two call sites for xdr_stream_subsegment(). One is
nfsd4_decode_write(), and the other is nfsd4_decode_setxattr().
Currently neither of these call sites calls this API when
xdr_buf::page_base is a non-zero value.

However, I'm about to add a case where page_base will sometimes not
be zero when nfsd4_decode_write() invokes this API. Replace the
logic in xdr_stream_subsegment() that advances to the next data item
in the xdr_stream with something more generic in order to handle
this new use case.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 8e70bf27
...@@ -1633,7 +1633,7 @@ EXPORT_SYMBOL_GPL(xdr_buf_subsegment); ...@@ -1633,7 +1633,7 @@ EXPORT_SYMBOL_GPL(xdr_buf_subsegment);
* Sets up @subbuf to represent a portion of @xdr. The portion * Sets up @subbuf to represent a portion of @xdr. The portion
* starts at the current offset in @xdr, and extends for a length * starts at the current offset in @xdr, and extends for a length
* of @nbytes. If this is successful, @xdr is advanced to the next * of @nbytes. If this is successful, @xdr is advanced to the next
* position following that portion. * XDR data item following that portion.
* *
* Return values: * Return values:
* %true: @subbuf has been initialized, and @xdr has been advanced. * %true: @subbuf has been initialized, and @xdr has been advanced.
...@@ -1642,29 +1642,31 @@ EXPORT_SYMBOL_GPL(xdr_buf_subsegment); ...@@ -1642,29 +1642,31 @@ EXPORT_SYMBOL_GPL(xdr_buf_subsegment);
bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf, bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf,
unsigned int nbytes) unsigned int nbytes)
{ {
unsigned int remaining, offset, len; unsigned int start = xdr_stream_pos(xdr);
unsigned int remaining, len;
if (xdr_buf_subsegment(xdr->buf, subbuf, xdr_stream_pos(xdr), nbytes)) /* Extract @subbuf and bounds-check the fn arguments */
if (xdr_buf_subsegment(xdr->buf, subbuf, start, nbytes))
return false; return false;
if (subbuf->head[0].iov_len) /* Advance @xdr by @nbytes */
if (!__xdr_inline_decode(xdr, subbuf->head[0].iov_len)) for (remaining = nbytes; remaining;) {
return false;
remaining = subbuf->page_len;
offset = subbuf->page_base;
while (remaining) {
len = min_t(unsigned int, remaining, PAGE_SIZE) - offset;
if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr)) if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
return false; return false;
if (!__xdr_inline_decode(xdr, len))
return false;
len = (char *)xdr->end - (char *)xdr->p;
if (remaining <= len) {
xdr->p = (__be32 *)((char *)xdr->p +
(remaining + xdr_pad_size(nbytes)));
break;
}
xdr->p = (__be32 *)((char *)xdr->p + len);
xdr->end = xdr->p;
remaining -= len; remaining -= len;
offset = 0;
} }
xdr_stream_set_pos(xdr, start + nbytes);
return true; return true;
} }
EXPORT_SYMBOL_GPL(xdr_stream_subsegment); EXPORT_SYMBOL_GPL(xdr_stream_subsegment);
......
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