11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
5165896Srwatson * Copyright (c) 2005 Robert N. M. Watson
6165896Srwatson * All rights reserved.
7165896Srwatson *
81541Srgrimes * All or some portions of this file are derived from material licensed
91541Srgrimes * to the University of California by American Telephone and Telegraph
101541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
111541Srgrimes * the permission of UNIX System Laboratories, Inc.
121541Srgrimes *
13165896Srwatson * Redistribution and use in source and binary forms, with or without
14165896Srwatson * modification, are permitted provided that the following conditions
15165896Srwatson * are met:
16165896Srwatson * 1. Redistributions of source code must retain the above copyright
17165896Srwatson *    notice, this list of conditions and the following disclaimer.
18165896Srwatson * 2. Redistributions in binary form must reproduce the above copyright
19165896Srwatson *    notice, this list of conditions and the following disclaimer in the
20165896Srwatson *    documentation and/or other materials provided with the distribution.
21165896Srwatson * 4. Neither the name of the University nor the names of its contributors
22165896Srwatson *    may be used to endorse or promote products derived from this software
23165896Srwatson *    without specific prior written permission.
24165896Srwatson *
25165896Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26165896Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27165896Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28165896Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29165896Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30165896Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31165896Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32165896Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33165896Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34165896Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35165896Srwatson * SUCH DAMAGE.
36165896Srwatson *
37152328Srwatson * Copyright (c) 1994 Christopher G. Demetriou
38152328Srwatson *
391541Srgrimes * Redistribution and use in source and binary forms, with or without
401541Srgrimes * modification, are permitted provided that the following conditions
411541Srgrimes * are met:
421541Srgrimes * 1. Redistributions of source code must retain the above copyright
431541Srgrimes *    notice, this list of conditions and the following disclaimer.
441541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
451541Srgrimes *    notice, this list of conditions and the following disclaimer in the
461541Srgrimes *    documentation and/or other materials provided with the distribution.
471541Srgrimes * 3. All advertising materials mentioning features or use of this software
481541Srgrimes *    must display the following acknowledgement:
491541Srgrimes *	This product includes software developed by the University of
501541Srgrimes *	California, Berkeley and its contributors.
511541Srgrimes * 4. Neither the name of the University nor the names of its contributors
521541Srgrimes *    may be used to endorse or promote products derived from this software
531541Srgrimes *    without specific prior written permission.
541541Srgrimes *
551541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
561541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
571541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
581541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
591541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
601541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
611541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
621541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
631541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
641541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
651541Srgrimes * SUCH DAMAGE.
661541Srgrimes *
673124Sdg *	@(#)kern_acct.c	8.1 (Berkeley) 6/14/93
681541Srgrimes */
691541Srgrimes
70116182Sobrien#include <sys/cdefs.h>
71116182Sobrien__FBSDID("$FreeBSD$");
72116182Sobrien
731541Srgrimes#include <sys/param.h>
742807Sbde#include <sys/systm.h>
75155262Sjhb#include <sys/acct.h>
76155262Sjhb#include <sys/fcntl.h>
77155262Sjhb#include <sys/kernel.h>
78155431Sjhb#include <sys/kthread.h>
79172023Sdds#include <sys/limits.h>
8076166Smarkm#include <sys/lock.h>
81155262Sjhb#include <sys/mount.h>
8276166Smarkm#include <sys/mutex.h>
83155262Sjhb#include <sys/namei.h>
84164033Srwatson#include <sys/priv.h>
851541Srgrimes#include <sys/proc.h>
86155262Sjhb#include <sys/resourcevar.h>
87155431Sjhb#include <sys/sched.h>
88152328Srwatson#include <sys/sx.h>
89155262Sjhb#include <sys/sysctl.h>
9022521Sdyson#include <sys/sysent.h>
91155262Sjhb#include <sys/syslog.h>
92155262Sjhb#include <sys/sysproto.h>
933124Sdg#include <sys/tty.h>
94155262Sjhb#include <sys/vnode.h>
951541Srgrimes
96163606Srwatson#include <security/mac/mac_framework.h>
97163606Srwatson
983124Sdg/*
993124Sdg * The routines implemented in this file are described in:
1003124Sdg *      Leffler, et al.: The Design and Implementation of the 4.3BSD
1013124Sdg *	    UNIX Operating System (Addison Welley, 1989)
1023124Sdg * on pages 62-63.
103169857Sdds * On May 2007 the historic 3 bits base 8 exponent, 13 bit fraction
104169857Sdds * compt_t representation described in the above reference was replaced
105169857Sdds * with that of IEEE-754 floats.
1063124Sdg *
1073124Sdg * Arguably, to simplify accounting operations, this mechanism should
1083124Sdg * be replaced by one in which an accounting log file (similar to /dev/klog)
1093124Sdg * is read by a user process, etc.  However, that has its own problems.
1103124Sdg */
1113124Sdg
112169857Sdds/* Floating point definitions from <float.h>. */
113169857Sdds#define FLT_MANT_DIG    24              /* p */
114169857Sdds#define FLT_MAX_EXP     128             /* emax */
115169857Sdds
1163124Sdg/*
1173124Sdg * Internal accounting functions.
1183124Sdg * The former's operation is described in Leffler, et al., and the latter
1193124Sdg * was provided by UCB with the 4.4BSD-Lite release
1203124Sdg */
121169857Sddsstatic uint32_t	encode_timeval(struct timeval);
122169857Sddsstatic uint32_t	encode_long(long);
123155431Sjhbstatic void	acctwatch(void);
124155431Sjhbstatic void	acct_thread(void *);
125234927Sjhbstatic int	acct_disable(struct thread *, int);
1263124Sdg
1273124Sdg/*
128100444Sjohan * Accounting vnode pointer, saved vnode pointer, and flags for each.
129152328Srwatson * acct_sx protects against changes to the active vnode and credentials
130152328Srwatson * while accounting records are being committed to disk.
1313124Sdg */
132162370Srwatsonstatic int		 acct_configured;
133152328Srwatsonstatic int		 acct_suspended;
134152328Srwatsonstatic struct vnode	*acct_vp;
135152328Srwatsonstatic struct ucred	*acct_cred;
136252422Smjgstatic struct plimit	*acct_limit;
137152328Srwatsonstatic int		 acct_flags;
138152328Srwatsonstatic struct sx	 acct_sx;
1393124Sdg
140152328SrwatsonSX_SYSINIT(acct, &acct_sx, "acct_sx");
141103208Sarr
1423124Sdg/*
143155431Sjhb * State of the accounting kthread.
144155431Sjhb */
145155431Sjhbstatic int		 acct_state;
146155431Sjhb
147155431Sjhb#define	ACCT_RUNNING	1	/* Accounting kthread is running. */
148155431Sjhb#define	ACCT_EXITREQ	2	/* Accounting kthread should exit. */
149155431Sjhb
150155431Sjhb/*
1513124Sdg * Values associated with enabling and disabling accounting
1523124Sdg */
15312819Sphkstatic int acctsuspend = 2;	/* stop accounting when < 2% free space left */
15412819SphkSYSCTL_INT(_kern, OID_AUTO, acct_suspend, CTLFLAG_RW,
15562119Snbm	&acctsuspend, 0, "percentage of free disk space below which accounting stops");
1563124Sdg
15712819Sphkstatic int acctresume = 4;	/* resume when free space risen to > 4% */
15812819SphkSYSCTL_INT(_kern, OID_AUTO, acct_resume, CTLFLAG_RW,
15962119Snbm	&acctresume, 0, "percentage of free disk space above which accounting resumes");
16012819Sphk
16112819Sphkstatic int acctchkfreq = 15;	/* frequency (in seconds) to check space */
16212819Sphk
163155438Sjhbstatic int
164155438Sjhbsysctl_acct_chkfreq(SYSCTL_HANDLER_ARGS)
165155438Sjhb{
166155438Sjhb	int error, value;
167155438Sjhb
168155438Sjhb	/* Write out the old value. */
169155438Sjhb	error = SYSCTL_OUT(req, &acctchkfreq, sizeof(int));
170155438Sjhb	if (error || req->newptr == NULL)
171155438Sjhb		return (error);
172155438Sjhb
173155438Sjhb	/* Read in and verify the new value. */
174155438Sjhb	error = SYSCTL_IN(req, &value, sizeof(int));
175155438Sjhb	if (error)
176155438Sjhb		return (error);
177155438Sjhb	if (value <= 0)
178155438Sjhb		return (EINVAL);
179155438Sjhb	acctchkfreq = value;
180155438Sjhb	return (0);
181155438Sjhb}
182155438SjhbSYSCTL_PROC(_kern, OID_AUTO, acct_chkfreq, CTLTYPE_INT|CTLFLAG_RW,
183155438Sjhb    &acctchkfreq, 0, sysctl_acct_chkfreq, "I",
184155438Sjhb    "frequency for checking the free space");
185155438Sjhb
186162370SrwatsonSYSCTL_INT(_kern, OID_AUTO, acct_configured, CTLFLAG_RD, &acct_configured, 0,
187162370Srwatson	"Accounting configured or not");
188162370Srwatson
189152328SrwatsonSYSCTL_INT(_kern, OID_AUTO, acct_suspended, CTLFLAG_RD, &acct_suspended, 0,
190152328Srwatson	"Accounting suspended or not");
191152328Srwatson
1923124Sdg/*
193167211Srwatson * Accounting system call.  Written based on the specification and previous
194167211Srwatson * implementation done by Mark Tinguely.
1953124Sdg */
1961549Srgrimesint
197225617Skmacysys_acct(struct thread *td, struct acct_args *uap)
1981541Srgrimes{
1993124Sdg	struct nameidata nd;
200252422Smjg	int error, flags, i, replacing;
2013124Sdg
202164033Srwatson	error = priv_check(td, PRIV_ACCT);
2033308Sphk	if (error)
20494301Sjhb		return (error);
2053124Sdg
2061541Srgrimes	/*
2073124Sdg	 * If accounting is to be started to a file, open that file for
208157232Sjhb	 * appending and make sure it's a 'normal'.
2091541Srgrimes	 */
210107849Salfred	if (uap->path != NULL) {
211241896Skib		NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1,
212159258Srwatson		    UIO_USERSPACE, uap->path, td);
21399740Sjohan		flags = FWRITE | O_APPEND;
214170152Skib		error = vn_open(&nd, &flags, 0, NULL);
2153308Sphk		if (error)
216157232Sjhb			return (error);
21754655Seivind		NDFREE(&nd, NDF_ONLY_PNBUF);
218106412Srwatson#ifdef MAC
219172930Srwatson		error = mac_system_check_acct(td->td_ucred, nd.ni_vp);
220106412Srwatson		if (error) {
221175294Sattilio			VOP_UNLOCK(nd.ni_vp, 0);
222106412Srwatson			vn_close(nd.ni_vp, flags, td->td_ucred, td);
223157232Sjhb			return (error);
224106412Srwatson		}
225106412Srwatson#endif
226175294Sattilio		VOP_UNLOCK(nd.ni_vp, 0);
2273124Sdg		if (nd.ni_vp->v_type != VREG) {
228100444Sjohan			vn_close(nd.ni_vp, flags, td->td_ucred, td);
229157232Sjhb			return (EACCES);
2303124Sdg		}
231106412Srwatson#ifdef MAC
232106412Srwatson	} else {
233172930Srwatson		error = mac_system_check_acct(td->td_ucred, NULL);
234106412Srwatson		if (error)
235157232Sjhb			return (error);
236106412Srwatson#endif
2373124Sdg	}
2381541Srgrimes
239152328Srwatson	/*
240152328Srwatson	 * Disallow concurrent access to the accounting vnode while we swap
241152328Srwatson	 * it out, in order to prevent access after close.
242152328Srwatson	 */
243152328Srwatson	sx_xlock(&acct_sx);
244126586Sbde
2453124Sdg	/*
246234927Sjhb	 * Don't log spurious disable/enable messages if we are
247234927Sjhb	 * switching from one accounting file to another due to log
248234927Sjhb	 * rotation.
249234927Sjhb	 */
250234927Sjhb	replacing = (acct_vp != NULL && uap->path != NULL);
251234927Sjhb
252234927Sjhb	/*
2533124Sdg	 * If accounting was previously enabled, kill the old space-watcher,
254152328Srwatson	 * close the file, and (if no new file was specified, leave).  Reset
255152328Srwatson	 * the suspended state regardless of whether accounting remains
256152328Srwatson	 * enabled.
2573124Sdg	 */
258152328Srwatson	acct_suspended = 0;
259241896Skib	if (acct_vp != NULL)
260234927Sjhb		error = acct_disable(td, !replacing);
261107849Salfred	if (uap->path == NULL) {
262155431Sjhb		if (acct_state & ACCT_RUNNING) {
263155431Sjhb			acct_state |= ACCT_EXITREQ;
264155431Sjhb			wakeup(&acct_state);
265155431Sjhb		}
266152328Srwatson		sx_xunlock(&acct_sx);
267157232Sjhb		return (error);
268103244Sarr	}
2691541Srgrimes
2701541Srgrimes	/*
271252422Smjg	 * Create our own plimit object without limits. It will be assigned
272252422Smjg	 * to exiting processes.
273252422Smjg	 */
274252422Smjg	acct_limit = lim_alloc();
275252422Smjg	for (i = 0; i < RLIM_NLIMITS; i++)
276252422Smjg		acct_limit->pl_rlimit[i].rlim_cur =
277252422Smjg		    acct_limit->pl_rlimit[i].rlim_max = RLIM_INFINITY;
278252422Smjg
279252422Smjg	/*
2803124Sdg	 * Save the new accounting file vnode, and schedule the new
2813124Sdg	 * free space watcher.
2821541Srgrimes	 */
283152328Srwatson	acct_vp = nd.ni_vp;
284152328Srwatson	acct_cred = crhold(td->td_ucred);
285152328Srwatson	acct_flags = flags;
286155431Sjhb	if (acct_state & ACCT_RUNNING)
287155431Sjhb		acct_state &= ~ACCT_EXITREQ;
288155431Sjhb	else {
289155431Sjhb		/*
290155431Sjhb		 * Try to start up an accounting kthread.  We may start more
291155431Sjhb		 * than one, but if so the extras will commit suicide as
292155431Sjhb		 * soon as they start up.
293155431Sjhb		 */
294172836Sjulian		error = kproc_create(acct_thread, NULL, NULL, 0, 0,
295155431Sjhb		    "accounting");
296155431Sjhb		if (error) {
297252415Smjg			(void) acct_disable(td, 0);
298155431Sjhb			sx_xunlock(&acct_sx);
299155431Sjhb			log(LOG_NOTICE, "Unable to start accounting thread\n");
300157232Sjhb			return (error);
301155431Sjhb		}
302155431Sjhb	}
303162370Srwatson	acct_configured = 1;
304152328Srwatson	sx_xunlock(&acct_sx);
305234927Sjhb	if (!replacing)
306234927Sjhb		log(LOG_NOTICE, "Accounting enabled\n");
3073124Sdg	return (error);
3081541Srgrimes}
3091541Srgrimes
3101541Srgrimes/*
311155431Sjhb * Disable currently in-progress accounting by closing the vnode, dropping
312155431Sjhb * our reference to the credential, and clearing the vnode's flags.
313155431Sjhb */
314155431Sjhbstatic int
315234927Sjhbacct_disable(struct thread *td, int logging)
316155431Sjhb{
317155431Sjhb	int error;
318155431Sjhb
319155431Sjhb	sx_assert(&acct_sx, SX_XLOCKED);
320155431Sjhb	error = vn_close(acct_vp, acct_flags, acct_cred, td);
321155431Sjhb	crfree(acct_cred);
322252422Smjg	lim_free(acct_limit);
323162370Srwatson	acct_configured = 0;
324155431Sjhb	acct_vp = NULL;
325155431Sjhb	acct_cred = NULL;
326155431Sjhb	acct_flags = 0;
327234927Sjhb	if (logging)
328234927Sjhb		log(LOG_NOTICE, "Accounting disabled\n");
329155431Sjhb	return (error);
330155431Sjhb}
331155431Sjhb
332155431Sjhb/*
3333124Sdg * Write out process accounting information, on process exit.
3343124Sdg * Data to be written out is specified in Leffler, et al.
3353124Sdg * and are enumerated below.  (They're also noted in the system
3363124Sdg * "acct.h" header file.)
3371541Srgrimes */
3383124Sdgint
339152328Srwatsonacct_process(struct thread *td)
3403124Sdg{
341169857Sdds	struct acctv2 acct;
342126586Sbde	struct timeval ut, st, tmp;
343252422Smjg	struct plimit *oldlim;
344126586Sbde	struct proc *p;
345170174Sjeff	struct rusage ru;
346241896Skib	int t, ret;
3473124Sdg
348139895Srwatson	/*
349139895Srwatson	 * Lockless check of accounting condition before doing the hard
350139895Srwatson	 * work.
351139895Srwatson	 */
352152328Srwatson	if (acct_vp == NULL || acct_suspended)
353139895Srwatson		return (0);
354139895Srwatson
355152328Srwatson	sx_slock(&acct_sx);
356103208Sarr
357139895Srwatson	/*
358139895Srwatson	 * If accounting isn't enabled, don't bother.  Have to check again
359139895Srwatson	 * once we own the lock in case we raced with disabling of accounting
360139895Srwatson	 * by another thread.
361139895Srwatson	 */
362152328Srwatson	if (acct_vp == NULL || acct_suspended) {
363152328Srwatson		sx_sunlock(&acct_sx);
3643124Sdg		return (0);
365103208Sarr	}
3663124Sdg
367126586Sbde	p = td->td_proc;
368126586Sbde
3693124Sdg	/*
3703124Sdg	 * Get process accounting information.
3713124Sdg	 */
3723124Sdg
373181963Sed	sx_slock(&proctree_lock);
374113624Sjhb	PROC_LOCK(p);
375181963Sed
376181963Sed	/* (1) The terminal from which the process was started */
377181963Sed	if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp)
378181963Sed		acct.ac_tty = tty_udev(p->p_pgrp->pg_session->s_ttyp);
379181963Sed	else
380181963Sed		acct.ac_tty = NODEV;
381181963Sed	sx_sunlock(&proctree_lock);
382181963Sed
383181963Sed	/* (2) The name of the command that ran */
3843124Sdg	bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm);
3853124Sdg
386181963Sed	/* (3) The amount of user and system time that was used */
387170472Sattilio	rufetchcalc(p, &ru, &ut, &st);
388169857Sdds	acct.ac_utime = encode_timeval(ut);
389169857Sdds	acct.ac_stime = encode_timeval(st);
3903124Sdg
391181963Sed	/* (4) The elapsed time the command ran (and its starting time) */
392114434Sdes	tmp = boottime;
393114434Sdes	timevaladd(&tmp, &p->p_stats->p_start);
394114434Sdes	acct.ac_btime = tmp.tv_sec;
395114434Sdes	microuptime(&tmp);
3963124Sdg	timevalsub(&tmp, &p->p_stats->p_start);
397169857Sdds	acct.ac_etime = encode_timeval(tmp);
3983124Sdg
399181963Sed	/* (5) The average amount of memory used */
4003124Sdg	tmp = ut;
4013124Sdg	timevaladd(&tmp, &st);
402169857Sdds	/* Convert tmp (i.e. u + s) into hz units to match ru_i*. */
4033124Sdg	t = tmp.tv_sec * hz + tmp.tv_usec / tick;
4043124Sdg	if (t)
405170174Sjeff		acct.ac_mem = encode_long((ru.ru_ixrss + ru.ru_idrss +
406170174Sjeff		    + ru.ru_isrss) / t);
4073124Sdg	else
4083124Sdg		acct.ac_mem = 0;
4093124Sdg
410181963Sed	/* (6) The number of disk I/O operations done */
411170174Sjeff	acct.ac_io = encode_long(ru.ru_inblock + ru.ru_oublock);
4123124Sdg
413181963Sed	/* (7) The UID and GID of the process */
41477183Srwatson	acct.ac_uid = p->p_ucred->cr_ruid;
41577183Srwatson	acct.ac_gid = p->p_ucred->cr_rgid;
4163124Sdg
4173124Sdg	/* (8) The boolean flags that tell how the process terminated, etc. */
418169857Sdds	acct.ac_flagx = p->p_acflag;
4193124Sdg
420169857Sdds	/* Setup ancillary structure fields. */
421169857Sdds	acct.ac_flagx |= ANVER;
422169857Sdds	acct.ac_zero = 0;
423169857Sdds	acct.ac_version = 2;
424169857Sdds	acct.ac_len = acct.ac_len2 = sizeof(acct);
425169857Sdds
4263124Sdg	/*
427252422Smjg	 * Eliminate rlimits (file size limit in particular).
4283124Sdg	 */
429125454Sjhb	oldlim = p->p_limit;
430252422Smjg	p->p_limit = lim_hold(acct_limit);
431125454Sjhb	PROC_UNLOCK(p);
432125454Sjhb	lim_free(oldlim);
43336676Sdg
434126586Sbde	/*
435126586Sbde	 * Write the accounting information to the file.
436126586Sbde	 */
437152328Srwatson	ret = vn_rdwr(UIO_WRITE, acct_vp, (caddr_t)&acct, sizeof (acct),
438152328Srwatson	    (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, acct_cred, NOCRED,
439194296Skib	    NULL, td);
440152328Srwatson	sx_sunlock(&acct_sx);
441103208Sarr	return (ret);
4423124Sdg}
4433124Sdg
444169857Sdds/* FLOAT_CONVERSION_START (Regression testing; don't remove this line.) */
445169857Sdds
446169857Sdds/* Convert timevals and longs into IEEE-754 bit patterns. */
447169857Sdds
448169857Sdds/* Mantissa mask (MSB is implied, so subtract 1). */
449169857Sdds#define MANT_MASK ((1 << (FLT_MANT_DIG - 1)) - 1)
450169857Sdds
4511541Srgrimes/*
452169857Sdds * We calculate integer values to a precision of approximately
453169857Sdds * 28 bits.
454169857Sdds * This is high-enough precision to fill the 24 float bits
455169857Sdds * and low-enough to avoid overflowing the 32 int bits.
4561541Srgrimes */
457169857Sdds#define CALC_BITS 28
4581541Srgrimes
459169857Sdds/* log_2(1000000). */
460169857Sdds#define LOG2_1M 20
4613124Sdg
462169857Sdds/*
463169857Sdds * Convert the elements of a timeval into a 32-bit word holding
464169857Sdds * the bits of a IEEE-754 float.
465169857Sdds * The float value represents the timeval's value in microsecond units.
466169857Sdds */
467169857Sddsstatic uint32_t
468169857Sddsencode_timeval(struct timeval tv)
4693124Sdg{
470169857Sdds	int log2_s;
471169857Sdds	int val, exp;	/* Unnormalized value and exponent */
472169857Sdds	int norm_exp;	/* Normalized exponent */
473169857Sdds	int shift;
4743124Sdg
475169857Sdds	/*
476169857Sdds	 * First calculate value and exponent to about CALC_BITS precision.
477169857Sdds	 * Note that the following conditionals have been ordered so that
478169857Sdds	 * the most common cases appear first.
479169857Sdds	 */
480169857Sdds	if (tv.tv_sec == 0) {
481169857Sdds		if (tv.tv_usec == 0)
482169857Sdds			return (0);
483169857Sdds		exp = 0;
484169857Sdds		val = tv.tv_usec;
485169857Sdds	} else {
486169857Sdds		/*
487169857Sdds		 * Calculate the value to a precision of approximately
488169857Sdds		 * CALC_BITS.
489169857Sdds		 */
490169857Sdds		log2_s = fls(tv.tv_sec) - 1;
491169857Sdds		if (log2_s + LOG2_1M < CALC_BITS) {
492169857Sdds			exp = 0;
493169857Sdds			val = 1000000 * tv.tv_sec + tv.tv_usec;
494169857Sdds		} else {
495169857Sdds			exp = log2_s + LOG2_1M - CALC_BITS;
496209390Sed			val = (unsigned int)(((uint64_t)1000000 * tv.tv_sec +
497169857Sdds			    tv.tv_usec) >> exp);
498169857Sdds		}
4993124Sdg	}
500169857Sdds	/* Now normalize and pack the value into an IEEE-754 float. */
501169857Sdds	norm_exp = fls(val) - 1;
502169857Sdds	shift = FLT_MANT_DIG - norm_exp - 1;
503169857Sdds#ifdef ACCT_DEBUG
504169857Sdds	printf("val=%d exp=%d shift=%d log2(val)=%d\n",
505169857Sdds	    val, exp, shift, norm_exp);
506169857Sdds	printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp,
507169857Sdds	    ((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK));
508169857Sdds#endif
509169857Sdds	return (((FLT_MAX_EXP - 1 + exp + norm_exp) << (FLT_MANT_DIG - 1)) |
510169857Sdds	    ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
511169857Sdds}
5123124Sdg
513169857Sdds/*
514169857Sdds * Convert a non-negative long value into the bit pattern of
515169857Sdds * an IEEE-754 float value.
516169857Sdds */
517169857Sddsstatic uint32_t
518169857Sddsencode_long(long val)
519169857Sdds{
520169857Sdds	int norm_exp;	/* Normalized exponent */
521169857Sdds	int shift;
5223124Sdg
523169857Sdds	if (val == 0)
524169857Sdds		return (0);
525172023Sdds	if (val < 0) {
526172023Sdds		log(LOG_NOTICE,
527172024Sdds		    "encode_long: negative value %ld in accounting record\n",
528172023Sdds		    val);
529172023Sdds		val = LONG_MAX;
530172023Sdds	}
531169857Sdds	norm_exp = fls(val) - 1;
532169857Sdds	shift = FLT_MANT_DIG - norm_exp - 1;
533169857Sdds#ifdef ACCT_DEBUG
534169857Sdds	printf("val=%d shift=%d log2(val)=%d\n",
535169857Sdds	    val, shift, norm_exp);
536169857Sdds	printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp,
537169857Sdds	    ((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK));
538169857Sdds#endif
539169857Sdds	return (((FLT_MAX_EXP - 1 + norm_exp) << (FLT_MANT_DIG - 1)) |
540169857Sdds	    ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
5413124Sdg}
5423124Sdg
543169857Sdds/* FLOAT_CONVERSION_END (Regression testing; don't remove this line.) */
544169857Sdds
5451541Srgrimes/*
54696755Strhodes * Periodically check the filesystem to see if accounting
5473124Sdg * should be turned on or off.  Beware the case where the vnode
5483124Sdg * has been vgone()'d out from underneath us, e.g. when the file
5493124Sdg * system containing the accounting file has been forcibly unmounted.
5501541Srgrimes */
5511541Srgrimes/* ARGSUSED */
55212819Sphkstatic void
553155431Sjhbacctwatch(void)
5541541Srgrimes{
5551541Srgrimes	struct statfs sb;
5561541Srgrimes
557155431Sjhb	sx_assert(&acct_sx, SX_XLOCKED);
558155431Sjhb
559155431Sjhb	/*
560155431Sjhb	 * If accounting was disabled before our kthread was scheduled,
561155431Sjhb	 * then acct_vp might be NULL.  If so, just ask our kthread to
562155431Sjhb	 * exit and return.
563155431Sjhb	 */
564155431Sjhb	if (acct_vp == NULL) {
565155431Sjhb		acct_state |= ACCT_EXITREQ;
566155431Sjhb		return;
567155431Sjhb	}
568155431Sjhb
569155431Sjhb	/*
570155431Sjhb	 * If our vnode is no longer valid, tear it down and signal the
571155431Sjhb	 * accounting thread to die.
572155431Sjhb	 */
573152328Srwatson	if (acct_vp->v_type == VBAD) {
574234927Sjhb		(void) acct_disable(NULL, 1);
575155431Sjhb		acct_state |= ACCT_EXITREQ;
576152328Srwatson		return;
577152328Srwatson	}
578155431Sjhb
579103244Sarr	/*
580152328Srwatson	 * Stopping here is better than continuing, maybe it will be VBAD
581152328Srwatson	 * next time around.
582112209Sjhb	 */
583241896Skib	if (VFS_STATFS(acct_vp->v_mount, &sb) < 0)
584152328Srwatson		return;
585152328Srwatson	if (acct_suspended) {
586152328Srwatson		if (sb.f_bavail > (int64_t)(acctresume * sb.f_blocks /
587152328Srwatson		    100)) {
588152328Srwatson			acct_suspended = 0;
5891541Srgrimes			log(LOG_NOTICE, "Accounting resumed\n");
5901541Srgrimes		}
59122521Sdyson	} else {
592152328Srwatson		if (sb.f_bavail <= (int64_t)(acctsuspend * sb.f_blocks /
593152328Srwatson		    100)) {
594152328Srwatson			acct_suspended = 1;
5951541Srgrimes			log(LOG_NOTICE, "Accounting suspended\n");
5961541Srgrimes		}
59722521Sdyson	}
598155431Sjhb}
599155431Sjhb
600155431Sjhb/*
601155431Sjhb * The main loop for the dedicated kernel thread that periodically calls
602155431Sjhb * acctwatch().
603155431Sjhb */
604155431Sjhbstatic void
605155431Sjhbacct_thread(void *dummy)
606155431Sjhb{
607155431Sjhb	u_char pri;
608155431Sjhb
609155431Sjhb	/* This is a low-priority kernel thread. */
610155431Sjhb	pri = PRI_MAX_KERN;
611170307Sjeff	thread_lock(curthread);
612155431Sjhb	sched_prio(curthread, pri);
613170307Sjeff	thread_unlock(curthread);
614155431Sjhb
615155431Sjhb	/* If another accounting kthread is already running, just die. */
616155431Sjhb	sx_xlock(&acct_sx);
617155431Sjhb	if (acct_state & ACCT_RUNNING) {
618155431Sjhb		sx_xunlock(&acct_sx);
619172836Sjulian		kproc_exit(0);
620155431Sjhb	}
621155431Sjhb	acct_state |= ACCT_RUNNING;
622155431Sjhb
623155431Sjhb	/* Loop until we are asked to exit. */
624155431Sjhb	while (!(acct_state & ACCT_EXITREQ)) {
625155431Sjhb
626155431Sjhb		/* Perform our periodic checks. */
627155431Sjhb		acctwatch();
628155431Sjhb
629155431Sjhb		/*
630155431Sjhb		 * We check this flag again before sleeping since the
631155431Sjhb		 * acctwatch() might have shut down accounting and asked us
632155431Sjhb		 * to exit.
633155431Sjhb		 */
634155431Sjhb		if (!(acct_state & ACCT_EXITREQ)) {
635167389Sjhb			sx_sleep(&acct_state, &acct_sx, 0, "-",
636167389Sjhb			    acctchkfreq * hz);
637155431Sjhb		}
638155431Sjhb	}
639155431Sjhb
640155431Sjhb	/*
641155431Sjhb	 * Acknowledge the exit request and shutdown.  We clear both the
642155431Sjhb	 * exit request and running flags.
643155431Sjhb	 */
644155431Sjhb	acct_state = 0;
645152328Srwatson	sx_xunlock(&acct_sx);
646172836Sjulian	kproc_exit(0);
6471541Srgrimes}
648