Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 326291
b: refs/heads/master
c: 97bc00b
h: refs/heads/master
i:
  326289: 92efa01
  326287: 52baaf5
v: v3
  • Loading branch information
Jeff Layton authored and Steve French committed Sep 25, 2012
1 parent 7496a9e commit c0f25db
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b8eed28375a43e1c9aaa9d15af2a052aae0d0725
refs/heads/master: 97bc00b39408a4180eeeaa976d02d37121488997
56 changes: 54 additions & 2 deletions trunk/fs/cifs/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/tcp.h>
#include <linux/highmem.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <linux/mempool.h>
Expand Down Expand Up @@ -240,14 +241,47 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec,
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
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{
int rc;
struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec;
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;
int val = 1;

Expand All @@ -258,8 +292,26 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
(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 */
val = 0;
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
Expand Down

0 comments on commit c0f25db

Please sign in to comment.