Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132900547
D20419.id58014.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D20419.id58014.diff
View Options
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_modevent(module_t, int, void *);
@@ -59,8 +64,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
@@ -68,6 +73,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),
@@ -127,7 +141,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);
@@ -138,7 +152,11 @@
goto fail;
}
- callout_reset(&sc->vtrnd_callout, 5 * hz, vtrnd_timer, sc);
+ if (g_vtrnd_softc == NULL) {
+ g_vtrnd_softc = sc;
+ atomic_thread_fence_rel();
+ random_source_register(&random_vtrnd);
+ }
fail:
if (error)
@@ -153,8 +171,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);
}
@@ -182,44 +212,68 @@
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);
+ uint32_t rdlen;
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);
- if (!virtqueue_empty(vq))
- return;
- if (virtqueue_enqueue(vq, &value, &sg, 0, 1) != 0)
- return;
+ mtx_lock(&sc->vtrnd_lock);
+ vq = sc->vtrnd_vq;
+ KASSERT(virtqueue_empty(vq), ("%s: non-empty queue", __func__));
+
+ error = virtqueue_enqueue(vq, buf, &sg, 0, 1);
+ if (error != 0) {
+ mtx_unlock(&sc->vtrnd_lock);
+ return (error);
+ }
/*
* Poll for the response, but the command is likely already
* done when we return from the notify.
*/
virtqueue_notify(vq);
- virtqueue_poll(vq, NULL);
-
- random_harvest_queue(&value, sizeof(value), RANDOM_PURE_VIRTIO);
+ virtqueue_poll(vq, &rdlen);
+ mtx_unlock(&sc->vtrnd_lock);
+
+ 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);
+ else if (rdlen == 0)
+ return (EAGAIN);
+ *sz = MIN(rdlen, *sz);
+ memcpy(buf, value, *sz);
+ explicit_bzero(value, *sz);
+ return (0);
}
-static void
-vtrnd_timer(void *xsc)
+static unsigned
+vtrnd_read(void *buf, unsigned usz)
{
struct vtrnd_softc *sc;
+ size_t sz;
+ int error;
+
+ sc = g_vtrnd_softc;
+ if (sc == NULL)
+ return (0);
- sc = xsc;
+ sz = usz;
+ 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
Details
Attached
Mime Type
text/plain
Expires
Wed, Oct 22, 12:19 AM (2 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24034195
Default Alt Text
D20419.id58014.diff (4 KB)
Attached To
Mode
D20419: virtio_random(4): Fix random(4) integration
Attached
Detach File
Event Timeline
Log In to Comment