Commit 84a78a6504f5c5394a8e558702e5b54131f01d14

Authored by Nathan Zimmer
Committed by Linus Torvalds
1 parent fa8218def1

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)