Skip to content

Commit b687380

Browse files
sebastianasKAGA-KOKO
authored andcommitted
irq: Track the owner of irq descriptor
Interrupt descriptors can be allocated from modules. The interrupts are used by other modules, but we have no refcount on the module which provides the interrupts and there is no way to establish one on the device level as the interrupt using module is agnostic to the fact that the interrupt is provided by a module rather than by some builtin interrupt controller. To prevent removal of the interrupt providing module, we can track the owner of the interrupt descriptor, which also provides the relevant irq chip functions in the irq descriptor. request/setup_irq() can now acquire a refcount on the owner module to prevent unloading. free_irq() drops the refcount. Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent f3637a5 commit b687380

File tree

4 files changed

+48
-17
lines changed

4 files changed

+48
-17
lines changed

include/linux/irq.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/errno.h>
2424
#include <linux/topology.h>
2525
#include <linux/wait.h>
26+
#include <linux/module.h>
2627

2728
#include <asm/irq.h>
2829
#include <asm/ptrace.h>
@@ -546,7 +547,15 @@ static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)
546547
return d->msi_desc;
547548
}
548549

549-
int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);
550+
int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
551+
struct module *owner);
552+
553+
static inline int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt,
554+
int node)
555+
{
556+
return __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE);
557+
}
558+
550559
void irq_free_descs(unsigned int irq, unsigned int cnt);
551560
int irq_reserve_irqs(unsigned int from, unsigned int cnt);
552561

include/linux/irqdesc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ struct irq_desc {
6666
#ifdef CONFIG_PROC_FS
6767
struct proc_dir_entry *dir;
6868
#endif
69+
struct module *owner;
6970
const char *name;
7071
} ____cacheline_internodealigned_in_smp;
7172

kernel/irq/irqdesc.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ static inline void desc_smp_init(struct irq_desc *desc, int node) { }
7070
static inline int desc_node(struct irq_desc *desc) { return 0; }
7171
#endif
7272

73-
static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
73+
static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
74+
struct module *owner)
7475
{
7576
int cpu;
7677

@@ -86,6 +87,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
8687
desc->irq_count = 0;
8788
desc->irqs_unhandled = 0;
8889
desc->name = NULL;
90+
desc->owner = owner;
8991
for_each_possible_cpu(cpu)
9092
*per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
9193
desc_smp_init(desc, node);
@@ -128,7 +130,7 @@ static void free_masks(struct irq_desc *desc)
128130
static inline void free_masks(struct irq_desc *desc) { }
129131
#endif
130132

131-
static struct irq_desc *alloc_desc(int irq, int node)
133+
static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
132134
{
133135
struct irq_desc *desc;
134136
gfp_t gfp = GFP_KERNEL;
@@ -147,7 +149,7 @@ static struct irq_desc *alloc_desc(int irq, int node)
147149
raw_spin_lock_init(&desc->lock);
148150
lockdep_set_class(&desc->lock, &irq_desc_lock_class);
149151

150-
desc_set_defaults(irq, desc, node);
152+
desc_set_defaults(irq, desc, node, owner);
151153

152154
return desc;
153155

@@ -173,13 +175,14 @@ static void free_desc(unsigned int irq)
173175
kfree(desc);
174176
}
175177

176-
static int alloc_descs(unsigned int start, unsigned int cnt, int node)
178+
static int alloc_descs(unsigned int start, unsigned int cnt, int node,
179+
struct module *owner)
177180
{
178181
struct irq_desc *desc;
179182
int i;
180183

181184
for (i = 0; i < cnt; i++) {
182-
desc = alloc_desc(start + i, node);
185+
desc = alloc_desc(start + i, node, owner);
183186
if (!desc)
184187
goto err;
185188
mutex_lock(&sparse_irq_lock);
@@ -227,7 +230,7 @@ int __init early_irq_init(void)
227230
nr_irqs = initcnt;
228231

229232
for (i = 0; i < initcnt; i++) {
230-
desc = alloc_desc(i, node);
233+
desc = alloc_desc(i, node, NULL);
231234
set_bit(i, allocated_irqs);
232235
irq_insert_desc(i, desc);
233236
}
@@ -261,7 +264,7 @@ int __init early_irq_init(void)
261264
alloc_masks(&desc[i], GFP_KERNEL, node);
262265
raw_spin_lock_init(&desc[i].lock);
263266
lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
264-
desc_set_defaults(i, &desc[i], node);
267+
desc_set_defaults(i, &desc[i], node, NULL);
265268
}
266269
return arch_early_irq_init();
267270
}
@@ -276,8 +279,16 @@ static void free_desc(unsigned int irq)
276279
dynamic_irq_cleanup(irq);
277280
}
278281

279-
static inline int alloc_descs(unsigned int start, unsigned int cnt, int node)
282+
static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
283+
struct module *owner)
280284
{
285+
u32 i;
286+
287+
for (i = 0; i < cnt; i++) {
288+
struct irq_desc *desc = irq_to_desc(start + i);
289+
290+
desc->owner = owner;
291+
}
281292
return start;
282293
}
283294

@@ -337,7 +348,8 @@ EXPORT_SYMBOL_GPL(irq_free_descs);
337348
* Returns the first irq number or error code
338349
*/
339350
int __ref
340-
irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
351+
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
352+
struct module *owner)
341353
{
342354
int start, ret;
343355

@@ -366,13 +378,13 @@ irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
366378

367379
bitmap_set(allocated_irqs, start, cnt);
368380
mutex_unlock(&sparse_irq_lock);
369-
return alloc_descs(start, cnt, node);
381+
return alloc_descs(start, cnt, node, owner);
370382

371383
err:
372384
mutex_unlock(&sparse_irq_lock);
373385
return ret;
374386
}
375-
EXPORT_SYMBOL_GPL(irq_alloc_descs);
387+
EXPORT_SYMBOL_GPL(__irq_alloc_descs);
376388

377389
/**
378390
* irq_reserve_irqs - mark irqs allocated
@@ -440,7 +452,7 @@ void dynamic_irq_cleanup(unsigned int irq)
440452
unsigned long flags;
441453

442454
raw_spin_lock_irqsave(&desc->lock, flags);
443-
desc_set_defaults(irq, desc, desc_node(desc));
455+
desc_set_defaults(irq, desc, desc_node(desc), NULL);
444456
raw_spin_unlock_irqrestore(&desc->lock, flags);
445457
}
446458

kernel/irq/manage.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
883883

884884
if (desc->irq_data.chip == &no_irq_chip)
885885
return -ENOSYS;
886+
if (!try_module_get(desc->owner))
887+
return -ENODEV;
886888
/*
887889
* Some drivers like serial.c use request_irq() heavily,
888890
* so we have to be careful not to interfere with a
@@ -906,8 +908,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
906908
*/
907909
nested = irq_settings_is_nested_thread(desc);
908910
if (nested) {
909-
if (!new->thread_fn)
910-
return -EINVAL;
911+
if (!new->thread_fn) {
912+
ret = -EINVAL;
913+
goto out_mput;
914+
}
911915
/*
912916
* Replace the primary handler which was provided from
913917
* the driver for non nested interrupt handling by the
@@ -929,8 +933,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
929933

930934
t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
931935
new->name);
932-
if (IS_ERR(t))
933-
return PTR_ERR(t);
936+
if (IS_ERR(t)) {
937+
ret = PTR_ERR(t);
938+
goto out_mput;
939+
}
934940
/*
935941
* We keep the reference to the task struct even if
936942
* the thread dies to avoid that the interrupt code
@@ -1095,6 +1101,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
10951101
kthread_stop(t);
10961102
put_task_struct(t);
10971103
}
1104+
out_mput:
1105+
module_put(desc->owner);
10981106
return ret;
10991107
}
11001108

@@ -1203,6 +1211,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
12031211
put_task_struct(action->thread);
12041212
}
12051213

1214+
module_put(desc->owner);
12061215
return action;
12071216
}
12081217

0 commit comments

Comments
 (0)