diff -urN linux-2.5.2-pre9/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt --- linux-2.5.2-pre9/Documentation/filesystems/proc.txt Wed Nov 7 17:39:36 2001 +++ linux/Documentation/filesystems/proc.txt Mon Jan 7 17:25:38 2002 @@ -118,6 +118,7 @@ Table 1-1: Process specific entries in /proc .............................................................................. File Content + affinity Writable bitmask of allowed CPUs (2.4)(smp) cmdline Command line arguments cpu Current and last cpu in wich it was executed (2.4)(smp) cwd Link to the current working directory @@ -165,6 +166,11 @@ information. The statm file contains more detailed information about the process memory usage. Its seven fields are explained in Table 1-2. +For writable entries, such as affinity: + + >echo 1 > /proc/PID/affinity + +To set the affinity of PID to (0x00000001 = only CPU0). Table 1-2: Contents of the statm files .............................................................................. diff -urN linux-2.5.2-pre9/fs/proc/array.c linux/fs/proc/array.c --- linux-2.5.2-pre9/fs/proc/array.c Mon Jan 7 17:32:36 2002 +++ linux/fs/proc/array.c Mon Jan 7 17:21:33 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 @@ -692,4 +694,65 @@ 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.5.2-pre9/fs/proc/base.c linux/fs/proc/base.c --- linux-2.5.2-pre9/fs/proc/base.c Mon Jan 7 17:32:36 2002 +++ linux/fs/proc/base.c Mon Jan 7 17:13:02 2002 @@ -42,6 +42,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) { @@ -325,8 +327,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) \ @@ -540,6 +578,7 @@ PROC_PID_STATM, PROC_PID_MAPS, PROC_PID_CPU, + PROC_PID_AFFINITY, PROC_PID_MOUNTS, PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -554,6 +593,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), @@ -915,6 +955,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.5.2-pre9/include/linux/capability.h linux/include/linux/capability.h --- linux-2.5.2-pre9/include/linux/capability.h Sun Dec 16 18:43:25 2001 +++ linux/include/linux/capability.h Mon Jan 7 17:12:33 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.5.2-pre9/include/linux/proc_fs_i.h linux/include/linux/proc_fs_i.h --- linux-2.5.2-pre9/include/linux/proc_fs_i.h Fri Apr 7 16:38:00 2000 +++ linux/include/linux/proc_fs_i.h Mon Jan 7 17:12:33 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; };