summaryrefslogtreecommitdiff
path: root/kernel/acct.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/acct.c')
-rw-r--r--kernel/acct.c92
1 files changed, 62 insertions, 30 deletions
diff --git a/kernel/acct.c b/kernel/acct.c
index 2e3f4a47e7d0..6312d6bd43e3 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -54,6 +54,7 @@
#include <linux/jiffies.h>
#include <linux/times.h>
#include <linux/syscalls.h>
+#include <linux/mount.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <linux/blkdev.h> /* sector_div */
@@ -192,6 +193,7 @@ static void acct_file_reopen(struct file *file)
add_timer(&acct_globals.timer);
}
if (old_acct) {
+ mnt_unpin(old_acct->f_vfsmnt);
spin_unlock(&acct_globals.lock);
do_acct_process(0, old_acct);
filp_close(old_acct, NULL);
@@ -199,6 +201,42 @@ static void acct_file_reopen(struct file *file)
}
}
+static int acct_on(char *name)
+{
+ struct file *file;
+ int error;
+
+ /* Difference from BSD - they don't do O_APPEND */
+ file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
+ 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;
+ }
+
+ error = security_acct(file);
+ if (error) {
+ filp_close(file, NULL);
+ return error;
+ }
+
+ spin_lock(&acct_globals.lock);
+ mnt_pin(file->f_vfsmnt);
+ acct_file_reopen(file);
+ spin_unlock(&acct_globals.lock);
+
+ mntput(file->f_vfsmnt); /* it's pinned, now give up active reference */
+
+ return 0;
+}
+
/**
* sys_acct - enable/disable process accounting
* @name: file name for accounting records or NULL to shutdown accounting
@@ -212,47 +250,41 @@ static void acct_file_reopen(struct file *file)
*/
asmlinkage long sys_acct(const char __user *name)
{
- struct file *file = NULL;
- char *tmp;
int error;
if (!capable(CAP_SYS_PACCT))
return -EPERM;
if (name) {
- tmp = getname(name);
- if (IS_ERR(tmp)) {
+ char *tmp = getname(name);
+ if (IS_ERR(tmp))
return (PTR_ERR(tmp));
- }
- /* Difference from BSD - they don't do O_APPEND */
- file = filp_open(tmp, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
+ error = acct_on(tmp);
putname(tmp);
- 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);
+ } else {
+ error = security_acct(NULL);
+ if (!error) {
+ spin_lock(&acct_globals.lock);
+ acct_file_reopen(NULL);
+ spin_unlock(&acct_globals.lock);
}
}
+ return error;
+}
- error = security_acct(file);
- if (error) {
- if (file)
- filp_close(file, NULL);
- return error;
- }
-
+/**
+ * acct_auto_close - turn off a filesystem's accounting if it is on
+ * @m: vfsmount being shut down
+ *
+ * If the accounting is turned on for a file in the subtree pointed to
+ * to by m, turn accounting off. Done when m is about to die.
+ */
+void acct_auto_close_mnt(struct vfsmount *m)
+{
spin_lock(&acct_globals.lock);
- acct_file_reopen(file);
+ if (acct_globals.file && acct_globals.file->f_vfsmnt == m)
+ acct_file_reopen(NULL);
spin_unlock(&acct_globals.lock);
-
- return (0);
}
/**
@@ -266,8 +298,8 @@ void acct_auto_close(struct super_block *sb)
{
spin_lock(&acct_globals.lock);
if (acct_globals.file &&
- acct_globals.file->f_dentry->d_inode->i_sb == sb) {
- acct_file_reopen((struct file *)NULL);
+ acct_globals.file->f_vfsmnt->mnt_sb == sb) {
+ acct_file_reopen(NULL);
}
spin_unlock(&acct_globals.lock);
}