Name: Modified set_affinity/get_affinity syscalls Author: Rusty Russell Status: Experimental Depends: Hotcpu/cpumask.patch.gz D: This allows userspace to have cpu affinity control without needing D: to know the size of kernel datastructures and allows them to D: control what happens when new CPUs are brought online. diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29333-linux-2.5.31/include/linux/affinity.h .29333-linux-2.5.31.updated/include/linux/affinity.h --- .29333-linux-2.5.31/include/linux/affinity.h 1970-01-01 10:00:00.000000000 +1000 +++ .29333-linux-2.5.31.updated/include/linux/affinity.h 2002-08-13 16:04:44.000000000 +1000 @@ -0,0 +1,9 @@ +#ifndef _LINUX_AFFINITY_H +#define _LINUX_AFFINITY_H +enum { + /* Set affinity to these processors */ + LINUX_AFFINITY_INCLUDE, + /* Set affinity to all *but* these processors */ + LINUX_AFFINITY_EXCLUDE, +}; +#endif diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29333-linux-2.5.31/kernel/sched.c .29333-linux-2.5.31.updated/kernel/sched.c --- .29333-linux-2.5.31/kernel/sched.c 2002-08-13 16:04:25.000000000 +1000 +++ .29333-linux-2.5.31.updated/kernel/sched.c 2002-08-13 16:18:50.000000000 +1000 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1540,21 +1541,44 @@ out_unlock: * @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 int sys_sched_setaffinity(pid_t pid, unsigned int len, - unsigned long *user_mask_ptr) +asmlinkage int sys_sched_setaffinity(pid_t pid, + int include, + unsigned int len, + unsigned long *user_mask_ptr) { DECLARE_BITMAP(new_mask, NR_CPUS); + unsigned char c; int retval; task_t *p; - if (len < sizeof(new_mask)) - return -EINVAL; - - if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) + memset(&new_mask, 0, sizeof(new_mask)); + if (copy_from_user(&new_mask, user_mask_ptr, + min((size_t)len, sizeof(new_mask)))) return -EFAULT; - if (any_online_cpu(new_mask) == NR_CPUS) + /* longer is OK, as long as they don't actually set any of the bits. */ + for (i = sizeof(new_mask); i < len; i++) { + if (get_user(c, user_mask_ptr+i)) + return -EFAULT; + if (c != 0) + return -ENOENT; + } + + /* Invert the mask in the exclude case. */ + switch (include) { + case LINUX_AFFINITY_EXCLUDE: + for (i = 0; i < BITS_TO_LONG(NR_CPUS); i++) + new_mask[i] ^= ~0UL; + break; + case LINUX_AFFINITY_INCLUDE: + break; + default: return -EINVAL; + } + + /* Must mention at least one online CPU */ + if (any_online_cpu(new_mask) == NR_CPUS) + return -EWOULDBLOCK; /* This is kinda true */ read_lock(&tasklist_lock); @@ -1590,37 +1614,26 @@ out_unlock: * @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 + * Returns the size required to hold the complete cpu mask. */ asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len, - unsigned long *user_mask_ptr) + void *user_mask_ptr) { - unsigned int real_len, i; DECLARE_BITMAP(mask, NR_CPUS); - int retval; task_t *p; - real_len = sizeof(mask); - if (len < real_len) - return -EINVAL; - read_lock(&tasklist_lock); - - retval = -ESRCH; p = find_process_by_pid(pid); - if (!p) - goto out_unlock; - - retval = 0; - for (i = 0; i < ARRAY_SIZE(mask); i++) - mask[i] = (p->cpus_allowed[i] & cpu_online_map[i]); - -out_unlock: + if (!p) { + read_unlock(&tasklist_lock); + return -ESRCH; + } + memcpy(mask, p->cpus_allowed, sizeof(mask)); read_unlock(&tasklist_lock); - if (retval) - return retval; - if (copy_to_user(user_mask_ptr, &mask, real_len)) + + if (copy_to_user(user_mask_ptr, &mask, len)) return -EFAULT; - return real_len; + return sizeof(mask); } /**