From d980eae2586d8b9cdf7fadf4d88863fdede70c26 Mon Sep 17 00:00:00 2001 From: Sebastian Vater Date: Fri, 26 Sep 2025 10:40:02 +0200 Subject: Implemented iSCSI DNBD3 image name and WWN extraction from IQN. Also fixed some remaining bugs with initial structure creation caused crashes on reconnection. Finally, reindentation is now all tabs. --- src/server/iscsi.c | 481 ++++++++++++++++++++++++++++++++++++----------------- src/server/iscsi.h | 10 +- 2 files changed, 340 insertions(+), 151 deletions(-) diff --git a/src/server/iscsi.c b/src/server/iscsi.c index 508da59..a65009b 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -763,7 +763,7 @@ iscsi_hashmap *iscsi_hashmap_create(const uint capacity) new_capacity |= (new_capacity >> 16U); new_capacity++; - if ( (new_capacity + 1U) > (uint) ((new_capacity * 3U) >> 2U) ) + if ( (capacity + 1U) > (uint) ((new_capacity * 3U) >> 2U) ) new_capacity += new_capacity; // If specified capacity does not fit in 75% of requested capacity, double actual size map->capacity = new_capacity; // Round up actual new capacity to nearest power of two @@ -1334,29 +1334,6 @@ int iscsi_hashmap_get(iscsi_hashmap *map, const uint8_t *key, const size_t key_s return (entry->key != NULL) ? 0 : -1; } -/** - * @brief Retrieves the first hash map bucket. - * - * Retrieves the first hash map bucket not marked for - * removal. - * - * @param[in] map Pointer to the hash map to retrieve - * the first hash map bucket from and may NOT be - * NULL, so take caution. - * @return Pointer to first valid hash map bucket or - * NULL in case the hash map is empty. - */ -iscsi_hashmap_bucket *iscsi_hashmap_get_first_entry(const iscsi_hashmap *map) -{ - iscsi_hashmap_bucket *entry = map->first; - - while ( (entry != NULL) && (entry->key == NULL) ) { - entry = entry->next; - } - - return entry; -} - /** * @brief Marks an element for removal by setting key and value both to NULL. * @@ -1513,10 +1490,10 @@ iscsi_bhs_packet *iscsi_create_packet() return bhs_pkt; } - bhs_pkt->opcode = 0U; // Initialize everything to zero - bhs_pkt->opcode_fields[0] = 0U; - bhs_pkt->opcode_fields[1] = 0U; - bhs_pkt->opcode_fields[2] = 0U; + bhs_pkt->opcode = 0U; // Initialize everything to zero + bhs_pkt->opcode_fields[0] = 0U; + bhs_pkt->opcode_fields[1] = 0U; + bhs_pkt->opcode_fields[2] = 0U; bhs_pkt->total_ahs_len = 0U; bhs_pkt->ds_len[0] = 0U; bhs_pkt->ds_len[1] = 0U; @@ -2611,7 +2588,7 @@ static iscsi_task *iscsi_task_find(iscsi_connection *conn, const uint32_t target iscsi_task *task; iscsi_list_foreach_node ( &conn->r2t_tasks_active, task ) { - if ( target_xfer_tag == task->target_xfer_tag ) + if ( task->target_xfer_tag == target_xfer_tag ) return task; } @@ -2639,9 +2616,13 @@ static void iscsi_task_xfer_complete_process_read_sub_tasks(iscsi_connection *co iscsi_task *tmp; iscsi_list_foreach_safe_node ( &primary_task->sub_tasks, sub_task, tmp ) { - if ( sub_task->des_data_xfer_pos != sub_task->scsi_task.xfer_len ) + logadd( LOG_ERROR, "DEBUG iscsi_task_xfer_complete_process_read_sub_tasks: xfer_pos subtask->xfer_pos = %d, subtask->xfer_pos = %d, subtask->pos = %d, subtask->len = %d, scsi->xfer_pos = %d, scsi->xfer_len = %d, scsi->pos = %d, scsi->len = %d", sub_task->des_data_xfer_pos, sub_task->des_data_xfer_len, sub_task->pos, sub_task->len, sub_task->scsi_task.xfer_pos, sub_task->scsi_task.xfer_len, sub_task->scsi_task.pos, sub_task->scsi_task.len ); + + if ( primary_task->des_data_xfer_pos != sub_task->scsi_task.pos ) break; + logadd( LOG_ERROR, "DEBUG iscsi_task_xfer_complete_process_read_sub_tasks: RESPONDING: xfer_pos subtask->xfer_pos = %d, subtask->xfer_pos = %d, subtask->pos = %d, subtask->len = %d, scsi->xfer_pos = %d, scsi->xfer_len = %d, scsi->pos = %d, scsi->len = %d", sub_task->des_data_xfer_pos, sub_task->des_data_xfer_len, sub_task->pos, sub_task->len, sub_task->scsi_task.xfer_pos, sub_task->scsi_task.xfer_len, sub_task->scsi_task.pos, sub_task->scsi_task.len ); + iscsi_list_remove( &sub_task->node ); primary_task->des_data_xfer_pos += sub_task->scsi_task.len; @@ -2712,9 +2693,18 @@ void iscsi_task_xfer_complete_process_read(iscsi_connection *conn, iscsi_task *t } iscsi_list_enqueue( &primary_task->sub_tasks, &task->node ); + + iscsi_list_foreach_node ( &primary_task->sub_tasks, sub_task ) { + logadd( LOG_ERROR, "DEBUG iscsi_task_xfer_complete_process_read: pos NE xfer_pos subtask->xfer_pos = %d, subtask->xfer_pos = %d, subtask->pos = %d, subtask->len = %d, scsi->xfer_pos = %d, scsi->xfer_len = %d, scsi->pos = %d, scsi->len = %d", sub_task->des_data_xfer_pos, sub_task->des_data_xfer_len, sub_task->pos, sub_task->len, sub_task->scsi_task.xfer_pos, sub_task->scsi_task.xfer_len, sub_task->scsi_task.pos, sub_task->scsi_task.len ); + } } else { iscsi_list_push( &primary_task->sub_tasks, &task->node ); + iscsi_task *sub_task; + iscsi_list_foreach_node ( &primary_task->sub_tasks, sub_task ) { + logadd( LOG_ERROR, "DEBUG iscsi_task_xfer_complete_process_read: pos NE xfer_pos subtask->xfer_pos = %d, subtask->xfer_pos = %d, subtask->pos = %d, subtask->len = %d, scsi->xfer_pos = %d, scsi->xfer_len = %d, scsi->pos = %d, scsi->len = %d", sub_task->des_data_xfer_pos, sub_task->des_data_xfer_len, sub_task->pos, sub_task->len, sub_task->scsi_task.xfer_pos, sub_task->scsi_task.xfer_len, sub_task->scsi_task.pos, sub_task->scsi_task.len ); + } + iscsi_task_xfer_complete_process_read_sub_tasks( conn, primary_task ); } } @@ -3238,7 +3228,7 @@ void iscsi_task_response(iscsi_connection *conn, iscsi_task *task) * @return Pointer to allocated and initialized portal group * or NULL in case of memory */ -iscsi_portal_group *iscsi_portal_group_create(const int tag, const int flags) +iscsi_portal_group *iscsi_portal_group_create(const uint64_t tag, const int flags) { iscsi_portal_group *portal_group = (iscsi_portal_group *) malloc( sizeof(struct iscsi_portal_group) ); @@ -4198,28 +4188,28 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task) bool dma_to_device = false; switch ( cdb->opcode ) { - case ISCSI_SCSI_OPCODE_INQUIRY : - case ISCSI_SCSI_OPCODE_REPORTLUNS : - case ISCSI_SCSI_OPCODE_REQUESTSENSE : - case ISCSI_SCSI_OPCODE_LOGSENSE : - case ISCSI_SCSI_OPCODE_TESTUNITREADY : - case ISCSI_SCSI_OPCODE_STARTSTOPUNIT : - case ISCSI_SCSI_OPCODE_READCAPACITY10 : - case ISCSI_SCSI_OPCODE_PERSISTENT_RESERVE_IN : - case ISCSI_SCSI_OPCODE_SERVICE_ACTION_IN_16 : - case ISCSI_SCSI_OPCODE_RESERVE6 : - case ISCSI_SCSI_OPCODE_RESERVE10 : - case ISCSI_SCSI_OPCODE_RELEASE6 : - case ISCSI_SCSI_OPCODE_RELEASE10 : { + case ISCSI_SCSI_OPCODE_INQUIRY : + case ISCSI_SCSI_OPCODE_REPORTLUNS : + case ISCSI_SCSI_OPCODE_REQUESTSENSE : + case ISCSI_SCSI_OPCODE_LOGSENSE : + case ISCSI_SCSI_OPCODE_TESTUNITREADY : + case ISCSI_SCSI_OPCODE_STARTSTOPUNIT : + case ISCSI_SCSI_OPCODE_READCAPACITY10 : + case ISCSI_SCSI_OPCODE_PERSISTENT_RESERVE_IN : + case ISCSI_SCSI_OPCODE_SERVICE_ACTION_IN_16 : + case ISCSI_SCSI_OPCODE_RESERVE6 : + case ISCSI_SCSI_OPCODE_RESERVE10 : + case ISCSI_SCSI_OPCODE_RELEASE6 : + case ISCSI_SCSI_OPCODE_RELEASE10 : { return ISCSI_SCSI_TASK_RUN_COMPLETE; break; } - case ISCSI_SCSI_OPCODE_MODESELECT6 : - case ISCSI_SCSI_OPCODE_MODESELECT10 : - case ISCSI_SCSI_OPCODE_MODESENSE6 : - case ISCSI_SCSI_OPCODE_MODESENSE10 : - case ISCSI_SCSI_OPCODE_LOGSELECT : { + case ISCSI_SCSI_OPCODE_MODESELECT6 : + case ISCSI_SCSI_OPCODE_MODESELECT10 : + case ISCSI_SCSI_OPCODE_MODESENSE6 : + case ISCSI_SCSI_OPCODE_MODESENSE10 : + case ISCSI_SCSI_OPCODE_LOGSELECT : { if ( reg == NULL ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_RESERVATION_CONFLICT, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); @@ -4267,19 +4257,19 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task) break; } - case ISCSI_SCSI_OPCODE_READ6 : - case ISCSI_SCSI_OPCODE_READ10 : - case ISCSI_SCSI_OPCODE_READ12 : - case ISCSI_SCSI_OPCODE_READ16 : { + case ISCSI_SCSI_OPCODE_READ6 : + case ISCSI_SCSI_OPCODE_READ10 : + case ISCSI_SCSI_OPCODE_READ12 : + case ISCSI_SCSI_OPCODE_READ16 : { break; } - case ISCSI_SCSI_OPCODE_WRITE6 : - case ISCSI_SCSI_OPCODE_WRITE10 : - case ISCSI_SCSI_OPCODE_WRITE12 : - case ISCSI_SCSI_OPCODE_WRITE16 : - case ISCSI_SCSI_OPCODE_UNMAP : - case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE10 : - case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE16 : { + case ISCSI_SCSI_OPCODE_WRITE6 : + case ISCSI_SCSI_OPCODE_WRITE10 : + case ISCSI_SCSI_OPCODE_WRITE12 : + case ISCSI_SCSI_OPCODE_WRITE16 : + case ISCSI_SCSI_OPCODE_UNMAP : + case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE10 : + case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE16 : { dma_to_device = true; break; @@ -4294,7 +4284,7 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task) } switch ( lun->pr_reservation.type ) { - case ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE : { + case ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE : { if ( dma_to_device ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_RESERVATION_CONFLICT, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); @@ -4303,15 +4293,15 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task) break; } - case ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS : { + case ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS : { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_RESERVATION_CONFLICT, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return ISCSI_SCSI_TASK_RUN_UNKNOWN; break; } - case ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE_REGS_ONLY : - case ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE_ALL_REGS : { + case ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE_REGS_ONLY : + case ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE_ALL_REGS : { if ( (reg == NULL) && dma_to_device ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_RESERVATION_CONFLICT, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); @@ -4320,8 +4310,8 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task) break; } - case ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS_REGS_ONLY : - case ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS_ALL_REGS : { + case ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS_REGS_ONLY : + case ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS_ALL_REGS : { if ( reg == NULL ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_RESERVATION_CONFLICT, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); @@ -4442,7 +4432,8 @@ int iscsi_scsi_pr_release_scsi2(iscsi_scsi_task *scsi_task) * @brief Checks whether an I/O feature is supported by a DNBD3 image. * * This function depends on DNBD3 image - * properties. + * properties and queries only one I/O + * feature at once. * * @param[in] image Pointer to DNBD3 image to check I/O * attributes for. May NOT be NULL, so be @@ -4456,7 +4447,33 @@ static inline bool iscsi_scsi_emu_io_type_is_supported(const dnbd3_image_t *imag { // TODO: Actually implement this function. - return (type != ISCSI_SCSI_EMU_IO_TYPE_UNMAP); + switch ( type ) { + case ISCSI_SCSI_EMU_IO_TYPE_REMOVABLE : { + return true; + + break; + } + case ISCSI_SCSI_EMU_IO_TYPE_UNMAP : { + return false; + + break; + } + case ISCSI_SCSI_EMU_IO_TYPE_NO_ROTATION : { + return false; + + break; + } + case ISCSI_SCSI_EMU_IO_TYPE_WRITE_CACHE : { + return false; + + break; + } + default : { + return false; + + break; + } + } } /** @@ -4725,8 +4742,20 @@ int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd const int64_t len = pread( 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); } @@ -5196,8 +5225,6 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) lba = iscsi_get_be32(cdb_read_write_10->lba); xfer_len = iscsi_get_be16(cdb_read_write_10->xfer_len); - logadd( LOG_ERROR, "DEBUG SCSI READ(10): lba: %ld, xfer_len: %d", lba, xfer_len ); - return iscsi_scsi_emu_block_read_write( lun->image, scsi_task, lba, xfer_len, 0 ); break; @@ -5520,18 +5547,9 @@ static int iscsi_scsi_emu_check_len(iscsi_scsi_task *scsi_task, const uint len, */ static void iscsi_scsi_emu_naa_ieee_ext_set(uint64_t *buf, const uint8_t *name) { - uint64_t value = 0ULL; - int i = 0; + const uint64_t wwn = iscsi_target_node_wwn_get( name ); - while ( name[i] != '\0' ) { - value = (value * 131ULL) + name[i++]; - } - - const uint64_t id_a = ((value & 0xFFF000000ULL) << 24ULL); - - value = ((value & 0xFFFFFFULL) | 0x2000000347000000ULL | id_a); - - iscsi_put_be64( (uint8_t *) buf, value ); + iscsi_put_be64( (uint8_t *) buf, wwn ); } /** @@ -6625,7 +6643,7 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task) scsi_task->buf = (uint8_t *) std_inquiry_data_pkt; - if ( rc < len ) + if ( rc < (int) len ) memset( (((uint8_t *) std_inquiry_data_pkt) + rc), 0, (len - rc) ); rc = len; @@ -7145,7 +7163,7 @@ void iscsi_port_destroy(iscsi_port *port) */ uint8_t *iscsi_port_get_name(const iscsi_port *port) { - return port->name; + return port->name; } /** @@ -7370,7 +7388,7 @@ iscsi_port *iscsi_device_find_port_by_portal_group_tag(const iscsi_device *devic if ( (port == NULL) || ((port->flags & ISCSI_PORT_FLAGS_IN_USE) == 0) ) return NULL; - return port; + return port; } /** @@ -7602,7 +7620,7 @@ int iscsi_target_node_create_callback(uint8_t *key, const size_t key_size, uint8 * @return Pointer to iSCSI target node on successful * operation or NULL in case of an error. */ -iscsi_target_node *iscsi_target_node_create(const uint8_t *name, const uint8_t *alias, const int index, const uint luns, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest) +iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, const int index, const uint luns, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest) { if ( (name == NULL) || (iscsi_target_node_check_name( name ) < 0) || (iscsi_target_node_check_flags( flags, chap_group ) < 0) ) return NULL; @@ -7648,7 +7666,12 @@ iscsi_target_node *iscsi_target_node_create(const uint8_t *name, const uint8_t * target->alias = NULL; } - target->device = iscsi_device_create( name, luns, ISCSI_TRANSPORT_ID_PROTOCOL_ID_ISCSI ); + dnbd3_image_t *image = iscsi_target_node_image_get( name ); + + if ( image == NULL ) + return NULL; + + target->device = iscsi_device_create( (uint8_t *) image->name, luns, ISCSI_TRANSPORT_ID_PROTOCOL_ID_ISCSI ); if ( target->device == NULL ) { logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI target device" ); @@ -7779,6 +7802,100 @@ int iscsi_target_node_find_callback(uint8_t *key, const size_t key_size, uint8_t return -1; } +/** + * @brief Calculates the WWN using 64-bit IEEE Extended NAA for a name. + * + * @param[in] name Pointer to string containing the + * name to calculate the IEEE Extended + * NAA for. NULL is NOT allowed here, so + * take caution. + * @return A 64-bit unsigned integer for + * storing the IEEE Extended NAA. + */ +uint64_t iscsi_target_node_wwn_get(const uint8_t *name) +{ + uint64_t value = 0ULL; + int i = 0; + + while ( name[i] != '\0' ) { + value = (value * 131ULL) + name[i++]; + } + + const uint64_t id_a = ((value & 0xFFF000000ULL) << 24ULL); + + return ((value & 0xFFFFFFULL) | 0x2000000347000000ULL | id_a); +} + +/** + * @brief Extracts the DNBD3 image out of an iSCSI IQN string and opens the DNBD3 image. + * + * This function uses the : separator as + * specified by the IQN standard.\n + * If no colons are in the IQN string, + * the complete string will be + * considered the image file name.\n + * The image file name is assumed + * before the last colon and is + * either directly opened or if + * that fails, a WWN name by + * IEEE Extended NAA is tried as + * well.\n + * The image revision is assumed + * after the last colon. + * @param[in] iqn Pointer to iSCSI IQN string. This + * is not allowed to be NULL, so be careful. + * @return Pointer to DNBD3 image if successful + * operation or NULL if failed. + */ +dnbd3_image_t *iscsi_target_node_image_get(uint8_t *iqn) +{ + uint8_t *image_name = iqn; + uint8_t *image_rev = NULL; + uint8_t *tmp = (uint8_t *) strchr( (char *) iqn, ':' ); + + while ( tmp != NULL ) { + tmp++; + + image_name = image_rev; + image_rev = tmp; + tmp = (uint8_t *) strchr( (char *) tmp, ':' ); + } + + if ( image_rev == NULL ) + image_rev = image_name; + + const uint len = (uint) (image_rev - image_name); + + if ( len > 0U ) { + tmp = (uint8_t *) malloc( len ); + + if ( tmp == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_image_get: Out of memory while allocating DNBD3 image name for iSCSI target node" ); + + return NULL; + } + + memcpy( tmp, image_name, (len - 1) ); + tmp[len - 1] = '\0'; + } else { + tmp = image_name; + } + + const uint16_t rev = (uint16_t) ((len > 0U) ? atoi( (char *) image_rev ) : 0); + dnbd3_image_t *image = image_getOrLoad( (char *) tmp, rev ); + + if ( image == NULL ) { + const uint64_t wwn = iscsi_target_node_wwn_get( tmp ); + + image = image_getByWwn( wwn, rev, true ); + } + + if ( len > 0U ) + free( tmp ); + + return image; +} + /** * @brief Searches an iSCSI target node by name using case insensitive search. * @@ -7800,6 +7917,41 @@ iscsi_target_node *iscsi_target_node_find(uint8_t *target_name) iscsi_hashmap_iterate( iscsi_globvec->target_nodes, iscsi_target_node_find_callback, (uint8_t *) &target_find ); + if ( target_find.target == NULL ) { + dnbd3_image_t *image = iscsi_target_node_image_get( target_name ); + + if ( image == NULL ) + return NULL; + + target_find.target = iscsi_target_node_create( target_name, NULL, 0, 8U, 1U, 0, 0L, 0, 0 ); + + if ( target_find.target == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_find: Out of memory while allocating iSCSI target node" ); + + return NULL; + } + + const uint key_len = (uint) (strlen( (char *) target_name ) + 1U); + uint8_t *hash_key = iscsi_hashmap_key_create( target_name, key_len ); + + if ( hash_key == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_find: Out of memory while allocating iSCSI target node" ); + + iscsi_target_node_destroy( target_find.target ); + + return NULL; + } + + int rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, (uint8_t *) hash_key, sizeof(key_len), (uint8_t *) target_find.target ); + + if ( rc < 0 ) { + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); + iscsi_target_node_destroy( target_find.target ); + + return NULL; + } + } + return target_find.target; } @@ -8377,13 +8529,9 @@ int32_t iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf, const */ int iscsi_connection_handle_scsi_data_in_queued_tasks(iscsi_connection *conn) { - logadd( LOG_ERROR, "DEBUG ENTER iscsi_connection_handle_scsi_data_in_queued_tasks" ); - while ( !iscsi_list_empty( &conn->scsi_data_in_queued_tasks ) && (conn->scsi_data_in_cnt < ISCSI_DEFAULT_MAX_DATA_IN_PER_CONNECTION) ) { iscsi_task *task = (iscsi_task *) iscsi_list_peek( &conn->scsi_data_in_queued_tasks ); - logadd( LOG_ERROR, "DEBUG BEGIN iscsi_connection_handle_scsi_data_in_queued_tasks: task->pos = %d, task->scsi_task.xfer_len = %d", task->pos, task->scsi_task.xfer_len ); - if ( task->pos < task->scsi_task.xfer_len ) { const uint32_t len = (task->scsi_task.xfer_len - task->pos); iscsi_task *sub_task = iscsi_task_create( conn, task, iscsi_scsi_task_xfer_complete ); @@ -8413,16 +8561,10 @@ int iscsi_connection_handle_scsi_data_in_queued_tasks(iscsi_connection *conn) iscsi_task_queue( conn, sub_task ); } - logadd( LOG_ERROR, "DEBUG NEXT iscsi_connection_handle_scsi_data_in_queued_tasks: task->pos = %d, task->scsi_task.xfer_len = %d", task->pos, task->scsi_task.xfer_len ); - - if ( task->pos == task->scsi_task.xfer_len ) { - logadd( LOG_ERROR, "DEBUG END iscsi_connection_handle_scsi_data_in_queued_tasks: task->pos = %d, task->scsi_task.xfer_len = %d", task->pos, task->scsi_task.xfer_len ); + if ( task->pos == task->scsi_task.xfer_len ) iscsi_list_remove( &task->node ); - } } - logadd( LOG_ERROR, "DEBUG LEAVE iscsi_connection_handle_scsi_data_in_queued_tasks" ); - return ISCSI_CONNECT_PDU_READ_OK; } @@ -9767,8 +9909,21 @@ void iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu, iscsi_co // TODO: Do the writing in a queue. iscsi_connection_write( conn, (uint8_t *) pdu->bhs_pkt, len ); - if ( callback != NULL ) - callback( user_data ); + // TODO: Begin remove after I/O async implementation + if ( callback == NULL ) + return; + + uint64_t *exec_data = malloc( 64 ); + + exec_data[2] = (uint64_t *) callback; + exec_data[3] = 1ULL; + exec_data[4] = user_data; + + iscsi_list_enqueue( &iscsi_globvec->exec_queue, (iscsi_node *) exec_data ); + // TODO: End remove after I/O async implementation + +// if ( callback != NULL ) +// callback( user_data ); } /** @@ -10536,7 +10691,7 @@ static int iscsi_connection_pdu_header_handle_scsi_data_out(iscsi_connection *co if ( xfer_len == task->r2t_next_exp_pos ) { task->r2t_sn_ack++; - } else if ( ((int8_t) scsi_data_out_req_pkt->opcode < 0) && (xfer_len > task->r2t_next_exp_pos) ) { + } else if ( ((int8_t) scsi_data_out_req_pkt->opcode < 0) && (xfer_len > task->r2t_next_exp_pos) ) { task->r2t_sn_ack++; uint32_t len = (xfer_len - task->r2t_next_exp_pos); @@ -10878,7 +11033,7 @@ static int iscsi_connection_pdu_data_handle_scsi_cmd_read(iscsi_connection *conn task->pos = 0UL; - iscsi_list_enqueue( &conn->scsi_data_in_queued_tasks, task ); + iscsi_list_enqueue( &conn->scsi_data_in_queued_tasks, &task->node ); return iscsi_connection_handle_scsi_data_in_queued_tasks( conn ); } @@ -12213,8 +12368,31 @@ int iscsi_connection_pdu_handle(iscsi_connection *conn) if ( iscsi_globvec == NULL ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; + // TODO: Remove after I/O sync implementation + iscsi_list_create( &iscsi_globvec->exec_queue ); + const int rc = iscsi_connection_pdu_read( conn ); + // TODO: Start: Remove after I/O sync implementation + + while ( !iscsi_list_empty( &iscsi_globvec->exec_queue ) ) { + uint64_t *exec_data = (uint64_t *) iscsi_list_peek( &iscsi_globvec->exec_queue ); + + iscsi_list_remove( (iscsi_node *) exec_data ); + + if ( exec_data[3] == 1ULL ) { + iscsi_scsi_task_xfer_complete_callback callback = (iscsi_scsi_task_xfer_complete_callback) exec_data[2]; + callback( (uint8_t *) exec_data[4] ); + } else if ( exec_data[3] == 3ULL ) { + iscsi_scsi_emu_io_complete_callback callback = (iscsi_scsi_emu_io_complete_callback) exec_data[2]; + callback( (dnbd3_image_t *) exec_data[4], (uint8_t *) exec_data[5], (bool) exec_data[6] ); + } + + free( exec_data ); + } + + // TODO: End: Remove after I/O sync implementation + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); if ( rc == 0 ) @@ -12259,86 +12437,93 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ if ( iscsi_globvec == NULL ) return; - uint64_t *hash_key = (uint64_t *) malloc( sizeof(uint64_t) ); + uint64_t *hash_key; + iscsi_portal_group *portal_group = NULL; + int rc = iscsi_hashmap_get( iscsi_globvec->portal_groups, (uint8_t *) &iscsi_globvec->portal_groups->last_insert_id, sizeof(iscsi_globvec->portal_groups->last_insert_id), (uint8_t **) &portal_group ); - if ( hash_key == NULL ) { - logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" ); + if ( portal_group == NULL ) { + hash_key = (uint64_t *) malloc( sizeof(uint64_t) ); - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + if ( hash_key == NULL ) { + logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" ); - return; - } + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); - iscsi_hashmap_key_create_id( iscsi_globvec->portal_groups, hash_key ); + return; + } - iscsi_portal_group *portal_group = iscsi_portal_group_create( (int) *hash_key, 0 ); + iscsi_hashmap_key_create_id( iscsi_globvec->portal_groups, hash_key ); + portal_group = iscsi_portal_group_create( *hash_key, 0 ); - if ( portal_group == NULL ) { - logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" ); + if ( portal_group == NULL ) { + logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" ); - iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); - return; - } + return; + } - portal_group->tag = (int) *hash_key; + portal_group->tag = *hash_key; - int rc = iscsi_hashmap_put( iscsi_globvec->portal_groups, (uint8_t *) hash_key, sizeof(uint64_t), (uint8_t *) portal_group ); + rc = iscsi_hashmap_put( iscsi_globvec->portal_groups, (uint8_t *) hash_key, sizeof(uint64_t), (uint8_t *) portal_group ); - if ( rc < 0 ) { - iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); - iscsi_portal_group_destroy( portal_group ); - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + if ( rc < 0 ) { + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); + iscsi_portal_group_destroy( portal_group ); + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); - return; + return; + } } - iscsi_portal *portal = iscsi_portal_create( (uint8_t *) client->hostName, port ); + uint8_t *tmp_buf = iscsi_sprintf_alloc( "%s:%s", client->hostName, port ); - if ( portal == NULL ) { - logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal" ); + if ( tmp_buf == NULL ) { + logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating temporarily iSCSI portal name" ); - iscsi_portal_group_destroy( portal_group ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); return; } - portal->group = portal_group; + const uint key_len = (uint) (strlen( (char *) tmp_buf ) + 1U); - // iscsi_target_node *target = iscsi_target_node_create( (uint8_t *) "iqn.2023-01.com.example:target", NULL, 0, 8U, 1U, 0, 0L, 0, 0 ); - // iscsi_target_node *target = iscsi_target_node_create( (uint8_t *) "debian-13.1.0-amd64-DVD-1.iso", NULL, 0, 8U, 1U, 0, 0L, 0, 0 ); - iscsi_target_node *target = iscsi_target_node_create( (uint8_t *) "ubuntu-24.04.3-desktop-amd64.iso", NULL, 0, 8U, 1U, 0, 0L, 0, 0 ); + hash_key = (uint64_t *) iscsi_hashmap_key_create( tmp_buf, key_len ); - if ( target == NULL ) { - logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI target node" ); + free( tmp_buf ); + + if ( hash_key == NULL ) { + logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating temporarily iSCSI portal name hash key" ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); return; } - hash_key = (uint64_t *) malloc( sizeof(uint64_t) ); + iscsi_portal *portal = NULL; + rc = iscsi_hashmap_get( portal_group->portals, (uint8_t *) hash_key, key_len, (uint8_t **) &portal ); - if ( hash_key == NULL ) { - logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI target node" ); + if ( portal == NULL ) { + portal = iscsi_portal_create( (uint8_t *) client->hostName, port ); - iscsi_target_node_destroy( target ); - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + if ( portal == NULL ) { + logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal" ); - return; - } + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); - iscsi_hashmap_key_create_id( iscsi_globvec->target_nodes, hash_key ); - rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, (uint8_t *) hash_key, sizeof(uint64_t), (uint8_t *) target ); + return; + } - if ( rc < 0 ) { - iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); - iscsi_target_node_destroy( target ); - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + rc = iscsi_portal_group_add_portal( portal_group, portal ); - return; + if ( rc < 0 ) { + iscsi_portal_destroy( portal ); + + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + + return; + } } iscsi_connection *conn = iscsi_connection_create( portal, client->sock ); diff --git a/src/server/iscsi.h b/src/server/iscsi.h index d95181e..dac8e8f 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -453,7 +453,6 @@ int iscsi_hashmap_put_free(iscsi_hashmap *map, uint8_t *key, const size_t key_si // with callback function in case the key already exists bool iscsi_hashmap_contains(iscsi_hashmap *map, const uint8_t *key, const size_t key_size); // Checks whether a specified key exists int iscsi_hashmap_get(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t **out_value); // Retrieves the value of a specified key -iscsi_hashmap_bucket *iscsi_hashmap_get_first_entry(const iscsi_hashmap *map); // Retrieves the first hash map bucket void iscsi_hashmap_remove(iscsi_hashmap *map, const uint8_t *key, const size_t key_size); // Marks an element for removal by setting key and value both to NULL void iscsi_hashmap_remove_free(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, iscsi_hashmap_callback callback, uint8_t *user_data); // Marks an element for removal by setting key and value both to NULL, @@ -9673,6 +9672,9 @@ typedef struct iscsi_globals { /// Hash map containing connection key and value pair types and allowed values or ranges. iscsi_hashmap *connection_key_value_pairs; + // TODO: Remove after async I/O implementation + iscsi_list exec_queue; + /// Global flags. int flags; @@ -9763,7 +9765,7 @@ typedef struct iscsi_portal { } iscsi_portal; -iscsi_portal_group *iscsi_portal_group_create(const int tag, const int flags); // Creates and initializes an iSCSI portal group +iscsi_portal_group *iscsi_portal_group_create(const uint64_t tag, const int flags); // Creates and initializes an iSCSI portal group void iscsi_portal_group_destroy(iscsi_portal_group *portal_group); // Deallocates resources acquired by iscsi_portal_group_create int iscsi_portal_group_add_portal(iscsi_portal_group *portal_group, iscsi_portal *portal); // Adds an iSCSI portal to the iSCSI portal group hash map @@ -11090,10 +11092,12 @@ int iscsi_device_port_add(iscsi_device *device, const uint8_t *name, const uint6 void iscsi_device_scsi_task_queue(iscsi_device *device, iscsi_scsi_task *scsi_task); // Enqueues an iSCSI SCSI task to the first LUN of an iSCSI device int iscsi_target_node_create_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Creates, initializes and adds a portal group to an iSCSI target node -iscsi_target_node *iscsi_target_node_create(const uint8_t *name, const uint8_t *alias, const int index, const uint luns, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest); // Creates and initializes an iSCSI target node +iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, const int index, const uint luns, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest); // Creates and initializes an iSCSI target node void iscsi_target_node_destroy(iscsi_target_node *target); // Deallocates all resources acquired by iscsi_target_node_create int iscsi_target_node_send(iscsi_connection *conn, const uint8_t *dst_iqn, const uint8_t *src_iqn, uint8_t *buf, const uint32_t pos, const uint32_t len); // Sends a buffer from a source iSCSI IQN to target iSCSI IQNs +uint64_t iscsi_target_node_wwn_get(const uint8_t *name); // Calculates the WWN using 64-bit IEEE Extended NAA for a name +dnbd3_image_t *iscsi_target_node_image_get(uint8_t *iqn); // Extracts the DNBD3 image out of an iSCSI IQN string and opens the DNBD3 image int iscsi_target_node_find_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Finds an iSCSI target node by case insensitive name search iscsi_target_node *iscsi_target_node_find(uint8_t *target_name); // Searches an iSCSI target node by name using case insensitive search -- cgit v1.2.3-55-g7522