Commit 97bc00b39408a4180eeeaa976d02d37121488997
Committed by
Steve French
1 parent
b8eed28375
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 1 changed file with 54 additions and 2 deletions Side-by-side Diff
fs/cifs/transport.c
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | #include <linux/delay.h> |
29 | 29 | #include <linux/freezer.h> |
30 | 30 | #include <linux/tcp.h> |
31 | +#include <linux/highmem.h> | |
31 | 32 | #include <asm/uaccess.h> |
32 | 33 | #include <asm/processor.h> |
33 | 34 | #include <linux/mempool.h> |
... | ... | @@ -240,6 +241,38 @@ |
240 | 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 | 276 | static int |
244 | 277 | smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) |
245 | 278 | { |
... | ... | @@ -247,7 +280,8 @@ |
247 | 280 | struct kvec *iov = rqst->rq_iov; |
248 | 281 | int n_vec = rqst->rq_nvec; |
249 | 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 | 285 | struct socket *ssocket = server->ssocket; |
252 | 286 | int val = 1; |
253 | 287 | |
254 | 288 | |
... | ... | @@ -258,8 +292,26 @@ |
258 | 292 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |
259 | 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; | |
262 | 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 | + } | |
313 | + | |
314 | +uncork: | |
263 | 315 | /* uncork it */ |
264 | 316 | val = 0; |
265 | 317 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |