bsdacct: switch from global bsd_acct_struct instance to per-pidns one

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>
This commit is contained in:
Pavel Emelyanov 2008-07-25 01:48:47 -07:00 committed by Linus Torvalds
parent 6248b1b342
commit 0b6b030fc3
3 changed files with 71 additions and 18 deletions

View File

@ -120,17 +120,20 @@ struct acct_v3
struct vfsmount; struct vfsmount;
struct super_block; struct super_block;
struct pacct_struct; struct pacct_struct;
struct pid_namespace;
extern void acct_auto_close_mnt(struct vfsmount *m); extern void acct_auto_close_mnt(struct vfsmount *m);
extern void acct_auto_close(struct super_block *sb); extern void acct_auto_close(struct super_block *sb);
extern void acct_init_pacct(struct pacct_struct *pacct); extern void acct_init_pacct(struct pacct_struct *pacct);
extern void acct_collect(long exitcode, int group_dead); extern void acct_collect(long exitcode, int group_dead);
extern void acct_process(void); extern void acct_process(void);
extern void acct_exit_ns(struct pid_namespace *);
#else #else
#define acct_auto_close_mnt(x) do { } while (0) #define acct_auto_close_mnt(x) do { } while (0)
#define acct_auto_close(x) do { } while (0) #define acct_auto_close(x) do { } while (0)
#define acct_init_pacct(x) do { } while (0) #define acct_init_pacct(x) do { } while (0)
#define acct_collect(x,y) do { } while (0) #define acct_collect(x,y) do { } while (0)
#define acct_process() do { } while (0) #define acct_process() do { } while (0)
#define acct_exit_ns(ns) do { } while (0)
#endif #endif
/* /*

View File

@ -93,8 +93,6 @@ struct bsd_acct_struct {
static DEFINE_SPINLOCK(acct_lock); static DEFINE_SPINLOCK(acct_lock);
static struct bsd_acct_struct acct_globals __cacheline_aligned;
/* /*
* Called whenever the timer says to check the free space. * 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. * 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 file *old_acct = NULL;
struct pid_namespace *old_ns = 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->active = 0;
acct->needcheck = 0; acct->needcheck = 0;
acct->file = NULL; acct->file = NULL;
acct->ns = NULL;
} }
if (file) { if (file) {
acct->file = file; acct->file = file;
acct->ns = get_pid_ns(task_active_pid_ns(current)); acct->ns = ns;
acct->needcheck = 0; acct->needcheck = 0;
acct->active = 1; acct->active = 1;
/* It's been deleted if it was used before so this is safe */ /* 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); spin_unlock(&acct_lock);
do_acct_process(acct, old_ns, old_acct); do_acct_process(acct, old_ns, old_acct);
filp_close(old_acct, NULL); filp_close(old_acct, NULL);
put_pid_ns(old_ns);
spin_lock(&acct_lock); spin_lock(&acct_lock);
} }
} }
@ -213,6 +212,8 @@ static int acct_on(char *name)
{ {
struct file *file; struct file *file;
int error; int error;
struct pid_namespace *ns;
struct bsd_acct_struct *acct = NULL;
/* Difference from BSD - they don't do O_APPEND */ /* Difference from BSD - they don't do O_APPEND */
file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
@ -229,18 +230,34 @@ static int acct_on(char *name)
return -EIO; 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); error = security_acct(file);
if (error) { if (error) {
kfree(acct);
filp_close(file, NULL); filp_close(file, NULL);
return error; return error;
} }
spin_lock(&acct_lock); spin_lock(&acct_lock);
if (ns->bacct == NULL) {
ns->bacct = acct;
acct = NULL;
}
mnt_pin(file->f_path.mnt); mnt_pin(file->f_path.mnt);
acct_file_reopen(&acct_globals, file); acct_file_reopen(ns->bacct, file, ns);
spin_unlock(&acct_lock); spin_unlock(&acct_lock);
mntput(file->f_path.mnt); /* it's pinned, now give up active reference */ mntput(file->f_path.mnt); /* it's pinned, now give up active reference */
kfree(acct);
return 0; return 0;
} }
@ -270,10 +287,16 @@ asmlinkage long sys_acct(const char __user *name)
error = acct_on(tmp); error = acct_on(tmp);
putname(tmp); putname(tmp);
} else { } else {
struct bsd_acct_struct *acct;
acct = task_active_pid_ns(current)->bacct;
if (acct == NULL)
return 0;
error = security_acct(NULL); error = security_acct(NULL);
if (!error) { if (!error) {
spin_lock(&acct_lock); spin_lock(&acct_lock);
acct_file_reopen(&acct_globals, NULL); acct_file_reopen(acct, NULL, NULL);
spin_unlock(&acct_lock); spin_unlock(&acct_lock);
} }
} }
@ -289,9 +312,15 @@ asmlinkage long sys_acct(const char __user *name)
*/ */
void acct_auto_close_mnt(struct vfsmount *m) 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); spin_lock(&acct_lock);
if (acct_globals.file && acct_globals.file->f_path.mnt == m) if (acct->file && acct->file->f_path.mnt == m)
acct_file_reopen(&acct_globals, NULL); acct_file_reopen(acct, NULL, NULL);
spin_unlock(&acct_lock); spin_unlock(&acct_lock);
} }
@ -304,10 +333,29 @@ void acct_auto_close_mnt(struct vfsmount *m)
*/ */
void acct_auto_close(struct super_block *sb) 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); spin_lock(&acct_lock);
if (acct_globals.file && if (acct->file && acct->file->f_path.mnt->mnt_sb == sb)
acct_globals.file->f_path.mnt->mnt_sb == sb) { acct_file_reopen(acct, NULL, NULL);
acct_file_reopen(&acct_globals, 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); spin_unlock(&acct_lock);
} }
@ -587,25 +635,25 @@ void acct_collect(long exitcode, int group_dead)
void acct_process(void) void acct_process(void)
{ {
struct file *file = NULL; 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: * accelerate the common fastpath:
*/ */
if (!acct_globals.file) if (!acct || !acct->file)
return; return;
spin_lock(&acct_lock); spin_lock(&acct_lock);
file = acct_globals.file; file = acct->file;
if (unlikely(!file)) { if (unlikely(!file)) {
spin_unlock(&acct_lock); spin_unlock(&acct_lock);
return; return;
} }
get_file(file); get_file(file);
ns = get_pid_ns(acct_globals.ns);
spin_unlock(&acct_lock); spin_unlock(&acct_lock);
do_acct_process(&acct_globals, ns, file); do_acct_process(acct, ns, file);
fput(file); fput(file);
put_pid_ns(ns);
} }

View File

@ -12,6 +12,7 @@
#include <linux/pid_namespace.h> #include <linux/pid_namespace.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/acct.h>
#define BITS_PER_PAGE (PAGE_SIZE*8) #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 */ /* Child reaper for the pid namespace is going away */
pid_ns->child_reaper = NULL; pid_ns->child_reaper = NULL;
acct_exit_ns(pid_ns);
return; return;
} }