Commit 703d7521 authored by Chuck Lever's avatar Chuck Lever

NFSD: Hoist rq_vec preparation into nfsd_read() [step two]

Now that the preparation of an rq_vec has been removed from the
generic read path, nfsd_splice_read() no longer needs to reset
rq_next_page.

nfsd4_encode_read() calls nfsd_splice_read() directly. As far as I
can ascertain, resetting rq_next_page for NFSv4 splice reads is
unnecessary because rq_next_page is already set correctly.

Moreover, resetting it might even be incorrect if previous
operations in the COMPOUND have already consumed at least a page of
the send buffer. I would expect that the result would be encoding
the READ payload over previously-encoded results.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 507df40e
...@@ -4103,13 +4103,13 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, ...@@ -4103,13 +4103,13 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
__be32 zero = xdr_zero; __be32 zero = xdr_zero;
__be32 nfserr; __be32 nfserr;
read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount); if (xdr_reserve_space_vec(xdr, maxcount) < 0)
if (read->rd_vlen < 0)
return nfserr_resource; return nfserr_resource;
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, file,
resp->rqstp->rq_vec, read->rd_vlen, &maxcount, read->rd_offset, &maxcount,
&read->rd_eof); xdr->buf->page_len & ~PAGE_MASK,
&read->rd_eof);
read->rd_length = maxcount; read->rd_length = maxcount;
if (nfserr) if (nfserr)
return nfserr; return nfserr;
......
...@@ -1003,6 +1003,18 @@ static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1003,6 +1003,18 @@ static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
} }
} }
/**
* nfsd_splice_read - Perform a VFS read using a splice pipe
* @rqstp: RPC transaction context
* @fhp: file handle of file to be read
* @file: opened struct file of file to be read
* @offset: starting byte offset
* @count: IN: requested number of bytes; OUT: number of bytes read
* @eof: OUT: set non-zero if operation reached the end of the file
*
* Returns nfs_ok on success, otherwise an nfserr stat value is
* returned.
*/
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct file *file, loff_t offset, unsigned long *count, struct file *file, loff_t offset, unsigned long *count,
u32 *eof) u32 *eof)
...@@ -1016,7 +1028,6 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1016,7 +1028,6 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
ssize_t host_err; ssize_t host_err;
trace_nfsd_read_splice(rqstp, fhp, offset, *count); trace_nfsd_read_splice(rqstp, fhp, offset, *count);
rqstp->rq_next_page = rqstp->rq_respages + 1;
host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err); return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
} }
......
...@@ -242,8 +242,7 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, ...@@ -242,8 +242,7 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,
extern void xdr_init_encode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, extern void xdr_init_encode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
struct page **pages, struct rpc_rqst *rqst); struct page **pages, struct rpc_rqst *rqst);
extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, extern int xdr_reserve_space_vec(struct xdr_stream *xdr, size_t nbytes);
size_t nbytes);
extern void __xdr_commit_encode(struct xdr_stream *xdr); extern void __xdr_commit_encode(struct xdr_stream *xdr);
extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len); extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
extern void xdr_truncate_decode(struct xdr_stream *xdr, size_t len); extern void xdr_truncate_decode(struct xdr_stream *xdr, size_t len);
......
...@@ -1070,22 +1070,22 @@ __be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) ...@@ -1070,22 +1070,22 @@ __be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
} }
EXPORT_SYMBOL_GPL(xdr_reserve_space); EXPORT_SYMBOL_GPL(xdr_reserve_space);
/** /**
* xdr_reserve_space_vec - Reserves a large amount of buffer space for sending * xdr_reserve_space_vec - Reserves a large amount of buffer space for sending
* @xdr: pointer to xdr_stream * @xdr: pointer to xdr_stream
* @vec: pointer to a kvec array
* @nbytes: number of bytes to reserve * @nbytes: number of bytes to reserve
* *
* Reserves enough buffer space to encode 'nbytes' of data and stores the * The size argument passed to xdr_reserve_space() is determined based
* pointers in 'vec'. The size argument passed to xdr_reserve_space() is * on the number of bytes remaining in the current page to avoid
* determined based on the number of bytes remaining in the current page to * invalidating iov_base pointers when xdr_commit_encode() is called.
* avoid invalidating iov_base pointers when xdr_commit_encode() is called. *
* Return values:
* %0: success
* %-EMSGSIZE: not enough space is available in @xdr
*/ */
int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, size_t nbytes) int xdr_reserve_space_vec(struct xdr_stream *xdr, size_t nbytes)
{ {
int thislen; size_t thislen;
int v = 0;
__be32 *p; __be32 *p;
/* /*
...@@ -1097,21 +1097,19 @@ int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, size_t nbyte ...@@ -1097,21 +1097,19 @@ int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, size_t nbyte
xdr->end = xdr->p; xdr->end = xdr->p;
} }
/* XXX: Let's find a way to make this more efficient */
while (nbytes) { while (nbytes) {
thislen = xdr->buf->page_len % PAGE_SIZE; thislen = xdr->buf->page_len % PAGE_SIZE;
thislen = min_t(size_t, nbytes, PAGE_SIZE - thislen); thislen = min_t(size_t, nbytes, PAGE_SIZE - thislen);
p = xdr_reserve_space(xdr, thislen); p = xdr_reserve_space(xdr, thislen);
if (!p) if (!p)
return -EIO; return -EMSGSIZE;
vec[v].iov_base = p;
vec[v].iov_len = thislen;
v++;
nbytes -= thislen; nbytes -= thislen;
} }
return v; return 0;
} }
EXPORT_SYMBOL_GPL(xdr_reserve_space_vec); EXPORT_SYMBOL_GPL(xdr_reserve_space_vec);
......
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