lib/iscsi: Create subtask after reading data segment for Data-OUT PDU

The following patches will change the handler for Data-OUT PDU to
submit subtask only when 64KB data is read or F bit is set.

Previously, we had created a subtask when processing header and
before reading data segment.  Creating a subtask beforehand is not
convenient for the following changes.

Hence create a subtask after reading data segment.

If LUN is removed while processing the Data-OUT PDU, the corresponding
primary task will be terminated by iscsi_clear_all_transfer_task(),
and any subtask completion is not sent to initiator. Hence we can
reject the received Data-OUT PDU safely.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: Ifb6d6988676080b458b31d12fef065f3c1de0cb6
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/6415
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Shuhei Matsumoto 2021-02-16 10:17:25 +09:00 committed by Tomasz Zawadzki
parent 59237d22b8
commit 2ef97692bc
2 changed files with 34 additions and 61 deletions

View File

@ -4142,7 +4142,7 @@ iscsi_pdu_hdr_op_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
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)
{ {
struct spdk_iscsi_task *task, *subtask; struct spdk_iscsi_task *task;
struct iscsi_bhs_data_out *reqh; struct iscsi_bhs_data_out *reqh;
struct spdk_scsi_lun *lun_dev; struct spdk_scsi_lun *lun_dev;
uint32_t transfer_tag; uint32_t transfer_tag;
@ -4225,15 +4225,6 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
task->current_r2t_length = 0; task->current_r2t_length = 0;
} }
subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
if (subtask == NULL) {
SPDK_ERRLOG("Unable to acquire subtask\n");
return SPDK_ISCSI_CONNECTION_FATAL;
}
subtask->scsi.offset = buffer_offset;
subtask->scsi.length = pdu->data_segment_len;
iscsi_task_associate_pdu(subtask, pdu);
if (task->next_expected_r2t_offset == transfer_len) { if (task->next_expected_r2t_offset == transfer_len) {
task->acked_r2tsn++; task->acked_r2tsn++;
} else if (F_bit && (task->next_r2t_offset < transfer_len)) { } else if (F_bit && (task->next_r2t_offset < transfer_len)) {
@ -4249,61 +4240,55 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
} }
if (lun_dev == NULL) { if (lun_dev == NULL) {
SPDK_DEBUGLOG(iscsi, "LUN %d is removed, complete the task immediately\n", SPDK_DEBUGLOG(iscsi, "LUN %d is removed, reject this PDU.\n",
task->lun_id); task->lun_id);
subtask->scsi.transfer_len = subtask->scsi.length; return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
spdk_scsi_task_process_null_lun(&subtask->scsi); } else if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(lun_dev, &task->scsi, &pdu->dif_ctx))) {
iscsi_task_cpl(&subtask->scsi);
return 0;
}
if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(lun_dev, &subtask->scsi, &pdu->dif_ctx))) {
pdu->dif_insert_or_strip = true; pdu->dif_insert_or_strip = true;
} }
pdu->task = subtask;
return 0; return 0;
} }
static int static int
iscsi_pdu_payload_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) iscsi_pdu_payload_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
{ {
struct spdk_iscsi_task *subtask; struct spdk_iscsi_task *task, *subtask;
struct iscsi_bhs_data_out *reqh; struct iscsi_bhs_data_out *reqh;
uint32_t transfer_tag; uint32_t transfer_tag;
uint32_t buffer_offset;
if (pdu->task == NULL) {
return 0;
}
subtask = pdu->task;
reqh = (struct iscsi_bhs_data_out *)&pdu->bhs; reqh = (struct iscsi_bhs_data_out *)&pdu->bhs;
transfer_tag = from_be32(&reqh->ttt); transfer_tag = from_be32(&reqh->ttt);
buffer_offset = from_be32(&reqh->buffer_offset);
if (get_transfer_task(conn, transfer_tag) == NULL) { task = get_transfer_task(conn, transfer_tag);
if (spdk_unlikely(task == NULL)) {
SPDK_ERRLOG("Not found for transfer_tag=%x\n", transfer_tag); SPDK_ERRLOG("Not found for transfer_tag=%x\n", transfer_tag);
subtask->scsi.transfer_len = subtask->scsi.length; return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
spdk_scsi_task_process_abort(&subtask->scsi);
iscsi_task_cpl(&subtask->scsi);
return 0;
} }
if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
SPDK_DEBUGLOG(iscsi, "LUN %d is removed, reject this PDU.\n",
task->lun_id);
return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
}
subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
if (subtask == NULL) {
SPDK_ERRLOG("Unable to acquire subtask\n");
return SPDK_ISCSI_CONNECTION_FATAL;
}
subtask->scsi.offset = buffer_offset;
subtask->scsi.length = pdu->data_segment_len;
iscsi_task_associate_pdu(subtask, pdu);
if (spdk_likely(!pdu->dif_insert_or_strip)) { if (spdk_likely(!pdu->dif_insert_or_strip)) {
spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_segment_len); spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_segment_len);
} else { } else {
spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_buf_len); spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_buf_len);
} }
if (spdk_scsi_dev_get_lun(conn->dev, subtask->lun_id) == NULL) {
SPDK_DEBUGLOG(iscsi, "LUN %d is removed, complete the task immediately\n",
subtask->lun_id);
subtask->scsi.transfer_len = subtask->scsi.length;
spdk_scsi_task_process_null_lun(&subtask->scsi);
iscsi_task_cpl(&subtask->scsi);
return 0;
}
iscsi_queue_task(conn, subtask); iscsi_queue_task(conn, subtask);
return 0; return 0;
} }

View File

@ -1858,7 +1858,7 @@ check_iscsi_r2t(struct spdk_iscsi_task *task, uint32_t len)
rsph = (struct iscsi_bhs_r2t *)&rsp_pdu->bhs; rsph = (struct iscsi_bhs_r2t *)&rsp_pdu->bhs;
CU_ASSERT(rsph->opcode == ISCSI_OP_R2T); CU_ASSERT(rsph->opcode == ISCSI_OP_R2T);
CU_ASSERT(from_be64(&rsph->lun) == spdk_scsi_lun_id_int_to_fmt(task->lun_id)); CU_ASSERT(from_be64(&rsph->lun) == spdk_scsi_lun_id_int_to_fmt(task->lun_id));
CU_ASSERT(from_be32(&rsph->buffer_offset) == task->next_r2t_offset); CU_ASSERT(from_be32(&rsph->buffer_offset) + len == task->next_r2t_offset);
CU_ASSERT(from_be32(&rsph->desired_xfer_len) == len); CU_ASSERT(from_be32(&rsph->desired_xfer_len) == len);
TAILQ_REMOVE(&g_write_pdu_list, rsp_pdu, tailq); TAILQ_REMOVE(&g_write_pdu_list, rsp_pdu, tailq);
@ -1955,10 +1955,10 @@ pdu_hdr_op_data_test(void)
rc = iscsi_pdu_hdr_op_data(&conn, &pdu); rc = iscsi_pdu_hdr_op_data(&conn, &pdu);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
CU_ASSERT(pdu.task == NULL); check_iscsi_reject(&pdu, ISCSI_REASON_PROTOCOL_ERROR);
/* Case 10 - SCSI Data-Out PDU is correct and processed. Created task is held /* Case 10 - SCSI Data-Out PDU is correct and processed. Its F bit is 0 and hence
* to the PDU, but its F bit is 0 and hence R2T is not sent. * R2T is not sent.
*/ */
dev.lun[0] = &lun; dev.lun[0] = &lun;
to_be32(&data_reqh->data_sn, primary.r2t_datasn); to_be32(&data_reqh->data_sn, primary.r2t_datasn);
@ -1966,12 +1966,11 @@ pdu_hdr_op_data_test(void)
rc = iscsi_pdu_hdr_op_data(&conn, &pdu); rc = iscsi_pdu_hdr_op_data(&conn, &pdu);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
CU_ASSERT(pdu.task != NULL); CU_ASSERT(!pdu.is_rejected);
iscsi_task_put(pdu.task);
pdu.task = NULL; pdu.task = NULL;
/* Case 11 - SCSI Data-Out PDU is correct and processed. Created task is held /* Case 11 - SCSI Data-Out PDU is correct and processed. Its F bit is 1 and hence
* to the PDU, and Its F bit is 1 and hence R2T is sent. * R2T is sent.
*/ */
data_reqh->flags |= ISCSI_FLAG_FINAL; data_reqh->flags |= ISCSI_FLAG_FINAL;
to_be32(&data_reqh->data_sn, primary.r2t_datasn); to_be32(&data_reqh->data_sn, primary.r2t_datasn);
@ -1980,19 +1979,8 @@ pdu_hdr_op_data_test(void)
rc = iscsi_pdu_hdr_op_data(&conn, &pdu); rc = iscsi_pdu_hdr_op_data(&conn, &pdu);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
CU_ASSERT(pdu.task != NULL); CU_ASSERT(!pdu.is_rejected);
check_iscsi_r2t(pdu.task, pdu.data_segment_len * 4); check_iscsi_r2t(&primary, pdu.data_segment_len * 4);
iscsi_task_put(pdu.task);
/* Case 12 - Task pool is empty. */
to_be32(&data_reqh->data_sn, primary.r2t_datasn);
to_be32(&data_reqh->buffer_offset, primary.next_expected_r2t_offset);
g_task_pool_is_empty = true;
rc = iscsi_pdu_hdr_op_data(&conn, &pdu);
CU_ASSERT(rc == SPDK_ISCSI_CONNECTION_FATAL);
g_task_pool_is_empty = false;
} }
/* Test an ISCSI_OP_TEXT PDU with CONTINUE bit set but /* Test an ISCSI_OP_TEXT PDU with CONTINUE bit set but