aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/random.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-09-22 15:24:02 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-10-10 14:32:20 -0400
commit655b226470b229552ad95b21323864df9bd9fc74 (patch)
tree9379bc872df3e7e859654a374e23be3fc4248521 /drivers/char/random.c
parentf5c2742c23886e707f062881c5f206c1fc704782 (diff)
random: speed up the fast_mix function by a factor of four
By mixing the entropy in chunks of 32-bit words instead of byte by byte, we can speed up the fast_mix function significantly. Since it is called on every single interrupt, on systems with a very heavy interrupt load, this can make a noticeable difference. Also fix a compilation warning in add_interrupt_randomness() and avoid xor'ing cycles and jiffies together just in case we have an architecture which tries to define random_get_entropy() by returning jiffies. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Reported-by: Jörn Engel <joern@logfs.org>
Diffstat (limited to 'drivers/char/random.c')
-rw-r--r--drivers/char/random.c50
1 files changed, 28 insertions, 22 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c
index a68b4a093272..74eeec58e779 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -584,21 +584,26 @@ struct fast_pool {
584 * collector. It's hardcoded for an 128 bit pool and assumes that any 584 * collector. It's hardcoded for an 128 bit pool and assumes that any
585 * locks that might be needed are taken by the caller. 585 * locks that might be needed are taken by the caller.
586 */ 586 */
587static void fast_mix(struct fast_pool *f, const void *in, int nbytes) 587static void fast_mix(struct fast_pool *f, __u32 input[4])
588{ 588{
589 const char *bytes = in;
590 __u32 w; 589 __u32 w;
591 unsigned i = f->count;
592 unsigned input_rotate = f->rotate; 590 unsigned input_rotate = f->rotate;
593 591
594 while (nbytes--) { 592 w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3];
595 w = rol32(*bytes++, input_rotate & 31) ^ f->pool[i & 3] ^ 593 f->pool[0] = (w >> 3) ^ twist_table[w & 7];
596 f->pool[(i + 1) & 3]; 594 input_rotate = (input_rotate + 14) & 31;
597 f->pool[i & 3] = (w >> 3) ^ twist_table[w & 7]; 595 w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0];
598 input_rotate += (i++ & 3) ? 7 : 14; 596 f->pool[1] = (w >> 3) ^ twist_table[w & 7];
599 } 597 input_rotate = (input_rotate + 7) & 31;
600 f->count = i; 598 w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1];
599 f->pool[2] = (w >> 3) ^ twist_table[w & 7];
600 input_rotate = (input_rotate + 7) & 31;
601 w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2];
602 f->pool[3] = (w >> 3) ^ twist_table[w & 7];
603 input_rotate = (input_rotate + 7) & 31;
604
601 f->rotate = input_rotate; 605 f->rotate = input_rotate;
606 f->count++;
602} 607}
603 608
604/* 609/*
@@ -828,20 +833,21 @@ void add_interrupt_randomness(int irq, int irq_flags)
828 struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness); 833 struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness);
829 struct pt_regs *regs = get_irq_regs(); 834 struct pt_regs *regs = get_irq_regs();
830 unsigned long now = jiffies; 835 unsigned long now = jiffies;
831 __u32 input[4], cycles = random_get_entropy(); 836 cycles_t cycles = random_get_entropy();
832 837 __u32 input[4], c_high, j_high;
833 input[0] = cycles ^ jiffies; 838 __u64 ip;
834 input[1] = irq; 839
835 if (regs) { 840 c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
836 __u64 ip = instruction_pointer(regs); 841 j_high = (sizeof(now) > 4) ? now >> 32 : 0;
837 input[2] = ip; 842 input[0] = cycles ^ j_high ^ irq;
838 input[3] = ip >> 32; 843 input[1] = now ^ c_high;
839 } 844 ip = regs ? instruction_pointer(regs) : _RET_IP_;
845 input[2] = ip;
846 input[3] = ip >> 32;
840 847
841 fast_mix(fast_pool, input, sizeof(input)); 848 fast_mix(fast_pool, input);
842 849
843 if ((fast_pool->count & 1023) && 850 if ((fast_pool->count & 63) && !time_after(now, fast_pool->last + HZ))
844 !time_after(now, fast_pool->last + HZ))
845 return; 851 return;
846 852
847 fast_pool->last = now; 853 fast_pool->last = now;