376 lines
11 KiB
Diff
376 lines
11 KiB
Diff
From d852cd8bdf95687090cde35fc56c3a13cebccf9d Mon Sep 17 00:00:00 2001
|
|
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Fri, 11 Jan 2013 11:23:51 +0100
|
|
Subject: [PATCH 193/365] completion: Use simple wait queues
|
|
|
|
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.
|
|
|
|
Change-Id: I9345d2ae7c277c755c400c850adbef8ec4251485
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
---
|
|
.../wireless/intersil/orinoco/orinoco_usb.c | 2 +-
|
|
drivers/usb/gadget/function/f_fs.c | 2 +-
|
|
drivers/usb/gadget/legacy/inode.c | 4 +--
|
|
include/linux/completion.h | 9 +++---
|
|
include/linux/suspend.h | 6 ++++
|
|
include/linux/swait.h | 1 +
|
|
include/linux/uprobes.h | 1 +
|
|
kernel/power/hibernate.c | 7 ++++
|
|
kernel/power/suspend.c | 4 +++
|
|
kernel/sched/completion.c | 32 +++++++++----------
|
|
kernel/sched/core.c | 10 ++++--
|
|
kernel/sched/swait.c | 20 ++++++++++++
|
|
12 files changed, 71 insertions(+), 27 deletions(-)
|
|
|
|
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
|
|
index de928938c7a1..b8984b3f009f 100644
|
|
--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
|
|
+++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
|
|
@@ -697,7 +697,7 @@ static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
|
|
while (!ctx->done.done && msecs--)
|
|
udelay(1000);
|
|
} else {
|
|
- wait_event_interruptible(ctx->done.wait,
|
|
+ swait_event_interruptible(ctx->done.wait,
|
|
ctx->done.done);
|
|
}
|
|
break;
|
|
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
|
|
index aac010b466bf..0d897481c595 100644
|
|
--- a/drivers/usb/gadget/function/f_fs.c
|
|
+++ b/drivers/usb/gadget/function/f_fs.c
|
|
@@ -1611,7 +1611,7 @@ static void ffs_data_put(struct ffs_data *ffs)
|
|
pr_info("%s(): freeing\n", __func__);
|
|
ffs_data_clear(ffs);
|
|
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
|
|
- waitqueue_active(&ffs->ep0req_completion.wait));
|
|
+ swait_active(&ffs->ep0req_completion.wait));
|
|
kfree(ffs->dev_name);
|
|
kfree(ffs);
|
|
}
|
|
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
|
|
index de0f3c2c9f6f..d706d2e134d9 100644
|
|
--- a/drivers/usb/gadget/legacy/inode.c
|
|
+++ b/drivers/usb/gadget/legacy/inode.c
|
|
@@ -347,7 +347,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 (done.wait, done.done);
|
|
if (value != 0) {
|
|
spin_lock_irq (&epdata->dev->lock);
|
|
if (likely (epdata->ep != NULL)) {
|
|
@@ -356,7 +356,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 (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 5d5aaae3af43..3bca1590e29f 100644
|
|
--- a/include/linux/completion.h
|
|
+++ b/include/linux/completion.h
|
|
@@ -7,8 +7,7 @@
|
|
* Atomic wait-for-completion handler data structures.
|
|
* 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"
|
|
@@ -24,11 +23,11 @@
|
|
*/
|
|
struct completion {
|
|
unsigned int done;
|
|
- wait_queue_head_t wait;
|
|
+ struct swait_queue_head wait;
|
|
};
|
|
|
|
#define COMPLETION_INITIALIZER(work) \
|
|
- { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
|
|
+ { 0, __SWAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
|
|
|
|
#define COMPLETION_INITIALIZER_ONSTACK(work) \
|
|
({ init_completion(&work); work; })
|
|
@@ -73,7 +72,7 @@ struct completion {
|
|
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 98a4bcd28157..9c04639ea4b7 100644
|
|
--- a/include/linux/suspend.h
|
|
+++ b/include/linux/suspend.h
|
|
@@ -193,6 +193,12 @@ struct platform_freeze_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
|
|
/**
|
|
* suspend_set_ops - set platform dependent suspend operations
|
|
diff --git a/include/linux/swait.h b/include/linux/swait.h
|
|
index c1f9c62a8a50..83f004a72320 100644
|
|
--- a/include/linux/swait.h
|
|
+++ b/include/linux/swait.h
|
|
@@ -87,6 +87,7 @@ static inline int swait_active(struct swait_queue_head *q)
|
|
extern void swake_up(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(struct swait_queue_head *q, struct swait_queue *wait, int state);
|
|
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
|
|
index 4a29c75b146e..0a294e950df8 100644
|
|
--- a/include/linux/uprobes.h
|
|
+++ b/include/linux/uprobes.h
|
|
@@ -27,6 +27,7 @@
|
|
#include <linux/errno.h>
|
|
#include <linux/rbtree.h>
|
|
#include <linux/types.h>
|
|
+#include <linux/wait.h>
|
|
|
|
struct vm_area_struct;
|
|
struct mm_struct;
|
|
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
|
|
index 73ddd8143753..18f3162a9d39 100644
|
|
--- a/kernel/power/hibernate.c
|
|
+++ b/kernel/power/hibernate.c
|
|
@@ -692,6 +692,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.
|
|
*/
|
|
@@ -705,6 +709,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)) {
|
|
@@ -782,6 +788,7 @@ int hibernate(void)
|
|
atomic_inc(&snapshot_device_available);
|
|
Unlock:
|
|
unlock_system_sleep();
|
|
+ pm_in_action = false;
|
|
return error;
|
|
}
|
|
|
|
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
|
|
index 880c5a2d48b9..fe37a261a126 100644
|
|
--- a/kernel/power/suspend.c
|
|
+++ b/kernel/power/suspend.c
|
|
@@ -559,6 +559,7 @@ static void pm_suspend_marker(char *annotation)
|
|
annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
|
|
}
|
|
+bool pm_in_action;
|
|
|
|
/**
|
|
* pm_suspend - Externally visible function for suspending the system.
|
|
@@ -575,6 +576,8 @@ int pm_suspend(suspend_state_t state)
|
|
return -EINVAL;
|
|
|
|
pm_suspend_marker("entry");
|
|
+ pm_in_action = true;
|
|
+
|
|
error = enter_state(state);
|
|
if (error) {
|
|
suspend_stats.fail++;
|
|
@@ -583,6 +586,7 @@ int pm_suspend(suspend_state_t state)
|
|
suspend_stats.success++;
|
|
}
|
|
pm_suspend_marker("exit");
|
|
+ pm_in_action = false;
|
|
return error;
|
|
}
|
|
EXPORT_SYMBOL(pm_suspend);
|
|
diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
|
|
index 8d0f35debf35..b62cf6400fe0 100644
|
|
--- a/kernel/sched/completion.c
|
|
+++ b/kernel/sched/completion.c
|
|
@@ -30,10 +30,10 @@ void complete(struct completion *x)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&x->wait.lock, flags);
|
|
+ raw_spin_lock_irqsave(&x->wait.lock, flags);
|
|
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);
|
|
|
|
@@ -50,10 +50,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/2;
|
|
- __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);
|
|
|
|
@@ -62,20 +62,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_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;
|
|
}
|
|
@@ -89,9 +89,9 @@ __wait_for_common(struct completion *x,
|
|
{
|
|
might_sleep();
|
|
|
|
- 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);
|
|
return timeout;
|
|
}
|
|
|
|
@@ -277,12 +277,12 @@ bool try_wait_for_completion(struct completion *x)
|
|
if (!READ_ONCE(x->done))
|
|
return 0;
|
|
|
|
- spin_lock_irqsave(&x->wait.lock, flags);
|
|
+ raw_spin_lock_irqsave(&x->wait.lock, flags);
|
|
if (!x->done)
|
|
ret = 0;
|
|
else
|
|
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);
|
|
@@ -311,7 +311,7 @@ bool completion_done(struct completion *x)
|
|
* after it's acquired the lock.
|
|
*/
|
|
smp_rmb();
|
|
- spin_unlock_wait(&x->wait.lock);
|
|
+ raw_spin_unlock_wait(&x->wait.lock);
|
|
return true;
|
|
}
|
|
EXPORT_SYMBOL(completion_done);
|
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
|
index c0b0aa0411a6..d939f247c67f 100644
|
|
--- a/kernel/sched/core.c
|
|
+++ b/kernel/sched/core.c
|
|
@@ -3449,7 +3449,10 @@ void migrate_disable(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
|
|
|
|
if (p->migrate_disable) {
|
|
@@ -3476,7 +3479,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 9c2da06a8869..a26906faf07e 100644
|
|
--- a/kernel/sched/swait.c
|
|
+++ b/kernel/sched/swait.c
|
|
@@ -1,5 +1,6 @@
|
|
#include <linux/sched.h>
|
|
#include <linux/swait.h>
|
|
+#include <linux/suspend.h>
|
|
|
|
void __init_swait_queue_head(struct swait_queue_head *q, const char *name,
|
|
struct lock_class_key *key)
|
|
@@ -29,6 +30,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(struct swait_queue_head *q)
|
|
{
|
|
unsigned long flags;
|
|
--
|
|
2.28.0
|
|
|