Change iscsi_scsi_command_async() to use iovectors for writes.
Change iscsi_scsi_command_async() to write data-out using iovectors attached to the scsi task structure instead of copying the data into the buffer holding the header. Still allow passing the data via an argument to the funtcion so that the ABI does not change but then just conver the data to an iovector. Update the write_to_socket functions to know about the iovectors and write them as part of the pdu. Convert write10_task to use iovectors. This will allow 'zero-copy' writes through libiscsi. However, as 'zero-copy writes does mean that we do more send() calls into the kernel this may degrade performance for very small i/o. A scsi write will not take at least 2 send() calls. One send call for the iscsi header structure and a second send call for the payload data. This will be more expensive than the old memcpy() of payload data plus one send() call since the send() will be a lot more expensive than memcpy() of a small amount of data.
This commit is contained in:
66
lib/socket.c
66
lib/socket.c
@@ -427,41 +427,73 @@ static int
|
||||
iscsi_write_to_socket(struct iscsi_context *iscsi)
|
||||
{
|
||||
ssize_t count;
|
||||
struct iscsi_pdu *pdu;
|
||||
|
||||
if (iscsi->fd == -1) {
|
||||
iscsi_set_error(iscsi, "trying to write but not connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (iscsi->outqueue) {
|
||||
while ((pdu = iscsi->outqueue) != NULL) {
|
||||
ssize_t total;
|
||||
|
||||
if (iscsi->outqueue->cmdsn > iscsi->maxcmdsn) {
|
||||
if (pdu->cmdsn > iscsi->maxcmdsn) {
|
||||
/* stop sending. maxcmdsn is reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
total = iscsi->outqueue->outdata.size;
|
||||
total = pdu->outdata.size;
|
||||
total = (total + 3) & 0xfffffffc;
|
||||
|
||||
count = send(iscsi->fd,
|
||||
iscsi->outqueue->outdata.data
|
||||
+ iscsi->outqueue->written,
|
||||
total - iscsi->outqueue->written,
|
||||
0);
|
||||
if (count == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return 0;
|
||||
/* Write header and any immediate data */
|
||||
if (pdu->written < total) {
|
||||
count = send(iscsi->fd,
|
||||
pdu->outdata.data + pdu->written,
|
||||
total - pdu->written,
|
||||
0);
|
||||
if (count == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return 0;
|
||||
}
|
||||
iscsi_set_error(iscsi, "Error when writing to "
|
||||
"socket :%d", errno);
|
||||
return -1;
|
||||
}
|
||||
iscsi_set_error(iscsi, "Error when writing to "
|
||||
"socket :%d", errno);
|
||||
return -1;
|
||||
pdu->written += count;
|
||||
}
|
||||
/* if we havent written the full header yet. */
|
||||
if (pdu->written != total) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
iscsi->outqueue->written += count;
|
||||
if (iscsi->outqueue->written == total) {
|
||||
struct iscsi_pdu *pdu = iscsi->outqueue;
|
||||
/* Write any iovectors that might have been passed to us */
|
||||
while (pdu->out_len > 0) {
|
||||
unsigned char *buf;
|
||||
|
||||
count = pdu->out_len;
|
||||
buf = iscsi_get_user_out_buffer(iscsi, pdu, pdu->out_offset, &count);
|
||||
if (buf == NULL) {
|
||||
iscsi_set_error(iscsi, "Can't find iovector data for DATA-OUT");
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = send(iscsi->fd,
|
||||
buf,
|
||||
count,
|
||||
0);
|
||||
if (count == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return 0;
|
||||
}
|
||||
iscsi_set_error(iscsi, "Error when writing to "
|
||||
"socket :%d", errno);
|
||||
return -1;
|
||||
}
|
||||
pdu->out_offset += count;
|
||||
pdu->out_len -= count;
|
||||
}
|
||||
|
||||
if (pdu->written == total) {
|
||||
SLIST_REMOVE(&iscsi->outqueue, pdu);
|
||||
if (pdu->flags & ISCSI_PDU_DELETE_WHEN_SENT) {
|
||||
iscsi_free_pdu(iscsi, pdu);
|
||||
|
||||
Reference in New Issue
Block a user