summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2017-02-28 06:29:44 +0000
committermav <mav@FreeBSD.org>2017-02-28 06:29:44 +0000
commit255043831e484097b0a3b1305cf4154ee720d833 (patch)
treea6bbea99df9bf8610722f9e2ed3e174f3b5a6e96
parentc88f71b70b0172e2697579dea6b19bc127acc0bd (diff)
downloadFreeBSD-src-255043831e484097b0a3b1305cf4154ee720d833.zip
FreeBSD-src-255043831e484097b0a3b1305cf4154ee720d833.tar.gz
MFC r313731: Do not rely on data alignment after m_pullup().
In general case m_pullup() does not really guarantee any data alignment. Instead of depenting on side effects caused by data being always copied out of mbuf cluster (which is probably a bug by itself), always allocate aligned BHS buffer and read data there directly from socket. While there, reuse new icl_conn_receive_buf() function to read digests. The code could probably be even more optimized to aggregate those reads, but until that done, this is still easier then the way it was before.
-rw-r--r--sys/dev/iscsi/icl_soft.c79
1 files changed, 44 insertions, 35 deletions
diff --git a/sys/dev/iscsi/icl_soft.c b/sys/dev/iscsi/icl_soft.c
index bcb4387..cde2b47 100644
--- a/sys/dev/iscsi/icl_soft.c
+++ b/sys/dev/iscsi/icl_soft.c
@@ -169,6 +169,40 @@ icl_conn_receive(struct icl_conn *ic, size_t len)
return (m);
}
+static int
+icl_conn_receive_buf(struct icl_conn *ic, void *buf, size_t len)
+{
+ struct iovec iov[1];
+ struct uio uio;
+ struct socket *so;
+ int error, flags;
+
+ so = ic->ic_socket;
+
+ memset(&uio, 0, sizeof(uio));
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+ uio.uio_iov = iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = len;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+
+ flags = MSG_DONTWAIT;
+ error = soreceive(so, NULL, &uio, NULL, NULL, &flags);
+ if (error != 0) {
+ ICL_DEBUG("soreceive error %d", error);
+ return (-1);
+ }
+ if (uio.uio_resid != 0) {
+ ICL_DEBUG("short read");
+ return (-1);
+ }
+
+ return (0);
+}
+
static struct icl_pdu *
icl_pdu_new_empty(struct icl_conn *ic, int flags)
{
@@ -229,7 +263,7 @@ icl_soft_conn_new_pdu(struct icl_conn *ic, int flags)
ip->ip_bhs_mbuf = m_getm2(NULL, sizeof(struct iscsi_bhs),
flags, MT_DATA, M_PKTHDR);
if (ip->ip_bhs_mbuf == NULL) {
- ICL_WARN("failed to allocate %zd bytes", sizeof(*ip));
+ ICL_WARN("failed to allocate BHS mbuf");
icl_pdu_free(ip);
return (NULL);
}
@@ -308,28 +342,13 @@ icl_pdu_size(const struct icl_pdu *response)
static int
icl_pdu_receive_bhs(struct icl_pdu *request, size_t *availablep)
{
- struct mbuf *m;
- m = icl_conn_receive(request->ip_conn, sizeof(struct iscsi_bhs));
- if (m == NULL) {
+ if (icl_conn_receive_buf(request->ip_conn,
+ request->ip_bhs, sizeof(struct iscsi_bhs))) {
ICL_DEBUG("failed to receive BHS");
return (-1);
}
- request->ip_bhs_mbuf = m_pullup(m, sizeof(struct iscsi_bhs));
- if (request->ip_bhs_mbuf == NULL) {
- ICL_WARN("m_pullup failed");
- return (-1);
- }
- request->ip_bhs = mtod(request->ip_bhs_mbuf, struct iscsi_bhs *);
-
- /*
- * XXX: For architectures with strict alignment requirements
- * we may need to allocate ip_bhs and copy the data into it.
- * For some reason, though, not doing this doesn't seem
- * to cause problems; tested on sparc64.
- */
-
*availablep -= sizeof(struct iscsi_bhs);
return (0);
}
@@ -371,22 +390,17 @@ icl_mbuf_to_crc32c(const struct mbuf *m0)
static int
icl_pdu_check_header_digest(struct icl_pdu *request, size_t *availablep)
{
- struct mbuf *m;
uint32_t received_digest, valid_digest;
if (request->ip_conn->ic_header_crc32c == false)
return (0);
- m = icl_conn_receive(request->ip_conn, ISCSI_HEADER_DIGEST_SIZE);
- if (m == NULL) {
+ CTASSERT(sizeof(received_digest) == ISCSI_HEADER_DIGEST_SIZE);
+ if (icl_conn_receive_buf(request->ip_conn,
+ &received_digest, ISCSI_HEADER_DIGEST_SIZE)) {
ICL_DEBUG("failed to receive header digest");
return (-1);
}
-
- CTASSERT(sizeof(received_digest) == ISCSI_HEADER_DIGEST_SIZE);
- m_copydata(m, 0, ISCSI_HEADER_DIGEST_SIZE, (void *)&received_digest);
- m_freem(m);
-
*availablep -= ISCSI_HEADER_DIGEST_SIZE;
/* Temporary attach AHS to BHS to calculate header digest. */
@@ -526,7 +540,6 @@ icl_pdu_receive_data_segment(struct icl_pdu *request,
static int
icl_pdu_check_data_digest(struct icl_pdu *request, size_t *availablep)
{
- struct mbuf *m;
uint32_t received_digest, valid_digest;
if (request->ip_conn->ic_data_crc32c == false)
@@ -535,16 +548,12 @@ icl_pdu_check_data_digest(struct icl_pdu *request, size_t *availablep)
if (request->ip_data_len == 0)
return (0);
- m = icl_conn_receive(request->ip_conn, ISCSI_DATA_DIGEST_SIZE);
- if (m == NULL) {
+ CTASSERT(sizeof(received_digest) == ISCSI_DATA_DIGEST_SIZE);
+ if (icl_conn_receive_buf(request->ip_conn,
+ &received_digest, ISCSI_DATA_DIGEST_SIZE)) {
ICL_DEBUG("failed to receive data digest");
return (-1);
}
-
- CTASSERT(sizeof(received_digest) == ISCSI_DATA_DIGEST_SIZE);
- m_copydata(m, 0, ISCSI_DATA_DIGEST_SIZE, (void *)&received_digest);
- m_freem(m);
-
*availablep -= ISCSI_DATA_DIGEST_SIZE;
/*
@@ -580,7 +589,7 @@ icl_conn_receive_pdu(struct icl_conn *ic, size_t *availablep)
if (ic->ic_receive_state == ICL_CONN_STATE_BHS) {
KASSERT(ic->ic_receive_pdu == NULL,
("ic->ic_receive_pdu != NULL"));
- request = icl_pdu_new_empty(ic, M_NOWAIT);
+ request = icl_soft_conn_new_pdu(ic, M_NOWAIT);
if (request == NULL) {
ICL_DEBUG("failed to allocate PDU; "
"dropping connection");
OpenPOWER on IntegriCloud