summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSebastian Vater2025-10-07 10:53:52 +0200
committerSebastian Vater2025-10-07 10:53:52 +0200
commit2f21de161fe6e81d82044e0af71ddd857af2f633 (patch)
tree2898497723b39245ca0c07a839099e3241009891 /src
parentMoved uplink mutex / condition init and destroy to task creation and destruct... (diff)
downloaddnbd3-2f21de161fe6e81d82044e0af71ddd857af2f633.tar.gz
dnbd3-2f21de161fe6e81d82044e0af71ddd857af2f633.tar.xz
dnbd3-2f21de161fe6e81d82044e0af71ddd857af2f633.zip
Fixes to iSCSI DNBD3 proxy uplink handling.
Diffstat (limited to 'src')
-rw-r--r--src/server/iscsi.c144
-rw-r--r--src/server/iscsi.h10
2 files changed, 67 insertions, 87 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index afb1e6c..e9b0fc1 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -2871,20 +2871,6 @@ iscsi_task *iscsi_task_create(iscsi_connection *conn, iscsi_task *parent, iscsi_
iscsi_scsi_task_create( &task->scsi_task, callback, iscsi_task_destroy_callback );
- if ( pthread_mutex_init( &task->scsi_task.uplink_mutex, NULL ) != 0 ) {
- logadd( LOG_ERROR, "iscsi_task_create: Error while initializing DNBD3 uplink mutex for iSCSI SCSI task" );
-
- return NULL;
- }
-
- if ( pthread_cond_init( &task->scsi_task.uplink_cond, NULL ) != 0 ) {
- logadd( LOG_ERROR, "iscsi_task_create: Error while initializing DNBD3 uplink condition for iSCSI SCSI task" );
-
- pthread_mutex_destroy( &task->scsi_task.uplink_mutex );
-
- return NULL;
- }
-
if ( parent != NULL ) {
parent->scsi_task.ref++;
@@ -2931,9 +2917,6 @@ void iscsi_task_destroy_callback(iscsi_scsi_task *scsi_task)
task->parent = NULL;
}
- pthread_cond_destroy( &task->scsi_task.uplink_cond );
- pthread_mutex_destroy( &task->scsi_task.uplink_mutex );
-
if ( task->pdu != NULL ) {
iscsi_connection_pdu_destroy( task->pdu );
@@ -5259,6 +5242,32 @@ static int iscsi_scsi_emu_queue_io_wait(iscsi_scsi_task *scsi_task, iscsi_scsi_e
}
/**
+ * @brief Called when data requested via an uplink server has arrived.
+ *
+ * This function is used to retrieve
+ * block data which is NOT locally
+ * available.
+ *
+ * @param[in] data Pointer to related scsi_task. May NOT
+ * be NULL, so be careful.
+ * @param[in] handle Uplink handle.
+ * @param[in] start Start of range in bytes.
+ * @param[in] length Length of range in bytes, as passed to
+ * uplink_request().
+ * @param[in] buffer Data for requested range.
+ */
+static void iscsi_uplink_callback(void *data, uint64_t handle UNUSED, uint64_t start UNUSED, uint32_t length, const char *buffer)
+{
+ iscsi_scsi_task *scsi_task = (iscsi_scsi_task *) data;
+
+ memcpy( scsi_task->buf, buffer, length );
+
+ pthread_mutex_lock( &scsi_task->uplink_mutex );
+ pthread_cond_signal( &scsi_task->uplink_cond );
+ pthread_mutex_unlock( &scsi_task->uplink_mutex );
+}
+
+/**
* @brief Converts offset and length specified by a block size to offset and length in bytes.
*
* This function uses bit shifting if
@@ -5288,33 +5297,6 @@ static uint64_t iscsi_scsi_emu_blocks_to_bytes(uint64_t *offset_bytes, const uin
}
/**
- * @brief Called when data requested via an uplink server has arrived.
- *
- * This function is used to retrieve
- * block data which is NOT locally
- * available.
- *
- * @param[in] data Pointer to related scsi_task. May NOT
- * be NULL, so be careful.
- * @param[in] handle Pointer to destination buffer, as passed to
- * iscsi_scsi_emu_io_block_read().
- * @param[in] start Start of range in bytes.
- * @param[in] length Length of range in bytes, as passed to
- * uplink_request().
- * @param[in] buffer Data for requested range.
- */
-static void iscsi_uplink_callback(void *data, uint64_t handle, uint64_t start UNUSED, uint32_t length, const char *buffer)
-{
- iscsi_scsi_task *scsi_task = (iscsi_scsi_task *) data;
-
- memcpy( (uint8_t *) handle, buffer, length );
-
- pthread_mutex_lock( &scsi_task->uplink_mutex );
- pthread_cond_signal( &scsi_task->uplink_cond );
- pthread_mutex_unlock( &scsi_task->uplink_mutex );
-}
-
-/**
* @brief Reads a number of blocks from a block offset of a DNBD3 image to a specified buffer.
*
* This function enqueues the I/O read
@@ -5325,9 +5307,6 @@ static void iscsi_uplink_callback(void *data, uint64_t handle, uint64_t start UN
* @param[in] scsi_task Pointer to iSCSI SCSI task which
* executes the I/O read operation, may
* NOT be NULL, so be careful.
- * @param[in] buf Pointer to buffer where to store
- * the read data. NULL is NOT allowed
- * here, take caution.
* @param[in] image Pointer to DNBD3 image to read
* data from and may NOT be NULL, so
* be careful.
@@ -5343,20 +5322,13 @@ static void iscsi_uplink_callback(void *data, uint64_t handle, uint64_t start UN
* @return 0 on successful operation, a negative
* error code otherwise.
*/
-int iscsi_scsi_emu_io_block_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data)
+int iscsi_scsi_emu_io_block_read(iscsi_scsi_task *scsi_task, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data)
{
uint64_t offset_bytes;
- const uint64_t num_bytes = iscsi_scsi_emu_blocks_to_bytes( &offset_bytes, offset_blocks, num_blocks, block_size );
- iscsi_connection_exec_queue *exec_queue = (iscsi_connection_exec_queue *) malloc( sizeof(struct iscsi_connection_exec_queue) );
-
- if ( exec_queue == NULL ) {
- logadd( LOG_ERROR, "iscsi_scsi_emu_io_block_read: Out of memory while allocating execution queue for I/O read" );
-
- return -ENOMEM;
- }
-
+ const uint64_t num_bytes = iscsi_scsi_emu_blocks_to_bytes( &offset_bytes, offset_blocks, num_blocks, block_size );
dnbd3_cache_map_t *cache = ref_get_cachemap( image );
bool readFromFile;
+ bool success;
if ( cache == NULL ) {
readFromFile = true;
@@ -5370,30 +5342,44 @@ int iscsi_scsi_emu_io_block_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3
if ( !readFromFile ) {
// Not cached, request via uplink
- pthread_mutex_lock( &scsi_task->uplink_mutex );
- if ( !uplink_request( image, scsi_task, iscsi_uplink_callback, (uint64_t) buf, offset_bytes, num_bytes ) ) {
- pthread_mutex_unlock( &scsi_task->uplink_mutex );
+ if ( pthread_mutex_init( &scsi_task->uplink_mutex, NULL ) != 0 ) {
+ logadd( LOG_ERROR, "iscsi_scsi_emu_io_block_read: Error while initializing DNBD3 uplink mutex for iSCSI SCSI task" );
+
+ return -ENOMEM;
+ }
+
+ if ( pthread_cond_init( &scsi_task->uplink_cond, NULL ) != 0 ) {
+ logadd( LOG_ERROR, "iscsi_scsi_emu_io_block_read: Error while initializing DNBD3 uplink condition for iSCSI SCSI task" );
- logadd( LOG_DEBUG1, "Could not relay uncached request to upstream proxy for image %s:%d",
- image->name, image->rid );
+ pthread_mutex_destroy( &scsi_task->uplink_mutex );
- return -EIO;
+ return -ENOMEM;
}
- // Wait sync (Maybe use pthread_cond_timedwait to detect unavailable uplink instead of hanging...)
- pthread_cond_wait( &scsi_task->uplink_cond, &scsi_task->uplink_mutex );
+ pthread_mutex_lock( &scsi_task->uplink_mutex );
+ success = uplink_request( image, (void *) scsi_task, iscsi_uplink_callback, 0ULL, offset_bytes, (uint32_t) num_bytes );
+
+ if ( success )
+ pthread_cond_wait( &scsi_task->uplink_cond, &scsi_task->uplink_mutex );
+
pthread_mutex_unlock( &scsi_task->uplink_mutex );
+ pthread_cond_destroy( &scsi_task->uplink_cond );
+ pthread_mutex_destroy( &scsi_task->uplink_mutex );
}
}
- bool success;
-
if ( readFromFile ) {
- const int64_t len = pread( image->readFd, buf, (size_t) num_bytes, offset_bytes );
+ const int64_t len = pread( image->readFd, scsi_task->buf, (size_t) num_bytes, offset_bytes );
success = ((uint64_t) len == num_bytes);
- } else {
- success = true;
+ }
+
+ iscsi_connection_exec_queue *exec_queue = (iscsi_connection_exec_queue *) malloc( sizeof(struct iscsi_connection_exec_queue) );
+
+ if ( exec_queue == NULL ) {
+ logadd( LOG_ERROR, "iscsi_scsi_emu_io_block_read: Out of memory while allocating execution queue for I/O read" );
+
+ return -ENOMEM;
}
exec_queue->data.io.callback = callback;
@@ -5452,9 +5438,6 @@ uint8_t *iscsi_scsi_emu_block_read_complete_callback(dnbd3_image_t *image, uint8
* executes the I/O compare and write
* operation, may NOT be NULL, so be
* careful.
- * @param[in] buf Pointer to buffer which contains
- * the data to be written. NULL is NOT
- * allowed here, take caution.
* @param[in] cmp_buf Pointer to buffer which contains
* the data to be compared and may NOT
* be NULL, so be careful.
@@ -5473,7 +5456,7 @@ uint8_t *iscsi_scsi_emu_block_read_complete_callback(dnbd3_image_t *image, uint8
* @return 0 on successful operation, a negative
* error code otherwise.
*/
-int iscsi_scsi_emu_io_block_cmp_write(iscsi_scsi_task *scsi_task, uint8_t *buf, uint8_t *cmp_buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data)
+int iscsi_scsi_emu_io_block_cmp_write(iscsi_scsi_task *scsi_task, uint8_t *cmp_buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data)
{
// TODO: Implement compare and write I/O.
@@ -5525,9 +5508,6 @@ uint8_t *iscsi_scsi_emu_block_write_complete_callback(dnbd3_image_t *image, uint
* @param[in] scsi_task Pointer to iSCSI SCSI task which
* executes the I/O write operation, may
* NOT be NULL, so be careful.
- * @param[in] buf Pointer to buffer which contains
- * the data to be written. NULL is NOT
- * allowed here, take caution.
* @param[in] image Pointer to DNBD3 image to write
* data to and may NOT be NULL, so
* be careful.
@@ -5543,11 +5523,11 @@ uint8_t *iscsi_scsi_emu_block_write_complete_callback(dnbd3_image_t *image, uint
* @return 0 on successful operation, a negative
* error code otherwise.
*/
-int iscsi_scsi_emu_io_block_write(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data)
+int iscsi_scsi_emu_io_block_write(iscsi_scsi_task *scsi_task, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data)
{
uint64_t offset_bytes;
const uint64_t num_bytes = iscsi_scsi_emu_blocks_to_bytes( &offset_bytes, offset_blocks, num_blocks, block_size );
- const int64_t len = pwrite( image->readFd, buf, (size_t) num_bytes, offset_bytes );
+ const int64_t len = pwrite( image->readFd, scsi_task->buf, (size_t) num_bytes, offset_bytes );
const bool success = ((uint64_t) len == num_bytes);
iscsi_connection_exec_queue *exec_queue = (iscsi_connection_exec_queue *) malloc( sizeof(struct iscsi_connection_exec_queue) );
@@ -5660,7 +5640,7 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task
return ISCSI_SCSI_TASK_RUN_PENDING;
}
- rc = iscsi_scsi_emu_io_block_read( scsi_task, scsi_task->buf, image, offset_blocks, num_blocks, block_size, iscsi_scsi_emu_block_read_complete_callback, (uint8_t *) scsi_task );
+ rc = iscsi_scsi_emu_io_block_read( scsi_task, image, offset_blocks, num_blocks, block_size, iscsi_scsi_emu_block_read_complete_callback, (uint8_t *) scsi_task );
} else if ( iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY ) || iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT ) ) {
iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_DATA_PROTECT, ISCSI_SCSI_ASC_WRITE_PROTECTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE );
@@ -5674,9 +5654,9 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task
uint8_t *cmp_buf = (scsi_task->buf + block_size);
- rc = iscsi_scsi_emu_io_block_cmp_write( scsi_task, scsi_task->buf, cmp_buf, image, offset_blocks, 1ULL, block_size, iscsi_scsi_emu_block_write_complete_callback, (uint8_t *) scsi_task );
+ rc = iscsi_scsi_emu_io_block_cmp_write( scsi_task, cmp_buf, image, offset_blocks, 1ULL, block_size, iscsi_scsi_emu_block_write_complete_callback, (uint8_t *) scsi_task );
} else {
- rc = iscsi_scsi_emu_io_block_write( scsi_task, scsi_task->buf, image, offset_blocks, num_blocks, block_size, iscsi_scsi_emu_block_write_complete_callback, (uint8_t *) scsi_task );
+ rc = iscsi_scsi_emu_io_block_write( scsi_task, image, offset_blocks, num_blocks, block_size, iscsi_scsi_emu_block_write_complete_callback, (uint8_t *) scsi_task );
}
if ( rc < 0 ) {
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index 7ce4122..ded2d1d 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -10823,10 +10823,10 @@ typedef struct iscsi_scsi_task {
/// I/O task wait.
iscsi_scsi_emu_io_wait io_wait;
- /// Uplink read mutex for sync
+ /// Uplink read mutex for synchronization.
pthread_mutex_t uplink_mutex;
- /// Conditional to signal uplink read complete
+ /// Conditional to signal uplink read complete.
pthread_cond_t uplink_cond;
/// Output buffer.
@@ -10941,11 +10941,11 @@ int iscsi_scsi_pr_in(iscsi_scsi_task *scsi_task, iscsi_scsi_pr_reserve_in_parame
int iscsi_scsi_pr_reserve_scsi2(iscsi_scsi_task *scsi_task, const iscsi_scsi_cdb_pr_reserve_6 *cdb_pr_reserve_6); // Reserves an iSCSI SCSI Persistent Reservation (PR) of an iSCSI SCSI task
int iscsi_scsi_pr_release_scsi2(iscsi_scsi_task *scsi_task); // Releases an iSCSI SCSI Persistent Reservation (PR) of an iSCSI SCSI task
-int iscsi_scsi_emu_io_block_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data); // Reads a number of blocks from a block offset of a DNBD3 image to a specified buffer
+int iscsi_scsi_emu_io_block_read(iscsi_scsi_task *scsi_task, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data); // Reads a number of blocks from a block offset of a DNBD3 image to a specified buffer
uint8_t *iscsi_scsi_emu_block_read_complete_callback(dnbd3_image_t *image, uint8_t *user_data, const bool success); // Completes an iSCSI SCSI task after a finished I/O read operation
-int iscsi_scsi_emu_io_block_cmp_write(iscsi_scsi_task *scsi_task, uint8_t *buf, uint8_t *cmp_buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data); // Compares and writes a number of blocks starting from a block offset in a DNBD3 image with specified buffers
+int iscsi_scsi_emu_io_block_cmp_write(iscsi_scsi_task *scsi_task, uint8_t *cmp_buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data); // Compares and writes a number of blocks starting from a block offset in a DNBD3 image with specified buffers
uint8_t *iscsi_scsi_emu_block_write_complete_callback(dnbd3_image_t *image, uint8_t *user_data, const bool success); // Completes an iSCSI SCSI task after a finished I/O write operation
-int iscsi_scsi_emu_io_block_write(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data); // Writes a number of blocks from a block offset to a DNBD3 image of a specified buffer
+int iscsi_scsi_emu_io_block_write(iscsi_scsi_task *scsi_task, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size, iscsi_scsi_emu_io_complete_callback callback, uint8_t *user_data); // Writes a number of blocks from a block offset to a DNBD3 image of a specified buffer
int iscsi_scsi_emu_io_queue(iscsi_scsi_emu_io_wait *io_wait); // Enqueues an I/O wait in the thread pool to execute
uint8_t *iscsi_scsi_emu_block_resubmit_process_callback(uint8_t *user_data); // Resubmits an iSCSI SCSI task for execution