Page MenuHomeFreeBSD

D20419.id57929.diff
No OneTemporary

D20419.id57929.diff

Index: sys/dev/virtio/random/virtio_random.c
===================================================================
--- sys/dev/virtio/random/virtio_random.c
+++ sys/dev/virtio/random/virtio_random.c
@@ -33,7 +33,10 @@
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/sglist.h>
#include <sys/callout.h>
#include <sys/random.h>
@@ -42,13 +45,15 @@
#include <machine/resource.h>
#include <sys/bus.h>
+#include <dev/random/randomdev.h>
+#include <dev/random/random_harvestq.h>
#include <dev/virtio/virtio.h>
#include <dev/virtio/virtqueue.h>
struct vtrnd_softc {
uint64_t vtrnd_features;
- struct callout vtrnd_callout;
struct virtqueue *vtrnd_vq;
+ struct mtx vtrnd_lock;
};
static int vtrnd_probe(device_t);
@@ -57,8 +62,8 @@
static void vtrnd_negotiate_features(device_t);
static int vtrnd_alloc_virtqueue(device_t);
-static void vtrnd_harvest(struct vtrnd_softc *);
-static void vtrnd_timer(void *);
+static int vtrnd_harvest(struct vtrnd_softc *, void *, size_t);
+static unsigned vtrnd_read(void *, unsigned);
#define VTRND_FEATURES 0
@@ -66,6 +71,15 @@
{ 0, NULL }
};
+static struct random_source random_vtrnd = {
+ .rs_ident = "VirtIO Entropy Adapter",
+ .rs_source = RANDOM_PURE_VIRTIO,
+ .rs_read = vtrnd_read,
+};
+
+/* Kludge for API limitations of random(4). */
+static struct vtrnd_softc *g_vtrnd_softc = NULL;
+
static device_method_t vtrnd_methods[] = {
/* Device methods. */
DEVMETHOD(device_probe, vtrnd_probe),
@@ -105,7 +119,7 @@
sc = device_get_softc(dev);
- callout_init(&sc->vtrnd_callout, 1);
+ mtx_init(&sc->vtrnd_lock, "vtrnd lock", NULL, MTX_DEF);
virtio_set_feature_desc(dev, vtrnd_feature_desc);
vtrnd_negotiate_features(dev);
@@ -116,7 +130,11 @@
goto fail;
}
- callout_reset(&sc->vtrnd_callout, 5 * hz, vtrnd_timer, sc);
+ if (g_vtrnd_softc == NULL) {
+ g_vtrnd_softc = sc;
+ wmb();
+ random_source_register(&random_vtrnd);
+ }
fail:
if (error)
@@ -131,8 +149,20 @@
struct vtrnd_softc *sc;
sc = device_get_softc(dev);
-
- callout_drain(&sc->vtrnd_callout);
+ mtx_lock(&sc->vtrnd_lock);
+ if (g_vtrnd_softc == sc) {
+ random_source_deregister(&random_vtrnd);
+ g_vtrnd_softc = NULL;
+ /*
+ * Unfortunately, deregister does not guarantee our source
+ * callback will not be invoked after it returns. Use a kludge
+ * to prevent some, but not all, possible races.
+ */
+ msleep_sbt(&g_vtrnd_softc, &sc->vtrnd_lock, 0, "vtrnddet",
+ mstosbt(50), 0, C_HARDCLOCK);
+ }
+ mtx_unlock(&sc->vtrnd_lock);
+ mtx_destroy(&sc->vtrnd_lock);
return (0);
}
@@ -160,26 +190,29 @@
return (virtio_alloc_virtqueues(dev, 0, 1, &vq_info));
}
-static void
-vtrnd_harvest(struct vtrnd_softc *sc)
+static int
+vtrnd_harvest(struct vtrnd_softc *sc, void *buf, size_t sz)
{
struct sglist_seg segs[1];
struct sglist sg;
struct virtqueue *vq;
- uint32_t value;
+ uint32_t value[HARVESTSIZE] __aligned(sizeof(uint32_t) * HARVESTSIZE);
int error;
- vq = sc->vtrnd_vq;
+ _Static_assert(sizeof(value) < PAGE_SIZE, "sglist assumption");
sglist_init(&sg, 1, segs);
- error = sglist_append(&sg, &value, sizeof(value));
- KASSERT(error == 0 && sg.sg_nseg == 1,
- ("%s: error %d adding buffer to sglist", __func__, error));
+ error = sglist_append(&sg, value, sz);
+ if (error != 0)
+ panic("%s: sglist_append error=%d", __func__, error);
+
+ mtx_lock(&sc->vtrnd_lock);
+ vq = sc->vtrnd_vq;
+ KASSERT(virtqueue_empty(vq), ("%s: non-empty queue", __func__));
- if (!virtqueue_empty(vq))
- return;
- if (virtqueue_enqueue(vq, &value, &sg, 0, 1) != 0)
- return;
+ error = virtqueue_enqueue(vq, buf, &sg, 0, 1);
+ if (error != 0)
+ return (error);
/*
* Poll for the response, but the command is likely already
@@ -187,17 +220,26 @@
*/
virtqueue_notify(vq);
virtqueue_poll(vq, NULL);
+ mtx_unlock(&sc->vtrnd_lock);
- random_harvest_queue(&value, sizeof(value), RANDOM_PURE_VIRTIO);
+ memcpy(buf, value, sz);
+ explicit_bzero(value, sz);
+ return (0);
}
-static void
-vtrnd_timer(void *xsc)
+static unsigned
+vtrnd_read(void *buf, unsigned sz)
{
struct vtrnd_softc *sc;
+ int error;
+
+ sc = g_vtrnd_softc;
+ if (sc == NULL)
+ return (0);
- sc = xsc;
+ error = vtrnd_harvest(sc, buf, sz);
+ if (error != 0)
+ return (0);
- vtrnd_harvest(sc);
- callout_schedule(&sc->vtrnd_callout, 5 * hz);
+ return (sz);
}

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 22, 9:50 PM (5 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27864399
Default Alt Text
D20419.id57929.diff (4 KB)

Event Timeline