SCSI add support for iovectors

If an application passes buffers to libiscsi for reading they are
currently added to a linked list one by one. This leads to a malloc
for each buffer object plus O(n) walks trough the list to add
the buffer to then end of the list. Additionally the buffer read
routine takes up to O(n) iterations to find the right buffer
for a request.

This patch introduces an scsi_iovector struct to pass buffers to
an scsi task. Adding a new buffer is in O(1) and finding the
right buffer to also. Malloc requirements are in O(log(n)).

Additionally the scsi_iovector struct is itended to be binary
compatible to an QEMUIOVector allowing to pass this structure
directly to the library.

Initial tests have been made booting an Ubuntu LTS 12.04.1
Desktop server up to the login prompt. The following observations
have been made with regards to scsi_malloc calls:

original implementation:	~11.500 mallocs
using iovector instead of list:	~ 7.500 mallocs
passing the iovector directly:        0 mallocs

To enable this feature in qemu for testing the following patch might
be used:

diff --git a/block/iscsi.c b/block/iscsi.c
index a6a819d..2809c15 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -390,11 +390,16 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
         return NULL;
     }

+#if defined(LIBISCSI_FEATURE_IOVECTOR)
+    assert(sizeof(struct QEMUIOVector) == sizeof(struct scsi_iovector));
+    scsi_iovector_assign(acb->task, (struct scsi_iovector*) acb->qiov);
+#else
     for (i = 0; i < acb->qiov->niov; i++) {
         scsi_task_add_data_in_buffer(acb->task,
                 acb->qiov->iov[i].iov_len,
                 acb->qiov->iov[i].iov_base);
     }
+#endif

     iscsi_set_events(iscsilun);

---
Signed-off-by: Peter Lieven <pl@kamp.de>
This commit is contained in:
Peter Lieven
2012-11-21 17:02:59 +01:00
parent 4a973e9a4e
commit 55f76cfb0c
6 changed files with 112 additions and 44 deletions

View File

@@ -33,6 +33,9 @@ extern "C" {
struct iscsi_context;
struct sockaddr;
/* FEATURES */
#define LIBISCSI_FEATURE_IOVECTOR (1)
#define MAX_STRING_SIZE (255)
/*

View File

@@ -197,6 +197,20 @@ enum scsi_residual {
SCSI_RESIDUAL_OVERFLOW
};
#if !defined(_SYS_UIO_H) && !defined(CONFIG_IOVEC)
struct iovec {
void *iov_base;
size_t iov_len;
};
#endif
struct scsi_iovector {
struct iovec *iov;
int niov;
int nalloc;
size_t size;
};
struct scsi_task {
int status;
@@ -217,7 +231,9 @@ struct scsi_task {
uint32_t cmdsn;
uint32_t lun;
struct scsi_data_buffer *in_buffers;
size_t buffers_offset;
int buffers_consumed;
struct scsi_iovector *buffers;
};
/* This function will free a scsi task structure.
@@ -707,6 +723,8 @@ EXTERN struct scsi_task *scsi_cdb_report_supported_opcodes(int report_timeouts,
void *scsi_malloc(struct scsi_task *task, size_t size);
EXTERN void scsi_iovector_assign(struct scsi_task *task, struct scsi_iovector *iov);
#ifdef __cplusplus
}
#endif