Revert "Rewrite and simplify iscsi_iovector_readv_writev"
Since writing headers and payload in a single iov has never been
implementend and after thinking about it several times seems to
be very hairy I would like to revert this change since
the original implementation is in O(1) while the changed one
is in O(n). This results in a complexity of O(n^2) instead of
O(n) for the whole send operation.
This reverts commit 06eab264f6.
This commit is contained in:
@@ -270,9 +270,8 @@ struct scsi_iovector {
|
|||||||
struct scsi_iovec *iov;
|
struct scsi_iovec *iov;
|
||||||
int niov;
|
int niov;
|
||||||
int nalloc;
|
int nalloc;
|
||||||
|
size_t offset;
|
||||||
size_t reserved_1;
|
int consumed;
|
||||||
int reserved_2;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scsi_task {
|
struct scsi_task {
|
||||||
|
|||||||
105
lib/socket.c
105
lib/socket.c
@@ -408,82 +408,89 @@ iscsi_queue_length(struct iscsi_context *iscsi)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
ssize_t
|
||||||
iscsi_iovector_readv_writev(struct iscsi_context *iscsi, struct scsi_iovector *iovector, uint32_t pos, size_t count, int do_write)
|
iscsi_iovector_readv_writev(struct iscsi_context *iscsi, struct scsi_iovector *iovector, uint32_t pos, ssize_t max_read, int do_write)
|
||||||
{
|
{
|
||||||
struct iovec *iovs;
|
|
||||||
struct iovec *first_iov;
|
|
||||||
struct iovec *last_iov;
|
|
||||||
int i, niov;
|
|
||||||
size_t skip_first, skip_last;
|
|
||||||
|
|
||||||
if (iovector->iov == NULL) {
|
if (iovector->iov == NULL) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
niov = iovector->niov;
|
if (pos < iovector->offset) {
|
||||||
iovs = alloca(sizeof(struct iovec) * niov);
|
/* start over in case we are going backwards */
|
||||||
if (iovs == NULL) {
|
iovector->offset = 0;
|
||||||
errno = ENOMEM;
|
iovector->consumed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iovector->niov <= iovector->consumed) {
|
||||||
|
/* someone issued a read/write but did not provide enough user buffers for all the data.
|
||||||
|
* maybe someone tried to read just 512 bytes off a MMC device?
|
||||||
|
*/
|
||||||
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for(i = 0; i < niov; i++) {
|
|
||||||
iovs[i].iov_base = iovector->iov[i].iov_base;
|
|
||||||
iovs[i].iov_len = iovector->iov[i].iov_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
first_iov = &iovs[0];
|
/* iov is a pointer to the first iovec to pass */
|
||||||
|
struct scsi_iovec *iov = &iovector->iov[iovector->consumed];
|
||||||
|
pos -= iovector->offset;
|
||||||
|
|
||||||
/* Step past iovectors until we find the first iov to send */
|
/* forward until iov points to the first iov to pass */
|
||||||
while (pos >= first_iov->iov_len) {
|
while (pos >= iov->iov_len) {
|
||||||
pos -= first_iov->iov_len;
|
iovector->offset += iov->iov_len;
|
||||||
first_iov++;
|
iovector->consumed++;
|
||||||
niov--;
|
pos -= iov->iov_len;
|
||||||
if (niov <= 0) {
|
if (iovector->niov <= iovector->consumed) {
|
||||||
/* We ran out of iovectors. */
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
iov = &iovector->iov[iovector->consumed];
|
||||||
/* How many bytes in the first iov to skip */
|
|
||||||
skip_first = pos;
|
|
||||||
if (skip_first > 0) {
|
|
||||||
char *buf = first_iov->iov_base;
|
|
||||||
first_iov->iov_base = &buf[skip_first];
|
|
||||||
first_iov->iov_len -= skip_first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* iov2 is a pointer to the last iovec to pass */
|
||||||
|
struct scsi_iovec *iov2 = iov;
|
||||||
|
|
||||||
/* Find the last iovector to send */
|
int niov=1; /* number of iovectors to pass */
|
||||||
last_iov = first_iov;
|
uint32_t len2 = pos + max_read; /* adjust length of iov2 */
|
||||||
while (count >last_iov->iov_len) {
|
|
||||||
count -= last_iov->iov_len;
|
/* forward until iov2 points to the last iovec we pass later. it might
|
||||||
last_iov++;
|
happen that we have a lot of iovectors but are limited by max_read */
|
||||||
niov--;
|
while (len2 > iov2->iov_len) {
|
||||||
if (niov <= 0) {
|
if (iovector->niov <= iovector->consumed+niov-1) {
|
||||||
/* We ran out of iovectors. */
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
niov++;
|
||||||
/* How many bytes in the last iov to skip */
|
len2 -= iov2->iov_len;
|
||||||
skip_last = last_iov->iov_len - count;
|
iov2 = &iovector->iov[iovector->consumed+niov-1];
|
||||||
if (skip_last > 0) {
|
|
||||||
last_iov->iov_len -= skip_last;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we might limit the length of the last iovec we pass to readv/writev
|
||||||
|
store its orignal length to restore it later */
|
||||||
|
size_t _len2 = iov2->iov_len;
|
||||||
|
|
||||||
/* number of iovectors we will be using */
|
/* adjust base+len of start iovec and len of last iovec */
|
||||||
niov = last_iov - first_iov + 1;
|
iov2->iov_len = len2;
|
||||||
|
iov->iov_base = (void*) ((uintptr_t)iov->iov_base + pos);
|
||||||
|
iov->iov_len -= pos;
|
||||||
|
|
||||||
|
ssize_t n;
|
||||||
if (do_write) {
|
if (do_write) {
|
||||||
count = writev(iscsi->fd, first_iov, niov);
|
n = writev(iscsi->fd, (struct iovec*) iov, niov);
|
||||||
} else {
|
} else {
|
||||||
count = readv(iscsi->fd, first_iov, niov);
|
n = readv(iscsi->fd, (struct iovec*) iov, niov);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
/* restore original values */
|
||||||
|
iov->iov_base = (void*) ((uintptr_t)iov->iov_base - pos);
|
||||||
|
iov->iov_len += pos;
|
||||||
|
iov2->iov_len = _len2;
|
||||||
|
|
||||||
|
if (n > max_read) {
|
||||||
|
/* we read/write more bytes than expected, this MUST not happen */
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|||||||
Reference in New Issue
Block a user