lkml.org 
[lkml]   [1998]   [Nov]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] process accounting (version 2)
	Here's a new version of patch for process accounting. Summary:
a) Fixes nasty interaction with umount() and remount to readonly (umount
failed to turn accounting off if it was suspended, remount failed to
do it in all cases).
b) Hopefully fixes a bunch of races.
c) Adds a function to fs/open.c - filp_open(name,flags,mode). It opens file
and returns pointer to struct file. Now do_open just calls it, checks the
result and does fd_install(); probably do_open should be folded back into
sys_open().
Result: duplicate of this functionality in kernel/acct.c went away. Next
candidate into victims lives in fs/dquot.c.
d) Adds sysctl interface to accounting parameters (see Documentation/sysctl/
for details).
Icing on the cake being that it compiles, successfully boots and even
seems to work ;-)
#include <language_disclaimer.h>
Piece in Documentation/sysctl/kernel.txt is awful and requires fixing ;-/

Patch against 2.1.127 follows:

diff -urN linux-2.1.127/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt
--- linux-2.1.127/Documentation/sysctl/kernel.txt Sun Oct 4 18:29:44 1998
+++ linux/Documentation/sysctl/kernel.txt Wed Nov 11 00:56:02 1998
@@ -15,6 +15,7 @@
before actually making adjustments.

Currently, these files are in /proc/sys/kernel:
+- acct
- ctrl-alt-del
- dentry-state
- domainname
@@ -33,6 +34,23 @@
- reboot-cmd ==> SPARC specific
- securelevel
- version
+
+==============================================================
+
+acct:
+
+highwater lowwater frequency
+
+If BSD-style process accounting is enabled these values control
+its behaviour. If free space on filesystem where the log lives
+goes below <lowwater>% accounting suspends. If free space gets
+above <highwater>% accounting resumes. <Frequency> determines
+how often do we check the amount of free space (value is in
+seconds). Default:
+4 2 30
+That is, suspend accounting if there left <= 2% free; resume it
+if we got >=4%; consider information about amount of free space
+valid for 30 seconds.

==============================================================

diff -urN linux-2.1.127/fs/open.c linux/fs/open.c
--- linux-2.1.127/fs/open.c Tue Nov 10 22:38:58 1998
+++ linux/fs/open.c Tue Nov 10 22:42:34 1998
@@ -626,7 +626,7 @@
* for the internal routines (ie open_namei()/follow_link() etc). 00 is
* used by symlinks.
*/
-static int do_open(const char * filename, int flags, int mode, int fd)
+struct file *filp_open(const char * filename, int flags, int mode)
{
struct inode * inode;
struct dentry * dentry;
@@ -667,8 +667,7 @@
}
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

- fd_install(fd, f);
- return 0;
+ return f;

cleanup_all:
if (f->f_mode & FMODE_WRITE)
@@ -679,7 +678,19 @@
cleanup_file:
put_filp(f);
out:
- return error;
+ return ERR_PTR(error);
+}
+
+/* should probably go into sys_open() */
+static int do_open(const char * filename, int flags, int mode, int fd)
+{
+ struct file * f;
+
+ f = filp_open(filename, flags, mode);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+ fd_install(fd, f);
+ return 0;
}

/*
diff -urN linux-2.1.127/fs/super.c linux/fs/super.c
--- linux-2.1.127/fs/super.c Tue Nov 10 01:36:50 1998
+++ linux/fs/super.c Tue Nov 10 23:11:13 1998
@@ -33,6 +33,7 @@
#include <linux/fd.h>
#include <linux/init.h>
#include <linux/quotaops.h>
+#include <linux/acct.h>

#include <asm/system.h>
#include <asm/uaccess.h>
@@ -663,10 +664,7 @@
* are no quotas running any more. Just turn them on again.
*/
DQUOT_OFF(dev);
-
-#ifdef CONFIG_BSD_PROCESS_ACCT
- (void) acct_auto_close(dev);
-#endif
+ acct_auto_close(dev);

/*
* If we may have to abort operations to get out of this
@@ -971,6 +969,8 @@
*/
shrink_dcache_sb(sb);
fsync_dev(sb->s_dev);
+ if (flags & MS_RDONLY)
+ acct_auto_close(sb->s_dev);
retval = do_remount_sb(sb, flags, data);
}
dput(dentry);
diff -urN linux-2.1.127/include/linux/acct.h linux/include/linux/acct.h
--- linux-2.1.127/include/linux/acct.h Tue Nov 10 23:08:08 1998
+++ linux/include/linux/acct.h Tue Nov 10 23:09:35 1998
@@ -76,8 +76,10 @@
#include <linux/config.h>

#ifdef CONFIG_BSD_PROCESS_ACCT
+extern void acct_auto_close(kdev_t dev);
extern int acct_process(long exitcode);
#else
+#define acct_auto_close(x) do { } while (0)
#define acct_process(x) do { } while (0)
#endif

diff -urN linux-2.1.127/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.1.127/include/linux/fs.h Sat Oct 24 23:30:06 1998
+++ linux/include/linux/fs.h Tue Nov 10 22:46:17 1998
@@ -687,6 +687,7 @@
extern int get_unused_fd(void);
extern void put_unused_fd(unsigned int);
extern int close_fp(struct file *, fl_owner_t id);
+extern struct file *filp_open(const char *, int, int);

extern char * getname(const char * filename);
extern void putname(char * name);
diff -urN linux-2.1.127/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux-2.1.127/include/linux/sysctl.h Tue Nov 10 23:37:58 1998
+++ linux/include/linux/sysctl.h Wed Nov 11 00:58:33 1998
@@ -85,7 +85,8 @@
KERN_PPC_POWERSAVE_NAP, /* use nap mode for power saving */
KERN_PPC_L2CR, /* l2cr register on PPC */
KERN_MODPROBE,
-/*29*/ KERN_SG_BIG_BUFF
+/*29*/ KERN_SG_BIG_BUFF,
+ KERN_ACCT /* BSD process accounting parameters */
};


diff -urN linux-2.1.127/kernel/acct.c linux/kernel/acct.c
--- linux-2.1.127/kernel/acct.c Tue Nov 10 00:33:51 1998
+++ linux/kernel/acct.c Wed Nov 11 00:39:10 1998
@@ -23,6 +23,21 @@
*
* Now we silently close acct_file on attempt to reopen. Cleaned sys_acct().
* XTerms and EMACS are manifestations of pure evil. 21/10/98, AV.
+ *
+ * Fixed a nasty interaction with with sys_umount(). If the accointing
+ * was suspeneded we failed to stop it on umount(). Messy.
+ * Another one: remount to readonly didn't stop accounting.
+ * Question: what should we do if we have CAP_SYS_ADMIN but not
+ * CAP_SYS_PACCT? Current code does the following: umount returns -EBUSY
+ * unless we are messing with the root. In that case we are getting a
+ * real mess with do_remount_sb(). 9/11/98, AV.
+ *
+ * Fixed a bunch of races (and pair of leaks). Probably not the best way,
+ * but this one obviously doesn't introduce deadlocks. Later. BTW, found
+ * one race (and leak) in BSD implementation.
+ * OK, that's better. ANOTHER race and leak in BSD variant. There always
+ * is one more bug... TODO: move filp_open into open.c and make
+ * parameters sysctl-controllable. 10/11/98, AV.
*/

#include <linux/config.h>
@@ -51,11 +66,13 @@
* These constants control the amount of freespace that suspend and
* resume the process accounting system, and the time delay between
* each check.
+ * Turned into sysctl-controllable parameters. AV, 12/11/98
*/

-#define RESUME (4) /* More than 4% free space will resume */
-#define SUSPEND (2) /* Less than 2% free space will suspend */
-#define ACCT_TIMEOUT (30 * HZ) /* 30 second timeout between checks */
+int acct_parm[3] = {4, 2, 30};
+#define RESUME (acct_parm[0]) /* >foo% free space - resume */
+#define SUSPEND (acct_parm[1]) /* <foo% free space - suspend */
+#define ACCT_TIMEOUT (acct_parm[2]) /* foo second timeout between checks */

/*
* External references and all of the globals.
@@ -66,6 +83,7 @@
static volatile int acct_needcheck = 0;
static struct file *acct_file = NULL;
static struct timer_list acct_timer = { NULL, NULL, 0, 0, acct_timeout };
+static int do_acct_process(long, struct file *);

/*
* Called whenever the timer says to check the free space.
@@ -78,39 +96,58 @@
/*
* Check the amount of free space and suspend/resume accordingly.
*/
-static void check_free_space(void)
+static int check_free_space(struct file *file)
{
mm_segment_t fs;
struct statfs sbuf;
struct super_block *sb;
+ int res = acct_active;
+ int act;

- if (!acct_file || !acct_needcheck)
- return;
+ if (!file || !acct_needcheck)
+ return res;

- sb = acct_file->f_dentry->d_inode->i_sb;
+ sb = file->f_dentry->d_inode->i_sb;
if (!sb->s_op || !sb->s_op->statfs)
- return;
+ return res;

fs = get_fs();
set_fs(KERNEL_DS);
+ /* May block */
sb->s_op->statfs(sb, &sbuf, sizeof(struct statfs));
set_fs(fs);

+ if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100)
+ act = -1;
+ else if (sbuf.f_bavail >= RESUME * sbuf.f_blocks / 100)
+ act = 1;
+ else
+ act = 0;
+
+ /*
+ * If some joker switched acct_file under us we'ld better be
+ * silent and _not_ touch anything.
+ */
+ if (file != acct_file)
+ return act ? (act>0) : res;
+
if (acct_active) {
- if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100) {
+ if (act < 0) {
acct_active = 0;
printk(KERN_INFO "Process accounting paused\r\n");
}
} else {
- if (sbuf.f_bavail >= RESUME * sbuf.f_blocks / 100) {
+ if (act > 0) {
acct_active = 1;
printk(KERN_INFO "Process accounting resumed\r\n");
}
}
+
del_timer(&acct_timer);
acct_needcheck = 0;
- acct_timer.expires = jiffies + ACCT_TIMEOUT;
+ acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
add_timer(&acct_timer);
+ return acct_active;
}

/*
@@ -121,9 +158,7 @@
*/
asmlinkage int sys_acct(const char *name)
{
- struct dentry *dentry;
- struct inode *inode;
- struct file_operations *ops;
+ struct file *file = NULL, *old_acct = NULL;
char *tmp;
int error = -EPERM;

@@ -131,82 +166,57 @@
if (!capable(CAP_SYS_PACCT))
goto out;

+ if (name) {
+ tmp = getname(name);
+ error = PTR_ERR(tmp);
+ if (IS_ERR(tmp))
+ goto out;
+ /* Difference from BSD - they don't do O_APPEND */
+ file = filp_open(tmp, O_WRONLY|O_APPEND, 0);
+ putname(tmp);
+ if (IS_ERR(file)) {
+ error = PTR_ERR(file);
+ goto out;
+ }
+ error = -EACCES;
+ if (!S_ISREG(file->f_dentry->d_inode->i_mode))
+ goto out_err;
+
+ error = -EIO;
+ if (!file->f_op->write)
+ goto out_err;
+ }
+
+ error = 0;
if (acct_file) {
- /* fput() may block, so just in case... */
- struct file *tmp = acct_file;
- if (acct_active)
- acct_process(0);
+ old_acct = acct_file;
del_timer(&acct_timer);
acct_active = 0;
acct_needcheck = 0;
acct_file = NULL;
- fput(tmp);
}
- error = 0;
- if (!name) /* We are done */
- goto out;
-
- tmp = getname(name);
- error = PTR_ERR(tmp);
- if (IS_ERR(tmp))
- goto out;
-
- dentry = open_namei(tmp, O_RDWR, 0600);
- putname(tmp);
-
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto out;
-
- inode = dentry->d_inode;
-
- error = -EACCES;
- if (!S_ISREG(inode->i_mode))
- goto out_d;
-
- error = -EIO;
- if (!inode->i_op || !(ops = inode->i_op->default_file_ops) ||
- !ops->write)
- goto out_d;
-
- error = -EUSERS;
- if (!(acct_file = get_empty_filp()))
- goto out_d;
-
- acct_file->f_mode = (O_WRONLY + 1) & O_ACCMODE;
- acct_file->f_flags = O_WRONLY;
- acct_file->f_dentry = dentry;
- acct_file->f_pos = inode->i_size;
- acct_file->f_reada = 0;
- acct_file->f_op = ops;
- error = get_write_access(inode);
- if (error)
- goto out_f;
- if (ops->open)
- error = ops->open(inode, acct_file);
- if (error) {
- put_write_access(inode);
- goto out_f;
+ if (name) {
+ acct_file = file;
+ acct_needcheck = 0;
+ acct_active = 1;
+ acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
+ add_timer(&acct_timer);
+ }
+ if (old_acct) {
+ do_acct_process(0,old_acct);
+ fput(old_acct);
}
- acct_needcheck = 0;
- acct_active = 1;
- acct_timer.expires = jiffies + ACCT_TIMEOUT;
- add_timer(&acct_timer);
- goto out;
-out_f:
- /* decrementing f_count is _not_ enough */
- put_filp(acct_file);
- acct_file = NULL;
-out_d:
- dput(dentry);
out:
unlock_kernel();
return error;
+out_err:
+ fput(file);
+ goto out;
}

void acct_auto_close(kdev_t dev)
{
- if (acct_active && acct_file && acct_file->f_dentry->d_inode->i_dev == dev)
+ if (acct_file && acct_file->f_dentry->d_inode->i_dev == dev)
sys_acct((char *)NULL);
}

@@ -260,7 +270,10 @@
#define KSTK_EIP(stack) (((unsigned long *)(stack))[1019])
#define KSTK_ESP(stack) (((unsigned long *)(stack))[1022])

-int acct_process(long exitcode)
+/*
+ * do_acct_process does all actual work.
+ */
+static int do_acct_process(long exitcode, struct file *file)
{
struct acct ac;
mm_segment_t fs;
@@ -268,14 +281,15 @@

/*
* First check to see if there is enough free_space to continue
- * the process accounting system. Check_free_space toggles the
- * acct_active flag so we need to check that after check_free_space.
+ * the process accounting system.
*/
- check_free_space();
-
- if (!acct_active)
+ if (!file)
return 0;
-
+ file->f_count++;
+ if (!check_free_space(file)) {
+ fput(file);
+ return 0;
+ }

/*
* Fill the accounting struct with the needed info as recorded
@@ -327,10 +341,19 @@
*/
fs = get_fs();
set_fs(KERNEL_DS);
- acct_file->f_op->write(acct_file, (char *)&ac,
- sizeof(struct acct), &acct_file->f_pos);
+ file->f_op->write(file, (char *)&ac,
+ sizeof(struct acct), &file->f_pos);
set_fs(fs);
+ fput(file);
return 0;
+}
+
+/*
+ * acct_process - now just a wrapper around do_acct_process
+ */
+int acct_process(long exitcode)
+{
+ return do_acct_process(exitcode, acct_file);
}

#else
diff -urN linux-2.1.127/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.1.127/kernel/sysctl.c Wed Nov 11 00:59:36 1998
+++ linux/kernel/sysctl.c Wed Nov 11 00:59:54 1998
@@ -58,6 +58,10 @@
void *buffer, size_t *lenp);
#endif

+#ifdef CONFIG_BSD_PROCESS_ACCT
+extern int acct_parm[];
+#endif
+
extern int pgt_cache_water[];

static int parse_table(int *, int, void *, size_t *, void *, size_t,
@@ -192,6 +196,10 @@
#ifdef CONFIG_CHR_DEV_SG
{KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
0444, NULL, &proc_dointvec},
+#endif
+#ifdef CONFIG_BSD_PROCESS_ACCT
+ {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
+ 0644, NULL, &proc_dointvec},
#endif
{0}
};

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:45    [W:0.029 / U:2.480 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site