65 lines
2.4 KiB
Diff
65 lines
2.4 KiB
Diff
From: Oleg Nesterov <oleg@redhat.com>
|
|
Date: Thu, 3 Nov 2011 16:07:49 -0700
|
|
Subject: [PATCH] PM / Freezer: Reimplement wait_event_freezekillable using
|
|
freezer_do_not_count/freezer_count
|
|
|
|
commit 6f35c4abd7f0294166a5e0ab0401fe7949b33034 upstream.
|
|
|
|
Commit 27920651fe "PM / Freezer: Make fake_signal_wake_up() wake
|
|
TASK_KILLABLE tasks too" updated fake_signal_wake_up() used by freezer
|
|
to wake up KILLABLE tasks. Sending unsolicited wakeups to tasks in
|
|
killable sleep is dangerous as there are code paths which depend on
|
|
tasks not waking up spuriously from KILLABLE sleep.
|
|
|
|
For example. sys_read() or page can sleep in TASK_KILLABLE assuming
|
|
that wait/down/whatever _killable can only fail if we can not return
|
|
to the usermode. TASK_TRACED is another obvious example.
|
|
|
|
The offending commit was to resolve freezer hang during system PM
|
|
operations caused by KILLABLE sleeps in network filesystems.
|
|
wait_event_freezekillable(), which depends on the spurious KILLABLE
|
|
wakeup, was added by f06ac72e92 "cifs, freezer: add
|
|
wait_event_freezekillable and have cifs use it" to be used to
|
|
implement killable & freezable sleeps in network filesystems.
|
|
|
|
To prepare for reverting of 27920651fe, this patch reimplements
|
|
wait_event_freezekillable() using freezer_do_not_count/freezer_count()
|
|
so that it doesn't depend on the spurious KILLABLE wakeup. This isn't
|
|
very nice but should do for now.
|
|
|
|
[tj: Refreshed patch to apply to linus/master and updated commit
|
|
description on Rafael's request.]
|
|
|
|
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
|
|
---
|
|
include/linux/freezer.h | 11 +++--------
|
|
1 files changed, 3 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
|
|
index a49b529..a5386e3 100644
|
|
--- a/include/linux/freezer.h
|
|
+++ b/include/linux/freezer.h
|
|
@@ -143,14 +143,9 @@ static inline void set_freezable_with_signal(void)
|
|
#define wait_event_freezekillable(wq, condition) \
|
|
({ \
|
|
int __retval; \
|
|
- do { \
|
|
- __retval = wait_event_killable(wq, \
|
|
- (condition) || freezing(current)); \
|
|
- if (__retval && !freezing(current)) \
|
|
- break; \
|
|
- else if (!(condition)) \
|
|
- __retval = -ERESTARTSYS; \
|
|
- } while (try_to_freeze()); \
|
|
+ freezer_do_not_count(); \
|
|
+ __retval = wait_event_killable(wq, (condition)); \
|
|
+ freezer_count(); \
|
|
__retval; \
|
|
})
|
|
|
|
--
|
|
1.7.7.2
|
|
|