diff -Naru 2.6-patch/Documentation/pagg.txt 2.6pagg-patch/Documentation/pagg.txt --- 2.6-patch/Documentation/pagg.txt 1969-12-31 18:00:00.000000000 -0600 +++ 2.6pagg-patch/Documentation/pagg.txt 2004-04-30 16:57:38.000000000 -0500 @@ -0,0 +1,157 @@ +Linux Process Aggregates (PAGG) +------------------------------- + +1. Description + +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). + +Additional details concerning this implementation of the process aggregates +infrastructure are described in the sections that follow. + + +2. Kernel Changes + +This section describe the files and data strcutrues that are involved in this +implementation of PAGG. Both modified as well as new files and data +structures are discussed. + +2.1. Modified Files + +The following files were modified to implement PAGG: + +- include/linux/init_task.h +- include/linux/sched.h +- kernel/Makefile +- kernel/exit.c +- kernel/fork.c +- fs/exec.c +- init/Kconfig + +2.2. New Files + +The following files were added to implement PAGG: + +- Documentation/pagg.txt +- include/linux/pagg.h +- kernel/pagg.c + + +2.3. Modified Data Structures + +The following existing data structures were altered to implement PAGG. + +- struct task_struct: (include/linux/sched.h) + struct pagg_list pagg_list; /* List of pagg containers */ + +This new member in task_struct, pagg_list, points to the list of pagg +containers to which the process is currently attached. + +2.4. New Data Structures + +The following new data structures were introduced to implement PAGG. + +- struct pagg: (include/linux/pagg.h) + struct pagg_hook *hook /* Ptr to pagg module entry */ + void *data; /* Task specific data */ + struct list_head entry; /* List connection */ + +- struct pagg_hook: (include/linux/pagg.h) + struct module *module; /* Ptr to PAGG module */ + char *name; /* PAGG hook name - restricted + * to 32 characters. */ + int (*attach)(struct task_struct *, /* Function to attach */ + struct pagg *, + void *); + int (*detach)(struct task_struct *, /* Function to detach */ + struct pagg *); + int (*init)(struct task_struct *, /* Load task init func. */ + struct pagg *); + void *data; /* Module specific data */ + struct list_head entry; /* List connection */ + void (*exec)(struct task_struct *, struct pagg *); /* exec func ptr */ + +The pagg structure provides the process' reference to the PAGG +containers provided by the PAGG modules. The attach function pointer +is the function used to notify the referenced PAGG container that the +process is being attached. The detach function pointer is used to notify +the referenced PAGG container that the process is exiting or otherwise +detaching from the container. The exec function pointer is 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. + +The pagg_hook structure provides the reference to the module that +implements a type of PAGG container. In addition to the function pointers +described concerning pagg, this structure provides an addition +function pointer. The init function pointer is currently not used +but will be available in the future. Future use of the init function +will be optional and will used to attach currently running processes to +a default PAGG container when a PAGG module is loaded on a running system. + + +2.5. Modified Functions + +The following functions were changed to implement PAGG: + +- do_fork: (kernel/fork.c) + /* execute the following pseudocode before add to run-queue */ + If parent process pagg list is not empty + Call attach_pagg_list function with child task_struct as argument +- do_exit: (kernel/exit.c) + /* execute the following pseudocode prior to schedule call */ + If current process pagg list is not empty + Call detach_pagg_list function with current task_struct +- sys_execve: (fs/exec.c) + /* When a process in a pagg exec's, an optional callout can be run. This + is implemented with an optional function pointer in the pagg_hook. */ + +2.6 New Functions + +The following new functions were added to implement PAGG: + +- int register_pagg_hook(struct pagg_hook *); (kernel/pagg.c) + Add module entry into table of pagg modules +- int unregister_pagg_hook(struct pagg_hook *); (kernel/pagg.c) + Find module entry in list of pagg modules + Foreach task + If task is attached to this pagg module + return error + If no tasks are referencing this module + remove module entry from list of pagg modules +- int attach_pagg_list(struct task_struct *); (kernel/pagg.c) + /* Assumed task pagg list pts to paggs that it attaches to */ + While another pagg container reference + Make copy of pagg container reference & insert into new list + Attach task to pagg container using new container reference + Get next pagg container reference + Make task pagg list use the new pagg list +- int detach_pagg_list(struct task_struct *); (kernel/pagg.c) + While another pagg container reference + Detach task from pagg container using reference + diff -Naru 2.6-patch/fs/exec.c 2.6pagg-patch/fs/exec.c --- 2.6-patch/fs/exec.c 2004-05-10 12:06:11.000000000 -0500 +++ 2.6pagg-patch/fs/exec.c 2004-05-20 14:46:49.000000000 -0500 @@ -46,7 +46,7 @@ #include #include #include - +#include #include #include #include @@ -1142,6 +1142,7 @@ retval = search_binary_handler(&bprm,regs); if (retval >= 0) { free_arg_pages(&bprm); + pagg_exec(current); /* execve success */ security_bprm_free(&bprm); diff -Naru 2.6-patch/include/linux/init_task.h 2.6pagg-patch/include/linux/init_task.h --- 2.6-patch/include/linux/init_task.h 2004-05-10 12:06:11.000000000 -0500 +++ 2.6pagg-patch/include/linux/init_task.h 2004-05-20 14:46:49.000000000 -0500 @@ -2,6 +2,7 @@ #define _LINUX__INIT_TASK_H #include +#include #define INIT_FILES \ { \ @@ -112,6 +113,7 @@ .proc_lock = SPIN_LOCK_UNLOCKED, \ .switch_lock = SPIN_LOCK_UNLOCKED, \ .journal_info = NULL, \ + INIT_TASK_PAGG(tsk) \ } diff -Naru 2.6-patch/include/linux/pagg.h 2.6pagg-patch/include/linux/pagg.h --- 2.6-patch/include/linux/pagg.h 1969-12-31 18:00:00.000000000 -0600 +++ 2.6pagg-patch/include/linux/pagg.h 2004-04-30 14:55:51.000000000 -0500 @@ -0,0 +1,246 @@ +/* + * 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 + */ + +/* + * Description: This file, include/linux/pagg.h, contains the 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 + +/* + * Used by task_struct to manage a list of pagg attachments for the task. + * The list will be used to hold references to pagg structures. + * These structures define the pagg attachments for the task. + * + * STRUCT MEMBERS: + * list: The list head pointer for the list of pagg + * structures. + * sem: The semaphore used to lock the list. + */ +struct pagg_list { + struct list_head head; + struct rw_semaphore sem; +}; + +#ifdef CONFIG_PAGG + +#define PAGG_NAMELN 32 /* Max chars in PAGG module name */ + + +/* Macro used to initialize a pagg_list structure after declaration + * + * Macro arguments: + * l: the pagg list (struct pagg_list) + */ +#define INIT_PAGG_LIST(_l) \ +do { \ + INIT_LIST_HEAD(_l.head); \ + init_rwsem(_l.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. + * 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. + * 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. + */ +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 */ + int (*init)(struct task_struct *, struct pagg *); + int (*attach)(struct task_struct *, struct pagg *, void*); + int (*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 int __pagg_detach(struct task_struct *task); +extern int __pagg_exec(struct task_struct *task); + +/* macros used when a child process must inherit attachment to pagg + * containers from the parent. + * + * Using static inline would result in not fully defined type errors. + * bad_fork_cleanup is defined in fork.c. + */ + +#define pagg_attach(child, parent) \ +do { \ + INIT_PAGG_LIST(&child->pagg_list); \ + if (!list_empty(&parent->pagg_list.head)) \ + if (__pagg_attach(child, parent) != 0) \ + goto bad_fork_cleanup; \ +} while(0) + +/* + * macro used when a process must detach from pagg containers to which it + * is currenlty a member. + * + */ +#define pagg_detach(task) \ +do { \ + if (!list_empty(&task->pagg_list.head)) \ + __pagg_detach(task); \ +} while(0) + +/* + * macro used when a process exec's. + * + */ +#define pagg_exec(task) \ +do { \ + if (!list_empty(&task->pagg_list.head)) \ + __pagg_exec(task); \ +} while(0) + +/* The static inlines commented out for now with the ifdef below */ +#ifdef NOTDEFINED + +/* function used when a child process must inherit attachment to pagg + * containers from the parent. + */ +static inline int pagg_attach(struct task_struct *child, + struct task_struct *parent) +{ + INIT_PAGG_LIST(&child->pagg_list); + if (!list_empty(&parent->pagg_list.head)) + return __pagg_attach(child, parent); + return 0; +} + +/* + * Function used when a process must detach from pagg containers to which it + * is currenlty a member. + * + */ +static inline void pagg_detach(struct task_struct *task) +{ + if (!list_empty(&task->pagg_list.head)) + __pagg_detach(task); +} + +/* + * function used when a process exec's. + * + */ +static inline void pagg_exec(struct task_struct *task) +{ + if (!list_empty(&task->pagg_list.head)) + __pagg_exec(task); +} +#endif /* NOT-DEFINED just comment out the block above for now */ + +/* + * 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 = { \ + .head = LIST_HEAD_INIT(tsk.pagg_list.head), \ + .sem = __RWSEM_INITIALIZER(tsk.pagg_list.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) do { } while(0) +#define pagg_detach(t) do { } while(0) +#define pagg_exec(t) do { } while(0) + +#endif /* CONFIG_PAGG */ + +#endif /* _LINUX_PAGG_H */ diff -Naru 2.6-patch/include/linux/sched.h 2.6pagg-patch/include/linux/sched.h --- 2.6-patch/include/linux/sched.h 2004-05-10 12:06:11.000000000 -0500 +++ 2.6pagg-patch/include/linux/sched.h 2004-05-20 14:46:49.000000000 -0500 @@ -29,6 +29,7 @@ #include #include #include +#include struct exec_domain; @@ -499,11 +500,15 @@ struct dentry *proc_dentry; struct backing_dev_info *backing_dev_info; - struct io_context *io_context; unsigned long ptrace_message; siginfo_t *last_siginfo; /* For ptrace use. */ + +#ifdef CONFIG_PAGG +/* List of pagg (process aggregate) attachments */ + struct pagg_list pagg_list; +#endif }; static inline pid_t process_group(struct task_struct *tsk) diff -Naru 2.6-patch/init/Kconfig 2.6pagg-patch/init/Kconfig --- 2.6-patch/init/Kconfig 2004-05-10 12:06:11.000000000 -0500 +++ 2.6pagg-patch/init/Kconfig 2004-05-20 14:46:49.000000000 -0500 @@ -121,6 +121,14 @@ up to the user level program to do useful things with this information. This is generally a good idea, so say Y. +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--- diff -Naru 2.6-patch/kernel/exit.c 2.6pagg-patch/kernel/exit.c --- 2.6-patch/kernel/exit.c 2004-05-10 12:06:11.000000000 -0500 +++ 2.6pagg-patch/kernel/exit.c 2004-05-20 14:46:49.000000000 -0500 @@ -22,7 +22,7 @@ #include #include #include - +#include #include #include #include @@ -799,6 +799,9 @@ module_put(tsk->binfmt->module); tsk->exit_code = code; + + pagg_detach(tsk); + exit_notify(tsk); schedule(); BUG(); diff -Naru 2.6-patch/kernel/fork.c 2.6pagg-patch/kernel/fork.c --- 2.6-patch/kernel/fork.c 2004-05-10 12:06:11.000000000 -0500 +++ 2.6pagg-patch/kernel/fork.c 2004-05-20 14:46:49.000000000 -0500 @@ -33,7 +33,7 @@ #include #include #include - +#include #include #include #include @@ -236,6 +236,9 @@ init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2; + + /* Initialize the pagg list in pid 0 before it can clone itself. */ + INIT_PAGG_LIST(¤t->pagg_list); } static struct task_struct *dup_task_struct(struct task_struct *orig) @@ -995,6 +998,12 @@ p->parent_exec_id = p->self_exec_id; + /* + * call pagg modules to properly attach new process to the same + * process aggregate containers as the parent process. + */ + pagg_attach(p, current); + /* ok, now we should be set up.. */ p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); p->pdeath_signal = 0; diff -Naru 2.6-patch/kernel/Makefile 2.6pagg-patch/kernel/Makefile --- 2.6-patch/kernel/Makefile 2004-05-10 12:06:11.000000000 -0500 +++ 2.6pagg-patch/kernel/Makefile 2004-05-20 14:46:49.000000000 -0500 @@ -18,6 +18,7 @@ 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 diff -Naru 2.6-patch/kernel/pagg.c 2.6pagg-patch/kernel/pagg.c --- 2.6-patch/kernel/pagg.c 1969-12-31 18:00:00.000000000 -0600 +++ 2.6pagg-patch/kernel/pagg.c 2004-05-20 13:36:37.000000000 -0500 @@ -0,0 +1,406 @@ +/* + * 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 + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* + * Description: This file, kernel/pagg.c, contains the routines used + * to implement process aggregates (paggs). The pagg + * extends the task_struct to allow for various process + * aggregation continers. Examples of such containers + * include "jobs" and cluster applications IDs. Process + * sessions and groups could have been implemented using + * paggs (although there would be little purpose in + * making that change at this juncture). The pagg + * structure maintains pointers to callback functions and + * data strucures maintained in modules that have + * registered with the kernel as pagg container + * providers. + */ + +#include + +#include +#include +#include +#include +#include + +/* 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 + * + * 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.head, entry) { + if (!strcmp(pagg->hook->name,key)) + return pagg; + } + return NULL; +} + + +/* + * pagg_alloc + * + * 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_list.sem. This can be locked using + * down_write(&task->pagg_list.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; + list_add_tail(&pagg->entry, &task->pagg_list.head); + return pagg; +} + + +/* + * pagg_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_list.sem + * for the task. This can be locked using down_write(&task->pagg_list.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) +{ + list_del(&pagg->entry); + kfree(pagg); +} + + +/* + * get_pagg_hook + * + * Given a pagg hook name key, this function will return a pointer + * to the pagg_hook struct that contains 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; +} + + +/* + * pagg_hook_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. + * + * In the future an initialization function may also be defined so that all + * existing tasks can be assigned to a default pagg entry for the hook. + * However, this would require iterating through the tasklist. To do that + * requires that the tasklist_lock be read locked. Since the initialization + * function might be in a module, and therefore it might sleep (implementors + * decision), holding the tasklist_lock seems like a bad idea. It may be a + * requirement that the initialization function will be strictly forbidden + * from locking - by gentlemans agreement... + * + * 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 */ + + /* 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); + 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 + * + * 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, all of the + * tasks are scanned and detached from any pagg containers defined by the + * pagg implementation module. + */ +int +pagg_hook_unregister(struct pagg_hook *pagg_hook_old) +{ + struct pagg_hook *pagg_hook; + struct task_struct *task; + + + /* 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) { + /* + * Scan through processes on system and check for + * references to pagg containers for this pagg hook. + * + * The module cannot be unloaded if there are references. + */ + read_lock(&tasklist_lock); + for_each_process(task) { + struct pagg *pagg = NULL; + + get_task_struct(task); /* So the task doesn't vanish on us */ + read_unlock(&tasklist_lock); + down_read(&task->pagg_list.sem); /* lock the pagg list */ + pagg = pagg_get(task, pagg_hook_old->name); + put_task_struct(task); + /* + * We won't be accessing pagg's memory, just need + * to see if one existed - so we can release the task + * lock now. + */ + up_read(&task->pagg_list.sem); /* unlock the pagg list */ + if (pagg) { + up_write(&pagg_hook_list_sem); + return -EBUSY; + } + + /* lock the task list again so we get a valid task in the loop */ + read_lock(&tasklist_lock); + } + read_unlock(&tasklist_lock); + 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 + * + * 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. + * + */ +int __pagg_attach(struct task_struct *to_task, struct task_struct *from_task) +{ + struct list_head *entry; + int retcode = 0; + + /* lock the parents pagg_list we are copying from */ + down_read(&from_task->pagg_list.sem); /* read lock the pagg list */ + + list_for_each(entry, &from_task->pagg_list.head) { + struct pagg *to_pagg = NULL; + struct pagg *from_pagg = list_entry(entry, struct pagg, + entry); + to_pagg = pagg_alloc(to_task, from_pagg->hook); + if (!to_pagg) { + retcode = -ENOMEM; + goto error_return; + } + retcode = to_pagg->hook->attach(to_task, to_pagg, from_pagg->data); + if (retcode != 0) { + /* attach should issue error message */ + goto error_return; + } + } + + up_read(&from_task->pagg_list.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_list.sem); /* unlock the pagg list */ + __pagg_detach(to_task); + return retcode; /* failure */ +} + +/* + * __pagg_detach + * + * Used to detach a task from all pagg containers to which it is attached. + * + * list_for_each used here because we need to reset the list after a + * pagg is detached. + */ +int +__pagg_detach(struct task_struct *task) +{ + struct list_head *entry; + int retcode = 0; + int rettmp = 0; + + /* Remove ref. to paggs from task immediately */ + down_write(&task->pagg_list.sem); /* write lock pagg list */ + + list_for_each(entry, &task->pagg_list.head) { + int rettemp = 0; + struct pagg *pagg = list_entry(entry, struct pagg, entry); + + entry = &task->pagg_list.head; + + rettemp = pagg->hook->detach(task, pagg); + if (rettmp) { + /* an error message should be logged in free_pagg */ + retcode = rettmp; + } + pagg_free(pagg); + } + + up_write(&task->pagg_list.sem); /* write unlock the pagg list */ + + return retcode; /* 0 = success, else return last code for failure */ +} + + +/* + * __pagg_exec + * + * 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; + + /* lock the parents pagg_list we are copying from */ + down_read(&task->pagg_list.sem); /* lock the pagg list */ + + list_for_each_entry(pagg, &task->pagg_list.head, entry) { + if (pagg->hook->exec) /* conditional because it's optional */ + pagg->hook->exec(task, pagg); + } + + up_read(&task->pagg_list.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);