aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-12-13 03:34:30 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-13 12:05:49 -0500
commit8a102eed9c4e1d21bad07a8fd97bd4fbf125d966 (patch)
tree9ec99f046b94971db46b08a87d7eab3e84c4acd4 /include/linux
parent3df494a32b936aef76d893f5065f962ebd9b9437 (diff)
[PATCH] PM: Fix SMP races in the freezer
Currently, to tell a task that it should go to the refrigerator, we set the PF_FREEZE flag for it and send a fake signal to it. Unfortunately there are two SMP-related problems with this approach. First, a task running on another CPU may be updating its flags while the freezer attempts to set PF_FREEZE for it and this may leave the task's flags in an inconsistent state. Second, there is a potential race between freeze_process() and refrigerator() in which freeze_process() running on one CPU is reading a task's PF_FREEZE flag while refrigerator() running on another CPU has just set PF_FROZEN for the same task and attempts to reset PF_FREEZE for it. If the refrigerator wins the race, freeze_process() will state that PF_FREEZE hasn't been set for the task and will set it unnecessarily, so the task will go to the refrigerator once again after it's been thawed. To solve first of these problems we need to stop using PF_FREEZE to tell tasks that they should go to the refrigerator. Instead, we can introduce a special TIF_*** flag and use it for this purpose, since it is allowed to change the other tasks' TIF_*** flags and there are special calls for it. To avoid the freeze_process()-refrigerator() race we can make freeze_process() to always check the task's PF_FROZEN flag after it's read its "freeze" flag. We should also make sure that refrigerator() will always reset the task's "freeze" flag after it's set PF_FROZEN for it. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Cc: Russell King <rmk@arm.linux.org.uk> Cc: David Howells <dhowells@redhat.com> Cc: Andi Kleen <ak@muc.de> Cc: "Luck, Tony" <tony.luck@intel.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/freezer.h11
-rw-r--r--include/linux/sched.h1
2 files changed, 6 insertions, 6 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 393063096134..5e75e26d4787 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -16,16 +16,15 @@ static inline int frozen(struct task_struct *p)
16 */ 16 */
17static inline int freezing(struct task_struct *p) 17static inline int freezing(struct task_struct *p)
18{ 18{
19 return p->flags & PF_FREEZE; 19 return test_tsk_thread_flag(p, TIF_FREEZE);
20} 20}
21 21
22/* 22/*
23 * Request that a process be frozen 23 * Request that a process be frozen
24 * FIXME: SMP problem. We may not modify other process' flags!
25 */ 24 */
26static inline void freeze(struct task_struct *p) 25static inline void freeze(struct task_struct *p)
27{ 26{
28 p->flags |= PF_FREEZE; 27 set_tsk_thread_flag(p, TIF_FREEZE);
29} 28}
30 29
31/* 30/*
@@ -33,7 +32,7 @@ static inline void freeze(struct task_struct *p)
33 */ 32 */
34static inline void do_not_freeze(struct task_struct *p) 33static inline void do_not_freeze(struct task_struct *p)
35{ 34{
36 p->flags &= ~PF_FREEZE; 35 clear_tsk_thread_flag(p, TIF_FREEZE);
37} 36}
38 37
39/* 38/*
@@ -54,7 +53,9 @@ static inline int thaw_process(struct task_struct *p)
54 */ 53 */
55static inline void frozen_process(struct task_struct *p) 54static inline void frozen_process(struct task_struct *p)
56{ 55{
57 p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN; 56 p->flags |= PF_FROZEN;
57 wmb();
58 clear_tsk_thread_flag(p, TIF_FREEZE);
58} 59}
59 60
60extern void refrigerator(void); 61extern void refrigerator(void);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index ea92e5c89089..446373535190 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1144,7 +1144,6 @@ static inline void put_task_struct(struct task_struct *t)
1144#define PF_MEMALLOC 0x00000800 /* Allocating memory */ 1144#define PF_MEMALLOC 0x00000800 /* Allocating memory */
1145#define PF_FLUSHER 0x00001000 /* responsible for disk writeback */ 1145#define PF_FLUSHER 0x00001000 /* responsible for disk writeback */
1146#define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ 1146#define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */
1147#define PF_FREEZE 0x00004000 /* this task is being frozen for suspend now */
1148#define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ 1147#define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */
1149#define PF_FROZEN 0x00010000 /* frozen for system suspend */ 1148#define PF_FROZEN 0x00010000 /* frozen for system suspend */
1150#define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ 1149#define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */