diff options
Diffstat (limited to 'include/linux/freezer.h')
-rw-r--r-- | include/linux/freezer.h | 69 |
1 files changed, 56 insertions, 13 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 5e75e26d4787..4631086f5060 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h | |||
@@ -37,25 +37,25 @@ static inline void do_not_freeze(struct task_struct *p) | |||
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Wake up a frozen process | 39 | * Wake up a frozen process |
40 | * | ||
41 | * task_lock() is taken to prevent the race with refrigerator() which may | ||
42 | * occur if the freezing of tasks fails. Namely, without the lock, if the | ||
43 | * freezing of tasks failed, thaw_tasks() might have run before a task in | ||
44 | * refrigerator() could call frozen_process(), in which case the task would be | ||
45 | * frozen and no one would thaw it. | ||
40 | */ | 46 | */ |
41 | static inline int thaw_process(struct task_struct *p) | 47 | static inline int thaw_process(struct task_struct *p) |
42 | { | 48 | { |
49 | task_lock(p); | ||
43 | if (frozen(p)) { | 50 | if (frozen(p)) { |
44 | p->flags &= ~PF_FROZEN; | 51 | p->flags &= ~PF_FROZEN; |
52 | task_unlock(p); | ||
45 | wake_up_process(p); | 53 | wake_up_process(p); |
46 | return 1; | 54 | return 1; |
47 | } | 55 | } |
48 | return 0; | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * freezing is complete, mark process as frozen | ||
53 | */ | ||
54 | static inline void frozen_process(struct task_struct *p) | ||
55 | { | ||
56 | p->flags |= PF_FROZEN; | ||
57 | wmb(); | ||
58 | clear_tsk_thread_flag(p, TIF_FREEZE); | 56 | clear_tsk_thread_flag(p, TIF_FREEZE); |
57 | task_unlock(p); | ||
58 | return 0; | ||
59 | } | 59 | } |
60 | 60 | ||
61 | extern void refrigerator(void); | 61 | extern void refrigerator(void); |
@@ -71,14 +71,55 @@ static inline int try_to_freeze(void) | |||
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
73 | 73 | ||
74 | extern void thaw_some_processes(int all); | 74 | /* |
75 | * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it | ||
76 | * calls wait_for_completion(&vfork) and reset right after it returns from this | ||
77 | * function. Next, the parent should call try_to_freeze() to freeze itself | ||
78 | * appropriately in case the child has exited before the freezing of tasks is | ||
79 | * complete. However, we don't want kernel threads to be frozen in unexpected | ||
80 | * places, so we allow them to block freeze_processes() instead or to set | ||
81 | * PF_NOFREEZE if needed and PF_FREEZER_SKIP is only set for userland vfork | ||
82 | * parents. Fortunately, in the ____call_usermodehelper() case the parent won't | ||
83 | * really block freeze_processes(), since ____call_usermodehelper() (the child) | ||
84 | * does a little before exec/exit and it can't be frozen before waking up the | ||
85 | * parent. | ||
86 | */ | ||
87 | |||
88 | /* | ||
89 | * If the current task is a user space one, tell the freezer not to count it as | ||
90 | * freezable. | ||
91 | */ | ||
92 | static inline void freezer_do_not_count(void) | ||
93 | { | ||
94 | if (current->mm) | ||
95 | current->flags |= PF_FREEZER_SKIP; | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * If the current task is a user space one, tell the freezer to count it as | ||
100 | * freezable again and try to freeze it. | ||
101 | */ | ||
102 | static inline void freezer_count(void) | ||
103 | { | ||
104 | if (current->mm) { | ||
105 | current->flags &= ~PF_FREEZER_SKIP; | ||
106 | try_to_freeze(); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Check if the task should be counted as freezeable by the freezer | ||
112 | */ | ||
113 | static inline int freezer_should_skip(struct task_struct *p) | ||
114 | { | ||
115 | return !!(p->flags & PF_FREEZER_SKIP); | ||
116 | } | ||
75 | 117 | ||
76 | #else | 118 | #else |
77 | static inline int frozen(struct task_struct *p) { return 0; } | 119 | static inline int frozen(struct task_struct *p) { return 0; } |
78 | static inline int freezing(struct task_struct *p) { return 0; } | 120 | static inline int freezing(struct task_struct *p) { return 0; } |
79 | static inline void freeze(struct task_struct *p) { BUG(); } | 121 | static inline void freeze(struct task_struct *p) { BUG(); } |
80 | static inline int thaw_process(struct task_struct *p) { return 1; } | 122 | static inline int thaw_process(struct task_struct *p) { return 1; } |
81 | static inline void frozen_process(struct task_struct *p) { BUG(); } | ||
82 | 123 | ||
83 | static inline void refrigerator(void) {} | 124 | static inline void refrigerator(void) {} |
84 | static inline int freeze_processes(void) { BUG(); return 0; } | 125 | static inline int freeze_processes(void) { BUG(); return 0; } |
@@ -86,5 +127,7 @@ static inline void thaw_processes(void) {} | |||
86 | 127 | ||
87 | static inline int try_to_freeze(void) { return 0; } | 128 | static inline int try_to_freeze(void) { return 0; } |
88 | 129 | ||
89 | 130 | static inline void freezer_do_not_count(void) {} | |
131 | static inline void freezer_count(void) {} | ||
132 | static inline int freezer_should_skip(struct task_struct *p) { return 0; } | ||
90 | #endif | 133 | #endif |