فهرست منبع

[SCSI] iscsi_tcp: fix handling of data buffer padding

If we got the padding, data and header in different skbs,
we were not handling the padding correctly because we attributed it
to the data's skb. This resulted in the initiator reading from
pad bytes + skb offset instead of the correct offset.

If you could not connect with the open solaris target, this
will fix the lock up problem you were hitting.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Mike Christie 18 سال پیش
والد
کامیت
dbdb016d92
2فایلهای تغییر یافته به همراه43 افزوده شده و 19 حذف شده
  1. 42 19
      drivers/scsi/iscsi_tcp.c
  2. 1 0
      drivers/scsi/iscsi_tcp.h

+ 42 - 19
drivers/scsi/iscsi_tcp.c

@@ -896,11 +896,27 @@ more:
 		}
 		}
 	}
 	}
 
 
-	if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV) {
+	if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV &&
+	    tcp_conn->in.copy) {
 		uint32_t recv_digest;
 		uint32_t recv_digest;
 
 
 		debug_tcp("extra data_recv offset %d copy %d\n",
 		debug_tcp("extra data_recv offset %d copy %d\n",
 			  tcp_conn->in.offset, tcp_conn->in.copy);
 			  tcp_conn->in.offset, tcp_conn->in.copy);
+
+		if (!tcp_conn->data_copied) {
+			if (tcp_conn->in.padding) {
+				debug_tcp("padding -> %d\n",
+					  tcp_conn->in.padding);
+				memset(pad, 0, tcp_conn->in.padding);
+				sg_init_one(&sg, pad, tcp_conn->in.padding);
+				crypto_hash_update(&tcp_conn->rx_hash,
+						   &sg, sg.length);
+			}
+			crypto_hash_final(&tcp_conn->rx_hash,
+					  (u8 *) &tcp_conn->in.datadgst);
+			debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+		}
+
 		rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
 		rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
 		if (rc) {
 		if (rc) {
 			if (rc == -EAGAIN)
 			if (rc == -EAGAIN)
@@ -925,8 +941,7 @@ more:
 	}
 	}
 
 
 	if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
 	if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
-	   tcp_conn->in.copy) {
-
+	    tcp_conn->in.copy) {
 		debug_tcp("data_recv offset %d copy %d\n",
 		debug_tcp("data_recv offset %d copy %d\n",
 		       tcp_conn->in.offset, tcp_conn->in.copy);
 		       tcp_conn->in.offset, tcp_conn->in.copy);
 
 
@@ -937,24 +952,32 @@ more:
 			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 			return 0;
 			return 0;
 		}
 		}
-		tcp_conn->in.copy -= tcp_conn->in.padding;
-		tcp_conn->in.offset += tcp_conn->in.padding;
-		if (conn->datadgst_en) {
-			if (tcp_conn->in.padding) {
-				debug_tcp("padding -> %d\n",
-					  tcp_conn->in.padding);
-				memset(pad, 0, tcp_conn->in.padding);
-				sg_init_one(&sg, pad, tcp_conn->in.padding);
-				crypto_hash_update(&tcp_conn->rx_hash,
-						   &sg, sg.length);
-			}
-			crypto_hash_final(&tcp_conn->rx_hash,
-					  (u8 *) &tcp_conn->in.datadgst);
-			debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+
+		if (tcp_conn->in.padding)
+			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+		else if (conn->datadgst_en)
 			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
 			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
-			tcp_conn->data_copied = 0;
-		} else
+		else
+			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+		tcp_conn->data_copied = 0;
+	}
+
+	if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV &&
+	    tcp_conn->in.copy) {
+		int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied,
+				  tcp_conn->in.copy);
+
+		tcp_conn->in.copy -= copylen;
+		tcp_conn->in.offset += copylen;
+		tcp_conn->data_copied += copylen;
+
+		if (tcp_conn->data_copied != tcp_conn->in.padding)
+			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+		else if (conn->datadgst_en)
+			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+		else
 			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
 			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+		tcp_conn->data_copied = 0;
 	}
 	}
 
 
 	debug_tcp("f, processed %d from out of %d padding %d\n",
 	debug_tcp("f, processed %d from out of %d padding %d\n",

+ 1 - 0
drivers/scsi/iscsi_tcp.h

@@ -29,6 +29,7 @@
 #define IN_PROGRESS_HEADER_GATHER	0x1
 #define IN_PROGRESS_HEADER_GATHER	0x1
 #define IN_PROGRESS_DATA_RECV		0x2
 #define IN_PROGRESS_DATA_RECV		0x2
 #define IN_PROGRESS_DDIGEST_RECV	0x3
 #define IN_PROGRESS_DDIGEST_RECV	0x3
+#define IN_PROGRESS_PAD_RECV		0x4
 
 
 /* xmit state machine */
 /* xmit state machine */
 #define XMSTATE_IDLE			0x0
 #define XMSTATE_IDLE			0x0