iscsi: fix segfault when r2t
Fixes #2781 This patch fixes two issue causing segfault on r2t: 1. pdu buffer is allocated from immediate_data_pool, but data_buf_len is set as data_out_pool 2. task->desired_data_transfer_length is rewrite by iscsi_send_r2t, which causes a wrong calculated pdu->data_buf_len Signed-off-by: melon.masou <melon.masou@outlook.com> Change-Id: I151859afff7104f29ad7f0ec57a8479d88b742bd Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15542 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
3d9b062852
commit
565a44628d
@ -4156,6 +4156,16 @@ iscsi_pdu_hdr_op_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
iscsi_get_mobj_max_data_len(struct spdk_mobj *mobj)
|
||||||
|
{
|
||||||
|
if (mobj->mp == g_iscsi.pdu_immediate_data_pool) {
|
||||||
|
return iscsi_get_max_immediate_data_size();
|
||||||
|
} else {
|
||||||
|
return SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
||||||
{
|
{
|
||||||
@ -4169,6 +4179,7 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
|||||||
uint32_t DataSN;
|
uint32_t DataSN;
|
||||||
uint32_t buffer_offset;
|
uint32_t buffer_offset;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
uint32_t current_desired_data_transfer_length;
|
||||||
int F_bit;
|
int F_bit;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -4195,6 +4206,7 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
lun_dev = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
|
lun_dev = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
|
||||||
|
current_desired_data_transfer_length = task->desired_data_transfer_length;
|
||||||
|
|
||||||
if (pdu->data_segment_len > task->desired_data_transfer_length) {
|
if (pdu->data_segment_len > task->desired_data_transfer_length) {
|
||||||
SPDK_ERRLOG("the dataout pdu data length is larger than the value sent by R2T PDU\n");
|
SPDK_ERRLOG("the dataout pdu data length is larger than the value sent by R2T PDU\n");
|
||||||
@ -4272,7 +4284,7 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
|||||||
* SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH to merge them into a
|
* SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH to merge them into a
|
||||||
* single subtask.
|
* single subtask.
|
||||||
*/
|
*/
|
||||||
pdu->data_buf_len = spdk_min(task->desired_data_transfer_length,
|
pdu->data_buf_len = spdk_min(current_desired_data_transfer_length,
|
||||||
SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -4280,7 +4292,7 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
|||||||
pdu->mobj[0] = mobj;
|
pdu->mobj[0] = mobj;
|
||||||
pdu->data = (void *)((uint64_t)mobj->buf + mobj->data_len);
|
pdu->data = (void *)((uint64_t)mobj->buf + mobj->data_len);
|
||||||
pdu->data_from_mempool = true;
|
pdu->data_from_mempool = true;
|
||||||
pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(iscsi_get_mobj_max_data_len(mobj));
|
||||||
|
|
||||||
iscsi_task_set_mobj(task, NULL);
|
iscsi_task_set_mobj(task, NULL);
|
||||||
}
|
}
|
||||||
@ -4626,7 +4638,7 @@ iscsi_pdu_payload_read(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
|||||||
pdu->mobj[0] = mobj;
|
pdu->mobj[0] = mobj;
|
||||||
pdu->data = mobj->buf;
|
pdu->data = mobj->buf;
|
||||||
pdu->data_from_mempool = true;
|
pdu->data_from_mempool = true;
|
||||||
} else if (mobj->data_len == SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH && read_len > 0) {
|
} else if (mobj->data_len == iscsi_get_mobj_max_data_len(mobj) && read_len > 0) {
|
||||||
mobj = pdu->mobj[1];
|
mobj = pdu->mobj[1];
|
||||||
if (mobj == NULL) {
|
if (mobj == NULL) {
|
||||||
/* The first data buffer just ran out. Allocate the second data buffer and
|
/* The first data buffer just ran out. Allocate the second data buffer and
|
||||||
@ -4650,7 +4662,7 @@ iscsi_pdu_payload_read(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* copy the actual data into local buffer */
|
/* copy the actual data into local buffer */
|
||||||
read_len = spdk_min(read_len, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH - mobj->data_len);
|
read_len = spdk_min(read_len, iscsi_get_mobj_max_data_len(mobj) - mobj->data_len);
|
||||||
|
|
||||||
if (read_len > 0) {
|
if (read_len > 0) {
|
||||||
rc = iscsi_conn_read_data_segment(conn,
|
rc = iscsi_conn_read_data_segment(conn,
|
||||||
|
@ -122,6 +122,21 @@ DEFINE_STUB(spdk_scsi_lun_get_dif_ctx, bool,
|
|||||||
(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task,
|
(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task,
|
||||||
struct spdk_dif_ctx *dif_ctx), false);
|
struct spdk_dif_ctx *dif_ctx), false);
|
||||||
|
|
||||||
|
static void
|
||||||
|
alloc_mock_mobj(struct spdk_mobj *mobj, int len)
|
||||||
|
{
|
||||||
|
mobj->buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(len));
|
||||||
|
SPDK_CU_ASSERT_FATAL(mobj->buf != NULL);
|
||||||
|
|
||||||
|
g_iscsi.pdu_immediate_data_pool = (struct spdk_mempool *)100;
|
||||||
|
g_iscsi.pdu_data_out_pool = (struct spdk_mempool *)200;
|
||||||
|
if (len == SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
|
||||||
|
mobj->mp = g_iscsi.pdu_data_out_pool;
|
||||||
|
} else {
|
||||||
|
mobj->mp = g_iscsi.pdu_immediate_data_pool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
op_login_check_target_test(void)
|
op_login_check_target_test(void)
|
||||||
{
|
{
|
||||||
@ -2037,11 +2052,8 @@ pdu_payload_read_test(void)
|
|||||||
|
|
||||||
g_iscsi.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
|
g_iscsi.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
|
||||||
|
|
||||||
mobj1.buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH));
|
alloc_mock_mobj(&mobj1, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||||
SPDK_CU_ASSERT_FATAL(mobj1.buf != NULL);
|
alloc_mock_mobj(&mobj2, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||||
|
|
||||||
mobj2.buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH));
|
|
||||||
SPDK_CU_ASSERT_FATAL(mobj2.buf != NULL);
|
|
||||||
|
|
||||||
MOCK_SET(spdk_mempool_get, &mobj1);
|
MOCK_SET(spdk_mempool_get, &mobj1);
|
||||||
|
|
||||||
@ -2212,14 +2224,9 @@ data_out_pdu_sequence_test(void)
|
|||||||
|
|
||||||
TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq);
|
TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq);
|
||||||
|
|
||||||
mobj1.buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH));
|
alloc_mock_mobj(&mobj1, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||||
SPDK_CU_ASSERT_FATAL(mobj1.buf != NULL);
|
alloc_mock_mobj(&mobj2, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||||
|
alloc_mock_mobj(&mobj3, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||||
mobj2.buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH));
|
|
||||||
SPDK_CU_ASSERT_FATAL(mobj2.buf != NULL);
|
|
||||||
|
|
||||||
mobj3.buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH));
|
|
||||||
SPDK_CU_ASSERT_FATAL(mobj3.buf != NULL);
|
|
||||||
|
|
||||||
/* Test scenario is as follows.
|
/* Test scenario is as follows.
|
||||||
*
|
*
|
||||||
@ -2382,8 +2389,7 @@ immediate_data_and_data_out_pdu_sequence_test(void)
|
|||||||
|
|
||||||
TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq);
|
TAILQ_INSERT_TAIL(&dev.luns, &lun, tailq);
|
||||||
|
|
||||||
mobj.buf = calloc(1, SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH));
|
alloc_mock_mobj(&mobj, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||||
SPDK_CU_ASSERT_FATAL(mobj.buf != NULL);
|
|
||||||
|
|
||||||
/* Test scenario is as follows.
|
/* Test scenario is as follows.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user