genirq: Delegate irq affinity setting to the irq thread

irq_set_thread_affinity() calls set_cpus_allowed_ptr() which might
sleep, but irq_set_thread_affinity() is called with desc->lock held
and can be called from hard interrupt context as well. The code has
another bug as it does not hold a ref on the task struct as required
by set_cpus_allowed_ptr().

Just set the IRQTF_AFFINITY bit in action->thread_flags. The next time
the thread runs it migrates itself. Solves all of the above problems
nicely.

Add kerneldoc to irq_set_thread_affinity() while at it.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <new-submission>

+48 -9
+2
include/linux/interrupt.h
··· 64 * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run 65 * IRQTF_DIED - handler thread died 66 * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed 67 */ 68 enum { 69 IRQTF_RUNTHREAD, 70 IRQTF_DIED, 71 IRQTF_WARNED, 72 }; 73 74 typedef irqreturn_t (*irq_handler_t)(int, void *);
··· 64 * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run 65 * IRQTF_DIED - handler thread died 66 * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed 67 + * IRQTF_AFFINITY - irq thread is requested to adjust affinity 68 */ 69 enum { 70 IRQTF_RUNTHREAD, 71 IRQTF_DIED, 72 IRQTF_WARNED, 73 + IRQTF_AFFINITY, 74 }; 75 76 typedef irqreturn_t (*irq_handler_t)(int, void *);
+1 -2
kernel/irq/internals.h
··· 42 43 extern int irq_select_affinity_usr(unsigned int irq); 44 45 - extern void 46 - irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask); 47 48 /* 49 * Debugging printout:
··· 42 43 extern int irq_select_affinity_usr(unsigned int irq); 44 45 + extern void irq_set_thread_affinity(struct irq_desc *desc); 46 47 /* 48 * Debugging printout:
+44 -6
kernel/irq/manage.c
··· 80 return 1; 81 } 82 83 - void 84 - irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask) 85 { 86 struct irqaction *action = desc->action; 87 88 while (action) { 89 if (action->thread) 90 - set_cpus_allowed_ptr(action->thread, cpumask); 91 action = action->next; 92 } 93 } ··· 120 if (desc->status & IRQ_MOVE_PCNTXT) { 121 if (!desc->chip->set_affinity(irq, cpumask)) { 122 cpumask_copy(desc->affinity, cpumask); 123 - irq_set_thread_affinity(desc, cpumask); 124 } 125 } 126 else { ··· 130 #else 131 if (!desc->chip->set_affinity(irq, cpumask)) { 132 cpumask_copy(desc->affinity, cpumask); 133 - irq_set_thread_affinity(desc, cpumask); 134 } 135 #endif 136 desc->status |= IRQ_AFFINITY_SET; ··· 184 spin_lock_irqsave(&desc->lock, flags); 185 ret = setup_affinity(irq, desc); 186 if (!ret) 187 - irq_set_thread_affinity(desc, desc->affinity); 188 spin_unlock_irqrestore(&desc->lock, flags); 189 190 return ret; ··· 452 } 453 454 /* 455 * Interrupt handler thread 456 */ 457 static int irq_thread(void *data) ··· 493 current->irqaction = action; 494 495 while (!irq_wait_for_interrupt(action)) { 496 497 atomic_inc(&desc->threads_active); 498
··· 80 return 1; 81 } 82 83 + /** 84 + * irq_set_thread_affinity - Notify irq threads to adjust affinity 85 + * @desc: irq descriptor which has affitnity changed 86 + * 87 + * We just set IRQTF_AFFINITY and delegate the affinity setting 88 + * to the interrupt thread itself. We can not call 89 + * set_cpus_allowed_ptr() here as we hold desc->lock and this 90 + * code can be called from hard interrupt context. 91 + */ 92 + void irq_set_thread_affinity(struct irq_desc *desc) 93 { 94 struct irqaction *action = desc->action; 95 96 while (action) { 97 if (action->thread) 98 + set_bit(IRQTF_AFFINITY, &action->thread_flags); 99 action = action->next; 100 } 101 } ··· 112 if (desc->status & IRQ_MOVE_PCNTXT) { 113 if (!desc->chip->set_affinity(irq, cpumask)) { 114 cpumask_copy(desc->affinity, cpumask); 115 + irq_set_thread_affinity(desc); 116 } 117 } 118 else { ··· 122 #else 123 if (!desc->chip->set_affinity(irq, cpumask)) { 124 cpumask_copy(desc->affinity, cpumask); 125 + irq_set_thread_affinity(desc); 126 } 127 #endif 128 desc->status |= IRQ_AFFINITY_SET; ··· 176 spin_lock_irqsave(&desc->lock, flags); 177 ret = setup_affinity(irq, desc); 178 if (!ret) 179 + irq_set_thread_affinity(desc); 180 spin_unlock_irqrestore(&desc->lock, flags); 181 182 return ret; ··· 444 } 445 446 /* 447 + * Check whether we need to change the affinity of the interrupt thread. 448 + */ 449 + static void 450 + irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) 451 + { 452 + cpumask_var_t mask; 453 + 454 + if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags)) 455 + return; 456 + 457 + /* 458 + * In case we are out of memory we set IRQTF_AFFINITY again and 459 + * try again next time 460 + */ 461 + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { 462 + set_bit(IRQTF_AFFINITY, &action->thread_flags); 463 + return; 464 + } 465 + 466 + spin_lock_irq(&desc->lock); 467 + cpumask_copy(mask, desc->affinity); 468 + spin_unlock_irq(&desc->lock); 469 + 470 + set_cpus_allowed_ptr(current, mask); 471 + free_cpumask_var(mask); 472 + } 473 + 474 + /* 475 * Interrupt handler thread 476 */ 477 static int irq_thread(void *data) ··· 457 current->irqaction = action; 458 459 while (!irq_wait_for_interrupt(action)) { 460 + 461 + irq_thread_check_affinity(desc, action); 462 463 atomic_inc(&desc->threads_active); 464
+1 -1
kernel/irq/migration.c
··· 45 < nr_cpu_ids)) 46 if (!desc->chip->set_affinity(irq, desc->pending_mask)) { 47 cpumask_copy(desc->affinity, desc->pending_mask); 48 - irq_set_thread_affinity(desc, desc->pending_mask); 49 } 50 51 cpumask_clear(desc->pending_mask);
··· 45 < nr_cpu_ids)) 46 if (!desc->chip->set_affinity(irq, desc->pending_mask)) { 47 cpumask_copy(desc->affinity, desc->pending_mask); 48 + irq_set_thread_affinity(desc); 49 } 50 51 cpumask_clear(desc->pending_mask);