]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.fixes/libiscsi-fix-data-corruption
Imported linux-2.6.27.39 suse/xen patches.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.fixes / libiscsi-fix-data-corruption
1 From: Mike Christie <michaelc@cs.wisc.edu>
2 Date: Wed, 24 Sep 2008 11:46:09 -0500
3 Subject: libiscsi: fix data corruption when target has to resend data-in packets
4 References: bnc#472432
5 X-Git: 1d9edf0270cb5a434d32e95279ce9493581906b3
6
7 iscsi_tcp was updating the exp_statsn (exp_statsn acknowledges
8 status and tells the target it is ok to let the resources for
9 a iscsi pdu to be reused) before it got all the data for pdu read
10 into OS buffers. Data corruption was occuring if something happens
11 to a packet and the network layer requests a retransmit, and the
12 initiator has told the target about the udpated exp_statsn ack,
13 then the target may be sending data from a buffer it has reused
14 for a new iscsi pdu. This fixes the problem by having the LLD
15 (iscsi_tcp in this case) just handle the transferring of data, and
16 has libiscsi handle the processing of status (libiscsi completion
17 processing is done after LLD data transfers are complete).
18
19 Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
20 Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
21 Signed-off-by: Hannes Reinecke <hare@suse.de>
22 ---
23 drivers/scsi/iscsi_tcp.c | 29 +++++------------------------
24 drivers/scsi/libiscsi.c | 41 +++++++++++++++++++++++++++++++++++------
25 2 files changed, 40 insertions(+), 30 deletions(-)
26
27 diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
28 index 25094c9..babe81a 100644
29 --- a/drivers/scsi/iscsi_tcp.c
30 +++ b/drivers/scsi/iscsi_tcp.c
31 @@ -530,22 +530,20 @@ iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task)
32 EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
33
34 /**
35 - * iscsi_data_rsp - SCSI Data-In Response processing
36 + * iscsi_data_in - SCSI Data-In Response processing
37 * @conn: iscsi connection
38 * @task: scsi command task
39 **/
40 static int
41 -iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
42 +iscsi_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
43 {
44 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
45 struct iscsi_tcp_task *tcp_task = task->dd_data;
46 struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
47 - struct iscsi_session *session = conn->session;
48 - struct scsi_cmnd *sc = task->sc;
49 int datasn = be32_to_cpu(rhdr->datasn);
50 - unsigned total_in_length = scsi_in(sc)->length;
51 + unsigned total_in_length = scsi_in(task->sc)->length;
52
53 - iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
54 + iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
55 if (tcp_conn->in.datalen == 0)
56 return 0;
57
58 @@ -565,23 +563,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
59 return ISCSI_ERR_DATA_OFFSET;
60 }
61
62 - if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
63 - sc->result = (DID_OK << 16) | rhdr->cmd_status;
64 - conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
65 - if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
66 - ISCSI_FLAG_DATA_OVERFLOW)) {
67 - int res_count = be32_to_cpu(rhdr->residual_count);
68 -
69 - if (res_count > 0 &&
70 - (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
71 - res_count <= total_in_length))
72 - scsi_in(sc)->resid = res_count;
73 - else
74 - sc->result = (DID_BAD_TARGET << 16) |
75 - rhdr->cmd_status;
76 - }
77 - }
78 -
79 conn->datain_pdus_cnt++;
80 return 0;
81 }
82 @@ -781,7 +762,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
83 if (!task)
84 rc = ISCSI_ERR_BAD_ITT;
85 else
86 - rc = iscsi_data_rsp(conn, task);
87 + rc = iscsi_data_in(conn, task);
88 if (rc) {
89 spin_unlock(&conn->session->lock);
90 break;
91 diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
92 index e7624db..8905895 100644
93 --- a/drivers/scsi/libiscsi.c
94 +++ b/drivers/scsi/libiscsi.c
95 @@ -645,6 +645,40 @@ out:
96 __iscsi_put_task(task);
97 }
98
99 +/**
100 + * iscsi_data_in_rsp - SCSI Data-In Response processing
101 + * @conn: iscsi connection
102 + * @hdr: iscsi pdu
103 + * @task: scsi command task
104 + **/
105 +static void
106 +iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
107 + struct iscsi_task *task)
108 +{
109 + struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)hdr;
110 + struct scsi_cmnd *sc = task->sc;
111 +
112 + if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
113 + return;
114 +
115 + sc->result = (DID_OK << 16) | rhdr->cmd_status;
116 + conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
117 + if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
118 + ISCSI_FLAG_DATA_OVERFLOW)) {
119 + int res_count = be32_to_cpu(rhdr->residual_count);
120 +
121 + if (res_count > 0 &&
122 + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
123 + res_count <= scsi_in(sc)->length))
124 + scsi_in(sc)->resid = res_count;
125 + else
126 + sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
127 + }
128 +
129 + conn->scsirsp_pdus_cnt++;
130 + __iscsi_put_task(task);
131 +}
132 +
133 static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
134 {
135 struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
136 @@ -911,12 +945,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
137 iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
138 break;
139 case ISCSI_OP_SCSI_DATA_IN:
140 - if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
141 - conn->scsirsp_pdus_cnt++;
142 - iscsi_update_cmdsn(session,
143 - (struct iscsi_nopin*) hdr);
144 - __iscsi_put_task(task);
145 - }
146 + iscsi_data_in_rsp(conn, hdr, task);
147 break;
148 case ISCSI_OP_LOGOUT_RSP:
149 iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
150 --
151 1.6.0.2
152