diff -uprN -X elsa_import/dontdiff linux-2.6.5/fs/proc/proc_misc.c linux-2.6.5-elsa/fs/proc/proc_misc.c --- linux-2.6.5/fs/proc/proc_misc.c 2004-04-04 05:36:24.000000000 +0200 +++ linux-2.6.5-elsa/fs/proc/proc_misc.c 2004-04-26 10:35:03.000000000 +0200 @@ -328,6 +328,18 @@ static struct file_operations proc_disks .release = seq_release, }; +extern struct seq_operations bankinfo_op; +static int bankinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &bankinfo_op); +} +static struct file_operations proc_bankinfo_operations = { + .open = bankinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + #ifdef CONFIG_MODULES extern struct seq_operations modules_op; static int modules_open(struct inode *inode, struct file *file) @@ -341,7 +353,6 @@ static struct file_operations proc_modul .release = seq_release, }; #endif - extern struct seq_operations slabinfo_op; extern ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *); static int slabinfo_open(struct inode *inode, struct file *file) @@ -695,6 +706,7 @@ void __init proc_misc_init(void) create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); create_seq_entry("diskstats", 0, &proc_diskstats_operations); + create_seq_entry("bankinfo", 0, &proc_bankinfo_operations); #ifdef CONFIG_MODULES create_seq_entry("modules", 0, &proc_modules_operations); #endif diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/linux/elsa_acct.h linux-2.6.5-elsa/include/linux/elsa_acct.h --- linux-2.6.5/include/linux/elsa_acct.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.5-elsa/include/linux/elsa_acct.h 2004-04-28 14:34:30.000000000 +0200 @@ -0,0 +1,54 @@ +/* + * include/linux/elsa_acct.h + * + * ELSA - Enhanced Linux System Accounting + * Guillaume Thouvenin - 26/04/2004 + * + */ + +#ifndef __LINUX_ELSA_ACCT_H +#define __LINUX_ELSA_ACCT_H + +/* IOCTL numbers */ +/* + * Remove all process present in a bank. It needs one argument which + * is the identifier of the bank. + */ +#define ELSACCT_CLEAN 0x0 +/* + * Add a process to a given bank. It needs two arguments which are: + * ARG0, the identifier of the bank and + * ARG1 the pid of the process to add. + */ +#define ELSACCT_ADD 0x1 +/* + * Remove a process from a given bank. It needs two arguments which are: + * ARG0 is the identifier of the bank. If it is equal to zero, it means + * that process should be removed from all banks and + * ARG1 is the pid of the process to remove. + */ +#define ELSACCT_REMOVE 0x2 + +/* structure used when passing argument to ioctl */ +struct elsa_arg_s { + int bid; + int pid; +}; + +/* + * Currently, we take as a starting point the BSD-style + * process accounting. + */ +struct elsa_acct_s { + int eac_bid; /* Bank id */ + int eac_ptot; /* Total number of process that are added to a bank */ + int eac_utime; /* Accounting User Time */ + int eac_stime; /* Accounting System Time */ + int eac_etime; /* Accounting Elapsed Time */ + int eac_mem; /* Accounting Average Memory Usage */ + int eac_minflt; /* Accounting Minor Pagefaults */ + int eac_majflt; /* Accounting Major Pagefaults */ + int eac_swaps; /* Accounting Number of Swaps */ +}; + +#endif /* !(__LINUX_ELSA_ACCT_H) */ diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/linux/elsa_bank.h linux-2.6.5-elsa/include/linux/elsa_bank.h --- linux-2.6.5/include/linux/elsa_bank.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.5-elsa/include/linux/elsa_bank.h 2004-04-28 14:34:20.000000000 +0200 @@ -0,0 +1,129 @@ +/* + * include/linux/elsa_bank.h + * + * ELSA - Enhanced Linux System Accounting + * Guillaume Thouvenin - 26/04/2004 + * + * Provides structures and functions to manipulate "BANK". + * They are containers that store a set of processes. + * When a "BANK" is empty it is destroy and accounting infor- + * mations are stored in a file. Informations are about + * all process contained in a "BANK" + * + * The idea is to provide a mechanism that allows to group + * chosen process together. "BANK" must have some properties like: + * o If a process belongs to a bank, its children belong to the same bank + * o A process can be placed in several different banks + * o When the user adds a process to an non-existent bank, the container + * must automatically be created + * o When the last process of a bank exits, informations about all processes + * that belonged to the bank must be stored (maybe in a file) and the + * container must be destroyed + * + * To do that, we use a double linked list provides by the kernel + * (include/linux/list.h) and we do the following thing: + * + * elsa_broot BANK #1 BANK #2 + * bank_root_s elsa_bank_s elsa_bank_s + * -------------- ----------- ----------- + * | next_bid = 3 | | bid = 1 | | bid = 2 | + * |--------------| |-----------| |-----------| + * <===>| freebid_head | | info | | info | + * |--------------| |-----------| |-----------| + * | bank_head |<===>| bank_list |<===>| bank_list |<===>... + * |--------------| |-----------| |-----------| + * | bank_cb | | data_head | | data_head |<===>... + * |--------------| ---------- ----------- + * | data_cb | ^ ^ + * -------------- | | + * | ================= + * PROCESS DATA #1 | DATA #2 | + * task_struct elsa_data_s | elsa_data_s | + * --------- ----------- | ----------- | + * | | | bid = 1 | | | bid = 1 | | + * | | |-----------| | |-----------| | + * | |<------| process | | | process | | + * | | |-----------| | |-----------| | + * | | | data_list |<= | data_list |<=== + * ... ... | |<===>| | + * |---------| |-----------| |-----------| + * |bank_head|<=====>| bank_list | | bank_list | + * |---------| ----------- ----------- + * ... ... + * + * + * Field "bank_list" in the elsa_data_s is used to know which are banks with + * a given process. Structure "task_struc" is modified to use this field. + */ + +#ifndef __LINUX_ELSA_BANK_H +#define __LINUX_ELSA_BANK_H + +#include +#include +#include + +/*** + * Internal structures + ***/ +struct bank_root_s { + /* + * We need to protect ID by a semaphore since it must be + * a unique number. We can't have to bank with same ID + */ + int next_bid; /* next available bank identifier */ + struct list_head freebid_head; /* a list of free bank identifier */ + struct list_head bank_head; /* head of the list of bank */ + void (*bank_cb) (int bid); /* action to perform when bank is removed */ + void (*data_cb) (int bid); /* action to perform when data is removed */ +}; + +#define BANK_ROOT_INIT(root) { \ + 1, \ + LIST_HEAD_INIT(root.freebid_head), \ + LIST_HEAD_INIT(root.bank_head), \ + NULL, \ + NULL \ +} + +struct elsa_freebid_s { + int bid; + struct list_head bid_list; +}; + +struct elsa_bank_s { + int bid; /* the bank identifier */ + void *info; /* allow to hang information to banks */ + struct list_head bank_list; /* list of available banks */ + struct list_head data_head; /* head of the list of datas in the + bank */ +}; + +struct elsa_data_s { + int bid; /* the bank to which data belong */ + struct task_struct *process; /* the process information */ + struct list_head data_list; /* link between datas in a bank */ + struct list_head bank_list; /* used by a process to link banks + that contains it */ +}; + + /************************************************ + * Following functions can be use by a module or * + * a system call (=> they are exported) * + ************************************************/ +void elsa_bank_init_cb(void *bank_cb, void *data_cb); +int elsa_bank_set_info(int bid, void *info); +void *elsa_bank_get_info(int bid); +int elsa_bank_add(int bid, struct task_struct *p); +int elsa_bank_clean(int bid); +int elsa_bank_remove(int bid, pid_t pid); + + /***************************************************************************** + * Following functions are called from kernel function. * + * elsa_copy_parent() is used when child is created (kernel/fork.c) * + * elsa_bank_remove_all() is used when a process terminates (kernel/exit.c) * + *****************************************************************************/ +void elsa_copy_parent_bank(struct task_struct *from, struct task_struct *to); +void elsa_bank_remove_all(struct task_struct *p); + +#endif /* !(__LINUX_ELSA_BANK_H) */ diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/linux/sched.h linux-2.6.5-elsa/include/linux/sched.h --- linux-2.6.5/include/linux/sched.h 2004-04-04 05:36:18.000000000 +0200 +++ linux-2.6.5-elsa/include/linux/sched.h 2004-04-26 10:35:03.000000000 +0200 @@ -493,6 +493,9 @@ struct task_struct { unsigned long ptrace_message; siginfo_t *last_siginfo; /* For ptrace use. */ + +/* List of BANK to which the process belong - Used by ELSA */ + struct list_head bank_head; }; static inline pid_t process_group(struct task_struct *tsk) diff -uprN -X elsa_import/dontdiff linux-2.6.5/init/Kconfig linux-2.6.5-elsa/init/Kconfig --- linux-2.6.5/init/Kconfig 2004-04-04 05:37:44.000000000 +0200 +++ linux-2.6.5-elsa/init/Kconfig 2004-04-26 11:16:19.000000000 +0200 @@ -103,6 +103,36 @@ config BSD_PROCESS_ACCT list is in the struct acct in ). It is up to the user level program to do useful things with this information. This is generally a good idea, so say Y. +config ELSA_ACCT + tristate "ELSA accounting" + default n + ---help--- + The goal of accounting is to collect and report the use of various + system resources by applications. Informations, like process time, + CPU usage, connect time or disk space usage, provides data that helps + the system to adjust the use of resources between processes. + + The current BSD-like process accounting that already exists in Linux + collects informations on individual users or groups of users. The ELSA + project aims to improve and extend the monitoring of resources with + different criteria like groups of processes. Another target for this + project is to give Linux an homogeneous set of commands for all kinds + of accounting (memory, CPU and I/O). + + To compile this driver as a module, choose M here: the module will be + called elsa-acct. + + Documentation about ELSA is available from + + +config ELSA_DEBUG + bool "ELSA bank debugging support" + default n + ---help--- + This option allows you to enable debugging output when using + banks structure. Currently, such structure is used by Enhanced + Linux System Accounting (ELSA). Informations are sent to the + console. config SYSCTL bool "Sysctl support" diff -uprN -X elsa_import/dontdiff linux-2.6.5/kernel/elsa_acct.c linux-2.6.5-elsa/kernel/elsa_acct.c --- linux-2.6.5/kernel/elsa_acct.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.5-elsa/kernel/elsa_acct.c 2004-04-28 14:34:36.000000000 +0200 @@ -0,0 +1,331 @@ +/* + * linux/kernel/elsa_acct.c + * + * ELSA - Enhanced Linux System Accounting + * Guillaume Thouvenin - 26/04/2004 + * + * This module implements Enhanced Linux System Accounting. + * We implement a character driver to transfer data between + * BANK that are in the kernel adress space and the user + * adress space. + * + * This code is licenced under GPL. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int elsa_major; + +/** + * do_elsa_acct - callback hook to data + * @bid: bank identifier + * + * Call when a data is destroyed. It does accounting updates. + */ +void do_elsa_acct(int bid) +{ + struct elsa_acct_s *info; + + info = (struct elsa_acct_s *)elsa_bank_get_info(bid); + + if (info) + info->eac_ptot++; + else + printk("do_elsa_acct: error BID == %d\n", bid); +} + +/** + * free_elsa_info - callback hook to bank + * @bid: bank identifier + * + * Call when a bank is destroyed. It dumps accounting + * information to a buffer and release memory space + * used to store information at the bank level + */ +void free_elsa_info(int bid) +{ + struct elsa_acct_s *info; + + info = (struct elsa_acct_s *)elsa_bank_get_info(bid); + + /* + * We put information in the log file. If the file isn't empty, + * information in the file will be destroyed. + */ + if (info) { + //file = open(ELSA_LOG, O_WRONLY | O_CREAT ,0600); + //if (file) { + // write(file, (char *)info, sizeof(struct elsa_acct_s)); + // close(file); + //} else { + //printk("free_elsa_info: ERROR, cannot open /var/log/elsacct\n"); + //} + printk("free_elsa_info: Max number BID#%d was %d\n", bid, + info->eac_ptot); + kfree(info); + } else { + printk("free_elsa_info: ERROR, info == NULL\n"); + } +} + +/** + * hang_elsa_info - attach info structure to the bank + * @bid: bank identifier + * + * create and attach a new info structure to bank with identifier + * equal to bid. + */ +void hang_elsa_info(int bid) +{ + struct elsa_acct_s *info; + + info = (struct elsa_acct_s *)kmalloc(sizeof(struct elsa_acct_s), + GFP_KERNEL); + + if (info) { + printk("Bank #id%d created: info hung\n", bid); + + /* initialize info fields */ + info->eac_bid = bid; + info->eac_ptot = 0; + info->eac_utime = 0; + info->eac_stime = 0; + info->eac_etime = 0; + info->eac_mem = 0; + info->eac_minflt = 0; + info->eac_majflt = 0; + info->eac_swaps = 0; + + elsa_bank_set_info(bid, info); + } else { + printk(KERN_WARNING "Bank #id%d created: info error\n", bid); + } + +} + + /****************************************** + * functions used to manipulate the device * + ******************************************/ + +/** + * elsacct_read - copy data to application code + * @file : file pointer + * @buf : pointer to the user empty buffer + * @count: size of the requested data transfer + * @ppos : pointer to long offset type that indicates the file + * position the user is accessing + * + * Copy data from the device to user space. + * Return a negative value if an error occurs. + */ +ssize_t elsacct_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + return (ssize_t) 0; +} + +/** + * elsacct_write - copy data from application code + * @file : file pointer + * @buf : pointer to the user buffer holding data to be written + * @count: size of the requested data transfer + * @ppos : pointer to long offset type that indicates the file + * position the user is accessing + * + * Copy data from user space to the device. + * Return a negative value if an error occurs. + */ +ssize_t elsacct_write(struct file * file, const char *buf, + size_t count, loff_t * ppos) +{ + ssize_t retval = 0; + + return retval; +} + +/** + * elsacct_ioctl - issue a device specific command + * @inode: pointer to inode structure + * @file : file pointer + * @cmd : specific command to perform. + * Commands can be ELSACCT_CLEAN, ELSACCT_ADD or ELSACCT_REMOVE + * @arg : arguments that depend of cmd. + * + * Perform some actions on banks that depend of command passed to the + * system call + */ +int elsacct_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int retval = 0; + struct elsa_arg_s *args = (struct elsa_arg_s *)arg; + struct task_struct *p; + + switch (cmd) { + case ELSACCT_CLEAN: + if (!args) { + printk(KERN_WARNING + "elsacct_ioctl: ELSACCT_CLEAN wrong parameter\n"); + retval = -EINVAL; + } else { + printk(KERN_INFO "elsacct_ioctl: clean bank ID#%d\n", + args->bid); + retval = elsa_bank_clean(args->bid); + } + break; + + case ELSACCT_ADD: + if (!args) { + printk(KERN_WARNING + "elsacct_ioctl: ELSACCT_CLEAN wrong parameter\n"); + retval = -EINVAL; + } else { + printk(KERN_INFO + "elsacct_ioctl: add process #%d to bank #%d\n", + args->pid, args->bid); + + p = find_task_by_pid(args->pid); + if (!p) { + printk(KERN_WARNING + "elsacct_ioct: PID#%d not found\n", + args->pid); + retval = -EAGAIN; + } else { + /* if args->bid == 0, it will create a new bank */ + retval = elsa_bank_add(args->bid, p); + if (retval > 0) + hang_elsa_info(retval); + } + } + break; + + case ELSACCT_REMOVE: + if (!args) { + printk(KERN_WARNING + "elsacct_ioctl: ELSACCT_CLEAN wrong parameter\n"); + retval = -EINVAL; + } else { + printk(KERN_INFO + "elsacct_ioctl: remove process #%d to bank #%d\n", + args->pid, args->bid); + retval = elsa_bank_remove(args->bid, args->pid); + } + break; + + default: + printk(KERN_WARNING + "elsacct_ioctl: 0x%x unsupported ioctl command\n", cmd); + retval = -ENOIOCTLCMD; + }; + + return retval; +} + +int elsacct_open(struct inode *inode, struct file *file) +{ + return 0; +} + +int elsacct_release(struct inode *inode, struct file *file) +{ + return 0; +} + +struct file_operations elsa_fops = { + .owner = THIS_MODULE, + .read = elsacct_read, + .write = elsacct_write, + .ioctl = elsacct_ioctl, + .open = elsacct_open, + .release = elsacct_release, +}; + +/** + * elsacct_init - Initialize enhanced linux system accounting + * + * Initializes "callbacks" to bank and data. Those + * functions are called a bank or a data are destroyed. + * It allows to perform some actions in the module. + */ +static int __init elsacct_init(void) +{ + int retval = 0; + + /* register character device with a dynamic major number */ + elsa_major = register_chrdev(0, "elsacct", &elsa_fops); + if (!elsa_major) { + printk(KERN_WARNING + "elsacct_init: can't get major %d\n", elsa_major); + return -EIO; + } + printk(KERN_INFO "elsacct_init: get major %d\n", elsa_major); + + /* set bank and data callbacks */ + elsa_bank_init_cb(&free_elsa_info, &do_elsa_acct); + + /* succeed */ + return retval; + + out_devfs: + /* currently, we know that this code can not be run + but we add it because when init will become more + complex we don't want to forget to remove some stuff + created before the problem */ + unregister_chrdev(elsa_major, "elsacct"); + return retval; +} + +#ifdef MODULE + + /************************ + * Module initialization * + ************************/ + +/** + * elsacct_init_module - called when module is loaded + * + * Display a message in dmesg and call the real + * initialization function. + */ +static int __init elsacct_init_module(void) +{ + printk(KERN_INFO "ELSA accounting started\n"); + return elsacct_init(); +} + +/** + * elsacct_cleanup - called when module is unloaded + * + * Display a message in dmesg + */ +static void __exit elsacct_cleanup_module(void) +{ + /* release the major number when module is unloaded */ + if (unregister_chrdev(elsa_major, "elsacct")) + printk(KERN_WARNING + "elsacct_cleanup: cannot unregister blkdev\n"); + else + printk(KERN_INFO "elsacct_cleanup: accounting terminated\n"); +} + +module_init(elsacct_init_module); +module_exit(elsacct_cleanup_module); + +MODULE_DESCRIPTION("Enhanced Linux System Accounting."); +MODULE_AUTHOR("Guillaume Thouvenin "); + +MODULE_LICENSE("GPL"); + +#else + +module_init(elsacct_init); + +#endif /* !(MODULE) */ diff -uprN -X elsa_import/dontdiff linux-2.6.5/kernel/elsa_bank.c linux-2.6.5-elsa/kernel/elsa_bank.c --- linux-2.6.5/kernel/elsa_bank.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.5-elsa/kernel/elsa_bank.c 2004-04-28 14:34:36.000000000 +0200 @@ -0,0 +1,639 @@ +/* + * linux/kernel/elsa_bank.c + * + * ELSA - Enhanced Linux System Accounting + * Guillaume Thouvenin - 26/04/2004 + * + * This file implements Enhanced Linux System Accounting. It + * provides structure and functions to manipulate "BANK". + * + * + * This code is licenced under GPL. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + + /********************************************* + * structures and macros used to manage banks * + *********************************************/ + +/* It's the head on the list of banks */ +static struct bank_root_s elsa_broot = BANK_ROOT_INIT(elsa_broot); + +/* semaphore that protect access to bank id */ +static DECLARE_MUTEX(elsa_bid_sem); + + /************************************************** + * Here are declaration of functions that are only * + * used in this file * + **************************************************/ + +/* get informations */ +static int elsa_get_bid(void); +static struct elsa_bank_s *elsa_get_bank(int bid); +static struct elsa_data_s *elsa_get_data(struct elsa_bank_s *bank, + struct task_struct *p); + +/* manage memory space used by banks */ +static int elsa_bank_alloc(void); +static int elsa_bank_free(struct elsa_bank_s *bank); + +/* manage bank's data */ +static void elsa_data_free(struct elsa_data_s *data); + + /************************************************ + * Following functions can be use by a module or * + * a system call (=> they are exported) * + ************************************************/ + +/** + * elsa_bank_set_info - Set pointer to information in + * bank structure + * @bid: bank identifier + * @info: pointer to information to link with the bank + */ +int elsa_bank_set_info(int bid, void *info) +{ + struct elsa_bank_s *bank = elsa_get_bank(bid); + + if (bank) + bank->info = info; + else + return -EAGAIN; + + return bid; +} + +void *elsa_bank_get_info(int bid) +{ + struct elsa_bank_s *bank = elsa_get_bank(bid); + + return (bank) ? bank->info : NULL; +} + +/** + * elsa_bank_init_cb - Initialize callbacks + * @bank_cb: function to call when bank is deleted + * @data_cb: function to call when data is deleted + * + * Initializes callbacks when bank and data are removed from a + * list. + */ +void elsa_bank_init_cb(void *bank_cb, void *data_cb) +{ + elsa_broot.bank_cb = bank_cb; + elsa_broot.data_cb = data_cb; +} + +/** + * elsa_bank_add - Add a process to a given bank + * @bid: bank identifier + * @p : pointer to a process + * + * Creates a new bank if BID is equal to 0, otherwise, add data + * to bank BID. + * + * If an error is encountered, a negative value is returned. + * It can not return 0. + * + * Here are steps to perform + * + * 1) get the bank with id bid + * If we don't find it, there is a bug since this function is used to + * add a child in parent's bank. Thus, there is at least the parent in + * the bank + * 2) Allocate space to the new data + * 3) Initialize its fields + */ +int elsa_bank_add(int bid, struct task_struct *p) +{ + struct elsa_bank_s *bank; + struct elsa_data_s *data; + + /* + * Create a new bank if bid is equal to zero, + * otherwise, find the bank with id equal to bid + */ + if (!bid) { + /* create a new bank */ + bid = elsa_bank_alloc(); + bank = elsa_get_bank(bid); + /* At this point bank != NULL or it is a bug */ + if (!bank) { + printk("elsa_bank_add: found a bug !!!"); + return -EPROTO; + } + } else { + bank = elsa_get_bank(bid); + if (!bank) { + printk("elsa_bank_add: Bank ID#%d not found\n", bid); + return -ENODATA; + } + } + + /* + * At this point, bank exists, we check if process is + * already present + */ + if (elsa_get_data(bank, p) != NULL) + /* Process already in the bank, nothing to do */ + return bid; + + /* allocate space to data */ + data = + (struct elsa_data_s *)kmalloc(sizeof(struct elsa_data_s), + GFP_KERNEL); + if (!data) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_add: cannot allocate space for data\n"); +#endif + return -ENOMEM; + } + + /* initialize data */ + data->bid = bid; + data->process = p; + list_add(&(data->data_list), &(bank->data_head)); + list_add(&(data->bank_list), &(p->bank_head)); + +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_add: Add process #%d to bank #%d\n", p->pid, bid); +#endif + + return bid; +} + +/** + * elsa_bank_clean - Removes data in a given bank + * @bid: identifier of the bank to clean + * + * Removes data found in a bank given in paramater. It go through the + * list, removes link and free space occupied by the data. + */ +int elsa_bank_clean(int bid) +{ + struct elsa_bank_s *bank; + struct elsa_data_s *data; + + bank = elsa_get_bank(bid); + if (!bank) { + /* bank doesn't exist */ + printk("elsa_bank_clean: bank doesn't exist\n"); + return -EAGAIN; + } + + /* release all datas and remove the bank */ + while (!list_empty(&(bank->data_head))) { + /* get pointer to the first element in the list */ + data = list_entry(bank->data_head.next, + struct elsa_data_s, data_list); + if (data) + elsa_data_free(data); + } + + return bid; +} + +/** + * elsa_bank_remove - Remove a process to one + * @bid: identifier of the bank where the process will be removed + * @pid: identifier of the process to be removed + * + * Removes a given process from a given list. If parameter bid is equal to + * zero, the process is removed from all banks. It returns the identifier + * of the bank from which it is removed. + */ +int elsa_bank_remove(int bid, pid_t pid) +{ + struct elsa_data_s *data = NULL; + struct task_struct *p = find_task_by_pid(pid); + int found = 0; + + if (bid == 0) { + elsa_bank_remove_all(p); + return 0; + } + + /* found bank with identifier equal to BID */ + if (!list_empty(&(p->bank_head))) + list_for_each_entry(data, &(p->bank_head), bank_list) + if (data->bid == bid) { + found = bid; + break; + } + + if (found && data) + elsa_data_free(data); + + return found; +} + +EXPORT_SYMBOL(elsa_bank_set_info); +EXPORT_SYMBOL(elsa_bank_get_info); +EXPORT_SYMBOL(elsa_bank_init_cb); +EXPORT_SYMBOL(elsa_bank_add); +EXPORT_SYMBOL(elsa_bank_clean); +EXPORT_SYMBOL(elsa_bank_remove); + + /***************************************************************************** + * Following functions are called from kernel function. * + * elsa_copy_parent() is used when child is created (kernel/fork.c) * + * elsa_bank_remove_all() is used when a process terminates (kernel/exit.c) * + *****************************************************************************/ + +/** + * elsa_copy_parent_bank - Add a given process to the same banks + * as another one + * @from: Process from where we will copy information + * @to: Process to where we will copy information + * + * Goes through the banks to which "from" process belong and add + * the process in those banks. + * + * It is used when doing a fork (kernel/fork.c - copy_process()). + * This function is used by the kernel to update child's banks. + */ +void elsa_copy_parent_bank(struct task_struct *from, struct task_struct *to) +{ + struct elsa_data_s *data; + + if (!list_empty(&from->bank_head)) + list_for_each_entry(data, &(from->bank_head), bank_list) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_copy_parent_bank: from pid#%d to pid#%d\n", + from->pid, to->pid); + if (data->bid == 0) + printk("elsa_copy_parent_bank: Find a bug\n"); +#endif + elsa_bank_add(data->bid, to); + } +} + +/** + * elsa_bank_remove_all - Remove a process to all belonging banks + * @p: a pointer to the process to remove from banks + * + * Removes the process from all banks. We use field "bank_head" of the + * task_struct. So, this new field has been placed in the task_struct + * only to allow to remove a processus from all banks to which it belongs. + * If it is the last process in the bank, the bank is released + */ +void elsa_bank_remove_all(struct task_struct *p) +{ + struct elsa_data_s *data; + + /* remove from all banks */ + while (!list_empty(&p->bank_head)) { + data = list_entry(p->bank_head.next, + struct elsa_data_s, bank_list); + if (data) + elsa_data_free(data); + } +} + + /****************************************************************** + * As said at the begin of this file, following functions are only * + * for internal usage. * + ******************************************************************/ + +/** + * elsa_get_bid - Returns a bank identifier + * + * Retruns an available bank identifier. It first looks + * if there is one in the list of freebid, if not, it tests + * if there is still free id (equivalent to next_bid > 0). + * If yes, it update next_bid returns the identifier. + * If an error is encountered, a negative value is returned. + * It can not return 0. + */ +static int elsa_get_bid(void) +{ + struct elsa_freebid_s *freebid; + int bid; + + down(&elsa_bid_sem); + + /* if there is one in the freebid list use it */ + if (!list_empty(&(elsa_broot.freebid_head))) { + /* get the first entry in the list */ + freebid = + list_entry(elsa_broot.freebid_head.next, + struct elsa_freebid_s, bid_list); + + /* got it */ + bid = freebid->bid; + + /* remove it from the list */ + list_del(&(freebid->bid_list)); + + /* free space */ + kfree(freebid); + } else { + /* test if there is one available free ID */ + if (elsa_broot.next_bid <= 0) { + /* there is no more banks */ + bid = -ENODATA; + } else { + + bid = elsa_broot.next_bid; + elsa_broot.next_bid++; + } + } + + up(&elsa_bid_sem); + return bid; +} + +/** + * elsa_get_bank - Returns a pointer to a bank + * @bid: The identifier of a bank + * + * Finds the bank with given ID in the list of banks + */ +static struct elsa_bank_s *elsa_get_bank(int bid) +{ + struct elsa_bank_s *bank = NULL; + int found = 0; + + if (!list_empty(&(elsa_broot.bank_head))) + list_for_each_entry(bank, &(elsa_broot.bank_head), bank_list) + if (bank->bid == bid) { + found = bid; + break; + } + + return found ? bank : NULL; +} + +/** + * elsa_get_data - Returns a pointer to a data + * @bank: a pointer to the container in which we are looking for the data + * @pid: the process identifier to look for + * + * Finds a data that points to a process if it exists. + */ +static struct elsa_data_s *elsa_get_data(struct elsa_bank_s *bank, + struct task_struct *p) +{ + struct elsa_data_s *data = NULL; + int found = 0; + + if (!list_empty(&(bank->data_head))) { + list_for_each_entry(data, &(bank->data_head), data_list) { + if (data->process == p) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_get_data: found PID#%d\n", p->pid); +#endif + found = 1; + break; + } + } + } + + /* if found != 0 then we return data */ + return found ? data : NULL; +} + +/** + * elsa_bank_alloc - Allocates a new bank + * + * Allocates a new bank and returns the identifiers of the new created bank. + * If an error is encountered, a negative value is returned. + * It can not return 0. + * + * Here are different steps of the operation + * + * 1) Allocate space for the new bank + * 2) Give it an identifier + * 3) Initialize the head of the list of items (items will point to process) + * 3) Add it to the list of available bank + */ +static int elsa_bank_alloc(void) +{ + struct elsa_bank_s *new_bank; + int new_bid; + + /* allocate space for the new bank */ + new_bank = + (struct elsa_bank_s *)kmalloc(sizeof(struct elsa_bank_s), + GFP_KERNEL); + if (!new_bank) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_alloc: cannot allocate space for new_bank\n"); +#endif + return -ENOMEM; + } + + /* give it an id */ + new_bid = elsa_get_bid(); + if (elsa_get_bid <= 0) { + /* There is no available id == ERROR */ + kfree(new_bank); +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_alloc: can not find bank identifier\n"); +#endif + return -ENODATA; + } else { + new_bank->bid = new_bid; + } + + /* Set info to NULL */ + new_bank->info = NULL; + + /* Initialize head (list of datas) */ + INIT_LIST_HEAD(&(new_bank->data_head)); + + /* add it to the list of banks */ + list_add(&(new_bank->bank_list), &(elsa_broot.bank_head)); + +#ifdef CONFIG_ELSA_DEBUG + printk + ("elsa_bank_alloc: bank #%d created and added to the list\n", + new_bank->bid); +#endif + return new_bank->bid; +} + +/** + * elsa_bank_free - Frees space occupied by a bank. + * @bank: a pointer to the bank to delete + * + * Removes a bank and returns the identifiers of the removed bank. + * When this function is called bank MUST be empty + * If an error is encountered, a negative value is returned. + * If there is no corresponding BANK_ID, 0 is returned. + * + * Here are different steps of the operation + * + * 1) Write accounting information + * 2) Put bank ID in the list of free BID. + * 3) Remove it from the list of banks + * 4) Free space for the new bank + */ +static int elsa_bank_free(struct elsa_bank_s *bank) +{ + struct elsa_freebid_s *new_freebid; + + if (!list_empty(&bank->data_head)) { + printk("elsa_bank_free: BUG found - lists isn't empty\n"); + return -EAGAIN; + } + + /* Before deleting the bank, we can do some action */ + /* callback */ + if (elsa_broot.bank_cb) + (elsa_broot.bank_cb) (bank->bid); + + /* Insert the identifier of the bank in the list of free bank ID */ + /* allocate space for the freebid item */ + new_freebid = (struct elsa_freebid_s *) + kmalloc(sizeof(struct elsa_freebid_s), GFP_KERNEL); + if (!new_freebid) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_free: cannot allocate space for freebid\n"); +#endif + return -ENOMEM; + } + new_freebid->bid = bank->bid; + list_add(&(new_freebid->bid_list), &(elsa_broot.freebid_head)); + + /* we can now remove the bank from the list */ + list_del(&(bank->bank_list)); +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_free: bank #%d removed from the list\n", bank->bid); +#endif + kfree(bank); + + return new_freebid->bid; +} + +/** + * elsa_data_free - Free data + * @data: data to be removed + * + * Frees memory space used by data. If it is the last element present in a + * bank, bank will also be removed. + */ +#define __elsa_data_free(data) do { \ + list_del(&data->data_list); \ + list_del(&data->bank_list); \ + kfree(data); \ +} while (0) + +static void elsa_data_free(struct elsa_data_s *data) +{ + struct elsa_bank_s *bank = elsa_get_bank(data->bid); + +#ifdef CONFIG_ELSA_DEBUG + printk + ("elsa_data_free: process #%d removed from bank #%d\n", + data->process->pid, data->bid); +#endif + /* callback */ + if (elsa_broot.data_cb) + (elsa_broot.data_cb) (data->bid); + + if (data->data_list.next == data->data_list.prev) { + /* data is the last item in the bank */ + __elsa_data_free(data); + /* bank is now empty */ + elsa_bank_free(bank); + } else { + __elsa_data_free(data); + } +} + + /********************************* + * functions used to manage /proc * + *********************************/ + +/*** + * Add an entry in /proc to get informations concerning + * banks. This entry is called /proc/bankinfo + ****/ +#ifdef CONFIG_PROC_FS +static void *b_start(struct seq_file *m, loff_t * pos) +{ + loff_t n = *pos; + struct list_head *p; + + /* Header is displaying just during the first called */ + if (!n) { + seq_puts(m, "# - bankinfo -\n"); + seq_puts(m, "# bankid:\t ...\n"); + } + + if (list_empty(&elsa_broot.bank_head)) + return NULL; + + p = elsa_broot.bank_head.next; + while (n--) { + p = p->next; + if (p == &elsa_broot.bank_head) + return NULL; + } + + /* we return a pointer to the data in the bank */ + return list_entry(p, struct elsa_bank_s, bank_list); +} + +static void b_stop(struct seq_file *m, void *v) +{ +} + +static void *b_next(struct seq_file *m, void *v, loff_t * pos) +{ + struct elsa_bank_s *bank = v; + + ++*pos; + return bank->bank_list.next == &elsa_broot.bank_head ? NULL : + list_entry(bank->bank_list.next, struct elsa_bank_s, bank_list); +} + +static int show_bankinfo(struct seq_file *m, void *v) +{ + struct elsa_bank_s *bank = v; + struct elsa_data_s *data; + + if (!bank) { + seq_printf(m, "There is no banks\n"); + } else { + /* display bank identifier */ + seq_printf(m, "%d:", bank->bid); + /* add a tabulation */ + seq_printf(m, "\t"); + /* display list of processus */ + if (list_empty(&(bank->data_head))) { + seq_printf(m, "Empty"); + } else { + list_for_each_entry(data, &(bank->data_head), data_list) + seq_printf(m, "%d ", data->process->pid); + } + /* add EOL */ + seq_printf(m, "\n"); + } + + return 0; +} + +/* bankinfo_op - iterator that generates /proc/bankinfo + * + * Output layout: + * bankID pid ... + */ +struct seq_operations bankinfo_op = { + .start = b_start, + .stop = b_stop, + .next = b_next, + .show = show_bankinfo, +}; +#endif diff -uprN -X elsa_import/dontdiff linux-2.6.5/kernel/exit.c linux-2.6.5-elsa/kernel/exit.c --- linux-2.6.5/kernel/exit.c 2004-04-04 05:38:13.000000000 +0200 +++ linux-2.6.5-elsa/kernel/exit.c 2004-04-26 10:35:03.000000000 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -95,6 +96,7 @@ repeat: p->parent->cnswap += p->nswap + p->cnswap; p->parent->cnvcsw += p->nvcsw + p->cnvcsw; p->parent->cnivcsw += p->nivcsw + p->cnivcsw; + elsa_bank_remove_all(p); sched_exit(p); write_unlock_irq(&tasklist_lock); spin_unlock(&p->proc_lock); diff -uprN -X elsa_import/dontdiff linux-2.6.5/kernel/fork.c linux-2.6.5-elsa/kernel/fork.c --- linux-2.6.5/kernel/fork.c 2004-04-04 05:36:18.000000000 +0200 +++ linux-2.6.5-elsa/kernel/fork.c 2004-04-26 10:35:03.000000000 +0200 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -232,6 +233,13 @@ void __init fork_init(unsigned long memp init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2; + + /* + * We initialize the field of process 0, otherwise it will cause + * an oops in elsa_copy_parent_bank(from, to) with from->pid==0 + * and to->pid==1 + */ + INIT_LIST_HEAD(&(current->bank_head)); } static struct task_struct *dup_task_struct(struct task_struct *orig) @@ -1053,6 +1061,8 @@ struct task_struct *copy_process(unsigne if (p->ptrace & PT_PTRACED) __ptrace_link(p, current->parent); + INIT_LIST_HEAD(&(p->bank_head)); + attach_pid(p, PIDTYPE_PID, p->pid); if (thread_group_leader(p)) { attach_pid(p, PIDTYPE_TGID, p->tgid); @@ -1187,6 +1197,13 @@ long do_fork(unsigned long clone_flags, * COW overhead when the child exec()s afterwards. */ set_need_resched(); + + /* + * Child is in the same BANK as parent. So we copy + * the list of banks from parent (current) to + * child (p) + */ + elsa_copy_parent_bank(current, p); } return pid; } diff -uprN -X elsa_import/dontdiff linux-2.6.5/kernel/Makefile linux-2.6.5-elsa/kernel/Makefile --- linux-2.6.5/kernel/Makefile 2004-04-04 05:36:26.000000000 +0200 +++ linux-2.6.5-elsa/kernel/Makefile 2004-04-26 11:17:22.000000000 +0200 @@ -7,7 +7,7 @@ obj-y = sched.o fork.o exec_domain.o sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o intermodule.o extable.o params.o posix-timers.o \ - kthread.o + kthread.o elsa_bank.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o @@ -21,6 +21,7 @@ obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_IKCONFIG) += configs.o obj-$(CONFIG_IKCONFIG_PROC) += configs.o obj-$(CONFIG_STOP_MACHINE) += stop_machine.o +obj-$(CONFIG_ELSA_ACCT) += elsa_acct.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -uprN -X elsa_import/dontdiff linux-2.6.5/Makefile linux-2.6.5-elsa/Makefile --- linux-2.6.5/Makefile 2004-04-04 05:37:36.000000000 +0200 +++ linux-2.6.5-elsa/Makefile 2004-04-26 10:35:03.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 5 -EXTRAVERSION = +EXTRAVERSION = -elsa NAME=Zonked Quokka # *DOCUMENTATION*