rng:
- implement a request queue for rng-random so multiple guest requests don't result in vq buffers getting forgotten - remove unused request cancellation code - a VM with multiple vq buffers, when migrated, could get in a situation where not all buffers are handed back to the guest. This is now fixed. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJW2CuuAAoJEB6aO1+FQIO2RM0QAIRywJ572soT0NoA39XLNo8t avixoEsOCYy1iP8dvzw4Rh/5wdzrXUWsL3oMe99LOTSaupgYDZgA7RAUBrDNTKBV jpE6injeCdhujMAS3vQw0+vCx6nV8XQWGu/jBePxIKa+Rw17Z2QaNnTuiLu84zGo Kwlv17rqQTjI0ynNirLwWCrpCH9wGGqEZS6FIHCDOm2HamF6YqQw4ew3UBf0c2Pw tTuMtxaDh7qn6Np6OlVoD4WkaYyJQO5rg/nxyGKqp6PhpLDeAifKat9gS9jWhmAo nIj7R+qc/CHr7TJNM3BuKJCR/HvdJO4T2foThmOuHhpEI6oOJNqARfwKJgLPrNRg b+DRShhHlBtujpJ/+B9H4PEeZa8GX/9EexC6AFm7Nk8jlKqSvHFC/XnR5GuQlOq6 s6ARZrMR+mNZVrgYp5BE3az8zYcrUnqwAZFhrY2epZ6c3lPSVHK+JvMGj3t3qomX NT6s9A979wp68L1j34KnvqyeZAksV6KY6uEyjC1S05ip+BdOqEoeqUs6fCiCyqnB EBx0V1ZthD5BuQk4Rwnxic2hbOQKGe13nrqbPWL+SyQt317b0uliA3XNibMmTuai R48YIlaT9niaJB1vkXhasfQhTNjn7BCPZDrozd7sOBaZfXPNfRhqZnxi0SZvQs9k 747xXMsv4Zz0XzKYNSOY =vi66 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/amit-virtio-rng/tags/rng-for-2.6-1' into staging rng: - implement a request queue for rng-random so multiple guest requests don't result in vq buffers getting forgotten - remove unused request cancellation code - a VM with multiple vq buffers, when migrated, could get in a situation where not all buffers are handed back to the guest. This is now fixed. # gpg: Signature made Thu 03 Mar 2016 12:18:54 GMT using RSA key ID 854083B6 # gpg: Good signature from "Amit Shah <amit@amitshah.net>" # gpg: aka "Amit Shah <amit@kernel.org>" # gpg: aka "Amit Shah <amitshah@gmx.net>" * remotes/amit-virtio-rng/tags/rng-for-2.6-1: virtio-rng: ask for more data if queue is not fully drained rng: add request queue support to rng-random rng: move request queue cleanup from RngEgd to RngBackend rng: move request queue from RngEgd to RngBackend rng: remove the unused request cancellation code MAINTAINERS: Add an entry for the include/sysemu/rng*.h files Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2d3b7c0164
@ -921,6 +921,7 @@ M: Amit Shah <amit.shah@redhat.com>
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: hw/virtio/virtio-rng.c
|
F: hw/virtio/virtio-rng.c
|
||||||
F: include/hw/virtio/virtio-rng.h
|
F: include/hw/virtio/virtio-rng.h
|
||||||
|
F: include/sysemu/rng*.h
|
||||||
F: backends/rng*.c
|
F: backends/rng*.c
|
||||||
|
|
||||||
nvme
|
nvme
|
||||||
|
@ -25,33 +25,12 @@ typedef struct RngEgd
|
|||||||
|
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
char *chr_name;
|
char *chr_name;
|
||||||
|
|
||||||
GSList *requests;
|
|
||||||
} RngEgd;
|
} RngEgd;
|
||||||
|
|
||||||
typedef struct RngRequest
|
static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
|
||||||
{
|
|
||||||
EntropyReceiveFunc *receive_entropy;
|
|
||||||
uint8_t *data;
|
|
||||||
void *opaque;
|
|
||||||
size_t offset;
|
|
||||||
size_t size;
|
|
||||||
} RngRequest;
|
|
||||||
|
|
||||||
static void rng_egd_request_entropy(RngBackend *b, size_t size,
|
|
||||||
EntropyReceiveFunc *receive_entropy,
|
|
||||||
void *opaque)
|
|
||||||
{
|
{
|
||||||
RngEgd *s = RNG_EGD(b);
|
RngEgd *s = RNG_EGD(b);
|
||||||
RngRequest *req;
|
size_t size = req->size;
|
||||||
|
|
||||||
req = g_malloc(sizeof(*req));
|
|
||||||
|
|
||||||
req->offset = 0;
|
|
||||||
req->size = size;
|
|
||||||
req->receive_entropy = receive_entropy;
|
|
||||||
req->opaque = opaque;
|
|
||||||
req->data = g_malloc(req->size);
|
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
uint8_t header[2];
|
uint8_t header[2];
|
||||||
@ -65,14 +44,6 @@ static void rng_egd_request_entropy(RngBackend *b, size_t size,
|
|||||||
|
|
||||||
size -= len;
|
size -= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->requests = g_slist_append(s->requests, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rng_egd_free_request(RngRequest *req)
|
|
||||||
{
|
|
||||||
g_free(req->data);
|
|
||||||
g_free(req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rng_egd_chr_can_read(void *opaque)
|
static int rng_egd_chr_can_read(void *opaque)
|
||||||
@ -81,7 +52,7 @@ static int rng_egd_chr_can_read(void *opaque)
|
|||||||
GSList *i;
|
GSList *i;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
||||||
for (i = s->requests; i; i = i->next) {
|
for (i = s->parent.requests; i; i = i->next) {
|
||||||
RngRequest *req = i->data;
|
RngRequest *req = i->data;
|
||||||
size += req->size - req->offset;
|
size += req->size - req->offset;
|
||||||
}
|
}
|
||||||
@ -94,8 +65,8 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
|
|||||||
RngEgd *s = RNG_EGD(opaque);
|
RngEgd *s = RNG_EGD(opaque);
|
||||||
size_t buf_offset = 0;
|
size_t buf_offset = 0;
|
||||||
|
|
||||||
while (size > 0 && s->requests) {
|
while (size > 0 && s->parent.requests) {
|
||||||
RngRequest *req = s->requests->data;
|
RngRequest *req = s->parent.requests->data;
|
||||||
int len = MIN(size, req->size - req->offset);
|
int len = MIN(size, req->size - req->offset);
|
||||||
|
|
||||||
memcpy(req->data + req->offset, buf + buf_offset, len);
|
memcpy(req->data + req->offset, buf + buf_offset, len);
|
||||||
@ -104,38 +75,13 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
|
|||||||
size -= len;
|
size -= len;
|
||||||
|
|
||||||
if (req->offset == req->size) {
|
if (req->offset == req->size) {
|
||||||
s->requests = g_slist_remove_link(s->requests, s->requests);
|
|
||||||
|
|
||||||
req->receive_entropy(req->opaque, req->data, req->size);
|
req->receive_entropy(req->opaque, req->data, req->size);
|
||||||
|
|
||||||
rng_egd_free_request(req);
|
rng_backend_finalize_request(&s->parent, req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rng_egd_free_requests(RngEgd *s)
|
|
||||||
{
|
|
||||||
GSList *i;
|
|
||||||
|
|
||||||
for (i = s->requests; i; i = i->next) {
|
|
||||||
rng_egd_free_request(i->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_slist_free(s->requests);
|
|
||||||
s->requests = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rng_egd_cancel_requests(RngBackend *b)
|
|
||||||
{
|
|
||||||
RngEgd *s = RNG_EGD(b);
|
|
||||||
|
|
||||||
/* We simply delete the list of pending requests. If there is data in the
|
|
||||||
* queue waiting to be read, this is okay, because there will always be
|
|
||||||
* more data than we requested originally
|
|
||||||
*/
|
|
||||||
rng_egd_free_requests(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rng_egd_opened(RngBackend *b, Error **errp)
|
static void rng_egd_opened(RngBackend *b, Error **errp)
|
||||||
{
|
{
|
||||||
RngEgd *s = RNG_EGD(b);
|
RngEgd *s = RNG_EGD(b);
|
||||||
@ -204,8 +150,6 @@ static void rng_egd_finalize(Object *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_free(s->chr_name);
|
g_free(s->chr_name);
|
||||||
|
|
||||||
rng_egd_free_requests(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rng_egd_class_init(ObjectClass *klass, void *data)
|
static void rng_egd_class_init(ObjectClass *klass, void *data)
|
||||||
@ -213,7 +157,6 @@ static void rng_egd_class_init(ObjectClass *klass, void *data)
|
|||||||
RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
|
RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
|
||||||
|
|
||||||
rbc->request_entropy = rng_egd_request_entropy;
|
rbc->request_entropy = rng_egd_request_entropy;
|
||||||
rbc->cancel_requests = rng_egd_cancel_requests;
|
|
||||||
rbc->opened = rng_egd_opened;
|
rbc->opened = rng_egd_opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,6 @@ struct RndRandom
|
|||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
||||||
EntropyReceiveFunc *receive_func;
|
|
||||||
void *opaque;
|
|
||||||
size_t size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,36 +34,35 @@ struct RndRandom
|
|||||||
static void entropy_available(void *opaque)
|
static void entropy_available(void *opaque)
|
||||||
{
|
{
|
||||||
RndRandom *s = RNG_RANDOM(opaque);
|
RndRandom *s = RNG_RANDOM(opaque);
|
||||||
uint8_t buffer[s->size];
|
|
||||||
ssize_t len;
|
|
||||||
|
|
||||||
len = read(s->fd, buffer, s->size);
|
while (s->parent.requests != NULL) {
|
||||||
if (len < 0 && errno == EAGAIN) {
|
RngRequest *req = s->parent.requests->data;
|
||||||
return;
|
ssize_t len;
|
||||||
|
|
||||||
|
len = read(s->fd, req->data, req->size);
|
||||||
|
if (len < 0 && errno == EAGAIN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_assert(len != -1);
|
||||||
|
|
||||||
|
req->receive_entropy(req->opaque, req->data, len);
|
||||||
|
|
||||||
|
rng_backend_finalize_request(&s->parent, req);
|
||||||
}
|
}
|
||||||
g_assert(len != -1);
|
|
||||||
|
|
||||||
s->receive_func(s->opaque, buffer, len);
|
|
||||||
s->receive_func = NULL;
|
|
||||||
|
|
||||||
|
/* We've drained all requests, the fd handler can be reset. */
|
||||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rng_random_request_entropy(RngBackend *b, size_t size,
|
static void rng_random_request_entropy(RngBackend *b, RngRequest *req)
|
||||||
EntropyReceiveFunc *receive_entropy,
|
|
||||||
void *opaque)
|
|
||||||
{
|
{
|
||||||
RndRandom *s = RNG_RANDOM(b);
|
RndRandom *s = RNG_RANDOM(b);
|
||||||
|
|
||||||
if (s->receive_func) {
|
if (s->parent.requests == NULL) {
|
||||||
s->receive_func(s->opaque, NULL, 0);
|
/* If there are no pending requests yet, we need to
|
||||||
|
* install our fd handler. */
|
||||||
|
qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->receive_func = receive_entropy;
|
|
||||||
s->opaque = opaque;
|
|
||||||
s->size = size;
|
|
||||||
|
|
||||||
qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rng_random_opened(RngBackend *b, Error **errp)
|
static void rng_random_opened(RngBackend *b, Error **errp)
|
||||||
|
@ -20,18 +20,20 @@ void rng_backend_request_entropy(RngBackend *s, size_t size,
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
|
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
|
||||||
|
RngRequest *req;
|
||||||
|
|
||||||
if (k->request_entropy) {
|
if (k->request_entropy) {
|
||||||
k->request_entropy(s, size, receive_entropy, opaque);
|
req = g_malloc(sizeof(*req));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rng_backend_cancel_requests(RngBackend *s)
|
req->offset = 0;
|
||||||
{
|
req->size = size;
|
||||||
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
|
req->receive_entropy = receive_entropy;
|
||||||
|
req->opaque = opaque;
|
||||||
|
req->data = g_malloc(req->size);
|
||||||
|
|
||||||
if (k->cancel_requests) {
|
k->request_entropy(s, req);
|
||||||
k->cancel_requests(s);
|
|
||||||
|
s->requests = g_slist_append(s->requests, req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +75,30 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
|||||||
s->opened = true;
|
s->opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rng_backend_free_request(RngRequest *req)
|
||||||
|
{
|
||||||
|
g_free(req->data);
|
||||||
|
g_free(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rng_backend_free_requests(RngBackend *s)
|
||||||
|
{
|
||||||
|
GSList *i;
|
||||||
|
|
||||||
|
for (i = s->requests; i; i = i->next) {
|
||||||
|
rng_backend_free_request(i->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free(s->requests);
|
||||||
|
s->requests = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rng_backend_finalize_request(RngBackend *s, RngRequest *req)
|
||||||
|
{
|
||||||
|
s->requests = g_slist_remove(s->requests, req);
|
||||||
|
rng_backend_free_request(req);
|
||||||
|
}
|
||||||
|
|
||||||
static void rng_backend_init(Object *obj)
|
static void rng_backend_init(Object *obj)
|
||||||
{
|
{
|
||||||
object_property_add_bool(obj, "opened",
|
object_property_add_bool(obj, "opened",
|
||||||
@ -81,6 +107,13 @@ static void rng_backend_init(Object *obj)
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rng_backend_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
RngBackend *s = RNG_BACKEND(obj);
|
||||||
|
|
||||||
|
rng_backend_free_requests(s);
|
||||||
|
}
|
||||||
|
|
||||||
static void rng_backend_class_init(ObjectClass *oc, void *data)
|
static void rng_backend_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||||
@ -93,6 +126,7 @@ static const TypeInfo rng_backend_info = {
|
|||||||
.parent = TYPE_OBJECT,
|
.parent = TYPE_OBJECT,
|
||||||
.instance_size = sizeof(RngBackend),
|
.instance_size = sizeof(RngBackend),
|
||||||
.instance_init = rng_backend_init,
|
.instance_init = rng_backend_init,
|
||||||
|
.instance_finalize = rng_backend_finalize,
|
||||||
.class_size = sizeof(RngBackendClass),
|
.class_size = sizeof(RngBackendClass),
|
||||||
.class_init = rng_backend_class_init,
|
.class_init = rng_backend_class_init,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
|
@ -69,6 +69,13 @@ static void chr_read(void *opaque, const void *buf, size_t size)
|
|||||||
g_free(elem);
|
g_free(elem);
|
||||||
}
|
}
|
||||||
virtio_notify(vdev, vrng->vq);
|
virtio_notify(vdev, vrng->vq);
|
||||||
|
|
||||||
|
if (!virtio_queue_empty(vrng->vq)) {
|
||||||
|
/* If we didn't drain the queue, call virtio_rng_process
|
||||||
|
* to take care of asking for more data as appropriate.
|
||||||
|
*/
|
||||||
|
virtio_rng_process(vrng);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_rng_process(VirtIORNG *vrng)
|
static void virtio_rng_process(VirtIORNG *vrng)
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#define RNG_BACKEND_CLASS(klass) \
|
#define RNG_BACKEND_CLASS(klass) \
|
||||||
OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND)
|
OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND)
|
||||||
|
|
||||||
|
typedef struct RngRequest RngRequest;
|
||||||
typedef struct RngBackendClass RngBackendClass;
|
typedef struct RngBackendClass RngBackendClass;
|
||||||
typedef struct RngBackend RngBackend;
|
typedef struct RngBackend RngBackend;
|
||||||
|
|
||||||
@ -31,13 +32,20 @@ typedef void (EntropyReceiveFunc)(void *opaque,
|
|||||||
const void *data,
|
const void *data,
|
||||||
size_t size);
|
size_t size);
|
||||||
|
|
||||||
|
struct RngRequest
|
||||||
|
{
|
||||||
|
EntropyReceiveFunc *receive_entropy;
|
||||||
|
uint8_t *data;
|
||||||
|
void *opaque;
|
||||||
|
size_t offset;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
struct RngBackendClass
|
struct RngBackendClass
|
||||||
{
|
{
|
||||||
ObjectClass parent_class;
|
ObjectClass parent_class;
|
||||||
|
|
||||||
void (*request_entropy)(RngBackend *s, size_t size,
|
void (*request_entropy)(RngBackend *s, RngRequest *req);
|
||||||
EntropyReceiveFunc *receive_entropy, void *opaque);
|
|
||||||
void (*cancel_requests)(RngBackend *s);
|
|
||||||
|
|
||||||
void (*opened)(RngBackend *s, Error **errp);
|
void (*opened)(RngBackend *s, Error **errp);
|
||||||
};
|
};
|
||||||
@ -48,8 +56,10 @@ struct RngBackend
|
|||||||
|
|
||||||
/*< protected >*/
|
/*< protected >*/
|
||||||
bool opened;
|
bool opened;
|
||||||
|
GSList *requests;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rng_backend_request_entropy:
|
* rng_backend_request_entropy:
|
||||||
* @s: the backend to request entropy from
|
* @s: the backend to request entropy from
|
||||||
@ -70,12 +80,13 @@ void rng_backend_request_entropy(RngBackend *s, size_t size,
|
|||||||
void *opaque);
|
void *opaque);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rng_backend_cancel_requests:
|
* rng_backend_free_request:
|
||||||
* @s: the backend to cancel all pending requests in
|
* @s: the backend that created the request
|
||||||
|
* @req: the request to finalize
|
||||||
*
|
*
|
||||||
* Cancels all pending requests submitted by @rng_backend_request_entropy. This
|
* Used by child rng backend classes to finalize requests once they've been
|
||||||
* should be used by a device during reset or in preparation for live migration
|
* processed. The request is removed from the list of active requests and
|
||||||
* to stop tracking any request.
|
* deleted.
|
||||||
*/
|
*/
|
||||||
void rng_backend_cancel_requests(RngBackend *s);
|
void rng_backend_finalize_request(RngBackend *s, RngRequest *req);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user