diff --git a/0018-fix-iovec-short-reads.patch b/0018-fix-iovec-short-reads.patch new file mode 100644 index 0000000..c03b148 --- /dev/null +++ b/0018-fix-iovec-short-reads.patch @@ -0,0 +1,119 @@ +From: Paolo Bonzini +Subject: [PATCH] Ignore padding when an iovector is supplied + +The iSCSI protocol adds padding to a data packet if the data size is not +a multiple of four. The iovector provided by QEMU does not include such +padding, and libiscsi then complains that there was a protocol error. +This patch fixes this by reading the padding in a separate "recv" +system call. These packets anyway do not happen in the data path, +where the packet size is a multiple of 512. + +This fixes QEMU's scsi-generic backend, which triggered the problem when +the target sent a 66-byte INQUIRY response. + +Signed-off-by: Paolo Bonzini + +diff --git a/include/iscsi-private.h b/include/iscsi-private.h +index 9345b09..a787127 100644 +--- a/include/iscsi-private.h ++++ b/include/iscsi-private.h +@@ -258,6 +258,7 @@ struct scsi_task; + void iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task); + + int iscsi_get_pdu_data_size(const unsigned char *hdr); ++int iscsi_get_pdu_padding_size(const unsigned char *hdr); + int iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in); + + int iscsi_process_login_reply(struct iscsi_context *iscsi, +diff --git a/lib/pdu.c b/lib/pdu.c +index b5e57fe..61abdd6 100644 +--- a/lib/pdu.c ++++ b/lib/pdu.c +@@ -207,11 +207,22 @@ iscsi_get_pdu_data_size(const unsigned char *hdr) + int size; + + size = scsi_get_uint32(&hdr[4]) & 0x00ffffff; +- size = (size+3) & 0xfffffffc; + + return size; + } + ++ ++int ++iscsi_get_pdu_padding_size(const unsigned char *hdr) ++{ ++ int data_size, padded_size; ++ ++ data_size = scsi_get_uint32(&hdr[4]) & 0x00ffffff; ++ padded_size = (data_size+3) & 0xfffffffc; ++ ++ return padded_size - data_size; ++} ++ + enum iscsi_reject_reason { + ISCSI_REJECT_RESERVED = 0x01, + ISCSI_REJECT_DATA_DIGEST_ERROR = 0x02, +diff --git a/lib/socket.c b/lib/socket.c +index edf2ec5..9055452 100644 +--- a/lib/socket.c ++++ b/lib/socket.c +@@ -461,7 +461,7 @@ static int + iscsi_read_from_socket(struct iscsi_context *iscsi) + { + struct iscsi_in_pdu *in; +- ssize_t data_size, count; ++ ssize_t data_size, count, padding_size; + + if (iscsi->incoming == NULL) { + iscsi->incoming = iscsi_zmalloc(iscsi, sizeof(struct iscsi_in_pdu)); +@@ -499,6 +499,8 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) + } + + data_size = iscsi_get_pdu_data_size(&in->hdr[0]); ++ padding_size = iscsi_get_pdu_padding_size(&in->hdr[0]); ++ + if (data_size < 0 || data_size > (ssize_t)iscsi->initiator_max_recv_data_segment_length) { + iscsi_set_error(iscsi, "Invalid data size received from target (%d)", (int)data_size); + return -1; +@@ -514,16 +516,29 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) + 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); ++ ++ /* This does not happen on the data path, so it does not need ++ * to be especially efficient. ++ */ ++ if (padding_size) { ++ char padding_buf[3]; ++ int count2; ++ count2 = recv(iscsi->fd, padding_buf, padding_size, 0); ++ if (count2 < 0) ++ count = count2; ++ else ++ count += count2; ++ } + } else { + if (in->data == NULL) { +- in->data = iscsi_malloc(iscsi, data_size); ++ in->data = iscsi_malloc(iscsi, data_size + padding_size); + if (in->data == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu->data(%d)", (int)data_size); + return -1; + } + } + buf = &in->data[in->data_pos]; +- count = recv(iscsi->fd, buf, count, 0); ++ count = recv(iscsi->fd, buf, count + padding_size, 0); + } + + if (count == 0) { +@@ -541,7 +555,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) + in->data_pos += count; + } + +- if (in->data_pos < data_size) { ++ if (in->data_pos < data_size + padding_size) { + return 0; + } + + diff --git a/libiscsi.spec b/libiscsi.spec index 1cbe98f..6ce5d6e 100644 --- a/libiscsi.spec +++ b/libiscsi.spec @@ -1,7 +1,7 @@ Name: libiscsi Summary: iSCSI client library Version: 1.9.0 -Release: 1%{?dist} +Release: 2%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: https://github.com/sahlberg/%{name} @@ -25,6 +25,7 @@ Patch14: 0014-fix-another-aliasing-problem.patch Patch15: 0015-fix-arm-aliasing-problem.patch Patch16: 0016-avoid-casting-struct-sockaddr.patch Patch17: 0017-use-scsi_get-set_uint16-32-64-in-tests.patch +Patch18: 0018-fix-iovec-short-reads.patch BuildRequires: autoconf BuildRequires: automake @@ -65,6 +66,7 @@ a network. %patch15 -p1 %patch16 -p1 %patch17 -p1 +%patch18 -p1 %build sh autogen.sh @@ -125,6 +127,9 @@ The libiscsi-devel package includes the header files for libiscsi. %{_libdir}/pkgconfig/libiscsi.pc %changelog +* Mon Aug 26 2013 Paolo Bonzini - 1.9.0-2 +- Add patch 18 to fix QEMU's scsi-generic mode + * Fri Aug 2 2013 Paolo Bonzini - 1.9.0-1 - Rebase to 1.9.0 - Cherry-pick selected patches from upstream