Add patch 18 to fix QEMU's scsi-generic mode

This commit is contained in:
Paolo Bonzini 2013-08-26 17:58:00 +02:00
parent 5228e3e672
commit 617a50a9c9
2 changed files with 125 additions and 1 deletions

View File

@ -0,0 +1,119 @@
From: Paolo Bonzini <pbonzini@redhat.com>
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 <pbonzini@redhat.com>
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;
}

View File

@ -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 <pbonzini@redhat.com> - 1.9.0-2
- Add patch 18 to fix QEMU's scsi-generic mode
* Fri Aug 2 2013 Paolo Bonzini <pbonzini@redhat.com> - 1.9.0-1
- Rebase to 1.9.0
- Cherry-pick selected patches from upstream