aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2011-02-10 08:03:50 -0500
committerSteve French <sfrench@us.ibm.com>2011-02-10 22:59:12 -0500
commit71823baff1978be892e7a36eddf6170e1cc6650d (patch)
tree2cc136ce754cc5c24ed8aefde5e486fc873ae139
parent195291e68c2ad59a046fc56d32bf59635b100e5c (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>
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/connect.c30
-rw-r--r--fs/cifs/transport.c3
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;
639multi_t2_fnd: 649multi_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);