1 From f2026ab95a3cee03145a08474c3feec39cbaad22 Mon Sep 17 00:00:00 2001
2 From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
3 Date: Wed, 21 Aug 2013 17:48:46 +0200
4 Subject: [PATCH 056/365] genirq: Do not invoke the affinity callback via a
7 Joe Korty reported, that __irq_set_affinity_locked() schedules a
8 workqueue while holding a rawlock which results in a might_sleep()
10 This patch moves the invokation into a process context so that we only
11 wakeup() a process while holding the lock.
13 Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
15 include/linux/interrupt.h | 1 +
16 kernel/irq/manage.c | 79 +++++++++++++++++++++++++++++++++++++++++++++--
17 2 files changed, 77 insertions(+), 3 deletions(-)
19 diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
20 index 48407e6..248380d 100644
21 --- a/include/linux/interrupt.h
22 +++ b/include/linux/interrupt.h
23 @@ -217,6 +217,7 @@ struct irq_affinity_notify {
26 struct work_struct work;
27 + struct list_head list;
28 void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask);
29 void (*release)(struct kref *ref);
31 diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
32 index 8ca0dcd..8842388 100644
33 --- a/kernel/irq/manage.c
34 +++ b/kernel/irq/manage.c
35 @@ -183,6 +183,62 @@ static inline void
36 irq_get_pending(struct cpumask *mask, struct irq_desc *desc) { }
39 +#ifdef CONFIG_PREEMPT_RT_FULL
40 +static void _irq_affinity_notify(struct irq_affinity_notify *notify);
41 +static struct task_struct *set_affinity_helper;
42 +static LIST_HEAD(affinity_list);
43 +static DEFINE_RAW_SPINLOCK(affinity_list_lock);
45 +static int set_affinity_thread(void *unused)
48 + struct irq_affinity_notify *notify;
51 + set_current_state(TASK_INTERRUPTIBLE);
53 + raw_spin_lock_irq(&affinity_list_lock);
54 + empty = list_empty(&affinity_list);
55 + raw_spin_unlock_irq(&affinity_list_lock);
59 + if (kthread_should_stop())
61 + set_current_state(TASK_RUNNING);
65 + raw_spin_lock_irq(&affinity_list_lock);
66 + if (!list_empty(&affinity_list)) {
67 + notify = list_first_entry(&affinity_list,
68 + struct irq_affinity_notify, list);
69 + list_del_init(¬ify->list);
71 + raw_spin_unlock_irq(&affinity_list_lock);
75 + _irq_affinity_notify(notify);
81 +static void init_helper_thread(void)
83 + if (set_affinity_helper)
85 + set_affinity_helper = kthread_run(set_affinity_thread, NULL,
87 + WARN_ON(IS_ERR(set_affinity_helper));
91 +static inline void init_helper_thread(void) { }
95 int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
98 @@ -222,7 +278,17 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
100 if (desc->affinity_notify) {
101 kref_get(&desc->affinity_notify->kref);
103 +#ifdef CONFIG_PREEMPT_RT_FULL
104 + raw_spin_lock(&affinity_list_lock);
105 + if (list_empty(&desc->affinity_notify->list))
106 + list_add_tail(&affinity_list,
107 + &desc->affinity_notify->list);
108 + raw_spin_unlock(&affinity_list_lock);
109 + wake_up_process(set_affinity_helper);
111 schedule_work(&desc->affinity_notify->work);
114 irqd_set(data, IRQD_AFFINITY_SET);
116 @@ -260,10 +326,8 @@ int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m)
118 EXPORT_SYMBOL_GPL(irq_set_affinity_hint);
120 -static void irq_affinity_notify(struct work_struct *work)
121 +static void _irq_affinity_notify(struct irq_affinity_notify *notify)
123 - struct irq_affinity_notify *notify =
124 - container_of(work, struct irq_affinity_notify, work);
125 struct irq_desc *desc = irq_to_desc(notify->irq);
126 cpumask_var_t cpumask;
128 @@ -285,6 +349,13 @@ out:
129 kref_put(¬ify->kref, notify->release);
132 +static void irq_affinity_notify(struct work_struct *work)
134 + struct irq_affinity_notify *notify =
135 + container_of(work, struct irq_affinity_notify, work);
136 + _irq_affinity_notify(notify);
140 * irq_set_affinity_notifier - control notification of IRQ affinity changes
141 * @irq: Interrupt for which to enable/disable notification
142 @@ -314,6 +385,8 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
144 kref_init(¬ify->kref);
145 INIT_WORK(¬ify->work, irq_affinity_notify);
146 + INIT_LIST_HEAD(¬ify->list);
147 + init_helper_thread();
150 raw_spin_lock_irqsave(&desc->lock, flags);