diff options
author | Jeff Layton <jlayton@redhat.com> | 2011-10-19 15:28:17 -0400 |
---|---|---|
committer | Jeff Layton <jlayton@redhat.com> | 2011-10-19 15:28:17 -0400 |
commit | 42c4dfc213190fafffc53815c2ee6064430bc379 (patch) | |
tree | 9d012e1c190f2e54324c7e44350e2b5bc28cfa0b /fs/cifs | |
parent | 7748dd6eab8e13f974d4664395e76afffacda04b (diff) |
cifs: turn read_from_socket into a wrapper around a vectorized version
Eventually we'll want to allow cifsd to read data directly into the
pagecache. In order to do that we'll need a routine that can take a
kvec array and pass that directly to kernel_recvmsg.
Unfortunately though, the kernel's recvmsg routines modify the kvec
array that gets passed in, so we need to use a copy of the kvec array
and refresh that copy on each pass through the loop.
Reviewed-and-Tested-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/connect.c | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 97a65af2a08a..4860940b748b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -375,14 +375,54 @@ server_unresponsive(struct TCP_Server_Info *server) | |||
375 | return false; | 375 | return false; |
376 | } | 376 | } |
377 | 377 | ||
378 | /* | ||
379 | * kvec_array_init - clone a kvec array, and advance into it | ||
380 | * @new: pointer to memory for cloned array | ||
381 | * @iov: pointer to original array | ||
382 | * @nr_segs: number of members in original array | ||
383 | * @bytes: number of bytes to advance into the cloned array | ||
384 | * | ||
385 | * This function will copy the array provided in iov to a section of memory | ||
386 | * and advance the specified number of bytes into the new array. It returns | ||
387 | * the number of segments in the new array. "new" must be at least as big as | ||
388 | * the original iov array. | ||
389 | */ | ||
390 | static unsigned int | ||
391 | kvec_array_init(struct kvec *new, struct kvec *iov, unsigned int nr_segs, | ||
392 | size_t bytes) | ||
393 | { | ||
394 | size_t base = 0; | ||
395 | |||
396 | while (bytes || !iov->iov_len) { | ||
397 | int copy = min(bytes, iov->iov_len); | ||
398 | |||
399 | bytes -= copy; | ||
400 | base += copy; | ||
401 | if (iov->iov_len == base) { | ||
402 | iov++; | ||
403 | nr_segs--; | ||
404 | base = 0; | ||
405 | } | ||
406 | } | ||
407 | memcpy(new, iov, sizeof(*iov) * nr_segs); | ||
408 | new->iov_base += base; | ||
409 | new->iov_len -= base; | ||
410 | return nr_segs; | ||
411 | } | ||
412 | |||
378 | static int | 413 | static int |
379 | read_from_socket(struct TCP_Server_Info *server, char *buf, | 414 | readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, |
380 | unsigned int to_read) | 415 | unsigned int nr_segs, unsigned int to_read) |
381 | { | 416 | { |
382 | int length = 0; | 417 | int length = 0; |
383 | int total_read; | 418 | int total_read; |
419 | unsigned int segs; | ||
384 | struct msghdr smb_msg; | 420 | struct msghdr smb_msg; |
385 | struct kvec iov; | 421 | struct kvec *iov; |
422 | |||
423 | iov = kmalloc(sizeof(*iov_orig) * nr_segs, GFP_NOFS); | ||
424 | if (!iov) | ||
425 | return -ENOMEM; | ||
386 | 426 | ||
387 | smb_msg.msg_control = NULL; | 427 | smb_msg.msg_control = NULL; |
388 | smb_msg.msg_controllen = 0; | 428 | smb_msg.msg_controllen = 0; |
@@ -393,10 +433,11 @@ read_from_socket(struct TCP_Server_Info *server, char *buf, | |||
393 | break; | 433 | break; |
394 | } | 434 | } |
395 | 435 | ||
396 | iov.iov_base = buf + total_read; | 436 | segs = kvec_array_init(iov, iov_orig, nr_segs, total_read); |
397 | iov.iov_len = to_read; | 437 | |
398 | length = kernel_recvmsg(server->ssocket, &smb_msg, &iov, 1, | 438 | length = kernel_recvmsg(server->ssocket, &smb_msg, |
399 | to_read, 0); | 439 | iov, segs, to_read, 0); |
440 | |||
400 | if (server->tcpStatus == CifsExiting) { | 441 | if (server->tcpStatus == CifsExiting) { |
401 | total_read = -ESHUTDOWN; | 442 | total_read = -ESHUTDOWN; |
402 | break; | 443 | break; |
@@ -423,9 +464,22 @@ read_from_socket(struct TCP_Server_Info *server, char *buf, | |||
423 | break; | 464 | break; |
424 | } | 465 | } |
425 | } | 466 | } |
467 | kfree(iov); | ||
426 | return total_read; | 468 | return total_read; |
427 | } | 469 | } |
428 | 470 | ||
471 | static int | ||
472 | read_from_socket(struct TCP_Server_Info *server, char *buf, | ||
473 | unsigned int to_read) | ||
474 | { | ||
475 | struct kvec iov; | ||
476 | |||
477 | iov.iov_base = buf; | ||
478 | iov.iov_len = to_read; | ||
479 | |||
480 | return readv_from_socket(server, &iov, 1, to_read); | ||
481 | } | ||
482 | |||
429 | static bool | 483 | static bool |
430 | is_smb_response(struct TCP_Server_Info *server, unsigned char type) | 484 | is_smb_response(struct TCP_Server_Info *server, unsigned char type) |
431 | { | 485 | { |