Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/amit-virtio-rng/tags/rng-for-2.…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
pm215 committed Mar 3, 2016
2 parents ed6128e + f8693c2 commit 2d3b7c0
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 104 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Expand Up @@ -921,6 +921,7 @@ M: Amit Shah <amit.shah@redhat.com>
S: Supported
F: hw/virtio/virtio-rng.c
F: include/hw/virtio/virtio-rng.h
F: include/sysemu/rng*.h
F: backends/rng*.c

nvme
Expand Down
69 changes: 6 additions & 63 deletions backends/rng-egd.c
Expand Up @@ -25,33 +25,12 @@ typedef struct RngEgd

CharDriverState *chr;
char *chr_name;

GSList *requests;
} RngEgd;

typedef struct RngRequest
{
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)
static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
{
RngEgd *s = RNG_EGD(b);
RngRequest *req;

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);
size_t size = req->size;

while (size > 0) {
uint8_t header[2];
Expand All @@ -65,14 +44,6 @@ static void rng_egd_request_entropy(RngBackend *b, size_t size,

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)
Expand All @@ -81,7 +52,7 @@ static int rng_egd_chr_can_read(void *opaque)
GSList *i;
int size = 0;

for (i = s->requests; i; i = i->next) {
for (i = s->parent.requests; i; i = i->next) {
RngRequest *req = i->data;
size += req->size - req->offset;
}
Expand All @@ -94,8 +65,8 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
RngEgd *s = RNG_EGD(opaque);
size_t buf_offset = 0;

while (size > 0 && s->requests) {
RngRequest *req = s->requests->data;
while (size > 0 && s->parent.requests) {
RngRequest *req = s->parent.requests->data;
int len = MIN(size, req->size - req->offset);

memcpy(req->data + req->offset, buf + buf_offset, len);
Expand All @@ -104,38 +75,13 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
size -= len;

if (req->offset == req->size) {
s->requests = g_slist_remove_link(s->requests, s->requests);

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)
{
RngEgd *s = RNG_EGD(b);
Expand Down Expand Up @@ -204,16 +150,13 @@ static void rng_egd_finalize(Object *obj)
}

g_free(s->chr_name);

rng_egd_free_requests(s);
}

static void rng_egd_class_init(ObjectClass *klass, void *data)
{
RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);

rbc->request_entropy = rng_egd_request_entropy;
rbc->cancel_requests = rng_egd_cancel_requests;
rbc->opened = rng_egd_opened;
}

Expand Down
43 changes: 19 additions & 24 deletions backends/rng-random.c
Expand Up @@ -22,10 +22,6 @@ struct RndRandom

int fd;
char *filename;

EntropyReceiveFunc *receive_func;
void *opaque;
size_t size;
};

/**
Expand All @@ -38,36 +34,35 @@ struct RndRandom
static void entropy_available(void *opaque)
{
RndRandom *s = RNG_RANDOM(opaque);
uint8_t buffer[s->size];
ssize_t len;

len = read(s->fd, buffer, s->size);
if (len < 0 && errno == EAGAIN) {
return;
}
g_assert(len != -1);
while (s->parent.requests != NULL) {
RngRequest *req = s->parent.requests->data;
ssize_t len;

len = read(s->fd, req->data, req->size);
if (len < 0 && errno == EAGAIN) {
return;
}
g_assert(len != -1);

s->receive_func(s->opaque, buffer, len);
s->receive_func = NULL;
req->receive_entropy(req->opaque, req->data, len);

rng_backend_finalize_request(&s->parent, req);
}

/* We've drained all requests, the fd handler can be reset. */
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
}

static void rng_random_request_entropy(RngBackend *b, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
static void rng_random_request_entropy(RngBackend *b, RngRequest *req)
{
RndRandom *s = RNG_RANDOM(b);

if (s->receive_func) {
s->receive_func(s->opaque, NULL, 0);
if (s->parent.requests == NULL) {
/* 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)
Expand Down
50 changes: 42 additions & 8 deletions backends/rng.c
Expand Up @@ -20,18 +20,20 @@ void rng_backend_request_entropy(RngBackend *s, size_t size,
void *opaque)
{
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
RngRequest *req;

if (k->request_entropy) {
k->request_entropy(s, size, receive_entropy, opaque);
}
}
req = g_malloc(sizeof(*req));

void rng_backend_cancel_requests(RngBackend *s)
{
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
req->offset = 0;
req->size = size;
req->receive_entropy = receive_entropy;
req->opaque = opaque;
req->data = g_malloc(req->size);

k->request_entropy(s, req);

if (k->cancel_requests) {
k->cancel_requests(s);
s->requests = g_slist_append(s->requests, req);
}
}

Expand Down Expand Up @@ -73,6 +75,30 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
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)
{
object_property_add_bool(obj, "opened",
Expand All @@ -81,6 +107,13 @@ static void rng_backend_init(Object *obj)
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)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
Expand All @@ -93,6 +126,7 @@ static const TypeInfo rng_backend_info = {
.parent = TYPE_OBJECT,
.instance_size = sizeof(RngBackend),
.instance_init = rng_backend_init,
.instance_finalize = rng_backend_finalize,
.class_size = sizeof(RngBackendClass),
.class_init = rng_backend_class_init,
.abstract = true,
Expand Down
7 changes: 7 additions & 0 deletions hw/virtio/virtio-rng.c
Expand Up @@ -69,6 +69,13 @@ static void chr_read(void *opaque, const void *buf, size_t size)
g_free(elem);
}
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)
Expand Down
29 changes: 20 additions & 9 deletions include/sysemu/rng.h
Expand Up @@ -24,20 +24,28 @@
#define RNG_BACKEND_CLASS(klass) \
OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND)

typedef struct RngRequest RngRequest;
typedef struct RngBackendClass RngBackendClass;
typedef struct RngBackend RngBackend;

typedef void (EntropyReceiveFunc)(void *opaque,
const void *data,
size_t size);

struct RngRequest
{
EntropyReceiveFunc *receive_entropy;
uint8_t *data;
void *opaque;
size_t offset;
size_t size;
};

struct RngBackendClass
{
ObjectClass parent_class;

void (*request_entropy)(RngBackend *s, size_t size,
EntropyReceiveFunc *receive_entropy, void *opaque);
void (*cancel_requests)(RngBackend *s);
void (*request_entropy)(RngBackend *s, RngRequest *req);

void (*opened)(RngBackend *s, Error **errp);
};
Expand All @@ -48,8 +56,10 @@ struct RngBackend

/*< protected >*/
bool opened;
GSList *requests;
};


/**
* rng_backend_request_entropy:
* @s: the backend to request entropy from
Expand All @@ -70,12 +80,13 @@ void rng_backend_request_entropy(RngBackend *s, size_t size,
void *opaque);

/**
* rng_backend_cancel_requests:
* @s: the backend to cancel all pending requests in
* rng_backend_free_request:
* @s: the backend that created the request
* @req: the request to finalize
*
* Cancels all pending requests submitted by @rng_backend_request_entropy. This
* should be used by a device during reset or in preparation for live migration
* to stop tracking any request.
* Used by child rng backend classes to finalize requests once they've been
* processed. The request is removed from the list of active requests and
* deleted.
*/
void rng_backend_cancel_requests(RngBackend *s);
void rng_backend_finalize_request(RngBackend *s, RngRequest *req);
#endif

0 comments on commit 2d3b7c0

Please sign in to comment.