diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-09-16 19:55:47 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-09-16 19:47:07 -0400 |
commit | 40b054970afcf067896d62cd6f7e617c62665304 (patch) | |
tree | 5596f2b4fa1c1f41f599caf21bd5d10681ab152b /drivers/target/iscsi | |
parent | 2ff017f5b4299e24a7f22d9a336dd162bf52bb54 (diff) |
iscsi-target: Fix sendpage breakage with proper padding+DataDigest iovec offsets
This patch fixes a bug in the iscsit_fe_sendpage_sg() transmit codepath that
was originally introduced with the v3.1 iscsi-target merge that incorrectly
uses hardcoded cmd->iov_data_count values to determine cmd->iov_data[] offsets
for extra outgoing padding and DataDigest payload vectors.
This code is obviously incorrect for the DataDigest enabled case with sendpage
offload, and this fix ensures correct operation for padding + DataDigest,
padding only, and DataDigest only cases. The bug was introduced during a
pre-merge change in iscsit_fe_sendpage_sg() to natively use struct scatterlist
instead of the legacy v3.0 struct se_mem logic.
Cc: Andy Grover <agrover@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/iscsi')
-rw-r--r-- | drivers/target/iscsi/iscsi_target_util.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 1d1b4fe33e43..f00137f377b2 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c | |||
@@ -1256,7 +1256,7 @@ int iscsit_fe_sendpage_sg( | |||
1256 | struct kvec iov; | 1256 | struct kvec iov; |
1257 | u32 tx_hdr_size, data_len; | 1257 | u32 tx_hdr_size, data_len; |
1258 | u32 offset = cmd->first_data_sg_off; | 1258 | u32 offset = cmd->first_data_sg_off; |
1259 | int tx_sent; | 1259 | int tx_sent, iov_off; |
1260 | 1260 | ||
1261 | send_hdr: | 1261 | send_hdr: |
1262 | tx_hdr_size = ISCSI_HDR_LEN; | 1262 | tx_hdr_size = ISCSI_HDR_LEN; |
@@ -1276,9 +1276,19 @@ send_hdr: | |||
1276 | } | 1276 | } |
1277 | 1277 | ||
1278 | data_len = cmd->tx_size - tx_hdr_size - cmd->padding; | 1278 | data_len = cmd->tx_size - tx_hdr_size - cmd->padding; |
1279 | if (conn->conn_ops->DataDigest) | 1279 | /* |
1280 | * Set iov_off used by padding and data digest tx_data() calls below | ||
1281 | * in order to determine proper offset into cmd->iov_data[] | ||
1282 | */ | ||
1283 | if (conn->conn_ops->DataDigest) { | ||
1280 | data_len -= ISCSI_CRC_LEN; | 1284 | data_len -= ISCSI_CRC_LEN; |
1281 | 1285 | if (cmd->padding) | |
1286 | iov_off = (cmd->iov_data_count - 2); | ||
1287 | else | ||
1288 | iov_off = (cmd->iov_data_count - 1); | ||
1289 | } else { | ||
1290 | iov_off = (cmd->iov_data_count - 1); | ||
1291 | } | ||
1282 | /* | 1292 | /* |
1283 | * Perform sendpage() for each page in the scatterlist | 1293 | * Perform sendpage() for each page in the scatterlist |
1284 | */ | 1294 | */ |
@@ -1307,8 +1317,7 @@ send_pg: | |||
1307 | 1317 | ||
1308 | send_padding: | 1318 | send_padding: |
1309 | if (cmd->padding) { | 1319 | if (cmd->padding) { |
1310 | struct kvec *iov_p = | 1320 | struct kvec *iov_p = &cmd->iov_data[iov_off++]; |
1311 | &cmd->iov_data[cmd->iov_data_count-1]; | ||
1312 | 1321 | ||
1313 | tx_sent = tx_data(conn, iov_p, 1, cmd->padding); | 1322 | tx_sent = tx_data(conn, iov_p, 1, cmd->padding); |
1314 | if (cmd->padding != tx_sent) { | 1323 | if (cmd->padding != tx_sent) { |
@@ -1322,8 +1331,7 @@ send_padding: | |||
1322 | 1331 | ||
1323 | send_datacrc: | 1332 | send_datacrc: |
1324 | if (conn->conn_ops->DataDigest) { | 1333 | if (conn->conn_ops->DataDigest) { |
1325 | struct kvec *iov_d = | 1334 | struct kvec *iov_d = &cmd->iov_data[iov_off]; |
1326 | &cmd->iov_data[cmd->iov_data_count]; | ||
1327 | 1335 | ||
1328 | tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); | 1336 | tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); |
1329 | if (ISCSI_CRC_LEN != tx_sent) { | 1337 | if (ISCSI_CRC_LEN != tx_sent) { |