忙しくて二週間ぐらい気づいていなかったが、一ヶ月ぐらい前に直した
sched_getaffinity()の非互換対処バグがマージされたようだ。

非互換といってもカーネルがバグを入れたわけではなく、
あるディストリ(Fedora?)がカーネルをNR_CPUS=4096に変えた
にもかかわらず、glibcはABI互換のためcpuset_tがNR_CPUSが
1024(or それ以下)だと決めうったコードから変えられないので、
結果として引数矛盾で常にEINVALがかえってしまっていた。

ところが、笑えることに世界唯一の4096CPUを持っているSGIは
SUSEを使っていて、SUSEは独自パッチをglibcにあてて、glibc側の
cpuset_tを4096bitに拡張しているので被害0.
被害にあっているのは小さいマシンを使っている
しもじものユーザーだという。

あまりにも馬鹿らしいのでsched_getaffinity()のABIを変えてしまった。
いままでコンパイル時に決まる最大値(=NR_CPUS)を元に引数チェックを
していたのをマシンブート時に決まる「そのマシンでの」最大CPUで
チェックするようにした。これで、CPU数が1024以下ならNR_CPUSに関係
なくちゃんと動作する。
CPUを1024個以上つんだマシンをもっている人がSUSE以外のディストリを
使っていた場合は非互換になるのだけれども、そんなユーザは事前調査で
いないことが分かっているのでさくっと無視するという対処をした
(せつこ、それ対処ちゃう)

パッチは以下のような感じの超小さいFixなのだが、ここで注目すべきは
UlrichがAckしている所である。たぶんあのキャラを知らない人には
イメージわかないと思うが、Ulrichが
1) わざわざLKMLまで出向いてきた
2) 自分が作ったわけじゃないパッチにパッチにAckしてる
という二重の意味で本当に本当にレアなパッチになっている。

もっとも、このレアさ加減はglibcにパッチを投げたことある人に
しか通じないと思うので誰とも共有できない喜びなのであるが

PS 誰かUlrichにcpu hotplugの動きを説明してやれよ。あいつが
全然理解してないから説明が面倒なことこの上ない



Reported-by: Sharyathi Nagesh
Signed-off-by: KOSAKI Motohiro
Acked-by: Ulrich Drepper
Acked-by: Peter Zijlstra
Cc: Linus Torvalds
Cc: Andrew Morton
Cc: Jack Steiner
Cc: Russ Anderson
Cc: Mike Travis
LKML-Reference: <20100312161316.9520.A69D9226@jp.fujitsu.com>
Signed-off-by: Ingo Molnar

diff --git a/kernel/sched.c b/kernel/sched.c
index 9ab3cd7..6eaef3d 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4902,7 +4902,9 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
int ret;
cpumask_var_t mask;

- if (len < cpumask_size())
+ if (len < nr_cpu_ids)
+ return -EINVAL;
+ if (len & (sizeof(unsigned long)-1))
return -EINVAL;

if (!alloc_cpumask_var(&mask, GFP_KERNEL))
@@ -4910,10 +4912,12 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,

ret = sched_getaffinity(pid, mask);
if (ret == 0) {
- if (copy_to_user(user_mask_ptr, mask, cpumask_size()))
+ int retlen = min(len, cpumask_size());
+
+ if (copy_to_user(user_mask_ptr, mask, retlen))
ret = -EFAULT;
else
- ret = cpumask_size();
+ ret = retlen;
}
free_cpumask_var(mask);