diff options
author | Jeff Layton <jlayton@redhat.com> | 2011-02-10 08:03:50 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2011-02-10 22:59:12 -0500 |
commit | 71823baff1978be892e7a36eddf6170e1cc6650d (patch) | |
tree | 2cc136ce754cc5c24ed8aefde5e486fc873ae139 /fs/cifs | |
parent | 195291e68c2ad59a046fc56d32bf59635b100e5c (diff) |
cifs: don't always drop malformed replies on the floor (try #3)
Slight revision to this patch...use min_t() instead of conditional
assignment. Also, remove the FIXME comment and replace it with the
explanation that Steve gave earlier.
After receiving a packet, we currently check the header. If it's no
good, then we toss it out and continue the loop, leaving the caller
waiting on that response.
In cases where the packet has length inconsistencies, but the MID is
valid, this leads to unneeded delays. That's especially problematic now
that the client waits indefinitely for responses.
Instead, don't immediately discard the packet if checkSMB fails. Try to
find a matching mid_q_entry, mark it as having a malformed response and
issue the callback.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/connect.c | 30 | ||||
-rw-r--r-- | fs/cifs/transport.c | 3 |
3 files changed, 28 insertions, 7 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1ab33eb71d95..17afb0fbcaed 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -654,7 +654,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
654 | #define MID_REQUEST_SUBMITTED 2 | 654 | #define MID_REQUEST_SUBMITTED 2 |
655 | #define MID_RESPONSE_RECEIVED 4 | 655 | #define MID_RESPONSE_RECEIVED 4 |
656 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ | 656 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ |
657 | #define MID_NO_RESP_NEEDED 0x10 | 657 | #define MID_RESPONSE_MALFORMED 0x10 |
658 | 658 | ||
659 | /* Types of response buffer returned from SendReceive2 */ | 659 | /* Types of response buffer returned from SendReceive2 */ |
660 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ | 660 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 161f24ca4f6e..8d6c17ab593d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -586,11 +586,20 @@ incomplete_rcv: | |||
586 | total_read += 4; /* account for rfc1002 hdr */ | 586 | total_read += 4; /* account for rfc1002 hdr */ |
587 | 587 | ||
588 | dump_smb(smb_buffer, total_read); | 588 | dump_smb(smb_buffer, total_read); |
589 | if (checkSMB(smb_buffer, smb_buffer->Mid, total_read)) { | 589 | |
590 | /* | ||
591 | * We know that we received enough to get to the MID as we | ||
592 | * checked the pdu_length earlier. Now check to see | ||
593 | * if the rest of the header is OK. We borrow the length | ||
594 | * var for the rest of the loop to avoid a new stack var. | ||
595 | * | ||
596 | * 48 bytes is enough to display the header and a little bit | ||
597 | * into the payload for debugging purposes. | ||
598 | */ | ||
599 | length = checkSMB(smb_buffer, smb_buffer->Mid, total_read); | ||
600 | if (length != 0) | ||
590 | cifs_dump_mem("Bad SMB: ", smb_buffer, | 601 | cifs_dump_mem("Bad SMB: ", smb_buffer, |
591 | total_read < 48 ? total_read : 48); | 602 | min_t(unsigned int, total_read, 48)); |
592 | continue; | ||
593 | } | ||
594 | 603 | ||
595 | mid_entry = NULL; | 604 | mid_entry = NULL; |
596 | server->lstrp = jiffies; | 605 | server->lstrp = jiffies; |
@@ -602,7 +611,8 @@ incomplete_rcv: | |||
602 | if ((mid_entry->mid == smb_buffer->Mid) && | 611 | if ((mid_entry->mid == smb_buffer->Mid) && |
603 | (mid_entry->midState == MID_REQUEST_SUBMITTED) && | 612 | (mid_entry->midState == MID_REQUEST_SUBMITTED) && |
604 | (mid_entry->command == smb_buffer->Command)) { | 613 | (mid_entry->command == smb_buffer->Command)) { |
605 | if (check2ndT2(smb_buffer,server->maxBuf) > 0) { | 614 | if (length == 0 && |
615 | check2ndT2(smb_buffer, server->maxBuf) > 0) { | ||
606 | /* We have a multipart transact2 resp */ | 616 | /* We have a multipart transact2 resp */ |
607 | isMultiRsp = true; | 617 | isMultiRsp = true; |
608 | if (mid_entry->resp_buf) { | 618 | if (mid_entry->resp_buf) { |
@@ -637,7 +647,12 @@ incomplete_rcv: | |||
637 | mid_entry->resp_buf = smb_buffer; | 647 | mid_entry->resp_buf = smb_buffer; |
638 | mid_entry->largeBuf = isLargeBuf; | 648 | mid_entry->largeBuf = isLargeBuf; |
639 | multi_t2_fnd: | 649 | multi_t2_fnd: |
640 | mid_entry->midState = MID_RESPONSE_RECEIVED; | 650 | if (length == 0) |
651 | mid_entry->midState = | ||
652 | MID_RESPONSE_RECEIVED; | ||
653 | else | ||
654 | mid_entry->midState = | ||
655 | MID_RESPONSE_MALFORMED; | ||
641 | #ifdef CONFIG_CIFS_STATS2 | 656 | #ifdef CONFIG_CIFS_STATS2 |
642 | mid_entry->when_received = jiffies; | 657 | mid_entry->when_received = jiffies; |
643 | #endif | 658 | #endif |
@@ -658,6 +673,9 @@ multi_t2_fnd: | |||
658 | else | 673 | else |
659 | smallbuf = NULL; | 674 | smallbuf = NULL; |
660 | } | 675 | } |
676 | } else if (length != 0) { | ||
677 | /* response sanity checks failed */ | ||
678 | continue; | ||
661 | } else if (!is_valid_oplock_break(smb_buffer, server) && | 679 | } else if (!is_valid_oplock_break(smb_buffer, server) && |
662 | !isMultiRsp) { | 680 | !isMultiRsp) { |
663 | cERROR(1, "No task to wake, unknown frame received! " | 681 | cERROR(1, "No task to wake, unknown frame received! " |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index fbc5aace54b1..46d8756f2b24 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -457,6 +457,9 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) | |||
457 | case MID_RETRY_NEEDED: | 457 | case MID_RETRY_NEEDED: |
458 | rc = -EAGAIN; | 458 | rc = -EAGAIN; |
459 | break; | 459 | break; |
460 | case MID_RESPONSE_MALFORMED: | ||
461 | rc = -EIO; | ||
462 | break; | ||
460 | default: | 463 | default: |
461 | cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, | 464 | cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, |
462 | mid->mid, mid->midState); | 465 | mid->mid, mid->midState); |