Merge pull request #55 from plieven/tcp_nodelay
SOCKET set TCP_NODELAY on iscsi->fd
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
121
lib/socket.c
121
lib/socket.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user