diff options
Diffstat (limited to 'fs/cifs')
-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 */ |