summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0095-completion-Use-simple-wait-queues.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0095-completion-Use-simple-wait-queues.patch')
-rw-r--r--debian/patches-rt/0095-completion-Use-simple-wait-queues.patch391
1 files changed, 391 insertions, 0 deletions
diff --git a/debian/patches-rt/0095-completion-Use-simple-wait-queues.patch b/debian/patches-rt/0095-completion-Use-simple-wait-queues.patch
new file mode 100644
index 000000000..34be7740f
--- /dev/null
+++ b/debian/patches-rt/0095-completion-Use-simple-wait-queues.patch
@@ -0,0 +1,391 @@
+From 6a60230ca64d58b651171ad00c84b251a7fd2046 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Fri, 11 Jan 2013 11:23:51 +0100
+Subject: [PATCH 095/347] completion: Use simple wait queues
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.246-rt110.tar.xz
+
+Completions have no long lasting callbacks and therefor do not need
+the complex waitqueue variant. Use simple waitqueues which reduces the
+contention on the waitqueue lock.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+---
+ arch/powerpc/platforms/ps3/device-init.c | 4 +--
+ .../wireless/intersil/orinoco/orinoco_usb.c | 4 +--
+ drivers/usb/gadget/function/f_fs.c | 2 +-
+ drivers/usb/gadget/legacy/inode.c | 4 +--
+ include/linux/completion.h | 8 ++---
+ include/linux/suspend.h | 6 ++++
+ include/linux/swait.h | 2 ++
+ kernel/power/hibernate.c | 7 ++++
+ kernel/power/suspend.c | 4 +++
+ kernel/sched/completion.c | 34 +++++++++----------
+ kernel/sched/core.c | 10 ++++--
+ kernel/sched/swait.c | 21 +++++++++++-
+ 12 files changed, 75 insertions(+), 31 deletions(-)
+
+diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c
+index e7075aaff1bb..1580464a9d5b 100644
+--- a/arch/powerpc/platforms/ps3/device-init.c
++++ b/arch/powerpc/platforms/ps3/device-init.c
+@@ -752,8 +752,8 @@ static int ps3_notification_read_write(struct ps3_notification_device *dev,
+ }
+ pr_debug("%s:%u: notification %s issued\n", __func__, __LINE__, op);
+
+- res = wait_event_interruptible(dev->done.wait,
+- dev->done.done || kthread_should_stop());
++ res = swait_event_interruptible_exclusive(dev->done.wait,
++ dev->done.done || kthread_should_stop());
+ if (kthread_should_stop())
+ res = -EINTR;
+ if (res) {
+diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+index a04d59843022..e0046c35a0bd 100644
+--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
++++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+@@ -697,8 +697,8 @@ static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
+ while (!ctx->done.done && msecs--)
+ udelay(1000);
+ } else {
+- wait_event_interruptible(ctx->done.wait,
+- ctx->done.done);
++ swait_event_interruptible_exclusive(ctx->done.wait,
++ ctx->done.done);
+ }
+ break;
+ default:
+diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
+index 49eb4e3c760f..49fc75368aa2 100644
+--- a/drivers/usb/gadget/function/f_fs.c
++++ b/drivers/usb/gadget/function/f_fs.c
+@@ -1626,7 +1626,7 @@ static void ffs_data_put(struct ffs_data *ffs)
+ ffs_data_clear(ffs);
+ ffs_release_dev(ffs->private_data);
+ BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
+- waitqueue_active(&ffs->ep0req_completion.wait) ||
++ swait_active(&ffs->ep0req_completion.wait) ||
+ waitqueue_active(&ffs->wait));
+ destroy_workqueue(ffs->io_completion_wq);
+ kfree(ffs->dev_name);
+diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
+index 3ebcbd199a79..a2240aa9f4ab 100644
+--- a/drivers/usb/gadget/legacy/inode.c
++++ b/drivers/usb/gadget/legacy/inode.c
+@@ -345,7 +345,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
+ spin_unlock_irq (&epdata->dev->lock);
+
+ if (likely (value == 0)) {
+- value = wait_event_interruptible (done.wait, done.done);
++ value = swait_event_interruptible_exclusive(done.wait, done.done);
+ if (value != 0) {
+ spin_lock_irq (&epdata->dev->lock);
+ if (likely (epdata->ep != NULL)) {
+@@ -354,7 +354,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
+ usb_ep_dequeue (epdata->ep, epdata->req);
+ spin_unlock_irq (&epdata->dev->lock);
+
+- wait_event (done.wait, done.done);
++ swait_event_exclusive(done.wait, done.done);
+ if (epdata->status == -ECONNRESET)
+ epdata->status = -EINTR;
+ } else {
+diff --git a/include/linux/completion.h b/include/linux/completion.h
+index 519e94915d18..bf8e77001f18 100644
+--- a/include/linux/completion.h
++++ b/include/linux/completion.h
+@@ -9,7 +9,7 @@
+ * See kernel/sched/completion.c for details.
+ */
+
+-#include <linux/wait.h>
++#include <linux/swait.h>
+
+ /*
+ * struct completion - structure used to maintain state for a "completion"
+@@ -25,7 +25,7 @@
+ */
+ struct completion {
+ unsigned int done;
+- wait_queue_head_t wait;
++ struct swait_queue_head wait;
+ };
+
+ #define init_completion_map(x, m) __init_completion(x)
+@@ -34,7 +34,7 @@ static inline void complete_acquire(struct completion *x) {}
+ static inline void complete_release(struct completion *x) {}
+
+ #define COMPLETION_INITIALIZER(work) \
+- { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
++ { 0, __SWAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
+
+ #define COMPLETION_INITIALIZER_ONSTACK_MAP(work, map) \
+ (*({ init_completion_map(&(work), &(map)); &(work); }))
+@@ -85,7 +85,7 @@ static inline void complete_release(struct completion *x) {}
+ static inline void __init_completion(struct completion *x)
+ {
+ x->done = 0;
+- init_waitqueue_head(&x->wait);
++ init_swait_queue_head(&x->wait);
+ }
+
+ /**
+diff --git a/include/linux/suspend.h b/include/linux/suspend.h
+index 3f529ad9a9d2..328439ce71f5 100644
+--- a/include/linux/suspend.h
++++ b/include/linux/suspend.h
+@@ -196,6 +196,12 @@ struct platform_s2idle_ops {
+ void (*end)(void);
+ };
+
++#if defined(CONFIG_SUSPEND) || defined(CONFIG_HIBERNATION)
++extern bool pm_in_action;
++#else
++# define pm_in_action false
++#endif
++
+ #ifdef CONFIG_SUSPEND
+ extern suspend_state_t mem_sleep_current;
+ extern suspend_state_t mem_sleep_default;
+diff --git a/include/linux/swait.h b/include/linux/swait.h
+index 73e06e9986d4..f426a0661aa0 100644
+--- a/include/linux/swait.h
++++ b/include/linux/swait.h
+@@ -160,7 +160,9 @@ static inline bool swq_has_sleeper(struct swait_queue_head *wq)
+ extern void swake_up_one(struct swait_queue_head *q);
+ extern void swake_up_all(struct swait_queue_head *q);
+ extern void swake_up_locked(struct swait_queue_head *q);
++extern void swake_up_all_locked(struct swait_queue_head *q);
+
++extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait);
+ extern void prepare_to_swait_exclusive(struct swait_queue_head *q, struct swait_queue *wait, int state);
+ extern long prepare_to_swait_event(struct swait_queue_head *q, struct swait_queue *wait, int state);
+
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index 6abdfdf571ee..7020a6582a4c 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -690,6 +690,10 @@ static int load_image_and_restore(void)
+ return error;
+ }
+
++#ifndef CONFIG_SUSPEND
++bool pm_in_action;
++#endif
++
+ /**
+ * hibernate - Carry out system hibernation, including saving the image.
+ */
+@@ -703,6 +707,8 @@ int hibernate(void)
+ return -EPERM;
+ }
+
++ pm_in_action = true;
++
+ lock_system_sleep();
+ /* The snapshot device should not be opened while we're running */
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+@@ -781,6 +787,7 @@ int hibernate(void)
+ atomic_inc(&snapshot_device_available);
+ Unlock:
+ unlock_system_sleep();
++ pm_in_action = false;
+ pr_info("hibernation exit\n");
+
+ return error;
+diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
+index 0bd595a0b610..a4456772d98e 100644
+--- a/kernel/power/suspend.c
++++ b/kernel/power/suspend.c
+@@ -600,6 +600,8 @@ static int enter_state(suspend_state_t state)
+ return error;
+ }
+
++bool pm_in_action;
++
+ /**
+ * pm_suspend - Externally visible function for suspending the system.
+ * @state: System sleep state to enter.
+@@ -614,6 +616,7 @@ int pm_suspend(suspend_state_t state)
+ if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
+ return -EINVAL;
+
++ pm_in_action = true;
+ pr_info("suspend entry (%s)\n", mem_sleep_labels[state]);
+ error = enter_state(state);
+ if (error) {
+@@ -623,6 +626,7 @@ int pm_suspend(suspend_state_t state)
+ suspend_stats.success++;
+ }
+ pr_info("suspend exit\n");
++ pm_in_action = false;
+ return error;
+ }
+ EXPORT_SYMBOL(pm_suspend);
+diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
+index a1ad5b7d5521..755a58084978 100644
+--- a/kernel/sched/completion.c
++++ b/kernel/sched/completion.c
+@@ -29,12 +29,12 @@ void complete(struct completion *x)
+ {
+ unsigned long flags;
+
+- spin_lock_irqsave(&x->wait.lock, flags);
++ raw_spin_lock_irqsave(&x->wait.lock, flags);
+
+ if (x->done != UINT_MAX)
+ x->done++;
+- __wake_up_locked(&x->wait, TASK_NORMAL, 1);
+- spin_unlock_irqrestore(&x->wait.lock, flags);
++ swake_up_locked(&x->wait);
++ raw_spin_unlock_irqrestore(&x->wait.lock, flags);
+ }
+ EXPORT_SYMBOL(complete);
+
+@@ -58,10 +58,10 @@ void complete_all(struct completion *x)
+ {
+ unsigned long flags;
+
+- spin_lock_irqsave(&x->wait.lock, flags);
++ raw_spin_lock_irqsave(&x->wait.lock, flags);
+ x->done = UINT_MAX;
+- __wake_up_locked(&x->wait, TASK_NORMAL, 0);
+- spin_unlock_irqrestore(&x->wait.lock, flags);
++ swake_up_all_locked(&x->wait);
++ raw_spin_unlock_irqrestore(&x->wait.lock, flags);
+ }
+ EXPORT_SYMBOL(complete_all);
+
+@@ -70,20 +70,20 @@ do_wait_for_common(struct completion *x,
+ long (*action)(long), long timeout, int state)
+ {
+ if (!x->done) {
+- DECLARE_WAITQUEUE(wait, current);
++ DECLARE_SWAITQUEUE(wait);
+
+- __add_wait_queue_entry_tail_exclusive(&x->wait, &wait);
++ __prepare_to_swait(&x->wait, &wait);
+ do {
+ if (signal_pending_state(state, current)) {
+ timeout = -ERESTARTSYS;
+ break;
+ }
+ __set_current_state(state);
+- spin_unlock_irq(&x->wait.lock);
++ raw_spin_unlock_irq(&x->wait.lock);
+ timeout = action(timeout);
+- spin_lock_irq(&x->wait.lock);
++ raw_spin_lock_irq(&x->wait.lock);
+ } while (!x->done && timeout);
+- __remove_wait_queue(&x->wait, &wait);
++ __finish_swait(&x->wait, &wait);
+ if (!x->done)
+ return timeout;
+ }
+@@ -100,9 +100,9 @@ __wait_for_common(struct completion *x,
+
+ complete_acquire(x);
+
+- spin_lock_irq(&x->wait.lock);
++ raw_spin_lock_irq(&x->wait.lock);
+ timeout = do_wait_for_common(x, action, timeout, state);
+- spin_unlock_irq(&x->wait.lock);
++ raw_spin_unlock_irq(&x->wait.lock);
+
+ complete_release(x);
+
+@@ -291,12 +291,12 @@ bool try_wait_for_completion(struct completion *x)
+ if (!READ_ONCE(x->done))
+ return false;
+
+- spin_lock_irqsave(&x->wait.lock, flags);
++ raw_spin_lock_irqsave(&x->wait.lock, flags);
+ if (!x->done)
+ ret = false;
+ else if (x->done != UINT_MAX)
+ x->done--;
+- spin_unlock_irqrestore(&x->wait.lock, flags);
++ raw_spin_unlock_irqrestore(&x->wait.lock, flags);
+ return ret;
+ }
+ EXPORT_SYMBOL(try_wait_for_completion);
+@@ -322,8 +322,8 @@ bool completion_done(struct completion *x)
+ * otherwise we can end up freeing the completion before complete()
+ * is done referencing it.
+ */
+- spin_lock_irqsave(&x->wait.lock, flags);
+- spin_unlock_irqrestore(&x->wait.lock, flags);
++ raw_spin_lock_irqsave(&x->wait.lock, flags);
++ raw_spin_unlock_irqrestore(&x->wait.lock, flags);
+ return true;
+ }
+ EXPORT_SYMBOL(completion_done);
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index 974d92afd23e..3c5999476609 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -7157,7 +7157,10 @@ void migrate_disable(void)
+ return;
+ }
+ #ifdef CONFIG_SCHED_DEBUG
+- WARN_ON_ONCE(p->migrate_disable_atomic);
++ if (unlikely(p->migrate_disable_atomic)) {
++ tracing_off();
++ WARN_ON_ONCE(1);
++ }
+ #endif
+
+ if (p->migrate_disable) {
+@@ -7187,7 +7190,10 @@ void migrate_enable(void)
+ }
+
+ #ifdef CONFIG_SCHED_DEBUG
+- WARN_ON_ONCE(p->migrate_disable_atomic);
++ if (unlikely(p->migrate_disable_atomic)) {
++ tracing_off();
++ WARN_ON_ONCE(1);
++ }
+ #endif
+
+ WARN_ON_ONCE(p->migrate_disable <= 0);
+diff --git a/kernel/sched/swait.c b/kernel/sched/swait.c
+index 66b59ac77c22..c7cb30cdd1b7 100644
+--- a/kernel/sched/swait.c
++++ b/kernel/sched/swait.c
+@@ -32,6 +32,25 @@ void swake_up_locked(struct swait_queue_head *q)
+ }
+ EXPORT_SYMBOL(swake_up_locked);
+
++void swake_up_all_locked(struct swait_queue_head *q)
++{
++ struct swait_queue *curr;
++ int wakes = 0;
++
++ while (!list_empty(&q->task_list)) {
++
++ curr = list_first_entry(&q->task_list, typeof(*curr),
++ task_list);
++ wake_up_process(curr->task);
++ list_del_init(&curr->task_list);
++ wakes++;
++ }
++ if (pm_in_action)
++ return;
++ WARN(wakes > 2, "complete_all() with %d waiters\n", wakes);
++}
++EXPORT_SYMBOL(swake_up_all_locked);
++
+ void swake_up_one(struct swait_queue_head *q)
+ {
+ unsigned long flags;
+@@ -69,7 +88,7 @@ void swake_up_all(struct swait_queue_head *q)
+ }
+ EXPORT_SYMBOL(swake_up_all);
+
+-static void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait)
++void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait)
+ {
+ wait->task = current;
+ if (list_empty(&wait->task_list))
+--
+2.36.1
+