diff options
| author | Pavel Shilovsky <piastryyy@gmail.com> | 2011-08-01 05:19:41 -0400 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2011-08-01 08:49:34 -0400 |
| commit | e7015fb1c508fe9b8c97707755ce08f5ace0afb9 (patch) | |
| tree | 7c084839f5e163c9099c8c4f88422f97a048748e | |
| parent | 3d9c2472a53ee1d26de9803899037aeeb44ccef1 (diff) | |
CIFS: Simplify socket reading in demultiplex thread
Move reading to separate function and remove csocket variable.
Also change semantic in a little: goto incomplete_rcv only when
we get -EAGAIN (or a familiar error) while reading rfc1002 header.
In this case we don't check for echo timeout when we don't get whole
header at once, as it was before.
Reviewed-and-Tested-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
| -rw-r--r-- | fs/cifs/connect.c | 154 |
1 files changed, 71 insertions, 83 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 217d36587185..a2e9fcf4a996 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -359,6 +359,64 @@ allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size, | |||
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | static int | 361 | static int |
| 362 | read_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg, | ||
| 363 | struct kvec *iov, unsigned int to_read, | ||
| 364 | unsigned int *ptotal_read, bool is_header_read) | ||
| 365 | { | ||
| 366 | int length, rc = 0; | ||
| 367 | unsigned int total_read; | ||
| 368 | char *buf = iov->iov_base; | ||
| 369 | |||
| 370 | for (total_read = 0; total_read < to_read; total_read += length) { | ||
| 371 | length = kernel_recvmsg(server->ssocket, smb_msg, iov, 1, | ||
| 372 | to_read - total_read, 0); | ||
| 373 | if (server->tcpStatus == CifsExiting) { | ||
| 374 | /* then will exit */ | ||
| 375 | rc = 2; | ||
| 376 | break; | ||
| 377 | } else if (server->tcpStatus == CifsNeedReconnect) { | ||
| 378 | cifs_reconnect(server); | ||
| 379 | /* Reconnect wakes up rspns q */ | ||
| 380 | /* Now we will reread sock */ | ||
| 381 | rc = 1; | ||
| 382 | break; | ||
| 383 | } else if (length == -ERESTARTSYS || | ||
| 384 | length == -EAGAIN || | ||
| 385 | length == -EINTR) { | ||
| 386 | /* | ||
| 387 | * Minimum sleep to prevent looping, allowing socket | ||
| 388 | * to clear and app threads to set tcpStatus | ||
| 389 | * CifsNeedReconnect if server hung. | ||
| 390 | */ | ||
| 391 | usleep_range(1000, 2000); | ||
| 392 | length = 0; | ||
| 393 | if (!is_header_read) | ||
| 394 | continue; | ||
| 395 | /* Special handling for header read */ | ||
| 396 | if (total_read) { | ||
| 397 | iov->iov_base = (to_read - total_read) + | ||
| 398 | buf; | ||
| 399 | iov->iov_len = to_read - total_read; | ||
| 400 | smb_msg->msg_control = NULL; | ||
| 401 | smb_msg->msg_controllen = 0; | ||
| 402 | rc = 3; | ||
| 403 | } else | ||
| 404 | rc = 1; | ||
| 405 | break; | ||
| 406 | } else if (length <= 0) { | ||
| 407 | cERROR(1, "Received no data, expecting %d", | ||
| 408 | to_read - total_read); | ||
| 409 | cifs_reconnect(server); | ||
| 410 | rc = 1; | ||
| 411 | break; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 415 | *ptotal_read = total_read; | ||
| 416 | return rc; | ||
| 417 | } | ||
| 418 | |||
| 419 | static int | ||
| 362 | cifs_demultiplex_thread(void *p) | 420 | cifs_demultiplex_thread(void *p) |
| 363 | { | 421 | { |
| 364 | int length; | 422 | int length; |
| @@ -368,14 +426,13 @@ cifs_demultiplex_thread(void *p) | |||
| 368 | struct smb_hdr *smb_buffer = NULL; | 426 | struct smb_hdr *smb_buffer = NULL; |
| 369 | struct msghdr smb_msg; | 427 | struct msghdr smb_msg; |
| 370 | struct kvec iov; | 428 | struct kvec iov; |
| 371 | struct socket *csocket = server->ssocket; | ||
| 372 | struct list_head *tmp, *tmp2; | 429 | struct list_head *tmp, *tmp2; |
| 373 | struct task_struct *task_to_wake = NULL; | 430 | struct task_struct *task_to_wake = NULL; |
| 374 | struct mid_q_entry *mid_entry; | 431 | struct mid_q_entry *mid_entry; |
| 375 | char temp; | 432 | char temp; |
| 376 | bool isLargeBuf = false; | 433 | bool isLargeBuf = false; |
| 377 | bool isMultiRsp; | 434 | bool isMultiRsp; |
| 378 | int reconnect; | 435 | int rc; |
| 379 | 436 | ||
| 380 | current->flags |= PF_MEMALLOC; | 437 | current->flags |= PF_MEMALLOC; |
| 381 | cFYI(1, "Demultiplex PID: %d", task_pid_nr(current)); | 438 | cFYI(1, "Demultiplex PID: %d", task_pid_nr(current)); |
| @@ -412,51 +469,18 @@ incomplete_rcv: | |||
| 412 | "Reconnecting...", server->hostname, | 469 | "Reconnecting...", server->hostname, |
| 413 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); | 470 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); |
| 414 | cifs_reconnect(server); | 471 | cifs_reconnect(server); |
| 415 | csocket = server->ssocket; | ||
| 416 | wake_up(&server->response_q); | 472 | wake_up(&server->response_q); |
| 417 | continue; | 473 | continue; |
| 418 | } | 474 | } |
| 419 | 475 | ||
| 420 | length = | 476 | rc = read_from_socket(server, &smb_msg, &iov, pdu_length, |
| 421 | kernel_recvmsg(csocket, &smb_msg, | 477 | &total_read, true /* header read */); |
| 422 | &iov, 1, pdu_length, 0 /* BB other flags? */); | 478 | if (rc == 3) |
| 423 | 479 | goto incomplete_rcv; | |
| 424 | if (server->tcpStatus == CifsExiting) { | 480 | else if (rc == 2) |
| 425 | break; | 481 | break; |
| 426 | } else if (server->tcpStatus == CifsNeedReconnect) { | 482 | else if (rc == 1) |
| 427 | cFYI(1, "Reconnect after server stopped responding"); | ||
| 428 | cifs_reconnect(server); | ||
| 429 | cFYI(1, "call to reconnect done"); | ||
| 430 | csocket = server->ssocket; | ||
| 431 | continue; | ||
| 432 | } else if (length == -ERESTARTSYS || | ||
| 433 | length == -EAGAIN || | ||
| 434 | length == -EINTR) { | ||
| 435 | msleep(1); /* minimum sleep to prevent looping | ||
| 436 | allowing socket to clear and app threads to set | ||
| 437 | tcpStatus CifsNeedReconnect if server hung */ | ||
| 438 | if (pdu_length < 4) { | ||
| 439 | iov.iov_base = (4 - pdu_length) + buf; | ||
| 440 | iov.iov_len = pdu_length; | ||
| 441 | smb_msg.msg_control = NULL; | ||
| 442 | smb_msg.msg_controllen = 0; | ||
| 443 | goto incomplete_rcv; | ||
| 444 | } else | ||
| 445 | continue; | ||
| 446 | } else if (length <= 0) { | ||
| 447 | cFYI(1, "Reconnect after unexpected peek error %d", | ||
| 448 | length); | ||
| 449 | cifs_reconnect(server); | ||
| 450 | csocket = server->ssocket; | ||
| 451 | wake_up(&server->response_q); | ||
| 452 | continue; | 483 | continue; |
| 453 | } else if (length < pdu_length) { | ||
| 454 | cFYI(1, "requested %d bytes but only got %d bytes", | ||
| 455 | pdu_length, length); | ||
| 456 | pdu_length -= length; | ||
| 457 | msleep(1); | ||
| 458 | goto incomplete_rcv; | ||
| 459 | } | ||
| 460 | 484 | ||
| 461 | /* The right amount was read from socket - 4 bytes */ | 485 | /* The right amount was read from socket - 4 bytes */ |
| 462 | /* so we can now interpret the length field */ | 486 | /* so we can now interpret the length field */ |
| @@ -493,14 +517,12 @@ incomplete_rcv: | |||
| 493 | cifs_set_port((struct sockaddr *) | 517 | cifs_set_port((struct sockaddr *) |
| 494 | &server->dstaddr, CIFS_PORT); | 518 | &server->dstaddr, CIFS_PORT); |
| 495 | cifs_reconnect(server); | 519 | cifs_reconnect(server); |
| 496 | csocket = server->ssocket; | ||
| 497 | wake_up(&server->response_q); | 520 | wake_up(&server->response_q); |
| 498 | continue; | 521 | continue; |
| 499 | } else if (temp != (char) 0) { | 522 | } else if (temp != (char) 0) { |
| 500 | cERROR(1, "Unknown RFC 1002 frame"); | 523 | cERROR(1, "Unknown RFC 1002 frame"); |
| 501 | cifs_dump_mem(" Received Data: ", buf, length); | 524 | cifs_dump_mem(" Received Data: ", buf, length); |
| 502 | cifs_reconnect(server); | 525 | cifs_reconnect(server); |
| 503 | csocket = server->ssocket; | ||
| 504 | continue; | 526 | continue; |
| 505 | } | 527 | } |
| 506 | 528 | ||
| @@ -510,59 +532,25 @@ incomplete_rcv: | |||
| 510 | cERROR(1, "Invalid size SMB length %d pdu_length %d", | 532 | cERROR(1, "Invalid size SMB length %d pdu_length %d", |
| 511 | length, pdu_length+4); | 533 | length, pdu_length+4); |
| 512 | cifs_reconnect(server); | 534 | cifs_reconnect(server); |
| 513 | csocket = server->ssocket; | ||
| 514 | wake_up(&server->response_q); | 535 | wake_up(&server->response_q); |
| 515 | continue; | 536 | continue; |
| 516 | } | 537 | } |
| 517 | 538 | ||
| 518 | /* else length ok */ | 539 | /* else length ok */ |
| 519 | reconnect = 0; | ||
| 520 | |||
| 521 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { | 540 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { |
| 522 | isLargeBuf = true; | 541 | isLargeBuf = true; |
| 523 | memcpy(bigbuf, smallbuf, 4); | 542 | memcpy(bigbuf, smallbuf, 4); |
| 524 | smb_buffer = (struct smb_hdr *)bigbuf; | 543 | smb_buffer = (struct smb_hdr *)bigbuf; |
| 525 | buf = bigbuf; | 544 | buf = bigbuf; |
| 526 | } | 545 | } |
| 527 | length = 0; | 546 | |
| 528 | iov.iov_base = 4 + buf; | 547 | iov.iov_base = 4 + buf; |
| 529 | iov.iov_len = pdu_length; | 548 | iov.iov_len = pdu_length; |
| 530 | for (total_read = 0; total_read < pdu_length; | 549 | rc = read_from_socket(server, &smb_msg, &iov, pdu_length, |
| 531 | total_read += length) { | 550 | &total_read, false); |
| 532 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, | 551 | if (rc == 2) |
| 533 | pdu_length - total_read, 0); | ||
| 534 | if (server->tcpStatus == CifsExiting) { | ||
| 535 | /* then will exit */ | ||
| 536 | reconnect = 2; | ||
| 537 | break; | ||
| 538 | } else if (server->tcpStatus == CifsNeedReconnect) { | ||
| 539 | cifs_reconnect(server); | ||
| 540 | csocket = server->ssocket; | ||
| 541 | /* Reconnect wakes up rspns q */ | ||
| 542 | /* Now we will reread sock */ | ||
| 543 | reconnect = 1; | ||
| 544 | break; | ||
| 545 | } else if (length == -ERESTARTSYS || | ||
| 546 | length == -EAGAIN || | ||
| 547 | length == -EINTR) { | ||
| 548 | msleep(1); /* minimum sleep to prevent looping, | ||
| 549 | allowing socket to clear and app | ||
| 550 | threads to set tcpStatus | ||
| 551 | CifsNeedReconnect if server hung*/ | ||
| 552 | length = 0; | ||
| 553 | continue; | ||
| 554 | } else if (length <= 0) { | ||
| 555 | cERROR(1, "Received no data, expecting %d", | ||
| 556 | pdu_length - total_read); | ||
| 557 | cifs_reconnect(server); | ||
| 558 | csocket = server->ssocket; | ||
| 559 | reconnect = 1; | ||
| 560 | break; | ||
| 561 | } | ||
| 562 | } | ||
| 563 | if (reconnect == 2) | ||
| 564 | break; | 552 | break; |
| 565 | else if (reconnect == 1) | 553 | else if (rc == 1) |
| 566 | continue; | 554 | continue; |
| 567 | 555 | ||
| 568 | total_read += 4; /* account for rfc1002 hdr */ | 556 | total_read += 4; /* account for rfc1002 hdr */ |
| @@ -705,7 +693,7 @@ multi_t2_fnd: | |||
| 705 | msleep(125); | 693 | msleep(125); |
| 706 | 694 | ||
| 707 | if (server->ssocket) { | 695 | if (server->ssocket) { |
| 708 | sock_release(csocket); | 696 | sock_release(server->ssocket); |
| 709 | server->ssocket = NULL; | 697 | server->ssocket = NULL; |
| 710 | } | 698 | } |
| 711 | /* buffer usually freed in free_mid - need to free it here on exit */ | 699 | /* buffer usually freed in free_mid - need to free it here on exit */ |
