diff options
author | mav <mav@FreeBSD.org> | 2017-02-28 06:29:44 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2017-02-28 06:29:44 +0000 |
commit | 255043831e484097b0a3b1305cf4154ee720d833 (patch) | |
tree | a6bbea99df9bf8610722f9e2ed3e174f3b5a6e96 | |
parent | c88f71b70b0172e2697579dea6b19bc127acc0bd (diff) | |
download | FreeBSD-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.c | 79 |
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"); |