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