diff -urN linux-2.4.18/fs/proc/array.c linux/fs/proc/array.c --- linux-2.4.18/fs/proc/array.c Mon Feb 25 17:10:28 2002 +++ linux/fs/proc/array.c Mon Feb 25 18:06:54 2002 @@ -50,6 +50,8 @@ * Al Viro & Jeff Garzik : moved most of the thing into base.c and * : proc_misc.c. The rest may eventually go into * : base.c too. + * + * Robert Love : added affinity (set processes's CPU affinity) */ #include @@ -693,4 +695,64 @@ return len; } -#endif + +int proc_pid_affinity_read(struct task_struct *task, char * buffer) +{ + int len; + + /* + * AND the mask against the current CPU configuration to return + * only valid bits + */ + len = sprintf(buffer, "%08lx\n", task->cpus_allowed & cpu_online_map); + return len; +} + +int proc_pid_affinity_write(struct task_struct *task, char * buffer, + size_t bytes) +{ + unsigned long new_mask; + int reschedule = 0; + char * endp; + + if ((current->euid != task->euid) && (current->euid != task->uid) + && !capable(CAP_SYS_NICE)) + return -EPERM; + + new_mask = simple_strtoul(buffer, &endp, 16); + + new_mask &= cpu_online_map; + if (!new_mask) + return -EINVAL; + + read_lock_irq(&tasklist_lock); + spin_lock(&runqueue_lock); + + task->cpus_allowed = new_mask; + + /* + * if running on a different CPU, cause a reschedule + * to move the process to an allowed CPU + */ + if (!(task->cpus_runnable & task->cpus_allowed)) { + if (task == current) + reschedule = 1; + else { + task->need_resched = 1; + smp_send_reschedule(task->processor); + } + } + + spin_unlock(&runqueue_lock); + read_unlock_irq(&tasklist_lock); + + /* + * if the task is on this CPU, wait to reschedule + * it until we drop the locks + */ + if (reschedule) + schedule(); + + return endp - buffer; +} +#endif /* CONFIG_SMP */ diff -urN linux-2.4.18/fs/proc/base.c linux/fs/proc/base.c --- linux-2.4.18/fs/proc/base.c Mon Feb 25 17:10:28 2002 +++ linux/fs/proc/base.c Mon Feb 25 18:06:54 2002 @@ -39,6 +39,8 @@ int proc_pid_status(struct task_struct*,char*); int proc_pid_statm(struct task_struct*,char*); int proc_pid_cpu(struct task_struct*,char*); +int proc_pid_affinity_read(struct task_struct*,char*); +int proc_pid_affinity_write(struct task_struct*,char*,size_t); static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) { @@ -282,8 +284,44 @@ return count; } +static ssize_t proc_info_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + struct inode * inode = file->f_dentry->d_inode; + unsigned long page; + ssize_t ret; + struct task_struct *task = inode->u.proc_i.task; + + if (inode->u.proc_i.op.proc_write == NULL) + return -EINVAL; + + if (count > PAGE_SIZE - 1) + return -EINVAL; + + if (!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user((char *)page, buf, count)) { + free_page(page); + return -EFAULT; + } + + ((char *) page)[count] = '\0'; + ret = inode->u.proc_i.op.proc_write(task, (char*) page, count); + if (ret < 0) { + free_page(page); + return -EFAULT; + } + + *ppos += ret; + + free_page(page); + return ret; +} + static struct file_operations proc_info_file_operations = { read: proc_info_read, + write: proc_info_write, }; #define MAY_PTRACE(p) \ @@ -497,6 +535,7 @@ PROC_PID_STATM, PROC_PID_MAPS, PROC_PID_CPU, + PROC_PID_AFFINITY, PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -510,6 +549,7 @@ E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO), #ifdef CONFIG_SMP E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO), + E(PROC_PID_AFFINITY, "affinity", S_IFREG|S_IRUGO|S_IWUSR), #endif E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO), E(PROC_PID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), @@ -876,6 +916,11 @@ inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_cpu; break; + case PROC_PID_AFFINITY: + inode->i_fop = &proc_info_file_operations; + inode->u.proc_i.op.proc_read = proc_pid_affinity_read; + inode->u.proc_i.op.proc_write = proc_pid_affinity_write; + break; #endif case PROC_PID_MEM: inode->i_op = &proc_mem_inode_operations; diff -urN linux-2.4.18/include/linux/capability.h linux/include/linux/capability.h --- linux-2.4.18/include/linux/capability.h Mon Feb 25 17:10:30 2002 +++ linux/include/linux/capability.h Mon Feb 25 18:06:54 2002 @@ -243,6 +243,7 @@ /* Allow use of FIFO and round-robin (realtime) scheduling on own processes and setting the scheduling algorithm used by another process. */ +/* Allow setting CPU affinity */ #define CAP_SYS_NICE 23 diff -urN linux-2.4.18/include/linux/proc_fs_i.h linux/include/linux/proc_fs_i.h --- linux-2.4.18/include/linux/proc_fs_i.h Mon Feb 25 17:10:30 2002 +++ linux/include/linux/proc_fs_i.h Mon Feb 25 18:06:55 2002 @@ -1,9 +1,11 @@ struct proc_inode_info { struct task_struct *task; int type; - union { + struct { int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); int (*proc_read)(struct task_struct *task, char *page); + int (*proc_write)(struct task_struct *task, char *page, + size_t bytes); } op; struct file *file; };