summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Vater2025-09-26 10:40:02 +0200
committerSebastian Vater2025-09-26 10:40:02 +0200
commitd980eae2586d8b9cdf7fadf4d88863fdede70c26 (patch)
tree2dea9bcf8fa847ae8b5cdb1bfd7553a0509ff305
parentHuge iSCSI refactoring. Added doubly linked list for iSCSI and SCSI task mana... (diff)
downloaddnbd3-d980eae2586d8b9cdf7fadf4d88863fdede70c26.tar.gz
dnbd3-d980eae2586d8b9cdf7fadf4d88863fdede70c26.tar.xz
dnbd3-d980eae2586d8b9cdf7fadf4d88863fdede70c26.zip
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.
-rw-r--r--src/server/iscsi.c481
-rw-r--r--src/server/iscsi.h10
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
@@ -1335,29 +1335,6 @@ int iscsi_hashmap_get(iscsi_hashmap *map, const uint8_t *key, const size_t key_s
}
/**
- * @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.
*
* Removes an element from the bucket list of the
@@ -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" );
@@ -7780,6 +7803,100 @@ int iscsi_target_node_find_callback(uint8_t *key, const size_t key_size, uint8_t
}
/**
+ * @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.
*
* This function searches for an iSCSI target node
@@ -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