summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Rettberg2025-10-06 15:00:20 +0200
committerSimon Rettberg2025-10-06 15:00:20 +0200
commit688b3c61c5d12e68c281f0ade1e986572ffecfb5 (patch)
treec2340239933919c3bdc6b2cdfd0c0a5d4e470877 /src
parentImplemented iSCSI global and SCSI device specific INI file configuration. Als... (diff)
downloaddnbd3-688b3c61c5d12e68c281f0ade1e986572ffecfb5.tar.gz
dnbd3-688b3c61c5d12e68c281f0ade1e986572ffecfb5.tar.xz
dnbd3-688b3c61c5d12e68c281f0ade1e986572ffecfb5.zip
[SERVER] iscsi: Implement relaying requests to uplink servers
Diffstat (limited to 'src')
-rw-r--r--src/server/iscsi.c66
-rw-r--r--src/server/iscsi.h6
2 files changed, 69 insertions, 3 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index b44f695..c634013 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -46,7 +46,9 @@
#include "ini.h"
#include "iscsi.h"
#include "locks.h"
+#include "uplink.h"
#include "threadpool.h"
+#include "reference.h"
/**
* @file iscsi.c
@@ -1310,7 +1312,7 @@ int iscsi_create()
}
globvec->flags = (ISCSI_GLOBALS_FLAGS_INIT_R2T | ISCSI_GLOBALS_FLAGS_IMMEDIATE_DATA | ISCSI_GLOBALS_FLAGS_DATA_PDU_IN_ORDER | ISCSI_GLOBALS_FLAGS_DATA_SEQ_IN_ORDER | ISCSI_GLOBALS_FLAGS_SCSI_IO_REMOVABLE | ISCSI_GLOBALS_FLAGS_SCSI_IO_WRITE_PROTECT);
- globvec->target_name_check = ISCSI_GLOBALS_TARGET_NAME_CHECK_FULL;
+ globvec->target_name_check = ISCSI_GLOBALS_TARGET_NAME_CHECK_RELAXED;
globvec->max_sessions = 0U;
globvec->header_digest = 0;
globvec->data_digest = 0;
@@ -5269,6 +5271,25 @@ 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.
+ *
+ * @param[in] data related scsi_task
+ * @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->up_mutex );
+ pthread_cond_signal( &scsi_task->up_cond );
+ pthread_mutex_unlock( &scsi_task->up_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
@@ -5301,8 +5322,6 @@ int iscsi_scsi_emu_io_block_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3
{
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 = pread( image->readFd, 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) );
if ( exec_queue == NULL ) {
@@ -5311,6 +5330,47 @@ int iscsi_scsi_emu_io_block_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3
return -ENOMEM;
}
+ dnbd3_cache_map_t *cache = ref_get_cachemap( image );
+ bool readFromFile;
+
+ if ( cache == NULL ) {
+ readFromFile = true;
+ } else {
+ // This is a proxyed image, check if we need to relay the request...
+ const uint64_t start = offset_bytes & ~(uint64_t)(DNBD3_BLOCK_SIZE - 1);
+ const uint64_t end = (offset_bytes + num_bytes + DNBD3_BLOCK_SIZE - 1) & ~(uint64_t)(DNBD3_BLOCK_SIZE - 1);
+ readFromFile = image_isRangeCachedUnsafe( cache, start, end );
+ ref_put( &cache->reference );
+
+ if ( !readFromFile ) {
+ // Not cached, request via uplink
+ pthread_mutex_init( &scsi_task->up_mutex, NULL );
+ pthread_cond_init( &scsi_task->up_cond, NULL );
+ pthread_mutex_lock( &scsi_task->up_mutex );
+ if ( !uplink_request( image, scsi_task, &iscsi_uplink_callback, (uint64_t)buf, offset_bytes, num_bytes ) ) {
+ pthread_mutex_unlock( &scsi_task->up_mutex );
+ pthread_cond_destroy( &scsi_task->up_cond );
+ pthread_mutex_destroy( &scsi_task->up_mutex );
+ logadd( LOG_DEBUG1, "Could not relay uncached request to upstream proxy for image %s:%d",
+ image->name, image->rid );
+ return -EIO;
+ }
+ // Wait sync (Maybe use pthread_cond_timedwait to detect unavailable uplink instead of hanging...)
+ pthread_cond_wait( &scsi_task->up_cond, &scsi_task->up_mutex );
+ pthread_mutex_unlock( &scsi_task->up_mutex );
+ pthread_cond_destroy( &scsi_task->up_cond );
+ pthread_mutex_destroy( &scsi_task->up_mutex );
+ }
+ }
+
+ bool success;
+ if ( readFromFile ) {
+ const int64_t len = pread( image->readFd, buf, (size_t) num_bytes, offset_bytes );
+ success = ((uint64_t) len == num_bytes);
+ } else {
+ success = true;
+ }
+
exec_queue->data.io.callback = callback;
exec_queue->data.io.image = image;
exec_queue->data.io.user_data = user_data;
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index 193b292..4c284e0 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -10858,6 +10858,12 @@ typedef struct iscsi_scsi_task {
/// Task management response code.
uint8_t task_mgmt_response;
+
+ /// Uplink read mutex for sync
+ pthread_mutex_t up_mutex;
+
+ /// Conditional to signal uplink read complete
+ pthread_cond_t up_cond;
} iscsi_scsi_task;