lkml.org 
[lkml]   [2004]   [May]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] Process Aggregates (PAGG) update for 2.6.6
    Hi there.

    Attached is a fresh PAGG patch for the 2.6.6 kernel.

    This patch implements the LKML feedback received so far (with very few
    exceptions).

    I would be happy to post the inescapable jobs patch (a user of PAGG) as well.
    It can be found here (along with pagg):

    http://oss.sgi.com/projects/pagg/

    Thanks!

    --
    Erik Jacobson - Linux System Software - Silicon Graphics - Eagan, Minnesotadiff -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-05-24 08:08:34.000000000 -0500
    @@ -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).
    +
    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 <linux/security.h>
    #include <linux/syscalls.h>
    #include <linux/rmap.h>
    -
    +#include <linux/pagg.h>
    #include <asm/uaccess.h>
    #include <asm/pgalloc.h>
    #include <asm/mmu_context.h>
    @@ -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 <linux/file.h>
    +#include <linux/pagg.h>

    #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-05-26 08:31:00.000000000 -0500
    @@ -0,0 +1,191 @@
    +/*
    + * 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 */
    +
    +
    +/* Macro used to initialize a pagg_list structure after declaration
    + *
    + * Macro arguments:
    + * 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.
    + * 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.
    + * 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*);
    + 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);
    +
    +/* 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);
    + if (!list_empty(&parent->pagg_list))
    + 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))
    + __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))
    + __pagg_exec(task);
    +}
    +
    +/*
    + * 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) 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-26 08:31:24.000000000 -0500
    @@ -499,11 +499,16 @@

    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 list_head pagg_list;
    + struct rw_semaphore pagg_sem;
    +#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 <linux/profile.h>
    #include <linux/mount.h>
    #include <linux/proc_fs.h>
    -
    +#include <linux/pagg.h>
    #include <asm/uaccess.h>
    #include <asm/pgtable.h>
    #include <asm/mmu_context.h>
    @@ -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-21 10:13:53.000000000 -0500
    @@ -33,7 +33,7 @@
    #include <linux/ptrace.h>
    #include <linux/mount.h>
    #include <linux/audit.h>
    -
    +#include <linux/pagg.h>
    #include <asm/pgtable.h>
    #include <asm/pgalloc.h>
    #include <asm/uaccess.h>
    @@ -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(current);
    }

    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-25 15:35:29.000000000 -0500
    @@ -0,0 +1,385 @@
    +/*
    + * 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 <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
    + *
    + * 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
    + *
    + * 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
    + *
    + * 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
    + *
    + * 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;
    +}
    +
    +
    +/*
    + * 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);
    + /* set the ref count to zero */
    + atomic_set(&pagg_hook_new->refcnt, 0);
    + /* printk("DEBUG - pagg hook register - refcnt now: %d\n",
    + atomic_read(&pagg_hook_new->refcnt)); */
    + 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, we check if
    + * the pagg hook is still in use.
    + */
    +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);
    +
    + /* printk("DEBUG - pagg hook unregister - refcnt now: %d\n",
    + * atomic_read(&pagg_hook->refcnt));
    + */
    +
    + if (pagg_hook && pagg_hook == pagg_hook_old) {
    + /* Is the pagg hook busy? Check if the refcnt is zero */
    + if (atomic_read(&pagg_hook->refcnt) != 0) {
    + up_write(&pagg_hook_list_sem);
    + printk(KERN_INFO "Failed attempt to unregister a PAGG hook from: %s\n", pagg_hook_old->name);
    + return -EBUSY;
    + }
    + 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)
    +{
    + int retcode = 0;
    + struct pagg *from_pagg;
    +
    + /* 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) {
    + 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_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 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 pagg *pagg;
    + struct pagg *paggtmp;
    + int retcode = 0;
    + int rettmp = 0;
    +
    + /* 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) {
    + rettmp = 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_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_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);
    \
     
     \ /
      Last update: 2005-03-22 14:03    [W:0.089 / U:89.608 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site