--- 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;