From: Anton Blanchard Remove the set_fs hack in the compat affinity calls. Create sched_getaffinity and sched_setaffinity helper functions that both the native and compat affinity syscalls use. Also make the compat functions match what the native ones are doing now, setaffinity calls succeed no matter what length the bitmask is, but getaffinity calls must pass in bitmasks at least as long as the kernel type. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton --- 25-akpm/include/linux/sched.h | 3 + 25-akpm/kernel/compat.c | 96 +++++++++++---------------------------- 25-akpm/kernel/sched.c | 102 ++++++++++++++++++++++++------------------ 3 files changed, 92 insertions(+), 109 deletions(-) diff -puN include/linux/sched.h~remove-set_fs-from-compat-sched-affinity-syscalls include/linux/sched.h --- 25/include/linux/sched.h~remove-set_fs-from-compat-sched-affinity-syscalls 2004-09-09 10:57:56.698827472 -0700 +++ 25-akpm/include/linux/sched.h 2004-09-09 10:57:56.739821240 -0700 @@ -1024,6 +1024,9 @@ static inline void arch_pick_mmap_layout } #endif +extern long sched_setaffinity(pid_t pid, cpumask_t new_mask); +extern long sched_getaffinity(pid_t pid, cpumask_t *mask); + #endif /* __KERNEL__ */ #endif diff -puN kernel/compat.c~remove-set_fs-from-compat-sched-affinity-syscalls kernel/compat.c --- 25/kernel/compat.c~remove-set_fs-from-compat-sched-affinity-syscalls 2004-09-09 10:57:56.715824888 -0700 +++ 25-akpm/kernel/compat.c 2004-09-09 10:57:56.724823520 -0700 @@ -412,92 +412,54 @@ compat_sys_wait4(compat_pid_t pid, compa } } -/* - * for maximum compatability, we allow programs to use a single (compat) - * unsigned long bitmask if all cpus will fit. If not, you have to have - * at least the kernel size available. - */ -#define USE_COMPAT_ULONG_CPUMASK (NR_CPUS <= BITS_PER_COMPAT_LONG) - -asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, - unsigned int len, - compat_ulong_t __user *user_mask_ptr) +static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr, + unsigned len, cpumask_t *new_mask) { - cpumask_t kern_mask; - mm_segment_t old_fs; - int ret; + unsigned long *k; - if (USE_COMPAT_ULONG_CPUMASK) { - compat_ulong_t user_mask; + if (len < sizeof(cpumask_t)) + memset(new_mask, 0, sizeof(cpumask_t)); + else if (len > sizeof(cpumask_t)) + len = sizeof(cpumask_t); - if (len < sizeof(user_mask)) - return -EINVAL; - - if (get_user(user_mask, user_mask_ptr)) - return -EFAULT; + k = cpus_addr(*new_mask); + return compat_get_bitmap(k, user_mask_ptr, len * 8); +} - cpus_addr(kern_mask)[0] = user_mask; - } else { - unsigned long *k; - - if (len < sizeof(kern_mask)) - return -EINVAL; - - k = cpus_addr(kern_mask); - ret = compat_get_bitmap(k, user_mask_ptr, - sizeof(kern_mask) * BITS_PER_LONG); - if (ret) - return ret; - } +asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, + unsigned int len, + compat_ulong_t __user *user_mask_ptr) +{ + cpumask_t new_mask; + int retval; - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_sched_setaffinity(pid, - sizeof(kern_mask), - (unsigned long __user *) &kern_mask); - set_fs(old_fs); + retval = compat_get_user_cpu_mask(user_mask_ptr, len, &new_mask); + if (retval) + return retval; - return ret; + return sched_setaffinity(pid, new_mask); } asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, compat_ulong_t __user *user_mask_ptr) { - cpumask_t kern_mask; - mm_segment_t old_fs; int ret; + cpumask_t mask; + unsigned long *k; - if (len < (USE_COMPAT_ULONG_CPUMASK ? sizeof(compat_ulong_t) - : sizeof(kern_mask))) + if (len < sizeof(cpumask_t)) return -EINVAL; - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_sched_getaffinity(pid, - sizeof(kern_mask), - (unsigned long __user *) &kern_mask); - set_fs(old_fs); - + ret = sched_getaffinity(pid, &mask); if (ret < 0) return ret; - if (USE_COMPAT_ULONG_CPUMASK) { - if (put_user(&cpus_addr(kern_mask)[0], user_mask_ptr)) - return -EFAULT; - ret = sizeof(compat_ulong_t); - } else { - unsigned long *k; - - k = cpus_addr(kern_mask); - ret = compat_put_bitmap(user_mask_ptr, k, - sizeof(kern_mask) * BITS_PER_LONG); - if (ret) - return ret; - - ret = sizeof(kern_mask); - } + k = cpus_addr(mask); + ret = compat_put_bitmap(user_mask_ptr, k, sizeof(cpumask_t) * 8); + if (ret) + return ret; - return ret; + return sizeof(cpumask_t); } static int get_compat_itimerspec(struct itimerspec *dst, diff -puN kernel/sched.c~remove-set_fs-from-compat-sched-affinity-syscalls kernel/sched.c --- 25/kernel/sched.c~remove-set_fs-from-compat-sched-affinity-syscalls 2004-09-09 10:57:56.718824432 -0700 +++ 25-akpm/kernel/sched.c 2004-09-09 10:57:56.738821392 -0700 @@ -3362,33 +3362,10 @@ out_unlock: return retval; } -static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len, - cpumask_t *new_mask) -{ - if (len < sizeof(cpumask_t)) { - memset(new_mask, 0, sizeof(cpumask_t)); - } else if (len > sizeof(cpumask_t)) { - len = sizeof(cpumask_t); - } - return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0; -} - -/** - * sys_sched_setaffinity - set the cpu affinity of a process - * @pid: pid of the process - * @len: length in bytes of the bitmask pointed to by user_mask_ptr - * @user_mask_ptr: user-space pointer to the new cpu mask - */ -asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr) +long sched_setaffinity(pid_t pid, cpumask_t new_mask) { - cpumask_t new_mask; - int retval; task_t *p; - - retval = get_user_cpu_mask(user_mask_ptr, len, &new_mask); - if (retval) - return retval; + int retval; lock_cpu_hotplug(); read_lock(&tasklist_lock); @@ -3421,6 +3398,36 @@ out_unlock: return retval; } +static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len, + cpumask_t *new_mask) +{ + if (len < sizeof(cpumask_t)) { + memset(new_mask, 0, sizeof(cpumask_t)); + } else if (len > sizeof(cpumask_t)) { + len = sizeof(cpumask_t); + } + return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0; +} + +/** + * sys_sched_setaffinity - set the cpu affinity of a process + * @pid: pid of the process + * @len: length in bytes of the bitmask pointed to by user_mask_ptr + * @user_mask_ptr: user-space pointer to the new cpu mask + */ +asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, + unsigned long __user *user_mask_ptr) +{ + cpumask_t new_mask; + int retval; + + retval = get_user_cpu_mask(user_mask_ptr, len, &new_mask); + if (retval) + return retval; + + return sched_setaffinity(pid, new_mask); +} + /* * Represents all cpu's present in the system * In systems capable of hotplug, this map could dynamically grow @@ -3436,24 +3443,11 @@ cpumask_t cpu_online_map = CPU_MASK_ALL; cpumask_t cpu_possible_map = CPU_MASK_ALL; #endif -/** - * sys_sched_getaffinity - get the cpu affinity of a process - * @pid: pid of the process - * @len: length in bytes of the bitmask pointed to by user_mask_ptr - * @user_mask_ptr: user-space pointer to hold the current cpu mask - */ -asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr) +long sched_getaffinity(pid_t pid, cpumask_t *mask) { - unsigned int real_len; - cpumask_t mask; int retval; task_t *p; - real_len = sizeof(mask); - if (len < real_len) - return -EINVAL; - lock_cpu_hotplug(); read_lock(&tasklist_lock); @@ -3463,16 +3457,40 @@ asmlinkage long sys_sched_getaffinity(pi goto out_unlock; retval = 0; - cpus_and(mask, p->cpus_allowed, cpu_possible_map); + cpus_and(*mask, p->cpus_allowed, cpu_possible_map); out_unlock: read_unlock(&tasklist_lock); unlock_cpu_hotplug(); if (retval) return retval; - if (copy_to_user(user_mask_ptr, &mask, real_len)) + + return 0; +} + +/** + * sys_sched_getaffinity - get the cpu affinity of a process + * @pid: pid of the process + * @len: length in bytes of the bitmask pointed to by user_mask_ptr + * @user_mask_ptr: user-space pointer to hold the current cpu mask + */ +asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len, + unsigned long __user *user_mask_ptr) +{ + int ret; + cpumask_t mask; + + if (len < sizeof(cpumask_t)) + return -EINVAL; + + ret = sched_getaffinity(pid, &mask); + if (ret < 0) + return ret; + + if (copy_to_user(user_mask_ptr, &mask, sizeof(cpumask_t))) return -EFAULT; - return real_len; + + return sizeof(cpumask_t); } /** _