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 64 * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run 65 65 * IRQTF_DIED - handler thread died 66 66 * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed 67 + * IRQTF_AFFINITY - irq thread is requested to adjust affinity 67 68 */ 68 69 enum { 69 70 IRQTF_RUNTHREAD, 70 71 IRQTF_DIED, 71 72 IRQTF_WARNED, 73 + IRQTF_AFFINITY, 72 74 }; 73 75 74 76 typedef irqreturn_t (*irq_handler_t)(int, void *);
+1 -2
kernel/irq/internals.h
··· 42 42 43 43 extern int irq_select_affinity_usr(unsigned int irq); 44 44 45 - extern void 46 - irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask); 45 + extern void irq_set_thread_affinity(struct irq_desc *desc); 47 46 48 47 /* 49 48 * Debugging printout:
+44 -6
kernel/irq/manage.c
··· 80 80 return 1; 81 81 } 82 82 83 - void 84 - irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask) 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) 85 93 { 86 94 struct irqaction *action = desc->action; 87 95 88 96 while (action) { 89 97 if (action->thread) 90 - set_cpus_allowed_ptr(action->thread, cpumask); 98 + set_bit(IRQTF_AFFINITY, &action->thread_flags); 91 99 action = action->next; 92 100 } 93 101 } ··· 120 112 if (desc->status & IRQ_MOVE_PCNTXT) { 121 113 if (!desc->chip->set_affinity(irq, cpumask)) { 122 114 cpumask_copy(desc->affinity, cpumask); 123 - irq_set_thread_affinity(desc, cpumask); 115 + irq_set_thread_affinity(desc); 124 116 } 125 117 } 126 118 else { ··· 130 122 #else 131 123 if (!desc->chip->set_affinity(irq, cpumask)) { 132 124 cpumask_copy(desc->affinity, cpumask); 133 - irq_set_thread_affinity(desc, cpumask); 125 + irq_set_thread_affinity(desc); 134 126 } 135 127 #endif 136 128 desc->status |= IRQ_AFFINITY_SET; ··· 184 176 spin_lock_irqsave(&desc->lock, flags); 185 177 ret = setup_affinity(irq, desc); 186 178 if (!ret) 187 - irq_set_thread_affinity(desc, desc->affinity); 179 + irq_set_thread_affinity(desc); 188 180 spin_unlock_irqrestore(&desc->lock, flags); 189 181 190 182 return ret; ··· 452 444 } 453 445 454 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 + /* 455 475 * Interrupt handler thread 456 476 */ 457 477 static int irq_thread(void *data) ··· 493 457 current->irqaction = action; 494 458 495 459 while (!irq_wait_for_interrupt(action)) { 460 + 461 + irq_thread_check_affinity(desc, action); 496 462 497 463 atomic_inc(&desc->threads_active); 498 464
+1 -1
kernel/irq/migration.c
··· 45 45 < nr_cpu_ids)) 46 46 if (!desc->chip->set_affinity(irq, desc->pending_mask)) { 47 47 cpumask_copy(desc->affinity, desc->pending_mask); 48 - irq_set_thread_affinity(desc, desc->pending_mask); 48 + irq_set_thread_affinity(desc); 49 49 } 50 50 51 51 cpumask_clear(desc->pending_mask);