From e00e47d28d869bad5d04a894b9793165061790c4 Mon Sep 17 00:00:00 2001 From: Roy Shterman Date: Fri, 27 May 2016 18:47:21 +0300 Subject: [PATCH] Libiscsi: Introducing new functions for zero-copy read operations iscsi-command: Adding new functions for all write operations (READ6, READ10, READ12, READ16, etc') for cases where the user wants to pass his own io vectors (prevent memcpy). new functions are called iscsi_read*_iov_task and looks very similar to the iscsi_read*_task, only they get scsi_iovec pointer and number of scsi_iovec as parameters. Change-Id: Ice6bdb9227d72b20f495927f17d6757c124e4c84 Signed-off-by: Roy Shterman --- include/iscsi.h | 45 ++++++++++++++- lib/iscsi-command.c | 133 ++++++++++++++++++++++++++++++++++++++++++++ lib/libiscsi.syms | 8 +++ lib/sync.c | 89 +++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 1 deletion(-) diff --git a/include/iscsi.h b/include/iscsi.h index 20f7d62..294182d 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -30,8 +30,10 @@ extern "C" { #endif + struct iscsi_context; struct sockaddr; +struct scsi_iovec; /* API VERSION */ #define LIBISCSI_API_VERSION (20160501) @@ -838,13 +840,21 @@ EXTERN struct scsi_task * iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, iscsi_command_cb cb, void *private_data); - +EXTERN struct scsi_task * +iscsi_read6_iov_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, iscsi_command_cb cb, + void *private_data, struct scsi_iovec *iov, int niov); EXTERN struct scsi_task * iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * +iscsi_read10_iov_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data, struct scsi_iovec *iov, int niov); +EXTERN struct scsi_task * iscsi_write10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number, @@ -860,6 +870,11 @@ iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, int rdprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * +iscsi_read12_iov_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data, struct scsi_iovec *iov, int niov); +EXTERN struct scsi_task * iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number, @@ -875,6 +890,11 @@ iscsi_read16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, int rdprotect, int dpo, int fua, int fua_nv, int group_number, iscsi_command_cb cb, void *private_data); EXTERN struct scsi_task * +iscsi_read16_iov_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data, struct scsi_iovec *iov, int niov); +EXTERN struct scsi_task * iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t datalen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number, @@ -1037,11 +1057,22 @@ EXTERN struct scsi_task * iscsi_read6_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize); +EXTERN struct scsi_task * +iscsi_read6_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + struct scsi_iovec *iov, int niov); + EXTERN struct scsi_task * iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task * +iscsi_read10_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + struct scsi_iovec *iov, int niov); + EXTERN struct scsi_task * iscsi_write10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, @@ -1057,6 +1088,12 @@ iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task * +iscsi_read12_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + struct scsi_iovec *iov, int niov); + EXTERN struct scsi_task * iscsi_write12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, unsigned char *data, uint32_t datalen, int blocksize, @@ -1072,6 +1109,12 @@ iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); +EXTERN struct scsi_task * +iscsi_read16_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + struct scsi_iovec *iov, int niov); + EXTERN struct scsi_task * iscsi_write16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, unsigned char *data, uint32_t datalen, int blocksize, diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index d8349cb..5023920 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -737,6 +737,38 @@ iscsi_get_lba_status_task(struct iscsi_context *iscsi, int lun, return task; } +struct scsi_task * +iscsi_read6_iov_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + iscsi_command_cb cb, void *private_data, struct scsi_iovec *iov, int niov) +{ + struct scsi_task *task; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " + "the blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_read6(lba, datalen, blocksize); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "read6 cdb."); + return NULL; + } + + if (iov != NULL) + scsi_task_set_iov_in(task, iov, niov); + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} + struct scsi_task * iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, @@ -765,6 +797,39 @@ iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, return task; } +struct scsi_task * +iscsi_read10_iov_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data, struct scsi_iovec *iov, int niov) +{ + struct scsi_task *task; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " + "the blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_read10(lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "read10 cdb."); + return NULL; + } + + if (iov != NULL) + scsi_task_set_iov_in(task, iov, niov); + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} struct scsi_task * iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, @@ -795,6 +860,40 @@ iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, return task; } +struct scsi_task * +iscsi_read12_iov_task(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data, struct scsi_iovec *iov, int niov) +{ + struct scsi_task *task; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " + "the blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_read12(lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "read12 cdb."); + return NULL; + } + + if (iov != NULL) + scsi_task_set_iov_in(task, iov, niov); + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} + struct scsi_task * iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, @@ -825,6 +924,40 @@ iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, return task; } +struct scsi_task * +iscsi_read16_iov_task(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + iscsi_command_cb cb, void *private_data, struct scsi_iovec *iov, int niov) +{ + struct scsi_task *task; + + if (datalen % blocksize != 0) { + iscsi_set_error(iscsi, "Datalen:%d is not a multiple of " + "the blocksize:%d.", datalen, blocksize); + return NULL; + } + + task = scsi_cdb_read16(lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number); + if (task == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to create " + "read16 cdb."); + return NULL; + } + + if (iov != NULL) + scsi_task_set_iov_in(task, iov, niov); + + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; + } + + return task; +} + struct scsi_task * iscsi_read16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 628603f..a411448 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -48,13 +48,21 @@ iscsi_queue_length iscsi_out_queue_length iscsi_queue_pdu iscsi_read10_sync +iscsi_read10_iov_sync iscsi_read10_task +iscsi_read10_iov_task iscsi_read12_sync +iscsi_read12_iov_sync iscsi_read12_task +iscsi_read12_iov_task iscsi_read16_sync +iscsi_read16_iov_sync iscsi_read16_task +iscsi_read16_iov_task iscsi_read6_sync +iscsi_read6_iov_sync iscsi_read6_task +iscsi_read6_iov_task iscsi_readcapacity10_sync iscsi_readcapacity10_task iscsi_readcapacity16_sync diff --git a/lib/sync.c b/lib/sync.c index 93f52ca..9b52036 100644 --- a/lib/sync.c +++ b/lib/sync.c @@ -420,6 +420,26 @@ iscsi_read6_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, return state.task; } +struct scsi_task * +iscsi_read6_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, struct scsi_iovec *iov, int niov) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_read6_iov_task(iscsi, lun, lba, datalen, blocksize, + scsi_sync_cb, &state, iov, niov) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Read6 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, @@ -442,6 +462,29 @@ iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, return state.task; } +struct scsi_task * +iscsi_read10_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + struct scsi_iovec *iov, int niov) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_read10_iov_task(iscsi, lun, lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number, + scsi_sync_cb, &state, iov, niov) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Read10 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, uint32_t datalen, int blocksize, @@ -464,6 +507,29 @@ iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, return state.task; } +struct scsi_task * +iscsi_read12_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + struct scsi_iovec *iov, int niov) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_read12_iov_task(iscsi, lun, lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number, + scsi_sync_cb, &state, iov, niov) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Read12 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, uint32_t datalen, int blocksize, @@ -486,6 +552,29 @@ iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, return state.task; } +struct scsi_task * +iscsi_read16_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba, + uint32_t datalen, int blocksize, + int rdprotect, int dpo, int fua, int fua_nv, int group_number, + struct scsi_iovec *iov, int niov) +{ + struct iscsi_sync_state state; + + memset(&state, 0, sizeof(state)); + + if (iscsi_read16_iov_task(iscsi, lun, lba, datalen, blocksize, rdprotect, + dpo, fua, fua_nv, group_number, + scsi_sync_cb, &state, iov, niov) == NULL) { + iscsi_set_error(iscsi, + "Failed to send Read16 command"); + return NULL; + } + + event_loop(iscsi, &state); + + return state.task; +} + struct scsi_task * iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba, int pmi)