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 <linux/pset.h>
+#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.
  *			<Alan.Cox@linux.org>
  *
+ * Tim Hockin	     :	pset support
+ *			<thockin@isunix.it.ilstu.edu>
  */
 
 #include <linux/types.h>
@@ -63,6 +65,9 @@
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/signal.h>
+#ifdef __SMP__
+#include <linux/pset.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -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 <linux/zorro.h>
 #endif
+#ifdef __SMP__
+#include <linux/pset.h>
+#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 <asm-i386/errno.h> */
 
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 <thockin@isunix.it.ilstu.edu> 1998-1999
+ *	based on work by Stuart Herbert (S.Herbert@sheffield.ac.uk)
+ */
+
+#include <linux/config.h>
+#include <linux/sysmp.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#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<<c)
+#define pset_cpu_disabled_in_pset(c,p)	(p->dis_cpumask & (cpumask_t)1<<c)
+#define pset_cpu_is_in_pset(c,p)	\
+	(pset_cpu_enabled_in_pset(c,p) || pset_cpu_disabled_in_pset(c,p))
+#define pset_is_last_cpu(c)		\
+	(pset_master->cpumask == ((cpumask_t)1<<c))
+#define pset_unset_cpu_flag(c,f)	\
+	(pset_cpustats[c]->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 <linux/kernel.h>
+#else
+#include <limits.h>
+#endif
+
+/* 
+ * Support for sysmp() system call 
+ *	Tim Hockin <thockin@isunix.it.ilstu.edu> 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 <grif@acm.org> 
+ *  Added pset support - Tim Hockin <thockin@isunix.it.ilstu.edu> Feb '99
  */
 
 #define __KERNEL_SYSCALLS__
@@ -50,6 +51,10 @@
 extern void nubus_init(void);
 #endif
 
+#ifdef __SMP__
+#include <linux/pset.h>
+#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 <linux/acct.h>
 #endif
+#ifdef __SMP__
+#include <linux/pset.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -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 <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#ifdef __SMP__
+#include <linux/pset.h>
+#endif
 
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
@@ -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 <thockin@isunix.it.ilstu.edu> 1998-1999
+ *	based on work by Stuart Herbert <S.Herbert@sheffield.ac.uk>
+ */
+
+#include <linux/config.h>
+
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+#include <linux/pset.h>
+#include <linux/proc_fs.h>
+
+/* 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<<cpu), new_pset);
+		pset_add_cpus_to_pset((cpumask_t)(1<<cpu), pset_master);
+	}
+
+	pset_cpumask_all = pset_master->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<<i) {
+			atomic_inc(&(pset_cpustats[i]->refcount));
+			/* make sure to obey the cpu restriction level */
+			if (pset_cpustats[i]->flags != CPUF_ENABLED)
+				pset_disable_cpus_in_pset((cpumask_t)1<<i,
+					pset);
+		}
+		tmp >>= 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<<i) {
+			atomic_dec(&(pset_cpustats[i]->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 <thockin@isunix.it.ilstu.edu>
  */
 
 /*
@@ -31,6 +32,9 @@
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#ifdef __SMP__
+#include <linux/pset.h>
+#endif
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -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<<cpu)))
 
 #else
 
@@ -167,11 +172,27 @@
 		goto out;
 			
 #ifdef __SMP__
+	if (!pset_can_schedule(p, this_cpu))
+		goto pset_cant_sched;
+
 	/* Give a largish advantage to the same processor...   */
 	/* (this is equivalent to penalizing other processors) */
 	if (p->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 <thockin@isunix.it.ilstu.edu> 1998-1999
+ *	based on work by Stuart Herbert (S.Herbert@sheffield.ac.uk)
+ */
+
+#include <linux/config.h>
+
+#include <linux/smp.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+#include <asm/uaccess.h>
+#include <linux/pset.h>
+
+
+/* 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<<cpu))
+                return -EINVAL;
+        if (pset_is_last_cpu(cpu))
+                return -EBUSY;
+	if (pset_cpustats[cpu]->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<<cpu, pset_master);
+
+	/* did we just restrict the current processor ? */
+	if (current->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<<cpu))
+                return -EINVAL;
+
+	if (pset_cpustats[cpu]->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<<cpu, pset_master);
+	}
+
+	return 0;
+}
+
+/* ************************************************************
+ * sysmp_isolate
+ * isolate a procesor to running only processes in this cpu set
+ * i.e. - disable it in the master pset and all sets but its own
+ * 
+ * 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_isolate(int cpu)
+{
+	struct pset_struct *pset;
+
+	PRINTD("sysmp_isolate(%d)\n", cpu);
+
+	if (!capable(CAP_SYS_ADMIN))
+                return -EPERM;
+        if (!pset_is_valid_cpumask((cpumask_t)1<<cpu))
+                return -EINVAL;
+        if (pset_is_last_cpu(cpu))
+                return -EBUSY;
+	if (pset_cpustats[cpu]->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<<cpu, pset);
+		}
+		pset = pset->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<<cpu))
+                return -EINVAL;
+
+	if (pset_cpustats[cpu]->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<<cpu, pset);
+			}
+			pset = pset->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<<cpu))
+                return -EINVAL;
+        if (pset_is_last_cpu(cpu))
+                return -EBUSY;
+	if (pset_cpustats[cpu]->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<<cpu, pset);
+		}
+		pset = pset->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<<cpu))
+                return -EINVAL;
+
+	if (pset_cpustats[cpu]->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<<cpu, pset);
+			}
+			pset = pset->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<<cpu))
+		return -EINVAL;
+	if (pset_is_last_cpu(cpu))
+		return -EBUSY;
+	if (pset_cpustats[cpu]->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<<cpu, pset);
+			break;
+		}
+                pset = pset->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<<cpu, new);
+	/* we add it, but it is disabled because 'new' is not ENABLED */
+	pset_enable_cpus_in_pset((cpumask_t)1<<cpu, new);
+
+	/* we have a new set, unlink current->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<<cpu))
+		return -EINVAL;
+
+	if (pset_cpustats[cpu]->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<<cpu, pset);
+				break;
+			}
+			pset = pset->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;
+}
