bsdacct: switch from global bsd_acct_struct instance to per-pidns one
Pavel Emelyanov [Fri, 25 Jul 2008 08:48:47 +0000 (01:48 -0700)]
Allocate the structure on the first call to sys_acct().  After this each
namespace, that ordered the accounting, will live with this structure till
its own death.

Two notes
- routines, that close the accounting on fs umount time use
  the init_pid_ns's acct by now;
- accounting routine accounts to dying task's namespace
  (also by now).

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

include/linux/acct.h
kernel/acct.c
kernel/pid_namespace.c

index e8cae54..882dc72 100644 (file)
@@ -120,17 +120,20 @@ struct acct_v3
 struct vfsmount;
 struct super_block;
 struct pacct_struct;
+struct pid_namespace;
 extern void acct_auto_close_mnt(struct vfsmount *m);
 extern void acct_auto_close(struct super_block *sb);
 extern void acct_init_pacct(struct pacct_struct *pacct);
 extern void acct_collect(long exitcode, int group_dead);
 extern void acct_process(void);
+extern void acct_exit_ns(struct pid_namespace *);
 #else
 #define acct_auto_close_mnt(x) do { } while (0)
 #define acct_auto_close(x)     do { } while (0)
 #define acct_init_pacct(x)     do { } while (0)
 #define acct_collect(x,y)      do { } while (0)
 #define acct_process()         do { } while (0)
+#define acct_exit_ns(ns)       do { } while (0)
 #endif
 
 /*
index 72d4760..febbbc6 100644 (file)
@@ -93,8 +93,6 @@ struct bsd_acct_struct {
 
 static DEFINE_SPINLOCK(acct_lock);
 
-static struct bsd_acct_struct acct_globals __cacheline_aligned;
-
 /*
  * Called whenever the timer says to check the free space.
  */
@@ -176,7 +174,8 @@ out:
  *
  * NOTE: acct_lock MUST be held on entry and exit.
  */
-static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file)
+static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file,
+               struct pid_namespace *ns)
 {
        struct file *old_acct = NULL;
        struct pid_namespace *old_ns = NULL;
@@ -188,10 +187,11 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file)
                acct->active = 0;
                acct->needcheck = 0;
                acct->file = NULL;
+               acct->ns = NULL;
        }
        if (file) {
                acct->file = file;
-               acct->ns = get_pid_ns(task_active_pid_ns(current));
+               acct->ns = ns;
                acct->needcheck = 0;
                acct->active = 1;
                /* It's been deleted if it was used before so this is safe */
@@ -204,7 +204,6 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file)
                spin_unlock(&acct_lock);
                do_acct_process(acct, old_ns, old_acct);
                filp_close(old_acct, NULL);
-               put_pid_ns(old_ns);
                spin_lock(&acct_lock);
        }
 }
@@ -213,6 +212,8 @@ static int acct_on(char *name)
 {
        struct file *file;
        int error;
+       struct pid_namespace *ns;
+       struct bsd_acct_struct *acct = NULL;
 
        /* Difference from BSD - they don't do O_APPEND */
        file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
@@ -229,18 +230,34 @@ static int acct_on(char *name)
                return -EIO;
        }
 
+       ns = task_active_pid_ns(current);
+       if (ns->bacct == NULL) {
+               acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL);
+               if (acct == NULL) {
+                       filp_close(file, NULL);
+                       return -ENOMEM;
+               }
+       }
+
        error = security_acct(file);
        if (error) {
+               kfree(acct);
                filp_close(file, NULL);
                return error;
        }
 
        spin_lock(&acct_lock);
+       if (ns->bacct == NULL) {
+               ns->bacct = acct;
+               acct = NULL;
+       }
+
        mnt_pin(file->f_path.mnt);
-       acct_file_reopen(&acct_globals, file);
+       acct_file_reopen(ns->bacct, file, ns);
        spin_unlock(&acct_lock);
 
        mntput(file->f_path.mnt); /* it's pinned, now give up active reference */
+       kfree(acct);
 
        return 0;
 }
@@ -270,10 +287,16 @@ asmlinkage long sys_acct(const char __user *name)
                error = acct_on(tmp);
                putname(tmp);
        } else {
+               struct bsd_acct_struct *acct;
+
+               acct = task_active_pid_ns(current)->bacct;
+               if (acct == NULL)
+                       return 0;
+
                error = security_acct(NULL);
                if (!error) {
                        spin_lock(&acct_lock);
-                       acct_file_reopen(&acct_globals, NULL);
+                       acct_file_reopen(acct, NULL, NULL);
                        spin_unlock(&acct_lock);
                }
        }
@@ -289,9 +312,15 @@ asmlinkage long sys_acct(const char __user *name)
  */
 void acct_auto_close_mnt(struct vfsmount *m)
 {
+       struct bsd_acct_struct *acct;
+
+       acct = init_pid_ns.bacct;
+       if (acct == NULL)
+               return;
+
        spin_lock(&acct_lock);
-       if (acct_globals.file && acct_globals.file->f_path.mnt == m)
-               acct_file_reopen(&acct_globals, NULL);
+       if (acct->file && acct->file->f_path.mnt == m)
+               acct_file_reopen(acct, NULL, NULL);
        spin_unlock(&acct_lock);
 }
 
@@ -304,10 +333,29 @@ void acct_auto_close_mnt(struct vfsmount *m)
  */
 void acct_auto_close(struct super_block *sb)
 {
+       struct bsd_acct_struct *acct;
+
+       acct = init_pid_ns.bacct;
+       if (acct == NULL)
+               return;
+
        spin_lock(&acct_lock);
-       if (acct_globals.file &&
-           acct_globals.file->f_path.mnt->mnt_sb == sb) {
-               acct_file_reopen(&acct_globals, NULL);
+       if (acct->file && acct->file->f_path.mnt->mnt_sb == sb)
+               acct_file_reopen(acct, NULL, NULL);
+       spin_unlock(&acct_lock);
+}
+
+void acct_exit_ns(struct pid_namespace *ns)
+{
+       struct bsd_acct_struct *acct;
+
+       spin_lock(&acct_lock);
+       acct = ns->bacct;
+       if (acct != NULL) {
+               if (acct->file != NULL)
+                       acct_file_reopen(acct, NULL, NULL);
+
+               kfree(acct);
        }
        spin_unlock(&acct_lock);
 }
@@ -587,25 +635,25 @@ void acct_collect(long exitcode, int group_dead)
 void acct_process(void)
 {
        struct file *file = NULL;
-       struct pid_namespace *ns;
+       struct pid_namespace *ns = task_active_pid_ns(current);
+       struct bsd_acct_struct *acct;
 
+       acct = ns->bacct;
        /*
         * accelerate the common fastpath:
         */
-       if (!acct_globals.file)
+       if (!acct || !acct->file)
                return;
 
        spin_lock(&acct_lock);
-       file = acct_globals.file;
+       file = acct->file;
        if (unlikely(!file)) {
                spin_unlock(&acct_lock);
                return;
        }
        get_file(file);
-       ns = get_pid_ns(acct_globals.ns);
        spin_unlock(&acct_lock);
 
-       do_acct_process(&acct_globals, ns, file);
+       do_acct_process(acct, ns, file);
        fput(file);
-       put_pid_ns(ns);
 }
index 06331cc..ea567b7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/syscalls.h>
 #include <linux/err.h>
+#include <linux/acct.h>
 
 #define BITS_PER_PAGE          (PAGE_SIZE*8)
 
@@ -181,6 +182,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
 
        /* Child reaper for the pid namespace is going away */
        pid_ns->child_reaper = NULL;
+       acct_exit_ns(pid_ns);
        return;
 }