Page MenuHomeFreeBSD

D53468.diff
No OneTemporary

D53468.diff

diff --git a/usr.sbin/bhyve/iov.h b/usr.sbin/bhyve/iov.h
--- a/usr.sbin/bhyve/iov.h
+++ b/usr.sbin/bhyve/iov.h
@@ -3,6 +3,7 @@
*
* Copyright (c) 2016 Jakub Klama <jceel@FreeBSD.org>.
* Copyright (c) 2018 Alexander Motin <mav@FreeBSD.org>
+ * Copyright (c) 2026 Hans Rosenfeld
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,12 +32,15 @@
#ifndef _IOV_H_
#define _IOV_H_
-void seek_iov(const struct iovec *iov1, int niov1, struct iovec *iov2,
- int *niov2, size_t seek);
-void truncate_iov(struct iovec *iov, int *niov, size_t length);
-size_t count_iov(const struct iovec *iov, int niov);
-ssize_t iov_to_buf(const struct iovec *iov, int niov, void **buf);
-ssize_t buf_to_iov(const void *buf, size_t buflen, const struct iovec *iov,
- int niov, size_t seek);
+#include <stdbool.h>
+
+/* Number of additional iovecs required for split_iov() */
+#define SPLIT_IOV_ADDL_IOV 2
+
+struct iovec *split_iov(struct iovec *, size_t *, size_t, size_t *);
+size_t count_iov(const struct iovec *, size_t);
+bool check_iov_len(const struct iovec *, size_t, size_t);
+ssize_t iov_to_buf(const struct iovec *, size_t, void **);
+ssize_t buf_to_iov(const void *, size_t, const struct iovec *, size_t);
#endif /* _IOV_H_ */
diff --git a/usr.sbin/bhyve/iov.c b/usr.sbin/bhyve/iov.c
--- a/usr.sbin/bhyve/iov.c
+++ b/usr.sbin/bhyve/iov.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2016 Jakub Klama <jceel@FreeBSD.org>.
* Copyright (c) 2018 Alexander Motin <mav@FreeBSD.org>
+ * Copyright (c) 2026 Hans Rosenfeld
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,45 +33,100 @@
#include <sys/types.h>
#include <sys/uio.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "iov.h"
-void
-seek_iov(const struct iovec *iov1, int niov1, struct iovec *iov2, int *niov2,
- size_t seek)
+/*
+ * Given an array of iovecs iov, the number of valid iovecs niov, and an
+ * offset, truncate iov at offset. If necessary, split the final iovec,
+ * moving the remaining iovecs up by one in iov. Return a pointer to the
+ * iovec beginning at offset, and the total number of remaining iovecs.
+ *
+ * The caller must take care that iov contains enough space for at least
+ * niov+1 iovecs so the remainder of the iovec array may be moved up by one.
+ */
+struct iovec *
+split_iov(struct iovec *iov, size_t *niov, size_t offset, size_t *niov_rem)
{
size_t remainder = 0;
- size_t left = seek;
- int i, j;
+ struct iovec *iov_rem;
+ size_t i;
+
+ /*
+ * Handle the special case of offset == 0: Return the whole iovec array
+ * as the remainder.
+ */
+ if (offset == 0) {
+ *niov_rem = *niov;
+ *niov = 0;
+ return (iov);
+ }
- for (i = 0; i < niov1; i++) {
- size_t toseek = MIN(left, iov1[i].iov_len);
- left -= toseek;
+ /* Seek to the requested offset and truncate the final iovec. */
+ for (i = 0; i < *niov && offset > iov[i].iov_len; i++) {
+ /*
+ * We're seeking past this iovec. Adjust the offset and move on.
+ */
+ offset -= iov[i].iov_len;
+ }
- if (toseek == iov1[i].iov_len)
- continue;
+ /* We've reached the end of the array without reaching the offset. */
+ if (i == *niov) {
+ *niov_rem = 0;
+ return (NULL);
+ }
- if (left == 0) {
- remainder = toseek;
- break;
- }
+ /*
+ * We found the iovec covering offset. Calculate the remainder and
+ * truncate at offset.
+ */
+ remainder = iov[i].iov_len - offset;
+ iov[i].iov_len = offset;
+ *niov_rem = *niov - i - 1;
+ *niov = i + 1;
+ iov_rem = &iov[*niov];
+
+ /*
+ * If there's no remainder in this iovec, we're done. Return the
+ * pointer to the next iovec after the offset, or NULL if there
+ * are no more iovecs beyond offset.
+ */
+ if (remainder == 0) {
+ if (*niov_rem == 0)
+ iov_rem = NULL;
+
+ return (iov_rem);
}
- for (j = i; j < niov1; j++) {
- iov2[j - i].iov_base = (char *)iov1[j].iov_base + remainder;
- iov2[j - i].iov_len = iov1[j].iov_len - remainder;
- remainder = 0;
+ /*
+ * In the (unlikely, ideally) case where there is a remainder from the
+ * final iovec before the split, make room for a new iovec covering the
+ * remainder by moving all following iovecs up. It is the caller's
+ * responsibility that there is enough spare space for this extra iovec.
+ */
+ for (struct iovec *tmp = &iov_rem[*niov_rem];
+ tmp != iov_rem;
+ tmp[0] = tmp[-1], tmp--) {
+ ;
}
- *niov2 = j - i;
+ /*
+ * Fill in the new first iovec, covering the remainder from the split.
+ */
+ iov_rem[0].iov_len = remainder;
+ iov_rem[0].iov_base = (char *)iov[i].iov_base + offset;
+ (*niov_rem)++;
+
+ return (iov_rem);
}
size_t
-count_iov(const struct iovec *iov, int niov)
+count_iov(const struct iovec *iov, size_t niov)
{
size_t total = 0;
- int i;
+ size_t i;
for (i = 0; i < niov; i++)
total += iov[i].iov_len;
@@ -78,29 +134,26 @@
return (total);
}
-void
-truncate_iov(struct iovec *iov, int *niov, size_t length)
+bool
+check_iov_len(const struct iovec *iov, size_t niov, size_t len)
{
- size_t done = 0;
- int i;
-
- for (i = 0; i < *niov; i++) {
- size_t toseek = MIN(length - done, iov[i].iov_len);
- done += toseek;
-
- if (toseek <= iov[i].iov_len) {
- iov[i].iov_len = toseek;
- *niov = i + 1;
- return;
- }
+ size_t total = 0;
+ size_t i;
+
+ for (i = 0; i < niov; i++) {
+ total += iov[i].iov_len;
+ if (total >= len)
+ return (true);
}
+
+ return (false);
}
ssize_t
-iov_to_buf(const struct iovec *iov, int niov, void **buf)
+iov_to_buf(const struct iovec *iov, size_t niov, void **buf)
{
size_t ptr, total;
- int i;
+ size_t i;
total = count_iov(iov, niov);
*buf = realloc(*buf, total);
@@ -116,21 +169,10 @@
}
ssize_t
-buf_to_iov(const void *buf, size_t buflen, const struct iovec *iov, int niov,
- size_t seek)
+buf_to_iov(const void *buf, size_t buflen, const struct iovec *iov, size_t niov)
{
- struct iovec *diov;
size_t off = 0, len;
- int i;
-
- if (seek > 0) {
- int ndiov;
-
- diov = malloc(sizeof(struct iovec) * niov);
- seek_iov(iov, niov, diov, &ndiov, seek);
- iov = diov;
- niov = ndiov;
- }
+ size_t i;
for (i = 0; i < niov && off < buflen; i++) {
len = MIN(iov[i].iov_len, buflen - off);
@@ -138,9 +180,5 @@
off += len;
}
- if (seek > 0)
- free(diov);
-
return ((ssize_t)off);
}
-
diff --git a/usr.sbin/bhyve/net_backends.c b/usr.sbin/bhyve/net_backends.c
--- a/usr.sbin/bhyve/net_backends.c
+++ b/usr.sbin/bhyve/net_backends.c
@@ -198,7 +198,7 @@
* we read it from there.
*/
ret = buf_to_iov(priv->bbuf, priv->bbuflen,
- iov, iovcnt, 0);
+ iov, iovcnt);
/* Mark the bounce buffer as empty. */
priv->bbuflen = 0;
diff --git a/usr.sbin/bhyve/pci_virtio_scsi.c b/usr.sbin/bhyve/pci_virtio_scsi.c
--- a/usr.sbin/bhyve/pci_virtio_scsi.c
+++ b/usr.sbin/bhyve/pci_virtio_scsi.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2016 Jakub Klama <jceel@FreeBSD.org>.
* Copyright (c) 2018 Marcelo Araujo <araujo@FreeBSD.org>.
+ * Copyright (c) 2026 Hans Rosenfeld
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -120,10 +121,11 @@
struct pci_vtscsi_request {
struct pci_vtscsi_queue * vsr_queue;
- struct iovec vsr_iov_in[VTSCSI_MAXSEG];
- int vsr_niov_in;
- struct iovec vsr_iov_out[VTSCSI_MAXSEG];
- int vsr_niov_out;
+ struct iovec vsr_iov[VTSCSI_MAXSEG + SPLIT_IOV_ADDL_IOV];
+ struct iovec * vsr_iov_in;
+ struct iovec * vsr_iov_out;
+ size_t vsr_niov_in;
+ size_t vsr_niov_out;
uint32_t vsr_idx;
STAILQ_ENTRY(pci_vtscsi_request) vsr_link;
};
@@ -230,13 +232,13 @@
static int pci_vtscsi_cfgread(void *, int, int, uint32_t *);
static int pci_vtscsi_cfgwrite(void *, int, int, uint32_t);
static inline int pci_vtscsi_get_lun(uint8_t *);
-static int pci_vtscsi_control_handle(struct pci_vtscsi_softc *, void *, size_t);
-static int pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *,
+static void pci_vtscsi_control_handle(struct pci_vtscsi_softc *, void *, size_t);
+static void pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *,
struct pci_vtscsi_ctrl_tmf *);
-static int pci_vtscsi_an_handle(struct pci_vtscsi_softc *,
+static void pci_vtscsi_an_handle(struct pci_vtscsi_softc *,
struct pci_vtscsi_ctrl_an *);
static int pci_vtscsi_request_handle(struct pci_vtscsi_queue *, struct iovec *,
- int, struct iovec *, int);
+ size_t, struct iovec *, size_t);
static void pci_vtscsi_controlq_notify(void *, struct vqueue_info *);
static void pci_vtscsi_eventq_notify(void *, struct vqueue_info *);
static void pci_vtscsi_requestq_notify(void *, struct vqueue_info *);
@@ -353,7 +355,7 @@
return (((lun[2] << 8) | lun[3]) & 0x3fff);
}
-static int
+static void
pci_vtscsi_control_handle(struct pci_vtscsi_softc *sc, void *buf,
size_t bufsize)
{
@@ -363,7 +365,7 @@
if (bufsize < sizeof(uint32_t)) {
WPRINTF("ignoring truncated control request");
- return (0);
+ return;
}
type = *(uint32_t *)buf;
@@ -371,25 +373,21 @@
if (type == VIRTIO_SCSI_T_TMF) {
if (bufsize != sizeof(*tmf)) {
WPRINTF("ignoring tmf request with size %zu", bufsize);
- return (0);
+ return;
}
tmf = (struct pci_vtscsi_ctrl_tmf *)buf;
- return (pci_vtscsi_tmf_handle(sc, tmf));
- }
-
- if (type == VIRTIO_SCSI_T_AN_QUERY) {
+ pci_vtscsi_tmf_handle(sc, tmf);
+ } else if (type == VIRTIO_SCSI_T_AN_QUERY) {
if (bufsize != sizeof(*an)) {
WPRINTF("ignoring AN request with size %zu", bufsize);
- return (0);
+ return;
}
an = (struct pci_vtscsi_ctrl_an *)buf;
- return (pci_vtscsi_an_handle(sc, an));
+ pci_vtscsi_an_handle(sc, an);
}
-
- return (0);
}
-static int
+static void
pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc,
struct pci_vtscsi_ctrl_tmf *tmf)
{
@@ -454,46 +452,73 @@
tmf->response = io->taskio.task_status;
ctl_scsi_free_io(io);
- return (1);
}
-static int
+static void
pci_vtscsi_an_handle(struct pci_vtscsi_softc *sc __unused,
struct pci_vtscsi_ctrl_an *an __unused)
{
- return (0);
}
static int
pci_vtscsi_request_handle(struct pci_vtscsi_queue *q, struct iovec *iov_in,
- int niov_in, struct iovec *iov_out, int niov_out)
+ size_t niov_in, struct iovec *iov_out, size_t niov_out)
{
struct pci_vtscsi_softc *sc = q->vsq_sc;
struct pci_vtscsi_req_cmd_rd *cmd_rd = NULL;
struct pci_vtscsi_req_cmd_wr *cmd_wr;
- struct iovec data_iov_in[VTSCSI_MAXSEG], data_iov_out[VTSCSI_MAXSEG];
+ struct iovec *data_iov_in, *data_iov_out;
union ctl_io *io;
- int data_niov_in, data_niov_out;
+ size_t data_niov_in, data_niov_out;
void *ext_data_ptr = NULL;
uint32_t ext_data_len = 0, ext_sg_entries = 0;
int err, nxferred;
- if (count_iov(iov_out, niov_out) < VTSCSI_OUT_HEADER_LEN(sc)) {
+ /*
+ * Make sure we got at least enough space for the VirtIO-SCSI
+ * command headers. If not, return this request immediately.
+ */
+ if (check_iov_len(iov_out, niov_out,
+ VTSCSI_OUT_HEADER_LEN(q->vsq_sc)) == false) {
WPRINTF("ignoring request with insufficient output");
return (0);
}
- if (count_iov(iov_in, niov_in) < VTSCSI_IN_HEADER_LEN(sc)) {
+
+ if (check_iov_len(iov_in, niov_in,
+ VTSCSI_IN_HEADER_LEN(q->vsq_sc)) == false) {
WPRINTF("ignoring request with incomplete header");
return (0);
}
- seek_iov(iov_in, niov_in, data_iov_in, &data_niov_in,
- VTSCSI_IN_HEADER_LEN(sc));
- seek_iov(iov_out, niov_out, data_iov_out, &data_niov_out,
- VTSCSI_OUT_HEADER_LEN(sc));
+ /*
+ * We have to split the iovec array into a header and data portion each
+ * for input and output.
+ *
+ * We need to start with the output section (at the end of iov) in case
+ * the iovec covering the final part of the output header needs to be
+ * split, in which case split_iov() will move all reamaining iovecs up
+ * by one to make room for a new iovec covering the first part of the
+ * output data portion.
+ */
+ data_iov_out = split_iov(iov_out, &niov_out,
+ VTSCSI_OUT_HEADER_LEN(q->vsq_sc), &data_niov_out);
+
+ /*
+ * Similarly, to not overwrite the first iovec of the output section,
+ * the 2nd call to split_iov() to split the input section must actually
+ * cover the entire iovec array (both input and the already split output
+ * sections).
+ */
+ niov_in += niov_out + data_niov_out;
+
+ data_iov_in = split_iov(iov_in, &niov_in,
+ VTSCSI_IN_HEADER_LEN(q->vsq_sc), &data_niov_in);
+
+ /*
+ * And of course we now have to adjust data_niov_in accordingly.
+ */
+ data_niov_in -= niov_out + data_niov_out;
- truncate_iov(iov_in, &niov_in, VTSCSI_IN_HEADER_LEN(sc));
- truncate_iov(iov_out, &niov_out, VTSCSI_OUT_HEADER_LEN(sc));
iov_to_buf(iov_in, niov_in, (void **)&cmd_rd);
cmd_wr = calloc(1, VTSCSI_OUT_HEADER_LEN(sc));
@@ -564,7 +589,7 @@
cmd_wr->sense_len);
}
- buf_to_iov(cmd_wr, VTSCSI_OUT_HEADER_LEN(sc), iov_out, niov_out, 0);
+ buf_to_iov(cmd_wr, VTSCSI_OUT_HEADER_LEN(sc), iov_out, niov_out);
nxferred = VTSCSI_OUT_HEADER_LEN(sc) + io->scsiio.ext_data_filled;
free(cmd_rd);
free(cmd_wr);
@@ -580,7 +605,7 @@
struct vi_req req;
void *buf = NULL;
size_t bufsize;
- int iolen, n;
+ int n;
sc = vsc;
@@ -589,14 +614,13 @@
assert(n >= 1 && n <= VTSCSI_MAXSEG);
bufsize = iov_to_buf(iov, n, &buf);
- iolen = pci_vtscsi_control_handle(sc, buf, bufsize);
- buf_to_iov((uint8_t *)buf + bufsize - iolen, iolen, iov, n,
- bufsize - iolen);
+ pci_vtscsi_control_handle(sc, buf, bufsize);
+ buf_to_iov((uint8_t *)buf, bufsize, iov, n);
/*
* Release this chain and handle more
*/
- vq_relchain(vq, req.idx, iolen);
+ vq_relchain(vq, req.idx, bufsize);
}
vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
free(buf);
@@ -614,7 +638,6 @@
struct pci_vtscsi_softc *sc;
struct pci_vtscsi_queue *q;
struct pci_vtscsi_request *req;
- struct iovec iov[VTSCSI_MAXSEG];
struct vi_req vireq;
int n;
@@ -622,18 +645,17 @@
q = &sc->vss_queues[vq->vq_num - 2];
while (vq_has_descs(vq)) {
- n = vq_getchain(vq, iov, VTSCSI_MAXSEG, &vireq);
+ req = calloc(1, sizeof(struct pci_vtscsi_request));
+
+ n = vq_getchain(vq, req->vsr_iov, VTSCSI_MAXSEG, &vireq);
assert(n >= 1 && n <= VTSCSI_MAXSEG);
- req = calloc(1, sizeof(struct pci_vtscsi_request));
req->vsr_idx = vireq.idx;
req->vsr_queue = q;
+ req->vsr_iov_in = &req->vsr_iov[0];
req->vsr_niov_in = vireq.readable;
+ req->vsr_iov_out = &req->vsr_iov[vireq.readable];
req->vsr_niov_out = vireq.writable;
- memcpy(req->vsr_iov_in, iov,
- req->vsr_niov_in * sizeof(struct iovec));
- memcpy(req->vsr_iov_out, iov + vireq.readable,
- req->vsr_niov_out * sizeof(struct iovec));
pthread_mutex_lock(&q->vsq_mtx);
STAILQ_INSERT_TAIL(&q->vsq_requests, req, vsr_link);

File Metadata

Mime Type
text/plain
Expires
Thu, Feb 19, 12:44 PM (6 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28879144
Default Alt Text
D53468.diff (14 KB)

Event Timeline