Re: Separating processes per CPU in a SMP system

Claude Gamache (cgamache@cae.ca)
22 Feb 1999 13:55:00 -0500


"Alexandre Hautequest" <hquest@linuxbr.com.br> writes:

> Is there some manner to i separate proccesses between processors? Like, if
> i have a machine with 4 processors, for example, and i want that httpd uses
> just processor 0, and sendmail just processor 1, and orasrv uses processors
> 2 and 3, and maybe they can be changed, with an entry at cron's or somewhat
> like this.
>
> Is this too much impossible?

Here is Tim Hockin's pset patch updated/cleaned against 2.0.36. It
allows you to lock CPU or process on specific CPU. We tested it on a
dual PII and it seems to work fine. You need the top-smp patch for
2.0.36 in order to see the CPU id when using top.

The new commands brought by the patch are:

'runon' and 'mpadmin'

Good luck

Claude

P.S.: Tim, let us know if the patch is really clean. There was a
problem with entry.S, now offsets in entry.S are in synch with
asm/unistd.h

-- 
  Claude Gamache, CAE Electronique Ltee, 8585 Cote-de-Liesse  
  Saint-Laurent,  Quebec, Canada H4T 1G6                        
  Email: cgamache@cae.ca  Tel.: (514) 341-2000 x3194, Fax: (514) 734-5612

diff -urN linux/arch/i386/config.in linux-pset-0.58/arch/i386/config.in --- linux/arch/i386/config.in Sun Nov 15 13:32:46 1998 +++ linux-pset-0.58/arch/i386/config.in Mon Feb 22 13:11:32 1999 @@ -49,6 +49,12 @@ bool 'Handle buggy SMP BIOSes with bad MTRR setup' CONFIG_MTRR fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'SMP processor set support (experimental)' CONFIG_SMP_PSET + if [ "$CONFIG_SMP_PSET" = "y" ]; then + bool 'Verbose processor set debugging' CONFIG_SMP_PSET_VERBOSE + fi +fi endmenu source drivers/block/Config.in diff -urN linux/arch/i386/kernel/entry.S linux-pset-0.58/arch/i386/kernel/entry.S --- linux/arch/i386/kernel/entry.S Sun Nov 15 13:32:46 1998 +++ linux-pset-0.58/arch/i386/kernel/entry.S Mon Feb 22 13:13:32 1999 @@ -698,7 +698,8 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .long 0,0 + .long SYMBOL_NAME(sys_sysmp) + .long 0 .long SYMBOL_NAME(sys_vm86) /* 166 */ .long 0 /* 167 */ .long 0 /* 168 STREAMS poll */ @@ -708,3 +709,5 @@ .long 0 /* 188 STREAMS getpmsg */ .long 0 /* 189 STREAMS putpmsg */ .space (NR_syscalls-189)*4 + + diff -urN linux/fs/proc/array.c linux-pset-0.58/fs/proc/array.c --- linux/fs/proc/array.c Sun Nov 15 13:33:14 1998 +++ linux-pset-0.58/fs/proc/array.c Mon Feb 22 13:11:32 1999 @@ -30,6 +30,9 @@ * <Yves.Arrouye@marin.fdn.fr> * * Alan Cox : security fixes. <Alan.Cox@linux.org> + * + * Stuart Herbert : add pset for Linux/SMP + * <S.Herbert@sheffield.ac.uk> */ #include <linux/types.h> @@ -48,6 +51,7 @@ #include <linux/mm.h> #include <linux/pagemap.h> #include <linux/swap.h> +#include <linux/pset.h> #include <asm/segment.h> #include <asm/pgtable.h> @@ -393,6 +397,31 @@ return result; } +#ifdef CONFIG_SMP_PSET +static int get_pset(int pid, char * buffer) +{ + struct task_struct *p = pset_get_task(pid); + + if (!p || !p->mm) + return 0; + + if (p->pset == NULL) + return sprintf(buffer, "0"); + else + return sprintf(buffer, "%d", p->pset->id); +} +#else +static int get_pset(int pid, char * buffer) +{ + struct task_struct *p = pset_get_task(pid); + + if (!p || !p->mm) + return 0; + + return sprintf(buffer, "0"); +} +#endif /* CONFIG_SMP_PSET */ + static int get_env(int pid, char * buffer) { struct task_struct ** p = get_task(pid); @@ -1017,6 +1046,10 @@ case PROC_KSYMS: return get_ksyms_list(page, start, offset, length); #endif +#ifdef CONFIG_SMP_PSET + case PROC_PSET: + return pset_proc_list(page); +#endif case PROC_STAT: return get_kstat(page); @@ -1093,6 +1126,8 @@ return get_stat(pid, page); case PROC_PID_STATM: return get_statm(pid, page); + case PROC_PID_PSET: + return get_pset(pid, page); } return -EBADF; } diff -urN linux/fs/proc/base.c linux-pset-0.58/fs/proc/base.c --- linux/fs/proc/base.c Wed Feb 21 04:26:09 1996 +++ linux-pset-0.58/fs/proc/base.c Mon Feb 22 13:11:32 1999 @@ -12,6 +12,7 @@ #include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/config.h> static struct file_operations proc_base_operations = { NULL, /* lseek - default */ @@ -148,4 +149,12 @@ 0, &proc_arraylong_inode_operations, NULL, proc_pid_fill_inode, }); +#ifdef CONFIG_SMP_PSET + proc_register(&proc_pid, &(struct proc_dir_entry) { + PROC_PID_PSET, 4, "pset", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + NULL, proc_pid_fill_inode, + }); +#endif }; diff -urN linux/fs/proc/root.c linux-pset-0.58/fs/proc/root.c --- linux/fs/proc/root.c Tue Apr 30 06:09:45 1996 +++ linux-pset-0.58/fs/proc/root.c Mon Feb 22 13:11:32 1999 @@ -13,6 +13,7 @@ #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/config.h> +#include <linux/pset.h> #include <asm/bitops.h> /* @@ -365,6 +366,12 @@ proc_register( &proc_root, &(struct proc_dir_entry) { PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, } ); +#ifdef CONFIG_SMP_PSET + proc_register(&proc_root, &(struct proc_dir_entry) { + PROC_PSET, 4, "pset", + S_IFREG | S_IRUGO, 1, 0, 0, + }); +#endif if (prof_shift) { proc_register(&proc_root, &(struct proc_dir_entry) { diff -urN linux/include/asm-i386/unistd.h linux-pset-0.58/include/asm-i386/unistd.h --- linux/include/asm-i386/unistd.h Sun Nov 15 13:33:16 1998 +++ linux-pset-0.58/include/asm-i386/unistd.h Mon Feb 22 13:14:23 1999 @@ -169,6 +169,7 @@ #define __NR_sched_rr_get_interval 161 #define __NR_nanosleep 162 #define __NR_mremap 163 +#define __NR_sysmp 164 #define __NR_poll 168 #define __NR_getpmsg 188 #define __NR_putpmsg 189 diff -urN linux/include/linux/proc_fs.h linux-pset-0.58/include/linux/proc_fs.h --- linux/include/linux/proc_fs.h Sun Nov 15 13:33:18 1998 +++ linux-pset-0.58/include/linux/proc_fs.h Mon Feb 22 13:11:32 1999 @@ -43,7 +43,11 @@ PROC_MTAB, PROC_MD, PROC_RTC, - PROC_LOCKS +#ifdef CONFIG_SMP_PSET + PROC_PSET, +#endif + PROC_LOCKS, + PROC_PID_PSET }; enum pid_directory_inos { diff -urN linux/include/linux/pset.h linux-pset-0.58/include/linux/pset.h --- linux/include/linux/pset.h Wed Dec 31 19:00:00 1969 +++ linux-pset-0.58/include/linux/pset.h Mon Feb 22 13:11:32 1999 @@ -0,0 +1,108 @@ +#ifndef __LINUX_PSET_H +#define __LINUX_PSET_H + +/* + * Generic processor set support + * Tim Hockin <thockin@ais.net> + * based on Stuart Herbert (S.Herbert@sheffield.ac.uk) + */ + +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/config.h> +#include <linux/sysmp.h> + +#ifdef __SMP__ +#ifdef CONFIG_SMP_PSET + +#define CONFIG_SMP_PSET_DEBUG 0 + +#define PSET_VERSION "0.58" + +/* the pset number of the master processor set (65535) */ +#define PSET_MASTER_PSET 0xFFFF + +/* pset flags */ +#define PSET_F_NONE 0 /* no flags */ +#define PSET_F_SYS 1 /* system CPU set - for future use */ +#define PSET_F_MASTER 2 /* master CPU set */ +#define PSET_F_USER 4 /* user-created CPU set */ +#define PSET_F_CPU 8 /* single CPU set */ +#define PSET_F_TMP 16 /* tmp CPU set */ + +/* main structure */ +struct pset_struct +{ + int id; /* which processor set is this? */ + unsigned int flags; /* list of flags set for this pset */ + unsigned long refcount; /* how many processes in this set? */ + unsigned long cpumask; /* which CPUs are within the set? */ + struct pset_struct *next_pset; /* next pset in the list */ + struct pset_struct *prev_pset; /* prev pset in the list */ +}; + +/* external variables */ +extern struct pset_struct *pset_list; +extern struct pset_struct *pset_master; +extern struct pda_stat *pset_cpu_stats[NR_CPUS]; +extern unsigned long pset_cpumask_all; + +/* macros */ +#define pset_is_noflag_pset(pset) (pset->flags == PSET_F_NONE) +#define pset_is_sys_pset(pset) (pset->flags & PSET_F_SYS) +#define pset_is_master_pset(pset) (pset->flags & PSET_F_MASTER) +#define pset_is_user_pset(pset) (pset->flags & PSET_F_USER) +#define pset_is_cpu_pset(pset) (pset->flags & PSET_F_CPU) +#define pset_is_ro_pset(pset) ((pset_is_cpu_pset(pset)) || \ + (pset_is_master_pset(pset))) +#define pset_is_active_cpumask(cpus) ((pset_master->cpumask & cpus) == cpus) +#define pset_is_valid_cpu(int) ((long)1<<cpu_id & pset_cpumask_all) +#define pset_clean_cpumask(set) (set & pset_master->cpumask) + +/* inline functions */ +inline struct pset_struct *pset_find_pset(int); +inline int pset_not_implemented(void); +inline struct task_struct *pset_get_task(pid_t); + +/* external functions from pset.c*/ +extern int pset_proc_list(char *); +extern void pset_init(void); +extern int pset_create_pset(int, unsigned int); +extern int pset_del_pset(int); +extern int pset_create_stats(int); +extern int pset_assign_to_tmp_pset(unsigned long); +extern int pset_add_cpumask(int, unsigned long); +extern int pset_del_cpumask(int, unsigned long); +extern struct pset_struct *pset_find_pset (int); +extern void pset_print_allpsets(void); +extern void pset_print_pset(struct pset_struct *); +extern int pset_assign_pid_to_pset(struct task_struct *, int); +extern int pset_remove_pid_from_pset (struct task_struct *); + +/* external functions from sysmp.c*/ +extern int pset_mp_pgsize(void); +extern int pset_mp_nprocs(void); +extern int pset_mp_naprocs(void); +extern int pset_mp_stat(struct pda_stat *); +extern int pset_mp_restrict(int); +extern int pset_mp_empower(int); +extern int pset_mp_isolate(int); +extern int pset_mp_unisolate(int); +extern int pset_mp_disable(int); +extern int pset_mp_enable(int); +extern int pset_mp_steal(int); +extern int pset_mp_return(int); +extern int pset_mp_mustrun(int); +extern int pset_mp_mustrun_pid(int, pid_t); +extern int pset_mp_runanywhere(void); +extern int pset_mp_runanywhere_pid(pid_t); +extern int pset_mpps_create(int, unsigned long); +extern int pset_mpps_delete(int); +extern int pset_mpps_add(int, unsigned long); +extern int pset_mpps_remove(int, unsigned long); + +extern int sys_sysmp(int, int, unsigned int, unsigned int, unsigned long); + +#endif /* CONFIG_SMP_PSET */ +#endif /* __SMP__ */ +#endif /* __LINUX_PSET_H */ diff -urN linux/include/linux/sched.h linux-pset-0.58/include/linux/sched.h --- linux/include/linux/sched.h Tue Dec 2 17:18:11 1997 +++ linux-pset-0.58/include/linux/sched.h Mon Feb 22 13:11:32 1999 @@ -17,6 +17,7 @@ #include <linux/personality.h> #include <linux/tasks.h> #include <linux/kernel.h> +#include <linux/config.h> #include <asm/system.h> #include <asm/semaphore.h> @@ -248,6 +249,9 @@ int processor; int last_processor; int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */ +#ifdef CONFIG_SMP_PSET + struct pset_struct *pset; /* processor set this task is in */ +#endif #endif }; diff -urN linux/include/linux/sysmp.h linux-pset-0.58/include/linux/sysmp.h --- linux/include/linux/sysmp.h Wed Dec 31 19:00:00 1969 +++ linux-pset-0.58/include/linux/sysmp.h Mon Feb 22 13:11:32 1999 @@ -0,0 +1,68 @@ +#ifndef __LINUX_SYSMP_H +#define __LINUX_SYSMP_H + +/* + * linux/sysmp.h + * Support for the sysmp(2) call. + * Intended to be 100% compatible with SGI interface, but probably not. + * + * Stuart Herbert (S.Herbert@sheffield.ac.uk) + * Tim Hockin <thockin@ais.net> + */ + +#define MP_START 0 +#define MP_PGSIZE 1 /* system pagesize */ +#define MP_SCHED 2 /* schedctl()-should we support this?*/ +#define MP_NPROCS 3 /* # processors */ +#define MP_NAPROCS 4 /* # active processors */ +#define MP_STAT 5 /* return a processor status */ +#define MP_RESTRICT 6 /* restrict cpu to mustrun processes */ +#define MP_EMPOWER 7 /* allow cpu to run any process */ +#define MP_ISOLATE 8 /* restrict cpu to cpu pset */ +#define MP_UNISOLATE 9 /* allow cpu to run any process */ +#define MP_DISABLE 10 /* restrict CPU from executing */ +#define MP_ENABLE 11 /* allow CPU to continue running */ +#define MP_STEAL 12 /* Steal a CPU for ONE process */ +#define MP_RETURN 13 /* Return a stolen processor */ +#define MP_PREEMPTIVE 14 /* not yet implemented */ +#define MP_NONPREEMPTIVE 15 /* not yet implemented */ +#define MP_CLOCK 16 /* not yet implemented */ +#define MP_FASTCLOCK 17 /* not yet implemented */ +#define MP_MUSTRUN 18 /* force current pid to a pset */ +#define MP_MUSTRUN_PID 19 /* force a pid to a pset */ +#define MP_GETMUSTRUN 20 /* */ +#define MP_GETMUSTRUN_PID 21 /* */ +#define MP_RUNANYWHERE 22 /* run current pid on any cpu */ +#define MP_RUNANYWHERE_PID 23 /* run a pid on any cpu */ +#define MP_KERNADDR 24 /* not yet implemented */ +#define MP_SASZ 25 /* not yet implemented */ +#define MP_SAGET 26 /* not yet implemented */ +#define MP_SAGET1 27 /* not yet implemented */ +#define MP_PSET 28 /* 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 */ +#define MPPS_MAX 4 /* Max entries <end of table>*/ + +/* type for CPU bitmasks */ +typedef unsigned long sbv_t; + +/* sysmp(MP_STAT) structure */ +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 PDAF_NOFLAGS 0 /* no flags - just in case */ +#define PDAF_ENABLED 1 /* processor allowed to sched procs */ +#define PDAF_RESTRICTED 2 /* processor is restricted */ +#define PDAF_ISOLATED 4 /* processor is isolated */ +#define PDAF_DISABLED 8 /* processor has been disabled */ +#define PDAF_STOLEN 16 /* processor has been stolen */ + +#endif /* __LINUX_SYSMP_H */ diff -urN linux/init/main.c linux-pset-0.58/init/main.c --- linux/init/main.c Sun Nov 15 13:33:19 1998 +++ linux-pset-0.58/init/main.c Mon Feb 22 13:11:32 1999 @@ -6,6 +6,7 @@ * GK 2/5/95 - Changed to support mounting root fs via NFS * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 + * SMP Processor set support - Stuart Herbert, June '96 & Tim Hockin '97 */ #define __KERNEL_SYSCALLS__ @@ -208,6 +209,10 @@ #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) extern void ipc_init(void); #endif +#ifdef CONFIG_SMP_PSET +extern void pset_init(void); +#endif + /* * Boot command-line arguments @@ -828,6 +833,11 @@ int i, j; smp_boot_cpus(); +#ifdef CONFIG_SMP_PSET + /* Set up the pset stuff here, before kernel_thread is called */ + pset_init(); +#endif + /* * Create the slave init tasks as sharing pid 0. * diff -urN linux/kernel/Makefile linux-pset-0.58/kernel/Makefile --- linux/kernel/Makefile Wed Jan 10 02:27:39 1996 +++ linux-pset-0.58/kernel/Makefile Mon Feb 22 13:11:32 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 signal.o itimer.o info.o time.o softirq.o \ - resource.o sysctl.o + resource.o sysctl.o pset.o sysmp.o ifeq ($(CONFIG_MODULES),y) OX_OBJS = ksyms.o diff -urN linux/kernel/exit.c linux-pset-0.58/kernel/exit.c --- linux/kernel/exit.c Wed Jun 3 18:17:50 1998 +++ linux-pset-0.58/kernel/exit.c Mon Feb 22 13:11:32 1999 @@ -16,6 +16,7 @@ #include <linux/tty.h> #include <linux/malloc.h> #include <linux/interrupt.h> +#include <linux/pset.h> #include <asm/segment.h> #include <asm/pgtable.h> @@ -136,6 +137,9 @@ if (task[i] == p) { nr_tasks--; task[i] = NULL; +#ifdef CONFIG_SMP_PSET + pset_remove_pid_from_pset(p); +#endif REMOVE_LINKS(p); release_thread(p); if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page) diff -urN linux/kernel/fork.c linux-pset-0.58/kernel/fork.c --- linux/kernel/fork.c Wed Jun 3 18:17:50 1998 +++ linux-pset-0.58/kernel/fork.c Mon Feb 22 13:11:32 1999 @@ -21,6 +21,7 @@ #include <linux/malloc.h> #include <linux/ldt.h> #include <linux/smp.h> +#include <linux/pset.h> #include <asm/segment.h> #include <asm/system.h> @@ -275,6 +276,12 @@ #ifdef __SMP__ p->processor = NO_PROC_ID; p->lock_depth = 1; +#ifdef CONFIG_SMP_PSET + if (p->pset == NULL) + pset_assign_pid_to_pset(p, PSET_MASTER_PSET); + else /* increment the pset refcount */ + (p->pset->refcount)++; +#endif #endif p->start_time = jiffies; task[nr] = p; diff -urN linux/kernel/pset.c linux-pset-0.58/kernel/pset.c --- linux/kernel/pset.c Wed Dec 31 19:00:00 1969 +++ linux-pset-0.58/kernel/pset.c Mon Feb 22 13:11:32 1999 @@ -0,0 +1,542 @@ +/* + * Generic processor set support + * Tim Hockin <thockin@ais.net> + * based on work by Stuart Herbert (S.Herbert@sheffield.ac.uk) + */ + +#include <linux/smp.h> +#include <linux/config.h> + +#ifdef __SMP__ +#ifdef CONFIG_SMP_PSET + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include <linux/pset.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <linux/tasks.h> + +#if CONFIG_SMP_PSET_DEBUG +#define PRINTK0(a) printk(a) +#define PRINTK1(a,b) printk(a,b) +#define PRINTK2(a,b,c) printk(a,b,c) +#define PRINTK3(a,b,c,d) printk(a,b,c,d) +#define PRINTK4(a,b,c,d,e) printk(a,b,c,d,e) +#define PRINTK5(a,b,c,d,e,f) printk(a,b,c,d,e,f) +#else +#define PRINTK0(a) +#define PRINTK1(a,b) +#define PRINTK2(a,b,c) +#define PRINTK3(a,b,c,d) +#define PRINTK4(a,b,c,d,e) +#define PRINTK5(a,b,c,d,e,f) +#endif + +/* linked list of processor sets */ +struct pset_struct *pset_list; +struct pset_struct *pset_master; +unsigned long pset_cpumask_all; + +/* array of per-cpu information */ +struct pda_stat *pset_cpu_stats[NR_CPUS]; + +/* inline functions */ +/* ****************************************************** + * return a task_struct * or NULL if pid does not exist + * *****************************************************/ +inline struct task_struct *pset_get_task(pid_t pid) +{ + struct task_struct *p = NULL; + + for_each_task(p) { + if (p->pid == pid) + return p; + } + + return NULL; +} +/* ****************************************************** + * return a pset_struct *, or NULL if id does not exist + * *****************************************************/ +inline struct pset_struct *pset_find_pset(int id) +{ + struct pset_struct *pset = pset_list; + + if (id == PSET_MASTER_PSET) + return pset_master; + + while (pset != NULL) { + if (pset->id == id) { + return pset; + } else { + pset = pset->next_pset; + } + } + + return NULL; +} + +/* ****************************************************** + * return -EINVAL + * *****************************************************/ +inline int pset_not_implemented(void) +{ + return -EINVAL; +} + + +/* ****************** normal functions **************************/ +/* *************************************************************** + * pset_init() + * + * Initialize the processor set support. + * + * Creates one processor set for each CPU present, and one + * master processor set which contains all of the CPUs. + * **************************************************************/ +void pset_init(void) +{ + int i, + cpu, + result = 0; + + printk("Pset : Linux/SMP processor set support version %s\n", PSET_VERSION); + + pset_list = NULL; + + /* create the master processor set */ + result = pset_create_pset(PSET_MASTER_PSET, PSET_F_MASTER); + if (result) panic("Unable to create master pset!"); + + /* the first entry is the master */ + pset_master = pset_list; + + /* add a set for each CPU - correspondingly numbered */ + for (i = 0; i < smp_num_cpus; i++) { + cpu = cpu_logical_map[i]; + result = pset_create_pset(cpu, PSET_F_CPU); + if (result) panic("Unable to create CPU set #%d!", cpu); + + result = pset_add_cpumask(cpu, (long)(1<<cpu)); + if (result) panic("Unable to add cpu to set %d!", cpu); + + result = pset_add_cpumask(PSET_MASTER_PSET, (long)(1<<cpu)); + if (result) panic("Unable to add CPU %d to master pset!", cpu); + + pset_cpu_stats[cpu] = NULL; + pset_create_stats(cpu); + } + + /* create the all set */ + pset_cpumask_all = pset_master->cpumask; + + /* So the user knows */ + printk("Pset : Added %d processor sets.\n", i + 1); + +#ifdef CONFIG_SMP_PSET_VERBOSE + pset_print_allpsets(); +#endif +} + +/* *************************************************************** + * pset_proc_list() + * + * return list of current psets to /proc file system + * This prints out a list of available processor sets in the following + * form : + * + * pset id bit-vector refs flags + * + * Code based on the get_module_list() from module.c ... + * **************************************************************/ +int pset_proc_list(char *buf) +{ + char *p; + struct pset_struct *pset; + char buffer[80]; + int flag; + + PRINTK0("Pset : pset_proc_list()\n"); + + p = buf; + p += sprintf(p, " Pset\t CPUs\t Refs\tFlags\n"); + + for (pset = pset_list; pset; pset = pset->next_pset) { + flag = 0; + if (p - buf > EXEC_PAGESIZE - 100) + break; /* avoid overflowing buffer */ + sprintf(buffer, "%5d\t%8lx\t%8lu\t", pset->id, pset->cpumask, + pset->refcount); + if (pset_is_noflag_pset(pset)) { + sprintf(buffer, "%s(none)", buffer); + } else { + if (pset_is_sys_pset(pset)) { + if (flag) + sprintf(buffer, "%s, ", buffer); + flag = 1; + sprintf(buffer, "%ssys", buffer); + } + if (pset_is_master_pset(pset)) { + if (flag) + sprintf(buffer, "%s, ", buffer); + flag = 1; + sprintf(buffer, "%smaster", buffer); + } + if (pset_is_user_pset(pset)) { + if (flag) + sprintf(buffer, "%s, ", buffer); + flag = 1; + sprintf(buffer, "%suser", buffer); + } + if (pset_is_cpu_pset(pset)) { + if (flag) + sprintf(buffer, "%s, ", buffer); + flag = 1; + sprintf(buffer, "%scpu", buffer); + } + } + p += sprintf(p, "%s\n", buffer); + } + return p - buf; + +} + +/* *************************************************************** + * pset_create_pset () + * + * Creates a processor set with the defined ID number. + * This does not add CPUs to the pset. + * + * We can assume that if we get this far, we have ok permissions, can't + * we? + * + * return -ENOMEM if insufficient memory to allocate data structures. + * return -EEXIST if a processor set with that ID already exists. + * return 0 on success. + * **************************************************************/ +int pset_create_pset(int id, unsigned int pflags) +{ + struct pset_struct *pset; + + PRINTK2("Pset : pset_create_pset(%d, %u)\n", id, pflags); + + if (pset_find_pset(id) == NULL) { + /* doesn't exist. Create it */ + pset = (struct pset_struct *)kmalloc(sizeof( + struct pset_struct), GFP_KERNEL); + + if (pset == NULL) + return -ENOMEM; + + pset->id = id; + pset->flags = pflags; + pset->cpumask = 0L; + pset->prev_pset = NULL; + pset->refcount = 0L; + + /* okay. Shove this onto the head of the list */ + if (pset_list == NULL) + pset->next_pset = NULL; + else + pset->next_pset = pset_list; + + pset_list = pset; + + return 0; + } else { + return -EEXIST; + } +} + +/* *************************************************************** + * pset_del_pset() + * + * Delete a processor set with the named ID number. + * + * return -EINVAL if the processor set does not exist. + * return -EBUSY if the pset has active processes + * return 0 on success. + * **************************************************************/ +int pset_del_pset(int pset_id) +{ + struct pset_struct *pset; + unsigned long mask; + int i = 0; + + PRINTK1("Pset : pset_del_pset(%d)\n", pset_id); + + /* does the processor set exist? if not, return error code */ + if ((pset = pset_find_pset(pset_id)) == NULL) + return -EINVAL; + + mask = pset->cpumask; + + /* can't delete pset which has active processes */ + if (pset->refcount) + return -EBUSY; + + /* make sure it's not a CPU or MASTER pset */ + if (pset_is_ro_pset(pset)) + return -EBUSY; + + /* unlink from the list */ + if (pset->next_pset != NULL) + pset->next_pset->prev_pset = pset->prev_pset; + + if (pset->prev_pset != NULL) + pset->prev_pset->next_pset = pset->next_pset; + else + pset_list = pset->next_pset; + + kfree(pset); + + /* make sure that all CPU stats get decremented */ + while (mask != 0) { + if ((mask >>= i) & 1) + pset_cpu_stats[i]->p_count--; + i++; + } + + return 0; +} + +/* *************************************************************** + * pset_create_stats () + * + * Creates a pda_stat structure for a CPU + * This should only ever be needed from pset_init() + * + * return -ENOMEM if insufficient memory to allocate data structures. + * return -EEXIST if a processor set with that ID already exists. + * return 0 on success. + * **************************************************************/ +int pset_create_stats(int id) +{ + struct pda_stat *stats; + + PRINTK1("pset_create_stats(%d)\n", id); + + if (pset_cpu_stats[id] != NULL) + return -EEXIST; + + stats = (struct pda_stat *)kmalloc(sizeof(struct pda_stat), GFP_KERNEL); + if (stats == NULL) + return -ENOMEM; + + stats->p_cpuid = id; + stats->p_flags = PDAF_ENABLED; + stats->p_count = 2; /* cpuset and master */ + + pset_cpu_stats[id] = stats; + + return 0; +} + +/* *************************************************************** + * pset_add_cpumask() + * + * add CPUs in bitmask "cpumask" to a processor set. + * + * returns -EINVAL if the processor set does not exist + * returns 0 on success. + * **************************************************************/ +int pset_add_cpumask(int pset_id, unsigned long cpumask) +{ + struct pset_struct *pset; + unsigned long mask; + int i = 0; + + PRINTK2("Pset : pset_add_cpumask(%d, %ul)\n", pset_id, cpumask); + + /* does the processor set exist? if not, return error code */ + if ((pset = pset_find_pset(pset_id)) == NULL) + return -EINVAL; + + pset->cpumask |= cpumask; + + /* increment CPU stats */ + mask = cpumask; + while (mask != 0) { + if ((mask >>= i) & 1) + pset_cpu_stats[i]->p_count++; + i++; + } + + return 0; +} + +/* *************************************************************** + * pset_del_cpumask() + * + * Remove a CPU from a processor set. + * return -EINVAL if processor set does not exist. + * return 0 on success. + * **************************************************************/ +int pset_del_cpumask(int pset_id, unsigned long cpumask) +{ + struct pset_struct *pset; + unsigned long mask; + int i = 0; + + PRINTK2("Pset : pset_del_cpumask(%d, %ul)\n", pset_id, cpumask); + + /* does the processor set exist? if not, return error code */ + if ((pset = pset_find_pset(pset_id)) == NULL) + return -EINVAL; + + /* remove only cpu's in the mask AND in this set */ + pset->cpumask ^= (pset->cpumask & cpumask); + + /* decrement CPU stats */ + mask = cpumask; + while (mask != 0) { + if ((mask >>= i) & 1) + pset_cpu_stats[i]->p_count--; + i++; + } + + return 0; +} + +/* *************************************************************** + * pset_print_allpsets() + * + * Debugging support. Calls pset_print_pset to dump info about each + * processor set. + * **************************************************************/ +void pset_print_allpsets(void) +{ + struct pset_struct *pset = pset_list; + + PRINTK0("Pset : pset_print_allpsets()\n"); + + /* traverse the list */ + while (pset != NULL) { + pset_print_pset(pset); + pset = pset->next_pset; + } + +} + +/* *************************************************************** + * pset_print_pset() + * + * Debugging support. Uses printk() to display processor set info. + * **************************************************************/ +void pset_print_pset(struct pset_struct *pset) +{ + int total = 0, + i = 0; + unsigned long cpumask; + + PRINTK1("Pset : pset_print_pset(%lx)\n", (unsigned long) pset); + + if (pset == NULL) + printk("NULL pset passed to print!"); + + cpumask = pset->cpumask; + while (cpumask != 0) { + if ((cpumask >>= i) & 1) + total++; + i++; + } + + printk("Pset : Processor set id %5d, CPUs %2d, bitmap %8lx, flags %4x\n", + pset->id, total, pset->cpumask, pset->flags); +} + +/* *************************************************************** + * pset_assign_pid_to_pset() + * + * Change the processor set assignment for a process. + * + * return -EINVAL if the pset doesn't exist. + * **************************************************************/ +int pset_assign_pid_to_pset(struct task_struct *task, int pset_id) +{ + struct pset_struct *pset; + + PRINTK2("Pset : pset_assign_pid_to_pset(%d, %d)\n", task->pid, pset_id); + + /* Does the pset exists? */ + if ((pset = pset_find_pset(pset_id)) == NULL) + return -EINVAL; + + task->pset = pset; + + (pset->refcount)++; + + return 0; +} + +/* *************************************************************** + * pset_remove_pid_from_pset() + * + * return -EINVAL if task has no pset + * **************************************************************/ +int pset_remove_pid_from_pset(struct task_struct *task) +{ + PRINTK1("Pset : pset_remove_pid_from_pset(%d)\n", task->pid); + if (task->pset == NULL) + return -EINVAL; + + /* + * we set task->pset to NULL because we could be about to get rid of + * task ... if task is merely moving psets, then the caller of this + * routine will also call pset_assign_pid_to_pset() ... + */ + if (task->pset->refcount) { + (task->pset->refcount)--; + } else { + printk("Pset : Tried to decrement zero refcount for pset %d, + pid %d\n", task->pset->id, task->pid); + } + + task->pset = NULL; + + return 0; +} + +/* ********************************************************** + * pset_assign_to_tmp_pset () + * + * Creates a temporary pset to run a process on a disabled processor + * This could be trouble if a process allocates with pset_mp_steal(), + * but never calls pset_mp_return() + * + * We can assume that if we get this far, we have ok permissions, can't + * we? + * + * return -ENOMEM if insufficient memory to allocate data structures. + * return 0 on success. + * **************************************************************/ +int pset_assign_to_tmp_pset(unsigned long cpumask) +{ + struct pset_struct *pset; + + PRINTK1("Pset : pset_assign_to_tmp_pset(%d)\n", cpumask); + + /* Create it */ + pset = (struct pset_struct *)kmalloc(sizeof( + struct pset_struct), GFP_KERNEL); + if (pset == NULL) + return -ENOMEM; + + pset->id = -1; + pset->flags = PSET_F_TMP; + pset->cpumask |= cpumask; + pset->next_pset = NULL; + pset->prev_pset = NULL; + + current->pset = pset; + + (pset->refcount)++; + + return 0; +} + +#endif /* CONFIG_SMP_PSET */ +#endif /* __SMP__ */ diff -urN linux/kernel/sched.c linux-pset-0.58/kernel/sched.c --- linux/kernel/sched.c Sun Nov 15 13:33:20 1998 +++ linux-pset-0.58/kernel/sched.c Mon Feb 22 13:11:32 1999 @@ -9,6 +9,8 @@ * 1997-01-28 Modified by Finn Arne Gangstad to make timers scale better. * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills + * 1996-08-19 Modified by Stuart Herbert to add processor set support + * 1997-98 Continued by Tim Hockin <thockin@ais.net> */ /* @@ -33,6 +35,7 @@ #include <linux/resource.h> #include <linux/mm.h> #include <linux/smp.h> +#include <linux/pset.h> #include <asm/system.h> #include <asm/io.h> @@ -246,9 +249,9 @@ /* We are not permitted to run a task someone else is running */ if (p->processor != NO_PROC_ID) return -1000; -#ifdef PAST_2_0 +#ifdef CONFIG_SMP_PSET /* This process is locked to a processor group */ - if (p->processor_mask && !(p->processor_mask & (1<<this_cpu)) + if ((p->pset) && !(p->pset->cpumask & (1<<this_cpu))) return -1000; #endif #endif diff -urN linux/kernel/sysmp.c linux-pset-0.58/kernel/sysmp.c --- linux/kernel/sysmp.c Wed Dec 31 19:00:00 1969 +++ linux-pset-0.58/kernel/sysmp.c Mon Feb 22 13:11:32 1999 @@ -0,0 +1,762 @@ +/* + * Generic processor set support + * Tim Hockin <thockin@ais.net> + * based on work by Stuart Herbert (S.Herbert@sheffield.ac.uk) + */ + +#include <linux/smp.h> +#include <linux/config.h> + +#ifdef __SMP__ +#ifdef CONFIG_SMP_PSET + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include <linux/pset.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <linux/tasks.h> +#include <asm/segment.h> + +#if CONFIG_SMP_PSET_DEBUG +#define PRINTK0(a) printk(a) +#define PRINTK1(a,b) printk(a,b) +#define PRINTK2(a,b,c) printk(a,b,c) +#define PRINTK3(a,b,c,d) printk(a,b,c,d) +#define PRINTK4(a,b,c,d,e) printk(a,b,c,d,e) +#define PRINTK5(a,b,c,d,e,f) printk(a,b,c,d,e,f) +#else +#define PRINTK0(a) +#define PRINTK1(a,b) +#define PRINTK2(a,b,c) +#define PRINTK3(a,b,c,d) +#define PRINTK4(a,b,c,d,e) +#define PRINTK5(a,b,c,d,e,f) +#endif + +/* *************************************************************** + * sys_sysmp() + * + * The system call between us and the outside world + * **************************************************************/ +asmlinkage int sys_sysmp(int cmd, int argi1, unsigned int argi2, + unsigned int argi3, unsigned long argl1) +{ + int result = 0; + + PRINTK5("Pset : sys_sysmp(%d, %d, %u, %u, %lu)\n", + cmd, argi1, argi2, argi3, argl1); + + /* All functions are stubbed here, but not all implemented */ + switch (cmd) { + case MP_PGSIZE: + result = pset_mp_pgsize(); + break; + case MP_SCHED: + result = pset_not_implemented(); + break; + case MP_NPROCS: + result = pset_mp_nprocs(); + break; + case MP_NAPROCS: + result = pset_mp_naprocs(); + break; + case MP_STAT: + result = pset_mp_stat((struct pda_stat *)argl1); + break; + case MP_RESTRICT: + result = pset_mp_restrict(argi1); + break; + case MP_EMPOWER: + result = pset_mp_empower(argi1); + break; + case MP_ISOLATE: + result = pset_mp_isolate(argi1); + break; + case MP_UNISOLATE: + result = pset_mp_unisolate(argi1); + break; + case MP_DISABLE: + result = pset_mp_disable(argi1); + break; + case MP_ENABLE: + result = pset_mp_enable(argi1); + break; + case MP_STEAL: + result = pset_mp_steal(argi1); + break; + case MP_RETURN: + result = pset_mp_return(argi1); + break; + case MP_PREEMPTIVE: + result = pset_not_implemented(); + break; + case MP_NONPREEMPTIVE: + result = pset_not_implemented(); + break; + case MP_CLOCK: + result = pset_not_implemented(); + break; + case MP_FASTCLOCK: + result = pset_not_implemented(); + break; + case MP_MUSTRUN: + result = pset_mp_mustrun(argi1); + break; + case MP_MUSTRUN_PID: + result = pset_mp_mustrun_pid(argi1, (pid_t)argl1); + break; + case MP_GETMUSTRUN: + result = pset_not_implemented(); + break; + case MP_GETMUSTRUN_PID: + /* make sure to cast argl1 as (pid_t) */ + result = pset_not_implemented(); + break; + case MP_RUNANYWHERE: + result = pset_mp_runanywhere(); + break; + case MP_RUNANYWHERE_PID: + result = pset_mp_runanywhere_pid((pid_t)argl1); + 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... + argi1 is int, argi2 is unsigned int, argl1 is (char *). + they should go to the handler as argi1, argl1, argi2. + */ + result = pset_not_implemented(); + break; + case MP_SAGET1: + /* make sure to note the order of arguments... + argi1 is int, argi2 is unsigned int, argl1 is (char*), + argi3 is unsigned int. they should go to the handler as + argi1, argl1, argi2, argi3. + */ + result = pset_not_implemented(); + break; + case MP_PSET: + switch (argi1) { + case MPPS_CREATE: + result = pset_mpps_create(argi2, argl1); + break; + case MPPS_DELETE: + result = pset_mpps_delete(argi2); + break; + case MPPS_ADD: + result = pset_mpps_add(argi2, argl1); + break; + case MPPS_REMOVE: + result = pset_mpps_remove(argi2, argl1); + break; + default: + result = -EINVAL; + } + break; + default: + result = -EINVAL; + } + + PRINTK1("Pset : sys_sysmp() returning %d\n", result); + + return result; +} + +/* *************************************************************** + * *************************************************************** + * Functions called by sysmp()... + * *************************************************************** + * **************************************************************/ + +/* *************************************************************** + * pset_mp_pgsize() + * + * return the system pagesize. + * **************************************************************/ +int pset_mp_pgsize(void) +{ + PRINTK0("Pset : pset_mp_pgsize()\n"); + return EXEC_PAGESIZE; +} + +/* ************************************************************** + * pset_mp_nprocs() + * + * return the number of processors on the machine. + * **************************************************************/ +int pset_mp_nprocs(void) +{ + PRINTK0("Pset : pset_mp_nprocs()\n"); + return smp_num_cpus; +} + +/* ************************************************************** + * pset_mp_naprocs() + * + * return the number of CPUs in the PSET_MASTER_PSET group + * **************************************************************/ +int pset_mp_naprocs(void) +{ + unsigned long cpumask; + int total = 0; + int i = 0; + + PRINTK0("Pset : pset_mp_naprocs()\n"); + + cpumask = pset_master->cpumask; + while (cpumask != 0) { + if ((cpumask >>= i) & 1) + total++; + i++; + } + + return total; +} + +/* ************************************************************** + * pset_mp_stat() + * + * fill an array with pda_stat information. + * let's hope (l)user gave us enough storage! + * **************************************************************/ +int pset_mp_stat(struct pda_stat *ptr) +{ + int i; + int result = 0; + + PRINTK0("Pset : pset_mp_stat()\n"); + + for (i = 0; i < smp_num_cpus; i++) { + memcpy_tofs(&ptr[i], pset_cpu_stats[cpu_logical_map[i]], + sizeof(struct pda_stat)); + } + + return result; +} + +/* ************************************************************** + * pset_mp_restrict() + * + * Remove a CPU from the PSET_MASTER_PSET group + * return -EINVAL if cpu is not in master set + * return -EBUSY if cpu_id is the last CPU in the master set + * **************************************************************/ +int pset_mp_restrict(int cpu_id) +{ + unsigned long cpumask; + int result = 0; + + PRINTK1("Pset : pset_mp_restrict(%d)\n", cpu_id); + + /* verify permission */ + if (!suser()) + return -EPERM; + + cpumask = (long)1<<cpu_id; + + if (pset_is_active_cpumask(cpumask)) { + /* is this CPU the last in the master set ?*/ + if (pset_master->cpumask == cpumask) + return -EBUSY; + + result = pset_del_cpumask(PSET_MASTER_PSET, cpumask); + + /* if processor was not available, we'd not be here */ + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_RESTRICTED; + } else { + return -EINVAL; + } + + return result; +} + +/* ************************************************************** + * pset_mp_empower() + * + * Place a CPU in the PSET_MASTER_PSET group (if available) + * return -EINVAL if CPU does not exist. + * **************************************************************/ +int pset_mp_empower(int cpu_id) +{ + unsigned long cpumask; + int result = 0; + + PRINTK1("Pset : pset_mp_empower(%d)\n", cpu_id); + + /* verify permission */ + if (!suser()) + return -EPERM; + + cpumask = (long)1<<cpu_id; + + /* make sure the cpu_id actually exists */ + if (pset_is_valid_cpu(cpu_id)) { + if (pset_cpu_stats[cpu_id]->p_flags != PDAF_RESTRICTED) + return -EINVAL; + + result = pset_add_cpumask(PSET_MASTER_PSET, cpumask); + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_ENABLED; + return result; + } + return -EINVAL; +} + +/* ************************************************************** + * pset_mp_isolate() + * + * Remove the CPU from ALL cpu_sets except its own + * return -EINVAL if cpu is not in master set + * return -EBUSY if cpu_id is the last CPU in the master set + * *************************************************************/ +int pset_mp_isolate(int cpu_id) +{ + unsigned long cpumask; + int result = 0; + struct pset_struct *pset = pset_list; + + PRINTK1("Pset : pset_mp_isolate(%d)\n", cpu_id); + + /* permissions */ + if (!suser()) + return -EPERM; + + cpumask = (long)1<<cpu_id; + + if (pset_is_active_cpumask(cpumask)) { + /* can't isolate the last CPU */ + if (pset_master->cpumask == cpumask) + return -EBUSY; + + while (pset->next_pset != NULL) { + /* if it is in the set, and its not it's own..*/ + if ((pset->cpumask&cpumask) && (pset->id!=cpu_id)) + result |= pset_del_cpumask(pset->id, cpumask); + pset = pset->next_pset; + } + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_ISOLATED; + } else { + return -EINVAL; + } + + return result; +} + +/* ************************************************************** + * pset_mp_unisolate() + * + * Whats the difference between this and empower? + * Place a CPU in the PSET_MASTER_PSET group (if available) + * return -EINVAL if CPU does not exist. + * *************************************************************/ +int pset_mp_unisolate(int cpu_id) +{ + unsigned long cpumask; + int result = 0; + + PRINTK1("Pset : pset_mp_unisolate(%d)\n", cpu_id); + + /* permissions */ + if (!suser()) + return -EPERM; + + cpumask = (long)1<<cpu_id; + + /* make sure the cpu_id is a real CPU */ + if (pset_is_valid_cpu(cpu_id)) { + if (pset_cpu_stats[cpu_id]->p_flags != PDAF_ISOLATED) + return -EINVAL; + + result = pset_add_cpumask(PSET_MASTER_PSET, cpumask); + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_ENABLED; + return result; + } + + return -EINVAL; +} + +/* ************************************************************** + * pset_mp_disable() + * + * Disable a CPU from running processes + * return -EINVAL if CPU does not exist. + * *************************************************************/ +int pset_mp_disable(int cpu_id) +{ + + unsigned long cpumask; + int result = 0; + struct pset_struct *pset = pset_list; + + PRINTK1("Pset : pset_mp_disable(%d)\n", cpu_id); + + if (!suser()) + return -EPERM; + + cpumask = (long)1<<cpu_id; + + if (pset_is_active_cpumask(cpumask)) { + /* can't disable the last CPU */ + if (pset_master->cpumask == cpumask) + return -EBUSY; + + while (pset->next_pset != NULL) { + /* if the pset has this cpu..*/ + if (pset->cpumask & cpumask) + result |= pset_del_cpumask(pset->id, cpumask); + pset=pset->next_pset; + } + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_DISABLED; + } else { + return -EINVAL; + } + + return result; +} + +/* ************************************************************** + * pset_mp_enable() + * + * Enable a CPU to run processes. + * return -EINVAL if CPU does not exist. + * *************************************************************/ +int pset_mp_enable(int cpu_id) +{ + unsigned long cpumask; + int result = 0; + + PRINTK1("Pset : pset_mp_enable(%d)\n", cpu_id); + + /* permissions */ + if (!suser()) + return -EPERM; + + cpumask = (long)1<<cpu_id; + + /* make sure cpu_id is a real CPU */ + if (pset_is_valid_cpu(cpu_id)) { + if (pset_cpu_stats[cpu_id]->p_flags != PDAF_DISABLED) + return -EINVAL; + + result = pset_add_cpumask(PSET_MASTER_PSET, cpumask); + if (!result) + result = pset_add_cpumask(cpu_id, cpumask); + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_ENABLED; + return result; + } + return -EINVAL; +} + +/* ************************************************************** + * pset_mp_steal() + * + * Force a process to run ONLY on one CPU, and that CPU to ONLY + * run one process. + * return -ENOMEM if no memory is available + * return -EINVAL if cpu does not exist + * return -EPERM if user is not root + * **************************************************************/ +int pset_mp_steal(int cpu_id) +{ + unsigned long cpumask; + int result = 0; + + PRINTK1("pset_mp_steal(%d)\n", cpu_id); + + /* permissions */ + if (!suser()) + return -EPERM; + + cpumask = (long)1<<cpu_id; + + if (pset_is_active_cpumask(cpumask)) { + /* can't steal the last CPU */ + if (pset_master->cpumask == cpumask) + return -EBUSY; + + result = pset_mp_disable(cpu_id); + if (!result) + result = pset_assign_to_tmp_pset(cpumask); + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_STOLEN; + } else { + return -EINVAL; + } + + return result; +} + +/* ************************************************************** + * pset_mp_return() + * + * return a stolen process and free the tmp pset + * return -EINVAL if cpu does not exist + * return -EPERM if user is not root + * return -EBUSY if child processes have inherited this pset + * **************************************************************/ +int pset_mp_return(int cpu_id) +{ + int result = 0; + + PRINTK1("pset_mp_return(%d)\n", cpu_id); + + /* permissions */ + if (!suser()) + return -EPERM; + + /* make sure cpu_id is a real CPU */ + if (pset_is_valid_cpu(cpu_id)) { + if (pset_cpu_stats[cpu_id]->p_flags != PDAF_STOLEN) + return -EINVAL; + + result = pset_mp_enable(cpu_id); + + if (result) + return result; + + /* keep in mind current is still in refcount */ + if ((current->pset->refcount) - 1) + return -EBUSY; + kfree(current->pset); + result = pset_remove_pid_from_pset(current); + result = pset_assign_pid_to_pset(current, PSET_MASTER_PSET); + + if (!result) + pset_cpu_stats[cpu_id]->p_flags = PDAF_ENABLED; + + return result; + } + + return -EINVAL; +} + +/* ************************************************************** + * pset_mp_runanywhere() + * + * Force this process to run in the master pset + * **************************************************************/ +int pset_mp_runanywhere(void) +{ + int result = 0; + + PRINTK0("Pset : pset_mp_runanywhere()\n"); + + result = pset_remove_pid_from_pset(current); + + if (!result) + result = pset_assign_pid_to_pset(current, PSET_MASTER_PSET); + + return result; +} + +/* ************************************************************** + * pset_mp_runanywhere_pid() + * + * Force a process to run in the master pset + * return -ESRCH if a task can not be found + * return -EPERM if user does not have rights over a process + * **************************************************************/ +int pset_mp_runanywhere_pid(pid_t pid) +{ + int result = 0; + struct task_struct *p; + + PRINTK0("Pset : pset_mp_runanywhere_pid()\n"); + + if ((p = pset_get_task(pid)) == NULL) + 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) && + !suser()) + return -EPERM; + + result = pset_remove_pid_from_pset(p); + + if (!result) + result = pset_assign_pid_to_pset(p, PSET_MASTER_PSET); + + return result; +} + +/* ************************************************************** + * pset_mp_mustrun() + * + * Force this process to run on a particular pset + * **************************************************************/ +int pset_mp_mustrun(int pset_id) +{ + int result = 0; + + PRINTK1("Pset : pset_mp_mustrun(%d)\n", pset_id); + + result = pset_remove_pid_from_pset(current); + if (!result) + result = pset_assign_pid_to_pset(current, pset_id); + + return result; +} + +/* ************************************************************** + * pset_mp_mustrun_pid() + * + * Force a process to run on a particular pset + * return -EINVAL if the pset does not exist + * **************************************************************/ +int pset_mp_mustrun_pid(int pset_id, pid_t pid) +{ + int result = 0; + struct task_struct *p; + + PRINTK2("Pset : pset_mp_mustrun_pid(%d,%d)\n", pset_id, pid); + + if ((p = pset_get_task(pid)) == NULL) + 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) && + !suser()) + return -EPERM; + + result = pset_remove_pid_from_pset(p); + if (!result) + result = pset_assign_pid_to_pset(p, pset_id); + + return result; +} + +/* ************************************************************** + * pset_mpps_create() + * + * Create a processor set + * return -EPERM if user is not root + * **************************************************************/ +int pset_mpps_create(int pset_id, unsigned long cpumask) +{ + int result = 0; + + PRINTK2("Pset : pset_mpps_create(%d,%ul)\n", pset_id, cpumask); + + /* FIXME - should non-root users be able to create a pset ?*/ + /* can it be destroyed when they log out? */ + /* Owner flag in pset struct? */ + if (!suser()) + return -EPERM; + + /* this implicitly filters out restricted CPU's */ + cpumask = pset_clean_cpumask(cpumask); + + result = pset_create_pset(pset_id, PSET_F_USER); + if (!result) + result = pset_add_cpumask(pset_id, cpumask); + + return result; +} + +/* ************************************************************** + * pset_mpps_delete() + * + * Delete a processor set + * return -EPERM if user is not root + * return -EINVAL if pset does not exist + * return -EBUSY if this is a master or cpu pset + * **************************************************************/ +int pset_mpps_delete(int pset_id) +{ + int result = 0; + + PRINTK1("Pset : pset_mpps_delete(%d)\n", pset_id); + + /* FIXME - can a user delete psets if they are allowed to create? */ + if (!suser()) + return -EPERM; + + result = pset_del_pset(pset_id); + + return result; +} + +/* ************************************************************** + * pset_mpps_add() + * + * Add a bitmap of CPUs to a processor set + * return -EPERM if user is not root + * return -EINVAL if pset pset_id does not exist + * return -EBUSY if pset is a cpu pset or master pset + * **************************************************************/ +int pset_mpps_add(int pset_id, unsigned long cpumask) +{ + struct pset_struct *pset; + int result = 0; + + PRINTK2("Pset : pset_mpps_add(%d, %lu)\n", pset_id, cpumask); + + /* FIXME - can a user add CPUs if they own the pset? */ + if (!suser()) + return -EPERM; + + /* this implicitly filters out restricted CPU's */ + cpumask = pset_clean_cpumask(cpumask); + + if ((pset = pset_find_pset(pset_id)) == NULL) + return -EINVAL; + + /* to manipulate pset_master use empower */ + if(pset_is_ro_pset(pset)) + return -EBUSY; + + result = pset_add_cpumask(pset_id, cpumask); + + return result; +} + +/* ************************************************************** + * pset_mpps_remove() + * + * Remove a bitmap of CPUs from a processor set + * return -EPERM if not user root + * return -EINVAL if pset pset_id does not exist + * return -EBUSY if pset is a CPU pset or the master pset. + * **************************************************************/ +int pset_mpps_remove(int pset_id, unsigned long cpumask) +{ + struct pset_struct *pset; + int result = 0; + + PRINTK2("Pset : pset_mpps_remove(%d, %lu)\n", pset_id, cpumask); + + /* FIXME - Can a user remove CPU's from a PSET they create? */ + if (!suser()) + return -EPERM; + + /* this implicitly filters out restricted CPU's */ + cpumask = pset_clean_cpumask(cpumask); + + if ((pset = pset_find_pset(pset_id)) == NULL) + return -EINVAL; + + /* to manipulate the master set use the restrict functions */ + if (pset_is_ro_pset(pset)) + return -EBUSY; + + result = pset_del_cpumask(pset_id, cpumask); + + return result; +} + +#endif /* CONFIG_SMP_PSET */ +#endif /* __SMP__ */

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/