Messages in this thread Patch in this message | | | Date | Wed, 11 Nov 1998 09:32:34 -0500 (EST) | From | Alexander Viro <> | 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/
| |