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: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
b8eed28375
commit
97bc00b394
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue