Skip to content

Commit cba6437

Browse files
committed
genirq/proc: Reject invalid affinity masks (again)
Qian Cai reported that the WARN_ON() in the x86/msi affinity setting code, which catches cases where the affinity setting is not done on the CPU which is the current target of the interrupt, triggers during CPU hotplug stress testing. It turns out that the warning which was added with the commit addressing the MSI affinity race unearthed yet another long standing bug. If user space writes a bogus affinity mask, i.e. it contains no online CPUs, then it calls irq_select_affinity_usr(). This was introduced for ALPHA in eee4526 ("[PATCH] Alpha: convert to generic irq framework (generic part)") and subsequently made available for all architectures in 1840475 ("genirq: Expose default irq affinity mask (take 3)") which introduced the circumvention of the affinity setting restrictions for interrupt which cannot be moved in process context. The whole exercise is bogus in various aspects: 1) If the interrupt is already started up then there is absolutely no point to honour a bogus interrupt affinity setting from user space. The interrupt is already assigned to an online CPU and it does not make any sense to reassign it to some other randomly chosen online CPU. 2) If the interupt is not yet started up then there is no point either. A subsequent startup of the interrupt will invoke irq_setup_affinity() anyway which will chose a valid target CPU. So the only correct solution is to just return -EINVAL in case user space wrote an affinity mask which does not contain any online CPUs, except for ALPHA which has it's own magic sauce for this. Fixes: 1840475 ("genirq: Expose default irq affinity mask (take 3)") Reported-by: Qian Cai <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Qian Cai <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent bb6d3fb commit cba6437

File tree

3 files changed

+24
-18
lines changed

3 files changed

+24
-18
lines changed

kernel/irq/internals.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,6 @@ static inline void unregister_handler_proc(unsigned int irq,
128128

129129
extern bool irq_can_set_affinity_usr(unsigned int irq);
130130

131-
extern int irq_select_affinity_usr(unsigned int irq);
132-
133131
extern void irq_set_thread_affinity(struct irq_desc *desc);
134132

135133
extern int irq_do_set_affinity(struct irq_data *data,

kernel/irq/manage.c

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -481,23 +481,9 @@ int irq_setup_affinity(struct irq_desc *desc)
481481
{
482482
return irq_select_affinity(irq_desc_get_irq(desc));
483483
}
484-
#endif
484+
#endif /* CONFIG_AUTO_IRQ_AFFINITY */
485+
#endif /* CONFIG_SMP */
485486

486-
/*
487-
* Called when a bogus affinity is set via /proc/irq
488-
*/
489-
int irq_select_affinity_usr(unsigned int irq)
490-
{
491-
struct irq_desc *desc = irq_to_desc(irq);
492-
unsigned long flags;
493-
int ret;
494-
495-
raw_spin_lock_irqsave(&desc->lock, flags);
496-
ret = irq_setup_affinity(desc);
497-
raw_spin_unlock_irqrestore(&desc->lock, flags);
498-
return ret;
499-
}
500-
#endif
501487

502488
/**
503489
* irq_set_vcpu_affinity - Set vcpu affinity for the interrupt

kernel/irq/proc.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,28 @@ static int irq_affinity_list_proc_show(struct seq_file *m, void *v)
111111
return show_irq_affinity(AFFINITY_LIST, m);
112112
}
113113

114+
#ifndef CONFIG_AUTO_IRQ_AFFINITY
115+
static inline int irq_select_affinity_usr(unsigned int irq)
116+
{
117+
/*
118+
* If the interrupt is started up already then this fails. The
119+
* interrupt is assigned to an online CPU already. There is no
120+
* point to move it around randomly. Tell user space that the
121+
* selected mask is bogus.
122+
*
123+
* If not then any change to the affinity is pointless because the
124+
* startup code invokes irq_setup_affinity() which will select
125+
* a online CPU anyway.
126+
*/
127+
return -EINVAL;
128+
}
129+
#else
130+
/* ALPHA magic affinity auto selector. Keep it for historical reasons. */
131+
static inline int irq_select_affinity_usr(unsigned int irq)
132+
{
133+
return irq_select_affinity(irq);
134+
}
135+
#endif
114136

115137
static ssize_t write_irq_affinity(int type, struct file *file,
116138
const char __user *buffer, size_t count, loff_t *pos)

0 commit comments

Comments
 (0)