diff options
Diffstat (limited to 'debian/patches-rt/0191-workqueue-Use-local-irq-lock-instead-of-irq-disable-.patch')
-rw-r--r-- | debian/patches-rt/0191-workqueue-Use-local-irq-lock-instead-of-irq-disable-.patch | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/debian/patches-rt/0191-workqueue-Use-local-irq-lock-instead-of-irq-disable-.patch b/debian/patches-rt/0191-workqueue-Use-local-irq-lock-instead-of-irq-disable-.patch new file mode 100644 index 000000000..d77219e80 --- /dev/null +++ b/debian/patches-rt/0191-workqueue-Use-local-irq-lock-instead-of-irq-disable-.patch @@ -0,0 +1,186 @@ +From c05bd3f09ed30bc24aa6a2fe5cfc0abd2fe883b3 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Sun, 17 Jul 2011 21:42:26 +0200 +Subject: [PATCH 191/347] workqueue: Use local irq lock instead of irq disable + regions +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.246-rt110.tar.xz + +Use a local_irq_lock as a replacement for irq off regions. We keep the +semantic of irq-off in regard to the pool->lock and remain preemptible. + +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +--- + kernel/workqueue.c | 45 ++++++++++++++++++++++++++++++--------------- + 1 file changed, 30 insertions(+), 15 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 3e2f67b77ab8..2b4c052c51b3 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -50,6 +50,7 @@ + #include <linux/sched/isolation.h> + #include <linux/nmi.h> + #include <linux/kvm_para.h> ++#include <linux/locallock.h> + + #include "workqueue_internal.h" + +@@ -351,6 +352,8 @@ EXPORT_SYMBOL_GPL(system_power_efficient_wq); + struct workqueue_struct *system_freezable_power_efficient_wq __read_mostly; + EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq); + ++static DEFINE_LOCAL_IRQ_LOCK(pendingb_lock); ++ + static int worker_thread(void *__worker); + static void workqueue_sysfs_unregister(struct workqueue_struct *wq); + +@@ -1104,9 +1107,11 @@ static void put_pwq_unlocked(struct pool_workqueue *pwq) + * As both pwqs and pools are RCU protected, the + * following lock operations are safe. + */ +- spin_lock_irq(&pwq->pool->lock); ++ rcu_read_lock(); ++ local_spin_lock_irq(pendingb_lock, &pwq->pool->lock); + put_pwq(pwq); +- spin_unlock_irq(&pwq->pool->lock); ++ local_spin_unlock_irq(pendingb_lock, &pwq->pool->lock); ++ rcu_read_unlock(); + } + } + +@@ -1210,7 +1215,7 @@ static int try_to_grab_pending(struct work_struct *work, bool is_dwork, + struct worker_pool *pool; + struct pool_workqueue *pwq; + +- local_irq_save(*flags); ++ local_lock_irqsave(pendingb_lock, *flags); + + /* try to steal the timer if it exists */ + if (is_dwork) { +@@ -1274,7 +1279,7 @@ static int try_to_grab_pending(struct work_struct *work, bool is_dwork, + spin_unlock(&pool->lock); + fail: + rcu_read_unlock(); +- local_irq_restore(*flags); ++ local_unlock_irqrestore(pendingb_lock, *flags); + if (work_is_canceling(work)) + return -ENOENT; + cpu_relax(); +@@ -1379,7 +1384,13 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, + * queued or lose PENDING. Grabbing PENDING and queueing should + * happen with IRQ disabled. + */ ++#ifndef CONFIG_PREEMPT_RT_FULL ++ /* ++ * nort: On RT the "interrupts-disabled" rule has been replaced with ++ * pendingb_lock. ++ */ + lockdep_assert_irqs_disabled(); ++#endif + + + /* if draining, only works from the same workqueue are allowed */ +@@ -1487,14 +1498,14 @@ bool queue_work_on(int cpu, struct workqueue_struct *wq, + bool ret = false; + unsigned long flags; + +- local_irq_save(flags); ++ local_lock_irqsave(pendingb_lock,flags); + + if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) { + __queue_work(cpu, wq, work); + ret = true; + } + +- local_irq_restore(flags); ++ local_unlock_irqrestore(pendingb_lock, flags); + return ret; + } + EXPORT_SYMBOL(queue_work_on); +@@ -1503,8 +1514,11 @@ void delayed_work_timer_fn(struct timer_list *t) + { + struct delayed_work *dwork = from_timer(dwork, t, timer); + ++ /* XXX */ ++ /* local_lock(pendingb_lock); */ + /* should have been called from irqsafe timer with irq already off */ + __queue_work(dwork->cpu, dwork->wq, &dwork->work); ++ /* local_unlock(pendingb_lock); */ + } + EXPORT_SYMBOL(delayed_work_timer_fn); + +@@ -1559,14 +1573,14 @@ bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq, + unsigned long flags; + + /* read the comment in __queue_work() */ +- local_irq_save(flags); ++ local_lock_irqsave(pendingb_lock, flags); + + if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) { + __queue_delayed_work(cpu, wq, dwork, delay); + ret = true; + } + +- local_irq_restore(flags); ++ local_unlock_irqrestore(pendingb_lock, flags); + return ret; + } + EXPORT_SYMBOL(queue_delayed_work_on); +@@ -1601,7 +1615,7 @@ bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq, + + if (likely(ret >= 0)) { + __queue_delayed_work(cpu, wq, dwork, delay); +- local_irq_restore(flags); ++ local_unlock_irqrestore(pendingb_lock, flags); + } + + /* -ENOENT from try_to_grab_pending() becomes %true */ +@@ -1612,11 +1626,12 @@ EXPORT_SYMBOL_GPL(mod_delayed_work_on); + static void rcu_work_rcufn(struct rcu_head *rcu) + { + struct rcu_work *rwork = container_of(rcu, struct rcu_work, rcu); ++ unsigned long flags; + + /* read the comment in __queue_work() */ +- local_irq_disable(); ++ local_lock_irqsave(pendingb_lock, flags); + __queue_work(WORK_CPU_UNBOUND, rwork->wq, &rwork->work); +- local_irq_enable(); ++ local_unlock_irqrestore(pendingb_lock, flags); + } + + /** +@@ -3008,7 +3023,7 @@ static bool __cancel_work_timer(struct work_struct *work, bool is_dwork) + + /* tell other tasks trying to grab @work to back off */ + mark_work_canceling(work); +- local_irq_restore(flags); ++ local_unlock_irqrestore(pendingb_lock, flags); + + /* + * This allows canceling during early boot. We know that @work +@@ -3069,10 +3084,10 @@ EXPORT_SYMBOL_GPL(cancel_work_sync); + */ + bool flush_delayed_work(struct delayed_work *dwork) + { +- local_irq_disable(); ++ local_lock_irq(pendingb_lock); + if (del_timer_sync(&dwork->timer)) + __queue_work(dwork->cpu, dwork->wq, &dwork->work); +- local_irq_enable(); ++ local_unlock_irq(pendingb_lock); + return flush_work(&dwork->work); + } + EXPORT_SYMBOL(flush_delayed_work); +@@ -3110,7 +3125,7 @@ static bool __cancel_work(struct work_struct *work, bool is_dwork) + return false; + + set_work_pool_and_clear_pending(work, get_work_pool_id(work)); +- local_irq_restore(flags); ++ local_unlock_irqrestore(pendingb_lock, flags); + return ret; + } + +-- +2.36.1 + |