Skip to content

Commit e309efc

Browse files
aarontomlinkawasaki
authored andcommitted
genirq/affinity: Restrict managed IRQ affinity to housekeeping CPUs
At present, the managed interrupt spreading algorithm distributes vectors across all available CPUs within a given node or system. On systems employing CPU isolation (e.g., "isolcpus=io_queue"), this behaviour defeats the primary purpose of isolation by routing hardware interrupts (such as NVMe completion queues) directly to isolated cores. Update irq_create_affinity_masks() to respect the housekeeping CPU mask. Introduce irq_spread_hk_filter() to intersect the natively calculated affinity mask with the HK_TYPE_IO_QUEUE mask, thereby keeping managed interrupts off isolated CPUs. To ensure strict isolation whilst guaranteeing a valid routing destination: 1. Fallback mechanism: Should the initial spreading logic assign a vector exclusively to isolated CPUs (resulting in an empty intersection), the filter safely falls back to the system's online housekeeping CPUs. 2. Hotplug safety: The fallback utilises data_race(cpu_online_mask) instead of allocating a local cpumask snapshot. This circumvents CONFIG_CPUMASK_OFFSTACK stack bloat hazards on high-core-count systems. Furthermore, it prevents deadlocks with concurrent CPU hotplug operations (e.g., during storage driver error recovery) by eliminating the need to hold the CPU hotplug read lock. 3. Fast-path optimisation: The filtering logic is conditionally executed only if housekeeping is enabled, thereby ensuring zero overhead for standard configurations. Signed-off-by: Aaron Tomlin <[email protected]>
1 parent b722c06 commit e309efc

1 file changed

Lines changed: 25 additions & 1 deletion

File tree

kernel/irq/affinity.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,24 @@
88
#include <linux/slab.h>
99
#include <linux/cpu.h>
1010
#include <linux/group_cpus.h>
11+
#include <linux/sched/isolation.h>
12+
13+
/**
14+
* irq_spread_hk_filter - Restrict an interrupt affinity mask to housekeeping CPUs
15+
* @mask: The interrupt affinity mask to filter (in/out)
16+
* @hk_mask: The system's housekeeping CPU mask
17+
*
18+
* Intersects @mask with @hk_mask to keep interrupts off isolated CPUs.
19+
* If this intersection is empty (meaning all targeted CPUs were isolated),
20+
* it falls back to the online housekeeping CPUs to guarantee a valid
21+
* routing destination.
22+
*/
23+
static void irq_spread_hk_filter(struct cpumask *mask,
24+
const struct cpumask *hk_mask)
25+
{
26+
if (!cpumask_and(mask, mask, hk_mask))
27+
cpumask_and(mask, hk_mask, data_race(cpu_online_mask));
28+
}
1129

1230
static void default_calc_sets(struct irq_affinity *affd, unsigned int affvecs)
1331
{
@@ -27,6 +45,8 @@ irq_create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd)
2745
{
2846
unsigned int affvecs, curvec, usedvecs, i;
2947
struct irq_affinity_desc *masks = NULL;
48+
const struct cpumask *hk_mask = housekeeping_cpumask(HK_TYPE_IO_QUEUE);
49+
bool hk_enabled = housekeeping_enabled(HK_TYPE_IO_QUEUE);
3050

3151
/*
3252
* Determine the number of vectors which need interrupt affinities
@@ -83,8 +103,12 @@ irq_create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd)
83103
return NULL;
84104
}
85105

86-
for (int j = 0; j < nr_masks; j++)
106+
for (int j = 0; j < nr_masks; j++) {
87107
cpumask_copy(&masks[curvec + j].mask, &result[j]);
108+
if (hk_enabled)
109+
irq_spread_hk_filter(&masks[curvec + j].mask,
110+
hk_mask);
111+
}
88112
kfree(result);
89113

90114
curvec += nr_masks;

0 commit comments

Comments
 (0)