| Subject: random: Make it work on rt |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 21 Aug 2012 20:38:50 +0200 |
| |
| Delegate the random insertion to the forced threaded interrupt |
| handler. Store the return IP of the hard interrupt handler in the irq |
| descriptor and feed it into the random generator as a source of |
| entropy. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: stable-rt@vger.kernel.org |
| --- |
| drivers/char/random.c | 10 ++++++---- |
| include/linux/irqdesc.h | 1 + |
| include/linux/random.h | 2 +- |
| kernel/irq/handle.c | 8 +++++++- |
| kernel/irq/manage.c | 6 ++++++ |
| 5 files changed, 21 insertions(+), 6 deletions(-) |
| |
| Index: linux-stable/drivers/char/random.c |
| =================================================================== |
| --- linux-stable.orig/drivers/char/random.c |
| +++ linux-stable/drivers/char/random.c |
| @@ -745,18 +745,16 @@ EXPORT_SYMBOL_GPL(add_input_randomness); |
| |
| static DEFINE_PER_CPU(struct fast_pool, irq_randomness); |
| |
| -void add_interrupt_randomness(int irq, int irq_flags) |
| +void add_interrupt_randomness(int irq, int irq_flags, __u64 ip) |
| { |
| struct entropy_store *r; |
| struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness); |
| - struct pt_regs *regs = get_irq_regs(); |
| unsigned long now = jiffies; |
| __u32 input[4], cycles = get_cycles(); |
| |
| input[0] = cycles ^ jiffies; |
| input[1] = irq; |
| - if (regs) { |
| - __u64 ip = instruction_pointer(regs); |
| + if (ip) { |
| input[2] = ip; |
| input[3] = ip >> 32; |
| } |
| @@ -770,7 +768,11 @@ void add_interrupt_randomness(int irq, i |
| fast_pool->last = now; |
| |
| r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| __mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL); |
| +#else |
| + mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL); |
| +#endif |
| /* |
| * If we don't have a valid cycle counter, and we see |
| * back-to-back timer interrupts, then skip giving credit for |
| Index: linux-stable/include/linux/irqdesc.h |
| =================================================================== |
| --- linux-stable.orig/include/linux/irqdesc.h |
| +++ linux-stable/include/linux/irqdesc.h |
| @@ -52,6 +52,7 @@ struct irq_desc { |
| unsigned int irq_count; /* For detecting broken IRQs */ |
| unsigned long last_unhandled; /* Aging timer for unhandled count */ |
| unsigned int irqs_unhandled; |
| + u64 random_ip; |
| raw_spinlock_t lock; |
| struct cpumask *percpu_enabled; |
| #ifdef CONFIG_SMP |
| Index: linux-stable/include/linux/random.h |
| =================================================================== |
| --- linux-stable.orig/include/linux/random.h |
| +++ linux-stable/include/linux/random.h |
| @@ -51,7 +51,7 @@ struct rnd_state { |
| extern void add_device_randomness(const void *, unsigned int); |
| extern void add_input_randomness(unsigned int type, unsigned int code, |
| unsigned int value); |
| -extern void add_interrupt_randomness(int irq, int irq_flags); |
| +extern void add_interrupt_randomness(int irq, int irq_flags, __u64 ip); |
| |
| extern void get_random_bytes(void *buf, int nbytes); |
| extern void get_random_bytes_arch(void *buf, int nbytes); |
| Index: linux-stable/kernel/irq/handle.c |
| =================================================================== |
| --- linux-stable.orig/kernel/irq/handle.c |
| +++ linux-stable/kernel/irq/handle.c |
| @@ -132,6 +132,8 @@ static void irq_wake_thread(struct irq_d |
| irqreturn_t |
| handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) |
| { |
| + struct pt_regs *regs = get_irq_regs(); |
| + u64 ip = regs ? instruction_pointer(regs) : 0; |
| irqreturn_t retval = IRQ_NONE; |
| unsigned int flags = 0, irq = desc->irq_data.irq; |
| |
| @@ -172,7 +174,11 @@ handle_irq_event_percpu(struct irq_desc |
| action = action->next; |
| } while (action); |
| |
| - add_interrupt_randomness(irq, flags); |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| + add_interrupt_randomness(irq, flags, ip); |
| +#else |
| + desc->random_ip = ip; |
| +#endif |
| |
| if (!noirqdebug) |
| note_interrupt(irq, desc, retval); |
| Index: linux-stable/kernel/irq/manage.c |
| =================================================================== |
| --- linux-stable.orig/kernel/irq/manage.c |
| +++ linux-stable/kernel/irq/manage.c |
| @@ -852,6 +852,12 @@ static int irq_thread(void *data) |
| if (!noirqdebug) |
| note_interrupt(action->irq, desc, action_ret); |
| |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + migrate_disable(); |
| + add_interrupt_randomness(action->irq, 0, |
| + desc->random_ip ^ (u64) action); |
| + migrate_enable(); |
| +#endif |
| wake_threads_waitq(desc); |
| } |
| |