diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-10-28 13:38:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-28 14:30:54 -0400 |
commit | a98b6094261c0112e9c455c96995972181bff049 (patch) | |
tree | 01a15d79e331730de5a255a7109cf1318b95f6ac /kernel/taskstats.c | |
parent | b8534d7bd89df0cd41cd47bcd6733a05ea9a691a (diff) |
[PATCH] taskstats: don't use tasklist_lock
Remove tasklist_lock from taskstats.c. find_task_by_pid() is rcu-safe.
->siglock allows us to traverse subthread without tasklist.
Q: delay accounting looks wrong to me. If sub-thread has already called
taskstats_exit_send() but didn't call release_task(self) yet it will be
accounted twice. The window is big. No?
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Shailabh Nagar <nagar@watson.ibm.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Jay Lan <jlan@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/taskstats.c')
-rw-r--r-- | kernel/taskstats.c | 59 |
1 files changed, 24 insertions, 35 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index b2efda94615a..b724aeea5443 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c | |||
@@ -174,21 +174,19 @@ static void send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) | |||
174 | up_write(&listeners->sem); | 174 | up_write(&listeners->sem); |
175 | } | 175 | } |
176 | 176 | ||
177 | static int fill_pid(pid_t pid, struct task_struct *pidtsk, | 177 | static int fill_pid(pid_t pid, struct task_struct *tsk, |
178 | struct taskstats *stats) | 178 | struct taskstats *stats) |
179 | { | 179 | { |
180 | int rc = 0; | 180 | int rc = 0; |
181 | struct task_struct *tsk = pidtsk; | ||
182 | 181 | ||
183 | if (!pidtsk) { | 182 | if (!tsk) { |
184 | read_lock(&tasklist_lock); | 183 | rcu_read_lock(); |
185 | tsk = find_task_by_pid(pid); | 184 | tsk = find_task_by_pid(pid); |
186 | if (!tsk) { | 185 | if (tsk) |
187 | read_unlock(&tasklist_lock); | 186 | get_task_struct(tsk); |
187 | rcu_read_unlock(); | ||
188 | if (!tsk) | ||
188 | return -ESRCH; | 189 | return -ESRCH; |
189 | } | ||
190 | get_task_struct(tsk); | ||
191 | read_unlock(&tasklist_lock); | ||
192 | } else | 190 | } else |
193 | get_task_struct(tsk); | 191 | get_task_struct(tsk); |
194 | 192 | ||
@@ -214,40 +212,28 @@ static int fill_pid(pid_t pid, struct task_struct *pidtsk, | |||
214 | 212 | ||
215 | } | 213 | } |
216 | 214 | ||
217 | static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk, | 215 | static int fill_tgid(pid_t tgid, struct task_struct *first, |
218 | struct taskstats *stats) | 216 | struct taskstats *stats) |
219 | { | 217 | { |
220 | struct task_struct *tsk, *first; | 218 | struct task_struct *tsk; |
221 | unsigned long flags; | 219 | unsigned long flags; |
220 | int rc = -ESRCH; | ||
222 | 221 | ||
223 | /* | 222 | /* |
224 | * Add additional stats from live tasks except zombie thread group | 223 | * Add additional stats from live tasks except zombie thread group |
225 | * leaders who are already counted with the dead tasks | 224 | * leaders who are already counted with the dead tasks |
226 | */ | 225 | */ |
227 | first = tgidtsk; | 226 | rcu_read_lock(); |
228 | if (!first) { | 227 | if (!first) |
229 | read_lock(&tasklist_lock); | ||
230 | first = find_task_by_pid(tgid); | 228 | first = find_task_by_pid(tgid); |
231 | if (!first) { | ||
232 | read_unlock(&tasklist_lock); | ||
233 | return -ESRCH; | ||
234 | } | ||
235 | get_task_struct(first); | ||
236 | read_unlock(&tasklist_lock); | ||
237 | } else | ||
238 | get_task_struct(first); | ||
239 | 229 | ||
230 | if (!first || !lock_task_sighand(first, &flags)) | ||
231 | goto out; | ||
240 | 232 | ||
241 | tsk = first; | 233 | if (first->signal->stats) |
242 | read_lock(&tasklist_lock); | 234 | memcpy(stats, first->signal->stats, sizeof(*stats)); |
243 | /* Start with stats from dead tasks */ | ||
244 | if (first->sighand) { | ||
245 | spin_lock_irqsave(&first->sighand->siglock, flags); | ||
246 | if (first->signal->stats) | ||
247 | memcpy(stats, first->signal->stats, sizeof(*stats)); | ||
248 | spin_unlock_irqrestore(&first->sighand->siglock, flags); | ||
249 | } | ||
250 | 235 | ||
236 | tsk = first; | ||
251 | do { | 237 | do { |
252 | if (tsk->exit_state == EXIT_ZOMBIE && thread_group_leader(tsk)) | 238 | if (tsk->exit_state == EXIT_ZOMBIE && thread_group_leader(tsk)) |
253 | continue; | 239 | continue; |
@@ -260,15 +246,18 @@ static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk, | |||
260 | delayacct_add_tsk(stats, tsk); | 246 | delayacct_add_tsk(stats, tsk); |
261 | 247 | ||
262 | } while_each_thread(first, tsk); | 248 | } while_each_thread(first, tsk); |
263 | read_unlock(&tasklist_lock); | ||
264 | stats->version = TASKSTATS_VERSION; | ||
265 | 249 | ||
250 | unlock_task_sighand(first, &flags); | ||
251 | rc = 0; | ||
252 | out: | ||
253 | rcu_read_unlock(); | ||
254 | |||
255 | stats->version = TASKSTATS_VERSION; | ||
266 | /* | 256 | /* |
267 | * Accounting subsytems can also add calls here to modify | 257 | * Accounting subsytems can also add calls here to modify |
268 | * fields of taskstats. | 258 | * fields of taskstats. |
269 | */ | 259 | */ |
270 | put_task_struct(first); | 260 | return rc; |
271 | return 0; | ||
272 | } | 261 | } |
273 | 262 | ||
274 | 263 | ||