diff options
author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2008-10-22 12:42:30 +0800 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-22 14:29:37 +0200 |
commit | bc8bcc79ea4203c7d04309f1307ab88c86f0b0cf (patch) | |
tree | 4aa34a173e9562cacb51ef7e7d175a68b4415f8a | |
parent | 35af28219e684a36cc8b1ff456c370ce22be157d (diff) | |
download | op-kernel-dev-bc8bcc79ea4203c7d04309f1307ab88c86f0b0cf.zip op-kernel-dev-bc8bcc79ea4203c7d04309f1307ab88c86f0b0cf.tar.gz |
x86/proc: fix /proc/cpuinfo cpu offline bug
Impact: fix missing CPUs in /proc/cpuinfo after CPU hotunplug/hotreplug
In my test, I found that if a cpu has been offline,
the next cpus may not be shown in the /proc/cpuinfo.
if one read() cannot consume the whole /proc/cpuinfo,
c_start() will be called again in the next read() calls.
And *pos has been increased by 1 by the caller(seq_read()).
if this time the cpu#*pos is offline, c_start() will return
NULL, and the next cpus can not be shown.
this fix use next_cpu_nr(*pos - 1, cpu_online_map) to
search the next unshown cpu.
the most easy way to reproduce this bug:
1) offline cpu#1 (cpu#0 is online)
2) dd ibs=2 if=/proc/cpuinfo
the result is that only cpu#0 is shown.
cpu#2 and cpu#3 .... cannot be shown in /proc/cpuinfo
it's bug.
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/cpu/proc.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c index a26c480..01b1244 100644 --- a/arch/x86/kernel/cpu/proc.c +++ b/arch/x86/kernel/cpu/proc.c @@ -160,14 +160,16 @@ static void *c_start(struct seq_file *m, loff_t *pos) { if (*pos == 0) /* just in case, cpu 0 is not the first */ *pos = first_cpu(cpu_online_map); - if ((*pos) < nr_cpu_ids && cpu_online(*pos)) + else + *pos = next_cpu_nr(*pos - 1, cpu_online_map); + if ((*pos) < nr_cpu_ids) return &cpu_data(*pos); return NULL; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { - *pos = next_cpu(*pos, cpu_online_map); + (*pos)++; return c_start(m, pos); } |