Merge pull request #55 from plieven/tcp_nodelay

SOCKET set TCP_NODELAY on iscsi->fd
This commit is contained in:
Ronnie Sahlberg
2012-12-10 18:40:44 -08:00
4 changed files with 130 additions and 85 deletions

View File

@@ -290,9 +290,8 @@ int iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt);
void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string,
...) __attribute__((format(printf, 2, 3))); ...) __attribute__((format(printf, 2, 3)));
unsigned char *iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, uint32_t pos, ssize_t *count); struct scsi_iovector *iscsi_get_scsi_task_iovector_in(struct iscsi_context *iscsi, struct iscsi_in_pdu *in);
unsigned char *iscsi_get_user_out_buffer(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, uint32_t pos, ssize_t *count); struct scsi_iovector *iscsi_get_scsi_task_iovector_out(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size); inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size);
inline void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size); inline void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size);

View File

@@ -436,7 +436,7 @@ iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
dsl = scsi_get_uint32(&in->hdr[4]) & 0x00ffffff; dsl = scsi_get_uint32(&in->hdr[4]) & 0x00ffffff;
/* Dont add to reassembly buffer if we already have a user buffer */ /* Dont add to reassembly buffer if we already have a user buffer */
if (scsi_task_get_data_in_buffer(task, 0, NULL) == NULL) { if (task->iovector_in.iov == NULL) {
if (iscsi_add_data(iscsi, &pdu->indata, in->data, dsl, 0) != 0) { if (iscsi_add_data(iscsi, &pdu->indata, in->data, dsl, 0) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: failed to add data " iscsi_set_error(iscsi, "Out-of-memory: failed to add data "
"to pdu in buffer."); "to pdu in buffer.");
@@ -1422,30 +1422,42 @@ iscsi_unmap_task(struct iscsi_context *iscsi, int lun, int anchor, int group,
return task; return task;
} }
unsigned char * struct scsi_iovector *
iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, uint32_t pos, ssize_t *count) iscsi_get_scsi_task_iovector_in(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
{ {
struct iscsi_pdu *pdu; struct iscsi_pdu *pdu;
uint32_t offset;
uint32_t itt; uint32_t itt;
if ((in->hdr[0] & 0x3f) != ISCSI_PDU_DATA_IN) { if ((in->hdr[0] & 0x3f) != ISCSI_PDU_DATA_IN) {
return NULL; return NULL;
} }
offset = scsi_get_uint32(&in->hdr[40]);
itt = scsi_get_uint32(&in->hdr[16]); itt = scsi_get_uint32(&in->hdr[16]);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == itt) { if (pdu->itt == itt) {
break; break;
} }
} }
if (pdu == NULL) { if (pdu == NULL) {
return NULL; return NULL;
} }
return scsi_task_get_data_in_buffer(pdu->scsi_cbdata.task, offset + pos, count); if (pdu->scsi_cbdata.task->iovector_in.iov == NULL) {
return NULL;
}
return &pdu->scsi_cbdata.task->iovector_in;
}
struct scsi_iovector *
iscsi_get_scsi_task_iovector_out(struct iscsi_context *iscsi _U_, struct iscsi_pdu *pdu)
{
if (pdu->scsi_cbdata.task->iovector_out.iov == NULL) {
return NULL;
}
return &pdu->scsi_cbdata.task->iovector_out;
} }
struct scsi_task * struct scsi_task *
@@ -1593,10 +1605,3 @@ iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi)
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
} }
} }
unsigned char *
iscsi_get_user_out_buffer(struct iscsi_context *iscsi _U_, struct iscsi_pdu *pdu, uint32_t pos, ssize_t *count)
{
return scsi_task_get_data_out_buffer(pdu->scsi_cbdata.task, pos, count);
}

View File

@@ -34,6 +34,7 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h>
#include "slist.h" #include "slist.h"
#include "scsi-lowlevel.h" #include "scsi-lowlevel.h"
@@ -2593,69 +2594,14 @@ scsi_iovector_add(struct scsi_task *task, struct scsi_iovector *iovector, int le
return 0; return 0;
} }
unsigned char *
scsi_iovector_get_buffer(struct scsi_iovector *iovector, uint32_t pos, ssize_t *count)
{
if (iovector->iov == NULL) {
return NULL;
}
if (pos == 0 && count == NULL) return iovector->iov[0].iov_base;
if (pos < iovector->offset) {
/* start over in case we are going backwards */
iovector->offset = 0;
iovector->consumed = 0;
}
if (iovector->niov <= iovector->consumed) {
/* someone issued a read but did not provide enough user buffers for all the data.
* maybe someone tried to read just 512 bytes off a MMC device?
*/
return NULL;
}
struct scsi_iovec *iov = &iovector->iov[iovector->consumed];
pos-= iovector->offset;
while (pos >= iov->iov_len) {
iovector->offset += iov->iov_len;
iovector->consumed++;
pos -= iov->iov_len;
if (iovector->niov <= iovector->consumed) {
return NULL;
}
iov = &iovector->iov[iovector->consumed];
}
if (count && *count >= (ssize_t)(iov->iov_len - pos)) {
*count = iov->iov_len - pos;
}
return (unsigned char *) iov->iov_base + pos;
}
int int
scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf) scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf)
{ {
return scsi_iovector_add(task, &task->iovector_in, len, buf); return scsi_iovector_add(task, &task->iovector_in, len, buf);
} }
unsigned char *
scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count)
{
return scsi_iovector_get_buffer(&task->iovector_in, pos, count);
}
int int
scsi_task_add_data_out_buffer(struct scsi_task *task, int len, unsigned char *buf) scsi_task_add_data_out_buffer(struct scsi_task *task, int len, unsigned char *buf)
{ {
return scsi_iovector_add(task, &task->iovector_out, len, buf); return scsi_iovector_add(task, &task->iovector_out, len, buf);
} }
unsigned char *
scsi_task_get_data_out_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count)
{
return scsi_iovector_get_buffer(&task->iovector_out, pos, count);
}

View File

@@ -42,6 +42,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include "scsi-lowlevel.h"
#include "iscsi.h" #include "iscsi.h"
#include "iscsi-private.h" #include "iscsi-private.h"
#include "slist.h" #include "slist.h"
@@ -283,6 +284,12 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
} }
#endif #endif
if (set_tcp_sockopt(iscsi->fd, TCP_NODELAY, 1) != 0) {
ISCSI_LOG(iscsi,1,"failed to set TCP_NODELAY sockopt: %s",strerror(errno));
} else {
ISCSI_LOG(iscsi,3,"TCP_NODELAY set to 1");
}
if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 if (connect(iscsi->fd, ai->ai_addr, socksize) != 0
&& errno != EINPROGRESS) { && errno != EINPROGRESS) {
iscsi_set_error(iscsi, "Connect failed with errno : " iscsi_set_error(iscsi, "Connect failed with errno : "
@@ -357,6 +364,91 @@ iscsi_queue_length(struct iscsi_context *iscsi)
return i; return i;
} }
ssize_t
iscsi_iovector_readv_writev(struct iscsi_context *iscsi, struct scsi_iovector *iovector, uint32_t pos, ssize_t max_read, int do_write)
{
if (iovector->iov == NULL) {
errno = EINVAL;
return -1;
}
if (pos < iovector->offset) {
/* start over in case we are going backwards */
iovector->offset = 0;
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;
}
/* iov is a pointer to the first iovec to pass */
struct scsi_iovec *iov = &iovector->iov[iovector->consumed];
pos -= iovector->offset;
/* forward until iov points to the first iov to pass */
while (pos >= iov->iov_len) {
iovector->offset += iov->iov_len;
iovector->consumed++;
pos -= iov->iov_len;
if (iovector->niov <= iovector->consumed) {
errno = EINVAL;
return -1;
}
iov = &iovector->iov[iovector->consumed];
}
/* iov2 is a pointer to the last iovec to pass */
struct scsi_iovec *iov2 = iov;
int niov=1; /* number of iovectors to pass */
uint32_t len2 = pos + max_read; /* adjust length of iov2 */
/* forward until iov2 points to the last iovec we pass later. it might
happen that we have a lot of iovectors but are limited by max_read */
while (len2 > iov2->iov_len) {
if (iovector->niov <= iovector->consumed+niov-1) {
errno = EINVAL;
return -1;
}
niov++;
len2 -= iov2->iov_len;
iov2 = &iovector->iov[iovector->consumed+niov-1];
}
/* 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;
/* adjust base+len of start iovec and len of last iovec */
iov2->iov_len = len2;
iov->iov_base = (void*) ((uintptr_t)iov->iov_base + pos);
iov->iov_len -= pos;
ssize_t n;
if (do_write) {
n = writev(iscsi->fd, (struct iovec*) iov, niov);
} else {
n = readv(iscsi->fd, (struct iovec*) iov, niov);
}
/* 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
iscsi_read_from_socket(struct iscsi_context *iscsi) iscsi_read_from_socket(struct iscsi_context *iscsi)
{ {
@@ -405,13 +497,16 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
} }
if (data_size != 0) { if (data_size != 0) {
unsigned char *buf = NULL; unsigned char *buf = NULL;
struct scsi_iovector * iovector_in;
count = data_size - in->data_pos; count = data_size - in->data_pos;
/* first try to see if we already have a user buffer */ /* first try to see if we already have a user buffer */
buf = iscsi_get_user_in_buffer(iscsi, in, in->data_pos, &count); iovector_in = iscsi_get_scsi_task_iovector_in(iscsi, in);
/* if not, allocate one */ if (iovector_in != NULL) {
if (buf == NULL) { uint32_t offset = scsi_get_uint32(&in->hdr[40]);
count = iscsi_iovector_readv_writev(iscsi, iovector_in, in->data_pos + offset, count, 0);
} else {
if (in->data == NULL) { if (in->data == NULL) {
in->data = iscsi_malloc(iscsi, data_size); in->data = iscsi_malloc(iscsi, data_size);
if (in->data == NULL) { if (in->data == NULL) {
@@ -420,9 +515,9 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
} }
} }
buf = &in->data[in->data_pos]; buf = &in->data[in->data_pos];
count = recv(iscsi->fd, buf, count, 0);
} }
count = recv(iscsi->fd, buf, count, 0);
if (count == 0) { if (count == 0) {
return -1; return -1;
} }
@@ -434,6 +529,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
"errno:%d", errno); "errno:%d", errno);
return -1; return -1;
} }
in->data_pos += count; in->data_pos += count;
} }
@@ -518,19 +614,17 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
/* Write any iovectors that might have been passed to us */ /* Write any iovectors that might have been passed to us */
while (pdu->out_written < pdu->out_len) { while (pdu->out_written < pdu->out_len) {
unsigned char *buf; struct scsi_iovector* iovector_out;
count = pdu->out_len - pdu->out_written; iovector_out = iscsi_get_scsi_task_iovector_out(iscsi, pdu);
buf = iscsi_get_user_out_buffer(iscsi, pdu, pdu->out_offset + pdu->out_written, &count);
if (buf == NULL) { if (iovector_out == NULL) {
iscsi_set_error(iscsi, "Can't find iovector data for DATA-OUT"); iscsi_set_error(iscsi, "Can't find iovector data for DATA-OUT");
return -1; return -1;
} }
count = send(iscsi->fd, count = iscsi_iovector_readv_writev(iscsi, iovector_out, pdu->out_offset + pdu->out_written, pdu->out_len - pdu->out_written, 1);
buf,
count,
0);
if (count == -1) { if (count == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) { if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0; return 0;
@@ -539,6 +633,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
"socket :%d", errno); "socket :%d", errno);
return -1; return -1;
} }
pdu->out_written += count; pdu->out_written += count;
} }