A common layer for Accounting packages

From: Jay Lan
Date: Fri Feb 18 2005 - 19:54:22 EST


It started with the need of CSA to handle end-of-process (eop) at
do_exit() at exit.c. The hook at exit.c was BSD Accounting specific.

Since the need of Linux system accounting has gone beyond what BSD
accounting provides, i think it is a good idea to create a thin layer
of common code for various accounting packages, such as BSD accounting,
CSA, ELSA, etc. The hook to do_exit() at exit.c was changed to invoke
a routine in the common code which would then invoke those accounting
packages that register to the acct_common to handle do_exit situation.

Here is the description of this acct_common patch:
1) two new files at include/linux/acct_common.h and kernel/acct_common.c
2) A new config flag CONFIG_ACCT_COMMON is created and
CONFIG_BSD_PROCESS_ACCT and a future CSA config flag depend on it.
I think it is a good idea to always have acct_common in the kernel;
in that case, the new config flag may not be really necessary. I can
go either way.
3) Accounting packages can register themselves to acct_common for
callbacks. Only do_exit handling is defined now. BSD acct.c has been
modified to register/unergister to acct_common.
4) The 'enhanced acct data collection' routines have been moved from
acct.c to acct_common.c. Files used to #include <linux/acct.h> were
modified to #include <linux/acct_common.h>.

This patch was generated against 2.6.11-rc3-mm2.

Signed-off-by: Jay Lan <jlan@xxxxxxx>

Index: linux/kernel/fork.c
===================================================================
--- linux.orig/kernel/fork.c 2005-02-17 19:24:54.388927143 -0800
+++ linux/kernel/fork.c 2005-02-18 09:59:14.179816325 -0800
@@ -40,7 +40,7 @@
#include <linux/audit.h>
#include <linux/profile.h>
#include <linux/rmap.h>
-#include <linux/acct.h>
+#include <linux/acct_common.h>

#include <asm/pgtable.h>
#include <asm/pgalloc.h>
Index: linux/fs/exec.c
===================================================================
--- linux.orig/fs/exec.c 2005-02-18 05:45:19.868493728 -0800
+++ linux/fs/exec.c 2005-02-18 09:59:14.196418021 -0800
@@ -47,7 +47,7 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
-#include <linux/acct.h>
+#include <linux/acct_common.h>

#include <asm/uaccess.h>
#include <asm/mmu_context.h>
Index: linux/kernel/exit.c
===================================================================
--- linux.orig/kernel/exit.c 2005-02-17 19:24:54.380138011 -0800
+++ linux/kernel/exit.c 2005-02-18 10:05:43.506174767 -0800
@@ -17,7 +17,7 @@
#include <linux/key.h>
#include <linux/security.h>
#include <linux/cpu.h>
-#include <linux/acct.h>
+#include <linux/acct_common.h>
#include <linux/file.h>
#include <linux/binfmts.h>
#include <linux/ptrace.h>
@@ -814,7 +814,7 @@ fastcall NORET_TYPE void do_exit(long co
group_dead = atomic_dec_and_test(&tsk->signal->live);
if (group_dead) {
del_timer_sync(&tsk->signal->real_timer);
- acct_process(code);
+ acct_do_exit(code, tsk);
}
exit_mm(tsk);

Index: linux/include/linux/acct_common.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/include/linux/acct_common.h 2005-02-18 12:41:28.232626074 -0800
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2005 Silicon Graphics, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Jay Lan <jlan@xxxxxxx>
+ */
+
+/*
+ * include/linux/acct_common.h
+ *
+ * Common Accounting for Linux - Definitions
+ *
+ * 02/17/05 Jay Lan <jlan@xxxxxxx>. Initial creation of the header file.
+ * This header file contains the definitions needed to support
+ * registration/unregistration of various accounting agents to
+ * the kernel. It also contains prototypes of common routines.
+ *
+ */
+
+#ifndef _LINUX_ACCT_COMMON_H
+#define _LINUX_ACCT_COMMON_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+
+
+/*
+ * Various accounting modules ID's
+ */
+#define ACCT_BSD 0
+#define ACCT_CSA 1
+#define ACCT_ELSA 2
+#define LAST_ACCT_ID ACCT_ELSA
+#define ACCT_PKG_COUNT (LAST_ACCT_ID+1)
+
+/*
+ * Used by accounting packages to define the callback functions into the
+ * packages.
+ *
+ * STRUCT MEMBERS:
+ * pkg_id: Accounting package ID. This should be set the package
+ * when register.
+ * do_exit: Function pointer to function used when do_exit()
+ * hook is needed.
+ * This is optional and may be set to NULL if it is
+ * not needed by the accounting package.
+ */
+struct acct_hook {
+ int pkg_id; /* accounting package ID */
+ void (*do_exit)(long exitcode, void *data);
+};
+
+
+/* Common accounting routines prototypes */
+extern int acct_register(struct acct_hook *);
+extern int acct_unregister(struct acct_hook *);
+
+#ifdef CONFIG_ACCT_COMMON
+extern void acct_do_exit(long, struct task_struct *tsk);
+extern void acct_update_integrals(struct task_struct *tsk);
+extern void acct_clear_integrals(struct task_struct *tsk);
+#else
+#define acct_do_exit(x,y) do { } while (0)
+#define acct_update_integrals(x) do { } while (0)
+#define acct_clear_integrals(x) do { } while (0)
+#endif
+
+#endif /* _LINUX_ACCT_COMMON_H */
Index: linux/include/linux/acct.h
===================================================================
--- linux.orig/include/linux/acct.h 2005-02-17 19:24:52.843016528 -0800
+++ linux/include/linux/acct.h 2005-02-18 10:02:00.557125382 -0800
@@ -119,14 +119,10 @@ struct acct_v3
#ifdef CONFIG_BSD_PROCESS_ACCT
struct super_block;
extern void acct_auto_close(struct super_block *sb);
-extern void acct_process(long exitcode);
-extern void acct_update_integrals(struct task_struct *tsk);
-extern void acct_clear_integrals(struct task_struct *tsk);
+extern void acct_process(long exitcode, void *data);
#else
#define acct_auto_close(x) do { } while (0)
-#define acct_process(x) do { } while (0)
-#define acct_update_integrals(x) do { } while (0)
-#define acct_clear_integrals(task) do { } while (0)
+#define acct_process(x,y) do { } while (0)
#endif

/*
Index: linux/kernel/acct.c
===================================================================
--- linux.orig/kernel/acct.c 2005-02-17 19:24:54.307871817 -0800
+++ linux/kernel/acct.c 2005-02-18 12:43:38.704382273 -0800
@@ -46,6 +46,7 @@
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/slab.h>
+#include <linux/acct_common.h>
#include <linux/acct.h>
#include <linux/file.h>
#include <linux/tty.h>
@@ -89,6 +90,37 @@ struct acct_glbs {
};

static struct acct_glbs acct_globals __cacheline_aligned = {SPIN_LOCK_UNLOCKED};
+static struct acct_hook bsd_hook = {
+ .pkg_id = ACCT_BSD,
+ .do_exit = acct_process,
+};
+
+/*
+ * init routine of BSD Process Accounting
+ */
+static int __init
+acct_bsd_init(void)
+{
+ int retval = 0;
+
+ retval = acct_register(&bsd_hook);
+ if (retval == 0)
+ printk(KERN_INFO "BSD Process Accounting Initialized\n");
+ else
+ printk(KERN_ERR "BSD Process Accounting Init Failed\n");
+ return retval;
+}
+
+/*
+ * cleanup routine of BSD Process Accounting
+ */
+static void __exit
+acct_bsd_cleanup(void)
+{
+ (void)acct_unregister(&bsd_hook);
+ printk(KERN_INFO "BSD Proces Accounting Unregistered\n");
+ return;
+}

/*
* Called whenever the timer says to check the free space.
@@ -506,7 +538,7 @@ static void do_acct_process(long exitcod
/*
* acct_process - now just a wrapper around do_acct_process
*/
-void acct_process(long exitcode)
+void acct_process(long exitcode, void *data)
{
struct file *file = NULL;

@@ -530,32 +562,5 @@ void acct_process(long exitcode)
}


-/*
- * acct_update_integrals
- * - update mm integral fields in task_struct
- */
-void acct_update_integrals(struct task_struct *tsk)
-{
- if (likely(tsk->mm)) {
- long delta = tsk->stime - tsk->acct_stimexpd;
-
- if (delta == 0)
- return;
- tsk->acct_stimexpd = tsk->stime;
- tsk->acct_rss_mem1 += delta * tsk->mm->rss;
- tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
- }
-}
-
-/*
- * acct_clear_integrals
- * - clear the mm integral fields in task_struct
- */
-void acct_clear_integrals(struct task_struct *tsk)
-{
- if (tsk) {
- tsk->acct_stimexpd = 0;
- tsk->acct_rss_mem1 = 0;
- tsk->acct_vm_mem1 = 0;
- }
-}
+module_init(acct_bsd_init);
+module_exit(acct_bsd_cleanup);
Index: linux/kernel/acct_common.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/kernel/acct_common.c 2005-02-18 12:39:06.266636027 -0800
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2005 Silicon Graphics, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Jay Lan <jlan@xxxxxxx>
+ */
+
+/*
+ * kernel/acct_common.c
+ *
+ * Common Accounting routines for Linux Accounting
+ *
+ * The acct.c mainly is BSD-style process accounting. However,
+ * as more accounting packages are created, such as CSA and
+ * ELSA, to extend the usage of the BSD accounting, there is
+ * a need to have a common file for all accounting packages
+ * including the BSD-style process accounting.
+ *
+ * 02/17/05 Jay Lan <jlan@xxxxxxx>. Initial creation of the file to
+ * provide common codes of Linux accounting. It also provides
+ * mechanism for various accounting agents to register and
+ * unregister to the kernel with callback hook. Only
+ * do_exit callback is supported initially.
+ *
+ */
+
+#include <linux/acct_common.h>
+#include <linux/module.h>
+
+
+/* Accounting packages list */
+static struct acct_hook *acct_list[ACCT_PKG_COUNT] = {0};
+static DECLARE_RWSEM(acct_list_sem);
+
+
+/*
+ * acct_register - accounting package registers to the kernel.
+ * @ap: The registering accounting package, in struct acct_pkg pointer type
+ *
+ * returns -errno value on failure, 0 on success.
+ */
+int
+acct_register(struct acct_hook *ap)
+{
+ if (!ap)
+ return -EINVAL; /* Invalid value */
+ if (ap->pkg_id < 0 || ap->pkg_id > LAST_ACCT_ID)
+ return -EINVAL; /* Invalid value */
+
+ down_write(&acct_list_sem);
+ if (acct_list[ap->pkg_id] != NULL) {
+ up_write(&acct_list_sem);
+ return -EBUSY; /* Already registered */
+ }
+
+ acct_list[ap->pkg_id] = ap;
+ up_write(&acct_list_sem);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acct_register);
+
+
+/*
+ * acct_unregister - accounting package unregister to the kernel.
+ * @ap: The unregistering accounting package, in struct acct_hook pointer type
+ *
+ * Returns -errno on failure, 0 on success.
+ */
+int
+acct_unregister(struct acct_hook *ap)
+{
+ if (!ap)
+ return -EINVAL; /* Invalid value */
+ if (ap->pkg_id < 0 || ap->pkg_id > LAST_ACCT_ID)
+ return -EINVAL; /* Invalid value */
+
+ down_write(&acct_list_sem);
+
+ if (acct_list[ap->pkg_id] != ap) {
+ up_write(&acct_list_sem);
+ return -EFAULT; /* Not matching entry */
+ }
+
+ acct_list[ap->pkg_id] = NULL;
+ up_write(&acct_list_sem);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acct_unregister);
+
+
+/*
+ * do_exit() hook for accounting packages
+ * @exitcode: the exitcode to pass along
+ *
+ */
+void acct_do_exit(long exitcode, struct task_struct *tsk)
+{
+ int i;
+
+ down_write(&acct_list_sem);
+ for (i=0; i < ACCT_PKG_COUNT; i++) {
+ if (acct_list[i] == NULL) /* not registered */
+ continue;
+ if (acct_list[i]->do_exit != NULL) { /* do_exit callback */
+ switch (acct_list[i]->pkg_id) {
+ case ACCT_BSD:
+ acct_list[i]->do_exit(exitcode, NULL);
+ break;
+ case ACCT_CSA:
+ acct_list[i]->do_exit(exitcode, tsk);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ up_write(&acct_list_sem);
+ return;
+}
+
+
+/*
+ * acct_update_integrals
+ * - update mm integral fields in task_struct
+ */
+void acct_update_integrals(struct task_struct *tsk)
+{
+ if (likely(tsk->mm)) {
+ long delta = tsk->stime - tsk->acct_stimexpd;
+
+ if (delta == 0) return;
+ tsk->acct_stimexpd = tsk->stime;
+ tsk->acct_rss_mem1 += delta * tsk->mm->rss;
+ tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
+ }
+}
+
+
+/*
+ * acct_clear_integrals
+ * - clear the mm integral fields in task_struct
+ */
+void acct_clear_integrals(struct task_struct *tsk)
+{
+ if (tsk) {
+ tsk->acct_stimexpd = 0;
+ tsk->acct_rss_mem1 = 0;
+ tsk->acct_vm_mem1 = 0;
+ }
+}
+
+
Index: linux/kernel/Makefile
===================================================================
--- linux.orig/kernel/Makefile 2005-02-17 19:24:54.485607592 -0800
+++ linux/kernel/Makefile 2005-02-18 10:04:23.279947003 -0800
@@ -16,6 +16,7 @@ obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_PM) += power/
+obj-$(CONFIG_ACCT_COMMON) += acct_common.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_KEXEC) += kexec.o
obj-$(CONFIG_COMPAT) += compat.o
Index: linux/init/Kconfig
===================================================================
--- linux.orig/init/Kconfig 2005-02-17 19:24:54.282480992 -0800
+++ linux/init/Kconfig 2005-02-18 09:59:14.330208158 -0800
@@ -113,8 +113,19 @@ config POSIX_MQUEUE

If unsure, say Y.

+config ACCT_COMMON
+ bool "Accounting Comon Layer"
+ help
+ If you say Y here, an accounting common code is built into the
+ kernel. In addition to common code for various accounting
+ agents, such as BSD Process Accounting, CSA, ELSA, etc., this code
+ allows various accounting agents to register to it.
+
+ If you ever need system accounting, you need this; so say Y.
+
config BSD_PROCESS_ACCT
bool "BSD Process Accounting"
+ depends on ACCT_COMMON
help
If you say Y here, a user level program will be able to instruct the
kernel (via a special system call) to write process accounting
Index: linux/kernel/sched.c
===================================================================
--- linux.orig/kernel/sched.c 2005-02-17 19:24:54.628186840 -0800
+++ linux/kernel/sched.c 2005-02-18 11:13:14.200643593 -0800
@@ -48,7 +48,7 @@
#include <linux/sysctl.h>
#include <linux/syscalls.h>
#include <linux/times.h>
-#include <linux/acct.h>
+#include <linux/acct_common.h>
#include <asm/tlb.h>

#include <asm/unistd.h>