Currently, the PF_FREEZE process flag is used to indicate that the process should enter the refrigerator as soon as possible. Unfortunately it is set by the freezer while the process may be changing its flags for another reason and this may lead to a race between the freezer and the process itself. This problem may be solved by introducing an additional member, called (for example) 'freezing', into task_struct which will only be used to indicate that the process should enter the refrigerator. Then, if the 'freezing' member of task_struct is reset by the process itself only after it has entered the refrigerator, the modifications of it will be guaranteed to occur at different times, because the freezer can only set it before the process enters the refrigerator. Thus the code will be SMP-safe even though no explicit locking is used. Signed-off-by: Rafael J. Wysocki <rjw at sisk.pl> --- include/linux/freezer.h | 10 +++++----- include/linux/sched.h | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) Index: linux-2.6.19-rc6-mm1/include/linux/freezer.h =================================================================== --- linux-2.6.19-rc6-mm1.orig/include/linux/freezer.h +++ linux-2.6.19-rc6-mm1/include/linux/freezer.h @@ -14,16 +14,15 @@ static inline int frozen(struct task_str */ static inline int freezing(struct task_struct *p) { - return p->flags & PF_FREEZE; + return !!p->freezing; } /* * Request that a process be frozen - * FIXME: SMP problem. We may not modify other process' flags! */ static inline void freeze(struct task_struct *p) { - p->flags |= PF_FREEZE; + p->freezing = 1; } /* @@ -31,7 +30,7 @@ static inline void freeze(struct task_st */ static inline void do_not_freeze(struct task_struct *p) { - p->flags &= ~PF_FREEZE; + p->freezing = 0; } /* @@ -52,7 +51,8 @@ static inline int thaw_process(struct ta */ static inline void frozen_process(struct task_struct *p) { - p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN; + p->flags |= PF_FROZEN; + p->freezing = 0; } extern void refrigerator(void); Index: linux-2.6.19-rc6-mm1/include/linux/sched.h =================================================================== --- linux-2.6.19-rc6-mm1.orig/include/linux/sched.h +++ linux-2.6.19-rc6-mm1/include/linux/sched.h @@ -1065,6 +1065,9 @@ struct task_struct { #ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays; #endif +#ifdef CONFIG_PM + int freezing; /* if set, we should be freezing for suspend */ +#endif #ifdef CONFIG_FAULT_INJECTION int make_it_fail; #endif @@ -1161,7 +1164,6 @@ static inline void put_task_struct(struc #define PF_MEMALLOC 0x00000800 /* Allocating memory */ #define PF_FLUSHER 0x00001000 /* responsible for disk writeback */ #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ -#define PF_FREEZE 0x00004000 /* this task is being frozen for suspend now */ #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ #define PF_FROZEN 0x00010000 /* frozen for system suspend */ #define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */