summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/target/iscsi/iscsi_target.c27
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c1
-rw-r--r--include/target/iscsi/iscsi_target_core.h1
3 files changed, 26 insertions, 3 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 828697015759..8cdea25f1377 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1568,9 +1568,11 @@ iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1568{ 1568{
1569 struct kvec *iov; 1569 struct kvec *iov;
1570 u32 checksum, iov_count = 0, padding = 0, rx_got = 0, rx_size = 0; 1570 u32 checksum, iov_count = 0, padding = 0, rx_got = 0, rx_size = 0;
1571 u32 payload_length = ntoh24(hdr->dlength); 1571 u32 payload_length;
1572 int iov_ret, data_crc_failed = 0; 1572 int iov_ret, data_crc_failed = 0;
1573 1573
1574 payload_length = min_t(u32, cmd->se_cmd.data_length,
1575 ntoh24(hdr->dlength));
1574 rx_size += payload_length; 1576 rx_size += payload_length;
1575 iov = &cmd->iov_data[0]; 1577 iov = &cmd->iov_data[0];
1576 1578
@@ -2575,14 +2577,33 @@ static int iscsit_handle_immediate_data(
2575 u32 checksum, iov_count = 0, padding = 0; 2577 u32 checksum, iov_count = 0, padding = 0;
2576 struct iscsi_conn *conn = cmd->conn; 2578 struct iscsi_conn *conn = cmd->conn;
2577 struct kvec *iov; 2579 struct kvec *iov;
2580 void *overflow_buf = NULL;
2578 2581
2579 iov_ret = iscsit_map_iovec(cmd, cmd->iov_data, cmd->write_data_done, length); 2582 BUG_ON(cmd->write_data_done > cmd->se_cmd.data_length);
2583 rx_size = min(cmd->se_cmd.data_length - cmd->write_data_done, length);
2584 iov_ret = iscsit_map_iovec(cmd, cmd->iov_data, cmd->write_data_done,
2585 rx_size);
2580 if (iov_ret < 0) 2586 if (iov_ret < 0)
2581 return IMMEDIATE_DATA_CANNOT_RECOVER; 2587 return IMMEDIATE_DATA_CANNOT_RECOVER;
2582 2588
2583 rx_size = length;
2584 iov_count = iov_ret; 2589 iov_count = iov_ret;
2585 iov = &cmd->iov_data[0]; 2590 iov = &cmd->iov_data[0];
2591 if (rx_size < length) {
2592 /*
2593 * Special case: length of immediate data exceeds the data
2594 * buffer size derived from the CDB.
2595 */
2596 overflow_buf = kmalloc(length - rx_size, GFP_KERNEL);
2597 if (!overflow_buf) {
2598 iscsit_unmap_iovec(cmd);
2599 return IMMEDIATE_DATA_CANNOT_RECOVER;
2600 }
2601 cmd->overflow_buf = overflow_buf;
2602 iov[iov_count].iov_base = overflow_buf;
2603 iov[iov_count].iov_len = length - rx_size;
2604 iov_count++;
2605 rx_size = length;
2606 }
2586 2607
2587 padding = ((-length) & 3); 2608 padding = ((-length) & 3);
2588 if (padding != 0) { 2609 if (padding != 0) {
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 5b26bc23016a..fae85bfd790e 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -737,6 +737,7 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
737 kfree(cmd->pdu_list); 737 kfree(cmd->pdu_list);
738 kfree(cmd->seq_list); 738 kfree(cmd->seq_list);
739 kfree(cmd->tmr_req); 739 kfree(cmd->tmr_req);
740 kfree(cmd->overflow_buf);
740 kfree(cmd->iov_data); 741 kfree(cmd->iov_data);
741 kfree(cmd->text_in_ptr); 742 kfree(cmd->text_in_ptr);
742 743
diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h
index 24c398f4a68f..a49d37140a64 100644
--- a/include/target/iscsi/iscsi_target_core.h
+++ b/include/target/iscsi/iscsi_target_core.h
@@ -473,6 +473,7 @@ struct iscsi_cmd {
473 struct timer_list dataout_timer; 473 struct timer_list dataout_timer;
474 /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */ 474 /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */
475 struct kvec *iov_data; 475 struct kvec *iov_data;
476 void *overflow_buf;
476 /* Iovecs for miscellaneous purposes */ 477 /* Iovecs for miscellaneous purposes */
477#define ISCSI_MISC_IOVECS 5 478#define ISCSI_MISC_IOVECS 5
478 struct kvec iov_misc[ISCSI_MISC_IOVECS]; 479 struct kvec iov_misc[ISCSI_MISC_IOVECS];