From a5eec7a4b1ba615fb77e744fc614360ddc715f16 Mon Sep 17 00:00:00 2001 From: Sebastian Vater Date: Mon, 29 Sep 2025 16:58:27 +0200 Subject: Images are now propagated as a read-only SCSI device in iSCSI implementation and WRITE operations return correct SCSI sense key, ASC and ASCQ in an attempt to write to a read-only device. Finally, another valgrind SCSI INQUIRY memleak fixed. --- src/server/iscsi.c | 42 +++++++++++++++++++++++++++++++++++------- src/server/iscsi.h | 17 +++++++++++++---- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/server/iscsi.c b/src/server/iscsi.c index 05c8876..d833076 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -3737,7 +3737,7 @@ int iscsi_scsi_pr_release_scsi2(iscsi_scsi_task *scsi_task) * @retval false The I/O feature is NOT supported for the * DNBD3 image. */ -static inline bool iscsi_scsi_emu_io_type_is_supported(const dnbd3_image_t *image, int type) +static inline bool iscsi_scsi_emu_io_type_is_supported(const dnbd3_image_t *image, const int type) { // TODO: Actually implement this function. @@ -3757,6 +3757,16 @@ static inline bool iscsi_scsi_emu_io_type_is_supported(const dnbd3_image_t *imag break; } + case ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY : { + return false; + + break; + } + case ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT : { + return true; + + break; + } case ISCSI_SCSI_EMU_IO_TYPE_WRITE_CACHE : { return false; @@ -4152,7 +4162,7 @@ uint8_t *iscsi_scsi_emu_block_write_complete_callback(dnbd3_image_t *image, uint if ( success ) scsi_task->status = ISCSI_SCSI_STATUS_GOOD; else - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_MEDIUM_ERR, ISCSI_SCSI_ASC_UNRECOVERED_READ_ERR, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_MEDIUM_ERR, ISCSI_SCSI_ASC_WRITE_ERR, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); iscsi_scsi_lun_task_complete( scsi_task->lun, scsi_task ); @@ -4192,11 +4202,23 @@ int iscsi_scsi_emu_io_blocks_write(iscsi_scsi_task *scsi_task, uint8_t *buf, dnb { uint64_t offset_bytes; const uint64_t num_bytes = iscsi_scsi_emu_blocks_to_bytes( &offset_bytes, offset_blocks, num_blocks, block_size ); - const int64_t len = pwrite( image->readFd, buf, (size_t) num_bytes, offset_bytes ); // TODO: Make write I/O async + const int64_t len = pwrite( image->readFd, buf, (size_t) num_bytes, offset_bytes ); // TODO: Make read I/O async const bool success = ((uint64_t) len == num_bytes); - scsi_task->xfer_pos = scsi_task->len; - callback( image, user_data, success ); + // TODO: Begin remove after I/O async implementation + uint64_t *exec_data = malloc( 64 ); + + exec_data[2] = (uint64_t *) callback; + exec_data[3] = 3ULL; + exec_data[4] = (dnbd3_image_t *) image; + exec_data[5] = user_data; + exec_data[6] = success; + + iscsi_list_enqueue( &iscsi_globvec->exec_queue, (iscsi_node *) exec_data ); + // TODO: End remove after I/O async implementation + + // scsi_task->xfer_pos = scsi_task->len; + // callback( image, user_data, success ); return (success ? 0 : -1); } @@ -4286,6 +4308,10 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task } rc = iscsi_scsi_emu_io_blocks_read( scsi_task, scsi_task->buf, image, offset_blocks, num_blocks, block_size, iscsi_scsi_emu_block_read_complete_callback, (uint8_t *) scsi_task ); + } else if ( iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY ) || iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT ) ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_DATA_PROTECT, ISCSI_SCSI_ASC_WRITE_PROTECTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + + return ISCSI_SCSI_TASK_RUN_COMPLETE; } else if ( (flags & ISCSI_SCSI_EMU_BLOCK_FLAGS_VERIFY) != 0 ) { if ( scsi_task->len != (block_size + block_size) ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); @@ -5215,6 +5241,8 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task alloc_len = sizeof(struct iscsi_scsi_vpd_page_block_limits_inquiry_data_packet); + vpd_page_block_limits_inquiry_data_pkt->flags = 0; + uint32_t blocks = (ISCSI_SCSI_EMU_MAX_XFER_LEN >> iscsi_scsi_emu_block_get_size_shift( image )); if ( blocks > 255UL ) @@ -5846,14 +5874,14 @@ static int iscsi_scsi_emu_primary_mode_sense(dnbd3_image_t *image, iscsi_scsi_ta if ( hdr_len == sizeof(struct iscsi_scsi_mode_sense_6_parameter_header_data_packet) ) { mode_sense_6_parameter_hdr_data_pkt->mode_data_len = (uint8_t) (alloc_len - sizeof(uint8_t)); mode_sense_6_parameter_hdr_data_pkt->medium_type = 0U; - mode_sense_6_parameter_hdr_data_pkt->flags = 0; + mode_sense_6_parameter_hdr_data_pkt->flags = (int8_t) ((iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY ) || iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT )) ? ISCSI_SCSI_MODE_SENSE_6_PARAM_HDR_DATA_FLAGS_WP : 0); mode_sense_6_parameter_hdr_data_pkt->block_desc_len = (uint8_t) block_desc_len; } else { iscsi_scsi_mode_sense_10_parameter_header_data_packet *mode_sense_10_parameter_hdr_data_pkt = (iscsi_scsi_mode_sense_10_parameter_header_data_packet *) mode_sense_6_parameter_hdr_data_pkt; iscsi_put_be16( (uint8_t *) &mode_sense_10_parameter_hdr_data_pkt->mode_data_len, (uint16_t) (alloc_len - sizeof(uint16_t)) ); mode_sense_10_parameter_hdr_data_pkt->medium_type = 0U; - mode_sense_10_parameter_hdr_data_pkt->flags = 0; + mode_sense_10_parameter_hdr_data_pkt->flags = (int8_t) ((iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY ) || iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT )) ? ISCSI_SCSI_MODE_SENSE_10_PARAM_HDR_DATA_FLAGS_WP : 0); mode_sense_10_parameter_hdr_data_pkt->long_lba = (uint8_t) long_lba; mode_sense_10_parameter_hdr_data_pkt->reserved = 0U; iscsi_put_be16( (uint8_t *) &mode_sense_10_parameter_hdr_data_pkt->block_desc_len, (uint16_t) block_desc_len ); diff --git a/src/server/iscsi.h b/src/server/iscsi.h index 6f48e80..4ee5dac 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -10123,6 +10123,9 @@ void iscsi_portal_destroy(iscsi_portal *portal); /// iSCSI SCSI Additional Sense Code (ASC): Warning. #define ISCSI_SCSI_ASC_WARNING 0x0B +/// iSCSI SCSI Additional Sense Code (ASC): Write error. +#define ISCSI_SCSI_ASC_WRITE_ERR 0x0C + /// iSCSI SCSI Additional Sense Code (ASC): Block guard check failed. #define ISCSI_SCSI_ASC_LOGICAL_BLOCK_GUARD_CHECK_FAIL 0x10 @@ -10487,16 +10490,22 @@ typedef struct iscsi_scsi_task { /// iSCSI SCSI emulation I/O type: Removable. -#define ISCSI_SCSI_EMU_IO_TYPE_REMOVABLE (1 << 0) +#define ISCSI_SCSI_EMU_IO_TYPE_REMOVABLE (1 << 0) /// iSCSI SCSI emulation I/O type: Unmap. -#define ISCSI_SCSI_EMU_IO_TYPE_UNMAP (1 << 1) +#define ISCSI_SCSI_EMU_IO_TYPE_UNMAP (1 << 1) /// iSCSI SCSI emulation I/O type: Non-rotating medium (e.g., solid state). -#define ISCSI_SCSI_EMU_IO_TYPE_NO_ROTATION (1 << 2) +#define ISCSI_SCSI_EMU_IO_TYPE_NO_ROTATION (1 << 2) + +/// iSCSI SCSI emulation I/O type: Physical read only device. +#define ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY (1 << 3) + +/// iSCSI SCSI emulation I/O type: Device is (temporarily) write protected. +#define ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT (1 << 4) /// iSCSI SCSI emulation I/O type: Write cache available. -#define ISCSI_SCSI_EMU_IO_TYPE_WRITE_CACHE (1 << 3) +#define ISCSI_SCSI_EMU_IO_TYPE_WRITE_CACHE (1 << 5) /// iSCSI SCSI emulation block flags: Write operation. -- cgit v1.2.3-55-g7522