mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
NFSD: Hoist rq_vec preparation into nfsd_read()
Accrue the following benefits: a) Deduplicate this common bit of code. b) Don't prepare rq_vec for NFSv2 and NFSv3 spliced reads, which don't use rq_vec. This is already the case for nfsd4_encode_read(). c) Eventually, converting NFSD's read path to use a bvec iterator will be simpler. In the next patch, nfsd_iter_read() will replace nfsd_readv() for all NFS versions. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
@@ -151,8 +151,6 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
|||||||
{
|
{
|
||||||
struct nfsd3_readargs *argp = rqstp->rq_argp;
|
struct nfsd3_readargs *argp = rqstp->rq_argp;
|
||||||
struct nfsd3_readres *resp = rqstp->rq_resp;
|
struct nfsd3_readres *resp = rqstp->rq_resp;
|
||||||
unsigned int len;
|
|
||||||
int v;
|
|
||||||
|
|
||||||
dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
|
dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
|
||||||
SVCFH_fmt(&argp->fh),
|
SVCFH_fmt(&argp->fh),
|
||||||
@@ -166,17 +164,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
|||||||
if (argp->offset + argp->count > (u64)OFFSET_MAX)
|
if (argp->offset + argp->count > (u64)OFFSET_MAX)
|
||||||
argp->count = (u64)OFFSET_MAX - argp->offset;
|
argp->count = (u64)OFFSET_MAX - argp->offset;
|
||||||
|
|
||||||
v = 0;
|
|
||||||
len = argp->count;
|
|
||||||
resp->pages = rqstp->rq_next_page;
|
resp->pages = rqstp->rq_next_page;
|
||||||
while (len > 0) {
|
|
||||||
struct page *page = *(rqstp->rq_next_page++);
|
|
||||||
|
|
||||||
rqstp->rq_vec[v].iov_base = page_address(page);
|
|
||||||
rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
|
|
||||||
len -= rqstp->rq_vec[v].iov_len;
|
|
||||||
v++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain buffer pointer for payload.
|
/* Obtain buffer pointer for payload.
|
||||||
* 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
|
* 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
|
||||||
@@ -187,7 +175,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
|||||||
|
|
||||||
fh_copy(&resp->fh, &argp->fh);
|
fh_copy(&resp->fh, &argp->fh);
|
||||||
resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
|
resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
|
||||||
rqstp->rq_vec, v, &resp->count, &resp->eof);
|
&resp->count, &resp->eof);
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -176,9 +176,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
|||||||
{
|
{
|
||||||
struct nfsd_readargs *argp = rqstp->rq_argp;
|
struct nfsd_readargs *argp = rqstp->rq_argp;
|
||||||
struct nfsd_readres *resp = rqstp->rq_resp;
|
struct nfsd_readres *resp = rqstp->rq_resp;
|
||||||
unsigned int len;
|
|
||||||
u32 eof;
|
u32 eof;
|
||||||
int v;
|
|
||||||
|
|
||||||
dprintk("nfsd: READ %s %d bytes at %d\n",
|
dprintk("nfsd: READ %s %d bytes at %d\n",
|
||||||
SVCFH_fmt(&argp->fh),
|
SVCFH_fmt(&argp->fh),
|
||||||
@@ -187,17 +185,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
|||||||
argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2);
|
argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2);
|
||||||
argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
|
argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
|
||||||
|
|
||||||
v = 0;
|
|
||||||
len = argp->count;
|
|
||||||
resp->pages = rqstp->rq_next_page;
|
resp->pages = rqstp->rq_next_page;
|
||||||
while (len > 0) {
|
|
||||||
struct page *page = *(rqstp->rq_next_page++);
|
|
||||||
|
|
||||||
rqstp->rq_vec[v].iov_base = page_address(page);
|
|
||||||
rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
|
|
||||||
len -= rqstp->rq_vec[v].iov_len;
|
|
||||||
v++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain buffer pointer for payload. 19 is 1 word for
|
/* Obtain buffer pointer for payload. 19 is 1 word for
|
||||||
* status, 17 words for fattr, and 1 word for the byte count.
|
* status, 17 words for fattr, and 1 word for the byte count.
|
||||||
@@ -207,7 +195,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
|||||||
resp->count = argp->count;
|
resp->count = argp->count;
|
||||||
fh_copy(&resp->fh, &argp->fh);
|
fh_copy(&resp->fh, &argp->fh);
|
||||||
resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
|
resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
|
||||||
rqstp->rq_vec, v, &resp->count, &eof);
|
&resp->count, &eof);
|
||||||
if (resp->status == nfs_ok)
|
if (resp->status == nfs_ok)
|
||||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||||
else if (resp->status == nfserr_jukebox)
|
else if (resp->status == nfserr_jukebox)
|
||||||
|
@@ -1036,6 +1036,50 @@ __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
|
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nfsd_iter_read - Perform a VFS read using an iterator
|
||||||
|
* @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
|
||||||
|
* @base: offset in first page of read buffer
|
||||||
|
* @eof: OUT: set non-zero if operation reached the end of the file
|
||||||
|
*
|
||||||
|
* Some filesystems or situations cannot use nfsd_splice_read. This
|
||||||
|
* function is the slightly less-performant fallback for those cases.
|
||||||
|
*
|
||||||
|
* Returns nfs_ok on success, otherwise an nfserr stat value is
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
__be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
|
struct file *file, loff_t offset, unsigned long *count,
|
||||||
|
unsigned int base, u32 *eof)
|
||||||
|
{
|
||||||
|
unsigned long v, total;
|
||||||
|
struct iov_iter iter;
|
||||||
|
loff_t ppos = offset;
|
||||||
|
struct page *page;
|
||||||
|
ssize_t host_err;
|
||||||
|
|
||||||
|
v = 0;
|
||||||
|
total = *count;
|
||||||
|
while (total) {
|
||||||
|
page = *(rqstp->rq_next_page++);
|
||||||
|
rqstp->rq_vec[v].iov_base = page_address(page) + base;
|
||||||
|
rqstp->rq_vec[v].iov_len = min_t(size_t, total, PAGE_SIZE - base);
|
||||||
|
total -= rqstp->rq_vec[v].iov_len;
|
||||||
|
++v;
|
||||||
|
base = 0;
|
||||||
|
}
|
||||||
|
WARN_ON_ONCE(v > ARRAY_SIZE(rqstp->rq_vec));
|
||||||
|
|
||||||
|
trace_nfsd_read_vector(rqstp, fhp, offset, *count);
|
||||||
|
iov_iter_kvec(&iter, ITER_DEST, rqstp->rq_vec, v, *count);
|
||||||
|
host_err = vfs_iter_read(file, &iter, &ppos, 0);
|
||||||
|
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gathered writes: If another process is currently writing to the file,
|
* Gathered writes: If another process is currently writing to the file,
|
||||||
* there's a high chance this is another nfsd (triggered by a bulk write
|
* there's a high chance this is another nfsd (triggered by a bulk write
|
||||||
@@ -1161,14 +1205,24 @@ out_nfserr:
|
|||||||
return nfserr;
|
return nfserr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Read data from a file. count must contain the requested read count
|
* nfsd_read - Read data from a file
|
||||||
* on entry. On return, *count contains the number of bytes actually read.
|
* @rqstp: RPC transaction context
|
||||||
|
* @fhp: file handle 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
|
||||||
|
*
|
||||||
|
* The caller must verify that there is enough space in @rqstp.rq_res
|
||||||
|
* to perform this operation.
|
||||||
|
*
|
||||||
* N.B. After this call fhp needs an fh_put
|
* N.B. After this call fhp needs an fh_put
|
||||||
|
*
|
||||||
|
* Returns nfs_ok on success, otherwise an nfserr stat value is
|
||||||
|
* returned.
|
||||||
*/
|
*/
|
||||||
__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
loff_t offset, struct kvec *vec, int vlen, unsigned long *count,
|
loff_t offset, unsigned long *count, u32 *eof)
|
||||||
u32 *eof)
|
|
||||||
{
|
{
|
||||||
struct nfsd_file *nf;
|
struct nfsd_file *nf;
|
||||||
struct file *file;
|
struct file *file;
|
||||||
@@ -1183,12 +1237,10 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
|
if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
|
||||||
err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof);
|
err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof);
|
||||||
else
|
else
|
||||||
err = nfsd_readv(rqstp, fhp, file, offset, vec, vlen, count, eof);
|
err = nfsd_iter_read(rqstp, fhp, file, offset, count, 0, eof);
|
||||||
|
|
||||||
nfsd_file_put(nf);
|
nfsd_file_put(nf);
|
||||||
|
|
||||||
trace_nfsd_read_done(rqstp, fhp, offset, *count);
|
trace_nfsd_read_done(rqstp, fhp, offset, *count);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -115,8 +115,12 @@ __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
struct kvec *vec, int vlen,
|
struct kvec *vec, int vlen,
|
||||||
unsigned long *count,
|
unsigned long *count,
|
||||||
u32 *eof);
|
u32 *eof);
|
||||||
__be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
loff_t, struct kvec *, int, unsigned long *,
|
struct file *file, loff_t offset,
|
||||||
|
unsigned long *count, unsigned int base,
|
||||||
|
u32 *eof);
|
||||||
|
__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
|
loff_t offset, unsigned long *count,
|
||||||
u32 *eof);
|
u32 *eof);
|
||||||
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t,
|
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t,
|
||||||
struct kvec *, int, unsigned long *,
|
struct kvec *, int, unsigned long *,
|
||||||
|
Reference in New Issue
Block a user