Skip to content

Commit

Permalink
genirq: Always force thread affinity
Browse files Browse the repository at this point in the history
Sankara reported that the genirq core code fails to adjust the
affinity of an interrupt thread in several cases:

 1) On request/setup_irq() the call to setup_affinity() happens before
    the new action is registered, so the new thread is not notified.

 2) For secondary shared interrupts nothing notifies the new thread to
    change its affinity.

 3) Interrupts which have the IRQ_NO_BALANCE flag set are not moving
    the thread either.

Fix this by setting the thread affinity flag right on thread creation
time. This ensures that under all circumstances the thread moves to
the right place. Requires a check in irq_thread_check_affinity for an
existing affinity mask (CONFIG_CPU_MASK_OFFSTACK=y)

Reported-and-tested-by: Sankara Muthukrishnan <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1209041738200.2754@ionos
Signed-off-by: Thomas Gleixner <[email protected]>
  • Loading branch information
KAGA-KOKO committed Nov 12, 2012
1 parent f3de44e commit 04aa530
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ static void
irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
{
cpumask_var_t mask;
bool valid = true;

if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags))
return;
Expand All @@ -746,10 +747,18 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
}

raw_spin_lock_irq(&desc->lock);
cpumask_copy(mask, desc->irq_data.affinity);
/*
* This code is triggered unconditionally. Check the affinity
* mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
*/
if (desc->irq_data.affinity)
cpumask_copy(mask, desc->irq_data.affinity);
else
valid = false;
raw_spin_unlock_irq(&desc->lock);

set_cpus_allowed_ptr(current, mask);
if (valid)
set_cpus_allowed_ptr(current, mask);
free_cpumask_var(mask);
}
#else
Expand Down Expand Up @@ -954,6 +963,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
*/
get_task_struct(t);
new->thread = t;
/*
* Tell the thread to set its affinity. This is
* important for shared interrupt handlers as we do
* not invoke setup_affinity() for the secondary
* handlers as everything is already set up. Even for
* interrupts marked with IRQF_NO_BALANCE this is
* correct as we want the thread to move to the cpu(s)
* on which the requesting code placed the interrupt.
*/
set_bit(IRQTF_AFFINITY, &new->thread_flags);
}

if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
Expand Down

0 comments on commit 04aa530

Please sign in to comment.