diff options
author | dg <dg@FreeBSD.org> | 1994-09-26 21:09:15 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1994-09-26 21:09:15 +0000 |
commit | 8369f70aad7baee1d993612bb6daf4826773b601 (patch) | |
tree | 2162a931eb46756da13719b52ffc57f24856425f /sys/kern/kern_acct.c | |
parent | e6f826d5207636b1680f8e1f22e87720481dc64f (diff) | |
download | FreeBSD-src-8369f70aad7baee1d993612bb6daf4826773b601.zip FreeBSD-src-8369f70aad7baee1d993612bb6daf4826773b601.tar.gz |
Process accounting implementation by Chris Demetriou, with minor local
changes.
Obtained from: NetBSD
Diffstat (limited to 'sys/kern/kern_acct.c')
-rw-r--r-- | sys/kern/kern_acct.c | 248 |
1 files changed, 216 insertions, 32 deletions
diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index 95c5660..2360c55 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 1994 Christopher G. Demetriou * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. @@ -35,8 +36,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 - * $Id: kern_acct.c,v 1.3 1994/08/02 07:41:52 davidg Exp $ + * @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 + * $Id$ */ #include <sys/param.h> @@ -47,51 +48,225 @@ #include <sys/file.h> #include <sys/syslog.h> #include <sys/kernel.h> +#include <sys/namei.h> +#include <sys/errno.h> +#include <sys/acct.h> +#include <sys/resourcevar.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +/* + * The routines implemented in this file are described in: + * Leffler, et al.: The Design and Implementation of the 4.3BSD + * UNIX Operating System (Addison Welley, 1989) + * on pages 62-63. + * + * Arguably, to simplify accounting operations, this mechanism should + * be replaced by one in which an accounting log file (similar to /dev/klog) + * is read by a user process, etc. However, that has its own problems. + */ + +/* + * Internal accounting functions. + * The former's operation is described in Leffler, et al., and the latter + * was provided by UCB with the 4.4BSD-Lite release + */ +comp_t encode_comp_t __P((u_long, u_long)); +void acctwatch __P((void *)); + +/* + * Accounting vnode pointer, and saved vnode pointer. + */ +struct vnode *acctp; +struct vnode *savacctp; + +/* + * Values associated with enabling and disabling accounting + */ +int acctsuspend = 2; /* stop accounting when < 2% free space left */ +int acctresume = 4; /* resume when free space risen to > 4% */ +int acctchkfreq = 15; /* frequency (in seconds) to check space */ + +/* + * Accounting system call. Written based on the specification and + * previous implementation done by Mark Tinguely. + */ struct acct_args { - char *fname; + char *path; }; + int -acct(a1, a2, a3) - struct proc *a1; - struct acct_args *a2; - int *a3; +acct(p, uap, retval) + struct proc *p; + struct acct_args *uap; + int *retval; { + struct nameidata nd; + int error; + + /* Make sure that the caller is root. */ + if (error = suser(p->p_ucred, &p->p_acflag)) + return (error); + /* - * Body deleted. + * If accounting is to be started to a file, open that file for + * writing and make sure it's a 'normal'. */ - return (ENOSYS); -} + if (uap->path != NULL) { + NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p); + if (error = vn_open(&nd, FWRITE, 0)) + return (error); + VOP_UNLOCK(nd.ni_vp); + if (nd.ni_vp->v_type != VREG) { + vn_close(nd.ni_vp, FWRITE, p->p_ucred, p); + return (EACCES); + } + } -void -acct_process(a1) - struct proc *a1; -{ + /* + * If accounting was previously enabled, kill the old space-watcher, + * close the file, and (if no new file was specified, leave). + */ + if (acctp != NULLVP || savacctp != NULLVP) { + untimeout(acctwatch, NULL); + error = vn_close((acctp != NULLVP ? acctp : savacctp), FWRITE, + p->p_ucred, p); + acctp = savacctp = NULLVP; + } + if (uap->path == NULL) + return (error); /* - * Body deleted. + * Save the new accounting file vnode, and schedule the new + * free space watcher. */ - return; + acctp = nd.ni_vp; + acctwatch(NULL); + return (error); } /* - * Periodically check the file system to see if accounting - * should be turned on or off. + * Write out process accounting information, on process exit. + * Data to be written out is specified in Leffler, et al. + * and are enumerated below. (They're also noted in the system + * "acct.h" header file.) */ +int +acct_process(p) + struct proc *p; +{ + struct acct acct; + struct rusage *r; + struct timeval ut, st, tmp; + int s, t; + struct vnode *vp; + + /* If accounting isn't enabled, don't bother */ + vp = acctp; + if (vp == NULLVP) + return (0); + + /* + * Get process accounting information. + */ + + /* (1) The name of the command that ran */ + bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm); + + /* (2) The amount of user and system time that was used */ + calcru(p, &ut, &st, NULL); + acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec); + acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); + + /* (3) The elapsed time the commmand ran (and its starting time) */ + acct.ac_btime = p->p_stats->p_start.tv_sec; + s = splclock(); + tmp = time; + splx(s); + timevalsub(&tmp, &p->p_stats->p_start); + acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec); + + /* (4) The average amount of memory used */ + r = &p->p_stats->p_ru; + tmp = ut; + timevaladd(&tmp, &st); + t = tmp.tv_sec * hz + tmp.tv_usec / tick; + if (t) + acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t; + else + acct.ac_mem = 0; + + /* (5) The number of disk I/O operations done */ + acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0); + + /* (6) The UID and GID of the process */ + acct.ac_uid = p->p_cred->p_ruid; + acct.ac_gid = p->p_cred->p_rgid; + + /* (7) The terminal from which the process was started */ + if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) + acct.ac_tty = p->p_pgrp->pg_session->s_ttyp->t_dev; + else + acct.ac_tty = NODEV; + + /* (8) The boolean flags that tell how the process terminated, etc. */ + acct.ac_flag = p->p_acflag; + + /* + * Now, just write the accounting information to the file. + */ + LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + return (vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct), + (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred, + (int *)0, p)); +} + /* - * Values associated with enabling and disabling accounting + * Encode_comp_t converts from ticks in seconds and microseconds + * to ticks in 1/AHZ seconds. The encoding is described in + * Leffler, et al., on page 63. */ -int acctsuspend = 2; /* stop accounting when < 2% free space left */ -int acctresume = 4; /* resume when free space risen to > 4% */ -int acctchkfreq = 15; /* frequency (in seconds) to check space */ + +#define MANTSIZE 13 /* 13 bit mantissa. */ +#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */ +#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */ + +comp_t +encode_comp_t(s, us) + u_long s, us; +{ + int exp, rnd; + + exp = 0; + rnd = 0; + s *= AHZ; + s += us / (1000000 / AHZ); /* Maximize precision. */ + + while (s > MAXFRACT) { + rnd = s & (1 << (EXPSIZE - 1)); /* Round up? */ + s >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */ + exp++; + } + + /* If we need to round up, do it (and handle overflow correctly). */ + if (rnd && (++s > MAXFRACT)) { + s >>= EXPSIZE; + exp++; + } + + /* Clean it up and polish it off. */ + exp <<= MANTSIZE; /* Shift the exponent into place */ + exp += s; /* and add on the mantissa. */ + return (exp); +} /* - * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. + * Periodically check the file system to see if accounting + * should be turned on or off. Beware the case where the vnode + * has been vgone()'d out from underneath us, e.g. when the file + * system containing the accounting file has been forcibly unmounted. */ -struct vnode *acctp; -struct vnode *savacctp; - /* ARGSUSED */ void acctwatch(a) @@ -99,22 +274,31 @@ acctwatch(a) { struct statfs sb; - if (savacctp) { + if (savacctp != NULLVP) { + if (savacctp->v_type == VBAD) { + (void) vn_close(savacctp, FWRITE, NOCRED, NULL); + savacctp = NULLVP; + return; + } (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); if (sb.f_bavail > acctresume * sb.f_blocks / 100) { acctp = savacctp; - savacctp = NULL; + savacctp = NULLVP; log(LOG_NOTICE, "Accounting resumed\n"); } - } else { - if (acctp == NULL) + } else if (acctp != NULLVP) { + if (acctp->v_type == VBAD) { + (void) vn_close(acctp, FWRITE, NOCRED, NULL); + acctp = NULLVP; return; + } (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { savacctp = acctp; - acctp = NULL; + acctp = NULLVP; log(LOG_NOTICE, "Accounting suspended\n"); } - } + } else + return; timeout(acctwatch, NULL, acctchkfreq * hz); } |