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: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
507df40ebf
commit
703d752155
4 changed files with 30 additions and 22 deletions
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
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
|
||||||
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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue