convert VOP_UNLOCK and vrele into vput's; add proc parameter to union_dircache
[unix-history] / usr / src / sys / kern / kern_acct.c
CommitLineData
8c0dbd1c 1/*-
b435ea85
KB
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
adb35f79
KB
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
8c0dbd1c
KB
9 *
10 * %sccs.include.proprietary.c%
da7c5cc6 11 *
4d3806d9 12 * @(#)kern_acct.c 8.8 (Berkeley) %G%
da7c5cc6 13 */
06138e31 14
38a01dbe
KB
15#include <sys/param.h>
16#include <sys/systm.h>
17#include <sys/namei.h>
18#include <sys/resourcevar.h>
19#include <sys/proc.h>
20#include <sys/ioctl.h>
21#include <sys/termios.h>
22#include <sys/tty.h>
23#include <sys/vnode.h>
24#include <sys/mount.h>
25#include <sys/kernel.h>
26#include <sys/file.h>
27#include <sys/acct.h>
28#include <sys/syslog.h>
7dcb2b7d 29#include <sys/syscallargs.h>
c4ec2128
KM
30
31/*
32 * Values associated with enabling and disabling accounting
33 */
34int acctsuspend = 2; /* stop accounting when < 2% free space left */
35int acctresume = 4; /* resume when free space risen to > 4% */
1e613993 36int acctchkfreq = 15; /* frequency (in seconds) to check space */
06138e31
SL
37
38/*
39 * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
40 */
c4ec2128
KM
41struct vnode *acctp;
42struct vnode *savacctp;
06138e31
SL
43
44/*
02cf434b
KM
45 * Enable or disable process accounting.
46 *
47 * If a non-null filename is given, that file is used to store accounting
48 * records on process exit. If a null filename is given process accounting
49 * is suspended. If accounting is enabled, the system checks the amount
50 * of freespace on the filesystem at timeval intervals. If the amount of
51 * freespace is below acctsuspend percent, accounting is suspended. If
52 * accounting has been suspended, and freespace rises above acctresume,
53 * accounting is resumed.
06138e31 54 */
fc0be3ee 55acct(p, uap, retval)
8c7d0e2a 56 struct proc *p;
7dcb2b7d
CD
57 struct acct_args /* {
58 syscallarg(char *) path;
59 } */ *uap;
60 register_t *retval;
06138e31 61{
c4ec2128 62 register struct vnode *vp;
f02cb652 63 extern void acctwatch __P((void *));
c4ec2128 64 struct vnode *oacctp;
8c7d0e2a 65 int error;
3789a403 66 struct nameidata nd;
06138e31 67
3789a403 68 if (error = suser(p->p_ucred, &p->p_acflag))
d9c2f47f 69 return (error);
849cbd39
KM
70 if (savacctp) {
71 acctp = savacctp;
72 savacctp = NULL;
73 }
7dcb2b7d 74 if (SCARG(uap, path) == NULL) {
c4ec2128 75 if (vp = acctp) {
849cbd39 76 acctp = NULL;
79583d0d 77 error = vn_close(vp, FWRITE, p->p_ucred, p);
f02cb652 78 untimeout(acctwatch, NULL);
dbba2129 79 }
79583d0d 80 return (error);
849cbd39 81 }
7dcb2b7d 82 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
9e7d3651 83 if (error = vn_open(&nd, FWRITE, 0644))
d9c2f47f 84 return (error);
3789a403 85 vp = nd.ni_vp;
4d3806d9 86 VOP_UNLOCK(vp, 0, p);
c4ec2128 87 if (vp->v_type != VREG) {
79583d0d 88 (void) vn_close(vp, FWRITE, p->p_ucred, p);
d9c2f47f 89 return (EACCES);
849cbd39 90 }
c4ec2128
KM
91 oacctp = acctp;
92 acctp = vp;
93 if (oacctp)
79583d0d 94 error = vn_close(oacctp, FWRITE, p->p_ucred, p);
f02cb652 95 acctwatch(NULL);
79583d0d 96 return (error);
06138e31
SL
97}
98
06138e31 99/*
c4ec2128 100 * Periodically check the file system to see if accounting
5ad4fbbd
KM
101 * should be turned on or off. Beware the case where the vnode
102 * has been vgone()'d out from underneath us, e.g. when the file
103 * system containing the accounting file has been forcibly unmounted.
06138e31 104 */
f02cb652
CT
105/* ARGSUSED */
106void
107acctwatch(a)
108 void *a;
06138e31 109{
c4ec2128 110 struct statfs sb;
06138e31
SL
111
112 if (savacctp) {
5ad4fbbd
KM
113 if (savacctp->v_type == VBAD) {
114 (void) vn_close(savacctp, FWRITE, NOCRED, NULL);
115 savacctp = NULL;
116 return;
117 }
6bcdc4f3 118 (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
c4ec2128 119 if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
06138e31
SL
120 acctp = savacctp;
121 savacctp = NULL;
c4ec2128 122 log(LOG_NOTICE, "Accounting resumed\n");
1e613993
KM
123 }
124 } else {
125 if (acctp == NULL)
c4ec2128 126 return;
5ad4fbbd
KM
127 if (acctp->v_type == VBAD) {
128 (void) vn_close(acctp, FWRITE, NOCRED, NULL);
129 acctp = NULL;
130 return;
131 }
1e613993
KM
132 (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
133 if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
134 savacctp = acctp;
135 acctp = NULL;
136 log(LOG_NOTICE, "Accounting suspended\n");
06138e31
SL
137 }
138 }
1e613993 139 timeout(acctwatch, NULL, acctchkfreq * hz);
c4ec2128
KM
140}
141
142/*
02cf434b
KM
143 * This routine calculates an accounting record for a process and,
144 * if accounting is enabled, writes it to the accounting file.
c4ec2128 145 */
fc0be3ee 146acct_process(p)
8c7d0e2a 147 register struct proc *p;
c4ec2128
KM
148{
149 register struct rusage *ru;
150 struct vnode *vp;
1cab08e7 151 struct timeval t, ut, st;
6b8f7051 152 int error, i, s;
c4ec2128
KM
153 struct acct acctbuf;
154 register struct acct *ap = &acctbuf;
155
6b8f7051
JSP
156 s = splclock();
157 if ((vp = acctp) == NULL) {
158 splx(s);
8c7d0e2a 159 return (0);
6b8f7051 160 }
5ad4fbbd
KM
161 if (vp->v_type == VBAD) {
162 (void) vn_close(vp, FWRITE, NOCRED, NULL);
163 acctp = NULL;
6b8f7051 164 splx(s);
5ad4fbbd
KM
165 return (0);
166 }
1cab08e7 167 bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm));
3789a403 168 ru = &p->p_stats->p_ru;
f02cb652 169 calcru(p, &ut, &st, NULL);
032146e9 170 t = time;
1cab08e7
MT
171 ap->ac_utime = compress(ut.tv_sec, ut.tv_usec);
172 ap->ac_stime = compress(st.tv_sec, st.tv_usec);
3789a403 173 timevalsub(&t, &p->p_stats->p_start);
032146e9 174 ap->ac_etime = compress(t.tv_sec, t.tv_usec);
3789a403
MK
175 ap->ac_btime = p->p_stats->p_start.tv_sec;
176 ap->ac_uid = p->p_cred->p_ruid;
177 ap->ac_gid = p->p_cred->p_rgid;
1cab08e7
MT
178 t = st;
179 timevaladd(&t, &ut);
350f5463 180 if (i = t.tv_sec * hz + t.tv_usec / tick)
3789a403 181 ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i;
032146e9
SL
182 else
183 ap->ac_mem = 0;
01b0e233 184 ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
cf5ef508 185 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyp)
1cab08e7 186 ap->ac_tty = p->p_session->s_ttyp->t_dev;
06138e31
SL
187 else
188 ap->ac_tty = NODEV;
3789a403 189 ap->ac_flag = p->p_acflag;
4c5d3e43 190 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
6b8f7051 191 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0,
6bcdc4f3 192 UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0,
6b8f7051
JSP
193 (struct proc *)0);
194 splx(s);
195 return (error);
06138e31
SL
196}
197
198/*
199 * Produce a pseudo-floating point representation
200 * with 3 bits base-8 exponent, 13 bits fraction.
201 */
032146e9 202compress(t, ut)
06138e31 203 register long t;
032146e9 204 long ut;
06138e31
SL
205{
206 register exp = 0, round = 0;
207
5d10e647 208 t = t * AHZ; /* compiler will convert only this format to a shift */
032146e9 209 if (ut)
5d10e647 210 t += ut / (1000000 / AHZ);
06138e31
SL
211 while (t >= 8192) {
212 exp++;
213 round = t&04;
214 t >>= 3;
215 }
216 if (round) {
217 t++;
218 if (t >= 8192) {
219 t >>= 3;
220 exp++;
221 }
222 }
223 return ((exp<<13) + t);
224}