Here is the PAGG patch for 2.6.11.

Process Aggregates (PAGG) is really a tool for building kernel modules
that need to group processes together.  This grouping ability could also
be viewed as hook management.

More info about PAGG can be found here:
http://oss.sgi.com/projects/pagg/

For a discussion on using PAGG as hook manager, see an LKML archive
site near you.  One link below:
http://marc.theaimsgroup.com/?l=linux-kernel&m=110624592118941&w=2

Signed-off-by: Erik Jacobson <[EMAIL PROTECTED]>
---
 Documentation/pagg.txt    |   32 ++
 fs/exec.c                 |    2
 include/linux/init_task.h |    2
 include/linux/pagg.h      |  223 ++++++++++++++++++++
 include/linux/sched.h     |    7
 init/Kconfig              |    8
 kernel/Makefile           |    1
 kernel/exit.c             |    4
 kernel/fork.c             |   14 +
 kernel/pagg.c             |  496 
++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 789 
insertions(+)


Index: linux/Documentation/pagg.txt
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux/Documentation/pagg.txt        2005-02-10 14:25:59.053635015 -0800
@@ -0,0 +1,32 @@
+Linux Process Aggregates (PAGG)
+-------------------------------
+
+The process aggregates infrastructure, or PAGG, provides a generalized
+mechanism for providing arbitrary process groups in Linux.  PAGG consists
+of a series of functions for registering and unregistering support
+for new types of process aggregation containers with the kernel.
+This is similar to the support currently provided within Linux that
+allows for dynamic support of filesystems, block and character devices,
+symbol tables, network devices, serial devices, and execution domains.
+This implementation of PAGG provides developers the basic hooks necessary
+to implement kernel modules for specific process containers, such as
+the job container.
+
+The do_fork function in the kernel was altered to support PAGG.  If a
+process is attached to any PAGG containers and subsequently forks a
+child process, the child process will also be attached to the same PAGG
+containers.  The PAGG containers involved during the fork are notified
+that a new process has been attached.  The notification is accomplished
+via a callback function provided by the PAGG module.
+
+The do_exit function in the kernel has also been altered.  If a process
+is attached to any PAGG containers and that process is exiting, the PAGG
+containers are notified that a process has detached from the container.
+The notification is accomplished via a callback function provided by
+the PAGG module.
+
+The sys_execve function has been modified to support an optional callout
+that can be run when a process in a pagg list does an exec.  It can be
+used, for example, by other kernel modules that wish to do advanced CPU
+placement on multi-processor systems (just one example).
+
Index: linux/fs/exec.c
===================================================================
--- linux.orig/fs/exec.c        2005-02-10 12:18:44.836148656 -0800
+++ linux/fs/exec.c     2005-02-10 14:29:06.024808677 -0800
@@ -48,6 +48,7 @@
 #include <linux/syscalls.h>
 #include <linux/rmap.h>
 #include <linux/acct.h>
+#include <linux/pagg.h>

 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1188,6 +1189,7 @@ int do_execve(char * filename,
        retval = search_binary_handler(bprm,regs);
        if (retval >= 0) {
                free_arg_pages(bprm);
+               pagg_exec(current);

                /* execve success */
                security_bprm_free(bprm);
Index: linux/include/linux/init_task.h
===================================================================
--- linux.orig/include/linux/init_task.h        2005-02-10 12:18:47.094955207 
-0800
+++ linux/include/linux/init_task.h     2005-02-10 14:25:59.095627528 -0800
@@ -2,6 +2,7 @@
 #define _LINUX__INIT_TASK_H

 #include <linux/file.h>
+#include <linux/pagg.h>

 #define INIT_FILES \
 {                                                      \
@@ -112,6 +113,7 @@ extern struct group_info init_groups;
        .proc_lock      = SPIN_LOCK_UNLOCKED,                           \
        .switch_lock    = SPIN_LOCK_UNLOCKED,                           \
        .journal_info   = NULL,                                         \
+       INIT_TASK_PAGG(tsk)                                             \
 }


Index: linux/include/linux/pagg.h
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux/include/linux/pagg.h  2005-02-10 14:25:59.112229219 -0800
@@ -0,0 +1,223 @@
+/*
+ * PAGG (Process Aggregates) interface
+ *
+ *
+ * Copyright (c) 2000-2002, 2004 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+/*
+ * Data structure definitions and function prototypes used to implement
+ * process aggregates (paggs).
+ *
+ * Paggs provides a generalized way to implement process groupings or
+ * containers.  Modules use these functions to register with the kernel as
+ * providers of process aggregation containers. The pagg data structures
+ * define the callback functions and data access pointers back into the
+ * pagg modules.
+ */
+
+#ifndef _LINUX_PAGG_H
+#define _LINUX_PAGG_H
+
+#include <linux/sched.h>
+
+#ifdef CONFIG_PAGG
+
+#define PAGG_NAMELN    32              /* Max chars in PAGG module name */
+
+
+/**
+ * INIT_PAGG_LIST - used to initialize a pagg_list structure after declaration
+ * @_l: Task struct to init the pagg_list and semaphore in
+ *
+ */
+#define INIT_PAGG_LIST(_l)                                             \
+do {                                                                   \
+       INIT_LIST_HEAD(&(_l)->pagg_list);                                       
\
+       init_rwsem(&(_l)->pagg_sem);                                            
\
+} while(0)
+
+
+/*
+ * Used by task_struct to manage list of pagg attachments for the process.
+ * Each pagg provides the link between the process and the
+ * correct pagg container.
+ *
+ * STRUCT MEMBERS:
+ *     hook:   Reference to pagg module structure.  That struct
+ *                     holds the name key and function pointers.
+ *     data:   Opaque data pointer - defined by pagg modules.
+ *     entry:  List pointers
+ */
+struct pagg {
+       struct pagg_hook        *hook;
+       void            *data;
+       struct list_head        entry;
+};
+
+/*
+ * Used by pagg modules to define the callback functions into the
+ * module.
+ *
+ * STRUCT MEMBERS:
+ *     name:           The name of the pagg container type provided by
+ *                     the module. This will be set by the pagg module.
+ *     attach:         Function pointer to function used when attaching
+ *                     a process to the pagg container referenced by
+ *                     this struct.
+ *                     Return codes from the attach function pointer have
+ *                     These meanings:
+ *                     <0 Error which is propagated back to copy_process so
+ *                        the fork fails.
+ *                     =0 success, attach to same container as parent
+ *                     >0 success, but don't attach to a container
+ *
+ *     detach:         Function pointer to function used when detaching
+ *                     a process to the pagg container referenced by
+ *                     this struct.
+ *     init:           Function pointer to initialization function.  This
+ *                     function is used when the module is loaded to attach
+ *                     existing processes to a default container as defined by
+ *                     the pagg module. This is optional and may be set to
+ *                     NULL if it is not needed by the pagg module.
+ *
+ *                     Note: The return values are managed the same way as in
+ *                     attach above.  Except, of course, an error doesn't
+ *                     result in a fork failure.
+ *
+ *                     Note: The implementation of pagg_hook_register causes
+ *                     us to evaluate some tasks more than once in some cases.
+ *                     See the comments in pagg_hook_register for why.
+ *                     Therefore, if the init function pointer returns >0,
+ *                     which means that it doesn't want a pagg association,
+ *                     that init function must be prepared to possibly look at
+ *                     the same "skipped" task more than once.
+ *
+ *     data:           Opaque data pointer - defined by pagg modules.
+ *     module:         Pointer to kernel module struct.  Used to increment &
+ *                     decrement the use count for the module.
+ *     entry:          List pointers
+ *     exec:           Function pointer to function used when a process
+ *                     in the pagg container exec's a new process. This
+ *                     is optional and may be set to NULL if it is not
+ *                     needed by the pagg module.
+ *     refcnt:         Keep track of user count of the pagg hook
+ */
+struct pagg_hook {
+       struct module   *module;
+       char            *name;  /* Name Key - restricted to 32 characters */
+       void            *data;  /* Opaque module specific data */
+       struct list_head        entry;  /* List pointers */
+                atomic_t refcnt; /* usage counter */
+       int             (*init)(struct task_struct *, struct pagg *);
+       int             (*attach)(struct task_struct *, struct pagg *, void*);
+       void            (*detach)(struct task_struct *, struct pagg *);
+       void            (*exec)(struct task_struct *, struct pagg *);
+};
+
+
+/* Kernel service functions for providing PAGG support */
+extern struct pagg *pagg_get(struct task_struct *task, char *key);
+extern struct pagg *pagg_alloc(struct task_struct *task,
+                              struct pagg_hook *pt);
+extern void pagg_free(struct pagg *pagg);
+extern int pagg_hook_register(struct pagg_hook *pt_new);
+extern int pagg_hook_unregister(struct pagg_hook *pt_old);
+extern int __pagg_attach(struct task_struct *to_task,
+                        struct task_struct *from_task);
+extern void __pagg_detach(struct task_struct *task);
+extern int __pagg_exec(struct task_struct *task);
+
+/**
+ * pagg_attach - child inherits attachment to pagg containers of its parent
+ * @child: child task - to inherit
+ * @parent: parenet task - child inherits pagg containers from this parent
+ *
+ * function used when a child process must inherit attachment to pagg
+ * containers from the parent.  Return code is propagated as a fork fail.
+ *
+ */
+static inline int pagg_attach(struct task_struct *child,
+                             struct task_struct *parent)
+{
+       INIT_PAGG_LIST(child);
+       if (!list_empty(&parent->pagg_list))
+               return __pagg_attach(child, parent);
+
+       return 0;
+}
+
+
+/**
+ * pagg_detach - Detach a process from a pagg container it is a member of
+ * @task: The task the pagg will be detached from
+ *
+ */
+static inline void pagg_detach(struct task_struct *task)
+{
+       if (!list_empty(&task->pagg_list))
+               __pagg_detach(task);
+}
+
+/**
+ * pagg_exec - Used when a process exec's
+ * @task: The process doing the exec
+ *
+ */
+static inline void pagg_exec(struct task_struct *task)
+{
+       if (!list_empty(&task->pagg_list))
+               __pagg_exec(task);
+}
+
+/**
+ * INIT_TASK_PAGG - Used in INIT_TASK to set the head and sem of pagg_list
+ * @tsk: The task work with
+ *
+ * Marco Used in INIT_TASK to set the head and sem of pagg_list.
+ * If CONFIG_PAGG is off, it is defined as an empty macro below.
+ *
+ */
+#define INIT_TASK_PAGG(tsk) \
+       .pagg_list = LIST_HEAD_INIT(tsk.pagg_list),     \
+       .pagg_sem  = __RWSEM_INITIALIZER(tsk.pagg_sem),
+
+#else  /* CONFIG_PAGG */
+
+/*
+ * Replacement macros used when PAGG (Process Aggregates) support is not
+ * compiled into the kernel.
+ */
+#define INIT_TASK_PAGG(tsk)
+#define INIT_PAGG_LIST(l) do { } while(0)
+#define pagg_attach(ct, pt) ({ 0; })
+#define pagg_detach(t)  do {  } while(0)
+#define pagg_exec(t)  do {  } while(0)
+
+#endif /* CONFIG_PAGG */
+
+#endif /* _LINUX_PAGG_H */
Index: linux/include/linux/sched.h
===================================================================
--- linux.orig/include/linux/sched.h    2005-02-10 12:19:08.071680110 -0800
+++ linux/include/linux/sched.h 2005-02-10 14:25:59.121018349 -0800
@@ -685,6 +685,13 @@ struct task_struct {
        struct mempolicy *mempolicy;
        short il_next;
 #endif
+
+#ifdef CONFIG_PAGG
+/* List of pagg (process aggregate) attachments */
+       struct list_head pagg_list;
+       struct rw_semaphore pagg_sem;
+#endif
+
 };

 static inline pid_t process_group(struct task_struct *tsk)
Index: linux/init/Kconfig
===================================================================
--- linux.orig/init/Kconfig     2005-02-10 12:19:13.571722691 -0800
+++ linux/init/Kconfig  2005-02-10 14:25:59.137620040 -0800
@@ -138,6 +138,14 @@ config BSD_PROCESS_ACCT_V3
          for processing it. A preliminary version of these tools is available
          at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>.

+config PAGG
+       bool "Support for process aggregates (PAGGs)"
+       help
+     Say Y here if you will be loading modules which provide support
+     for process aggregate containers.  Examples of such modules include the
+     Linux Jobs module and the Linux Array Sessions module.  If you will not
+     be using such modules, say N.
+
 config SYSCTL
        bool "Sysctl support"
        ---help---
Index: linux/kernel/Makefile
===================================================================
--- linux.orig/kernel/Makefile  2004-12-24 13:34:26.000000000 -0800
+++ linux/kernel/Makefile       2005-02-10 14:25:59.153245161 -0800
@@ -18,6 +18,7 @@ obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_COMPAT) += compat.o
+obj-$(CONFIG_PAGG) += pagg.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
Index: linux/kernel/fork.c
===================================================================
--- linux.orig/kernel/fork.c    2005-02-10 12:18:47.959219711 -0800
+++ linux/kernel/fork.c 2005-02-10 14:30:46.804885277 -0800
@@ -40,6 +40,7 @@
 #include <linux/profile.h>
 #include <linux/rmap.h>
 #include <linux/acct.h>
+#include <linux/pagg.h>

 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -129,6 +130,9 @@ void __init fork_init(unsigned long memp

        init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
        init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
+
+       /* Initialize the pagg list in pid 0 before it can clone itself. */
+       INIT_PAGG_LIST(current);
 }

 static struct task_struct *dup_task_struct(struct task_struct *orig)
@@ -953,6 +957,15 @@ static task_t *copy_process(unsigned lon
        sched_fork(p);

        /*
+        * call pagg modules to properly attach new process to the same
+        * process aggregate containers as the parent process.  Fail the fork
+        * on error.
+        */
+       retval = pagg_attach(p, current);
+       if (retval)
+               goto bad_fork_cleanup_namespace;
+
+       /*
         * Ok, make it visible to the rest of the system.
         * We dont wake it up yet.
         */
@@ -1042,6 +1055,7 @@ fork_out:
        return p;

 bad_fork_cleanup_namespace:
+       pagg_detach(p);
        exit_namespace(p);
 bad_fork_cleanup_keys:
        exit_keys(p);
Index: linux/kernel/pagg.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux/kernel/pagg.c 2005-02-10 14:25:59.187425113 -0800
@@ -0,0 +1,496 @@
+/*
+ * PAGG (Process Aggregates) interface
+ *
+ *
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/pagg.h>
+#include <asm/semaphore.h>
+
+/* list of pagg hook entries that reference the "module" implementations */
+static LIST_HEAD(pagg_hook_list);
+static DECLARE_RWSEM(pagg_hook_list_sem);
+
+
+/**
+ * pagg_get - get a pagg given a search key
+ * @task: We examine the pagg_list from the given task
+ * @key: Key name of pagg we wish to retrieve
+ *
+ * Given a pagg_list list structure, this function will return
+ * a pointer to the pagg struct that matches the search
+ * key.  If the key is not found, the function will return NULL.
+ *
+ * The caller should hold at least a read lock on the pagg_list
+ * for task using down_read(&task->pagg_list.sem).
+ *
+ */
+struct pagg *
+pagg_get(struct task_struct *task, char *key)
+{
+       struct pagg *pagg;
+
+       list_for_each_entry(pagg, &task->pagg_list, entry) {
+               if (!strcmp(pagg->hook->name,key))
+                       return pagg;
+       }
+       return NULL;
+}
+
+
+/**
+ * pagg_alloc - Insert a new pagg in to the pagg_list for a task
+ * @task: Task we want to insert the pagg in to
+ * @pagg_hook: Pagg hook to associate with the new pagg
+ *
+ * Given a task and a pagg hook, this function will allocate
+ * a new pagg structure, initialize the settings, and insert the pagg into
+ * the pagg_list for the task.
+ *
+ * The caller for this function should hold at least a read lock on the
+ * pagg_hook_list_sem - or ensure that the pagg hook entry cannot be
+ * removed. If this function was called from the pagg module (usually the
+ * case), then the caller need not hold this lock. The caller should hold
+ * a write lock on for the tasks pagg_sem.  This can be locked using
+ * down_write(&task->pagg_sem)
+ *
+ */
+struct pagg *
+pagg_alloc(struct task_struct *task, struct pagg_hook *pagg_hook)
+{
+       struct pagg *pagg;
+
+       pagg = kmalloc(sizeof(struct pagg), GFP_KERNEL);
+       if (!pagg)
+               return NULL;
+
+       pagg->hook = pagg_hook;
+       pagg->data = NULL;
+       atomic_inc(&pagg_hook->refcnt);  /* Increase hook's reference count */
+       list_add_tail(&pagg->entry, &task->pagg_list);
+       return pagg;
+}
+
+
+/**
+ * pagg_free - Delete pagg from the list and free its memory
+ * @pagg: The pagg to free
+ *
+ * This function will ensure the pagg is deleted form
+ * the list of pagg entries for the task. Finally, the memory for the
+ * pagg is discarded.
+ *
+ * The caller of this function should hold a write lock on the pagg_sem
+ * for the task. This can be locked using down_write(&task->pagg_sem).
+ *
+ * Prior to calling pagg_free, the pagg should have been detached from the
+ * pagg container represented by this pagg.  That is usually done using
+ * p->hook->detach(task, pagg);
+ *
+ */
+void
+pagg_free(struct pagg *pagg)
+{
+       atomic_dec(&pagg->hook->refcnt); /* decr the reference count on the 
hook */
+       list_del(&pagg->entry);
+       kfree(pagg);
+}
+
+
+/**
+ * get_pagg_hook - Get the pagg hook matching the requested name
+ * @key: The name of the pagg hook to get
+ *
+ * Given a pagg hook name key, this function will return a pointer
+ * to the pagg_hook struct that matches the name.
+ *
+ * You should hold either the write or read lock for pagg_hook_list_sem
+ * before using this function.  This will ensure that the pagg_hook_list
+ * does not change while iterating through the list entries.
+ *
+ */
+static struct pagg_hook *
+get_pagg_hook(char *key)
+{
+       struct pagg_hook *pagg_hook;
+
+       list_for_each_entry(pagg_hook, &pagg_hook_list, entry) {
+               if (!strcmp(pagg_hook->name, key)) {
+                       return pagg_hook;
+               }
+       }
+       return NULL;
+}
+
+/**
+ * remove_client_paggs_from_all_tasks - Remove all paggs associated with hook
+ * @php: Pagg hook associated with paggs to purge
+ *
+ * Given a pagg hook, this function will remove all paggs associated with that
+ * pagg hook from all tasks calling the provided function on each pagg.
+ *
+ * If there is a detach function associated with the pagg, it is called
+ * before the pagg is freed.
+ *
+ * This is meant to be used by pagg_hook_register and pagg_hook_unregister
+ *
+ */
+static void
+remove_client_paggs_from_all_tasks(struct pagg_hook *php)
+{
+       if (php == NULL)
+               return;
+
+       /* Because of internal race conditions we can't gaurantee
+        * getting every task in just one pass so we just keep going
+        * until there are no tasks with paggs from this hook attached.
+        * The inefficiency of this should be tempered by the fact that this
+        * happens at most once for each registered client.
+        */
+       while (atomic_read(&php->refcnt) != 0) {
+               struct task_struct *g = NULL, *p = NULL;
+
+               read_lock(&tasklist_lock);
+               do_each_thread(g, p) {
+                       struct pagg *paggp;
+                       int task_exited;
+
+                       get_task_struct(p);
+                       read_unlock(&tasklist_lock);
+                       down_write(&p->pagg_sem);
+                       paggp = pagg_get(p, php->name);
+                       if (paggp != NULL) {
+                               (void)php->detach(p, paggp);
+                               pagg_free(paggp);
+                       }
+                       up_write(&p->pagg_sem);
+                       read_lock(&tasklist_lock);
+
+                       /* If a PAGG got removed from the list while we're 
going through
+                        * each process, the tasks list for the process would 
be empty.  In
+                        * that case, break out of this for_each_thread so we 
can do it
+                        * again. */
+                       task_exited = list_empty(&p->sibling);
+                       put_task_struct(p);
+                       if (task_exited)
+                               goto endloop;
+               } while_each_thread(g, p);
+ endloop:
+               read_unlock(&tasklist_lock);
+       }
+}
+
+/**
+ * pagg_hook_register - Register a new pagg hook and enter it the list
+ * @pagg_hook_new: The new pagg hook to register
+ *
+ * Used to register a new pagg hook and enter it into the pagg_hook_list.
+ * The service name for a pagg hook is restricted to 32 characters.
+ *
+ * If an "init()" function is supplied in the hook being registered then a
+ * pagg will be attached to all existing tasks and the supplied "init()"
+ * function will be applied to it.  If any call to the supplied "init()"
+ * function returns a non zero result the registration will be aborted. As
+ * part of the abort process, all paggs belonging to the new client will be
+ * removed from all tasks and the supplied "detach()" function will be
+ * called on them.
+ *
+ * If a memory error is encountered, the pagg hook is unregistered and any
+ * tasks that have been attached to the initial pagg container are detached
+ * from that container.
+ *
+ */
+int
+pagg_hook_register(struct pagg_hook *pagg_hook_new)
+{
+       struct pagg_hook *pagg_hook = NULL;
+
+       /* Add new pagg module to access list */
+       if (!pagg_hook_new)
+               return -EINVAL;                 /* error */
+       if (!list_empty(&pagg_hook_new->entry))
+               return -EINVAL;                 /* error */
+       if (pagg_hook_new->name == NULL || strlen(pagg_hook_new->name) > 
PAGG_NAMELN)
+               return -EINVAL;                 /* error */
+       if (!pagg_hook_new->attach || !pagg_hook_new->detach)
+               return -EINVAL;                 /* error */
+
+       /* Try to insert new hook entry into the pagg hook list */
+       down_write(&pagg_hook_list_sem);
+
+       pagg_hook = get_pagg_hook(pagg_hook_new->name);
+
+       if (pagg_hook) {
+               up_write(&pagg_hook_list_sem);
+               printk(KERN_WARNING "Attempt to register duplicate"
+                               " PAGG support (name=%s)\n", 
pagg_hook_new->name);
+               return -EBUSY;
+       }
+
+       /* Okay, we can insert into the pagg hook list */
+       list_add_tail(&pagg_hook_new->entry, &pagg_hook_list);
+       /* set the ref count to zero */
+       atomic_set(&pagg_hook_new->refcnt, 0);
+
+       /* Now we can call the initializer function (if present) for each task 
*/
+       if (pagg_hook_new->init != NULL) {
+               struct task_struct *g = NULL, *p = NULL;
+               int init_result = 0;
+
+               /* Because of internal race conditions we can't guarantee
+                * getting every task in just one pass so we just keep going
+                * until we don't find any unitialized tasks.  The inefficiency
+                * of this should be tempered by the fact that this happens
+                * at most once for each registered client.
+                */
+               read_lock(&tasklist_lock);
+ repeat:
+               do_each_thread(g, p) {
+                       struct pagg *paggp;
+                       int task_exited;
+
+                       get_task_struct(p);
+                       read_unlock(&tasklist_lock);
+                       down_write(&p->pagg_sem);
+                       paggp = pagg_get(p, pagg_hook_new->name);
+                       if (!paggp && !(p->flags & PF_EXITING)) {
+                               paggp = pagg_alloc(p, pagg_hook_new);
+                               if (paggp != NULL) {
+                                       init_result = pagg_hook_new->init(p, 
paggp);
+
+                                       /* Success, but init function pointer 
doesn't want grouping */
+                                       if (init_result > 0)
+                                               pagg_free(paggp);
+                               }
+                               else
+                                       init_result = -ENOMEM;
+                       }
+                       up_write(&p->pagg_sem);
+                       read_lock(&tasklist_lock);
+                       /* Like in remove_client_paggs_from_all_tasks, if the 
task
+                        * disappeared on us while we were going through the
+                        * for_each_thread loop, we need to start over with 
that loop.
+                        * That's why we have the list_empty here */
+                       task_exited = list_empty(&p->sibling);
+                       put_task_struct(p);
+                       if (init_result < 0)
+                               goto endloop;
+                       if (task_exited)
+                               goto repeat;
+               } while_each_thread(g, p);
+ endloop:
+               read_unlock(&tasklist_lock);
+
+               /*
+                * if anything went wrong during initialisation abandon the
+                * registration process
+                */
+               if (init_result < 0) {
+                       remove_client_paggs_from_all_tasks(pagg_hook_new);
+                       list_del_init(&pagg_hook_new->entry);
+                       up_write(&pagg_hook_list_sem);
+
+                       printk(KERN_WARNING "Registering PAGG support for"
+                               " (name=%s) failed\n", pagg_hook_new->name);
+
+                       return init_result; /* hook init function error result 
*/
+               }
+       }
+
+       up_write(&pagg_hook_list_sem);
+
+       printk(KERN_INFO "Registering PAGG support for (name=%s)\n",
+                       pagg_hook_new->name);
+
+       return 0;                                       /* success */
+
+}
+
+/**
+ * pagg_hook_unregister - Unregister pagg hook and remove it from the list
+ * @pagg_hook_old: The hook to unregister and remove
+ *
+ * Used to unregister pagg hooks and remove them from the pagg_hook_list.
+ * Once the pagg hook entry in the pagg_hook_list is found, paggs associated
+ * with the hook (if any) will have their detach function called and will
+ * be detached.
+ *
+ */
+int
+pagg_hook_unregister(struct pagg_hook *pagg_hook_old)
+{
+       struct pagg_hook *pagg_hook;
+
+       /* Check the validity of the arguments */
+       if (!pagg_hook_old)
+               return -EINVAL;                 /* error */
+       if (list_empty(&pagg_hook_old->entry))
+               return -EINVAL;                 /* error */
+       if (pagg_hook_old->name == NULL)
+               return -EINVAL;                 /* error */
+
+       down_write(&pagg_hook_list_sem);
+
+       pagg_hook = get_pagg_hook(pagg_hook_old->name);
+
+       if (pagg_hook && pagg_hook == pagg_hook_old) {
+               remove_client_paggs_from_all_tasks(pagg_hook);
+               list_del_init(&pagg_hook->entry);
+               up_write(&pagg_hook_list_sem);
+
+               printk(KERN_INFO "Unregistering PAGG support for"
+                               " (name=%s)\n", pagg_hook_old->name);
+
+               return 0;                       /* success */
+       }
+
+       up_write(&pagg_hook_list_sem);
+
+       printk(KERN_WARNING "Attempt to unregister PAGG support (name=%s)"
+                       " failed - not found\n", pagg_hook_old->name);
+
+       return -EINVAL;                         /* error */
+}
+
+
+/**
+ * __pagg_attach - Attach a new task to the same containers of its parent
+ * @to_task: The child task that will inherit the parent's containers
+ * @from_task: The parent task
+ *
+ * Used to attach a new task to the same pagg containers to which it's parent
+ * is attached.
+ *
+ * The "from" argument is the parent task.  The "to" argument is the child
+ * task.
+ *
+ * See the attach decription in linux/include/linux/pagg.h for details on
+ * how to handle return codes from the attach function pointer.
+ *
+ */
+int
+__pagg_attach(struct task_struct *to_task, struct task_struct *from_task)
+{
+       struct pagg *from_pagg;
+       int ret;
+
+       /* lock the parents pagg_list we are copying from */
+       down_read(&from_task->pagg_sem); /* read lock the pagg list */
+
+       list_for_each_entry(from_pagg, &from_task->pagg_list, entry) {
+               struct pagg *to_pagg = NULL;
+
+               to_pagg = pagg_alloc(to_task, from_pagg->hook);
+               if (!to_pagg) {
+                       ret=-ENOMEM;
+                       goto error_return;
+               }
+               ret = to_pagg->hook->attach(to_task, to_pagg, from_pagg->data);
+
+               if (ret < 0) {
+                       /* Propagates to copy_process as a fork failure */
+                       goto error_return;
+               }
+               else if (ret > 0) {
+                       /* Success, but attach function pointer doesn't want 
grouping */
+                       pagg_free(to_pagg);
+               }
+       }
+
+       up_read(&from_task->pagg_sem); /* unlock the pagg list */
+
+       return 0;                                       /* success */
+
+  error_return:
+       /*
+        * Clean up all the pagg attachments made on behalf of the new
+        * task.  Set new task pagg ptr to NULL for return.
+        */
+       up_read(&from_task->pagg_sem); /* unlock the pagg list */
+       __pagg_detach(to_task);
+       return ret;                             /* failure */
+}
+
+/**
+ * __pagg_detach - Detach a task from all pagg containers it is attached to
+ * @task: Task to detach from pagg containers
+ *
+ * Used to detach a task from all pagg containers to which it is attached.
+ *
+ */
+void
+__pagg_detach(struct task_struct *task)
+{
+       struct pagg *pagg;
+       struct pagg *paggtmp;
+
+       /* Remove ref. to paggs from task immediately */
+       down_write(&task->pagg_sem); /* write lock pagg list */
+
+       list_for_each_entry_safe(pagg, paggtmp, &task->pagg_list, entry) {
+               pagg->hook->detach(task, pagg);
+               pagg_free(pagg);
+       }
+
+       up_write(&task->pagg_sem); /* write unlock the pagg list */
+
+       return;   /* 0 = success, else return last code for failure */
+}
+
+
+/**
+ * __pagg_exec - Execute callback when a process in a container execs
+ * @task: We go through the pagg list in the given task
+ *
+ * Used to when a process that is in a pagg container does an exec.
+ *
+ * The "from" argument is the task.  The "name" argument is the name
+ * of the process being exec'ed.
+ *
+ */
+int
+__pagg_exec(struct task_struct *task)
+{
+       struct pagg     *pagg;
+
+       down_read(&task->pagg_sem); /* lock the pagg list */
+
+       list_for_each_entry(pagg, &task->pagg_list, entry) {
+               if (pagg->hook->exec) /* conditional because it's optional */
+                       pagg->hook->exec(task, pagg);
+       }
+
+       up_read(&task->pagg_sem); /* unlock the pagg list */
+       return 0;
+}
+
+
+EXPORT_SYMBOL(pagg_get);
+EXPORT_SYMBOL(pagg_alloc);
+EXPORT_SYMBOL(pagg_free);
+EXPORT_SYMBOL(pagg_hook_register);
+EXPORT_SYMBOL(pagg_hook_unregister);
Index: linux/kernel/exit.c
===================================================================
--- linux.orig/kernel/exit.c    2005-02-10 12:18:47.950430580 -0800
+++ linux/kernel/exit.c 2005-02-10 14:25:59.195237674 -0800
@@ -26,6 +26,7 @@
 #include <linux/proc_fs.h>
 #include <linux/mempolicy.h>
 #include <linux/syscalls.h>
+#include <linux/pagg.h>

 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -828,6 +829,9 @@ fastcall NORET_TYPE void do_exit(long co
                module_put(tsk->binfmt->module);

        tsk->exit_code = code;
+
+       pagg_detach(tsk);
+
        exit_notify(tsk);
 #ifdef CONFIG_NUMA
        mpol_free(tsk->mempolicy);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to