diff -ruN clean-linux-2.2.12/CREDITS pset-linux-2.2.12/CREDITS --- clean-linux-2.2.12/CREDITS Wed Aug 25 17:29:45 1999 +++ pset-linux-2.2.12/CREDITS Mon Sep 6 13:45:16 1999 @@ -836,6 +836,12 @@ D: bug toaster (A1 sauce makes all the difference) D: Transmeta BOFH in my copius free time +N: Tim Hockin +E: thockin@isunix.it.ilstu.edu +W: http://isunix.it.ilstu.edu +D: Pset / sysmp support +S: (in flux) + N: Dirk Hohndel E: hohndel@suse.de D: The XFree86[tm] Project diff -ruN clean-linux-2.2.12/Documentation/Configure.help pset-linux-2.2.12/Documentation/Configure.help --- clean-linux-2.2.12/Documentation/Configure.help Wed Aug 25 17:29:45 1999 +++ pset-linux-2.2.12/Documentation/Configure.help Mon Sep 6 23:20:26 1999 @@ -110,6 +110,24 @@ If you don't know what to do here, say N. +Verbose processor set messages +CONFIG_SMP_PSET_VERBOSE + Pset enables the kernel to assign processes to run on a single CPU + or set of CPUs (a set of processors => pset). The process can then + request to be put on a specific processor set via the sysmp() + system call. This option will give you slightly more verbose status + and error messages about SMP processor set support at boot time. + + For REALLY verbose messages, also set CONFIG_SMP_PSET_DEBUG to 1 in + include/linux/pset.h. If you are already getting more messages than + you care to see, perhaps CONFIG_SMP_PSET_DEBUG is already 1, in + which case you can set it to 0 to quiet it down. + + See also: Documentation/pset.txt and the home web site at + http://isunix.it.ilstu.edu/~thockin/pset/ + + If you don't know what to do here, say N. + Kernel math emulation CONFIG_MATH_EMULATION Linux can emulate a math coprocessor (used for floating point diff -ruN clean-linux-2.2.12/Documentation/pset.txt pset-linux-2.2.12/Documentation/pset.txt --- clean-linux-2.2.12/Documentation/pset.txt Wed Dec 31 16:00:00 1969 +++ pset-linux-2.2.12/Documentation/pset.txt Mon Sep 6 23:20:29 1999 @@ -0,0 +1,24 @@ +Watch this space for more pset documentation. +http://isunix.it.ilstu.edu/~thockin/pset/ +------------------------------------------------------------------------ +In order to do anything useful with this, you should get the pset-utils +package from http://isunix.it.ilstu.edu/~thockin/pset/. The most current +version is pset-utils-0.61 + +About SMP processor set support (experimental) +----------------------------------------------- +This enables the kernel to assign every process to a single CPU or +group of CPUs (a set of processors => pset). The process can then +request to be put on a specific processor set via the sysmp() +system call. Library wrappers for this system call are (or will be) +available for maximum portability between OSes. This will also +activate a new magic SysRq key (if you have that option on) - 'C' +to reset all CPUs and processes. + +This will enlarge your kernel by about 5 KB. + +See also: Documentation/pset.txt and the home web site at + http://isunix.it.ilstu.edu/~thockin/pset/ + +http://isunix.it.ilstu.edu/~thockin/pset/ +thockin@isunix.it.ilstu.edu diff -ruN clean-linux-2.2.12/MAINTAINERS pset-linux-2.2.12/MAINTAINERS --- clean-linux-2.2.12/MAINTAINERS Wed Aug 25 17:29:45 1999 +++ pset-linux-2.2.12/MAINTAINERS Mon Sep 6 13:45:16 1999 @@ -667,6 +667,12 @@ L: linux-ppp@vger.rutgers.edu S: Maintained +PSET SUPPORT +P: Tim Hockin +M: thockin@isunix.it.ilstu.edu +W: http://isunix.it.ilstu.edu/~thockin/pset +S: Maintained + REAL TIME CLOCK DRIVER P: Paul Gortmaker M: p_gortmaker@yahoo.com diff -ruN clean-linux-2.2.12/arch/i386/config.in pset-linux-2.2.12/arch/i386/config.in --- clean-linux-2.2.12/arch/i386/config.in Mon Aug 9 12:04:38 1999 +++ pset-linux-2.2.12/arch/i386/config.in Mon Sep 6 23:21:15 1999 @@ -40,6 +40,9 @@ bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP +if [ "$CONFIG_SMP" = "y" ]; then + bool ' Verbose processor set messages' CONFIG_SMP_PSET_VERBOSE +fi endmenu mainmenu_option next_comment diff -ruN clean-linux-2.2.12/arch/i386/kernel/entry.S pset-linux-2.2.12/arch/i386/kernel/entry.S --- clean-linux-2.2.12/arch/i386/kernel/entry.S Fri Apr 30 08:13:37 1999 +++ pset-linux-2.2.12/arch/i386/kernel/entry.S Mon Sep 6 13:45:16 1999 @@ -562,6 +562,7 @@ .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ + .long SYMBOL_NAME(sys_sysmp) /* * NOTE!! This doesn't have to be exact - we just have @@ -569,6 +570,6 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-190 + .rept NR_syscalls-191 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -ruN clean-linux-2.2.12/drivers/char/sysrq.c pset-linux-2.2.12/drivers/char/sysrq.c --- clean-linux-2.2.12/drivers/char/sysrq.c Mon Aug 9 12:05:01 1999 +++ pset-linux-2.2.12/drivers/char/sysrq.c Mon Sep 6 23:24:59 1999 @@ -32,6 +32,10 @@ int sysrq_enabled = 1; #endif +#ifdef __SMP__ +#include +#endif + extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; @@ -134,6 +138,12 @@ send_sig_all(SIGKILL, 1); orig_log_level = 8; break; +#ifdef __SMP__ + case 'c': + printk("Enable CPUs and Reset Psets\n"); + pset_reset_psets(); + break; +#endif default: /* Unknown: help */ if (kbd) printk("unRaw "); @@ -144,6 +154,9 @@ printk("Boot " #ifdef CONFIG_APM "Off " +#endif +#ifdef __SMP__ + "Cpus/psets " #endif "Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n"); /* Don't use 'A' as it's handled specially on the Sparc */ diff -ruN clean-linux-2.2.12/fs/proc/array.c pset-linux-2.2.12/fs/proc/array.c --- clean-linux-2.2.12/fs/proc/array.c Wed Aug 25 17:29:49 1999 +++ pset-linux-2.2.12/fs/proc/array.c Tue Sep 7 22:24:55 1999 @@ -42,6 +42,8 @@ * Alan Cox : security fixes. * * + * Tim Hockin : pset support + * */ #include @@ -63,6 +65,9 @@ #include #include #include +#ifdef __SMP__ +#include +#endif #include #include @@ -1322,6 +1327,13 @@ case PROC_CPUINFO: return get_cpuinfo(page); +#ifdef __SMP__ + case PROC_PSETS: + return pset_get_proc_psets(page); + + case PROC_CPUSTATS: + return pset_get_proc_cpustats(page); +#endif case PROC_VERSION: return get_version(page); @@ -1456,6 +1468,8 @@ #ifdef __SMP__ case PROC_PID_CPU: return get_pidcpu(pid, page); + case PROC_PID_PSET: + return pset_get_proc_pid_pset(pid, page); #endif } return -EBADF; diff -ruN clean-linux-2.2.12/fs/proc/base.c pset-linux-2.2.12/fs/proc/base.c --- clean-linux-2.2.12/fs/proc/base.c Mon Aug 24 13:02:43 1998 +++ pset-linux-2.2.12/fs/proc/base.c Tue Sep 7 22:25:17 1999 @@ -173,6 +173,13 @@ 0, &proc_array_inode_operations, NULL, proc_pid_fill_inode, }; + +static struct proc_dir_entry proc_pid_pset = { + PROC_PID_PSET, 4, "pset", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + NULL, proc_pid_fill_inode, +}; #endif __initfunc(void proc_base_init(void)) @@ -193,6 +200,7 @@ proc_register(&proc_pid, &proc_pid_maps); #ifdef __SMP__ proc_register(&proc_pid, &proc_pid_cpu); + proc_register(&proc_pid, &proc_pid_pset); #endif }; diff -ruN clean-linux-2.2.12/fs/proc/root.c pset-linux-2.2.12/fs/proc/root.c --- clean-linux-2.2.12/fs/proc/root.c Mon Aug 9 12:04:41 1999 +++ pset-linux-2.2.12/fs/proc/root.c Tue Sep 7 22:25:52 1999 @@ -21,6 +21,9 @@ #ifdef CONFIG_ZORRO #include #endif +#ifdef __SMP__ +#include +#endif /* * Offset of the first process in the /proc root directory.. @@ -535,6 +538,18 @@ S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_array_inode_operations }; +#ifdef __SMP__ +static struct proc_dir_entry proc_root_psets = { + PROC_PSETS, 5, "psets", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations +}; +static struct proc_dir_entry proc_root_cpustats = { + PROC_CPUSTATS, 8, "cpustats", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations +}; +#endif #if defined (CONFIG_PROC_HARDWARE) static struct proc_dir_entry proc_root_hardware = { PROC_HARDWARE, 8, "hardware", @@ -685,6 +700,10 @@ proc_register(&proc_root, &proc_root_kmsg); proc_register(&proc_root, &proc_root_version); proc_register(&proc_root, &proc_root_cpuinfo); +#ifdef __SMP__ + proc_register(&proc_root, &proc_root_psets); + proc_register(&proc_root, &proc_root_cpustats); +#endif proc_register(&proc_root, &proc_root_self); proc_net = create_proc_entry("net", S_IFDIR, 0); proc_scsi = create_proc_entry("scsi", S_IFDIR, 0); diff -ruN clean-linux-2.2.12/include/asm-i386/unistd.h pset-linux-2.2.12/include/asm-i386/unistd.h --- clean-linux-2.2.12/include/asm-i386/unistd.h Wed Jan 20 11:06:24 1999 +++ pset-linux-2.2.12/include/asm-i386/unistd.h Mon Sep 6 13:45:16 1999 @@ -195,6 +195,7 @@ #define __NR_getpmsg 188 /* some people actually want streams */ #define __NR_putpmsg 189 /* some people actually want streams */ #define __NR_vfork 190 +#define __NR_sysmp 191 /* user-visible error numbers are in the range -1 - -122: see */ diff -ruN clean-linux-2.2.12/include/linux/capability.h pset-linux-2.2.12/include/linux/capability.h --- clean-linux-2.2.12/include/linux/capability.h Mon Aug 9 12:04:41 1999 +++ pset-linux-2.2.12/include/linux/capability.h Mon Sep 6 17:22:20 1999 @@ -225,6 +225,7 @@ /* Allow enabling/disabling tagged queuing on SCSI controllers and sending arbitrary SCSI commands */ /* Allow setting encryption key on loopback filesystem */ +/* Allow manipulation of psets */ #define CAP_SYS_ADMIN 21 @@ -237,6 +238,7 @@ /* Allow use of FIFO and round-robin (realtime) scheduling on own processes and setting the scheduling algorithm used by another process. */ +/* Allow sysmp(MP_MUSTRUN_PID) and sysmp(MP_RUNANYWHERE_PID) commands */ #define CAP_SYS_NICE 23 diff -ruN clean-linux-2.2.12/include/linux/proc_fs.h pset-linux-2.2.12/include/linux/proc_fs.h --- clean-linux-2.2.12/include/linux/proc_fs.h Wed Aug 25 17:29:53 1999 +++ pset-linux-2.2.12/include/linux/proc_fs.h Tue Sep 7 22:27:05 1999 @@ -20,6 +20,10 @@ PROC_KMSG, PROC_VERSION, PROC_CPUINFO, +#ifdef __SMP__ + PROC_PSETS, + PROC_CPUSTATS, +#endif PROC_PCI, PROC_MCA, PROC_NUBUS, @@ -72,6 +76,9 @@ PROC_PID_RINGBUF, #endif PROC_PID_CPU, +#ifdef __SMP__ + PROC_PID_PSET, +#endif }; enum pid_subdirectory_inos { diff -ruN clean-linux-2.2.12/include/linux/pset.h pset-linux-2.2.12/include/linux/pset.h --- clean-linux-2.2.12/include/linux/pset.h Wed Dec 31 16:00:00 1969 +++ pset-linux-2.2.12/include/linux/pset.h Sun Oct 3 19:36:37 1999 @@ -0,0 +1,180 @@ +#ifndef __LINUX_PSET_H +#define __LINUX_PSET_H + +/* + * Generic processor set support + * Tim Hockin 1998-1999 + * based on work by Stuart Herbert (S.Herbert@sheffield.ac.uk) + */ + +#include +#include +#include +#include + +#define CONFIG_SMP_PSET_DEBUG 1 + +#if defined(CONFIG_SMP_PSET_VERBOSE) && CONFIG_SMP_PSET_DEBUG +#define PRINTD(fmt, args...) printk("Pset: "##fmt, ##args) +#else +#define PRINTD(fmt, args...) +#endif + +#define PSET_VERSION "0.65" +#define PSET_MASTER_PSET 0xFFFF + +/* pset flags */ +#define PSET_FL_MASTER 0x00000001 /* master CPU set */ +#define PSET_FL_CPU 0x00000002 /* single CPU set */ +#define PSET_FL_SYS 0x00000004 /* system CPU set */ +#define PSET_FL_NONPREEMPTIVE 0x00000008 /* non-preemptive CPU set */ +#define PSET_FL_USER 0x00000010 /* user-created CPU set */ + +/* non-enabled CPU prio boosts */ +#define PSET_CPU_RESTRICTED_BOOST 15 +#define PSET_CPU_ISOLATED_BOOST 25 +#define PSET_CPU_NONPREEMPTIVE_BOOST 50 + +/* macros */ +#define pset_is_master_pset(p) (p->flags & PSET_FL_MASTER) +#define pset_is_cpu_pset(p) (p->flags & PSET_FL_CPU) +#define pset_is_sys_pset(p) (p->flags & PSET_FL_SYS) +#define pset_is_nonpreemptive_pset(p) (p->flags & PSET_FL_NONPREEMPTIVE) +#define pset_is_user_pset(p) (p->flags & PSET_FL_USER) +#define pset_is_ro_pset(p) \ + (pset_is_master_pset(p) || pset_is_cpu_pset(p) || pset_is_sys_pset(p)) +#define pset_is_valid_cpumask(m) ((m & pset_cpumask_all) == m) +#define pset_preen_cpumask(m) (m & pset_cpumask_all) +#define pset_cpu_enabled_in_pset(c,p) (p->cpumask & (cpumask_t)1<dis_cpumask & (cpumask_t)1<cpumask == ((cpumask_t)1<flags ^= (pset_cpustats[c]->flags & f)) +#define pset_set_cpu_flag(c,f) (pset_cpustats[c]->flags |= f) + +struct pset_struct { + int id; + cpumask_t cpumask; /* active CPUs in this set */ + cpumask_t dis_cpumask; /* inactive CPUs in this set */ + unsigned int flags; /* flags for this set */ + atomic_t refcount; /* count of processes with this set */ + struct pset_struct *next; + struct pset_struct *prev; +}; + +struct cpustat_struct { + int id; + int flags; /* flags for this cpu */ + atomic_t refcount; /* count of sets with this cpu */ +}; + +/* externally visible functions */ +extern void pset_init(void) __init; +extern struct pset_struct *pset_allocate_pset(int, unsigned int); +extern void pset_deallocate_pset(struct pset_struct *); +extern void pset_add_pset_to_list(struct pset_struct *); +extern void pset_remove_pset_from_list(struct pset_struct *); +extern void pset_add_task_to_pset(struct task_struct *, struct pset_struct *); +extern void pset_remove_task_from_pset(struct task_struct *); +extern void pset_add_cpus_to_pset(cpumask_t, struct pset_struct *); +extern void pset_remove_cpus_from_pset(cpumask_t, struct pset_struct *); +extern void pset_disable_cpus_in_pset(cpumask_t, struct pset_struct *); +extern void pset_enable_cpus_in_pset(cpumask_t, struct pset_struct *); +extern void pset_reset_psets(void); +extern int pset_get_proc_psets(char *); +extern int pset_get_proc_pid_pset(pid_t, char *); +extern int pset_get_proc_cpustats(char *); + +extern int sys_sysmp(int, int, int, int, unsigned long); + +/* extern vars */ +extern struct pset_struct *pset_master; +extern struct pset_struct *pset_list; +extern cpumask_t pset_cpumask_all; +extern struct cpustat_struct *pset_cpustats[NR_CPUS]; +extern rwlock_t pset_lock; +extern rwlock_t pset_cpustat_lock; + +/* inline functions */ +/* ************************************************************ + * pset_not_implemented + * a requested function was not yet implemented + * + * return -ENOSYS + * ***********************************************************/ +extern inline int pset_not_implemented(void) +{ + PRINTD("pset_not_implemented()\n"); + + return -ENOSYS; +} + +/* ************************************************************ + * pset_find_pset + * find a pset by its id + * + * return a pointer to the requested pset_struct + * return NULL if the requested pset does not exist + * ***********************************************************/ +extern inline struct pset_struct *pset_find_pset(int id) +{ + struct pset_struct *pset = pset_list; + + PRINTD("pset_find_pset(%d)\n", id); + + if (id == PSET_MASTER_PSET) { + return pset_master; + } + if (id < 0) { + return NULL; + } + + /* the list should be ordered */ + while (pset && pset->id <= id) { + if (pset->id == id) { + return pset; + } else { + pset = pset->next; + } + } + + return NULL; +} + +/* ************************************************************ + * pset_find_new_pset_id + * find an available pset id + * + * return a positive integer, the pset id, on success + * return -1 when the list is full + * ***********************************************************/ +extern inline int pset_find_new_pset_id(void) +{ + struct pset_struct *pset; + int i; + + PRINTD("pset_find_new_pset_id()\n"); + + i = pset_list->id; + pset = pset_list->next; + + /* + * find the first open spot in the list. we don't look for the + * end, because pset_master is the terminating entry + */ + while (pset) { + /* is there a gap between prev and curr */ + if (pset->id - i > 1) + return i+1; + + i = pset->id; + pset = pset->next; + } + + return -1; +} + +#endif /* ifndef __LINUX_PSET_H */ diff -ruN clean-linux-2.2.12/include/linux/sched.h pset-linux-2.2.12/include/linux/sched.h --- clean-linux-2.2.12/include/linux/sched.h Wed Aug 25 17:29:53 1999 +++ pset-linux-2.2.12/include/linux/sched.h Mon Sep 6 17:22:21 1999 @@ -252,6 +252,8 @@ int processor; int last_processor; int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */ + struct pset_struct *pset; /* pset this process is in */ + int pset_passedover; /* num times we should have been scheduled */ struct task_struct *next_task, *prev_task; struct task_struct *next_run, *prev_run; @@ -365,6 +367,7 @@ /* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain,0, \ /* counter */ DEF_PRIORITY,DEF_PRIORITY,0, \ /* SMP */ 0,0,0,-1, \ +/* pset */ NULL, 0,\ /* schedlink */ &init_task,&init_task, &init_task, &init_task, \ /* binfmt */ NULL, \ /* ec,brk... */ 0,0,0,0,0,0, \ diff -ruN clean-linux-2.2.12/include/linux/sysmp.h pset-linux-2.2.12/include/linux/sysmp.h --- clean-linux-2.2.12/include/linux/sysmp.h Wed Dec 31 16:00:00 1969 +++ pset-linux-2.2.12/include/linux/sysmp.h Mon Sep 6 13:45:16 1999 @@ -0,0 +1,84 @@ +#ifndef __LINUX_SYSMP_H +#define __LINUX_SYSMP_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +/* + * Support for sysmp() system call + * Tim Hockin 1998-1999 + * based on work by Stuart Herbert (S.Herbert@sheffield.ac.uk) + */ + +/* type for CPU bitmasks */ +typedef unsigned long cpumask_t; + +/* this is for SGI compatibility */ +typedef cpumask_t sbv_t; + +/* pda_stat structure (for MP_STAT) */ +struct pda_stat { + int p_cpuid; /* processor ID */ + int p_flags; /* various flags */ + int p_count; /* count of sets with this cpu */ +}; + +/* values for p_flags */ +#define CPUF_ENABLED 0x00000001 /* processor allowed to sched procs */ +#define CPUF_RESTRICTED 0x00000002 /* processor is restricted */ +#define CPUF_ISOLATED 0x00000004 /* processor is isolated */ +#define CPUF_NONPREEMPTIVE 0x00000008 /* processor is non-preemptive */ +#define CPUF_DISABLED 0x00000010 /* processor is disabled */ + +/* for SGI compatibility */ +#define PDAF_ENABLED CPUF_ENABLED +#define PDAF_ISOLATED CPUF_ISOLATED +#define PDAF_NONPREEMPTIVE CPUF_NONPREEMPTIVE +#define PDAF_MASTER 0 +#define PDAF_CLOCK 0 +#define PDAF_FASTCLOCK 0 +#define PDAF_BROADCAST_OFF 0 + +/* sysmp commands */ +#define MP_PGSIZE 1 /* system pagesize */ +#define MP_SCHED 2 /* schedctl - not yet implemented */ +#define MP_NPROCS 3 /* return # processors */ +#define MP_NAPROCS 4 /* return # active processors */ +#define MP_CURPROC 5 /* return the current processor */ +#define MP_STAT 6 /* return a processor status */ +#define MP_RESTRICT 7 /* restrict cpu to mustrun processes */ +#define MP_EMPOWER 8 /* allow cpu to run any process */ +#define MP_ISOLATE 9 /* restrict cpu to cpu pset */ +#define MP_UNISOLATE 10 /* allow cpu to run processes */ +#define MP_DISABLE 11 /* restrict CPU from executing */ +#define MP_ENABLE 12 /* allow CPU to continue running */ +#define MP_NONPREEMPTIVE 13 /* restrict a CPU to related procs */ +#define MP_PREEMPTIVE 14 /* enable normal scheduling */ +#define MP_CLOCK 15 /* ** not yet implemented */ +#define MP_FASTCLOCK 16 /* ** not yet implemented */ +#define MP_MUSTRUN 17 /* force current pid to a pset */ +#define MP_MUSTRUN_PID 18 /* force a pid to a pset */ +#define MP_GETMUSTRUN 19 /* return pset num of current proc */ +#define MP_GETMUSTRUN_PID 20 /* return pset num of a process */ +#define MP_RUNANYWHERE 21 /* run current pid on any cpu */ +#define MP_RUNANYWHERE_PID 22 /* run a pid on any cpu */ +#define MP_KERNADDR 23 /* ** not yet implemented */ +#define MP_SASZ 24 /* ** not yet implemented */ +#define MP_SAGET 25 /* ** not yet implemented */ +#define MP_SAGET1 26 /* ** not yet implemented */ +#define MP_PSET 27 /* pset subcommand */ + +/* MP_PSET sub-commands */ +#define MPPS_CREATE 1 /* create a new pset */ +#define MPPS_DELETE 2 /* delete an existing pset */ +#define MPPS_ADD 3 /* add processors to a pset */ +#define MPPS_REMOVE 4 /* remove processors from a set */ + +/* related values */ +#define PSET_ID_NEW -1 /* find a new pset id for us */ +#define PSET_ALL_CPUS (cpumask_t)ULONG_MAX /* every CPU */ + +#endif /* ifndef __LINUX_SYSMP_H */ diff -ruN clean-linux-2.2.12/init/main.c pset-linux-2.2.12/init/main.c --- clean-linux-2.2.12/init/main.c Mon Aug 9 12:04:41 1999 +++ pset-linux-2.2.12/init/main.c Tue Sep 7 22:30:06 1999 @@ -7,6 +7,7 @@ * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 * Simplified starting of init: Michael A. Griffith + * Added pset support - Tim Hockin Feb '99 */ #define __KERNEL_SYSCALLS__ @@ -50,6 +51,10 @@ extern void nubus_init(void); #endif +#ifdef __SMP__ +#include +#endif + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -1134,6 +1139,8 @@ smp_boot_cpus(); smp_threads_ready=1; smp_commence(); + /* Set up pset stuff */ + pset_init(); } #endif diff -ruN clean-linux-2.2.12/kernel/Makefile pset-linux-2.2.12/kernel/Makefile --- clean-linux-2.2.12/kernel/Makefile Wed May 6 11:01:46 1998 +++ pset-linux-2.2.12/kernel/Makefile Mon Sep 6 13:45:16 1999 @@ -13,7 +13,7 @@ O_TARGET := kernel.o O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ - sysctl.o acct.o capability.o + sysctl.o acct.o capability.o pset.o sysmp.o OX_OBJS += signal.o diff -ruN clean-linux-2.2.12/kernel/exit.c pset-linux-2.2.12/kernel/exit.c --- clean-linux-2.2.12/kernel/exit.c Wed Aug 25 17:29:53 1999 +++ pset-linux-2.2.12/kernel/exit.c Tue Sep 7 22:30:58 1999 @@ -13,6 +13,9 @@ #ifdef CONFIG_BSD_PROCESS_ACCT #include #endif +#ifdef __SMP__ +#include +#endif #include #include @@ -52,6 +55,9 @@ REMOVE_LINKS(p); write_unlock_irq(&tasklist_lock); +#ifdef __SMP__ + pset_remove_task_from_pset(p); +#endif release_thread(p); current->cmin_flt += p->min_flt + p->cmin_flt; current->cmaj_flt += p->maj_flt + p->cmaj_flt; diff -ruN clean-linux-2.2.12/kernel/fork.c pset-linux-2.2.12/kernel/fork.c --- clean-linux-2.2.12/kernel/fork.c Wed Aug 25 17:29:53 1999 +++ pset-linux-2.2.12/kernel/fork.c Tue Sep 7 22:31:16 1999 @@ -17,6 +17,9 @@ #include #include #include +#ifdef __SMP__ +#include +#endif #include #include @@ -652,6 +655,16 @@ /* ?? should we just memset this ?? */ for(i = 0; i < smp_num_cpus; i++) p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + if (p->pset) { + atomic_inc(&(p->pset->refcount)); + } else { + /* this fails on bootup, so CYA */ + if (pset_master) { + write_lock_irq(&pset_lock); + pset_add_task_to_pset(p, pset_master); + write_unlock_irq(&pset_lock); + } + } spin_lock_init(&p->sigmask_lock); } #endif diff -ruN clean-linux-2.2.12/kernel/pset.c pset-linux-2.2.12/kernel/pset.c --- clean-linux-2.2.12/kernel/pset.c Wed Dec 31 16:00:00 1969 +++ pset-linux-2.2.12/kernel/pset.c Sun Oct 3 19:32:34 1999 @@ -0,0 +1,646 @@ +/* + * Generic processor set support + * Tim Hockin 1998-1999 + * based on work by Stuart Herbert + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* private functions */ +void pset_dump_all_psets(void); +void pset_dump_pset(struct pset_struct *); +struct cpustat_struct *pset_allocate_cpustat(int); +void pset_dump_all_cpustats(void); +void pset_dump_cpustat(struct cpustat_struct *); + +/* globals */ +struct pset_struct *pset_master = NULL; +struct pset_struct *pset_list = NULL; +cpumask_t pset_cpumask_all = 0; +struct cpustat_struct *pset_cpustats[NR_CPUS]; +rwlock_t pset_lock = RW_LOCK_UNLOCKED; +rwlock_t pset_cpustat_lock = RW_LOCK_UNLOCKED; + +/* ************************************************************ + * pset_init + * set up the master and CPU psets + * NOTE: we don't need locks here - this is run exactly once. + * + * does not return a value + * ***********************************************************/ +void __init pset_init(void) +{ + int i; + + PRINTD("pset_init()\n"); + + printk("Pset: processor set support version %s\n", PSET_VERSION); + + /* create the master set */ + pset_master = pset_allocate_pset(PSET_MASTER_PSET, PSET_FL_MASTER); + if (!pset_master) { + panic("Unable to allocate memory for master pset!"); + } + pset_add_pset_to_list(pset_master); + + for (i = 0; i < smp_num_cpus; i++) { + struct pset_struct *new_pset; + int cpu; + + cpu = __cpu_logical_map[i]; + + /* create a new set for each CPU */ + new_pset = pset_allocate_pset(cpu, PSET_FL_CPU); + if (!new_pset) { + panic("Unable to create CPU set #%d!", cpu); + } + pset_add_pset_to_list(new_pset); + + /* allocate space for this CPU's stats */ + if (!pset_allocate_cpustat(cpu)) { + panic("Unable to create CPU stat #%d!", cpu); + } + + /* add this CPU to the right sets */ + pset_add_cpus_to_pset((cpumask_t)(1<cpumask | pset_master->dis_cpumask; + + printk("Pset: Created %d processor sets\n", i+1); +#ifdef CONFIG_SMP_PSET_VERBOSE + pset_dump_all_psets(); + pset_dump_all_cpustats(); +#endif +} + +/* ************************************************************ + * pset_reset_psets + * set all tasks to pset_master, enable all CPUs + * this is most likely called by the magic SysRq key + * + * does not return a value + * ***********************************************************/ +void pset_reset_psets(void) +{ + struct task_struct *p; + struct pset_struct *pset = pset_list; + int cpu; + int i; + + PRINTD("pset_reset_psets()\n"); + + /* assign all tasks to pset_master */ + read_lock(&tasklist_lock); + for_each_task(p) + pset_add_task_to_pset(p, pset_master); + read_unlock(&tasklist_lock); + + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + + /* enable all CPUs - forcefully*/ + for (i = 0; i < smp_num_cpus ; i++) { + cpu = __cpu_logical_map[i]; + pset_unset_cpu_flag(cpu, 0xFFFF); + pset_set_cpu_flag(cpu, CPUF_ENABLED); + } + + /* enable all CPUs in all psets - again, forcefully*/ + while (pset) { + pset_enable_cpus_in_pset(pset_cpumask_all, pset); + pset = pset->next; + } + + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + + printk("Pset: All tasks set to master pset, all CPUs enabled\n"); +} + + +/* ************************************************************ + * pset_dump_all_psets + * display a dump for every pset + * + * does not return a value + * ***********************************************************/ +void pset_dump_all_psets(void) +{ + struct pset_struct *pset = pset_list; + + PRINTD("pset_dump_all_psets()\n"); + + while (pset) { + pset_dump_pset(pset); + pset = pset->next; + } +} + +/* ************************************************************ + * pset_dump_pset + * display info about a pset + * + * does not return a value + * ***********************************************************/ +void pset_dump_pset(struct pset_struct *pset) +{ + int count = 0; + cpumask_t tmp; + + PRINTD("pset_dump_pset(pset id %d)\n", pset->id); + + tmp = pset->cpumask | pset->dis_cpumask; + while (tmp) { + if (tmp & 1) { + count++; + } + tmp >>= 1; + } + + printk("Pset: pset id: %5d, #CPUs: %5d, cpumask: 0x%08lX, flags: ", + pset->id, count, (pset->cpumask|pset->dis_cpumask)); + if (pset_is_master_pset(pset)) { + printk("master"); + } else if (pset_is_cpu_pset(pset)) { + printk("cpu"); + } else if (pset_is_sys_pset(pset)) { + printk("sys"); + } else if (pset_is_nonpreemptive_pset(pset)) { + printk("non-preemptive"); + } else if (pset_is_user_pset(pset)) { + printk("user"); + } + + printk("\n"); +} + +/* ************************************************************ + * pset_dump_all_cpustats + * display a dump for every cpustat + * + * does not return a value + * ***********************************************************/ +void pset_dump_all_cpustats(void) +{ + int i; + + PRINTD("pset_dump_all_cpustats()\n"); + + for (i = 0; i < NR_CPUS; i++) { + if (pset_cpustats[i]) { + pset_dump_cpustat(pset_cpustats[i]); + } + } +} + +/* ************************************************************ + * pset_dump_cpustat + * display a dump for a cpustat + * + * does not return a value + * ***********************************************************/ +void pset_dump_cpustat(struct cpustat_struct *cpustat) +{ + PRINTD("pset_dump_cpustat(cpustat id %d)\n", cpustat->id); + + printk("Pset: cpustat id: %5d, refcount: %5d, flags: ", + cpustat->id, atomic_read(&(cpustat->refcount))); + + if (cpustat->flags & CPUF_ENABLED) { + printk("enabled "); + } + if (cpustat->flags & CPUF_RESTRICTED) { + printk("restricted "); + } + if (cpustat->flags & CPUF_ISOLATED) { + printk("isolated "); + } + if (cpustat->flags & CPUF_DISABLED) { + printk("disabled "); + } + if (cpustat->flags & CPUF_NONPREEMPTIVE) { + printk("non-preemptive "); + } + printk("\n"); +} + +/* ************************************************************ + * pset_allocate_pset + * kmalloc some memory and set some fields + * + * return pointer to new pset_struct on success + * return NULL if no memory available + * ***********************************************************/ +struct pset_struct *pset_allocate_pset(int id, unsigned int flags) +{ + struct pset_struct *new_pset = NULL; + + PRINTD("pset_allocate_pset(%d, %u)\n", id, flags); + + new_pset = (struct pset_struct *)kmalloc(sizeof(struct pset_struct), + GFP_KERNEL); + + if (new_pset) { + new_pset->id = id; + new_pset->cpumask = (cpumask_t)0; + new_pset->dis_cpumask = (cpumask_t)0; + new_pset->flags = flags; + atomic_set(&(new_pset->refcount), 0); + new_pset->next = NULL; + new_pset->prev = NULL; + } + + return new_pset; +} + +/* ************************************************************ + * pset_deallocate_pset + * free a pset + * + * does not return a value + * ***********************************************************/ +void pset_deallocate_pset(struct pset_struct *pset) +{ + PRINTD("pset_deallocate_pset(pset id %d)\n", pset->id); + + pset_remove_cpus_from_pset(pset->cpumask|pset->dis_cpumask, pset); + pset_remove_pset_from_list(pset); + + kfree(pset); +} + +/* ************************************************************ + * pset_allocate_cpustat + * kmalloc some memory and set some fields + * + * return pointer to new cpustat_struct on success + * return NULL if no memory available + * ***********************************************************/ +struct cpustat_struct *pset_allocate_cpustat(int cpu) +{ + struct cpustat_struct *new_stat = NULL; + + PRINTD("pset_allocate_cpustat(%d)\n", cpu); + + new_stat = (struct cpustat_struct *)kmalloc(sizeof + (struct cpustat_struct), GFP_KERNEL); + + if (new_stat) { + new_stat->id = cpu; + new_stat->flags = CPUF_ENABLED; + atomic_set(&(new_stat->refcount), 0); + } + + pset_cpustats[cpu] = new_stat; + + return new_stat; +} + +/* ************************************************************ + * pset_add_pset_to_list + * Add a pset_struct to the ordered pset_list + * + * does not return a value + * ***********************************************************/ +void pset_add_pset_to_list(struct pset_struct *pset) +{ + struct pset_struct **tmp; + + PRINTD("pset_add_pset_to_list(pset id %d)\n", pset->id); + + tmp = &pset_list; + while (*tmp) { + if ((*tmp)->id < pset->id) { + tmp = &((*tmp)->next); + } else { + break; + } + } + + /* pset_list is implicitly handled */ + pset->next = *tmp; + if (*tmp) { + pset->prev = (*tmp)->prev; + (*tmp)->prev = pset; + } + *tmp = pset; +} + +/* ************************************************************ + * pset_remove_pset_from_list + * Remove a pset_struct from the ordered pset_list + * + * does not return a value + * ***********************************************************/ +void pset_remove_pset_from_list(struct pset_struct *pset) +{ + PRINTD("pset_remove_pset_from_list(pset id %d)\n", pset->id); + + /* explicitly handle this */ + if (pset_list == pset) { + pset_list = pset->next; + } + + if (pset->next) { + pset->next->prev = pset->prev; + } + if (pset->prev) { + pset->prev->next = pset->next; + } +} + +/* ************************************************************ + * pset_add_cpus_to_pset + * add a cpumask_t mask of cpus to a pset_struct + * + * does not return a value + * ***********************************************************/ +void pset_add_cpus_to_pset(cpumask_t cpus, struct pset_struct *pset) +{ + cpumask_t tmp; + int i = 0; + + PRINTD("pset_add_cpus_to_pset(%lu, pset id %d)\n", cpus, pset->id); + + /* + * only add cpus we don't have - this check is so we don't add one to + * cpumask, while it already is in dis_cpumask + */ + cpus ^= ((pset->cpumask|pset->dis_cpumask) & cpus); + pset->cpumask |= cpus; + + tmp = cpus; + while (tmp) { + if (cpus & (cpumask_t)1<refcount)); + /* make sure to obey the cpu restriction level */ + if (pset_cpustats[i]->flags != CPUF_ENABLED) + pset_disable_cpus_in_pset((cpumask_t)1<>= 1; + i++; + } +} + +/* ************************************************************ + * pset_remove_cpus_from_pset + * remove a cpumask_t mask of cpus from a pset_struct + * + * does not return a value + * ***********************************************************/ +void pset_remove_cpus_from_pset(cpumask_t cpus, struct pset_struct *pset) +{ + cpumask_t tmp; + int i = 0; + + PRINTD("pset_remove_cpus_from_pset(%lu, pset id %d)\n",cpus,pset->id); + + tmp = cpus & (pset->cpumask|pset->dis_cpumask); + + /* remove the cpus from the active and disable masks */ + pset->cpumask &= ~cpus; + pset->dis_cpumask &= ~cpus; + + while (tmp) { + if (cpus & (cpumask_t)1<refcount)); + } + tmp >>= 1; + i++; + } +} + +/* ************************************************************ + * pset_add_task_to_pset + * associate a pset with a task + * + * does not return a value + * ***********************************************************/ +void pset_add_task_to_pset(struct task_struct *p, struct pset_struct *pset) +{ + PRINTD("pset_add_task_to_pset(task id %d, pset id %d)\n", + p->pid ,pset->id); + + if (p->pset) { + pset_remove_task_from_pset(p); + } + + p->pset = pset; + atomic_inc(&(pset->refcount)); +} + +/* ************************************************************ + * pset_remove_task_from_pset + * disassociate a task from any pset + * this is in teh exit() path - try to keep it small + * + * does not return a value + * ***********************************************************/ +void pset_remove_task_from_pset(struct task_struct *p) +{ + /* this is an obnoxious message - this happens a LOT */ + /* PRINTD("pset_remove_task_from_pset(task id %d)\n",p->pid); */ + + if (!p->pset) + return; + + if (atomic_read(&(p->pset->refcount))) { + atomic_dec(&(p->pset->refcount)); + } else { + printk("Pset: Tried to decrement zero refcount for pset %d, + pid %d\n", p->pset->id, p->pid); + } + +#ifdef FIGURED_OUT_NONPREEMPTIVE + /* if this is a stolen set, and the last task, clean it up */ + /* FIXME: I don't like this here... */ + if (pset_is_nonpreemptive_pset(p->pset) + && !atomic_read(&(p->pset->refcount))) { + pset_remove_cpus_from_pset( + p->pset->cpumask|p->pset->dis_cpumask, p->pset); + kfree(p->pset); + } +#endif + + p->pset = NULL; +} + +/* ************************************************************ + * pset_disable_cpus_in_pset + * move a set of cpus from the cpumask to dis_cpumask field + * + * does not return a value + * ***********************************************************/ +void pset_disable_cpus_in_pset(cpumask_t cpus, struct pset_struct *pset) +{ + PRINTD("pset_disable_cpus_in_pset(%lu, pset id %d)\n", cpus, + pset->id); + + /* only deal with CPUs that are active in this set */ + cpus &= pset->cpumask; + + pset->cpumask &= ~cpus; + pset->dis_cpumask |= cpus; +} + +/* ************************************************************ + * pset_enable_cpus_in_pset + * move a set of cpus from the dis_cpumask to cpumask field + * + * does not return a value + * ***********************************************************/ +void pset_enable_cpus_in_pset(cpumask_t cpus, struct pset_struct *pset) +{ + PRINTD("pset_enable_cpus_in_pset(%lu, pset id %d)\n", cpus, + pset->id); + + /* only deal with CPUs that are disabled in this set */ + cpus &= pset->dis_cpumask; + + pset->dis_cpumask &= ~cpus; + pset->cpumask |= cpus; +} + +/* ************************************************************ + * pset_get_proc_psets + * fill buf with the output for /proc/psets + * + * returns the length of the buffer + * ***********************************************************/ +int pset_get_proc_psets(char *buf) +{ + int len; + struct pset_struct *pset; + + PRINTD("pset_get_proc_psets(buf)\n"); + + len=sprintf(buf, " Pset NumCPUs CPUs (active) (disabled) Refs Flags\n"); + + read_lock(&pset_lock); + for (pset = pset_list; pset; pset = pset->next) { + int count = 0; + cpumask_t tmp = pset->cpumask | pset->dis_cpumask; + + /* avoid overflowing buffer */ + if (len > EXEC_PAGESIZE - 100) { + break; + } + + while (tmp) { + if (tmp & 1) { + count++; + } + tmp >>= 1; + } + + len += sprintf(buf+len, "%5d %5d 0x%08lX 0x%08lx %5d ", + pset->id, count, pset->cpumask, pset->dis_cpumask, + atomic_read(&(pset->refcount))); + + if (pset_is_master_pset(pset)) { + len += sprintf(buf+len, "master\n"); + } else if (pset_is_cpu_pset(pset)) { + len += sprintf(buf+len, "cpu\n"); + } else if (pset_is_sys_pset(pset)) { + len += sprintf(buf+len, "sys\n"); + } else if (pset_is_nonpreemptive_pset(pset)) { + len += sprintf(buf+len, "non-preemptive\n"); + } else if (pset_is_user_pset(pset)) { + len += sprintf(buf+len, "user\n"); + } + } + read_unlock(&pset_lock); + + return len; +} + +/* ************************************************************ + * pset_get_proc_pid_pset + * fill buf with the output for /proc/PID/pset + * + * returns the length of the buffer + * ***********************************************************/ +int pset_get_proc_pid_pset(pid_t pid, char *buf) +{ + struct task_struct *p = current ; + int len; + + PRINTD("pset_get_proc_pid_pset(pid %d, buf)\n", pid); + + read_lock(&tasklist_lock); + if (pid != p->pid) { + p = find_task_by_pid(pid); + } + + if (!p || !p->mm) { + return 0; + } + + if (p->pset == NULL) { + len = sprintf(buf, "None\n"); + } else { + len = sprintf(buf, "%d\n", p->pset->id); + } + read_unlock(&tasklist_lock); + + return len; +} + +/* ************************************************************ + * pset_get_proc_cpustats + * fill the buffer with info for /proc/cpustats + * + * return the length of the buffer + * ***********************************************************/ +int pset_get_proc_cpustats(char *buf) +{ + int len; + int i; + + PRINTD("pset_get_proc_cpustats(buf)\n"); + + len=sprintf(buf, " CPU Refs Flags\n"); + + read_lock(&pset_cpustat_lock); + for (i = 0; i < NR_CPUS; i++) { + if (!pset_cpustats[i]) { + continue; + } + + len += sprintf(buf+len, "%5d %5d ", + pset_cpustats[i]->id, + atomic_read(&(pset_cpustats[i]->refcount))); + + if (pset_cpustats[i]->flags & CPUF_ENABLED) { + len += sprintf(buf+len, "enabled "); + } + if (pset_cpustats[i]->flags & CPUF_RESTRICTED) { + len += sprintf(buf+len, "restricted "); + } + if (pset_cpustats[i]->flags & CPUF_ISOLATED) { + len += sprintf(buf+len, "isolated "); + } + if (pset_cpustats[i]->flags & CPUF_DISABLED) { + len += sprintf(buf+len, "disabled "); + } + if (pset_cpustats[i]->flags & CPUF_NONPREEMPTIVE) { + len += sprintf(buf+len, "non-preemptive "); + } + len += sprintf(buf+len, "\n"); + } + read_unlock(&pset_cpustat_lock); + + return len; +} diff -ruN clean-linux-2.2.12/kernel/sched.c pset-linux-2.2.12/kernel/sched.c --- clean-linux-2.2.12/kernel/sched.c Mon May 10 09:55:21 1999 +++ pset-linux-2.2.12/kernel/sched.c Tue Sep 7 22:33:01 1999 @@ -15,6 +15,7 @@ * Copyright (C) 1998 Andrea Arcangeli * 1998-12-28 Implemented better SMP scheduling by Ingo Molnar * 1999-03-10 Improved NTP compatibility by Ulrich Windl + * 1999-04-03 Added pset handling - Tim Hockin */ /* @@ -31,6 +32,9 @@ #include #include #include +#ifdef __SMP__ +#include +#endif #include #include @@ -116,6 +120,7 @@ #define idle_task(cpu) (task[cpu_number_map[(cpu)]]) #define can_schedule(p) (!(p)->has_cpu) +#define pset_can_schedule(p,cpu) (!(p->pset) || ((p->pset->cpumask)&(1<processor == this_cpu) weight += PROC_CHANGE_PENALTY; -#endif + + /* let's not deal with psets on the idle task */ + if (!p->pid) + goto pset_out; + + /* give p a good advantage if it has been passed over */ + weight += ((p->pset_passedover)*(PROC_CHANGE_PENALTY/2)); + + /* give an advantage if this cpu is in a non-enabled state */ + if (pset_cpustats[this_cpu]->flags != CPUF_ENABLED) + goto pset_cpu_not_enabled; + +pset_out: +#endif /* #ifdef __SMP__ */ /* .. and a slight advantage to the current MM */ if (p->mm == prev->mm) @@ -180,6 +201,36 @@ out: return weight; + +#ifdef __SMP__ +pset_cant_sched: + /* + * penalize p if it can't be run on this_cpu + * this has the effect of making us recalc counters + * more frequently if this_cpu is in a restricted state + */ + weight -= ((p->pset_passedover) * PROC_CHANGE_PENALTY); + goto pset_out; + +pset_cpu_not_enabled: + /* + * give a boost to a process that is eligible to run on a CPU that is + * in some non-enabled state. this boost is proportional to the + * severity of the processors state - more restricted = higher boost + */ + switch(pset_cpustats[this_cpu]->flags) { + case CPUF_RESTRICTED: + weight += PSET_CPU_RESTRICTED_BOOST; + break; + case CPUF_ISOLATED: + weight += PSET_CPU_ISOLATED_BOOST; + break; + case CPUF_ISOLATED|CPUF_NONPREEMPTIVE: + weight += PSET_CPU_NONPREEMPTIVE_BOOST; + break; + } + goto pset_out; +#endif } /* @@ -769,6 +820,17 @@ p = p->next_run; } +#ifdef __SMP__ + /* see if next is actually able to run on this_cpu */ + if (!pset_can_schedule(next, this_cpu)) + goto pset_cant_sched; + + /* we can happily schedule, passedover gets reset */ + next->pset_passedover = 0; + +pset_cant_sched_back: +#endif + /* Do we need to re-calculate counters? */ if (!c) goto recalculate; @@ -864,6 +926,27 @@ printk("Scheduling in interrupt\n"); *(int *)0 = 0; return; + +#ifdef __SMP__ +pset_cant_sched: + /* increment this - next _SHOULD_ be running */ + next->pset_passedover++; + + /* see if we can run next now, just on another cpu */ + spin_unlock_irq(&runqueue_lock); + /* this also serves as a delay for other CPUs to grab this lock */ + reschedule_idle(next); + spin_lock_irq(&runqueue_lock); + + if (prev->pid) { + /* break a process context by running idle */ + next = idle_task(this_cpu); + goto pset_cant_sched_back; + } + + /* try again */ + goto repeat_schedule; +#endif } rwlock_t waitqueue_lock = RW_LOCK_UNLOCKED; diff -ruN clean-linux-2.2.12/kernel/sysmp.c pset-linux-2.2.12/kernel/sysmp.c --- clean-linux-2.2.12/kernel/sysmp.c Wed Dec 31 16:00:00 1969 +++ pset-linux-2.2.12/kernel/sysmp.c Sun Oct 3 19:31:37 1999 @@ -0,0 +1,1045 @@ +/* + * Support for sysmp() system call + * Tim Hockin 1998-1999 + * based on work by Stuart Herbert (S.Herbert@sheffield.ac.uk) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* private functions */ +int sysmp_pgsize(void); +int sysmp_nprocs(void); +int sysmp_naprocs(void); +int sysmp_curproc(void); +int sysmp_stat(struct pda_stat *); +int sysmp_restrict(int); +int sysmp_empower(int); +int sysmp_isolate(int); +int sysmp_unisolate(int); +int sysmp_disable(int); +int sysmp_enable(int); +int sysmp_nonpreemptive(int); +int sysmp_preemptive(int); +int sysmp_mustrun(int); +int sysmp_mustrun_pid(int, pid_t); +int sysmp_getmustrun(void); +int sysmp_getmustrun_pid(pid_t); +int sysmp_runanywhere(void); +int sysmp_runanywhere_pid(pid_t); +int sysmp_pset_create(int, cpumask_t); +int sysmp_pset_delete(int); +int sysmp_pset_add(int, cpumask_t); +int sysmp_pset_remove(int, cpumask_t); + +/* ************************************************************ + * sys_sysmp + * The system call between us and the outside world + * + * return a positive value or zero on success (depends on cmd) + * return a negative value on error, indicating the error + * ***********************************************************/ +asmlinkage int sys_sysmp(int cmd, int i1, int i2, int i3, unsigned long ul) +{ + int result = 0; + + PRINTD("sys_sysmp(%d, %d, %d, %d, %lu)\n", cmd, i1, + i2, i3, ul); + + /* All functions are stubbed here, but not all are implemented */ + switch (cmd) { + case MP_PGSIZE: + result = sysmp_pgsize(); + break; + + case MP_SCHED: + result = pset_not_implemented(); + break; + + case MP_NPROCS: + result = sysmp_nprocs(); + break; + + case MP_NAPROCS: + result = sysmp_naprocs(); + break; + + case MP_CURPROC: + result = sysmp_curproc(); + break; + + case MP_STAT: + read_lock(&pset_cpustat_lock); + result = sysmp_stat((struct pda_stat *)ul); + read_unlock(&pset_cpustat_lock); + break; + + case MP_RESTRICT: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_restrict(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_EMPOWER: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_empower(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_ISOLATE: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_isolate(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_UNISOLATE: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_unisolate(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_DISABLE: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_disable(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_ENABLE: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_enable(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_NONPREEMPTIVE: + /* FIXME: do we need tasklist_lock for current ? */ + /* FIXME: this doesn't quite work as expected. + * we end up running idle some of the time on the + * non-preemptive CPU. Maybe this should be removed + * completely, or else we need per-CPU run-queues. + */ + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_nonpreemptive(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_PREEMPTIVE: + /* FIXME: do we need tasklist_lock for current ? */ + /* FIXME: should exit() call this if the last process + * derived form the caller of NONPREEMPTIVE does not? + */ + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_preemptive(i1); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MP_CLOCK: + result = pset_not_implemented(); + break; + + case MP_FASTCLOCK: + result = pset_not_implemented(); + break; + + case MP_MUSTRUN: + /* FIXME: do we need tasklist_lock for current ? */ + write_lock(&pset_lock); + result = sysmp_mustrun(i1); + write_unlock(&pset_lock); + break; + + case MP_MUSTRUN_PID: + write_lock(&pset_lock); + /* FIXME: is read_lock sufficient here? */ + read_lock(&tasklist_lock); + result = sysmp_mustrun_pid(i1, (pid_t)i2); + read_unlock(&tasklist_lock); + write_unlock(&pset_lock); + break; + + case MP_GETMUSTRUN: + /* FIXME: do we need tasklist_lock for current ? */ + write_lock(&pset_lock); + result = sysmp_getmustrun(); + write_unlock(&pset_lock); + break; + + case MP_GETMUSTRUN_PID: + write_lock(&pset_lock); + /* FIXME: is read_lock sufficient here? */ + read_lock(&tasklist_lock); + result = sysmp_getmustrun_pid((pid_t)i1); + read_unlock(&tasklist_lock); + write_unlock(&pset_lock); + break; + + case MP_RUNANYWHERE: + /* FIXME: do we need tasklist_lock for current ? */ + write_lock(&pset_lock); + result = sysmp_runanywhere(); + write_unlock(&pset_lock); + break; + + case MP_RUNANYWHERE_PID: + write_lock(&pset_lock); + /* FIXME: is read_lock sufficient here? */ + read_lock(&tasklist_lock); + result = sysmp_runanywhere_pid((pid_t)i1); + read_unlock(&tasklist_lock); + write_unlock(&pset_lock); + break; + + case MP_KERNADDR: + result = pset_not_implemented(); + break; + + case MP_SASZ: + result = pset_not_implemented(); + break; + + case MP_SAGET: + /* make sure to note the order of arguments... + i1 is int, i2 is int, ul is (char *). + they should go to the handler as i1, ul, i2. + */ + result = pset_not_implemented(); + break; + + case MP_SAGET1: + /* make sure to note the order of arguments... + i1 is int, i2 is int, ul is (char*), i3 is int. + they should go to the handler as + i1, ul, i2, i3. + */ + result = pset_not_implemented(); + break; + + case MP_PSET: + switch (i1) { + case MPPS_CREATE: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_pset_create((int)i2, (cpumask_t)ul); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MPPS_DELETE: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_pset_delete((int)i2); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MPPS_ADD: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_pset_add(i2, (cpumask_t)ul); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + case MPPS_REMOVE: + write_lock(&pset_lock); + write_lock(&pset_cpustat_lock); + result = sysmp_pset_remove(i2, (cpumask_t)ul); + write_unlock(&pset_cpustat_lock); + write_unlock(&pset_lock); + break; + + default: + result = -EINVAL; + } + break; + default: + result = -EINVAL; + } + + PRINTD("sys_sysmp() returning %d\n", result); + + return result; +} + +/* *************************************************************** + * sysmp_pgsize + * get the system pagesize + * + * return the value of EXEC_PAGESIZE + * does not fail + * **************************************************************/ +int sysmp_pgsize(void) +{ + PRINTD("sysmp_pgsize()\n"); + + return EXEC_PAGESIZE; +} + +/* *************************************************************** + * sysmp_nprocs + * get the number of processors in the system + * + * return the count of cpus + * does not fail + * **************************************************************/ +int sysmp_nprocs(void) +{ + PRINTD("sysmp_nprocs()\n"); + + return smp_num_cpus; +} + +/* *************************************************************** + * sysmp_naprocs + * get the number of active processors in the master set + * + * return the count of active cpus + * does not fail + * **************************************************************/ +int sysmp_naprocs(void) +{ + cpumask_t tmp; + int count = 0; + + PRINTD("sysmp_naprocs()\n"); + + tmp = pset_master->cpumask; + while (tmp) { + if (tmp & 1) { + count++; + } + tmp >>= 1; + } + + return count; +} + +/* *************************************************************** + * sysmp_curproc + * get the number of the current processor + * + * returns the current CPU number + * does not fail + * **************************************************************/ +int sysmp_curproc(void) +{ + PRINTD("sysmp_curproc()\n"); + + return current->processor; +} + +/* ************************************************************ + * sysmp_stat + * fill a buffer with pda_stat structures, from pset_cpustats + * + * returns 0 on success + * returns -1 if buffer is invalid + * ***********************************************************/ +int sysmp_stat(struct pda_stat *ptr) +{ + struct pda_stat tmp; + int i; + + PRINTD("pset_mp_stat(%p)\n", ptr); + + if (verify_area(VERIFY_WRITE, ptr, + sizeof(struct pda_stat)*smp_num_cpus)) { + return -1; + } + + for (i = 0; i < smp_num_cpus; i++) { + struct cpustat_struct *cs; + + cs = pset_cpustats[__cpu_logical_map[i]]; + tmp.p_cpuid = cs->id; + tmp.p_count = atomic_read(&(cs->refcount)); + tmp.p_flags = cs->flags; + + copy_to_user(&ptr[i], &tmp, sizeof(struct pda_stat)); + } + + return 0; +} + +/* ************************************************************ + * sysmp_restrict + * restrict a procesor to running only MUSTRUN processes + * i.e. - disable it in the master pset + * + * returns 0 on success + * returns -EPERM if the caller is not super-user + * returns -EINVAL if the requested CPU does not exist + * returns -EBUSY if the requested CPU is the last unrestricted CPU + * returns -EBUSY if the CPU is not ENABLED + * ***********************************************************/ +int sysmp_restrict(int cpu) +{ + PRINTD("sysmp_restrict(%d)\n", cpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pset_is_valid_cpumask((cpumask_t)1<flags != CPUF_ENABLED) + return -EBUSY; + + /* set CPU flags */ + pset_unset_cpu_flag(cpu, CPUF_ENABLED); + pset_set_cpu_flag(cpu, CPUF_RESTRICTED); + + /* set cpumasks */ + pset_disable_cpus_in_pset((cpumask_t)1<processor == cpu) { + current->need_resched = 1; + } + + return 0; +} + +/* ************************************************************ + * sysmp_empower + * enable a processor to run any process + * i.e. - enable it in the master pset + * + * returns 0 on success + * returns 0 if the CPU is not restricted + * returns -EPERM if the caller is not super-user + * returns -EINVAL if the requested CPU does not exist + * ***********************************************************/ +int sysmp_empower(int cpu) +{ + PRINTD("sysmp_empower(%d)\n", cpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pset_is_valid_cpumask((cpumask_t)1<flags == CPUF_RESTRICTED) { + /* set CPU flags */ + pset_unset_cpu_flag(cpu, CPUF_RESTRICTED); + pset_set_cpu_flag(cpu, CPUF_ENABLED); + + /* set the cpumask */ + pset_enable_cpus_in_pset((cpumask_t)1<flags != CPUF_ENABLED) + return -EBUSY; + + /* set CPU flags */ + pset_unset_cpu_flag(cpu, CPUF_ENABLED); + pset_set_cpu_flag(cpu, CPUF_ISOLATED); + + /* set cpumasks - turn it off in all sets but its own */ + pset = pset_list; + while (pset) { + if (pset_cpu_enabled_in_pset(cpu, pset) && pset->id != cpu) { + pset_disable_cpus_in_pset((cpumask_t)1<next; + } + + /* did we just isolate the current processor ? */ + if (current->processor == cpu) { + current->need_resched = 1; + } + + return 0; +} + +/* ************************************************************ + * sysmp_unisolate + * enable a processor to run any process + * i.e. - enable it in any set that has it, maybe the master set + * + * returns 0 on success + * returns 0 if the CPU is not isolated + * returns -EPERM if the caller is not super-user + * returns -EINVAL if the requested CPU does not exist + * ***********************************************************/ +int sysmp_unisolate(int cpu) +{ + struct pset_struct *pset; + + PRINTD("sysmp_unisolate(%d)\n", cpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pset_is_valid_cpumask((cpumask_t)1<flags == CPUF_ISOLATED) { + /* set CPU flags */ + pset_unset_cpu_flag(cpu, CPUF_ISOLATED); + pset_set_cpu_flag(cpu, CPUF_ENABLED); + + /* set cpumasks */ + pset = pset_list; + while (pset) { + if (pset_cpu_disabled_in_pset(cpu, pset)) { + pset_enable_cpus_in_pset((cpumask_t)1<next; + } + } + return 0; +} + +/* ************************************************************ + * sysmp_disable + * disable a procesor from running any processes (take it offline) + * i.e. - disable it in all sets + * + * returns 0 on success + * returns -EPERM if the caller is not super-user + * returns -EINVAL if the requested CPU does not exist + * returns -EBUSY if the requested CPU is the last unrestricted CPU + * returns -EBUSY if the CPU is not ENABLED + * ***********************************************************/ +int sysmp_disable(int cpu) +{ + struct pset_struct *pset; + + PRINTD("sysmp_disable(%d)\n", cpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pset_is_valid_cpumask((cpumask_t)1<flags != CPUF_ENABLED) + return -EBUSY; + + /* set CPU flags */ + pset_unset_cpu_flag(cpu, CPUF_ENABLED); + pset_set_cpu_flag(cpu, CPUF_DISABLED); + + /* set cpumasks - turn it off in all sets */ + pset = pset_list; + while (pset) { + if (pset_cpu_enabled_in_pset(cpu, pset)) { + pset_disable_cpus_in_pset((cpumask_t)1<next; + } + + /* did we just disable the current processor ? */ + if (current->processor == cpu) { + current->need_resched = 1; + } + + return 0; +} + +/* ************************************************************ + * sysmp_enable + * enable a processor to run processes + * i.e. - enable it in any set that has it + * + * returns 0 on success + * returns 0 if the CPU is not disabled + * returns -EPERM if the caller is not super-user + * returns -EINVAL if the requested CPU does not exist + * ***********************************************************/ +int sysmp_enable(int cpu) +{ + struct pset_struct *pset; + + PRINTD("sysmp_enable(%d)\n", cpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pset_is_valid_cpumask((cpumask_t)1<flags == CPUF_DISABLED) { + /* set CPU flags */ + pset_unset_cpu_flag(cpu, CPUF_DISABLED); + pset_set_cpu_flag(cpu, CPUF_ENABLED); + + /* set cpumasks */ + pset = pset_list; + while (pset) { + if (pset_cpu_disabled_in_pset(cpu, pset)) { + pset_enable_cpus_in_pset((cpumask_t)1<next; + } + } + + return 0; +} + +/* ************************************************************ + * sysmp_nonpreemptive + * restrict a CPU to running the current and child processes + * + * returns 0 on success + * returns -EPERM if user is not root + * returns -EINVAL if the requested CPU does not exist + * returns -EBUSY if the requested CPU is the last unrestricted CPU + * returns -EBUSY if the CPU is not isolated + * returns -ENOMEM if no memory is available for a new set + * ***********************************************************/ +int sysmp_nonpreemptive(int cpu) +{ +#ifdef FIGURED_OUT_NONPREEMPTIVE + struct pset_struct *pset, + *new; + + PRINTD("sysmp_nonpreemptive(%d)\n", cpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pset_is_valid_cpumask((cpumask_t)1<flags != CPUF_ISOLATED) + return -EBUSY; + + /* we create a set, but do not add it to the pset_list */ + /* do this here, so we can return if no mem is available */ + new = pset_allocate_pset(-1, PSET_FL_NONPREEMPTIVE); + if (!new) + return -ENOMEM; + + /* set CPU flags */ + pset_unset_cpu_flag(cpu, CPUF_ENABLED); + pset_set_cpu_flag(cpu, CPUF_NONPREEMPTIVE); + + /* set cpumasks - we are isolated, so turn it off in its own set */ + pset = pset_list; + while (pset) { + if (pset->id == cpu) { + pset_disable_cpus_in_pset((cpumask_t)1<next; + } + + /* set up the new set */ + pset = current->pset; + new->id = (pset) ? (0-(pset->id)) : (0-PSET_MASTER_PSET); + + pset_add_cpus_to_pset((cpumask_t)1<pset */ + pset_remove_task_from_pset(current); + pset_add_task_to_pset(current, new); +#endif + + return 0; +} + +/* ************************************************************ + * sysmp_preemptive + * enable a CPU to run general processes + * + * returns 0 on success + * returns 0 if the CPU is not non-preemptive + * returns -EPERM if user is not root + * returns -EINVAL if the requested CPU does not exist + * ***********************************************************/ +int sysmp_preemptive(int cpu) +{ +#ifdef FIGURED_OUT_NONPREEMPTIVE + struct pset_struct *pset; + + PRINTD("sysmp_preemptive(%d)\n", cpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pset_is_valid_cpumask((cpumask_t)1<flags == CPUF_NONPREEMPTIVE) { + /* set CPU flags - we should be isolated now */ + pset_unset_cpu_flag(cpu, CPUF_NONPREEMPTIVE); + + /* set cpumasks - we should still be isolated */ + pset = pset_list; + while (pset) { + if (pset->id == cpu) { + pset_enable_cpus_in_pset((cpumask_t)1<next; + } + + /* if this process was bound to the stolen CPU, restore its state */ + if (pset_is_nonpreemptive_pset(current->pset) && + pset_cpu_is_in_pset(cpu, current->pset)) { + pset = pset_find_pset(0-current->pset->id); + + /* this will handle freeing it if it is unused */ + pset_remove_task_from_pset(current); + pset_add_task_to_pset(current, pset ? pset : pset_master); + } + } + + /* + * just as a note: if a different process calls this than called + * nonpreemptive, the original process will still be bound to this + * pset. That process will eventually be removed from the pset, + * via a call here, a mustrun, or exit -- see the code in + * pset_remove_task_from_pset for details. + */ +#endif + + return 0; +} + +/* ************************************************************ + * sysmp_mustrun + * restrict the current process to a pset + * + * returns 0 on success + * returns -EINVAL if the requested pset does not exist + * ***********************************************************/ +int sysmp_mustrun(int pset_id) +{ + struct pset_struct *pset; + + PRINTD("sysmp_mustrun(%d)\n", pset_id); + + pset = pset_find_pset(pset_id); + if (pset) { + pset_remove_task_from_pset(current); + pset_add_task_to_pset(current, pset); + + /* are we currently on some other cpu, not in this set ? */ + if (!pset_cpu_is_in_pset(current->processor, pset)) { + current->need_resched = 1; + } + + return 0; + } + + return -EINVAL; +} + +/* ************************************************************ + * sysmp_mustrun_pid + * restrict a process to a pset + * + * returns 0 on success + * returns -ESRCH if the target task does not exist + * returns -EPERM if the target process is not modifiable by this user + * returns -EINVAL if the requested pset does not exist + * ***********************************************************/ +int sysmp_mustrun_pid(int pset_id, pid_t pid) +{ + struct pset_struct *pset; + struct task_struct *p; + + PRINTD("sysmp_mustrun_pid(%d, %d)\n", pset_id, pid); + + p = find_task_by_pid(pid); + if (!p) { + return -ESRCH; + } + + /* be sure we can modify this process */ + if ((current->euid ^ p->suid) && (current->euid ^ p->uid) && + (current->uid ^ p->suid) && (current->uid ^ p->uid) && + (!capable(CAP_SYS_NICE))) { + return -EPERM; + } + + pset = pset_find_pset(pset_id); + if (pset) { + pset_remove_task_from_pset(p); + pset_add_task_to_pset(p, pset); + + /* is p currently on some other cpu, not in this set ? */ + if (!pset_cpu_is_in_pset(p->processor, pset)) { + p->need_resched = 1; + } + + return 0; + } + + return -EINVAL; +} + +/* ************************************************************ + * sysmp_getmustrun + * return the pset id for the current process + * + * returns 0 on success + * returns -EINVAL if the requested process is unrestricted + * ***********************************************************/ +int sysmp_getmustrun(void) +{ + PRINTD("sysmp_getmustrun()\n"); + + if (!(current->pset) || current->pset->id == PSET_MASTER_PSET) { + return -EINVAL; + } else { + return current->pset->id; + } +} + +/* ************************************************************ + * sysmp_getmustrun_pid + * return the pset id for the specified process + * + * returns 0 on success + * returns -ESRCH if the target task does not exist + * returns -EINVAL if the requested process is unrestricted + * ***********************************************************/ +int sysmp_getmustrun_pid(pid_t pid) +{ + struct task_struct *p; + + PRINTD("sysmp_getmustrun_pid(%d)\n", pid); + + p = find_task_by_pid(pid); + if (!p) { + return -ESRCH; + } + + if (!(p->pset) || p->pset->id == PSET_MASTER_PSET) { + return -EINVAL; + } else { + return p->pset->id; + } +} + +/* ************************************************************ + * sysmp_runanywhere + * allow the current process to run on any active CPU + * i.e. - add it to the master_pset + * + * returns 0 on success + * ***********************************************************/ +int sysmp_runanywhere(void) +{ + PRINTD("sysmp_runanywhere()\n"); + + pset_remove_task_from_pset(current); + pset_add_task_to_pset(current, pset_master); + + return 0; +} + +/* ************************************************************ + * sysmp_runanywhere_pid + * allow a process to run on any active CPU + * i.e. - add it to the master_pset + * + * returns 0 on success + * returns -ESRCH if the target task does not exist + * returns -EPERM if the target process is not modifiable by this user + * ***********************************************************/ +int sysmp_runanywhere_pid(pid_t pid) +{ + struct task_struct *p; + + PRINTD("sysmp_runanywhere_pid(%d)\n", pid); + + p = find_task_by_pid(pid); + if (!p) { + return -ESRCH; + } + + /* be sure we can modify this process */ + if ((current->euid ^ p->suid) && (current->euid ^ p->uid) && + (current->uid ^ p->suid) && (current->uid ^ p->uid) && + (!capable(CAP_SYS_NICE))) { + return -EPERM; + } + + pset_remove_task_from_pset(p); + pset_add_task_to_pset(p, pset_master); + + return 0; +} + +/* ************************************************************ + * sysmp_pset_create + * create a new pset + * + * returns a positive integer (the pset id created) on success + * returns -EPERM if the user is not root + * returns -EEXIST if the specified pset already exists + * returns -EBUSY if PSET_ID_NEW was requested, but none is free + * returns -EINVAL if an invalid pset id was requested + * returns -ENOMEM if the pset struct can not be allocated + * ***********************************************************/ +int sysmp_pset_create(int pset_id, cpumask_t cpus) +{ + struct pset_struct *pset; + + PRINTD("sysmp_pset_create(%d, %lu)\n", pset_id, cpus); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (pset_find_pset(pset_id)) + return -EEXIST; + if (pset_id == PSET_ID_NEW) { + pset_id = pset_find_new_pset_id(); + if (pset_id < 0) + return -EBUSY; + } + if (pset_id < 0) + return -EINVAL; + + pset = pset_allocate_pset(pset_id, PSET_FL_USER); + if (!pset) + return -ENOMEM; + + pset_add_pset_to_list(pset); + pset_add_cpus_to_pset(pset_preen_cpumask(cpus), pset); + + return pset_id; +} + +/* ************************************************************ + * sysmp_pset_delete + * delete a pset from the system + * + * returns 0 on success + * returns -EPERM if the user is not root + * returns -EINVAL if the requested pset does not exist + * returns -EBUSY if the requested pset is in use + * returns -EBUSY if the requested pset is not modifiable + * ***********************************************************/ +int sysmp_pset_delete(int pset_id) +{ + struct pset_struct *pset; + + PRINTD("sysmp_pset_delete(%d)\n", pset_id); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + pset = pset_find_pset(pset_id); + if (!pset) + return -EINVAL; + if (atomic_read(&(pset->refcount)) || pset_is_ro_pset(pset)) + return -EBUSY; + + pset_deallocate_pset(pset); + + return 0; +} + + +/* ************************************************************ + * sysmp_pset_add + * add a cpumask to a pset + * + * returns 0 on success + * returns -EPERM if the user is not root + * returns -EINVAL if the requested pset does not exist + * returns -EBUSY if the requested pset is not modifiable + * ***********************************************************/ +int sysmp_pset_add(int pset_id, cpumask_t cpus) +{ + struct pset_struct *pset; + + PRINTD("sysmp_pset_add(%d, %lu)\n", pset_id, cpus); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + pset = pset_find_pset(pset_id); + if (!pset) + return -EINVAL; + if (pset_is_ro_pset(pset)) + return -EBUSY; + + pset_add_cpus_to_pset(pset_preen_cpumask(cpus), pset); + + return 0; +} + +/* ************************************************************ + * sysmp_pset_remove + * remove a cpumask from a pset + * + * returns 0 on success + * returns -EPERM if the user is not root + * returns -EINVAL if the requested pset does not exist + * returns -EBUSY if the requested pset is not modifiable + * ***********************************************************/ +int sysmp_pset_remove(int pset_id, cpumask_t cpus) +{ + struct pset_struct *pset; + + PRINTD("sysmp_pset_remove(%d, %lu)\n", pset_id, cpus); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + pset = pset_find_pset(pset_id); + if (!pset) + return -EINVAL; + if (pset_is_ro_pset(pset)) + return -EBUSY; + + pset_remove_cpus_from_pset(pset_preen_cpumask(cpus), pset); + + /* we may be on a CPU that is no longer in the set */ + if (pset == current->pset) { + current->need_resched = 1; + } + + return 0; +}