diff options
| author | Sebastian Vater | 2025-10-01 11:52:30 +0200 |
|---|---|---|
| committer | Sebastian Vater | 2025-10-01 11:52:30 +0200 |
| commit | 07cc37a77437f63f9552ddddf8d29431d5fe6256 (patch) | |
| tree | fe9a7fee87e1c661f115d90877081a84ead4e6d2 | |
| parent | Fixed some very memory leaks in iSCSI reported by valgrind and improved sessi... (diff) | |
| download | dnbd3-07cc37a77437f63f9552ddddf8d29431d5fe6256.tar.gz dnbd3-07cc37a77437f63f9552ddddf8d29431d5fe6256.tar.xz dnbd3-07cc37a77437f63f9552ddddf8d29431d5fe6256.zip | |
Implemented better read/write and mutex locking in iSCSI server. Some little code cleanups and finally bug fixes again.
| -rw-r--r-- | src/server/iscsi.c | 545 | ||||
| -rw-r--r-- | src/server/iscsi.h | 40 |
2 files changed, 399 insertions, 186 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c index e3609d5..ef44d8e 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -18,6 +18,7 @@ * */ +#include "locks.h" #include <ctype.h> #include <errno.h> #include <stdarg.h> @@ -190,11 +191,34 @@ int iscsi_create() return -1; } - globvec->portal_groups = iscsi_hashmap_create( 0U ); + if ( pthread_rwlock_init( &globvec->devices_rwlock, NULL ) != 0 ) { + logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing read/write lock for iSCSI global vector devices hash map" ); + + iscsi_hashmap_destroy( globvec->devices ); + free( globvec ); + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + + return -1; + } + + globvec->portal_groups = iscsi_hashmap_create( 1U ); if ( globvec->portal_groups == NULL ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector portal groups hash map" ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); + iscsi_hashmap_destroy( globvec->devices ); + free( globvec ); + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + + return -1; + } + + if ( pthread_rwlock_init( &globvec->portal_groups_rwlock, NULL ) != 0 ) { + logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing read/write lock for iSCSI global vector portal groups hash map" ); + + iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); free( globvec ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -207,7 +231,23 @@ int iscsi_create() if ( globvec->target_nodes == NULL ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector target nodes hash map" ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); + iscsi_hashmap_destroy( globvec->devices ); + free( globvec ); + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + + return -1; + } + + if ( pthread_rwlock_init( &globvec->target_nodes_rwlock, NULL ) != 0 ) { + logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing read/write lock for iSCSI global vector target nodes hash map" ); + + iscsi_hashmap_destroy( globvec->target_nodes ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); + iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); free( globvec ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -220,8 +260,27 @@ int iscsi_create() if ( globvec->sessions == NULL ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector sessions hash map" ); + pthread_rwlock_destroy( &globvec->target_nodes_rwlock ); + iscsi_hashmap_destroy( globvec->target_nodes ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); + iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); + iscsi_hashmap_destroy( globvec->devices ); + free( globvec ); + pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + + return -1; + } + + if ( pthread_rwlock_init( &globvec->sessions_rwlock, NULL ) != 0 ) { + logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing read/write lock for iSCSI global vector sessions hash map map" ); + + iscsi_hashmap_destroy( globvec->sessions ); + pthread_rwlock_destroy( &globvec->target_nodes_rwlock ); iscsi_hashmap_destroy( globvec->target_nodes ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); free( globvec ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -234,9 +293,13 @@ int iscsi_create() if ( globvec->session_key_value_pairs == NULL ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector session key and value pairs hash map" ); + pthread_rwlock_destroy( &globvec->sessions_rwlock ); iscsi_hashmap_destroy( globvec->sessions ); + pthread_rwlock_destroy( &globvec->target_nodes_rwlock ); iscsi_hashmap_destroy( globvec->target_nodes ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); free( globvec ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -251,9 +314,13 @@ int iscsi_create() iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); + pthread_rwlock_destroy( &globvec->sessions_rwlock ); iscsi_hashmap_destroy( globvec->sessions ); + pthread_rwlock_destroy( &globvec->target_nodes_rwlock ); iscsi_hashmap_destroy( globvec->target_nodes ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); free( globvec ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -268,9 +335,13 @@ int iscsi_create() iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); + pthread_rwlock_destroy( &globvec->sessions_rwlock ); iscsi_hashmap_destroy( globvec->sessions ); + pthread_rwlock_destroy( &globvec->target_nodes_rwlock ); iscsi_hashmap_destroy( globvec->target_nodes ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); free( globvec ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -287,9 +358,13 @@ int iscsi_create() iscsi_hashmap_destroy( globvec->connection_key_value_pairs ); iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); + pthread_rwlock_destroy( &globvec->sessions_rwlock ); iscsi_hashmap_destroy( globvec->sessions ); + pthread_rwlock_destroy( &globvec->target_nodes_rwlock ); iscsi_hashmap_destroy( globvec->target_nodes ); + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); iscsi_hashmap_destroy( globvec->portal_groups ); + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); free( globvec ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -297,6 +372,8 @@ int iscsi_create() return -1; } + pthread_mutex_init( &globvec->exec_queue_mutex, NULL ); // TODO: Start: Remove after I/O sync implementation + globvec->flags = 0; globvec->max_sessions = 0U; globvec->chap_group = 0L; @@ -329,6 +406,8 @@ void iscsi_destroy() if ( globvec != NULL ) { iscsi_globvec = NULL; + pthread_mutex_destroy( &globvec->exec_queue_mutex ); // TODO: Start: Remove after I/O sync implementation + iscsi_hashmap_iterate( globvec->connection_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->connection_key_value_pairs ); globvec->connection_key_value_pairs = NULL; @@ -337,15 +416,19 @@ void iscsi_destroy() iscsi_hashmap_destroy( globvec->session_key_value_pairs ); globvec->session_key_value_pairs = NULL; + pthread_rwlock_destroy( &globvec->sessions_rwlock ); iscsi_hashmap_destroy( globvec->sessions ); globvec->sessions = NULL; + pthread_rwlock_destroy( &globvec->target_nodes_rwlock ); iscsi_hashmap_destroy( globvec->target_nodes ); globvec->target_nodes = NULL; + pthread_rwlock_destroy( &globvec->portal_groups_rwlock ); iscsi_hashmap_destroy( globvec->portal_groups ); globvec->portal_groups = NULL; + pthread_rwlock_destroy( &globvec->devices_rwlock ); iscsi_hashmap_destroy( globvec->devices ); globvec->devices = NULL; @@ -1611,7 +1694,7 @@ static int iscsi_add_int_key_value_pair(iscsi_hashmap *key_value_pairs, const ui */ static int iscsi_update_int_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_t *key, const int32_t value) { - const uint8_t *hash_val = iscsi_sprintf_alloc( "%" PRId32, value ); + uint8_t *hash_val = iscsi_sprintf_alloc( "%" PRId32, value ); if ( hash_val == NULL ) { logadd( LOG_ERROR, "iscsi_update_int_key_value_pair: Out of memory allocating integer value." ); @@ -1801,8 +1884,6 @@ void iscsi_task_destroy_callback(iscsi_scsi_task *scsi_task) { if ( scsi_task != NULL ) { iscsi_task *task = (iscsi_task *) (((uint8_t *) scsi_task) - offsetof(struct iscsi_task, scsi_task)); - iscsi_task *sub_task; - iscsi_task *tmp; if ( task->parent != NULL ) { if ( (task->scsi_task.flags & ISCSI_SCSI_TASK_FLAGS_XFER_READ) != 0 ) @@ -2976,7 +3057,7 @@ void iscsi_scsi_task_lun_process_abort(iscsi_scsi_task *scsi_task) * @return Pointer to ISCSI device LUN or NULL in case * of an error (memory exhaustion). */ -iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id) +iscsi_scsi_lun *iscsi_scsi_lun_create(const int lun_id) { iscsi_scsi_lun *lun = (iscsi_scsi_lun *) malloc( sizeof(struct iscsi_scsi_lun) ); @@ -3017,7 +3098,7 @@ iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id) lun->device = NULL; lun->image = NULL; - lun->id = id; + lun->id = lun_id; lun->flags = 0; lun->pr_gen = 0UL; @@ -4032,13 +4113,15 @@ int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd // TODO: Begin remove after I/O async implementation uint64_t *exec_data = malloc( 64 ); - exec_data[2] = (uint64_t *) callback; + exec_data[2] = (uint64_t) callback; exec_data[3] = 3ULL; - exec_data[4] = (dnbd3_image_t *) image; - exec_data[5] = user_data; + exec_data[4] = (uint64_t) image; + exec_data[5] = (uint64_t) user_data; exec_data[6] = success; + pthread_mutex_lock( &iscsi_globvec->exec_queue_mutex ); iscsi_list_enqueue( &iscsi_globvec->exec_queue, (iscsi_node *) exec_data ); + pthread_mutex_unlock( &iscsi_globvec->exec_queue_mutex ); // TODO: End remove after I/O async implementation // scsi_task->xfer_pos = scsi_task->len; @@ -4191,13 +4274,15 @@ int iscsi_scsi_emu_io_blocks_write(iscsi_scsi_task *scsi_task, uint8_t *buf, dnb // TODO: Begin remove after I/O async implementation uint64_t *exec_data = malloc( 64 ); - exec_data[2] = (uint64_t *) callback; + exec_data[2] = (uint64_t) callback; exec_data[3] = 3ULL; - exec_data[4] = (dnbd3_image_t *) image; - exec_data[5] = user_data; + exec_data[4] = (uint64_t) image; + exec_data[5] = (uint64_t) user_data; exec_data[6] = success; + pthread_mutex_lock( &iscsi_globvec->exec_queue_mutex ); iscsi_list_enqueue( &iscsi_globvec->exec_queue, (iscsi_node *) exec_data ); + pthread_mutex_unlock( &iscsi_globvec->exec_queue_mutex ); // TODO: End remove after I/O async implementation // scsi_task->xfer_pos = scsi_task->len; @@ -6536,6 +6621,8 @@ int iscsi_port_transport_id_set(iscsi_port *port, const uint8_t *name, const uin port->transport_id_len = (uint16_t) (offsetof(struct iscsi_transport_id, name) + len); + free( tmp_buf ); + return ISCSI_CONNECT_PDU_READ_OK; } @@ -6547,17 +6634,13 @@ int iscsi_port_transport_id_set(iscsi_port *port, const uint8_t *name, const uin * * @param[in] name Pointer to name of iSCSI device, * may NOT be NULL, so be careful. - * @param[in] luns Maximum number of LUNs for this - * iSCSI device. + * @param[in] lun_id Initial LUN identifier to create. * @param[in] protocol_id Protocol identifier. * @return Pointer to iSCSI device or NULL in * case of an error. */ -iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns, const uint8_t protocol_id) +iscsi_device *iscsi_device_create(const uint8_t *name, const int lun_id, const uint8_t protocol_id) { - if ( luns == 0U ) - return NULL; - iscsi_device *device = (iscsi_device *) malloc( sizeof(struct iscsi_device) ); if ( device == NULL ) { @@ -6580,7 +6663,7 @@ iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns, const ui memcpy( device->name, name, len ); - device->luns = iscsi_hashmap_create( luns ); + device->luns = iscsi_hashmap_create( 8U ); if ( device->luns == NULL ) { logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN hash map" ); @@ -6591,41 +6674,53 @@ iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns, const ui return NULL; } - for ( uint i = 0U; i < luns; i++ ) { - iscsi_scsi_lun *lun = iscsi_scsi_lun_create( i ); - uint8_t *hash_key = iscsi_hashmap_key_create( (uint8_t *) &i, sizeof(i) ); + iscsi_scsi_lun *lun = iscsi_scsi_lun_create( lun_id ); - if ( hash_key == NULL ) { - logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN hash map" ); + if ( lun == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN hash map" ); - iscsi_hashmap_iterate( device->luns, iscsi_hashmap_key_destroy_value_callback, NULL ); - iscsi_hashmap_destroy( device->luns ); - free( device->name ); - free( device ); + iscsi_hashmap_destroy( device->luns ); + free( device->name ); + free( device ); - return NULL; - } + return NULL; + } - const int rc = iscsi_hashmap_put( device->luns, hash_key, sizeof(i), (uint8_t *) lun ); + const uint64_t lun_hash = lun_id; + uint8_t *hash_key = iscsi_hashmap_key_create( (uint8_t *) &lun_hash, sizeof(lun_hash) ); - if ( rc < 0 ) { - iscsi_hashmap_iterate( device->luns, iscsi_hashmap_key_destroy_value_callback, NULL ); - iscsi_hashmap_destroy( device->luns ); - free( device->name ); - free( device ); + if ( hash_key == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN hash map" ); - return NULL; - } + iscsi_scsi_lun_destroy( lun ); + iscsi_hashmap_destroy( device->luns ); + free( device->name ); + free( device ); + + return NULL; + } + + const int rc = iscsi_hashmap_put( device->luns, hash_key, sizeof(lun_hash), (uint8_t *) lun ); + + if ( rc < 0 ) { + iscsi_hashmap_key_destroy( hash_key ); + iscsi_scsi_lun_destroy( lun ); + iscsi_hashmap_destroy( device->luns ); + free( device->name ); + free( device ); - lun->device = device; + return NULL; } + lun->device = device; + device->ports = iscsi_hashmap_create( 0U ); if ( device->ports == NULL ) { logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device ports hash map" ); - iscsi_hashmap_iterate( device->luns, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_key_destroy( hash_key ); + iscsi_scsi_lun_destroy( lun ); iscsi_hashmap_destroy( device->luns ); free( device->name ); free( device ); @@ -6635,6 +6730,7 @@ iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns, const ui device->id = 0; device->flags = 0; + device->ref = 1UL; device->protocol_id = protocol_id; return device; @@ -6652,7 +6748,7 @@ iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns, const ui */ void iscsi_device_destroy(iscsi_device *device) { - if ( device != NULL ) { + if ( (device != NULL) && (--device->ref == 0UL) ) { if ( device->ports != NULL ) { iscsi_hashmap_destroy( device->ports ); @@ -6703,41 +6799,6 @@ iscsi_port *iscsi_device_find_port_by_portal_group_tag(const iscsi_device *devic } /** - * @brief Finds an iSCSI LUN by LUN identifier. - * - * Callback function for each element while iterating - * through the iSCSI device hash map.\n - * LUNs about to be removed are not returned by this - * callback. - * - * @param[in] key Pointer to zero padded key. NULL is - * an invalid pointer here, so be careful. - * @param[in] key_size Number of bytes for the key. - * @param[in] value Value of the key, NULL creates an - * empty key assignment. - * @param[in,out] user_data Pointer to a data structure - * containing the iSCSI LUN and the LUN id to be - * searched for and may NOT be NULL, so be - * careful. - * @retval -1 The LUN has been found and stored - * in the result structure. Therefore, no further - * searching is needed. - * @retval 0 The LUN has not been found yet. - */ -int iscsi_device_find_lun_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data) -{ - iscsi_device_find_lun_id *lun_find = (iscsi_device_find_lun_id *) user_data; - iscsi_scsi_lun *lun = (iscsi_scsi_lun *) value; - - if ( (lun->id != lun_find->id) || ((lun->flags & ISCSI_SCSI_LUN_FLAGS_REMOVED) != 0) ) - return 0; - - lun_find->lun = lun; - - return -1; -} - -/** * @brief Searches an iSCSI LUN by LUN identifier. * * This function searches for an iSCSI LUN by @@ -6755,11 +6816,14 @@ int iscsi_device_find_lun_callback(uint8_t *key, const size_t key_size, uint8_t */ iscsi_scsi_lun *iscsi_device_find_lun(iscsi_device *device, const int lun_id) { - iscsi_device_find_lun_id lun_find = {NULL, lun_id}; + const uint64_t hash_key = (uint64_t) lun_id; + iscsi_scsi_lun *lun; + const int rc = iscsi_hashmap_get( device->luns, (uint8_t *) &hash_key, sizeof(hash_key), (uint8_t **) &lun ); - iscsi_hashmap_iterate( device->luns, iscsi_device_find_lun_callback, (uint8_t *) &lun_find ); + if ( (rc < 0) || ((lun->flags & ISCSI_SCSI_LUN_FLAGS_REMOVED) != 0) ) + return NULL; - return lun_find.lun; + return lun; } /** @@ -6902,7 +6966,7 @@ static int iscsi_target_node_check_flags(const int flags, const int32_t chap_gro */ int iscsi_target_node_create_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data) { - iscsi_target_node *target = (iscsi_target_node *) user_data; + iscsi_target_node *target = (iscsi_target_node *) user_data; iscsi_portal_group *portal_group = (iscsi_portal_group *) value; uint8_t *port_name = iscsi_sprintf_alloc( "%s,t,0x%4.4" PRIx64, target->device->name, portal_group->tag ); @@ -6922,7 +6986,7 @@ int iscsi_target_node_create_callback(uint8_t *key, const size_t key_size, uint8 * may NOT be NULL, so be careful. * @param[in] alias Pointer to alias of IQN name. * @param[in] index Target node index number. - * @param[in] luns Number of LUNs for underlying SCSI device. + * @param[in] lun_id LUN identifier to associate with underlying SCSI device. * @param[in] queue_depth Maximum queue depth. * @param[in] flags Flags for this target node. * @param[in] chap_group CHAP group to associate this node with. @@ -6931,7 +6995,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(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 int lun_id, 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; @@ -6979,14 +7043,7 @@ iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, 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" ); - + if ( image == NULL ) { if ( target->alias != NULL ) free( target->alias ); @@ -6996,10 +7053,123 @@ iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, return NULL; } - const int rc = iscsi_hashmap_iterate( iscsi_globvec->portal_groups, iscsi_target_node_create_callback, (uint8_t *) target ); + const uint key_len = (uint) (strlen( (char *) image->name ) + 1U); + uint8_t *hash_key = iscsi_hashmap_key_create( (uint8_t *) image->name, key_len ); + iscsi_device *device = NULL; + + pthread_rwlock_wrlock( &iscsi_globvec->devices_rwlock ); + int rc = iscsi_hashmap_get( iscsi_globvec->devices, hash_key, key_len, (uint8_t **) &device ); + + if ( device != NULL ) { + iscsi_scsi_lun *lun = iscsi_device_find_lun( device, lun_id ); + + if ( lun == NULL ) { + lun = iscsi_scsi_lun_create( lun_id ); + + if ( lun == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI device LUN hash map" ); + + pthread_rwlock_unlock( &iscsi_globvec->devices_rwlock ); + iscsi_hashmap_key_destroy( hash_key ); + + if ( target->alias != NULL ) + free( target->alias ); + + free( target->name ); + free( target ); + + return NULL; + } + + const uint64_t lun_hash = lun_id; + uint8_t *lun_hash_key = iscsi_hashmap_key_create( (uint8_t *) &lun_hash, sizeof(lun_hash) ); + + if ( lun_hash_key == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI device LUN hash map" ); + + pthread_rwlock_unlock( &iscsi_globvec->devices_rwlock ); + iscsi_scsi_lun_destroy( lun ); + iscsi_hashmap_key_destroy( hash_key ); + + if ( target->alias != NULL ) + free( target->alias ); + + free( target->name ); + free( target ); + + return NULL; + } + + const int rc = iscsi_hashmap_put( device->luns, lun_hash_key, sizeof(lun_hash), (uint8_t *) lun ); + + if ( rc < 0 ) { + pthread_rwlock_unlock( &iscsi_globvec->devices_rwlock ); + iscsi_hashmap_key_destroy( lun_hash_key ); + iscsi_scsi_lun_destroy( lun ); + iscsi_hashmap_key_destroy( hash_key ); + + if ( target->alias != NULL ) + free( target->alias ); + + free( target->name ); + free( target ); + + return NULL; + } + } + + device->ref++; + + iscsi_hashmap_key_destroy( hash_key ); + } else { + device = iscsi_device_create( (uint8_t *) image->name, lun_id, ISCSI_TRANSPORT_ID_PROTOCOL_ID_ISCSI ); + + if ( device == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI target device" ); + + pthread_rwlock_unlock( &iscsi_globvec->devices_rwlock ); + iscsi_hashmap_key_destroy( hash_key ); + + if ( target->alias != NULL ) + free( target->alias ); + + free( target->name ); + free( target ); + + return NULL; + } + + rc = iscsi_hashmap_put( iscsi_globvec->devices, hash_key, key_len, (uint8_t *) device ); + + if ( rc < 0 ) { + pthread_rwlock_unlock( &iscsi_globvec->devices_rwlock ); + iscsi_device_destroy( device ); + iscsi_hashmap_key_destroy( hash_key ); + + if ( target->alias != NULL ) + free( target->alias ); + + free( target->name ); + free( target ); + + return NULL; + } + } + + pthread_rwlock_unlock( &iscsi_globvec->devices_rwlock ); + + target->device = device; + + pthread_rwlock_rdlock( &iscsi_globvec->portal_groups_rwlock ); + rc = iscsi_hashmap_iterate( iscsi_globvec->portal_groups, iscsi_target_node_create_callback, (uint8_t *) target ); + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); if ( rc < 0 ) { - iscsi_device_destroy( target->device ); + pthread_rwlock_wrlock( &iscsi_globvec->devices_rwlock ); + iscsi_hashmap_remove( iscsi_globvec->devices, hash_key, key_len ); + pthread_rwlock_unlock( &iscsi_globvec->devices_rwlock ); + iscsi_device_destroy( device ); + iscsi_hashmap_key_destroy( hash_key ); if ( target->alias != NULL ) free( target->alias ); @@ -7082,38 +7252,6 @@ int32_t iscsi_target_node_send(iscsi_connection *conn, const uint8_t *dst_iqn, c } /** - * @brief Finds an iSCSI target node by case insensitive name search. - * - * Callback function for each element while iterating - * through the iSCSI target nodes. - * - * @param[in] key Pointer to zero padded key. NULL is - * an invalid pointer here, so be careful. - * @param[in] key_size Number of bytes for the key. - * @param[in] value Value of the key, NULL creates an - * empty key assignment. - * @param[in,out] user_data Pointer to a data structure - * containing the iSCSI target node and the name to be - * searched for and may NOT be NULL, so be careful. - * @retval -1 The target node has been found and stored - * in the result structure. Therefore, no further - * searching is needed. - * @retval 0 The target node has not been found yet. - */ -int iscsi_target_node_find_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data) -{ - iscsi_target_node_find_name *target_find = (iscsi_target_node_find_name *) user_data; - iscsi_target_node *target = (iscsi_target_node *) value; - - if ( strcasecmp( (char *) target->name, (char *) target_find->name ) != 0 ) - return 0; - - target_find->target = target; - - return -1; -} - -/** * @brief Calculates the WWN using 64-bit IEEE Extended NAA for a name. * * @param[in] name Pointer to string containing the @@ -7219,6 +7357,38 @@ dnbd3_image_t *iscsi_target_node_image_get(uint8_t *iqn) } /** + * @brief Finds an iSCSI target node by case insensitive name search. + * + * Callback function for each element while iterating + * through the iSCSI target nodes. + * + * @param[in] key Pointer to zero padded key. NULL is + * an invalid pointer here, so be careful. + * @param[in] key_size Number of bytes for the key. + * @param[in] value Value of the key, NULL creates an + * empty key assignment. + * @param[in,out] user_data Pointer to a data structure + * containing the iSCSI target node and the name to be + * searched for and may NOT be NULL, so be careful. + * @retval -1 The target node has been found and stored + * in the result structure. Therefore, no further + * searching is needed. + * @retval 0 The target node has not been found yet. + */ +int iscsi_target_node_find_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data) +{ + iscsi_target_node_find_name *target_find = (iscsi_target_node_find_name *) user_data; + iscsi_target_node *target = (iscsi_target_node *) value; + + if ( strcasecmp( (char *) target->name, (char *) target_find->name ) != 0 ) + return 0; + + target_find->target = target; + + return -1; +} + +/** * @brief Searches an iSCSI target node by name using case insensitive search. * * This function searches for an iSCSI target node @@ -7237,44 +7407,56 @@ iscsi_target_node *iscsi_target_node_find(uint8_t *target_name) iscsi_target_node_find_name target_find = {NULL, target_name}; + pthread_rwlock_wrlock( &iscsi_globvec->target_nodes_rwlock ); iscsi_hashmap_iterate( iscsi_globvec->target_nodes, iscsi_target_node_find_callback, (uint8_t *) &target_find ); - if ( target_find.target == NULL ) { + iscsi_target_node *target = target_find.target; + + if ( target == NULL ) { dnbd3_image_t *image = iscsi_target_node_image_get( target_name ); - if ( image == NULL ) + if ( image == NULL ) { + pthread_rwlock_unlock( &iscsi_globvec->target_nodes_rwlock ); + return NULL; + } - target_find.target = iscsi_target_node_create( target_name, NULL, 0, 8U, 16U, 0, 0L, 0, 0 ); + target = iscsi_target_node_create( target_name, NULL, 0, image->rid, 16U, 0, 0L, 0, 0 ); - if ( target_find.target == NULL ) { + if ( target == NULL ) { logadd( LOG_ERROR, "iscsi_target_node_find: Out of memory while allocating iSCSI target node" ); + pthread_rwlock_unlock( &iscsi_globvec->target_nodes_rwlock ); + return NULL; } const uint key_len = (uint) (strlen( (char *) target_name ) + 1U); - uint8_t *hash_key = iscsi_hashmap_key_create( target_name, key_len ); + 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 ); + pthread_rwlock_unlock( &iscsi_globvec->target_nodes_rwlock ); + iscsi_target_node_destroy( target ); return NULL; } - int rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, (uint8_t *) hash_key, sizeof(key_len), (uint8_t *) target_find.target ); + int rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, (uint8_t *) hash_key, sizeof(key_len), (uint8_t *) target ); if ( rc < 0 ) { + pthread_rwlock_unlock( &iscsi_globvec->target_nodes_rwlock ); iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); - iscsi_target_node_destroy( target_find.target ); + iscsi_target_node_destroy( target ); return NULL; } } - return target_find.target; + pthread_rwlock_unlock( &iscsi_globvec->target_nodes_rwlock ); + + return target; } /** @@ -9034,8 +9216,13 @@ static iscsi_session *iscsi_session_get_by_tsih(const uint16_t tsih) const uint64_t hash_key = tsih; iscsi_session *session; + + pthread_rwlock_rdlock( &iscsi_globvec->sessions_rwlock ); + int rc = iscsi_hashmap_get( iscsi_globvec->sessions, (uint8_t *) &hash_key, sizeof(hash_key), (uint8_t **) &session ); + pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock ); + return (rc == 0) ? session : NULL; } @@ -9050,12 +9237,11 @@ static iscsi_session *iscsi_session_get_by_tsih(const uint16_t tsih) * @param[in] init_port_name Pointer to initiator port name, * may NOT be NULL, so take caution. * @param[in] tsih Target Session Identifying Handle (TSIH). - * @param[in] cid Connection ID (CID). * @return Upper 8 bits of contain status class, lower 8 * bits status detail. All 16 bits set to zero * indicate success. */ -static uint16_t iscsi_session_append(iscsi_connection *conn, const uint8_t *init_port_name, const uint16_t tsih, const uint16_t cid) +static uint16_t iscsi_session_append(iscsi_connection *conn, const uint8_t *init_port_name, const uint16_t tsih) { iscsi_session *session = iscsi_session_get_by_tsih( tsih ); @@ -9096,7 +9282,7 @@ static int iscsi_connection_login_check_session(iscsi_connection *conn, iscsi_pd int rc = 0; if ( login_response_pkt->tsih != 0U ) { - rc = iscsi_session_append( conn, init_port_name, iscsi_get_be16(login_response_pkt->tsih), (uint16_t) cid ); + rc = iscsi_session_append( conn, init_port_name, iscsi_get_be16(login_response_pkt->tsih) ); if ( rc != 0 ) { login_response_pkt->status_class = (uint8_t) (rc >> 8U); @@ -9667,23 +9853,27 @@ void iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu, iscsi_co uint64_t *exec_data = malloc( 64 ); - exec_data[2] = (uint64_t *) iscsi_connection_pdu_write_complete; + exec_data[2] = (uint64_t) iscsi_connection_pdu_write_complete; exec_data[3] = 2ULL; - exec_data[4] = pdu; + exec_data[4] = (uint64_t) pdu; exec_data[5] = (rc == (int32_t) len) ? 0 : -1; + pthread_mutex_lock( &iscsi_globvec->exec_queue_mutex ); iscsi_list_enqueue( &iscsi_globvec->exec_queue, (iscsi_node *) exec_data ); + pthread_mutex_unlock( &iscsi_globvec->exec_queue_mutex ); if ( callback == NULL ) return; exec_data = malloc( 64 ); - exec_data[2] = (uint64_t *) callback; + exec_data[2] = (uint64_t) callback; exec_data[3] = 1ULL; - exec_data[4] = user_data; + exec_data[4] = (uint64_t) user_data; + pthread_mutex_lock( &iscsi_globvec->exec_queue_mutex ); iscsi_list_enqueue( &iscsi_globvec->exec_queue, (iscsi_node *) exec_data ); + pthread_mutex_unlock( &iscsi_globvec->exec_queue_mutex ); // TODO: End remove after I/O async implementation // iscsi_connection_pdu_write_complete( (uint8_t *) pdu, (rc == (int32_t) len) ? 0 : -1 ); @@ -9964,7 +10154,7 @@ static int iscsi_connection_pdu_header_handle_scsi_cmd(iscsi_connection *conn, i iscsi_scsi_cmd_packet *stat_scsi_cmd_pkt = (iscsi_scsi_cmd_packet *) pdu->bhs_pkt; uint64_t stat_opcode = (uint64_t) stat_scsi_cmd_pkt->scsi_cdb.opcode; uint64_t *stat_value = NULL; - int stat_rc = iscsi_hashmap_get( conn->stat_scsi_opcodes, (uint8_t *) &stat_opcode, sizeof(stat_opcode), (uint8_t *) &stat_value ); + int stat_rc = iscsi_hashmap_get( conn->stat_scsi_opcodes, (uint8_t *) &stat_opcode, sizeof(stat_opcode), (uint8_t **) &stat_value ); if ( stat_value == NULL ) { stat_value = malloc( sizeof(uint64_t) ); @@ -10020,6 +10210,7 @@ static int iscsi_connection_pdu_header_handle_scsi_cmd(iscsi_connection *conn, i const uint64_t lun = iscsi_get_be64(scsi_cmd_pkt->lun); const int lun_id = iscsi_scsi_lun_get_from_iscsi( lun ); + task->lun_id = lun_id; task->scsi_task.lun = iscsi_device_find_lun( conn->device, lun_id ); if ( task->scsi_task.lun == NULL ) { @@ -11089,9 +11280,13 @@ static int iscsi_connection_login_set_info(iscsi_connection *conn, iscsi_pdu *lo conn->stat_sn = iscsi_get_be32(login_response_pkt->stat_sn); conn->session->isid = isid; + pthread_rwlock_wrlock( &iscsi_globvec->sessions_rwlock ); iscsi_hashmap_key_create_id( iscsi_globvec->sessions, &conn->session->tsih ); + int rc = iscsi_hashmap_put( iscsi_globvec->sessions, (uint8_t *) &conn->session->tsih, sizeof(conn->session->tsih), (uint8_t *) conn->session ); + pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock ); + if ( rc < 0 ) { iscsi_session_destroy( conn->session ); conn->session = NULL; @@ -11964,7 +12159,7 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn) uint64_t stat_opcode = (uint64_t) ISCSI_GET_OPCODE(bhs_pkt->opcode); uint64_t *stat_value = NULL; - int stat_rc = iscsi_hashmap_get( conn->stat_iscsi_opcodes, (uint8_t *) &stat_opcode, sizeof(stat_opcode), (uint8_t *) &stat_value ); + int stat_rc = iscsi_hashmap_get( conn->stat_iscsi_opcodes, (uint8_t *) &stat_opcode, sizeof(stat_opcode), (uint8_t **) &stat_value ); if ( stat_value == NULL ) { stat_value = malloc( sizeof(uint64_t) ); @@ -12103,29 +12298,32 @@ int iscsi_connection_pdu_handle(iscsi_connection *conn) int i; for ( i = 0; i < ISCSI_PDU_HANDLE_COUNT; i++ ) { - pthread_rwlock_wrlock( &iscsi_globvec_rwlock ); - - if ( iscsi_globvec == NULL ) { - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); - - return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - } - // TODO: Remove after I/O sync implementation + pthread_mutex_lock( &iscsi_globvec->exec_queue_mutex ); iscsi_list_create( &iscsi_globvec->exec_queue ); + pthread_mutex_unlock( &iscsi_globvec->exec_queue_mutex ); const int rc = iscsi_connection_pdu_read( conn ); // TODO: Start: Remove after I/O sync implementation - while ( !iscsi_list_empty( &iscsi_globvec->exec_queue ) ) { + for ( ;; ) { + pthread_mutex_lock( &iscsi_globvec->exec_queue_mutex ); + + if ( iscsi_list_empty( &iscsi_globvec->exec_queue ) ) { + pthread_mutex_unlock( &iscsi_globvec->exec_queue_mutex ); + + break; + } + uint64_t *exec_data = (uint64_t *) iscsi_list_peek( &iscsi_globvec->exec_queue ); iscsi_list_remove( (iscsi_node *) exec_data ); + pthread_mutex_unlock( &iscsi_globvec->exec_queue_mutex ); 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] ); + callback( (iscsi_scsi_task *) exec_data[4] ); } else if ( exec_data[3] == 2ULL ) { iscsi_connection_write_complete_callback callback = (iscsi_connection_write_complete_callback) exec_data[2]; callback( (uint8_t *) exec_data[4], (int) exec_data[5] ); @@ -12139,8 +12337,6 @@ int iscsi_connection_pdu_handle(iscsi_connection *conn) // TODO: End: Remove after I/O sync implementation - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); - if ( rc == ISCSI_CONNECT_PDU_READ_OK ) break; else if ( rc == ISCSI_CONNECT_PDU_READ_ERR_FATAL ) @@ -12172,13 +12368,16 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ _Static_assert( sizeof(dnbd3_request_t) <= sizeof(struct iscsi_bhs_packet), "DNBD3 request size larger than iSCSI BHS packet data size - Manual intervention required!" ); sock_setTimeout( client->sock, 1000L * 3600L ); // TODO: Remove after finishing iSCSI implementation - pthread_rwlock_wrlock( &iscsi_globvec_rwlock ); + pthread_rwlock_rdlock( &iscsi_globvec_rwlock ); if ( iscsi_globvec == NULL ) return; uint64_t *hash_key; iscsi_portal_group *portal_group = NULL; + + pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock ); + 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 ( portal_group == NULL ) { @@ -12187,6 +12386,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ if ( hash_key == NULL ) { logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" ); + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); return; @@ -12199,6 +12399,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ 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->portal_groups_rwlock ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); return; @@ -12212,12 +12413,14 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ if ( rc < 0 ) { iscsi_portal_group_destroy( portal_group ); + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); return; } } + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); host_to_string( &client->host, client->hostName, HOSTNAMELEN ); const uint8_t *port = memchr( client->hostName, ':', HOSTNAMELEN ); @@ -12267,6 +12470,8 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ } iscsi_portal *portal = NULL; + + pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock ); rc = iscsi_hashmap_get( portal_group->portals, (uint8_t *) hash_key, key_len, (uint8_t **) &portal ); if ( portal == NULL ) { @@ -12280,7 +12485,8 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ if ( portal == NULL ) { logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal" ); - iscsi_hashmap_key_destroy( hash_key ); + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); free( host ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -12290,8 +12496,9 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ rc = iscsi_portal_group_add_portal( portal_group, portal ); if ( rc < 0 ) { + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); iscsi_portal_destroy( portal ); - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); free( host ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -12299,7 +12506,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ } } - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); free( host ); iscsi_connection *conn = iscsi_connection_create( portal, client->sock ); @@ -12314,11 +12521,15 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ return; } + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); + conn->pdu_processing = iscsi_connection_pdu_create( conn, 0U, 0, 0UL, 0 ); if ( conn->pdu_processing == NULL ) { iscsi_connection_destroy( conn ); + pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock ); iscsi_portal_group_del_portal( portal_group, portal ); + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); iscsi_portal_destroy( portal ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); @@ -12328,30 +12539,28 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ memcpy( conn->pdu_processing->bhs_pkt, request, len ); conn->pdu_processing->bhs_pos = len; - conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_HDR; + conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_HDR; - pthread_rwlock_unlock( &iscsi_globvec_rwlock ); + logadd( LOG_INFO, "" ); + logadd( LOG_INFO, "iSCSI connection opened for device %s from initiator %s using port %s and portal %s:%s", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port ); while ( iscsi_connection_pdu_handle( conn ) >= ISCSI_CONNECT_PDU_READ_OK ) { } - pthread_rwlock_wrlock( &iscsi_globvec_rwlock ); - - if ( iscsi_globvec == NULL ) - return; - iscsi_hashmap_bucket *stat_bucket; + logadd( LOG_INFO, "iSCSI connection closed for device %s from initiator %s using port %s and portal %s:%s", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port ); + iscsi_list_foreach_node ( &conn->stat_iscsi_opcodes->list, stat_bucket ) { uint64_t *stat_opcode = (uint64_t *) stat_bucket->value; - logadd( LOG_INFO, "iSCSI opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: Opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? conn->device->name : "(null)"), conn->init_name, ((conn->init_port != NULL) ? conn->init_port->name : "(null)"), portal->host, portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode ); + logadd( LOG_INFO, "iSCSI opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: Opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode ); } iscsi_list_foreach_node ( &conn->stat_scsi_opcodes->list, stat_bucket ) { uint64_t *stat_opcode = (uint64_t *) stat_bucket->value; - logadd( LOG_INFO, "iSCSI SCSI CDB opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: SCSI CDB opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? conn->device->name : "(null)"), conn->init_name, ((conn->init_port != NULL) ? conn->init_port->name : "(null)"), portal->host, portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode ); + logadd( LOG_INFO, "iSCSI SCSI CDB opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: SCSI CDB opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode ); } iscsi_session *session = conn->session; @@ -12369,8 +12578,10 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ iscsi_connection_destroy( conn ); + pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock ); iscsi_portal_group_del_portal( portal_group, portal ); iscsi_portal_destroy( portal ); + pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock ); pthread_rwlock_unlock( &iscsi_globvec_rwlock ); } diff --git a/src/server/iscsi.h b/src/server/iscsi.h index 33346af..b45772f 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -9917,15 +9917,27 @@ typedef struct iscsi_globals { /// Hash map containing all iSCSI devices. iscsi_hashmap *devices; + /// Read/write lock for hash map containing all iSCSI devices. MUST be initialized with iscsi_create before any iSCSI functions are used. + pthread_rwlock_t devices_rwlock; + /// Hash map containing all registered iSCSI portal groups. iscsi_hashmap *portal_groups; + /// Read/write lock for hash map containing all iSCSI portal_groups. MUST be initialized with iscsi_create before any iSCSI functions are used. + pthread_rwlock_t portal_groups_rwlock; + /// iSCSI target nodes. iscsi_hashmap *target_nodes; + /// Read/write lock for hash map containing all iSCSI target nodes. MUST be initialized with iscsi_create before any iSCSI functions are used. + pthread_rwlock_t target_nodes_rwlock; + /// Hash map containing all iSCSI sessions. iscsi_hashmap *sessions; + /// Read/write lock for hash map containing all iSCSI sessions. MUST be initialized with iscsi_create before any iSCSI functions are used. + pthread_rwlock_t sessions_rwlock; + /// Hash map containing session key and value pair types and allowed values or ranges. iscsi_hashmap *session_key_value_pairs; @@ -9935,6 +9947,9 @@ typedef struct iscsi_globals { // TODO: Remove after async I/O implementation iscsi_list exec_queue; + // TODO: Remove after async I/O implementation + pthread_mutex_t exec_queue_mutex; + /// Global flags. int flags; @@ -10524,7 +10539,7 @@ int iscsi_scsi_task_status_copy(iscsi_scsi_task *dst_scsi_task, const iscsi_scsi void iscsi_scsi_task_lun_process_none(iscsi_scsi_task *scsi_task); // Processes a iSCSI SCSI task with no LUN identifier void iscsi_scsi_task_lun_process_abort(iscsi_scsi_task *scsi_task); // Processes a iSCSI SCSI aborted task -iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id); // Allocates and initializes an iSCSI LUN structure for linkage with a DNBD3 image +iscsi_scsi_lun *iscsi_scsi_lun_create(const int lun_id); // Allocates and initializes an iSCSI LUN structure for linkage with a DNBD3 image void iscsi_scsi_lun_destroy(iscsi_scsi_lun *lun); // Deallocates all resources acquired by iscsi_scsi_lun_create uint64_t iscsi_scsi_lun_get_from_scsi(const int lun_id); // Converts an internal representation of a LUN identifier to an iSCSI LUN required for packet data @@ -10682,26 +10697,14 @@ typedef struct iscsi_device { /// Flags. int flags; + /// Reference counter. + uint32_t ref; + /// Protocol identifier. uint8_t protocol_id; } iscsi_device; -/** - * @brief iSCSI device search by LUN identifier. - * - * This structure is used by iterating through - * all iSCSI LUNs finding by LUN identifier. - */ -typedef struct iscsi_device_find_lun_id { - /// Found iSCSI LUN is stored here, should be initialized to NULL. - iscsi_scsi_lun *lun; - - /// The LUN identifier to search for (always MUST be between 0 and 7). - int id; -} iscsi_device_find_lun_id; - - /// iSCSI target node WWN identifier prefix string. #define ISCSI_TARGET_NODE_WWN_NAME_PREFIX "wwn-0x" @@ -11363,11 +11366,10 @@ void iscsi_task_xfer_complete_process_other(iscsi_connection *conn, iscsi_task * void iscsi_task_response(iscsi_connection *conn, iscsi_task *task); // Creates, initializes and sends an iSCSI task reponse PDU. -iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns, const uint8_t protocol_id); // Creates and initializes an iSCSI device with a maximum number of LUNs +iscsi_device *iscsi_device_create(const uint8_t *name, const int lun_id, const uint8_t protocol_id); // Creates and initializes an iSCSI device with a maximum number of LUNs void iscsi_device_destroy(iscsi_device *device); // Deallocates all resources acquired by iscsi_device_create iscsi_port *iscsi_device_find_port_by_portal_group_tag(const iscsi_device *device, const uint64_t id); // Gets an iSCSI device being in use by portal group identifier -int iscsi_device_find_lun_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Finds an iSCSI LUN by LUN identifier iscsi_scsi_lun *iscsi_device_find_lun(iscsi_device *device, const int lun_id); // Searches an iSCSI LUN by LUN identifier int iscsi_device_port_add(iscsi_device *device, const uint8_t *name, const uint64_t id); // Creates, initializes and adds an iSCSI target port to an iSCSI device @@ -11375,7 +11377,7 @@ 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(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 int lun_id, 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 int32_t 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 |
