|
28 | 28 | #define RNG_MODULE_NAME "hw_random"
|
29 | 29 |
|
30 | 30 | static struct hwrng *current_rng;
|
| 31 | +/* the current rng has been explicitly chosen by user via sysfs */ |
| 32 | +static int cur_rng_set_by_user; |
31 | 33 | static struct task_struct *hwrng_fill;
|
32 | 34 | /* list of registered rngs, sorted decending by quality */
|
33 | 35 | static LIST_HEAD(rng_list);
|
@@ -304,6 +306,7 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
|
304 | 306 | list_for_each_entry(rng, &rng_list, list) {
|
305 | 307 | if (sysfs_streq(rng->name, buf)) {
|
306 | 308 | err = 0;
|
| 309 | + cur_rng_set_by_user = 1; |
307 | 310 | if (rng != current_rng)
|
308 | 311 | err = set_current_rng(rng);
|
309 | 312 | break;
|
@@ -352,16 +355,27 @@ static ssize_t hwrng_attr_available_show(struct device *dev,
|
352 | 355 | return strlen(buf);
|
353 | 356 | }
|
354 | 357 |
|
| 358 | +static ssize_t hwrng_attr_selected_show(struct device *dev, |
| 359 | + struct device_attribute *attr, |
| 360 | + char *buf) |
| 361 | +{ |
| 362 | + return snprintf(buf, PAGE_SIZE, "%d\n", cur_rng_set_by_user); |
| 363 | +} |
| 364 | + |
355 | 365 | static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
|
356 | 366 | hwrng_attr_current_show,
|
357 | 367 | hwrng_attr_current_store);
|
358 | 368 | static DEVICE_ATTR(rng_available, S_IRUGO,
|
359 | 369 | hwrng_attr_available_show,
|
360 | 370 | NULL);
|
| 371 | +static DEVICE_ATTR(rng_selected, S_IRUGO, |
| 372 | + hwrng_attr_selected_show, |
| 373 | + NULL); |
361 | 374 |
|
362 | 375 | static struct attribute *rng_dev_attrs[] = {
|
363 | 376 | &dev_attr_rng_current.attr,
|
364 | 377 | &dev_attr_rng_available.attr,
|
| 378 | + &dev_attr_rng_selected.attr, |
365 | 379 | NULL
|
366 | 380 | };
|
367 | 381 |
|
@@ -444,10 +458,12 @@ int hwrng_register(struct hwrng *rng)
|
444 | 458 |
|
445 | 459 | old_rng = current_rng;
|
446 | 460 | err = 0;
|
447 |
| - if (!old_rng || (rng->quality > old_rng->quality)) { |
| 461 | + if (!old_rng || |
| 462 | + (!cur_rng_set_by_user && rng->quality > old_rng->quality)) { |
448 | 463 | /*
|
449 | 464 | * Set new rng as current as the new rng source
|
450 |
| - * provides better entropy quality. |
| 465 | + * provides better entropy quality and was not |
| 466 | + * chosen by userspace. |
451 | 467 | */
|
452 | 468 | err = set_current_rng(rng);
|
453 | 469 | if (err)
|
@@ -479,6 +495,7 @@ void hwrng_unregister(struct hwrng *rng)
|
479 | 495 | list_del(&rng->list);
|
480 | 496 | if (current_rng == rng) {
|
481 | 497 | drop_current_rng();
|
| 498 | + cur_rng_set_by_user = 0; |
482 | 499 | /* rng_list is sorted by quality, use the best (=first) one */
|
483 | 500 | if (!list_empty(&rng_list)) {
|
484 | 501 | struct hwrng *new_rng;
|
|
0 commit comments