public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Enhanced Linux System Accounting
@ 2004-05-05 13:26 Guillaume Thouvenin
  2004-05-05 18:12 ` Karim Yaghmour
  2004-05-05 20:18 ` Chris Wright
  0 siblings, 2 replies; 4+ messages in thread
From: Guillaume Thouvenin @ 2004-05-05 13:26 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1600 bytes --]

Hello,

    This is a new patch "patch-2.6.5-elsa_1" for 2.6.5 kernel. The patch 
can be downloaded from

http://sourceforge.net/project/showfiles.php?group_id=105806

   I also attach it at the end of this file. The goal of ELSA is to give 
to Linux the same accounting level that already exist on other 
commercial Unix. To achieve this goal we supply a patch that provides 
mechanism to group process together and perform accounting information 
on those groups. The mechanism is very close to PAGG+CSA but I think 
that aims are differents (of course it's open to discussion). As already 
said, we're trying to provide an environment that can support System V 
accounting. Also, we want to think about how to provide a unify 
interface from existing accounting tools and how can we interact with 
other Linux administrative tools like WebMin. Therefore, there are two 
main goals which are:

       o  provide an environment that can support System V accounting
       o  provide a unify interface from existing accounting tools (like
sar) to be used by existing Linux administrative tools (like WebMin)

     This patch is just a beginning and currently it allows to group
process together in a "bank" via /dev/elsacct device using ioctl(). 
Also, it allows to recover accounting informations (taken from BSD 
accounting for the moment) about a "bank".  We also provide a C program 
called elsa_cmd.c that "plays" with ioctl() to manage banks. This 
program can be found at

http://cvs.sourceforge.net/viewcvs.py/elsa/tests/elsa_cmd.c

Any feedbacks, any comments are welcome
Best,

Guillaume



[-- Attachment #2: patch-2.6.5-elsa_1 --]
[-- Type: text/plain, Size: 44010 bytes --]

diff -uprN -X elsa_import/dontdiff linux-2.6.5/drivers/elsacct/bank.c linux-2.6.5-elsa/drivers/elsacct/bank.c
--- linux-2.6.5/drivers/elsacct/bank.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.5-elsa/drivers/elsacct/bank.c	2004-05-05 11:07:06.535625584 +0200
@@ -0,0 +1,657 @@
+/*
+ *  driver/elsacct/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 <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+
+#include <asm/semaphore.h>
+
+#include <linux/bank.h>
+
+ /*********************************************
+ * 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_ELSACCT_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_ELSACCT_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_bank() 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_ELSACCT_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_ELSACCT_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_ELSACCT_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_ELSACCT_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_ELSACCT_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_ELSACCT_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_ELSACCT_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. Before calling this function, we must be
+ * sure that data is not a pointer to NULL.
+ */
+#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_ELSACCT_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, data->process);
+
+	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 *
+ *                                *
+ * The entry is /proc/bankinfo    *
+ *********************************/
+
+/***
+ * 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<process> <process> ...\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,
+};
+
+int bankinfo_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &bankinfo_op);
+}
+
+struct file_operations proc_bankinfo_ops = {
+	.open = bankinfo_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+EXPORT_SYMBOL(proc_bankinfo_ops);
+
+#endif
diff -uprN -X elsa_import/dontdiff linux-2.6.5/drivers/elsacct/elsacct.c linux-2.6.5-elsa/drivers/elsacct/elsacct.c
--- linux-2.6.5/drivers/elsacct/elsacct.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.5-elsa/drivers/elsacct/elsacct.c	2004-05-05 11:02:45.935242864 +0200
@@ -0,0 +1,435 @@
+/*
+ *  driver/elsacct/elsacct.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 <linux/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/times.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/elsacct.h>
+#include <linux/bank.h>
+
+static int elsa_major;
+
+/**
+ *  encode_comp_t - encode an unsigned long into a comp_t
+ *  @value: value to encode
+ *
+ *  This routine has been adopted from the encode_comp_t() function in
+ *  the kern_acct.c file of the FreeBSD operating system. The encoding
+ *  is a 13-bit fraction with a 3-bit (base 8) exponent. 
+ *
+ *  This routine is taken from kernel/acct.c
+ */
+
+#define	MANTSIZE	13	/* 13 bit mantissa. */
+#define	EXPSIZE		3	/* Base 8 (3 bit) exponent. */
+#define	MAXFRACT	((1 << MANTSIZE) - 1)	/* Maximum fractional value. */
+
+typedef __u16 comp_t;
+
+static comp_t encode_comp_t(unsigned long value)
+{
+	int exp, rnd;
+
+	exp = rnd = 0;
+	while (value > MAXFRACT) {
+		rnd = value & (1 << (EXPSIZE - 1));	/* Round up? */
+		value >>= EXPSIZE;	/* Base 8 exponent == 3 bit shift. */
+		exp++;
+	}
+
+	/*
+	 * If we need to round up, do it (and handle overflow correctly).
+	 */
+	if (rnd && (++value > MAXFRACT)) {
+		value >>= EXPSIZE;
+		exp++;
+	}
+
+	/*
+	 * Clean it up and polish it off.
+	 */
+	exp <<= MANTSIZE;	/* Shift the exponent into place */
+	exp += value;		/* and add on the mantissa. */
+	return exp;
+}
+
+/**
+ * do_elsa_acct - Accounting is done here
+ * @info: pointer to accounting informations
+ *
+ * We copy code from BSD accounting
+ */
+void do_elsa_acct(struct elsa_acct_s *info, struct task_struct *p)
+{
+	u64 elapsed;
+
+	/* One more process in the bank */
+	info->eac_ptot++;
+
+	/* elapsed time */
+	elapsed = jiffies_64_to_clock_t(get_jiffies_64() - p->start_time);
+	info->eac_etime += encode_comp_t(elapsed < (unsigned long)-1l ?
+					 (unsigned long)elapsed : (unsigned
+								   long)-1l);
+
+	/* user time and system time */
+	info->eac_utime += encode_comp_t(jiffies_to_clock_t(p->utime));
+	info->eac_stime += encode_comp_t(jiffies_to_clock_t(p->stime));
+
+	/* minor and major page faults */
+	info->eac_minflt += encode_comp_t(p->min_flt);
+	info->eac_majflt += encode_comp_t(p->maj_flt);
+
+	/* Number of swaps */
+	info->eac_swaps += encode_comp_t(p->nswap);
+}
+
+/**
+ * elsa_acct - callback hook to data
+ * @bid: bank identifier
+ * 
+ * Call when a data is destroyed. It does accounting updates.
+ */
+void elsa_acct(int bid, struct task_struct *p)
+{
+	struct elsa_acct_s *info;
+
+	info = (struct elsa_acct_s *)elsa_bank_get_info(bid);
+
+	if (info)
+		do_elsa_acct(info, p);
+	else
+		printk("elsa_acct: error BID == %d\n", bid);
+}
+
+#define display_elsa_info(info) do {                             \
+	printk("\tNumber of Processes : %d\n",info->eac_ptot);   \
+	printk("\tElapsed Time        : %d\n",info->eac_etime);  \
+	printk("\tUser Time           : %d\n",info->eac_utime);  \
+	printk("\tSystem Time         : %d\n",info->eac_stime);  \
+	printk("\tMinor page faults   : %d\n",info->eac_minflt); \
+	printk("\tMajor page faults   : %d\n",info->eac_majflt); \
+	printk("\tNumber of swaps     : %d\n",info->eac_swaps);  \
+} while(0)
+
+/**
+ * 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) {
+		printk("free_elsa_info: ELSA information about bank #%d\n",
+		       bid);
+		display_elsa_info(info);
+		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 */
+		memset(info, 0, sizeof(struct elsa_acct_s));
+		info->eac_bid = bid;
+		/* So, fields are all equals to zero except eac_bid */
+		elsa_bank_set_info(bid, info);
+	} else {
+		printk(KERN_WARNING "Bank #id%d created: info error\n", bid);
+	}
+
+}
+
+ /**************************************************************
+ * functions used to manipulate the device                     *
+ *                                                             *
+ * The enhanced linux system accounting device is /dev/elsacct *
+ * and the major number is dynamically given by OS             *
+ **************************************************************/
+
+/* 
+ * The process context, represented as a typical driver method - ioctl(), must 
+ * use spin_lock_irq() because it knows that interrupts are always enabled while 
+ * executing the device ioctl() method.
+ */
+spinlock_t elsa_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * 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);
+			spin_lock_irq(&elsa_lock);
+			/* critical section */
+			retval = elsa_bank_clean(args->bid);
+			spin_unlock_irq(&elsa_lock);
+		}
+		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 */
+				spin_lock_irq(&elsa_lock);
+				retval = elsa_bank_add(args->bid, p);
+				if (retval > 0)
+					hang_elsa_info(retval);
+				spin_unlock_irq(&elsa_lock);
+			}
+		}
+		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);
+			spin_lock_irq(&elsa_lock);
+			retval = elsa_bank_remove(args->bid, args->pid);
+			spin_unlock_irq(&elsa_lock);
+		}
+		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;
+	struct proc_dir_entry *entry;
+
+	/* 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, &elsa_acct);
+
+#ifdef CONFIG_PROC_FS
+	/* create /proc entry */
+	entry = create_proc_entry("bankinfo", 0, NULL);
+	if (entry)
+		entry->proc_fops = &proc_bankinfo_ops;
+	else
+		return -EIO;
+#endif
+
+	/* 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 <guillaume.thouvenin@bull.net>");
+
+MODULE_LICENSE("GPL");
+
+#else
+
+module_init(elsacct_init);
+
+#endif				/* !(MODULE) */
diff -uprN -X elsa_import/dontdiff linux-2.6.5/drivers/elsacct/Kconfig linux-2.6.5-elsa/drivers/elsacct/Kconfig
--- linux-2.6.5/drivers/elsacct/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.5-elsa/drivers/elsacct/Kconfig	2004-05-05 10:27:50.000000000 +0200
@@ -0,0 +1,52 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+menu "ELSAcct Driver"
+
+config BANK
+	bool "ELSA bank support"
+	depends on EXPERIMENTAL
+	default n
+	---help---
+	  BANK structures are needed if you want to do enhanced 
+	  linux system accounting
+
+	  say Y if you want to use Enhanced Linux Sytem Accounting
+
+config ELSACCT
+	tristate "Enhanced Linux System Accounting"
+	depends on EXPERIMENTAL
+	requires BANK
+	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
+  	  <http://elsa.sourceforge.net>
+
+config ELSACCT_DEBUG
+	bool "ELSA bank debugging support"
+	depends on ELSACCT
+	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.
+
+endmenu
diff -uprN -X elsa_import/dontdiff linux-2.6.5/drivers/elsacct/Makefile linux-2.6.5-elsa/drivers/elsacct/Makefile
--- linux-2.6.5/drivers/elsacct/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.5-elsa/drivers/elsacct/Makefile	2004-05-05 10:15:41.000000000 +0200
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux kernel.
+#
+obj-$(CONFIG_BANK)	+= bank.o
+obj-$(CONFIG_ELSACCT)	+= elsacct.o
diff -uprN -X elsa_import/dontdiff linux-2.6.5/drivers/Kconfig linux-2.6.5-elsa/drivers/Kconfig
--- linux-2.6.5/drivers/Kconfig	2004-04-04 05:38:17.000000000 +0200
+++ linux-2.6.5-elsa/drivers/Kconfig	2004-05-05 08:46:35.000000000 +0200
@@ -4,6 +4,8 @@ menu "Device Drivers"
 
 source "drivers/base/Kconfig"
 
+source "drivers/elsacct/Kconfig"
+
 source "drivers/mtd/Kconfig"
 
 source "drivers/parport/Kconfig"
diff -uprN -X elsa_import/dontdiff linux-2.6.5/drivers/Makefile linux-2.6.5-elsa/drivers/Makefile
--- linux-2.6.5/drivers/Makefile	2004-04-04 05:37:43.000000000 +0200
+++ linux-2.6.5-elsa/drivers/Makefile	2004-05-05 07:46:34.000000000 +0200
@@ -50,3 +50,4 @@ obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-y				+= firmware/
+obj-y				+= elsacct/
diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/linux/bank.h linux-2.6.5-elsa/include/linux/bank.h
--- linux-2.6.5/include/linux/bank.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.5-elsa/include/linux/bank.h	2004-05-05 11:02:56.087699456 +0200
@@ -0,0 +1,141 @@
+/*
+ *  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_BANK_H
+#define __LINUX_BANK_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+
+/***
+ * 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, struct task_struct * p);	/* 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 */
+	int uid;		/* identifier of user that creates the bank */
+	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 */
+};
+
+#ifdef CONFIG_PROC_FS
+extern struct file_operations proc_bankinfo_ops;
+#endif
+
+ /*********************************************
+ * Following functions can be use by a module *
+ * (=> 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) *
+ *****************************************************************************/
+#ifdef CONFIG_BANK
+extern void elsa_copy_parent_bank(struct task_struct *from,
+				  struct task_struct *to);
+extern void elsa_bank_remove_all(struct task_struct *p);
+#else
+#define elsa_copy_parent_bank(a,b) do {} while(0)
+#define elsa_bank_remove_all(a)    do {} while(0)
+#endif				/* !(CONFIG_BANK) */
+
+#endif				/* !(__LINUX_BANK_H) */
diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/linux/elsacct.h linux-2.6.5-elsa/include/linux/elsacct.h
--- linux-2.6.5/include/linux/elsacct.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.5-elsa/include/linux/elsacct.h	2004-05-05 11:02:52.144298944 +0200
@@ -0,0 +1,53 @@
+/*
+ *  include/linux/elsa_acct.h
+ * 
+ *  ELSA - Enhanced Linux System Accounting
+ *  Guillaume Thouvenin - 26/04/2004
+ *      
+ */
+
+#ifndef __LINUX_ELSACCT_H
+#define __LINUX_ELSACCT_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_minflt;		/* Accounting Minor Pagefaults */
+	int eac_majflt;		/* Accounting Major Pagefaults */
+	int eac_swaps;		/* Accounting Number of Swaps */
+};
+
+#endif				/* !(__LINUX_ELSACCT_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-05-04 13:27: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/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-05-05 07:51:31.000000000 +0200
@@ -22,6 +22,7 @@
 #include <linux/profile.h>
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
+#include <linux/bank.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -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-05-05 07:51:52.000000000 +0200
@@ -31,6 +31,7 @@
 #include <linux/futex.h>
 #include <linux/ptrace.h>
 #include <linux/mount.h>
+#include <linux/bank.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -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/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-05-05 11:06:22.767279384 +0200
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 5
-EXTRAVERSION =
+EXTRAVERSION = -elsa
 NAME=Zonked Quokka
 
 # *DOCUMENTATION*



^ permalink raw reply	[flat|nested] 4+ messages in thread
* [PATCH] Enhanced Linux System Accounting
@ 2004-05-12 12:20 Guillaume Thouvenin
  0 siblings, 0 replies; 4+ messages in thread
From: Guillaume Thouvenin @ 2004-05-12 12:20 UTC (permalink / raw)
  To: Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 1106 bytes --]

Hello,

 This is a new patch "patch-2.6.6-elsa" for 2.6.6 kernel. It can be 
downloaded from:
http://sourceforge.net/project/showfiles.php?group_id=105806

  I also attach it at the end of this file. In this patch we rewrite 
functions and we made a clean separation between different parts of ELSA 
(thank you very much to Chris Wright for its usefull comments). This 
patch allows you to test BSD-like accounting for a group of process. 
Informations are dumped in /var/log/bank (need to change that). "BANK" 
can be manipulated via ioctl() and /dev/elsacct. A C program, called 
"elsa_cmd.c", that allows to add/remove process to/from a bank can be 
downloaded from the CVS:
http://cvs.sourceforge.net/viewcvs.py/elsa/tests/

  We need to improve lock between the main structure called "elsa_broot" 
and add new accounting informations. Our goal is to provide an 
environment that can support System V accounting and a unify interface 
from existing accounting tools (like sar) to be used by existing Linux 
administrative tools (like WebMin).

Any feedbacks, any comments are welcome
Best,
Guillaume



[-- Attachment #2: patch-2.6.6-elsa --]
[-- Type: text/plain, Size: 42174 bytes --]

diff -uprN -X elsa_import/dontdiff linux-2.6.6/drivers/elsacct/bank.c linux-2.6.6-elsa/drivers/elsacct/bank.c
--- linux-2.6.6/drivers/elsacct/bank.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-elsa/drivers/elsacct/bank.c	2004-05-12 07:24:41.380161848 +0200
@@ -0,0 +1,607 @@
+/*
+ *  driver/elsacct/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 <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+
+#include <linux/bank.h>
+
+#include <asm/semaphore.h>
+#include <asm/bug.h>
+
+ /*********************************************
+ * structures and macros used to manage banks *
+ *********************************************/
+
+#ifdef CONFIG_BANK_DEBUG
+#define dprintk(format...) printk(format)
+#else
+#define dprintk(format)
+#endif
+
+/* It's the head on the list of banks */
+static struct bank_root elsa_broot = BANK_ROOT_INIT(elsa_broot);
+
+/* semaphore that protect access to bank id */
+static DECLARE_MUTEX(elsa_bid_sem);
+//SPIN_LOCK_UNLOCKED(elsalist_lock);
+
+ /********************************************************************
+ * Following functions can be use by a module (=> they are exported) *
+ ********************************************************************/
+
+/**
+ * elsa_bank_alloc - Allocates a new bank
+ * @fn : callback used when a data or a bank are destroyed
+ * @info : generic information attached to a bank (used for accounting) 
+ *
+ * Allocates a new bank and returns the new created bank.
+ * If an error is encountered NULL is returned.
+ *
+ * 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)
+ *   4) Add it to the list of available bank
+ */
+struct elsa_bank
+*elsa_bank_alloc(int (*fn) (int, struct elsa_bank *, struct elsa_data *),
+		 void *info)
+{
+	struct elsa_bank *b;
+	int bid;
+
+	/* allocate space for the new bank */
+	b = (struct elsa_bank *)kmalloc(sizeof(struct elsa_bank), GFP_KERNEL);
+	if (!b) {
+		printk("elsa_bank_alloc: cannot allocate space\n");
+		return NULL;
+	}
+
+	/* 
+	 * give it an id 
+	 * Currently we only used next_bid field but this mechnism 
+	 * can give problems if we use many banks and the bid go through
+	 * its maximum  
+	 */
+	down(&elsa_bid_sem);
+	bid = elsa_broot.next_bid++;
+	up(&elsa_bid_sem);
+
+	if (bid <= 0) {
+		/* There is no available id == ERROR */
+		kfree(b);
+		printk("elsa_bank_alloc: can not find bank identifier\n");
+		return NULL;
+	} else {
+		b->bid = bid;
+	}
+
+	/* Initialize fields */
+	b->info = info;
+	b->callback = fn;
+	INIT_LIST_HEAD(&(b->data_head));
+
+	/* add the new bank to the list of banks --- NEED LOCK */
+	list_add(&(b->bank_list), &(elsa_broot.bank_head));
+
+	dprintk("elsa_bank_alloc: bank #%d created\n", b->bid);
+
+	return b;
+}
+
+/**
+ * elsa_data_alloc - Allocates a new data
+ * 
+ * Allocates a new data and returns the new created item.
+ * If an error is encountered NULL is returned.
+ *
+ * Here are different steps of the operation
+ *
+ *   1) Allocate space for the new data
+ *   2) Initialize different fields
+ */
+struct elsa_data *elsa_data_alloc(void)
+{
+	struct elsa_data *d;
+
+	/* allocate space for the new data */
+	d = (struct elsa_data *)kmalloc(sizeof(struct elsa_data), GFP_KERNEL);
+	if (!d) {
+		printk("elsa_data_alloc: cannot allocate space\n");
+		return NULL;
+	}
+
+	/* Initialize fields */
+	d->bid = 0;
+	d->process = NULL;
+	INIT_LIST_HEAD(&(d->data_list));
+	INIT_LIST_HEAD(&(d->bank_list));
+
+	return d;
+}
+
+/**
+ * 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.
+ *
+ * Here are different steps of the operation
+ *
+ *   1) Write accounting information
+ *   2) Remove it from the list of banks
+ *   3) Free space used by bank
+ */
+void elsa_bank_free(struct elsa_bank *bank)
+{
+	BUG_ON(bank == NULL);
+	BUG_ON(!list_empty(&bank->data_head));
+
+	/* Before deleting the bank, we can do some action */
+	/* callback */
+	if (bank->callback) {
+		(bank->callback) (ELSA_BANK_CALLBACK, bank, NULL);
+	}
+
+	/* remove bank from the bank's list */
+	list_del(&(bank->bank_list));
+	dprintk("elsa_bank_free: bank #%d removed from the list\n", bank->bid);
+	kfree(bank);
+}
+
+/**
+ * elsa_data_free - Free data
+ * @data: data to be removed
+ * 
+ * Frees memory space used by data. 
+ */
+void elsa_data_free(struct elsa_data *data)
+{
+	struct elsa_bank *b = NULL;
+
+	BUG_ON(data == NULL);
+
+	/*
+	 * if data->bid is equal to 0, it means that an error occured between
+	 * data's allocation and data's addition in a bank. So, it isn't inserted
+	 * in any list and there is no need to call the "callback"
+	 */
+	if (data->bid != 0) {
+		/* callback, we are in the child so callback code */
+		b = elsa_get_bank(data->bid);
+		if (b && b->callback) {
+			(b->callback) (ELSA_DATA_CALLBACK, b, data);
+		}
+
+		list_del(&data->data_list);
+
+		/* Need access to head_list in task_struct */
+		write_lock_irq(&tasklist_lock);
+		list_del(&data->bank_list);
+		write_unlock_irq(&tasklist_lock);
+
+		dprintk
+		    ("elsa_data_free: process #%d removed from the bank#%d\n",
+		     data->process->pid, b->bid);
+	}
+
+	kfree(data);
+}
+
+/**
+ * elsa_bank_add - Add a process to a given bank
+ * @b  : pointer to a bank 
+ * @p  : pointer to a process
+ *
+ * add a data to a bank by setting lists. Other fields are unchanged
+ *
+ * If an error is encountered, a negative value is returned. 
+ * It can not return 0.
+ *
+ * Here are steps to perform
+ *  
+ *   1) Check arguments
+ *   2) Check if process is already in the bank
+ *   3) Initialize its fields
+ *   4) Return BID
+ */
+int elsa_bank_add(struct elsa_bank *b, struct elsa_data *d)
+{
+	if (!b || !d || !(d->process)) {
+		dprintk("elsa_bank_add: Wrong parameters\n");
+		return -EINVAL;
+	}
+
+	/* Bank ID cannot be equal to 0 */
+	BUG_ON(b->bid == 0);
+
+	/* check if process is already present */
+	if (elsa_process_present(d->process, b))
+		/* Process already in the bank, so we can not add it */
+		return -EPERM;
+
+	/* Set BID */
+	d->bid = b->bid;
+
+	/* Add data in the list of bank's data */
+	list_add(&(d->data_list), &(b->data_head));
+
+	/* Add data in the list of process's bank */
+	write_lock_irq(&tasklist_lock);
+	list_add(&(d->bank_list), &(d->process->bank_head));
+	write_unlock_irq(&tasklist_lock);
+
+	dprintk("elsa_bank_add: Add process #%d to bank #%d\n", d->process->pid,
+		b->bid);
+
+	return b->bid;
+}
+
+/**
+ * elsa_bank_remove - Remove a process to a given bank
+ * @b: pointer to the bank
+ * @d: pointer to the process
+ *
+ * Removes a given process from a given bank. 
+ * Return 0 if succedeed, negative value otherwise
+ */
+int elsa_bank_remove(struct elsa_data *d)
+{
+	int b_empty = 0;
+	struct elsa_bank *b = NULL;	/*  Used if d is the last 
+					   item of the bank */
+
+	if (!d)
+		return -EINVAL;
+
+	/* bank will be empty if d is the last item in the bank */
+	if (d->data_list.next == d->data_list.prev) {
+		b_empty = 1;
+		b = elsa_get_bank(d->bid);
+	}
+
+	/* kfree memory */
+	elsa_data_free(d);
+
+	/* 
+	 * We must free bank after data otherwise we will miss 
+	 * accounting informations 
+	 */
+	if (b_empty)
+		elsa_bank_free(b);
+
+	return 0;
+}
+
+/**
+ * elsa_bank_clean - Removes all datas in a given bank
+ * @b: pointer to the bank to be removed
+ *
+ * Removes data found in a bank given as paramater. It go through the
+ * list, removes link and free space occupied by the data.
+ * Return 0 if succedeed, negative value otherwise
+ */
+int elsa_bank_clean(struct elsa_bank *b)
+{
+	if (!b) {
+		/* bank doesn't exist */
+		dprintk("elsa_bank_clean: bank doesn't exist\n");
+		return -EAGAIN;
+	}
+
+	/* release all datas and remove the bank */
+	while (!list_empty(&(b->data_head))) {
+		/* get pointer to the first element in the list */
+		struct elsa_data *d = list_entry(b->data_head.next,
+						 struct elsa_data, data_list);
+		elsa_data_free(d);
+	}
+
+	elsa_bank_free(b);
+
+	return 0;
+}
+
+/**
+ * elsa_process_remove - Remove a process from all banks that it belongs
+ * @p: pointer to the process to be removed
+ *
+ * Removes process from all banks
+ * Return 0 if succedeed, negative value otherwise
+ */
+int elsa_process_remove(struct task_struct *p)
+{
+
+	if (!p) {
+		/* bank doesn't exist */
+		dprintk("elsa_process_remove: process doesn't exist\n");
+		return -EAGAIN;
+	}
+
+	/* release all datas and remove the bank */
+	while (!list_empty(&(p->bank_head))) {
+		/* get pointer to the first element in the list */
+		struct elsa_data *d = list_entry(p->bank_head.next,
+						 struct elsa_data, bank_list);
+		elsa_bank_remove(d);
+	}
+
+	return 0;
+}
+
+/**
+ * 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
+ */
+struct elsa_bank *elsa_get_bank(unsigned int bid)
+{
+	struct list_head *entry;
+
+	list_for_each(entry, &(elsa_broot.bank_head)) {
+		struct elsa_bank *b =
+		    list_entry(entry, struct elsa_bank, bank_list);
+		if (b->bid == bid)
+			return b;
+	}
+
+	return NULL;
+}
+
+/**
+ * elsa_get_data - Returns a pointer to the container of a 
+ *                 given pid in a given bank.
+ * @pid: The identifier of the process
+ * 
+ * Find the data that holds process #PID in a given bank. If
+ * not found, NULL is returned.
+ */
+struct elsa_data *elsa_get_data(unsigned int pid, unsigned int bid)
+{
+	struct list_head *entry;
+	struct task_struct *p;
+
+	read_lock(&tasklist_lock);
+	p = find_task_by_pid(pid);
+	read_unlock(&tasklist_lock);
+
+	list_for_each(entry, &(p->bank_head)) {
+		struct elsa_data *d =
+		    list_entry(entry, struct elsa_data, bank_list);
+		if (d->bid == bid)
+			/* Got it */
+			return d;
+	}
+
+	return NULL;
+}
+
+/**
+ * elsa_process_present - Returns 1 if process is in the bank
+ * @p: the process identifier to look for
+ * @b: the bank in which we must look.
+ * 
+ * Return 1 if process is present in a bank, 0 otherwise
+ */
+int elsa_process_present(struct task_struct *p, struct elsa_bank *b)
+{
+	struct list_head *entry;
+
+	list_for_each(entry, &(b->data_head)) {
+		struct elsa_data *d =
+		    list_entry(entry, struct elsa_data, data_list);
+		if (d->process == p) {
+			/* Found it */
+			return 1;
+		}
+	}
+
+	/* Process not found in b */
+	return 0;
+}
+
+/* memory management */
+EXPORT_SYMBOL(elsa_bank_alloc);
+EXPORT_SYMBOL(elsa_data_alloc);
+EXPORT_SYMBOL(elsa_bank_free);
+EXPORT_SYMBOL(elsa_data_free);
+
+/* data manipulation */
+EXPORT_SYMBOL(elsa_bank_add);
+EXPORT_SYMBOL(elsa_bank_remove);
+EXPORT_SYMBOL(elsa_bank_clean);
+EXPORT_SYMBOL(elsa_process_remove);
+
+/* get informations */
+EXPORT_SYMBOL(elsa_get_bank);
+EXPORT_SYMBOL(elsa_get_data);
+EXPORT_SYMBOL(elsa_process_present);
+
+ /*****************************************************************************
+ * Following functions are called from kernel function.                       *
+ *   elsa_copy_parent_bank() is used when child is created (kernel/fork.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 list_head *entry;
+
+	/* 
+	 * First, initialize to->bank_head otherwise, if 
+	 * from->bank_head is NULL it won't be initialize
+	 */
+	write_lock_irq(&tasklist_lock);
+	INIT_LIST_HEAD(&(to->bank_head));
+	write_unlock_irq(&tasklist_lock);
+
+	list_for_each(entry, &(from->bank_head)) {
+		struct elsa_bank *b;
+		struct elsa_data *d_from;
+		struct elsa_data *d_to;
+
+		dprintk("elsa_copy_parent_bank: from pid#%d to pid#%d\n",
+			from->pid, to->pid);
+
+		d_from = list_entry(entry, struct elsa_data, bank_list);
+		if (!d_from)
+			return;
+
+		/* allocat space to new data */
+		d_to = elsa_data_alloc();
+		if (!d_to) {
+			printk("elsa_copy_parent_bank: Cannot create data\n");
+			return;
+		}
+
+		d_to->bid = d_from->bid;
+		d_to->process = to;
+
+		/* d_to->process is set so we can call elsa_bank_add */
+		b = elsa_get_bank(d_from->bid);
+		if (!b) {
+			elsa_data_free(d_to);
+			printk
+			    ("elsa_copy_parent_bank: Destination not found\n");
+			return;
+		}
+
+		if (b->bid != elsa_bank_add(b, d_to)) {
+			elsa_data_free(d_to);
+			printk("elsa_copy_parent_bank: Copy error\n");
+			return;
+		}
+	}
+}
+
+ /*********************************
+ * functions used to manage /proc *
+ *                                *
+ * The entry is /proc/bankinfo    *
+ *********************************/
+
+/***
+ * 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<process> <process> ...\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, 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 *bank = v;
+
+	++*pos;
+	return bank->bank_list.next == &elsa_broot.bank_head ? NULL :
+	    list_entry(bank->bank_list.next, struct elsa_bank, bank_list);
+}
+
+static int show_bankinfo(struct seq_file *m, void *v)
+{
+	struct elsa_bank *bank = v;
+	struct elsa_data *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,
+};
+
+int bankinfo_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &bankinfo_op);
+}
+
+struct file_operations proc_bankinfo_ops = {
+	.open = bankinfo_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+EXPORT_SYMBOL(proc_bankinfo_ops);
+
+#endif
diff -uprN -X elsa_import/dontdiff linux-2.6.6/drivers/elsacct/elsacct.c linux-2.6.6-elsa/drivers/elsacct/elsacct.c
--- linux-2.6.6/drivers/elsacct/elsacct.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-elsa/drivers/elsacct/elsacct.c	2004-05-12 07:24:41.389160480 +0200
@@ -0,0 +1,438 @@
+/*
+ *  driver/elsacct/elsacct.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 <linux/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/times.h>
+
+#include <linux/elsacct.h>
+#include <linux/bank.h>
+
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_ELSACCT_DEBUG
+#define dprintk(format...) printk(format)
+#else
+#define dprintk(format...)
+#endif
+
+static int elsa_major;
+static struct elsa_acct acct_info = ELSA_ACCT_INIT;
+
+/**
+ *  encode_comp_t - encode an unsigned long into a comp_t
+ *  @value: value to encode
+ *
+ *  This routine has been adopted from the encode_comp_t() function in
+ *  the kern_acct.c file of the FreeBSD operating system. The encoding
+ *  is a 13-bit fraction with a 3-bit (base 8) exponent. 
+ *
+ *  This routine is taken from kernel/acct.c
+ */
+#define	MANTSIZE	13	/* 13 bit mantissa. */
+#define	EXPSIZE		3	/* Base 8 (3 bit) exponent. */
+#define	MAXFRACT	((1 << MANTSIZE) - 1)	/* Maximum fractional value. */
+
+typedef __u16 comp_t;
+
+static comp_t encode_comp_t(unsigned long value)
+{
+	int exp, rnd;
+
+	exp = rnd = 0;
+	while (value > MAXFRACT) {
+		rnd = value & (1 << (EXPSIZE - 1));	/* Round up? */
+		value >>= EXPSIZE;	/* Base 8 exponent == 3 bit shift. */
+		exp++;
+	}
+
+	/*
+	 * If we need to round up, do it (and handle overflow correctly).
+	 */
+	if (rnd && (++value > MAXFRACT)) {
+		value >>= EXPSIZE;
+		exp++;
+	}
+
+	/*
+	 * Clean it up and polish it off.
+	 */
+	exp <<= MANTSIZE;	/* Shift the exponent into place */
+	exp += value;		/* and add on the mantissa. */
+	return exp;
+}
+
+ /**************************
+ * Accounting is done here *
+ **************************/
+/*
+ * It's just for testing (Can not choose file)
+ */
+/**
+ * do_elsacct_data - Update accounting information when bank is removed
+ * @b: pointer to bank's data
+ *
+ * We copy code from BSD accounting. It's just to test accounting
+ * Result is written in a file (you can not choose it for now).
+ * It returns 0 if succeded, negative value otherwise
+ */
+static int do_elsacct_bank(struct elsa_bank *b)
+{
+	struct elsa_acct *info = (struct elsa_acct *)b->info;
+	struct file *file = NULL;
+	mm_segment_t old_fs;
+
+	if (!info)
+		return -EINVAL;
+
+	/* Set bank ID */
+	info->eac_bid = b->bid;
+
+	/* Open file where accounting information will be written */
+	file = filp_open(ELSACCT_FILE, O_CREAT | O_WRONLY | O_APPEND, 0666);
+
+	if (IS_ERR(file)) {
+		return (PTR_ERR(file));
+	}
+
+	if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
+		filp_close(file, NULL);
+		return (-EACCES);
+	}
+
+	if (!file->f_op->write) {
+		filp_close(file, NULL);
+		return (-EIO);
+	}
+
+	/*
+	 * Kernel segment override to datasegment and write it
+	 * to the accounting file. 
+	 */
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	file->f_op->write(file, (char *)info, sizeof(struct elsa_acct),
+			  &file->f_pos);
+
+	set_fs(old_fs);
+
+	filp_close(file, NULL);
+	return 0;
+}
+
+/**
+ * do_elsacct_data - Update accounting information when data is removed
+ * @b: pointer to bank's data
+ * @d: pointer to the data
+ *
+ * We copy code from BSD accounting. It's just to test accounting
+ * It returns 0 if succeded, negative value otherwise
+ */
+static int do_elsacct_data(struct elsa_bank *b, struct elsa_data *d)
+{
+	u64 elapsed;
+	struct elsa_acct *info = (struct elsa_acct *)b->info;
+	struct task_struct *p = d->process;
+
+	if (!info)
+		return -EINVAL;
+
+	/* One more process in the bank */
+	info->eac_ptot++;
+
+	/* elapsed time */
+	elapsed = jiffies_64_to_clock_t(get_jiffies_64() - p->start_time);
+	info->eac_etime += encode_comp_t(elapsed < (unsigned long)-1l ?
+					 (unsigned long)elapsed : (unsigned
+								   long)-1l);
+
+	/* user time and system time */
+	info->eac_utime += encode_comp_t(jiffies_to_clock_t(p->utime));
+	info->eac_stime += encode_comp_t(jiffies_to_clock_t(p->stime));
+
+	/* minor and major page faults */
+	info->eac_minflt += encode_comp_t(p->min_flt);
+	info->eac_majflt += encode_comp_t(p->maj_flt);
+
+	return 0;
+}
+
+int do_elsacct(int opcode, struct elsa_bank *b, struct elsa_data *d)
+{
+	int retval = 0;
+
+	switch (opcode) {
+	case ELSA_BANK_CALLBACK:
+		BUG_ON(b == NULL);
+		retval = do_elsacct_bank(b);
+		break;
+	case ELSA_DATA_CALLBACK:
+		BUG_ON(b == NULL);
+		BUG_ON(d == NULL);
+		retval = do_elsacct_data(b, d);
+		break;
+	default:
+		printk("do_elsacct: unknown opcode\n");
+		retval = -ENOIOCTLCMD;
+		break;
+	}
+
+	return retval;
+}
+
+ /**************************************************************
+ * functions used to manipulate the device                     *
+ *                                                             *
+ * The enhanced linux system accounting device is /dev/elsacct *
+ * and the major number is dynamically given by OS             *
+ **************************************************************/
+
+/* 
+ * The process context, represented as a typical driver method - ioctl(), must 
+ * use spin_lock_irq() because it knows that interrupts are always enabled while 
+ * executing the device ioctl() method.
+ */
+spinlock_t elsa_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * elsacct_ioctl - issue a device specific command
+ * @inode: pointer to inode structure
+ * @file : file pointer
+ * @cmd  : specific command to perform.
+ * @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_ioctl_args args;
+	struct task_struct *p;
+	struct elsa_bank *b;
+	struct elsa_data *d;
+
+	/* Recover ioctl parameters */
+	if (copy_from_user(&args, (struct elsa_ioctl_args *)arg,
+			   sizeof(struct elsa_ioctl_args)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case ELSACCT_BANK_REMOVE:
+		/*
+		 * To remove a data from a bank, we need to:
+		 *     1) if #BID == 0
+		 *            get pointer to process
+		 *            remove from all banks that it belongs
+		 *        else
+		 *            get pointer to data
+		 *            remove from bank #BID
+		 *        endif
+		 */
+		if (args.bid == 0) {
+			read_lock(&tasklist_lock);
+			p = find_task_by_pid(args.pid);
+			read_unlock(&tasklist_lock);
+			if (!p) {
+				dprintk("elsacct_ioct: process #%d not found\n",
+					args.pid);
+				return -EAGAIN;
+			}
+
+			spin_lock_irq(&elsa_lock);
+			retval = elsa_process_remove(p);
+			spin_unlock_irq(&elsa_lock);
+		} else {
+
+			d = elsa_get_data(args.pid, args.bid);
+			if (!d) {
+				dprintk("elsacct_ioct: data not found\n");
+				return -EAGAIN;
+			}
+
+			spin_lock_irq(&elsa_lock);
+			retval = elsa_bank_remove(d);
+			spin_unlock_irq(&elsa_lock);
+		}
+		break;
+
+	case ELSACCT_BANK_CLEAN:
+		/*
+		 * To clean a bank (remove all data), we need to:
+		 *     1) Get pointer to the bank
+		 *     2) Remove it
+		 */
+		b = elsa_get_bank(args.bid);
+		if (!b) {
+			dprintk("elsacct_ioct: BANK not found\n");
+			return -EAGAIN;
+		}
+
+		spin_lock_irq(&elsa_lock);
+		retval = elsa_bank_clean(b);
+		spin_unlock_irq(&elsa_lock);
+		break;
+
+	case ELSACCT_BANK_ADD:
+		/*
+		 * To add a process to a bank we need to perform 
+		 * following actions:
+		 *     1) Allocate memory space to data (container)
+		 *     2) Update process in data field
+		 *     3) If #BID == 0
+		 *          create a new bank;
+		 *        else
+		 *          get pointer to bank #BID
+		 *     4) Add the container to the bank
+		 */
+		d = elsa_data_alloc();
+		if (!d)
+			return -ENOMEM;
+
+		/* We need the pointer to task_struct */
+		read_lock(&tasklist_lock);
+		p = find_task_by_pid(args.pid);
+		read_unlock(&tasklist_lock);
+		if (!p) {
+			dprintk("elsacct_ioct: PID#%d not found\n", args.pid);
+			/* Don't forget to release memory */
+			elsa_data_free(d);
+			return -EAGAIN;
+		}
+		d->process = p;
+
+		if (args.bid == 0)
+			b = elsa_bank_alloc(&do_elsacct, &acct_info);
+		else
+			b = elsa_get_bank(args.bid);
+
+		if (!b) {
+			dprintk("elsacct_ioct: BID#%d not found\n", args.bid);
+			/* Don't forget to release memory */
+			elsa_data_free(d);
+			return -EAGAIN;
+		}
+
+		spin_lock_irq(&elsa_lock);
+		retval = elsa_bank_add(b, d);
+		spin_unlock_irq(&elsa_lock);
+		break;
+
+	default:
+		dprintk(KERN_WARNING
+			"elsacct_ioctl: 0x%x unsupported ioctl command\n", cmd);
+		retval = -ENOIOCTLCMD;
+	};
+
+	return retval;
+}
+
+struct file_operations elsa_fops = {
+	.owner = THIS_MODULE,
+	.ioctl = elsacct_ioctl,
+};
+
+/**
+ * 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;
+	struct proc_dir_entry *entry;
+
+	/* register character device with a dynamic major number */
+	elsa_major = register_chrdev(0, "elsacct", &elsa_fops);
+	if (!elsa_major) {
+		dprintk(KERN_WARNING
+			"elsacct_init: can't get major %d\n", elsa_major);
+		return -EIO;
+	}
+
+	/* 
+	 * To get the major number we use a script that parse /proc/devices
+	 * and get the correct major number. We don't use elsa_major except
+	 * to test if the device is registered.
+	 */
+	dprintk(KERN_INFO "ELSACCT: device driver is recorded\n");
+	/*
+	 * From here, dev is registered. Thus, if there is a problem
+	 * we must unregister the device.
+	 */
+
+#ifdef CONFIG_PROC_FS
+	/* create /proc entry */
+	entry = create_proc_entry("bankinfo", 0, NULL);
+	if (entry) {
+		entry->proc_fops = &proc_bankinfo_ops;
+	} else {
+		unregister_chrdev(elsa_major, "elsacct");
+		return -EIO;
+	}
+#endif
+
+	/* succeed */
+	return retval;
+}
+
+ /************************
+ * 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)
+{
+	dprintk(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"))
+		dprintk(KERN_WARNING
+			"elsacct_cleanup: cannot unregister blkdev\n");
+	else
+		dprintk(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 <guillaume.thouvenin@bull.net>");
+
+MODULE_LICENSE("GPL");
diff -uprN -X elsa_import/dontdiff linux-2.6.6/drivers/elsacct/Kconfig linux-2.6.6-elsa/drivers/elsacct/Kconfig
--- linux-2.6.6/drivers/elsacct/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-elsa/drivers/elsacct/Kconfig	2004-05-11 14:19:56.000000000 +0200
@@ -0,0 +1,61 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+menu "ELSAcct Driver"
+
+config BANK
+	bool "ELSA bank support"
+	depends on EXPERIMENTAL
+	default n
+	---help---
+	  BANK structures are needed if you want to do enhanced 
+	  linux system accounting
+
+	  say Y if you want to use Enhanced Linux Sytem Accounting
+
+config BANK_DEBUG
+	bool "ELSA bank debugging support"
+	depends on BANK
+	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 ELSACCT
+	tristate "Enhanced Linux System Accounting"
+	depends on EXPERIMENTAL
+	requires BANK
+	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
+  	  <http://elsa.sourceforge.net>
+
+config ELSACCT_DEBUG
+	bool "ELSA accounting debugging support"
+	depends on ELSACCT
+	default n
+	---help---
+          This option allows you to enable debugging output when using 
+	  enhanced linux system accounting. Informations are sent to the 
+	  console.
+
+endmenu
diff -uprN -X elsa_import/dontdiff linux-2.6.6/drivers/elsacct/Makefile linux-2.6.6-elsa/drivers/elsacct/Makefile
--- linux-2.6.6/drivers/elsacct/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-elsa/drivers/elsacct/Makefile	2004-05-06 12:39:50.000000000 +0200
@@ -0,0 +1,5 @@
+#
+# Makefile for the Enhanced Linux System Accounting
+#
+obj-$(CONFIG_BANK)	+= bank.o
+obj-$(CONFIG_ELSACCT)	+= elsacct.o
diff -uprN -X elsa_import/dontdiff linux-2.6.6/drivers/Kconfig linux-2.6.6-elsa/drivers/Kconfig
--- linux-2.6.6/drivers/Kconfig	2004-05-10 04:33:20.000000000 +0200
+++ linux-2.6.6-elsa/drivers/Kconfig	2004-05-10 09:45:43.000000000 +0200
@@ -4,6 +4,8 @@ menu "Device Drivers"
 
 source "drivers/base/Kconfig"
 
+source "drivers/elsacct/Kconfig"
+
 source "drivers/mtd/Kconfig"
 
 source "drivers/parport/Kconfig"
diff -uprN -X elsa_import/dontdiff linux-2.6.6/drivers/Makefile linux-2.6.6-elsa/drivers/Makefile
--- linux-2.6.6/drivers/Makefile	2004-05-10 04:33:13.000000000 +0200
+++ linux-2.6.6-elsa/drivers/Makefile	2004-05-10 09:46:10.000000000 +0200
@@ -50,3 +50,4 @@ obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-y				+= firmware/
+obj-y				+= elsacct/
diff -uprN -X elsa_import/dontdiff linux-2.6.6/include/linux/bank.h linux-2.6.6-elsa/include/linux/bank.h
--- linux-2.6.6/include/linux/bank.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-elsa/include/linux/bank.h	2004-05-12 07:24:35.766015328 +0200
@@ -0,0 +1,164 @@
+/*
+ *  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:
+ * 
+ *                              BANK #1           BANK #2  
+ *                             elsa_bank       elsa_bank  
+ *         elsa_broot         -----------       ----------- 
+ *          bank_root        |  bid = 1  |     |  bid = 2  |
+ *       --------------      |-----------|     |-----------|
+ *      | next_bid = 3 |     |   info    |     |   info    |
+ *      |--------------|     |-----------|     |-----------|
+ *      | freebid_head |     | callback  |     | callback  |
+ *      |--------------|     |-----------|     |-----------|
+ *      | bank_head    |<===>| bank_list |<===>| bank_list |<===>...
+ *       --------------      |-----------|     |-----------|
+ *                           | data_head |     | data_head |<===>...
+ *                            ----------        -----------
+ *                                   ^ ^
+ *                                   | |
+ *                                   |  ================= 
+ *    PROCESS            DATA #1     |     DATA #2       |  
+ *  task_struct         elsa_data    |    elsa_data      |
+ *   ---------         -----------   |   -----------     |
+ *  |         |       |  bid = 1  |  |  |  bid = 1  |    |
+ *  |         |       |-----------|  |  |-----------|    |
+ *  |         |<------|  process  |  |  |  process  |    |
+ *  |         |       |-----------|  |  |-----------|    |
+ *  |         |       | data_list |<=   | data_list |<===
+ * ...       ...      |           |<===>|           |
+ *  |---------|       |-----------|     |-----------|
+ *  |bank_head|<=====>| bank_list |     | bank_list |
+ *   ---------         -----------       -----------
+ *
+ *
+ * Field "bank_list" in the elsa_data is used to know which are banks with
+ * a given process. Structure "task_struc" is modified to use this field.
+ */
+
+#ifndef __LINUX_BANK_H
+#define __LINUX_BANK_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#define ELSA_BANK_CALLBACK 0
+#define ELSA_DATA_CALLBACK 1
+
+extern rwlock_t elsalist_lock;
+
+/***
+ * Internal structures
+ ***/
+
+struct bank_root {
+	/* 
+	 * We need to protect ID by a semaphore since it must be
+	 * a unique number. We can't have to bank with same ID
+	 */
+	unsigned int next_bid;	/* next available bank identifier */
+	struct list_head freebid_head;	/* a list of free bank identifier - Not used yet */
+	struct list_head bank_head;	/* head of the list of bank */
+};
+
+#define BANK_ROOT_INIT(root) \
+{							     \
+	.next_bid 	= 1,                                 \
+	.freebid_head 	= LIST_HEAD_INIT(root.freebid_head), \
+	.bank_head	= LIST_HEAD_INIT(root.bank_head),    \
+}
+
+struct elsa_freebid {
+	int bid;
+	struct list_head bid_list;
+};
+
+struct elsa_data;		/* Needed in struct elsa_bank */
+
+struct elsa_bank {
+	int bid;		/* the bank identifier */
+	void *info;		/* allow to hang information to banks */
+	int (*callback) (int, struct elsa_bank *, struct elsa_data *);	/* callback */
+	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 {
+	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 */
+};
+
+#ifdef CONFIG_PROC_FS
+extern struct file_operations proc_bankinfo_ops;
+#endif
+
+ /*********************************************
+ * Following functions can be use by a module *
+ * (=> they are exported)                     *
+ *********************************************/
+
+/* allocate memory space: (call to kmalloc) */
+struct elsa_bank
+*elsa_bank_alloc(int (*fn) (int, struct elsa_bank *, struct elsa_data *),
+		 void *);
+struct elsa_data *elsa_data_alloc(void);
+void elsa_bank_free(struct elsa_bank *bank);
+void elsa_data_free(struct elsa_data *data);
+
+/* 
+ * manipulate datas:
+ * Memory space can be released (call to kfree) in the last three
+ * functions.
+ */
+int elsa_bank_add(struct elsa_bank *b, struct elsa_data *d);
+int elsa_bank_remove(struct elsa_data *d);
+int elsa_bank_clean(struct elsa_bank *b);
+/* elsa_process_remove() is used by the kernel so it is declared below */
+
+/* get information */
+struct elsa_bank *elsa_get_bank(unsigned int bid);
+struct elsa_data *elsa_get_data(unsigned int pid, unsigned int bid);
+int elsa_process_present(struct task_struct *p, struct elsa_bank *b);
+
+ /*****************************************************************************
+ * Following functions are called from kernel function.                       *
+ *   elsa_copy_parent() is used when child is created (kernel/fork.c)         *
+ *   elsa_process_remove() is used when a process terminates (kernel/exit.c) *
+ *****************************************************************************/
+#ifdef CONFIG_BANK
+extern void elsa_copy_parent_bank(struct task_struct *from,
+				  struct task_struct *to);
+extern int elsa_process_remove(struct task_struct *p);
+#else
+#define elsa_copy_parent_bank(a,b) do {} while(0)
+#define elsa_bank_remove_all(a)    do {} while(0)
+#endif				/* !(CONFIG_BANK) */
+
+#endif				/* !(__LINUX_BANK_H) */
diff -uprN -X elsa_import/dontdiff linux-2.6.6/include/linux/elsacct.h linux-2.6.6-elsa/include/linux/elsacct.h
--- linux-2.6.6/include/linux/elsacct.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-elsa/include/linux/elsacct.h	2004-05-12 07:24:32.067577576 +0200
@@ -0,0 +1,55 @@
+/*
+ *  include/linux/elsa_acct.h
+ * 
+ *  ELSA - Enhanced Linux System Accounting
+ *  Guillaume Thouvenin - 26/04/2004
+ *      
+ */
+
+#ifndef __LINUX_ELSACCT_H
+#define __LINUX_ELSACCT_H
+
+/* IOCTL numbers */
+#define ELSACCT_MAGIC		0x3538
+
+#define ELSACCT_BANK_REMOVE	0x353801	/* Remove one data from a bank, 
+						 * if #BID == 0 remove from all banks */
+#define ELSACCT_BANK_CLEAN	0x353802	/* Remove all data from a bank */
+#define ELSACCT_BANK_ADD	0x353803	/* Add a process to a bank,
+						 * if #BID == 0 create the bank */
+
+/* Currently, informations are stored in the same file and we cannot chose it */
+#define ELSACCT_FILE	"/var/log/bank"
+
+struct elsa_ioctl_args {
+	unsigned int bid;	/* bank identifier */
+	unsigned int pid;	/* process identifier */
+};
+
+/* 
+ * Currently, we take as a starting point the BSD-style 
+ * process accounting and we write values into dmesg
+ * buffer. (of course we need to change this) 
+ */
+struct elsa_acct {
+	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_minflt;		/* Accounting Minor Pagefaults */
+	int eac_majflt;		/* Accounting Major Pagefaults */
+};
+
+#define ELSA_ACCT_INIT 		\
+{ 				\
+	.eac_bid 	= 0,	\
+	.eac_ptot	= 0,	\
+	.eac_utime	= 0,	\
+	.eac_stime	= 0,	\
+	.eac_etime	= 0,	\
+	.eac_minflt 	= 0,	\
+	.eac_majflt 	= 0,	\
+}
+
+#endif				/* !(__LINUX_ELSACCT_H) */
diff -uprN -X elsa_import/dontdiff linux-2.6.6/include/linux/init_task.h linux-2.6.6-elsa/include/linux/init_task.h
--- linux-2.6.6/include/linux/init_task.h	2004-05-10 04:32:00.000000000 +0200
+++ linux-2.6.6-elsa/include/linux/init_task.h	2004-05-10 09:48:18.000000000 +0200
@@ -112,6 +112,7 @@ extern struct group_info init_groups;
 	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
+	.bank_head	= LIST_HEAD_INIT(tsk.bank_head),		\
 }
 
 
diff -uprN -X elsa_import/dontdiff linux-2.6.6/include/linux/sched.h linux-2.6.6-elsa/include/linux/sched.h
--- linux-2.6.6/include/linux/sched.h	2004-05-10 04:32:00.000000000 +0200
+++ linux-2.6.6-elsa/include/linux/sched.h	2004-05-10 09:50:04.000000000 +0200
@@ -504,6 +504,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.6/kernel/exit.c linux-2.6.6-elsa/kernel/exit.c
--- linux-2.6.6/kernel/exit.c	2004-05-10 04:33:19.000000000 +0200
+++ linux-2.6.6-elsa/kernel/exit.c	2004-05-10 09:55:57.000000000 +0200
@@ -59,6 +59,7 @@ repeat: 
 	atomic_dec(&p->user->processes);
 	spin_lock(&p->proc_lock);
 	proc_dentry = proc_pid_unhash(p);
+	elsa_process_remove(p);
 	write_lock_irq(&tasklist_lock);
 	if (unlikely(p->ptrace))
 		__ptrace_unlink(p);
diff -uprN -X elsa_import/dontdiff linux-2.6.6/kernel/fork.c linux-2.6.6-elsa/kernel/fork.c
--- linux-2.6.6/kernel/fork.c	2004-05-10 04:32:00.000000000 +0200
+++ linux-2.6.6-elsa/kernel/fork.c	2004-05-10 09:57:36.000000000 +0200
@@ -1011,6 +1011,19 @@ struct task_struct *copy_process(unsigne
 	INIT_LIST_HEAD(&p->ptrace_children);
 	INIT_LIST_HEAD(&p->ptrace_list);
 
+        /*
+         * Child is in the same BANK as parent. So we copy the list of banks
+         * from current to p. We can not just counting reference on the structure
+         * because the may evoluate in differents way. I think it's easier to
+         * do like this but maybe I'm wrong... -- guillaume
+         *
+         * We put that call outside lock_irq because elsa_copy_parent_bank
+         * uses kmalloc(GFP_KERNEL). Therefore, as we modify task_struct,
+         * we manage lock_irq ourselves. -- guillaume
+         *
+         */
+        elsa_copy_parent_bank(current, p);
+	
 	/* Need tasklist lock for parent etc handling! */
 	write_lock_irq(&tasklist_lock);
 	/*
diff -uprN -X elsa_import/dontdiff linux-2.6.6/Makefile linux-2.6.6-elsa/Makefile
--- linux-2.6.6/Makefile	2004-05-10 04:32:53.000000000 +0200
+++ linux-2.6.6-elsa/Makefile	2004-05-10 09:58:01.000000000 +0200
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 6
-EXTRAVERSION =
+EXTRAVERSION = -elsa
 NAME=Zonked Quokka
 
 # *DOCUMENTATION*


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2004-05-12 12:22 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-05 13:26 [PATCH] Enhanced Linux System Accounting Guillaume Thouvenin
2004-05-05 18:12 ` Karim Yaghmour
2004-05-05 20:18 ` Chris Wright
  -- strict thread matches above, loose matches on Subject: below --
2004-05-12 12:20 Guillaume Thouvenin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox