Add patch 18 to fix QEMU's scsi-generic mode
This commit is contained in:
parent
5228e3e672
commit
617a50a9c9
119
0018-fix-iovec-short-reads.patch
Normal file
119
0018-fix-iovec-short-reads.patch
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user