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,
...) __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);
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_in(struct iscsi_context *iscsi, struct iscsi_in_pdu *in);
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_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;
/* 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) {
iscsi_set_error(iscsi, "Out-of-memory: failed to add data "
"to pdu in buffer.");
@@ -1422,30 +1422,42 @@ iscsi_unmap_task(struct iscsi_context *iscsi, int lun, int anchor, int group,
return task;
}
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)
{
struct iscsi_pdu *pdu;
uint32_t offset;
uint32_t itt;
if ((in->hdr[0] & 0x3f) != ISCSI_PDU_DATA_IN) {
return NULL;
}
offset = scsi_get_uint32(&in->hdr[40]);
itt = scsi_get_uint32(&in->hdr[16]);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == itt) {
break;
}
}
if (pdu == 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 *
@@ -1593,10 +1605,3 @@ iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi)
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 <string.h>
#include <stdint.h>
#include <errno.h>
#include "slist.h"
#include "scsi-lowlevel.h"
@@ -2593,69 +2594,14 @@ scsi_iovector_add(struct scsi_task *task, struct scsi_iovector *iovector, int le
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
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);
}
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
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);
}
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 <errno.h>
#include <fcntl.h>
#include "scsi-lowlevel.h"
#include "iscsi.h"
#include "iscsi-private.h"
#include "slist.h"
@@ -283,6 +284,12 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
}
#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
&& errno != EINPROGRESS) {
iscsi_set_error(iscsi, "Connect failed with errno : "
@@ -357,6 +364,91 @@ iscsi_queue_length(struct iscsi_context *iscsi)
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
iscsi_read_from_socket(struct iscsi_context *iscsi)
{
@@ -405,13 +497,16 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
}
if (data_size != 0) {
unsigned char *buf = NULL;
struct scsi_iovector * iovector_in;
count = data_size - in->data_pos;
/* first try to see if we already have a user buffer */
buf = iscsi_get_user_in_buffer(iscsi, in, in->data_pos, &count);
/* if not, allocate one */
if (buf == NULL) {
iovector_in = iscsi_get_scsi_task_iovector_in(iscsi, in);
if (iovector_in != 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) {
in->data = iscsi_malloc(iscsi, data_size);
if (in->data == NULL) {
@@ -420,9 +515,9 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
}
}
buf = &in->data[in->data_pos];
count = recv(iscsi->fd, buf, count, 0);
}
count = recv(iscsi->fd, buf, count, 0);
if (count == 0) {
return -1;
}
@@ -434,6 +529,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
"errno:%d", errno);
return -1;
}
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 */
while (pdu->out_written < pdu->out_len) {
unsigned char *buf;
struct scsi_iovector* iovector_out;
count = pdu->out_len - pdu->out_written;
buf = iscsi_get_user_out_buffer(iscsi, pdu, pdu->out_offset + pdu->out_written, &count);
if (buf == NULL) {
iovector_out = iscsi_get_scsi_task_iovector_out(iscsi, pdu);
if (iovector_out == NULL) {
iscsi_set_error(iscsi, "Can't find iovector data for DATA-OUT");
return -1;
}
count = send(iscsi->fd,
buf,
count,
0);
count = iscsi_iovector_readv_writev(iscsi, iovector_out, pdu->out_offset + pdu->out_written, pdu->out_len - pdu->out_written, 1);
if (count == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0;
@@ -539,6 +633,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
"socket :%d", errno);
return -1;
}
pdu->out_written += count;
}