diff options
| author | Nathan Zimmer <nzimmer@sgi.com> | 2013-08-28 16:35:14 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-08-28 19:26:38 -0700 | 
| commit | 84a78a6504f5c5394a8e558702e5b54131f01d14 (patch) | |
| tree | bd56909861d573e35ef940182891fe1eb210fec8 /kernel | |
| parent | fa8218def1b1a16f0a410e2c1c767b4738cc81fa (diff) | |
| download | linux-84a78a6504f5c5394a8e558702e5b54131f01d14.tar.bz2 | |
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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/time/timer_list.c | 41 | 
1 files changed, 24 insertions, 17 deletions
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index 3bdf28323012..61ed862cdd37 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -265,10 +265,9 @@ static inline void timer_list_header(struct seq_file *m, u64 now)  static int timer_list_show(struct seq_file *m, void *v)  {  	struct timer_list_iter *iter = v; -	u64 now = ktime_to_ns(ktime_get());  	if (iter->cpu == -1 && !iter->second_pass) -		timer_list_header(m, now); +		timer_list_header(m, iter->now);  	else if (!iter->second_pass)  		print_cpu(m, iter->cpu, iter->now);  #ifdef CONFIG_GENERIC_CLOCKEVENTS @@ -298,33 +297,41 @@ void sysrq_timer_list_show(void)  	return;  } -static void *timer_list_start(struct seq_file *file, loff_t *offset) +static void *move_iter(struct timer_list_iter *iter, loff_t offset)  { -	struct timer_list_iter *iter = file->private; - -	if (!*offset) { -		iter->cpu = -1; -		iter->now = ktime_to_ns(ktime_get()); -	} else if (iter->cpu >= nr_cpu_ids) { +	for (; offset; offset--) { +		iter->cpu = cpumask_next(iter->cpu, cpu_online_mask); +		if (iter->cpu >= nr_cpu_ids) {  #ifdef CONFIG_GENERIC_CLOCKEVENTS -		if (!iter->second_pass) { -			iter->cpu = -1; -			iter->second_pass = true; -		} else -			return NULL; +			if (!iter->second_pass) { +				iter->cpu = -1; +				iter->second_pass = true; +			} else +				return NULL;  #else -		return NULL; +			return NULL;  #endif +		}  	}  	return iter;  } +static void *timer_list_start(struct seq_file *file, loff_t *offset) +{ +	struct timer_list_iter *iter = file->private; + +	if (!*offset) +		iter->now = ktime_to_ns(ktime_get()); +	iter->cpu = -1; +	iter->second_pass = false; +	return move_iter(iter, *offset); +} +  static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset)  {  	struct timer_list_iter *iter = file->private; -	iter->cpu = cpumask_next(iter->cpu, cpu_online_mask);  	++*offset; -	return timer_list_start(file, offset); +	return move_iter(iter, 1);  }  static void timer_list_stop(struct seq_file *seq, void *v)  |