aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-11-23 12:28:17 -0500
committerTejun Heo <tj@kernel.org>2011-11-23 12:28:17 -0500
commit34b087e48367c252e343c2f8de65676a78af1e4a (patch)
treefbe94bad0a3073c6f4231752fba99c6bc8702277
parentadfa543e7314b36ac55a40019977de6e47946dd7 (diff)
freezer: kill unused set_freezable_with_signal()
There's no in-kernel user of set_freezable_with_signal() left. Mixing TIF_SIGPENDING with kernel threads can lead to nasty corner cases as kernel threads never travel signal delivery path on their own. e.g. the current implementation is buggy in the cancelation path of __thaw_task(). It calls recalc_sigpending_and_wake() in an attempt to clear TIF_SIGPENDING but the function never clears it regardless of sigpending state. This means that signallable freezable kthreads may continue executing with !freezing() && stuck TIF_SIGPENDING, which can be troublesome. This patch removes set_freezable_with_signal() along with PF_FREEZER_NOSIG and recalc_sigpending*() calls in freezer. User tasks get TIF_SIGPENDING, kernel tasks get woken up and the spurious sigpending is dealt with in the usual signal delivery path. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Oleg Nesterov <oleg@redhat.com>
-rw-r--r--include/linux/freezer.h20
-rw-r--r--include/linux/sched.h1
-rw-r--r--kernel/freezer.c27
-rw-r--r--kernel/kthread.c2
4 files changed, 8 insertions, 42 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index a28842e588f4..a33550fc05c5 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -49,7 +49,7 @@ static inline bool try_to_freeze(void)
49} 49}
50 50
51extern bool freeze_task(struct task_struct *p); 51extern bool freeze_task(struct task_struct *p);
52extern bool __set_freezable(bool with_signal); 52extern bool set_freezable(void);
53 53
54#ifdef CONFIG_CGROUP_FREEZER 54#ifdef CONFIG_CGROUP_FREEZER
55extern bool cgroup_freezing(struct task_struct *task); 55extern bool cgroup_freezing(struct task_struct *task);
@@ -105,23 +105,6 @@ static inline int freezer_should_skip(struct task_struct *p)
105} 105}
106 106
107/* 107/*
108 * Tell the freezer that the current task should be frozen by it
109 */
110static inline bool set_freezable(void)
111{
112 return __set_freezable(false);
113}
114
115/*
116 * Tell the freezer that the current task should be frozen by it and that it
117 * should send a fake signal to the task to freeze it.
118 */
119static inline bool set_freezable_with_signal(void)
120{
121 return __set_freezable(true);
122}
123
124/*
125 * Freezer-friendly wrappers around wait_event_interruptible(), 108 * Freezer-friendly wrappers around wait_event_interruptible(),
126 * wait_event_killable() and wait_event_interruptible_timeout(), originally 109 * wait_event_killable() and wait_event_interruptible_timeout(), originally
127 * defined in <linux/wait.h> 110 * defined in <linux/wait.h>
@@ -176,7 +159,6 @@ static inline void freezer_do_not_count(void) {}
176static inline void freezer_count(void) {} 159static inline void freezer_count(void) {}
177static inline int freezer_should_skip(struct task_struct *p) { return 0; } 160static inline int freezer_should_skip(struct task_struct *p) { return 0; }
178static inline void set_freezable(void) {} 161static inline void set_freezable(void) {}
179static inline void set_freezable_with_signal(void) {}
180 162
181#define wait_event_freezable(wq, condition) \ 163#define wait_event_freezable(wq, condition) \
182 wait_event_interruptible(wq, condition) 164 wait_event_interruptible(wq, condition)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index d12bd03b688f..2f90470ad843 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1788,7 +1788,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
1788#define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ 1788#define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */
1789#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ 1789#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */
1790#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ 1790#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */
1791#define PF_FREEZER_NOSIG 0x80000000 /* Freezer won't send signals to it */
1792 1791
1793/* 1792/*
1794 * Only the _current_ task can read/write to tsk->flags, but other 1793 * Only the _current_ task can read/write to tsk->flags, but other
diff --git a/kernel/freezer.c b/kernel/freezer.c
index 2589a61de44c..9815b8d1eed5 100644
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -39,7 +39,7 @@ bool freezing_slow_path(struct task_struct *p)
39 if (pm_nosig_freezing || cgroup_freezing(p)) 39 if (pm_nosig_freezing || cgroup_freezing(p))
40 return true; 40 return true;
41 41
42 if (pm_freezing && !(p->flags & PF_FREEZER_NOSIG)) 42 if (pm_freezing && !(p->flags & PF_KTHREAD))
43 return true; 43 return true;
44 44
45 return false; 45 return false;
@@ -72,10 +72,6 @@ bool __refrigerator(bool check_kthr_stop)
72 schedule(); 72 schedule();
73 } 73 }
74 74
75 spin_lock_irq(&current->sighand->siglock);
76 recalc_sigpending(); /* We sent fake signal, clean it up */
77 spin_unlock_irq(&current->sighand->siglock);
78
79 pr_debug("%s left refrigerator\n", current->comm); 75 pr_debug("%s left refrigerator\n", current->comm);
80 76
81 /* 77 /*
@@ -120,7 +116,7 @@ bool freeze_task(struct task_struct *p)
120 return false; 116 return false;
121 } 117 }
122 118
123 if (!(p->flags & PF_FREEZER_NOSIG)) { 119 if (!(p->flags & PF_KTHREAD)) {
124 fake_signal_wake_up(p); 120 fake_signal_wake_up(p);
125 /* 121 /*
126 * fake_signal_wake_up() goes through p's scheduler 122 * fake_signal_wake_up() goes through p's scheduler
@@ -145,28 +141,19 @@ void __thaw_task(struct task_struct *p)
145 * be visible to @p as waking up implies wmb. Waking up inside 141 * be visible to @p as waking up implies wmb. Waking up inside
146 * freezer_lock also prevents wakeups from leaking outside 142 * freezer_lock also prevents wakeups from leaking outside
147 * refrigerator. 143 * refrigerator.
148 *
149 * If !FROZEN, @p hasn't reached refrigerator, recalc sigpending to
150 * avoid leaving dangling TIF_SIGPENDING behind.
151 */ 144 */
152 spin_lock_irqsave(&freezer_lock, flags); 145 spin_lock_irqsave(&freezer_lock, flags);
153 if (frozen(p)) { 146 if (frozen(p))
154 wake_up_process(p); 147 wake_up_process(p);
155 } else {
156 spin_lock(&p->sighand->siglock);
157 recalc_sigpending_and_wake(p);
158 spin_unlock(&p->sighand->siglock);
159 }
160 spin_unlock_irqrestore(&freezer_lock, flags); 148 spin_unlock_irqrestore(&freezer_lock, flags);
161} 149}
162 150
163/** 151/**
164 * __set_freezable - make %current freezable 152 * set_freezable - make %current freezable
165 * @with_signal: do we want %TIF_SIGPENDING for notification too?
166 * 153 *
167 * Mark %current freezable and enter refrigerator if necessary. 154 * Mark %current freezable and enter refrigerator if necessary.
168 */ 155 */
169bool __set_freezable(bool with_signal) 156bool set_freezable(void)
170{ 157{
171 might_sleep(); 158 might_sleep();
172 159
@@ -177,10 +164,8 @@ bool __set_freezable(bool with_signal)
177 */ 164 */
178 spin_lock_irq(&freezer_lock); 165 spin_lock_irq(&freezer_lock);
179 current->flags &= ~PF_NOFREEZE; 166 current->flags &= ~PF_NOFREEZE;
180 if (with_signal)
181 current->flags &= ~PF_FREEZER_NOSIG;
182 spin_unlock_irq(&freezer_lock); 167 spin_unlock_irq(&freezer_lock);
183 168
184 return try_to_freeze(); 169 return try_to_freeze();
185} 170}
186EXPORT_SYMBOL(__set_freezable); 171EXPORT_SYMBOL(set_freezable);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 1c36deaae2f1..3d3de633702e 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -282,7 +282,7 @@ int kthreadd(void *unused)
282 set_cpus_allowed_ptr(tsk, cpu_all_mask); 282 set_cpus_allowed_ptr(tsk, cpu_all_mask);
283 set_mems_allowed(node_states[N_HIGH_MEMORY]); 283 set_mems_allowed(node_states[N_HIGH_MEMORY]);
284 284
285 current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; 285 current->flags |= PF_NOFREEZE;
286 286
287 for (;;) { 287 for (;;) {
288 set_current_state(TASK_INTERRUPTIBLE); 288 set_current_state(TASK_INTERRUPTIBLE);