cpumask: fix compat getaffinity
Commit a45185d2d
"cpumask: convert kernel/compat.c" broke libnuma, which
abuses sched_getaffinity to find out NR_CPUS in order to parse
/sys/devices/system/node/node*/cpumap.
On NUMA systems with less than 32 possibly CPUs, the current
compat_sys_sched_getaffinity now returns '4' instead of the actual
NR_CPUS/8, which makes libnuma bail out when parsing the cpumap.
The libnuma call sched_getaffinity(0, bitmap, 4096) at first. It mean
the libnuma expect the return value of sched_getaffinity() is either len
argument or NR_CPUS. But it doesn't expect to return nr_cpu_ids.
Strictly speaking, userland requirement are
1) Glibc assume the return value mean the lengh of initialized
of mask argument. E.g. if sched_getaffinity(1024) return 128,
glibc make zero fill rest 896 byte.
2) Libnuma assume the return value can be used to guess NR_CPUS
in kernel. It assume len-arg<NR_CPUS makes -EINVAL. But
it try len=4096 at first and 4096 is always bigger than
NR_CPUS. Then, if we remove strange min_length normalization,
we never hit -EINVAL case.
sched_getaffinity() already solved this issue. This patch adapts
compat_sys_sched_getaffinity() to match the non-compat case.
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Reported-by: Ken Werner <ken.werner@web.de>
Cc: stable@kernel.org
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
cf77e988dd
Коммит
fa9dc265ac
|
@ -495,29 +495,26 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
|
|||
{
|
||||
int ret;
|
||||
cpumask_var_t mask;
|
||||
unsigned long *k;
|
||||
unsigned int min_length = cpumask_size();
|
||||
|
||||
if (nr_cpu_ids <= BITS_PER_COMPAT_LONG)
|
||||
min_length = sizeof(compat_ulong_t);
|
||||
|
||||
if (len < min_length)
|
||||
if ((len * BITS_PER_BYTE) < nr_cpu_ids)
|
||||
return -EINVAL;
|
||||
if (len & (sizeof(compat_ulong_t)-1))
|
||||
return -EINVAL;
|
||||
|
||||
if (!alloc_cpumask_var(&mask, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sched_getaffinity(pid, mask);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (ret == 0) {
|
||||
size_t retlen = min_t(size_t, len, cpumask_size());
|
||||
|
||||
k = cpumask_bits(mask);
|
||||
ret = compat_put_bitmap(user_mask_ptr, k, min_length * 8);
|
||||
if (ret == 0)
|
||||
ret = min_length;
|
||||
|
||||
out:
|
||||
if (compat_put_bitmap(user_mask_ptr, cpumask_bits(mask), retlen * 8))
|
||||
ret = -EFAULT;
|
||||
else
|
||||
ret = retlen;
|
||||
}
|
||||
free_cpumask_var(mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче