diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-09-18 19:20:35 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-09-24 22:46:31 -0400 |
commit | 97bc00b39408a4180eeeaa976d02d37121488997 (patch) | |
tree | 99a139bd0a2a1bd93cd372caf8e9318e2a75043c /fs/cifs | |
parent | b8eed28375a43e1c9aaa9d15af2a052aae0d0725 (diff) |
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>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/transport.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 8ff4c5f3670..381dbb77847 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/freezer.h> | 29 | #include <linux/freezer.h> |
30 | #include <linux/tcp.h> | 30 | #include <linux/tcp.h> |
31 | #include <linux/highmem.h> | ||
31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
32 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
33 | #include <linux/mempool.h> | 34 | #include <linux/mempool.h> |
@@ -240,6 +241,38 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | |||
240 | return rc; | 241 | return rc; |
241 | } | 242 | } |
242 | 243 | ||
244 | /** | ||
245 | * rqst_page_to_kvec - Turn a slot in the smb_rqst page array into a kvec | ||
246 | * @rqst: pointer to smb_rqst | ||
247 | * @idx: index into the array of the page | ||
248 | * @iov: pointer to struct kvec that will hold the result | ||
249 | * | ||
250 | * Helper function to convert a slot in the rqst->rq_pages array into a kvec. | ||
251 | * The page will be kmapped and the address placed into iov_base. The length | ||
252 | * will then be adjusted according to the ptailoff. | ||
253 | */ | ||
254 | static void | ||
255 | cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, | ||
256 | struct kvec *iov) | ||
257 | { | ||
258 | /* | ||
259 | * FIXME: We could avoid this kmap altogether if we used | ||
260 | * kernel_sendpage instead of kernel_sendmsg. That will only | ||
261 | * work if signing is disabled though as sendpage inlines the | ||
262 | * page directly into the fraglist. If userspace modifies the | ||
263 | * page after we calculate the signature, then the server will | ||
264 | * reject it and may break the connection. kernel_sendmsg does | ||
265 | * an extra copy of the data and avoids that issue. | ||
266 | */ | ||
267 | iov->iov_base = kmap(rqst->rq_pages[idx]); | ||
268 | |||
269 | /* if last page, don't send beyond this offset into page */ | ||
270 | if (idx == (rqst->rq_npages - 1)) | ||
271 | iov->iov_len = rqst->rq_tailsz; | ||
272 | else | ||
273 | iov->iov_len = rqst->rq_pagesz; | ||
274 | } | ||
275 | |||
243 | static int | 276 | static int |
244 | smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | 277 | smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) |
245 | { | 278 | { |
@@ -247,7 +280,8 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
247 | struct kvec *iov = rqst->rq_iov; | 280 | struct kvec *iov = rqst->rq_iov; |
248 | int n_vec = rqst->rq_nvec; | 281 | int n_vec = rqst->rq_nvec; |
249 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); | 282 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); |
250 | size_t total_len; | 283 | unsigned int i; |
284 | size_t total_len = 0, sent; | ||
251 | struct socket *ssocket = server->ssocket; | 285 | struct socket *ssocket = server->ssocket; |
252 | int val = 1; | 286 | int val = 1; |
253 | 287 | ||
@@ -258,8 +292,26 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
258 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, | 292 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |
259 | (char *)&val, sizeof(val)); | 293 | (char *)&val, sizeof(val)); |
260 | 294 | ||
261 | rc = smb_send_kvec(server, iov, n_vec, &total_len); | 295 | rc = smb_send_kvec(server, iov, n_vec, &sent); |
296 | if (rc < 0) | ||
297 | goto uncork; | ||
298 | |||
299 | total_len += sent; | ||
300 | |||
301 | /* now walk the page array and send each page in it */ | ||
302 | for (i = 0; i < rqst->rq_npages; i++) { | ||
303 | struct kvec p_iov; | ||
304 | |||
305 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | ||
306 | rc = smb_send_kvec(server, &p_iov, 1, &sent); | ||
307 | kunmap(rqst->rq_pages[i]); | ||
308 | if (rc < 0) | ||
309 | break; | ||
310 | |||
311 | total_len += sent; | ||
312 | } | ||
262 | 313 | ||
314 | uncork: | ||
263 | /* uncork it */ | 315 | /* uncork it */ |
264 | val = 0; | 316 | val = 0; |
265 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, | 317 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |