--- head/usr.sbin/bhyve/virtio.c 2019/05/18 17:30:03 347959
+++ head/usr.sbin/bhyve/virtio.c 2019/05/18 19:32:38 347960
@@ -3,6 +3,7 @@
*
* Copyright (c) 2013 Chris Torek <torek @ torek net>
* 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
@@ -32,6 +33,8 @@
#include <sys/param.h>
#include <sys/uio.h>
+#include <machine/atomic.h>
+
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
@@ -422,6 +425,12 @@
vue = &vuh->vu_ring[uidx++ & mask];
vue->vu_idx = idx;
vue->vu_tlen = iolen;
+
+ /*
+ * Ensure the used descriptor is visible before updating the index.
+ * This is necessary on ISAs with memory ordering less strict than x86.
+ */
+ atomic_thread_fence_rel();
vuh->vu_idx = uidx;
}
@@ -459,6 +468,13 @@
vs = vq->vq_vs;
old_idx = vq->vq_save_used;
vq->vq_save_used = new_idx = vq->vq_used->vu_idx;
+
+ /*
+ * Use full memory barrier between vu_idx store from preceding
+ * vq_relchain() call and the loads from VQ_USED_EVENT_IDX() or
+ * va_flags below.
+ */
+ atomic_thread_fence_seq_cst();
if (used_all_avail &&
(vs->vs_negotiated_caps & VIRTIO_F_NOTIFY_ON_EMPTY))
intr = 1;
--- head/usr.sbin/bhyve/block_if.c 2019/05/02 19:59:37 347032
+++ head/usr.sbin/bhyve/block_if.c 2019/05/02 22:46:37 347033
@@ -65,7 +65,7 @@
#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,
--- head/usr.sbin/bhyve/block_if.h 2019/05/02 19:59:37 347032
+++ head/usr.sbin/bhyve/block_if.h 2019/05/02 22:46:37 347033
@@ -41,7 +41,13 @@
#include <sys/uio.h>
#include <sys/unistd.h>
-#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 {
int br_iovcnt;
--- head/usr.sbin/bhyve/pci_virtio_block.c 2019/05/02 19:59:37 347032
+++ head/usr.sbin/bhyve/pci_virtio_block.c 2019/05/02 22:46:37 347033
@@ -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 @@
#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 @@
/* 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;