summaryrefslogtreecommitdiffstats
path: root/net/sunrpc/svc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-23 16:00:10 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-23 16:00:10 -0700
commit9157141c95bc3ffcdae93fde5d5aafee7ce6e39a (patch)
treed19dd16a9caeec931fabfb31213aac9dda68af6d /net/sunrpc/svc.c
parent6f7948f566bf423ddf5ff58dc0198afcf37c0b64 (diff)
parent108b833cde9c9b93204e6a4e455829a67f9785c3 (diff)
Merge tag 'nfsd-4.19-1' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields: "Chuck Lever fixed a problem with NFSv4.0 callbacks over GSS from multi-homed servers. The only new feature is a minor bit of protocol (change_attr_type) which the client doesn't even use yet. Other than that, various bugfixes and cleanup" * tag 'nfsd-4.19-1' of git://linux-nfs.org/~bfields/linux: (27 commits) sunrpc: Add comment defining gssd upcall API keywords nfsd: Remove callback_cred nfsd: Use correct credential for NFSv4.0 callback with GSS sunrpc: Extract target name into svc_cred sunrpc: Enable the kernel to specify the hostname part of service principals sunrpc: Don't use stack buffer with scatterlist rpc: remove unneeded variable 'ret' in rdma_listen_handler nfsd: use true and false for boolean values nfsd: constify write_op[] fs/nfsd: Delete invalid assignment statements in nfsd4_decode_exchange_id NFSD: Handle full-length symlinks NFSD: Refactor the generic write vector fill helper svcrdma: Clean up Read chunk path svcrdma: Avoid releasing a page in svc_xprt_release() nfsd: Mark expected switch fall-through sunrpc: remove redundant variables 'checksumlen','blocksize' and 'data' nfsd: fix leaked file lock with nfs exported overlayfs nfsd: don't advertise a SCSI layout for an unsupported request_queue nfsd: fix corrupted reply to badly ordered compound nfsd: clarify check_op_ordering ...
Diffstat (limited to 'net/sunrpc/svc.c')
-rw-r--r--net/sunrpc/svc.c78
1 files changed, 29 insertions, 49 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 30a4226baf03..d13e05f1a990 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1537,16 +1537,16 @@ EXPORT_SYMBOL_GPL(svc_max_payload);
/**
* svc_fill_write_vector - Construct data argument for VFS write call
* @rqstp: svc_rqst to operate on
+ * @pages: list of pages containing data payload
* @first: buffer containing first section of write payload
* @total: total number of bytes of write payload
*
- * Returns the number of elements populated in the data argument array.
+ * Fills in rqstp::rq_vec, and returns the number of elements.
*/
-unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct kvec *first,
- size_t total)
+unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct page **pages,
+ struct kvec *first, size_t total)
{
struct kvec *vec = rqstp->rq_vec;
- struct page **pages;
unsigned int i;
/* Some types of transport can present the write payload
@@ -1560,14 +1560,11 @@ unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct kvec *first,
++i;
}
- WARN_ON_ONCE(rqstp->rq_arg.page_base != 0);
- pages = rqstp->rq_arg.pages;
while (total) {
vec[i].iov_base = page_address(*pages);
vec[i].iov_len = min_t(size_t, total, PAGE_SIZE);
total -= vec[i].iov_len;
++i;
-
++pages;
}
@@ -1580,65 +1577,48 @@ EXPORT_SYMBOL_GPL(svc_fill_write_vector);
* svc_fill_symlink_pathname - Construct pathname argument for VFS symlink call
* @rqstp: svc_rqst to operate on
* @first: buffer containing first section of pathname
+ * @p: buffer containing remaining section of pathname
* @total: total length of the pathname argument
*
- * Returns pointer to a NUL-terminated string, or an ERR_PTR. The buffer is
- * released automatically when @rqstp is recycled.
+ * The VFS symlink API demands a NUL-terminated pathname in mapped memory.
+ * Returns pointer to a NUL-terminated string, or an ERR_PTR. Caller must free
+ * the returned string.
*/
char *svc_fill_symlink_pathname(struct svc_rqst *rqstp, struct kvec *first,
- size_t total)
+ void *p, size_t total)
{
- struct xdr_buf *arg = &rqstp->rq_arg;
- struct page **pages;
- char *result;
-
- /* VFS API demands a NUL-terminated pathname. This function
- * uses a page from @rqstp as the pathname buffer, to enable
- * direct placement. Thus the total buffer size is PAGE_SIZE.
- * Space in this buffer for NUL-termination requires that we
- * cap the size of the returned symlink pathname just a
- * little early.
- */
- if (total > PAGE_SIZE - 1)
- return ERR_PTR(-ENAMETOOLONG);
+ size_t len, remaining;
+ char *result, *dst;
- /* Some types of transport can present the pathname entirely
- * in rq_arg.pages. If not, then copy the pathname into one
- * page.
- */
- pages = arg->pages;
- WARN_ON_ONCE(arg->page_base != 0);
- if (first->iov_base == 0) {
- result = page_address(*pages);
- result[total] = '\0';
- } else {
- size_t len, remaining;
- char *dst;
+ result = kmalloc(total + 1, GFP_KERNEL);
+ if (!result)
+ return ERR_PTR(-ESERVERFAULT);
- result = page_address(*(rqstp->rq_next_page++));
- dst = result;
- remaining = total;
+ dst = result;
+ remaining = total;
- len = min_t(size_t, total, first->iov_len);
+ len = min_t(size_t, total, first->iov_len);
+ if (len) {
memcpy(dst, first->iov_base, len);
dst += len;
remaining -= len;
+ }
- /* No more than one page left */
- if (remaining) {
- len = min_t(size_t, remaining, PAGE_SIZE);
- memcpy(dst, page_address(*pages), len);
- dst += len;
- }
-
- *dst = '\0';
+ if (remaining) {
+ len = min_t(size_t, remaining, PAGE_SIZE);
+ memcpy(dst, p, len);
+ dst += len;
}
- /* Sanity check: we don't allow the pathname argument to
+ *dst = '\0';
+
+ /* Sanity check: Linux doesn't allow the pathname argument to
* contain a NUL byte.
*/
- if (strlen(result) != total)
+ if (strlen(result) != total) {
+ kfree(result);
return ERR_PTR(-EINVAL);
+ }
return result;
}
EXPORT_SYMBOL_GPL(svc_fill_symlink_pathname);