summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorHarald Freudenberger <freude@linux.vnet.ibm.com>2017-07-11 09:36:22 +0200
committerHerbert Xu <herbert@gondor.apana.org.au>2017-07-18 12:16:08 +0200
commit2bbb6983887fefc8026beab01198d30f47b7bd22 (patch)
treedfc46deced14f60193d7a04a13870d768f2a8c1b /drivers/char
parentcrypto: caam - fix condition for the jump over key(s) command (diff)
downloadlinux-2bbb6983887fefc8026beab01198d30f47b7bd22.tar.xz
linux-2bbb6983887fefc8026beab01198d30f47b7bd22.zip
hwrng: use rng source with best quality
This patch rewoks the hwrng to always use the rng source with best entropy quality. On registation and unregistration the hwrng now tries to choose the best (= highest quality value) rng source. The handling of the internal list of registered rng sources is now always sorted by quality and the top most rng chosen. Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com> Reviewed-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/hw_random/core.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 503a41dfa193..e9dda162d4d2 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -29,6 +29,7 @@
static struct hwrng *current_rng;
static struct task_struct *hwrng_fill;
+/* list of registered rngs, sorted decending by quality */
static LIST_HEAD(rng_list);
/* Protects rng_list and current_rng */
static DEFINE_MUTEX(rng_mutex);
@@ -417,6 +418,7 @@ int hwrng_register(struct hwrng *rng)
{
int err = -EINVAL;
struct hwrng *old_rng, *tmp;
+ struct list_head *rng_list_ptr;
if (!rng->name || (!rng->data_read && !rng->read))
goto out;
@@ -432,14 +434,25 @@ int hwrng_register(struct hwrng *rng)
init_completion(&rng->cleanup_done);
complete(&rng->cleanup_done);
+ /* rng_list is sorted by decreasing quality */
+ list_for_each(rng_list_ptr, &rng_list) {
+ tmp = list_entry(rng_list_ptr, struct hwrng, list);
+ if (tmp->quality < rng->quality)
+ break;
+ }
+ list_add_tail(&rng->list, rng_list_ptr);
+
old_rng = current_rng;
err = 0;
- if (!old_rng) {
+ if (!old_rng || (rng->quality > old_rng->quality)) {
+ /*
+ * Set new rng as current as the new rng source
+ * provides better entropy quality.
+ */
err = set_current_rng(rng);
if (err)
goto out_unlock;
}
- list_add_tail(&rng->list, &rng_list);
if (old_rng && !rng->init) {
/*
@@ -466,12 +479,12 @@ void hwrng_unregister(struct hwrng *rng)
list_del(&rng->list);
if (current_rng == rng) {
drop_current_rng();
+ /* rng_list is sorted by quality, use the best (=first) one */
if (!list_empty(&rng_list)) {
- struct hwrng *tail;
-
- tail = list_entry(rng_list.prev, struct hwrng, list);
+ struct hwrng *new_rng;
- set_current_rng(tail);
+ new_rng = list_entry(rng_list.next, struct hwrng, list);
+ set_current_rng(new_rng);
}
}