Skip to content

Commit dd9f6d3

Browse files
imran-knThomas Gleixner
authored andcommitted
genirq/cpuhotplug: Notify about affinity changes breaking the affinity mask
During CPU offlining the interrupts affined to that CPU are moved to other online CPUs, which might break the original affinity mask if the outgoing CPU was the last online CPU in that mask. This change is not propagated to irq_desc::affinity_notify(), which leaves users of the affinity notifier mechanism with stale information. Avoid this by scheduling affinity change notification work for interrupts that were affined to the CPU being offlined, if the new target CPU is not part of the original affinity mask. Since irq_set_affinity_locked() uses the same logic to schedule affinity change notification work, split out this logic into a dedicated function and use that at both places. [ tglx: Removed the EXPORT(), removed the !SMP stub, moved the prototype, added a lockdep assert instead of a comment, fixed up coding style and name space. Polished and clarified the change log ] Signed-off-by: Imran Khan <imran.f.khan@oracle.com> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260113143727.1041265-1-imran.f.khan@oracle.com
1 parent fb11a24 commit dd9f6d3

3 files changed

Lines changed: 23 additions & 11 deletions

File tree

kernel/irq/cpuhotplug.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,11 @@ void irq_migrate_all_off_this_cpu(void)
177177
bool affinity_broken;
178178

179179
desc = irq_to_desc(irq);
180-
scoped_guard(raw_spinlock, &desc->lock)
180+
scoped_guard(raw_spinlock, &desc->lock) {
181181
affinity_broken = migrate_one_irq(desc);
182-
182+
if (affinity_broken && desc->affinity_notify)
183+
irq_affinity_schedule_notify_work(desc);
184+
}
183185
if (affinity_broken) {
184186
pr_debug_ratelimited("IRQ %u: no longer affine to CPU%u\n",
185187
irq, smp_processor_id());

kernel/irq/internals.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,14 @@ extern bool irq_can_set_affinity_usr(unsigned int irq);
135135

136136
extern int irq_do_set_affinity(struct irq_data *data,
137137
const struct cpumask *dest, bool force);
138+
extern void irq_affinity_schedule_notify_work(struct irq_desc *desc);
138139

139140
#ifdef CONFIG_SMP
140141
extern int irq_setup_affinity(struct irq_desc *desc);
141142
#else
142143
static inline int irq_setup_affinity(struct irq_desc *desc) { return 0; }
143144
#endif
144145

145-
146146
#define for_each_action_of_desc(desc, act) \
147147
for (act = desc->action; act; act = act->next)
148148

kernel/irq/manage.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,21 @@ static bool irq_set_affinity_deactivated(struct irq_data *data,
347347
return true;
348348
}
349349

350+
/**
351+
* irq_affinity_schedule_notify_work - Schedule work to notify about affinity change
352+
* @desc: Interrupt descriptor whose affinity changed
353+
*/
354+
void irq_affinity_schedule_notify_work(struct irq_desc *desc)
355+
{
356+
lockdep_assert_held(&desc->lock);
357+
358+
kref_get(&desc->affinity_notify->kref);
359+
if (!schedule_work(&desc->affinity_notify->work)) {
360+
/* Work was already scheduled, drop our extra ref */
361+
kref_put(&desc->affinity_notify->kref, desc->affinity_notify->release);
362+
}
363+
}
364+
350365
int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
351366
bool force)
352367
{
@@ -367,14 +382,9 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
367382
irq_copy_pending(desc, mask);
368383
}
369384

370-
if (desc->affinity_notify) {
371-
kref_get(&desc->affinity_notify->kref);
372-
if (!schedule_work(&desc->affinity_notify->work)) {
373-
/* Work was already scheduled, drop our extra ref */
374-
kref_put(&desc->affinity_notify->kref,
375-
desc->affinity_notify->release);
376-
}
377-
}
385+
if (desc->affinity_notify)
386+
irq_affinity_schedule_notify_work(desc);
387+
378388
irqd_set(data, IRQD_AFFINITY_SET);
379389

380390
return ret;

0 commit comments

Comments
 (0)