diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2023-05-18 13:45:56 -0400 |
---|---|---|
committer | Chuck Lever <chuck.lever@oracle.com> | 2023-06-11 16:37:45 -0400 |
commit | 507df40ebf31655203dd05e6e31db5849a83347a (patch) | |
tree | d639cfde77a2ea18bdad9def841aca9b18e8a457 /fs/nfsd/vfs.c | |
parent | ed4a567a179ec15c15f78fa60ca6de9cc4f34897 (diff) | |
download | lwn-507df40ebf31655203dd05e6e31db5849a83347a.tar.gz lwn-507df40ebf31655203dd05e6e31db5849a83347a.zip |
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>
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 68 |
1 files changed, 60 insertions, 8 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 0016bcc04a59..d9055b5c496b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -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); } +/** + * 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, * there's a high chance this is another nfsd (triggered by a bulk write @@ -1161,14 +1205,24 @@ out_nfserr: return nfserr; } -/* - * Read data from a file. count must contain the requested read count - * on entry. On return, *count contains the number of bytes actually read. +/** + * nfsd_read - Read data from a file + * @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 + * + * Returns nfs_ok on success, otherwise an nfserr stat value is + * returned. */ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, - loff_t offset, struct kvec *vec, int vlen, unsigned long *count, - u32 *eof) + loff_t offset, unsigned long *count, u32 *eof) { struct nfsd_file *nf; 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)) err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof); 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); - trace_nfsd_read_done(rqstp, fhp, offset, *count); - return err; } |