Commit 84a78a6504f5c5394a8e558702e5b54131f01d14
Committed by
Linus Torvalds
1 parent
fa8218def1
Exists in
master
and in
20 other branches
timer_list: correct the iterator for timer_list
Correct an issue with /proc/timer_list reported by Holger. When reading from the proc file with a sufficiently small buffer, 2k so not really that small, there was one could get hung trying to read the file a chunk at a time. The timer_list_start function failed to account for the possibility that the offset was adjusted outside the timer_list_next. Signed-off-by: Nathan Zimmer <nzimmer@sgi.com> Reported-by: Holger Hans Peter Freyther <holger@freyther.de> Cc: John Stultz <john.stultz@linaro.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Berke Durak <berke.durak@xiphos.com> Cc: Jeff Layton <jlayton@redhat.com> Tested-by: Al Viro <viro@zeniv.linux.org.uk> Cc: <stable@vger.kernel.org> # 3.10.x Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 24 additions and 17 deletions Side-by-side Diff
kernel/time/timer_list.c
... | ... | @@ -265,10 +265,9 @@ |
265 | 265 | static int timer_list_show(struct seq_file *m, void *v) |
266 | 266 | { |
267 | 267 | struct timer_list_iter *iter = v; |
268 | - u64 now = ktime_to_ns(ktime_get()); | |
269 | 268 | |
270 | 269 | if (iter->cpu == -1 && !iter->second_pass) |
271 | - timer_list_header(m, now); | |
270 | + timer_list_header(m, iter->now); | |
272 | 271 | else if (!iter->second_pass) |
273 | 272 | print_cpu(m, iter->cpu, iter->now); |
274 | 273 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
275 | 274 | |
276 | 275 | |
277 | 276 | |
278 | 277 | |
279 | 278 | |
280 | 279 | |
281 | 280 | |
... | ... | @@ -298,33 +297,41 @@ |
298 | 297 | return; |
299 | 298 | } |
300 | 299 | |
301 | -static void *timer_list_start(struct seq_file *file, loff_t *offset) | |
300 | +static void *move_iter(struct timer_list_iter *iter, loff_t offset) | |
302 | 301 | { |
303 | - struct timer_list_iter *iter = file->private; | |
304 | - | |
305 | - if (!*offset) { | |
306 | - iter->cpu = -1; | |
307 | - iter->now = ktime_to_ns(ktime_get()); | |
308 | - } else if (iter->cpu >= nr_cpu_ids) { | |
302 | + for (; offset; offset--) { | |
303 | + iter->cpu = cpumask_next(iter->cpu, cpu_online_mask); | |
304 | + if (iter->cpu >= nr_cpu_ids) { | |
309 | 305 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
310 | - if (!iter->second_pass) { | |
311 | - iter->cpu = -1; | |
312 | - iter->second_pass = true; | |
313 | - } else | |
314 | - return NULL; | |
306 | + if (!iter->second_pass) { | |
307 | + iter->cpu = -1; | |
308 | + iter->second_pass = true; | |
309 | + } else | |
310 | + return NULL; | |
315 | 311 | #else |
316 | - return NULL; | |
312 | + return NULL; | |
317 | 313 | #endif |
314 | + } | |
318 | 315 | } |
319 | 316 | return iter; |
320 | 317 | } |
321 | 318 | |
319 | +static void *timer_list_start(struct seq_file *file, loff_t *offset) | |
320 | +{ | |
321 | + struct timer_list_iter *iter = file->private; | |
322 | + | |
323 | + if (!*offset) | |
324 | + iter->now = ktime_to_ns(ktime_get()); | |
325 | + iter->cpu = -1; | |
326 | + iter->second_pass = false; | |
327 | + return move_iter(iter, *offset); | |
328 | +} | |
329 | + | |
322 | 330 | static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset) |
323 | 331 | { |
324 | 332 | struct timer_list_iter *iter = file->private; |
325 | - iter->cpu = cpumask_next(iter->cpu, cpu_online_mask); | |
326 | 333 | ++*offset; |
327 | - return timer_list_start(file, offset); | |
334 | + return move_iter(iter, 1); | |
328 | 335 | } |
329 | 336 | |
330 | 337 | static void timer_list_stop(struct seq_file *seq, void *v) |