Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97bc00b3 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French
Browse files

cifs: teach smb_send_rqst how to handle arrays of pages



Add code that allows smb_send_rqst to send an array of pages after the
initial kvec array has been sent. For now, we simply kmap the page
array and send it using the standard smb_send_kvec function. Eventually,
we may want to convert this code to use kernel_sendpage under the hood
and avoid the kmap altogether for the page data.

Reviewed-by: default avatarPavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent b8eed283
Loading
Loading
Loading
Loading
+54 −2
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/freezer.h>
#include <linux/tcp.h>
#include <linux/tcp.h>
#include <linux/highmem.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/processor.h>
#include <linux/mempool.h>
#include <linux/mempool.h>
@@ -240,6 +241,38 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec,
	return rc;
	return rc;
}
}


/**
 * rqst_page_to_kvec - Turn a slot in the smb_rqst page array into a kvec
 * @rqst: pointer to smb_rqst
 * @idx: index into the array of the page
 * @iov: pointer to struct kvec that will hold the result
 *
 * Helper function to convert a slot in the rqst->rq_pages array into a kvec.
 * The page will be kmapped and the address placed into iov_base. The length
 * will then be adjusted according to the ptailoff.
 */
static void
cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
			struct kvec *iov)
{
	/*
	 * FIXME: We could avoid this kmap altogether if we used
	 * kernel_sendpage instead of kernel_sendmsg. That will only
	 * work if signing is disabled though as sendpage inlines the
	 * page directly into the fraglist. If userspace modifies the
	 * page after we calculate the signature, then the server will
	 * reject it and may break the connection. kernel_sendmsg does
	 * an extra copy of the data and avoids that issue.
	 */
	iov->iov_base = kmap(rqst->rq_pages[idx]);

	/* if last page, don't send beyond this offset into page */
	if (idx == (rqst->rq_npages - 1))
		iov->iov_len = rqst->rq_tailsz;
	else
		iov->iov_len = rqst->rq_pagesz;
}

static int
static int
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{
{
@@ -247,7 +280,8 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
	struct kvec *iov = rqst->rq_iov;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	int n_vec = rqst->rq_nvec;
	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
	size_t total_len;
	unsigned int i;
	size_t total_len = 0, sent;
	struct socket *ssocket = server->ssocket;
	struct socket *ssocket = server->ssocket;
	int val = 1;
	int val = 1;


@@ -258,8 +292,26 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
				(char *)&val, sizeof(val));
				(char *)&val, sizeof(val));


	rc = smb_send_kvec(server, iov, n_vec, &total_len);
	rc = smb_send_kvec(server, iov, n_vec, &sent);
	if (rc < 0)
		goto uncork;

	total_len += sent;

	/* now walk the page array and send each page in it */
	for (i = 0; i < rqst->rq_npages; i++) {
		struct kvec p_iov;

		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
		rc = smb_send_kvec(server, &p_iov, 1, &sent);
		kunmap(rqst->rq_pages[i]);
		if (rc < 0)
			break;

		total_len += sent;
	}


uncork:
	/* uncork it */
	/* uncork it */
	val = 0;
	val = 0;
	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,