From e92d7e7e2db67b607e3aedde21cf1e738ee2ec70 Mon Sep 17 00:00:00 2001 From: jhb Date: Wed, 29 May 2019 23:11:07 +0000 Subject: [PATCH] MFC 347033: Increase the VirtIO segment count to support modern Windows guests. The Windows virtio driver ignores the advertized seg_max field and assumes the host can accept up to 67 segments in indirect descriptors, triggering an assert in the bhyve process. This brings back r282922 but with a couple of changes: - It raises the block interface segment limit to 128 instead of 67. - Linux's virtio driver assumes that the segment limit is no larger than the ring size. To avoid breaking Linux guests, raise the VirtIO ring size to 128, and cap the VirtIO segment limit at ring size - 2 (effectively 126). Approved by: re (gjb) --- usr.sbin/bhyve/block_if.c | 2 +- usr.sbin/bhyve/block_if.h | 8 +++++++- usr.sbin/bhyve/pci_virtio_block.c | 15 +++++++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c index 09b5fcba40f..6b8a9e5224f 100644 --- a/usr.sbin/bhyve/block_if.c +++ b/usr.sbin/bhyve/block_if.c @@ -62,7 +62,7 @@ __FBSDID("$FreeBSD$"); #define BLOCKIF_SIG 0xb109b109 #define BLOCKIF_NUMTHR 8 -#define BLOCKIF_MAXREQ (64 + BLOCKIF_NUMTHR) +#define BLOCKIF_MAXREQ (BLOCKIF_RING_MAX + BLOCKIF_NUMTHR) enum blockop { BOP_READ, diff --git a/usr.sbin/bhyve/block_if.h b/usr.sbin/bhyve/block_if.h index ee064922d1a..00c92c84adb 100644 --- a/usr.sbin/bhyve/block_if.h +++ b/usr.sbin/bhyve/block_if.h @@ -41,7 +41,13 @@ #include #include -#define BLOCKIF_IOV_MAX 33 /* not practical to be IOV_MAX */ +/* + * BLOCKIF_IOV_MAX is the maximum number of scatter/gather entries in + * a single request. BLOCKIF_RING_MAX is the maxmimum number of + * pending requests that can be queued. + */ +#define BLOCKIF_IOV_MAX 128 /* not practical to be IOV_MAX */ +#define BLOCKIF_RING_MAX 128 struct blockif_req { struct iovec br_iov[BLOCKIF_IOV_MAX]; diff --git a/usr.sbin/bhyve/pci_virtio_block.c b/usr.sbin/bhyve/pci_virtio_block.c index bfa65b49cf6..c4a4b5aa630 100644 --- a/usr.sbin/bhyve/pci_virtio_block.c +++ b/usr.sbin/bhyve/pci_virtio_block.c @@ -3,6 +3,7 @@ * * Copyright (c) 2011 NetApp, Inc. * All rights reserved. + * Copyright (c) 2019 Joyent, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,7 +56,9 @@ __FBSDID("$FreeBSD$"); #include "virtio.h" #include "block_if.h" -#define VTBLK_RINGSZ 64 +#define VTBLK_RINGSZ 128 + +_Static_assert(VTBLK_RINGSZ <= BLOCKIF_RING_MAX, "Each ring entry must be able to queue a request"); #define VTBLK_S_OK 0 #define VTBLK_S_IOERR 1 @@ -351,7 +354,15 @@ pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) /* setup virtio block config space */ sc->vbsc_cfg.vbc_capacity = size / DEV_BSIZE; /* 512-byte units */ sc->vbsc_cfg.vbc_size_max = 0; /* not negotiated */ - sc->vbsc_cfg.vbc_seg_max = BLOCKIF_IOV_MAX; + + /* + * If Linux is presented with a seg_max greater than the virtio queue + * size, it can stumble into situations where it violates its own + * invariants and panics. For safety, we keep seg_max clamped, paying + * heed to the two extra descriptors needed for the header and status + * of a request. + */ + sc->vbsc_cfg.vbc_seg_max = MIN(VTBLK_RINGSZ - 2, BLOCKIF_IOV_MAX); sc->vbsc_cfg.vbc_geometry.cylinders = 0; /* no geometry */ sc->vbsc_cfg.vbc_geometry.heads = 0; sc->vbsc_cfg.vbc_geometry.sectors = 0; -- 2.45.0