Page MenuHomeFreeBSD

D32014.id95336.diff
No OneTemporary

D32014.id95336.diff

Index: sys/dev/virtio/random/virtio_random.c
===================================================================
--- sys/dev/virtio/random/virtio_random.c
+++ sys/dev/virtio/random/virtio_random.c
@@ -48,8 +48,15 @@
#include <dev/virtio/virtio.h>
#include <dev/virtio/virtqueue.h>
+struct vtrnd_harvest_buf {
+ uint32_t value[HARVESTSIZE] __aligned(sizeof(uint32_t) * HARVESTSIZE);
+ struct sglist_seg segs[1];
+ struct sglist sg;
+};
+
struct vtrnd_softc {
device_t vtrnd_dev;
+ struct vtrnd_harvest_buf vtrnd_harvest_buf;
uint64_t vtrnd_features;
struct virtqueue *vtrnd_vq;
};
@@ -136,10 +143,12 @@
vtrnd_attach(device_t dev)
{
struct vtrnd_softc *sc, *exp;
+ struct vtrnd_harvest_buf *buf;
int error;
sc = device_get_softc(dev);
sc->vtrnd_dev = dev;
+ buf = &sc->vtrnd_harvest_buf;
virtio_set_feature_desc(dev, vtrnd_feature_desc);
error = vtrnd_setup_features(sc);
@@ -160,6 +169,14 @@
error = EEXIST;
goto fail;
}
+
+ _Static_assert(sizeof(buf->value) < PAGE_SIZE, "sglist assumption");
+
+ sglist_init(&buf->sg, 1, buf->segs);
+ error = sglist_append(&buf->sg, buf->value, sizeof(buf->value));
+ if (error != 0)
+ panic("%s: sglist_append error=%d", __func__, error);
+
random_source_register(&random_vtrnd);
fail:
@@ -223,28 +240,36 @@
return (virtio_alloc_virtqueues(dev, 0, 1, &vq_info));
}
+#define VTRND_HARVEST_MAXWAIT (SBT_1MS * 2)
+
static int
vtrnd_harvest(struct vtrnd_softc *sc, void *buf, size_t *sz)
{
- struct sglist_seg segs[1];
- struct sglist sg;
+ struct vtrnd_harvest_buf *hbuf;
struct virtqueue *vq;
void *cookie;
- uint32_t value[HARVESTSIZE] __aligned(sizeof(uint32_t) * HARVESTSIZE);
uint32_t rdlen;
int error;
- _Static_assert(sizeof(value) < PAGE_SIZE, "sglist assumption");
-
- sglist_init(&sg, 1, segs);
- error = sglist_append(&sg, value, *sz);
- if (error != 0)
- panic("%s: sglist_append error=%d", __func__, error);
-
vq = sc->vtrnd_vq;
- KASSERT(virtqueue_empty(vq), ("%s: non-empty queue", __func__));
+ hbuf = &sc->vtrnd_harvest_buf;
- error = virtqueue_enqueue(vq, buf, &sg, 0, 1);
+ /*
+ * The host provider may have ratelimited us, causing the last poll
+ * attempt to fail. Discard the result and try again. Perhaps we could
+ * have used it, but it's safer to discard it after it's been sitting in
+ * memory for so long in the same allocation as the softc. The odds of
+ * it having been observed seem too high to risk it.
+ */
+ if (!virtqueue_empty(vq)) {
+ cookie = virtqueue_poll_timeout(vq, NULL,
+ VTRND_HARVEST_MAXWAIT);
+ /* We could still be blocked. */
+ if (cookie == NULL)
+ return (EAGAIN);
+ }
+
+ error = virtqueue_enqueue(vq, hbuf, &hbuf->sg, 0, 1);
if (error != 0)
return (error);
@@ -253,19 +278,23 @@
* done when we return from the notify.
*/
virtqueue_notify(vq);
- cookie = virtqueue_poll(vq, &rdlen);
+ cookie = virtqueue_poll_timeout(vq, &rdlen, VTRND_HARVEST_MAXWAIT);
/* Almost trivially true, but could indicate something bad. */
- KASSERT(cookie == buf, ("inconsistent virtqueue state"));
+ KASSERT(cookie == NULL || cookie == hbuf,
+ ("inconsistent virtqueue state"));
+
+ if (cookie == NULL)
+ return (EAGAIN);
if (rdlen > *sz)
panic("%s: random device wrote %zu bytes beyond end of provided"
" buffer %p:%zu", __func__, (size_t)rdlen - *sz,
- (void *)value, *sz);
+ (void *)hbuf->value, *sz);
else if (rdlen == 0)
return (EAGAIN);
*sz = MIN(rdlen, *sz);
- memcpy(buf, value, *sz);
- explicit_bzero(value, *sz);
+ memcpy(buf, hbuf->value, *sz);
+ explicit_bzero(hbuf->value, *sz);
return (0);
}

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 26, 1:28 PM (3 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28033164
Default Alt Text
D32014.id95336.diff (3 KB)

Event Timeline