From 50bd0364d6237bfdb82d267ba523456385da7e30 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Thu, 3 Oct 2019 16:06:09 +0900 Subject: [PATCH] lib/iscsi: Separate PDU header and payload handing for SCSI Data-Out To use zero copy bdev I/O APIs, we have to allocate iSCSI task before allocating data buffer. Hence we separate PDU header and payload handling for SCSI Data-Out, and include iSCSI task allocation into PDU header handling. Factor out PDU header handling in iscsi_op_data() into iscsi_pdu_hdr_op_data(). spdk_nvmf_tcp_h2c_data_hdr_handle() and spdk_nvmf_tcp_h2c_data_payload_handle() in lib/nvmf/tcp.c are used as a reference implementation. Use pdu->task to pass the task allocated by iscsi_pdu_hdr_op_data() into iscsi_op_data(). In iscsi_op_data(), if it sees pdu->is_rejected is true or pdu->task is NULL, do nothing. Besides, check LUN hot plug again to separate PDU header handling and PDU payload handling. Signed-off-by: Shuhei Matsumoto Change-Id: I5074e945254081960744577e4ed8e0170793e5e0 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/470291 Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Ben Walker Community-CI: Broadcom SPDK FC-NVMe CI --- lib/iscsi/iscsi.c | 106 ++++++++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/lib/iscsi/iscsi.c b/lib/iscsi/iscsi.c index d4503c389..f1715b23e 100644 --- a/lib/iscsi/iscsi.c +++ b/lib/iscsi/iscsi.c @@ -4392,18 +4392,15 @@ iscsi_pdu_hdr_op_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) } static int -iscsi_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 iscsi_bhs_data_out *reqh; struct spdk_scsi_lun *lun_dev; uint32_t transfer_tag; uint32_t task_tag; - uint32_t transfer_len; uint32_t DataSN; uint32_t buffer_offset; - uint32_t len; - int F_bit; int rc; int reject_reason = ISCSI_REASON_INVALID_PDU_FIELD; @@ -4412,18 +4409,17 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) return SPDK_ISCSI_CONNECTION_FATAL; } - if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) { - reject_reason = ISCSI_REASON_PROTOCOL_ERROR; - goto reject_return; - } - reqh = (struct iscsi_bhs_data_out *)&pdu->bhs; - F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL); transfer_tag = from_be32(&reqh->ttt); task_tag = from_be32(&reqh->itt); DataSN = from_be32(&reqh->data_sn); buffer_offset = from_be32(&reqh->buffer_offset); + if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) { + reject_reason = ISCSI_REASON_PROTOCOL_ERROR; + goto reject_return; + } + task = get_transfer_task(conn, transfer_tag); if (task == NULL) { SPDK_ERRLOG("Not found task for transfer_tag=%x\n", transfer_tag); @@ -4458,26 +4454,13 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) return SPDK_ISCSI_CONNECTION_FATAL; } - transfer_len = task->scsi.transfer_len; - task->current_r2t_length += pdu->data_segment_len; - task->next_expected_r2t_offset += pdu->data_segment_len; - task->r2t_datasn++; - - if (task->current_r2t_length > conn->sess->MaxBurstLength) { - SPDK_ERRLOG("R2T burst(%u) > MaxBurstLength(%u)\n", - task->current_r2t_length, + if (task->current_r2t_length + pdu->data_segment_len > conn->sess->MaxBurstLength) { + SPDK_ERRLOG("R2T burst(%zu) > MaxBurstLength(%u)\n", + task->current_r2t_length + pdu->data_segment_len, conn->sess->MaxBurstLength); return SPDK_ISCSI_CONNECTION_FATAL; } - if (F_bit) { - /* - * This R2T burst is done. Clear the length before we - * receive a PDU for the next R2T burst. - */ - task->current_r2t_length = 0; - } - subtask = spdk_iscsi_task_get(conn, task, spdk_iscsi_task_cpl); if (subtask == NULL) { SPDK_ERRLOG("Unable to acquire subtask\n"); @@ -4485,12 +4468,70 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) } subtask->scsi.offset = buffer_offset; subtask->scsi.length = pdu->data_segment_len; + spdk_iscsi_task_associate_pdu(subtask, pdu); + + if (lun_dev == NULL) { + SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "LUN %d is removed, complete the task immediately\n", + task->lun_id); + subtask->scsi.transfer_len = subtask->scsi.length; + spdk_scsi_task_process_null_lun(&subtask->scsi); + spdk_iscsi_task_cpl(&subtask->scsi); + return 0; + } + + pdu->task = subtask; + return 0; + +send_r2t_recovery_return: + rc = iscsi_send_r2t_recovery(conn, task, task->acked_r2tsn, true); + if (rc == 0) { + return 0; + } + +reject_return: + return iscsi_reject(conn, pdu, reject_reason); +} + +static int +iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) +{ + struct spdk_iscsi_task *task, *subtask; + struct iscsi_bhs_data_out *reqh; + uint32_t transfer_len; + uint32_t len; + int F_bit; + int rc; + + rc = iscsi_pdu_hdr_op_data(conn, pdu); + if (rc != 0 || pdu->is_rejected || pdu->task == NULL) { + return rc; + } + + subtask = pdu->task; + task = spdk_iscsi_task_get_primary(subtask); + assert(task != subtask); + + reqh = (struct iscsi_bhs_data_out *)&pdu->bhs; + F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL); + + transfer_len = task->scsi.transfer_len; + task->current_r2t_length += pdu->data_segment_len; + task->next_expected_r2t_offset += pdu->data_segment_len; + task->r2t_datasn++; + + if (F_bit) { + /* + * This R2T burst is done. Clear the length before we + * receive a PDU for the next R2T burst. + */ + task->current_r2t_length = 0; + } + if (spdk_likely(!pdu->dif_insert_or_strip)) { spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_segment_len); } else { spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_buf_len); } - spdk_iscsi_task_associate_pdu(subtask, pdu); if (task->next_expected_r2t_offset == transfer_len) { task->acked_r2tsn++; @@ -4506,7 +4547,7 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) task->next_r2t_offset += len; } - if (lun_dev == NULL) { + if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) { SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "LUN %d is removed, complete the task immediately\n", task->lun_id); subtask->scsi.transfer_len = subtask->scsi.length; @@ -4517,15 +4558,6 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu) iscsi_queue_task(conn, subtask); return 0; - -send_r2t_recovery_return: - rc = iscsi_send_r2t_recovery(conn, task, task->acked_r2tsn, true); - if (rc == 0) { - return 0; - } - -reject_return: - return iscsi_reject(conn, pdu, reject_reason); } static void