diff --git a/etc/skel/dot.version b/etc/skel/dot.version index 9d13ca487..fcdeeb1da 100644 --- a/etc/skel/dot.version +++ b/etc/skel/dot.version @@ -1 +1 @@ -# SecBSD 1.3-c7a8681: Sun Sep 10 00:00:00 UTC 2023 (Tezcatlipoca) +# SecBSD 1.3-88c72e05f8: Thu Sep 14 00:00:00 UTC 2023 (Tezcatlipoca) diff --git a/share/man/man5/bsd.port.mk.5 b/share/man/man5/bsd.port.mk.5 index 73380a6f8..26d48d4b6 100644 --- a/share/man/man5/bsd.port.mk.5 +++ b/share/man/man5/bsd.port.mk.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: bsd.port.mk.5,v 1.627 2023/09/12 08:54:04 jsg Exp $ +.\" $OpenBSD: bsd.port.mk.5,v 1.628 2023/09/14 14:06:13 sthen Exp $ .\" .\" Copyright (c) 2000-2008 Marc Espie .\" @@ -24,7 +24,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: September 12 2023 $ +.Dd $Mdocdate: September 14 2023 $ .Dt BSD.PORT.MK 5 .Os .Sh NAME @@ -746,6 +746,10 @@ See Generate and print the list of static and dynamic libraries present in the port. See .Xr pkg_create 1 . +.It Cm print-plist-all-libs +Iterate over +.Cm print-plist-libs +for all subpackages in a given port. .It Cm print-plist-libs-with-depends Like .Cm print-plist-libs , diff --git a/usr.bin/tmux/screen-write.c b/usr.bin/tmux/screen-write.c index 72c8f3bde..96a4916be 100644 --- a/usr.bin/tmux/screen-write.c +++ b/usr.bin/tmux/screen-write.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen-write.c,v 1.220 2023/09/01 16:01:54 nicm Exp $ */ +/* $OpenBSD: screen-write.c,v 1.221 2023/09/14 13:01:35 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1742,6 +1742,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx) if (ci->used == 0) return; + ctx->flags &= ~SCREEN_WRITE_COMBINE; before = screen_write_collect_trim(ctx, s->cy, s->cx, ci->used, &wrapped); @@ -1792,8 +1793,6 @@ screen_write_collect_add(struct screen_write_ctx *ctx, u_int sx = screen_size_x(s); int collect; - ctx->flags &= ~SCREEN_WRITE_COMBINE; - /* * Don't need to check that the attributes and whatnot are still the * same - input_parse will end the collection when anything that isn't @@ -1873,7 +1872,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) screen_write_collect_flush(ctx, 0, __func__); gc = screen_write_combine(ctx, combine, &xx, &cx); if (gc != NULL) { - cy = s->cy; + cx = s->cx; cy = s->cy; screen_write_set_cursor(ctx, xx, s->cy); screen_write_initctx(ctx, &ttyctx, 0); ttyctx.cell = gc; diff --git a/usr.sbin/crunchgen/crunchgen.c b/usr.sbin/crunchgen/crunchgen.c index 1bb6c30f2..b5a859bd4 100644 --- a/usr.sbin/crunchgen/crunchgen.c +++ b/usr.sbin/crunchgen/crunchgen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crunchgen.c,v 1.26 2023/04/16 19:57:01 deraadt Exp $ */ +/* $OpenBSD: crunchgen.c,v 1.27 2023/09/14 16:39:00 jca Exp $ */ /* * Copyright (c) 1994 University of Maryland @@ -904,7 +904,7 @@ top_makefile_rules(FILE * outmk) fprintf(outmk, "CFLAGS+=-fno-asynchronous-unwind-tables\n"); fprintf(outmk, "LDFLAGS+=$(NOPIE_LDFLAGS)\n"); fprintf(outmk, "STRIP?=strip\n"); - fprintf(outmk, "LINK=$(LD) -dc -r ${LDFLAGS}\n"); + fprintf(outmk, "LINK=$(LD) -d -r ${LDFLAGS}\n"); fprintf(outmk, "LIBS="); for (l = libdirs; l != NULL; l = l->next) fprintf(outmk, " -L%s", l->str); diff --git a/usr.sbin/radiusd/radiusd.conf.5 b/usr.sbin/radiusd/radiusd.conf.5 index f1271f1ca..f461217c6 100644 --- a/usr.sbin/radiusd/radiusd.conf.5 +++ b/usr.sbin/radiusd/radiusd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: radiusd.conf.5,v 1.17 2023/09/08 05:56:22 yasuoka Exp $ +.\" $OpenBSD: radiusd.conf.5,v 1.18 2023/09/14 09:55:28 yasuoka Exp $ .\" .\" Copyright (c) 2014 Esdenera Networks GmbH .\" Copyright (c) 2014, 2023 Internet Initiative Japan Inc. @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 8 2023 $ +.Dd $Mdocdate: September 14 2023 $ .Dt RADIUSD.CONF 5 .Os .Sh NAME @@ -130,7 +130,8 @@ This configuration cannot be omitted. .It Ic max-tries Ar number Specify the maximum number of retransmissions for a server. .Xr radiusd 8 -will retransmit 2, 6, 14, 22, and 30 seconds after the first transmission. +will retransmit 2, 6, 14, 22, and 30 seconds after the first transmission +and subsequent retransmissions will occur every 8 seconds. If the number of retransmissions per server reaches this value, the current server is marked as .Dq fail , diff --git a/usr.sbin/relayd/pfe_filter.c b/usr.sbin/relayd/pfe_filter.c index f884ac5ae..97aea01df 100644 --- a/usr.sbin/relayd/pfe_filter.c +++ b/usr.sbin/relayd/pfe_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfe_filter.c,v 1.63 2023/06/30 12:16:00 sashan Exp $ */ +/* $OpenBSD: pfe_filter.c,v 1.65 2023/09/14 09:54:31 yasuoka Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard diff --git a/usr.sbin/vmd/vioblk.c b/usr.sbin/vmd/vioblk.c index 87ad721b7..a74348441 100644 --- a/usr.sbin/vmd/vioblk.c +++ b/usr.sbin/vmd/vioblk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vioblk.c,v 1.7 2023/09/06 19:27:54 dv Exp $ */ +/* $OpenBSD: vioblk.c,v 1.8 2023/09/14 15:25:43 dv Exp $ */ /* * Copyright (c) 2023 Dave Voutila @@ -37,13 +37,18 @@ extern char *__progname; extern struct vmd_vm *current_vm; +struct iovec io_v[VIOBLK_QUEUE_SIZE]; static const char *disk_type(int); static uint32_t handle_io_read(struct viodev_msg *, struct virtio_dev *, int8_t *); static int handle_io_write(struct viodev_msg *, struct virtio_dev *); -void vioblk_notify_rx(struct vioblk_dev *); -int vioblk_notifyq(struct vioblk_dev *); + +static void vioblk_update_qs(struct vioblk_dev *); +static void vioblk_update_qa(struct vioblk_dev *); +static int vioblk_notifyq(struct vioblk_dev *); +static ssize_t vioblk_rw(struct vioblk_dev *, int, off_t, + struct vring_desc *, struct vring_desc **); static void dev_dispatch_vm(int, short, void *); static void handle_sync_io(int, short, void *); @@ -79,6 +84,9 @@ vioblk_main(int fd, int fd_vmm) if (pledge("stdio vmm proc", NULL) == -1) fatal("pledge"); + /* Zero and initialize io work queue. */ + memset(io_v, 0, nitems(io_v)*sizeof(io_v[0])); + /* Receive our virtio_dev, mostly preconfigured. */ memset(&dev, 0, sizeof(dev)); sz = atomicio(read, fd, &dev, sizeof(dev)); @@ -96,9 +104,9 @@ vioblk_main(int fd, int fd_vmm) vioblk = &dev.vioblk; log_debug("%s: got viblk dev. num disk fds = %d, sync fd = %d, " - "async fd = %d, sz = %lld maxfer = %d, vmm fd = %d", __func__, - vioblk->ndisk_fd, dev.sync_fd, dev.async_fd, vioblk->sz, - vioblk->max_xfer, fd_vmm); + "async fd = %d, capacity = %lld seg_max = %u, vmm fd = %d", + __func__, vioblk->ndisk_fd, dev.sync_fd, dev.async_fd, + vioblk->capacity, vioblk->seg_max, fd_vmm); /* Receive our vm information from the vm process. */ memset(&vm, 0, sizeof(vm)); @@ -145,9 +153,9 @@ vioblk_main(int fd, int fd_vmm) log_warnx("failed to init disk %s image", disk_type(type)); goto fail; } - vioblk->sz = szp / 512; - log_debug("%s: initialized vioblk[%d] with %s image (sz=%lld)", - __func__, vioblk->idx, disk_type(type), vioblk->sz); + vioblk->capacity = szp / 512; + log_debug("%s: initialized vioblk[%d] with %s image (capacity=%lld)", + __func__, vioblk->idx, disk_type(type), vioblk->capacity); /* If we're restoring hardware, reinitialize the virtqueue hva. */ if (vm.vm_state & VM_STATE_RECEIVED) @@ -240,7 +248,7 @@ vioblk_cmd_name(uint32_t type) } } -void +static void vioblk_update_qa(struct vioblk_dev *dev) { struct virtio_vq_info *vq_info; @@ -259,7 +267,7 @@ vioblk_update_qa(struct vioblk_dev *dev) vq_info->q_hva = hva; } -void +static void vioblk_update_qs(struct vioblk_dev *dev) { struct virtio_vq_info *vq_info; @@ -277,122 +285,26 @@ vioblk_update_qs(struct vioblk_dev *dev) dev->cfg.queue_size = vq_info->qs; } -static void -vioblk_free_info(struct ioinfo *info) -{ - if (!info) - return; - free(info->buf); - free(info); -} - -static struct ioinfo * -vioblk_start_read(struct vioblk_dev *dev, off_t sector, size_t sz) -{ - struct ioinfo *info; - - /* Limit to 64M for now */ - if (sz > (1 << 26)) { - log_warnx("%s: read size exceeded 64M", __func__); - return (NULL); - } - - info = calloc(1, sizeof(*info)); - if (!info) - goto nomem; - info->buf = malloc(sz); - if (info->buf == NULL) - goto nomem; - info->len = sz; - info->offset = sector * VIRTIO_BLK_SECTOR_SIZE; - return info; - -nomem: - free(info); - log_warn("malloc error vioblk read"); - return (NULL); -} - - -static const uint8_t * -vioblk_finish_read(struct vioblk_dev *dev, struct ioinfo *info) -{ - struct virtio_backing *file = &dev->file; - - if (file == NULL || file->pread == NULL) { - log_warnx("%s: XXX null?!", __func__); - return NULL; - } - if (file->pread(file->p, info->buf, info->len, info->offset) != info->len) { - log_warn("vioblk read error"); - return NULL; - } - - return info->buf; -} - -static struct ioinfo * -vioblk_start_write(struct vioblk_dev *dev, off_t sector, - paddr_t addr, size_t len) -{ - struct ioinfo *info; - - /* Limit to 64M for now */ - if (len > (1 << 26)) { - log_warnx("%s: write size exceeded 64M", __func__); - return (NULL); - } - - info = calloc(1, sizeof(*info)); - if (!info) - goto nomem; - - info->buf = malloc(len); - if (info->buf == NULL) - goto nomem; - info->len = len; - info->offset = sector * VIRTIO_BLK_SECTOR_SIZE; - - if (read_mem(addr, info->buf, info->len)) { - vioblk_free_info(info); - return NULL; - } - - return info; - -nomem: - free(info); - log_warn("malloc error vioblk write"); - return (NULL); -} - -static int -vioblk_finish_write(struct vioblk_dev *dev, struct ioinfo *info) -{ - struct virtio_backing *file = &dev->file; - - if (file->pwrite(file->p, info->buf, info->len, info->offset) != info->len) { - log_warn("vioblk write error"); - return EIO; - } - return 0; -} - /* - * XXX in various cases, ds should be set to VIRTIO_BLK_S_IOERR, if we can + * Process virtqueue notifications. If an unrecoverable error occurs, puts + * device into a "needs reset" state. + * + * Returns 1 if an we need to assert an IRQ. */ -int +static int vioblk_notifyq(struct vioblk_dev *dev) { - uint16_t idx, cmd_desc_idx, secdata_desc_idx, ds_desc_idx; + uint32_t cmd_len; + uint16_t idx, cmd_desc_idx; uint8_t ds; - int cnt; - off_t secbias; + off_t offset; + ssize_t sz; + int is_write, notify, i; char *vr; - struct vring_desc *desc, *cmd_desc, *secdata_desc, *ds_desc; + struct vring_desc *table, *desc; struct vring_avail *avail; struct vring_used *used; - struct virtio_blk_req_hdr cmd; + struct virtio_blk_req_hdr *cmd; struct virtio_vq_info *vq_info; /* Invalid queue? */ @@ -400,253 +312,117 @@ vioblk_notifyq(struct vioblk_dev *dev) return (0); vq_info = &dev->vq[dev->cfg.queue_notify]; + idx = vq_info->last_avail; vr = vq_info->q_hva; if (vr == NULL) fatalx("%s: null vring", __func__); - /* Compute offsets in ring of descriptors, avail ring, and used ring */ - desc = (struct vring_desc *)(vr); + /* Compute offsets in table of descriptors, avail ring, and used ring */ + table = (struct vring_desc *)(vr); avail = (struct vring_avail *)(vr + vq_info->vq_availoffset); used = (struct vring_used *)(vr + vq_info->vq_usedoffset); - idx = vq_info->last_avail & VIOBLK_QUEUE_MASK; + while (idx != avail->idx) { + /* Retrieve Command descriptor. */ + cmd_desc_idx = avail->ring[idx & VIOBLK_QUEUE_MASK]; + desc = &table[cmd_desc_idx]; + cmd_len = desc->len; - if ((avail->idx & VIOBLK_QUEUE_MASK) == idx) { - log_debug("%s - nothing to do?", __func__); - return (0); - } - - while (idx != (avail->idx & VIOBLK_QUEUE_MASK)) { - - ds = VIRTIO_BLK_S_IOERR; - cmd_desc_idx = avail->ring[idx] & VIOBLK_QUEUE_MASK; - cmd_desc = &desc[cmd_desc_idx]; - - if ((cmd_desc->flags & VRING_DESC_F_NEXT) == 0) { - log_warnx("unchained vioblk cmd descriptor received " - "(idx %d)", cmd_desc_idx); - goto out; + /* + * Validate Command descriptor. It should be chained to another + * descriptor and not be itself writable. + */ + if ((desc->flags & VRING_DESC_F_NEXT) == 0) { + log_warnx("%s: unchained cmd descriptor", __func__); + goto reset; + } + if (DESC_WRITABLE(desc)) { + log_warnx("%s: invalid cmd descriptor state", __func__); + goto reset; } - /* Read command from descriptor ring */ - if (cmd_desc->flags & VRING_DESC_F_WRITE) { - log_warnx("vioblk: unexpected writable cmd descriptor " - "%d", cmd_desc_idx); - goto out; - } - if (read_mem(cmd_desc->addr, &cmd, sizeof(cmd))) { - log_warnx("vioblk: command read_mem error @ 0x%llx", - cmd_desc->addr); - goto out; - } + /* Retrieve the vioblk command request. */ + cmd = hvaddr_mem(desc->addr, sizeof(*cmd)); + if (cmd == NULL) + goto reset; - switch (cmd.type) { + /* Advance to the 2nd descriptor. */ + desc = &table[desc->next & VIOBLK_QUEUE_MASK]; + + /* Process each available command & chain. */ + switch (cmd->type) { case VIRTIO_BLK_T_IN: - /* first descriptor */ - secdata_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; - secdata_desc = &desc[secdata_desc_idx]; - - if ((secdata_desc->flags & VRING_DESC_F_NEXT) == 0) { - log_warnx("unchained vioblk data descriptor " - "received (idx %d)", cmd_desc_idx); - goto out; - } - - cnt = 0; - secbias = 0; - do { - struct ioinfo *info; - const uint8_t *secdata; - - if ((secdata_desc->flags & VRING_DESC_F_WRITE) - == 0) { - log_warnx("vioblk: unwritable data " - "descriptor %d", secdata_desc_idx); - goto out; - } - - info = vioblk_start_read(dev, - cmd.sector + secbias, secdata_desc->len); - - if (info == NULL) { - log_warnx("vioblk: can't start read"); - goto out; - } - - /* read the data, use current data descriptor */ - secdata = vioblk_finish_read(dev, info); - if (secdata == NULL) { - vioblk_free_info(info); - log_warnx("vioblk: block read error, " - "sector %lld", cmd.sector); - goto out; - } - - if (write_mem(secdata_desc->addr, secdata, - secdata_desc->len)) { - log_warnx("can't write sector " - "data to gpa @ 0x%llx", - secdata_desc->addr); - vioblk_free_info(info); - goto out; - } - - vioblk_free_info(info); - - secbias += (secdata_desc->len / - VIRTIO_BLK_SECTOR_SIZE); - secdata_desc_idx = secdata_desc->next & - VIOBLK_QUEUE_MASK; - secdata_desc = &desc[secdata_desc_idx]; - - /* Guard against infinite chains */ - if (++cnt >= VIOBLK_QUEUE_SIZE) { - log_warnx("%s: descriptor table " - "invalid", __func__); - goto out; - } - } while (secdata_desc->flags & VRING_DESC_F_NEXT); - - ds_desc_idx = secdata_desc_idx; - ds_desc = secdata_desc; - - ds = VIRTIO_BLK_S_OK; - break; case VIRTIO_BLK_T_OUT: - secdata_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; - secdata_desc = &desc[secdata_desc_idx]; - - if ((secdata_desc->flags & VRING_DESC_F_NEXT) == 0) { - log_warnx("wr vioblk: unchained vioblk data " - "descriptor received (idx %d)", - cmd_desc_idx); - goto out; - } - - if (secdata_desc->len > dev->max_xfer) { - log_warnx("%s: invalid read size %d requested", - __func__, secdata_desc->len); - goto out; - } - - cnt = 0; - secbias = 0; - do { - struct ioinfo *info; - - if (secdata_desc->flags & VRING_DESC_F_WRITE) { - log_warnx("wr vioblk: unexpected " - "writable data descriptor %d", - secdata_desc_idx); - goto out; - } - - info = vioblk_start_write(dev, - cmd.sector + secbias, - secdata_desc->addr, secdata_desc->len); - - if (info == NULL) { - log_warnx("wr vioblk: can't read " - "sector data @ 0x%llx", - secdata_desc->addr); - goto out; - } - - if (vioblk_finish_write(dev, info)) { - log_warnx("wr vioblk: disk write " - "error"); - vioblk_free_info(info); - goto out; - } - - vioblk_free_info(info); - - secbias += secdata_desc->len / - VIRTIO_BLK_SECTOR_SIZE; - - secdata_desc_idx = secdata_desc->next & - VIOBLK_QUEUE_MASK; - secdata_desc = &desc[secdata_desc_idx]; - - /* Guard against infinite chains */ - if (++cnt >= VIOBLK_QUEUE_SIZE) { - log_warnx("%s: descriptor table " - "invalid", __func__); - goto out; - } - } while (secdata_desc->flags & VRING_DESC_F_NEXT); - - ds_desc_idx = secdata_desc_idx; - ds_desc = secdata_desc; - - ds = VIRTIO_BLK_S_OK; - break; - case VIRTIO_BLK_T_FLUSH: - case VIRTIO_BLK_T_FLUSH_OUT: - ds_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; - ds_desc = &desc[ds_desc_idx]; - - ds = VIRTIO_BLK_S_UNSUPP; + /* Read (IN) & Write (OUT) */ + is_write = (cmd->type == VIRTIO_BLK_T_OUT) ? 1 : 0; + offset = cmd->sector * VIRTIO_BLK_SECTOR_SIZE; + sz = vioblk_rw(dev, is_write, offset, table, &desc); + if (sz == -1) + ds = VIRTIO_BLK_S_IOERR; + else + ds = VIRTIO_BLK_S_OK; break; case VIRTIO_BLK_T_GET_ID: - secdata_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; - secdata_desc = &desc[secdata_desc_idx]; - /* * We don't support this command yet. While it's not * officially part of the virtio spec (will be in v1.2) * there's no feature to negotiate. Linux drivers will * often send this command regardless. - * - * When the command is received, it should appear as a - * chain of 3 descriptors, similar to the IN/OUT - * commands. The middle descriptor should have have a - * length of VIRTIO_BLK_ID_BYTES bytes. */ - if ((secdata_desc->flags & VRING_DESC_F_NEXT) == 0) { - log_warnx("id vioblk: unchained vioblk data " - "descriptor received (idx %d)", - cmd_desc_idx); - goto out; - } - - /* Skip the data descriptor. */ - ds_desc_idx = secdata_desc->next & VIOBLK_QUEUE_MASK; - ds_desc = &desc[ds_desc_idx]; - ds = VIRTIO_BLK_S_UNSUPP; - break; default: - log_warnx("%s: unsupported command 0x%x", __func__, - cmd.type); - ds_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; - ds_desc = &desc[ds_desc_idx]; - + log_warnx("%s: unsupported vioblk command %d", __func__, + cmd->type); ds = VIRTIO_BLK_S_UNSUPP; break; } - if ((ds_desc->flags & VRING_DESC_F_WRITE) == 0) { - log_warnx("%s: ds descriptor %d unwritable", __func__, - ds_desc_idx); - goto out; - } - if (write_mem(ds_desc->addr, &ds, sizeof(ds))) { - log_warnx("%s: can't write device status data @ 0x%llx", - __func__, ds_desc->addr); - goto out; + /* Advance to the end of the chain, if needed. */ + i = 0; + while (desc->flags & VRING_DESC_F_NEXT) { + desc = &table[desc->next & VIOBLK_QUEUE_MASK]; + if (++i >= VIOBLK_QUEUE_SIZE) { + /* + * If we encounter an infinite/looping chain, + * not much we can do but say we need a reset. + */ + log_warnx("%s: descriptor chain overflow", + __func__); + goto reset; + } } - dev->cfg.isr_status = 1; + /* Provide the status of our command processing. */ + if (!DESC_WRITABLE(desc)) { + log_warnx("%s: status descriptor unwritable", __func__); + goto reset; + } + /* Overkill as ds is 1 byte, but validates gpa. */ + if (write_mem(desc->addr, &ds, sizeof(ds))) + log_warnx("%s: can't write device status data " + "@ 0x%llx",__func__, desc->addr); + + dev->cfg.isr_status |= 1; + notify = 1; + used->ring[used->idx & VIOBLK_QUEUE_MASK].id = cmd_desc_idx; - used->ring[used->idx & VIOBLK_QUEUE_MASK].len = cmd_desc->len; + used->ring[used->idx & VIOBLK_QUEUE_MASK].len = cmd_len; + __sync_synchronize(); used->idx++; - - vq_info->last_avail = avail->idx & VIOBLK_QUEUE_MASK; - idx = (idx + 1) & VIOBLK_QUEUE_MASK; + idx++; } -out: + + vq_info->last_avail = idx; + return (notify); + +reset: + /* + * When setting the "needs reset" flag, the driver is notified + * via a configuration change interrupt. + */ + dev->cfg.device_status |= DEVICE_NEEDS_RESET; + dev->cfg.isr_status |= VIRTIO_CONFIG_ISR_CONFIG_CHANGE; return (1); } @@ -815,9 +591,12 @@ handle_io_write(struct viodev_msg *msg, struct virtio_dev *dev) vioblk_update_qs(vioblk); break; case VIRTIO_CONFIG_QUEUE_NOTIFY: - vioblk->cfg.queue_notify = data; - if (vioblk_notifyq(vioblk)) - intr = 1; + /* XXX We should be stricter about status checks. */ + if (!(vioblk->cfg.device_status & DEVICE_NEEDS_RESET)) { + vioblk->cfg.queue_notify = data; + if (vioblk_notifyq(vioblk)) + intr = 1; + } break; case VIRTIO_CONFIG_DEVICE_STATUS: vioblk->cfg.device_status = data; @@ -857,15 +636,15 @@ handle_io_read(struct viodev_msg *msg, struct virtio_dev *dev, int8_t *intr) case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI: switch (sz) { case 4: - data = (uint32_t)(vioblk->sz); + data = (uint32_t)(vioblk->capacity); break; case 2: data &= 0xFFFF0000; - data |= (uint32_t)(vioblk->sz) & 0xFFFF; + data |= (uint32_t)(vioblk->capacity) & 0xFFFF; break; case 1: data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz) & 0xFF; + data |= (uint32_t)(vioblk->capacity) & 0xFF; break; } /* XXX handle invalid sz */ @@ -873,39 +652,39 @@ handle_io_read(struct viodev_msg *msg, struct virtio_dev *dev, int8_t *intr) case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 1: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz >> 8) & 0xFF; + data |= (uint32_t)(vioblk->capacity >> 8) & 0xFF; } /* XXX handle invalid sz */ break; case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 2: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz >> 16) & 0xFF; + data |= (uint32_t)(vioblk->capacity >> 16) & 0xFF; } else if (sz == 2) { data &= 0xFFFF0000; - data |= (uint32_t)(vioblk->sz >> 16) & 0xFFFF; + data |= (uint32_t)(vioblk->capacity >> 16) & 0xFFFF; } /* XXX handle invalid sz */ break; case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 3: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz >> 24) & 0xFF; + data |= (uint32_t)(vioblk->capacity >> 24) & 0xFF; } /* XXX handle invalid sz */ break; case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 4: switch (sz) { case 4: - data = (uint32_t)(vioblk->sz >> 32); + data = (uint32_t)(vioblk->capacity >> 32); break; case 2: data &= 0xFFFF0000; - data |= (uint32_t)(vioblk->sz >> 32) & 0xFFFF; + data |= (uint32_t)(vioblk->capacity >> 32) & 0xFFFF; break; case 1: data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz >> 32) & 0xFF; + data |= (uint32_t)(vioblk->capacity >> 32) & 0xFF; break; } /* XXX handle invalid sz */ @@ -913,65 +692,65 @@ handle_io_read(struct viodev_msg *msg, struct virtio_dev *dev, int8_t *intr) case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 5: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz >> 40) & 0xFF; + data |= (uint32_t)(vioblk->capacity >> 40) & 0xFF; } /* XXX handle invalid sz */ break; case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 6: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz >> 48) & 0xFF; + data |= (uint32_t)(vioblk->capacity >> 48) & 0xFF; } else if (sz == 2) { data &= 0xFFFF0000; - data |= (uint32_t)(vioblk->sz >> 48) & 0xFFFF; + data |= (uint32_t)(vioblk->capacity >> 48) & 0xFFFF; } /* XXX handle invalid sz */ break; case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 7: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->sz >> 56) & 0xFF; + data |= (uint32_t)(vioblk->capacity >> 56) & 0xFF; } /* XXX handle invalid sz */ break; - case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 8: + case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 12: switch (sz) { case 4: - data = (uint32_t)(vioblk->max_xfer); + data = (uint32_t)(vioblk->seg_max); break; case 2: data &= 0xFFFF0000; - data |= (uint32_t)(vioblk->max_xfer) & 0xFFFF; + data |= (uint32_t)(vioblk->seg_max) & 0xFFFF; break; case 1: data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->max_xfer) & 0xFF; + data |= (uint32_t)(vioblk->seg_max) & 0xFF; break; } /* XXX handle invalid sz */ break; - case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 9: + case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 13: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->max_xfer >> 8) & 0xFF; + data |= (uint32_t)(vioblk->seg_max >> 8) & 0xFF; } /* XXX handle invalid sz */ break; - case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 10: + case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 14: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->max_xfer >> 16) & 0xFF; + data |= (uint32_t)(vioblk->seg_max >> 16) & 0xFF; } else if (sz == 2) { data &= 0xFFFF0000; - data |= (uint32_t)(vioblk->max_xfer >> 16) + data |= (uint32_t)(vioblk->seg_max >> 16) & 0xFFFF; } /* XXX handle invalid sz */ break; - case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 11: + case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 15: if (sz == 1) { data &= 0xFFFFFF00; - data |= (uint32_t)(vioblk->max_xfer >> 24) & 0xFF; + data |= (uint32_t)(vioblk->seg_max >> 24) & 0xFF; } /* XXX handle invalid sz */ break; @@ -1008,3 +787,84 @@ handle_io_read(struct viodev_msg *msg, struct virtio_dev *dev, int8_t *intr) return (data); } + +/* + * Emulate read/write io. Walks the descriptor chain, collecting io work and + * then emulates the read or write. + * + * On success, returns bytes read/written. + * On error, returns -1 and descriptor (desc) remains at its current position. + */ +static ssize_t +vioblk_rw(struct vioblk_dev *dev, int is_write, off_t offset, + struct vring_desc *desc_tbl, struct vring_desc **desc) +{ + struct iovec *iov = NULL; + ssize_t sz = 0; + size_t io_idx = 0; /* Index into iovec workqueue. */ + size_t xfer_sz = 0; /* Total accumulated io bytes. */ + + do { + iov = &io_v[io_idx]; + + /* + * Reads require writable descriptors. Writes require + * non-writeable descriptors. + */ + if ((!is_write) ^ DESC_WRITABLE(*desc)) { + log_warnx("%s: invalid descriptor for %s command", + __func__, is_write ? "write" : "read"); + return (-1); + } + + /* Collect the IO segment information. */ + iov->iov_len = (size_t)(*desc)->len; + iov->iov_base = hvaddr_mem((*desc)->addr, iov->iov_len); + if (iov->iov_base == NULL) + return (-1); + + /* Move our counters. */ + xfer_sz += iov->iov_len; + io_idx++; + + /* Guard against infinite chains */ + if (io_idx >= nitems(io_v)) { + log_warnx("%s: descriptor table " + "invalid", __func__); + return (-1); + } + + /* Advance to the next descriptor. */ + *desc = &desc_tbl[(*desc)->next & VIOBLK_QUEUE_MASK]; + } while ((*desc)->flags & VRING_DESC_F_NEXT); + + /* + * Validate the requested block io operation alignment and size. + * Checking offset is just an extra caution as it is derived from + * a disk sector and is done for completeness in bounds checking. + */ + if (offset % VIRTIO_BLK_SECTOR_SIZE != 0 && + xfer_sz % VIRTIO_BLK_SECTOR_SIZE != 0) { + log_warnx("%s: unaligned read", __func__); + return (-1); + } + if (xfer_sz > SSIZE_MAX) { /* iovec_copyin limit */ + log_warnx("%s: invalid %s size: %zu", __func__, + is_write ? "write" : "read", xfer_sz); + return (-1); + } + + /* Emulate the Read or Write operation. */ + if (is_write) + sz = dev->file.pwritev(dev->file.p, io_v, io_idx, offset); + else + sz = dev->file.preadv(dev->file.p, io_v, io_idx, offset); + if (sz != (ssize_t)xfer_sz) { + log_warnx("%s: %s failure at offset 0x%llx, xfer_sz=%zu, " + "sz=%ld", __func__, (is_write ? "write" : "read"), offset, + xfer_sz, sz); + return (-1); + } + + return (sz); +} diff --git a/usr.sbin/vmd/vioqcow2.c b/usr.sbin/vmd/vioqcow2.c index c648d6681..753cce6e4 100644 --- a/usr.sbin/vmd/vioqcow2.c +++ b/usr.sbin/vmd/vioqcow2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vioqcow2.c,v 1.23 2023/05/28 05:28:50 asou Exp $ */ +/* $OpenBSD: vioqcow2.c,v 1.24 2023/09/14 15:25:43 dv Exp $ */ /* * Copyright (c) 2018 Ori Bernstein @@ -105,7 +105,9 @@ static void inc_refs(struct qcdisk *, off_t, int); static off_t mkcluster(struct qcdisk *, struct qcdisk *, off_t, off_t); static int qc2_open(struct qcdisk *, int *, size_t); static ssize_t qc2_pread(void *, char *, size_t, off_t); +static ssize_t qc2_preadv(void *, struct iovec *, int, off_t); static ssize_t qc2_pwrite(void *, char *, size_t, off_t); +static ssize_t qc2_pwritev(void *, struct iovec *, int, off_t); static void qc2_close(void *, int); /* @@ -128,7 +130,9 @@ virtio_qcow2_init(struct virtio_backing *file, off_t *szp, int *fd, size_t nfd) } file->p = diskp; file->pread = qc2_pread; + file->preadv = qc2_preadv; file->pwrite = qc2_pwrite; + file->pwritev = qc2_pwritev; file->close = qc2_close; *szp = diskp->disksz; return 0; @@ -304,6 +308,24 @@ qc2_open(struct qcdisk *disk, int *fds, size_t nfd) return 0; } +static ssize_t +qc2_preadv(void *p, struct iovec *iov, int cnt, off_t offset) +{ + int i; + off_t pos = offset; + ssize_t sz = 0, total = 0; + + for (i = 0; i < cnt; i++, iov++) { + sz = qc2_pread(p, iov->iov_base, iov->iov_len, pos); + if (sz == -1) + return (sz); + total += sz; + pos += sz; + } + + return (total); +} + static ssize_t qc2_pread(void *p, char *buf, size_t len, off_t off) { @@ -359,7 +381,25 @@ qc2_pread(void *p, char *buf, size_t len, off_t off) return len; } -ssize_t +static ssize_t +qc2_pwritev(void *p, struct iovec *iov, int cnt, off_t offset) +{ + int i; + off_t pos = offset; + ssize_t sz = 0, total = 0; + + for (i = 0; i < cnt; i++, iov++) { + sz = qc2_pwrite(p, iov->iov_base, iov->iov_len, pos); + if (sz == -1) + return (sz); + total += sz; + pos += sz; + } + + return (total); +} + +static ssize_t qc2_pwrite(void *p, char *buf, size_t len, off_t off) { struct qcdisk *disk, *d; diff --git a/usr.sbin/vmd/vioraw.c b/usr.sbin/vmd/vioraw.c index fb74303c9..83a915b2c 100644 --- a/usr.sbin/vmd/vioraw.c +++ b/usr.sbin/vmd/vioraw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vioraw.c,v 1.10 2023/05/28 05:28:50 asou Exp $ */ +/* $OpenBSD: vioraw.c,v 1.11 2023/09/14 15:25:43 dv Exp $ */ /* * Copyright (c) 2018 Ori Bernstein * @@ -31,12 +31,24 @@ raw_pread(void *file, char *buf, size_t len, off_t off) return pread(*(int *)file, buf, len, off); } +static ssize_t +raw_preadv(void *file, struct iovec *iov, int cnt, off_t offset) +{ + return preadv(*(int *)file, iov, cnt, offset); +} + static ssize_t raw_pwrite(void *file, char *buf, size_t len, off_t off) { return pwrite(*(int *)file, buf, len, off); } +static ssize_t +raw_pwritev(void *file, struct iovec *iov, int cnt, off_t offset) +{ + return pwritev(*(int *)file, iov, cnt, offset); +} + static void raw_close(void *file, int stayopen) { @@ -68,7 +80,9 @@ virtio_raw_init(struct virtio_backing *file, off_t *szp, int *fd, size_t nfd) *fdp = fd[0]; file->p = fdp; file->pread = raw_pread; + file->preadv = raw_preadv; file->pwrite = raw_pwrite; + file->pwritev = raw_pwritev; file->close = raw_close; *szp = sz; return (0); diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c index 798b5fea6..203594c56 100644 --- a/usr.sbin/vmd/virtio.c +++ b/usr.sbin/vmd/virtio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.c,v 1.106 2023/07/27 09:27:43 dv Exp $ */ +/* $OpenBSD: virtio.c,v 1.107 2023/09/14 15:25:43 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -650,8 +650,8 @@ virtio_init(struct vmd_vm *vm, int child_cdrom, + sizeof(uint16_t) * (2 + VIOBLK_QUEUE_SIZE)); dev->vioblk.vq[0].last_avail = 0; dev->vioblk.cfg.device_feature = - VIRTIO_BLK_F_SIZE_MAX; - dev->vioblk.max_xfer = 1048576; + VIRTIO_BLK_F_SEG_MAX; + dev->vioblk.seg_max = VIOBLK_SEG_MAX; /* * Initialize disk fds to an invalid fd (-1), then diff --git a/usr.sbin/vmd/virtio.h b/usr.sbin/vmd/virtio.h index 29fda474d..8c1488e98 100644 --- a/usr.sbin/vmd/virtio.h +++ b/usr.sbin/vmd/virtio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.h,v 1.47 2023/09/06 19:26:39 dv Exp $ */ +/* $OpenBSD: virtio.h,v 1.48 2023/09/14 15:25:43 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -33,12 +33,13 @@ #define ALIGNSZ(sz, align) ((sz + align - 1) & ~(align - 1)) #define MIN(a,b) (((a)<(b))?(a):(b)) -/* Queue sizes must be power of two */ +/* Queue sizes must be power of two and less than IOV_MAX (1024). */ #define VIORND_QUEUE_SIZE 64 #define VIORND_QUEUE_MASK (VIORND_QUEUE_SIZE - 1) #define VIOBLK_QUEUE_SIZE 128 #define VIOBLK_QUEUE_MASK (VIOBLK_QUEUE_SIZE - 1) +#define VIOBLK_SEG_MAX (VIOBLK_QUEUE_SIZE - 2) #define VIOSCSI_QUEUE_SIZE 128 #define VIOSCSI_QUEUE_MASK (VIOSCSI_QUEUE_SIZE - 1) @@ -69,6 +70,10 @@ * Rename the address config register to be more descriptive. */ #define VIRTIO_CONFIG_QUEUE_PFN VIRTIO_CONFIG_QUEUE_ADDRESS +#define DEVICE_NEEDS_RESET VIRTIO_CONFIG_DEVICE_STATUS_DEVICE_NEEDS_RESET +#define DESC_WRITABLE(/* struct vring_desc */ x) \ + (((x)->flags & VRING_DESC_F_WRITE) ? 1 : 0) + /* * VM <-> Device messaging. @@ -115,9 +120,11 @@ struct virtio_io_cfg { struct virtio_backing { void *p; - ssize_t (*pread)(void *p, char *buf, size_t len, off_t off); - ssize_t (*pwrite)(void *p, char *buf, size_t len, off_t off); - void (*close)(void *p, int); + ssize_t (*pread)(void *, char *, size_t, off_t); + ssize_t (*preadv)(void *, struct iovec *, int, off_t); + ssize_t (*pwrite)(void *, char *, size_t, off_t); + ssize_t (*pwritev)(void *, struct iovec *, int, off_t); + void (*close)(void *, int); }; /* @@ -212,8 +219,8 @@ struct vioblk_dev { int disk_fd[VM_MAX_BASE_PER_DISK]; /* fds for disk image(s) */ uint8_t ndisk_fd; /* number of valid disk fds */ - uint64_t sz; /* size in 512 byte sectors */ - uint32_t max_xfer; + uint64_t capacity; /* size in 512 byte sectors */ + uint32_t seg_max; /* maximum number of segments */ unsigned int idx; }; @@ -318,6 +325,7 @@ struct vmmci_dev { uint8_t pci_id; }; +/* XXX to be removed once vioscsi is adapted to vectorized io. */ struct ioinfo { uint8_t *buf; ssize_t len; @@ -354,9 +362,6 @@ int virtio_raw_init(struct virtio_backing *, off_t *, int*, size_t); int vioblk_dump(int); int vioblk_restore(int, struct vmd_vm *, int[][VM_MAX_BASE_PER_DISK]); -void vioblk_update_qs(struct vioblk_dev *); -void vioblk_update_qa(struct vioblk_dev *); -int vioblk_notifyq(struct vioblk_dev *); int vionet_dump(int); int vionet_restore(int, struct vmd_vm *, int *);