Skip to content

Commit eae03e2

Browse files
chuckleverJ. Bruce Fields
authored andcommitted
nfsd: Incoming xdr_bufs may have content in tail buffer
Since the beginning, svcsock has built a received RPC Call message by populating the xdr_buf's head, then placing the remaining message bytes in the xdr_buf's page list. The xdr_buf's tail is never populated. This means that an NFSv4 COMPOUND containing an NFS WRITE operation plus trailing operations has a page list that contains the WRITE data payload followed by the trailing operations. NFSv4 XDR decoders will not look in the xdr_buf's tail, ever, because svcsock never put anything there. To support transports that can pass the write payload in the xdr_buf's pagelist and trailing content in the xdr_buf's tail, introduce logic in READ_BUF that switches to the xdr_buf's tail vec when the decoder runs out of content in rq_arg.pages. Signed-off-by: Chuck Lever <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent 0828170 commit eae03e2

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

fs/nfsd/nfs4xdr.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,25 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
159159
*/
160160
unsigned int avail = (char *)argp->end - (char *)argp->p;
161161
__be32 *p;
162+
163+
if (argp->pagelen == 0) {
164+
struct kvec *vec = &argp->rqstp->rq_arg.tail[0];
165+
166+
if (!argp->tail) {
167+
argp->tail = true;
168+
avail = vec->iov_len;
169+
argp->p = vec->iov_base;
170+
argp->end = vec->iov_base + avail;
171+
}
172+
173+
if (avail < nbytes)
174+
return NULL;
175+
176+
p = argp->p;
177+
argp->p += XDR_QUADLEN(nbytes);
178+
return p;
179+
}
180+
162181
if (avail + argp->pagelen < nbytes)
163182
return NULL;
164183
if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */
@@ -4471,6 +4490,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p)
44714490
args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
44724491
args->pagelist = rqstp->rq_arg.pages;
44734492
args->pagelen = rqstp->rq_arg.page_len;
4493+
args->tail = false;
44744494
args->tmpp = NULL;
44754495
args->to_free = NULL;
44764496
args->ops = args->iops;

fs/nfsd/xdr4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ struct nfsd4_compoundargs {
615615
__be32 * end;
616616
struct page ** pagelist;
617617
int pagelen;
618+
bool tail;
618619
__be32 tmp[8];
619620
__be32 * tmpp;
620621
struct svcxdr_tmpbuf *to_free;

0 commit comments

Comments
 (0)