diff options
author | Theodore Ts'o <tytso@mit.edu> | 2014-06-14 21:43:13 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-07-15 04:49:40 -0400 |
commit | 43759d4f429c8d55fd56f863542e20f4e6e8f589 (patch) | |
tree | 253a45901a3e3d83be2566e0ad59af1c2c171be7 /drivers/char/random.c | |
parent | 840f95077ffd640df9c74ad9796fa094a5c8075a (diff) |
random: use an improved fast_mix() function
Use more efficient fast_mix() function. Thanks to George Spelvin for
doing the leg work to find a more efficient mixing function.
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: George Spelvin <linux@horizon.com>
Diffstat (limited to 'drivers/char/random.c')
-rw-r--r-- | drivers/char/random.c | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index dfe918a21e32..d3bb7927fb49 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -267,6 +267,8 @@ | |||
267 | #define CREATE_TRACE_POINTS | 267 | #define CREATE_TRACE_POINTS |
268 | #include <trace/events/random.h> | 268 | #include <trace/events/random.h> |
269 | 269 | ||
270 | /* #define ADD_INTERRUPT_BENCH */ | ||
271 | |||
270 | /* | 272 | /* |
271 | * Configuration information | 273 | * Configuration information |
272 | */ | 274 | */ |
@@ -558,25 +560,29 @@ struct fast_pool { | |||
558 | * collector. It's hardcoded for an 128 bit pool and assumes that any | 560 | * collector. It's hardcoded for an 128 bit pool and assumes that any |
559 | * locks that might be needed are taken by the caller. | 561 | * locks that might be needed are taken by the caller. |
560 | */ | 562 | */ |
561 | static void fast_mix(struct fast_pool *f, __u32 input[4]) | 563 | static void fast_mix(struct fast_pool *f) |
562 | { | 564 | { |
563 | __u32 w; | 565 | __u32 a = f->pool[0], b = f->pool[1]; |
564 | unsigned input_rotate = f->rotate; | 566 | __u32 c = f->pool[2], d = f->pool[3]; |
565 | 567 | ||
566 | w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3]; | 568 | a += b; c += d; |
567 | f->pool[0] = (w >> 3) ^ twist_table[w & 7]; | 569 | b = rol32(a, 6); d = rol32(c, 27); |
568 | input_rotate = (input_rotate + 14) & 31; | 570 | d ^= a; b ^= c; |
569 | w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0]; | 571 | |
570 | f->pool[1] = (w >> 3) ^ twist_table[w & 7]; | 572 | a += b; c += d; |
571 | input_rotate = (input_rotate + 7) & 31; | 573 | b = rol32(a, 16); d = rol32(c, 14); |
572 | w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1]; | 574 | d ^= a; b ^= c; |
573 | f->pool[2] = (w >> 3) ^ twist_table[w & 7]; | 575 | |
574 | input_rotate = (input_rotate + 7) & 31; | 576 | a += b; c += d; |
575 | w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2]; | 577 | b = rol32(a, 6); d = rol32(c, 27); |
576 | f->pool[3] = (w >> 3) ^ twist_table[w & 7]; | 578 | d ^= a; b ^= c; |
577 | input_rotate = (input_rotate + 7) & 31; | 579 | |
578 | 580 | a += b; c += d; | |
579 | f->rotate = input_rotate; | 581 | b = rol32(a, 16); d = rol32(c, 14); |
582 | d ^= a; b ^= c; | ||
583 | |||
584 | f->pool[0] = a; f->pool[1] = b; | ||
585 | f->pool[2] = c; f->pool[3] = d; | ||
580 | f->count++; | 586 | f->count++; |
581 | } | 587 | } |
582 | 588 | ||
@@ -829,6 +835,27 @@ EXPORT_SYMBOL_GPL(add_input_randomness); | |||
829 | 835 | ||
830 | static DEFINE_PER_CPU(struct fast_pool, irq_randomness); | 836 | static DEFINE_PER_CPU(struct fast_pool, irq_randomness); |
831 | 837 | ||
838 | #ifdef ADD_INTERRUPT_BENCH | ||
839 | static unsigned long avg_cycles, avg_deviation; | ||
840 | |||
841 | #define AVG_SHIFT 8 /* Exponential average factor k=1/256 */ | ||
842 | #define FIXED_1_2 (1 << (AVG_SHIFT-1)) | ||
843 | |||
844 | static void add_interrupt_bench(cycles_t start) | ||
845 | { | ||
846 | long delta = random_get_entropy() - start; | ||
847 | |||
848 | /* Use a weighted moving average */ | ||
849 | delta = delta - ((avg_cycles + FIXED_1_2) >> AVG_SHIFT); | ||
850 | avg_cycles += delta; | ||
851 | /* And average deviation */ | ||
852 | delta = abs(delta) - ((avg_deviation + FIXED_1_2) >> AVG_SHIFT); | ||
853 | avg_deviation += delta; | ||
854 | } | ||
855 | #else | ||
856 | #define add_interrupt_bench(x) | ||
857 | #endif | ||
858 | |||
832 | void add_interrupt_randomness(int irq, int irq_flags) | 859 | void add_interrupt_randomness(int irq, int irq_flags) |
833 | { | 860 | { |
834 | struct entropy_store *r; | 861 | struct entropy_store *r; |
@@ -836,22 +863,23 @@ void add_interrupt_randomness(int irq, int irq_flags) | |||
836 | struct pt_regs *regs = get_irq_regs(); | 863 | struct pt_regs *regs = get_irq_regs(); |
837 | unsigned long now = jiffies; | 864 | unsigned long now = jiffies; |
838 | cycles_t cycles = random_get_entropy(); | 865 | cycles_t cycles = random_get_entropy(); |
839 | __u32 input[4], c_high, j_high; | 866 | __u32 c_high, j_high; |
840 | __u64 ip; | 867 | __u64 ip; |
841 | unsigned long seed; | 868 | unsigned long seed; |
842 | int credit = 0; | 869 | int credit = 0; |
843 | 870 | ||
844 | c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; | 871 | c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; |
845 | j_high = (sizeof(now) > 4) ? now >> 32 : 0; | 872 | j_high = (sizeof(now) > 4) ? now >> 32 : 0; |
846 | input[0] = cycles ^ j_high ^ irq; | 873 | fast_pool->pool[0] ^= cycles ^ j_high ^ irq; |
847 | input[1] = now ^ c_high; | 874 | fast_pool->pool[1] ^= now ^ c_high; |
848 | ip = regs ? instruction_pointer(regs) : _RET_IP_; | 875 | ip = regs ? instruction_pointer(regs) : _RET_IP_; |
849 | input[2] = ip; | 876 | fast_pool->pool[2] ^= ip; |
850 | input[3] = ip >> 32; | 877 | fast_pool->pool[3] ^= ip >> 32; |
851 | 878 | ||
852 | fast_mix(fast_pool, input); | 879 | fast_mix(fast_pool); |
853 | if ((irq_flags & __IRQF_TIMER) == 0) | 880 | if ((irq_flags & __IRQF_TIMER) == 0) |
854 | fast_pool->notimer_count++; | 881 | fast_pool->notimer_count++; |
882 | add_interrupt_bench(cycles); | ||
855 | 883 | ||
856 | if (cycles) { | 884 | if (cycles) { |
857 | if ((fast_pool->count < 64) && | 885 | if ((fast_pool->count < 64) && |
@@ -1650,6 +1678,22 @@ struct ctl_table random_table[] = { | |||
1650 | .mode = 0444, | 1678 | .mode = 0444, |
1651 | .proc_handler = proc_do_uuid, | 1679 | .proc_handler = proc_do_uuid, |
1652 | }, | 1680 | }, |
1681 | #ifdef ADD_INTERRUPT_BENCH | ||
1682 | { | ||
1683 | .procname = "add_interrupt_avg_cycles", | ||
1684 | .data = &avg_cycles, | ||
1685 | .maxlen = sizeof(avg_cycles), | ||
1686 | .mode = 0444, | ||
1687 | .proc_handler = proc_doulongvec_minmax, | ||
1688 | }, | ||
1689 | { | ||
1690 | .procname = "add_interrupt_avg_deviation", | ||
1691 | .data = &avg_deviation, | ||
1692 | .maxlen = sizeof(avg_deviation), | ||
1693 | .mode = 0444, | ||
1694 | .proc_handler = proc_doulongvec_minmax, | ||
1695 | }, | ||
1696 | #endif | ||
1653 | { } | 1697 | { } |
1654 | }; | 1698 | }; |
1655 | #endif /* CONFIG_SYSCTL */ | 1699 | #endif /* CONFIG_SYSCTL */ |