Selon Guillaume Thouvenin <guillaume.thouvenin@polymtl.ca>: > I'd like to know if I add initialization in the right place? I ask that > because when I boot the modified kernel it didn't boot. I recompiled it with > additionnal debugging symbols, sysreq and serial support for the console to > see > where is the problem but after adding debugging support everything works. So > maybe there is an error that occurs under special conditions... I removed kernel hacking option "Compile the kernel with debug info" and "Magic SysRq key", recompiled the kernel and the kernel oops occured again. Therefore I could get it and here is the oops: Unable to handle kernel paging request at virtual address fffffff0 printing eip: c0137c95 *pde = 00004067 *pte = 00000000 Oops: 0000 [#1] SMP CPU: 0 EIP: 0060:[<c0137c95>] Not tainted EFLAGS: 00010213 (2.6.5-elsa) EIP is at elsa_copy_parent_bank+0x31/0x5d eax: 00000001 ebx: fffffff0 ecx: c03bf10c edx: 00000000 esi: f7f9f780 edi: 00000001 ebp: 00000001 esp: c044bf20 ds: 007b es: 007b ss: 0068 Process swapper (pid: 0, threadinfo=c044a000 task=c03beb60) Stack: f7f9f780 f7f9f780 f7f9f780 00000000 c011e787 f7f9f780 00000000 c044bf88 00000000 00000000 00000000 00000024 00000000 00000024 c03fd1c0 c044a000 00099100 c044bfc4 004e3007 c010533d 00800b00 00000000 c044bf88 00000000 Call Trace: [<c011e787>] do_fork+0x111/0x1b0 [<c010533d>] kernel_thread+0x8e/0x96 [<c0103086>] init+0x0/0x12e [<c01052a4>] kernel_thread_helper+0x0/0xb [<c010301f>] _stext+0x1f/0x52 [<c0103086>] init+0x0/0x12e [<c044c862>] start_kernel+0x178/0x195 [<c044c428>] unknown_bootoption+0x0/0x129 Code: 8b 03 89 04 24 e8 41 01 00 00 8b 53 10 8d 5a f0 8b 43 10 0f <0>Kernel panic: Attempted to kill the idle task! In idle task - not syncing I understand that the problem is in the function elsa_copy_parent_bank() but how can I go deeper in the analysis. If I remove all code in this function, just keeping the call to this function from the kernel/fork.c file, I also have an oops. I copy the patch that shows all modifications I done in the kernel knowing the problem appears when I try to add and manage new field in the task_struct. Thank you very much for any help Guillaume ------B<-------- patch-2.6.5-elsa --------- diff -uprN -X elsa_import/dontdiff linux-2.6.5/arch/i386/kernel/entry.S linux-2.6.5-elsa/arch/i386/kernel/entry.S --- linux-2.6.5/arch/i386/kernel/entry.S 2004-04-04 05:36:52.000000000 +0200 +++ linux-2.6.5-elsa/arch/i386/kernel/entry.S 2004-04-15 08:04:17.000000000 +0200 @@ -882,5 +882,6 @@ ENTRY(sys_call_table) .long sys_utimes .long sys_fadvise64_64 .long sys_ni_syscall /* sys_vserver */ + .long sys_elsa syscall_table_size=(.-sys_call_table) diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/asm-i386/unistd.h linux-2.6.5-elsa/include/asm-i386/unistd.h --- linux-2.6.5/include/asm-i386/unistd.h 2004-04-04 05:37:36.000000000 +0200 +++ linux-2.6.5-elsa/include/asm-i386/unistd.h 2004-04-15 08:04:17.000000000 +0200 @@ -279,8 +279,9 @@ #define __NR_utimes 271 #define __NR_fadvise64_64 272 #define __NR_vserver 273 +#define __NR_elsa 274 -#define NR_syscalls 274 +#define NR_syscalls 275 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */ diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/linux/elsa.h linux-2.6.5-elsa/include/linux/elsa.h --- linux-2.6.5/include/linux/elsa.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.5-elsa/include/linux/elsa.h 2004-04-15 10:29:06.000000000 +0200 @@ -0,0 +1,150 @@ +/* + * include/linux/elsa.h + * + * Copyright (C) 2004 Guillaume Thouvenin + * + * ELSA - Enhanced Linux System Accounting + * + * + * Provides structure and functions to manipulate "BANK". + * They are containers that store a set of processes. It is + * to user to manage them using elsa_acct() system call. + * 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_root_s + * ------------- BANK 1 BANK 2 + * | next_id = 3 | elsa_bank_s elsa_bank_s + * |-------------| --------- --------- + * <===>| freeid_head | | id = 1 | | id = 2 | + * |-------------| |---------| |---------| + * | bank_head |<===>|bank_list|<===>|bank_list|<===>... + * ------------- |---------| |---------| + * |data_head| |data_head|<===>... + * --------- --------- + * ^ ^ + * | | + * | ================ + * PROCESS DATA | DATA | + * task_struct elsa_data_s | elsa_data_s | + * --------- -------- | --------- | + * | |<------| 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 bank with + * a given process. Structure "task_struc" is modified to use this field. + * + */ + +#ifndef __LINUX_ELSA_H +#define __LINUX_ELSA_H + +/* + * sys_elsa() interface. + * + * int sys_elsa(int opcode, + * unsigned int arg0, + * unsigned int arg1) + */ + +enum elsa_opcode { + /* + * Allocates a new bank and returns the + * identifier of the new created bank. + * If it fails, it returns 0. + * ARG0, ARG1 are not used. + */ + BANK_ALLOC, + /* + * Free previously allocated bank. + * ARG0 is the identifier of the bank, + * ARG1 is not used. + */ + BANK_FREE, + /* + * Add a process to a given bank. + * ARG0 is the identifier of the bank, + * ARG1 is the pid of the process to add. + */ + BANK_ADD, + /* + * Remove a process from a given bank. + * ARG0 is the identifier of the bank, + * ARG1 is the pid of the process to remove. + */ + BANK_REMOVE, + /* + * Remove a process from all banks. + * ARG0 is unused, + * ARG1 is the pid of the process to remove. + */ + BANK_REMOVE_ALL +}; + +/* + * Following structure can only by manipulated by the kernel. + */ + +#ifdef __KERNEL__ + +#include <linux/sched.h> +#include <linux/list.h> + +extern void elsa_copy_parent_bank(struct task_struct *p); + +struct bank_root_s { + unsigned int next_id; /* next available bank identifier */ + struct list_head freeid_head; /* a list of free bank identifier */ + struct list_head bank_head; /* head of the list of bank */ +}; + +#define BANK_ROOT_INIT(root) { \ + 1, \ + LIST_HEAD_INIT(root.freeid_head), \ + LIST_HEAD_INIT(root.bank_head) \ +} + +struct elsa_freeid_s { + unsigned int id; + struct list_head id_list; +}; + +struct elsa_bank_s { + unsigned int id; /* the bank identifier */ + 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 { + unsigned int bank_id; /* 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 */ +}; + +#endif /* !(__KERNEL) */ +#endif /* !(__LINUX_ELSA_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-15 09:23:46.000000000 +0200 @@ -493,6 +493,11 @@ struct task_struct { unsigned long ptrace_message; siginfo_t *last_siginfo; /* For ptrace use. */ + +#ifdef CONFIG_ELSA +/* List of BANK to which the process belong - Used by ELSA */ + struct list_head bank_head; +#endif }; static inline pid_t process_group(struct task_struct *tsk) diff -uprN -X elsa_import/dontdiff linux-2.6.5/include/linux/syscalls.h linux-2.6.5-elsa/include/linux/syscalls.h --- linux-2.6.5/include/linux/syscalls.h 2004-04-04 05:38:26.000000000 +0200 +++ linux-2.6.5-elsa/include/linux/syscalls.h 2004-04-15 08:50:03.000000000 +0200 @@ -471,6 +471,7 @@ asmlinkage long sys_nfsservctl(int cmd, void __user *res); asmlinkage long sys_syslog(int type, char __user *buf, int len); asmlinkage long sys_uselib(const char __user *library); +asmlinkage long sys_elsa(int opcode, unsigned int bank_id, pid_t pid); asmlinkage long sys_ni_syscall(void); #endif 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-15 08:04:17.000000000 +0200 @@ -104,6 +104,20 @@ config BSD_PROCESS_ACCT up to the user level program to do useful things with this information. This is generally a good idea, so say Y. +config ELSA + bool "Enhanced Linux System Accounting" + default n + ---help--- + Not available + +config ELSA_DEBUG + bool "ELSA debugging support" + depends on ELSA + ---help--- + If you are using the Enhanced Linux System Accounting, this option + allows you to enable debugging output. Informations are sent to the + console. + config SYSCTL bool "Sysctl support" ---help--- diff -uprN -X elsa_import/dontdiff linux-2.6.5/kernel/elsa.c linux-2.6.5-elsa/kernel/elsa.c --- linux-2.6.5/kernel/elsa.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.5-elsa/kernel/elsa.c 2004-04-15 16:03:17.000000000 +0200 @@ -0,0 +1,412 @@ +/* + * linux/kernel/elsa.c + * + * ELSA - Enhanced Linux System Accounting + * + * This file implements Enhanced Linux System Accounting. It + * provides structure and functions to manipulate "BANK". + * + * (C) Copyright 2004 Guillaume Thouvenin + * + * This code is licenced under the GPL. + */ + +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/types.h> +#include <linux/sched.h> + +#include <linux/elsa.h> + +/* It's the head on the list of banks */ +static struct bank_root_s elsa_broot = BANK_ROOT_INIT(elsa_broot); + +static int elsa_bank_process_add(unsigned int bank_id, struct task_struct *p); + +/** + * elsa_copy_parent_bank - Add a given process to the same banks + * as another one + * + * Goes through the banks to which parent's process belong and add + * the process in those banks. It is used when doing a fork. This + * function is used by the kernel to update child's banks + */ +void elsa_copy_parent_bank(struct task_struct *p) +{ + struct elsa_data_s *data; + + if (!list_empty(&p->parent->bank_head)) + list_for_each_entry(data, &(p->parent->bank_head), bank_list) + elsa_bank_process_add(data->bank_id, p); +} + +/** + * elsa_get_free_id - Returns a bank identifier + * + * Retruns an available bank identifier. It first looks + * if there is one in the list of freeid, if not, it tests + * if there is still free id (equivalent to next_id != 0). + * If yes, it update next_id returns the identifier. + */ +static int elsa_get_free_id(void) +{ + struct elsa_freeid_s *freeid; + int bank_id; + + /* if there is one in the freeid list use it */ + if (!list_empty(&(elsa_broot.freeid_head))) { + /* get the first entry in the list */ + freeid = + list_entry(elsa_broot.freeid_head.next, + struct elsa_freeid_s, id_list); + + /* got it */ + bank_id = freeid->id; + + /* remove it from the list */ + list_del(&(freeid->id_list)); + + /* free space */ + kfree(freeid); + } else { + /* test if there is one available free ID */ + if (elsa_broot.next_id == 0) + /* there is no more banks */ + return 0; + + bank_id = elsa_broot.next_id; + elsa_broot.next_id++; + } + + return bank_id; +} + +/** + * elsa_get_bank - Returns a pointer to a bank + * @bank_id: The identifier of a bank + * + * Find the bank with given ID in the list of banks + */ +static struct elsa_bank_s *elsa_get_bank(unsigned int bank_id) +{ + 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->id == bank_id) { + found = bank_id; + 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 + * @process: A pointer to the process + * + * Find 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_process_add - Add a process to a given bank + * + * Adds a process to a given bank + * Here are steps to perform + * + * 1) get the bank with id bank_id + * 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 + * + * The difference with elsa_bank_add() is that in the latest function the BANK + * can not exist. In this one, if the BANK doesn't exist, it's a bug. We certainly + * can write better code because currently code is duplicated :<-- TODO + */ +static int elsa_bank_process_add(unsigned int bank_id, struct task_struct *p) +{ + struct elsa_bank_s *bank; + struct elsa_data_s *data; + + bank = elsa_get_bank(bank_id); + if (bank == NULL) { + printk("elsa_bank_process_add: Bug found !!!\n"); + return 0; + } + + /* allocate space to data */ + data = + (struct elsa_data_s *)kmalloc(sizeof(struct elsa_data_s), + GFP_KERNEL); + if (data == NULL) { +#ifdef CONFIG_ELSA_DEBUG + printk + ("elsa_bank_process_add: cannot allocate space for data\n"); +#endif + return 0; + } + + /* initialize data */ + data->bank_id = bank_id; + data->process = p; + list_add(&(data->data_list), &(bank->data_head)); + list_add(&(data->bank_list), &(p->bank_head)); + + return bank_id; +} + +/** + * elsa_bank_alloc - Allocates a new bank + * + * Allocates a new bank and return the identifiers of the new created bank. + * 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 + * + * Futur work: Deal with the /proc entry + */ +int elsa_bank_alloc(void) +{ + struct elsa_bank_s *new_bank; + int new_id; + + /* allocate space for the new bank */ + new_bank = + (struct elsa_bank_s *)kmalloc(sizeof(struct elsa_bank_s), + GFP_KERNEL); + if (new_bank == NULL) + return 0; + + /* give it an id */ + new_id = elsa_get_free_id(); + if (elsa_get_free_id == 0) { + /* There is no available id == ERROR */ + kfree(new_bank); + return 0; + } else + new_bank->id = new_id; + + /* 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->id); +#endif + return new_bank->id; +} + +/** + * elsa_bank_free - Frees space occupying by a bank. + * @bank_id: identifier of the bank to be free + * + * Frees and removes a bank and return the identifiers of the removed bank. + * When this function is called, the bank MUST be empty. If the bank is not + * empty, -1 is returned. If there is no corresponding BANK_ID, 0 is returned. + * + * Here are different steps of the operation + * + * 1) Locate the bank with the corresponding ID. + * 2) Remove it from the list of banks + * 3) Free space for the new bank + * + * Futur work: Deal with the /proc entry + */ +int elsa_bank_free(unsigned int bank_id) +{ + struct elsa_bank_s *bank; + struct elsa_freeid_s *new_freeid; + + /* we must locate the bank with BANK_ID in the list */ + if (list_empty(&(elsa_broot.bank_head))) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_free: list is empty\n"); +#endif + return 0; + } +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_free: Try to find BID#%d\n", bank_id); +#endif + bank = elsa_get_bank(bank_id); + if (bank == NULL) + return -1; + + /* error if the list of processus in a bank is not empty */ + if (!list_empty(&(bank->data_head))) { +#ifdef CONFIG_ELSA_DEBUG + printk + ("elsa_bank_free: remove element with links to processus\n"); +#endif + return -2; + } + + /* Insert the identifier of the bank in the list of free bank ID */ + /* allocate space for the freeid item */ + new_freeid = (struct elsa_freeid_s *) + kmalloc(sizeof(struct elsa_freeid_s), GFP_KERNEL); + if (new_freeid == NULL) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_free: cannot allocate space for freeid\n"); +#endif + return -3; + } + new_freeid->id = bank->id; + list_add(&(new_freeid->id_list), &(elsa_broot.freeid_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->id); +#endif + kfree(bank); + + return bank_id; +} + +/** + * elsa_bank_add - Add a process to a bank + * @bank_id: identifier of the bank where the process will be added + * @pid: identifier of the process to be added + * + * Add a data to a bank and returns the bank ID, 0 if an error + * occured. + * + * Here is steps to perform: + * + * 1) Locate the bank + * 2) If the bank doesn't exist, create it. Else, + * check if the process is already in the bank + * 3) Create a data element + * 4) Get the pointer to the process + * 5) Update fields of the data element + * + * Futur work: Deal with the /proc entry + */ +int elsa_bank_add(unsigned int bank_id, pid_t pid) +{ + struct elsa_bank_s *bank; + struct elsa_data_s *data; + struct task_struct *p = find_task_by_pid(pid); + + if (p == NULL) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_add: Process ID#%d not found\n", pid); +#endif + return -1; + } + + /* Find the bank with id equal to bank_id */ + bank = elsa_get_bank(bank_id); + + if (bank == NULL) { + /* The bank doesn't exist and thus we create it */ + bank_id = elsa_bank_alloc(); + bank = elsa_get_bank(bank_id); + /* At this point bank != NULL, otherwise there is a bug */ + if (bank == NULL) { + printk("elsa_bank_add: found a bug !!!"); + return 0; + } + } + /* 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 bank_id; + + /* allocate space to data */ + data = + (struct elsa_data_s *)kmalloc(sizeof(struct elsa_data_s), + GFP_KERNEL); + if (data == NULL) { +#ifdef CONFIG_ELSA_DEBUG + printk("elsa_bank_add: cannot allocate space for data\n"); +#endif + return -2; + } + + /* initialize data */ + data->bank_id = bank_id; + 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, bank_id); +#endif + return bank_id; +} + +/** + * elsa_bank_remove - Remove a process to one or more banks + * @bank_id: identifier of the bank where the process will be removed + * @pid: identifier of the process to be removed + */ +int elsa_bank_remove(unsigned int bank_id, pid_t pid) +{ + return 0; +} + +/** + * sys_elsa - This is the system call + * @opcode + * + */ +asmlinkage long sys_elsa(int opcode, unsigned int bank_id, pid_t pid) +{ + int err = 0; + + switch (opcode) { + case BANK_ALLOC: + err = elsa_bank_alloc(); + break; + + case BANK_FREE: + err = elsa_bank_free(bank_id); + break; + + case BANK_ADD: + err = elsa_bank_add(bank_id, pid); + break; + + case BANK_REMOVE: + case BANK_REMOVE_ALL: + break; + + default: + err = -EINVAL; + break; + }; + + return err; +} 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-15 12:33:05.000000000 +0200 @@ -31,6 +31,7 @@ #include <linux/futex.h> #include <linux/ptrace.h> #include <linux/mount.h> +#include <linux/elsa.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -1053,6 +1054,11 @@ struct task_struct *copy_process(unsigne if (p->ptrace & PT_PTRACED) __ptrace_link(p, current->parent); +#ifdef CONFIG_ELSA + /* child is in the same BANK as parent */ + INIT_LIST_HEAD(&(p->bank_head)); +#endif + attach_pid(p, PIDTYPE_PID, p->pid); if (thread_group_leader(p)) { attach_pid(p, PIDTYPE_TGID, p->tgid); @@ -1187,6 +1193,12 @@ long do_fork(unsigned long clone_flags, * COW overhead when the child exec()s afterwards. */ set_need_resched(); + +#ifdef CONFIG_ELSA + /* child is in the same BANK as parent */ + if (p->pid != 0) + elsa_copy_parent_bank(p); +#endif } 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-15 08:04:18.000000000 +0200 @@ -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) += elsa.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <alan@linuxcare.com.au>, 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-15 08:04:17.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 5 -EXTRAVERSION = +EXTRAVERSION = -elsa NAME=Zonked Quokka # *DOCUMENTATION* -- Kernelnewbies: Help each other learn about the Linux kernel. Archive: http://mail.nl.linux.org/kernelnewbies/ FAQ: http://kernelnewbies.org/faq/