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: stable/11/sys/kern/kern_acct.c 311957 2017-01-12 01:09:15Z kib $"); 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> 81311957Skib#include <sys/malloc.h> 82155262Sjhb#include <sys/mount.h> 8376166Smarkm#include <sys/mutex.h> 84155262Sjhb#include <sys/namei.h> 85164033Srwatson#include <sys/priv.h> 861541Srgrimes#include <sys/proc.h> 87155262Sjhb#include <sys/resourcevar.h> 88155431Sjhb#include <sys/sched.h> 89152328Srwatson#include <sys/sx.h> 90155262Sjhb#include <sys/sysctl.h> 9122521Sdyson#include <sys/sysent.h> 92155262Sjhb#include <sys/syslog.h> 93155262Sjhb#include <sys/sysproto.h> 943124Sdg#include <sys/tty.h> 95155262Sjhb#include <sys/vnode.h> 961541Srgrimes 97163606Srwatson#include <security/mac/mac_framework.h> 98163606Srwatson 993124Sdg/* 1003124Sdg * The routines implemented in this file are described in: 1013124Sdg * Leffler, et al.: The Design and Implementation of the 4.3BSD 1023124Sdg * UNIX Operating System (Addison Welley, 1989) 1033124Sdg * on pages 62-63. 104169857Sdds * On May 2007 the historic 3 bits base 8 exponent, 13 bit fraction 105169857Sdds * compt_t representation described in the above reference was replaced 106169857Sdds * with that of IEEE-754 floats. 1073124Sdg * 1083124Sdg * Arguably, to simplify accounting operations, this mechanism should 1093124Sdg * be replaced by one in which an accounting log file (similar to /dev/klog) 1103124Sdg * is read by a user process, etc. However, that has its own problems. 1113124Sdg */ 1123124Sdg 113169857Sdds/* Floating point definitions from <float.h>. */ 114169857Sdds#define FLT_MANT_DIG 24 /* p */ 115169857Sdds#define FLT_MAX_EXP 128 /* emax */ 116169857Sdds 1173124Sdg/* 1183124Sdg * Internal accounting functions. 1193124Sdg * The former's operation is described in Leffler, et al., and the latter 1203124Sdg * was provided by UCB with the 4.4BSD-Lite release 1213124Sdg */ 122169857Sddsstatic uint32_t encode_timeval(struct timeval); 123169857Sddsstatic uint32_t encode_long(long); 124155431Sjhbstatic void acctwatch(void); 125155431Sjhbstatic void acct_thread(void *); 126234927Sjhbstatic int acct_disable(struct thread *, int); 1273124Sdg 1283124Sdg/* 129100444Sjohan * Accounting vnode pointer, saved vnode pointer, and flags for each. 130152328Srwatson * acct_sx protects against changes to the active vnode and credentials 131152328Srwatson * while accounting records are being committed to disk. 1323124Sdg */ 133162370Srwatsonstatic int acct_configured; 134152328Srwatsonstatic int acct_suspended; 135152328Srwatsonstatic struct vnode *acct_vp; 136152328Srwatsonstatic struct ucred *acct_cred; 137252422Smjgstatic struct plimit *acct_limit; 138152328Srwatsonstatic int acct_flags; 139152328Srwatsonstatic struct sx acct_sx; 1403124Sdg 141152328SrwatsonSX_SYSINIT(acct, &acct_sx, "acct_sx"); 142103208Sarr 1433124Sdg/* 144155431Sjhb * State of the accounting kthread. 145155431Sjhb */ 146155431Sjhbstatic int acct_state; 147155431Sjhb 148155431Sjhb#define ACCT_RUNNING 1 /* Accounting kthread is running. */ 149155431Sjhb#define ACCT_EXITREQ 2 /* Accounting kthread should exit. */ 150155431Sjhb 151155431Sjhb/* 1523124Sdg * Values associated with enabling and disabling accounting 1533124Sdg */ 15412819Sphkstatic int acctsuspend = 2; /* stop accounting when < 2% free space left */ 15512819SphkSYSCTL_INT(_kern, OID_AUTO, acct_suspend, CTLFLAG_RW, 15662119Snbm &acctsuspend, 0, "percentage of free disk space below which accounting stops"); 1573124Sdg 15812819Sphkstatic int acctresume = 4; /* resume when free space risen to > 4% */ 15912819SphkSYSCTL_INT(_kern, OID_AUTO, acct_resume, CTLFLAG_RW, 16062119Snbm &acctresume, 0, "percentage of free disk space above which accounting resumes"); 16112819Sphk 16212819Sphkstatic int acctchkfreq = 15; /* frequency (in seconds) to check space */ 16312819Sphk 164155438Sjhbstatic int 165155438Sjhbsysctl_acct_chkfreq(SYSCTL_HANDLER_ARGS) 166155438Sjhb{ 167155438Sjhb int error, value; 168155438Sjhb 169155438Sjhb /* Write out the old value. */ 170155438Sjhb error = SYSCTL_OUT(req, &acctchkfreq, sizeof(int)); 171155438Sjhb if (error || req->newptr == NULL) 172155438Sjhb return (error); 173155438Sjhb 174155438Sjhb /* Read in and verify the new value. */ 175155438Sjhb error = SYSCTL_IN(req, &value, sizeof(int)); 176155438Sjhb if (error) 177155438Sjhb return (error); 178155438Sjhb if (value <= 0) 179155438Sjhb return (EINVAL); 180155438Sjhb acctchkfreq = value; 181155438Sjhb return (0); 182155438Sjhb} 183155438SjhbSYSCTL_PROC(_kern, OID_AUTO, acct_chkfreq, CTLTYPE_INT|CTLFLAG_RW, 184155438Sjhb &acctchkfreq, 0, sysctl_acct_chkfreq, "I", 185155438Sjhb "frequency for checking the free space"); 186155438Sjhb 187162370SrwatsonSYSCTL_INT(_kern, OID_AUTO, acct_configured, CTLFLAG_RD, &acct_configured, 0, 188162370Srwatson "Accounting configured or not"); 189162370Srwatson 190152328SrwatsonSYSCTL_INT(_kern, OID_AUTO, acct_suspended, CTLFLAG_RD, &acct_suspended, 0, 191152328Srwatson "Accounting suspended or not"); 192152328Srwatson 1933124Sdg/* 194167211Srwatson * Accounting system call. Written based on the specification and previous 195167211Srwatson * implementation done by Mark Tinguely. 1963124Sdg */ 1971549Srgrimesint 198225617Skmacysys_acct(struct thread *td, struct acct_args *uap) 1991541Srgrimes{ 2003124Sdg struct nameidata nd; 201252422Smjg int error, flags, i, replacing; 2023124Sdg 203164033Srwatson error = priv_check(td, PRIV_ACCT); 2043308Sphk if (error) 20594301Sjhb return (error); 2063124Sdg 2071541Srgrimes /* 2083124Sdg * If accounting is to be started to a file, open that file for 209157232Sjhb * appending and make sure it's a 'normal'. 2101541Srgrimes */ 211107849Salfred if (uap->path != NULL) { 212241896Skib NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, 213159258Srwatson UIO_USERSPACE, uap->path, td); 21499740Sjohan flags = FWRITE | O_APPEND; 215170152Skib error = vn_open(&nd, &flags, 0, NULL); 2163308Sphk if (error) 217157232Sjhb return (error); 21854655Seivind NDFREE(&nd, NDF_ONLY_PNBUF); 219106412Srwatson#ifdef MAC 220172930Srwatson error = mac_system_check_acct(td->td_ucred, nd.ni_vp); 221106412Srwatson if (error) { 222175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 223106412Srwatson vn_close(nd.ni_vp, flags, td->td_ucred, td); 224157232Sjhb return (error); 225106412Srwatson } 226106412Srwatson#endif 227175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 2283124Sdg if (nd.ni_vp->v_type != VREG) { 229100444Sjohan vn_close(nd.ni_vp, flags, td->td_ucred, td); 230157232Sjhb return (EACCES); 2313124Sdg } 232106412Srwatson#ifdef MAC 233106412Srwatson } else { 234172930Srwatson error = mac_system_check_acct(td->td_ucred, NULL); 235106412Srwatson if (error) 236157232Sjhb return (error); 237106412Srwatson#endif 2383124Sdg } 2391541Srgrimes 240152328Srwatson /* 241152328Srwatson * Disallow concurrent access to the accounting vnode while we swap 242152328Srwatson * it out, in order to prevent access after close. 243152328Srwatson */ 244152328Srwatson sx_xlock(&acct_sx); 245126586Sbde 2463124Sdg /* 247234927Sjhb * Don't log spurious disable/enable messages if we are 248234927Sjhb * switching from one accounting file to another due to log 249234927Sjhb * rotation. 250234927Sjhb */ 251234927Sjhb replacing = (acct_vp != NULL && uap->path != NULL); 252234927Sjhb 253234927Sjhb /* 2543124Sdg * If accounting was previously enabled, kill the old space-watcher, 255152328Srwatson * close the file, and (if no new file was specified, leave). Reset 256152328Srwatson * the suspended state regardless of whether accounting remains 257152328Srwatson * enabled. 2583124Sdg */ 259152328Srwatson acct_suspended = 0; 260241896Skib if (acct_vp != NULL) 261234927Sjhb error = acct_disable(td, !replacing); 262107849Salfred if (uap->path == NULL) { 263155431Sjhb if (acct_state & ACCT_RUNNING) { 264155431Sjhb acct_state |= ACCT_EXITREQ; 265155431Sjhb wakeup(&acct_state); 266155431Sjhb } 267152328Srwatson sx_xunlock(&acct_sx); 268157232Sjhb return (error); 269103244Sarr } 2701541Srgrimes 2711541Srgrimes /* 272252422Smjg * Create our own plimit object without limits. It will be assigned 273252422Smjg * to exiting processes. 274252422Smjg */ 275252422Smjg acct_limit = lim_alloc(); 276252422Smjg for (i = 0; i < RLIM_NLIMITS; i++) 277252422Smjg acct_limit->pl_rlimit[i].rlim_cur = 278252422Smjg acct_limit->pl_rlimit[i].rlim_max = RLIM_INFINITY; 279252422Smjg 280252422Smjg /* 2813124Sdg * Save the new accounting file vnode, and schedule the new 2823124Sdg * free space watcher. 2831541Srgrimes */ 284152328Srwatson acct_vp = nd.ni_vp; 285152328Srwatson acct_cred = crhold(td->td_ucred); 286152328Srwatson acct_flags = flags; 287155431Sjhb if (acct_state & ACCT_RUNNING) 288155431Sjhb acct_state &= ~ACCT_EXITREQ; 289155431Sjhb else { 290155431Sjhb /* 291155431Sjhb * Try to start up an accounting kthread. We may start more 292155431Sjhb * than one, but if so the extras will commit suicide as 293155431Sjhb * soon as they start up. 294155431Sjhb */ 295172836Sjulian error = kproc_create(acct_thread, NULL, NULL, 0, 0, 296155431Sjhb "accounting"); 297155431Sjhb if (error) { 298252415Smjg (void) acct_disable(td, 0); 299155431Sjhb sx_xunlock(&acct_sx); 300155431Sjhb log(LOG_NOTICE, "Unable to start accounting thread\n"); 301157232Sjhb return (error); 302155431Sjhb } 303155431Sjhb } 304162370Srwatson acct_configured = 1; 305152328Srwatson sx_xunlock(&acct_sx); 306234927Sjhb if (!replacing) 307234927Sjhb log(LOG_NOTICE, "Accounting enabled\n"); 3083124Sdg return (error); 3091541Srgrimes} 3101541Srgrimes 3111541Srgrimes/* 312155431Sjhb * Disable currently in-progress accounting by closing the vnode, dropping 313155431Sjhb * our reference to the credential, and clearing the vnode's flags. 314155431Sjhb */ 315155431Sjhbstatic int 316234927Sjhbacct_disable(struct thread *td, int logging) 317155431Sjhb{ 318155431Sjhb int error; 319155431Sjhb 320155431Sjhb sx_assert(&acct_sx, SX_XLOCKED); 321155431Sjhb error = vn_close(acct_vp, acct_flags, acct_cred, td); 322155431Sjhb crfree(acct_cred); 323252422Smjg lim_free(acct_limit); 324162370Srwatson acct_configured = 0; 325155431Sjhb acct_vp = NULL; 326155431Sjhb acct_cred = NULL; 327155431Sjhb acct_flags = 0; 328234927Sjhb if (logging) 329234927Sjhb log(LOG_NOTICE, "Accounting disabled\n"); 330155431Sjhb return (error); 331155431Sjhb} 332155431Sjhb 333155431Sjhb/* 3343124Sdg * Write out process accounting information, on process exit. 3353124Sdg * Data to be written out is specified in Leffler, et al. 3363124Sdg * and are enumerated below. (They're also noted in the system 3373124Sdg * "acct.h" header file.) 3381541Srgrimes */ 3393124Sdgint 340152328Srwatsonacct_process(struct thread *td) 3413124Sdg{ 342169857Sdds struct acctv2 acct; 343126586Sbde struct timeval ut, st, tmp; 344252422Smjg struct plimit *oldlim; 345126586Sbde struct proc *p; 346170174Sjeff struct rusage ru; 347241896Skib int t, ret; 3483124Sdg 349139895Srwatson /* 350139895Srwatson * Lockless check of accounting condition before doing the hard 351139895Srwatson * work. 352139895Srwatson */ 353152328Srwatson if (acct_vp == NULL || acct_suspended) 354139895Srwatson return (0); 355139895Srwatson 356152328Srwatson sx_slock(&acct_sx); 357103208Sarr 358139895Srwatson /* 359139895Srwatson * If accounting isn't enabled, don't bother. Have to check again 360139895Srwatson * once we own the lock in case we raced with disabling of accounting 361139895Srwatson * by another thread. 362139895Srwatson */ 363152328Srwatson if (acct_vp == NULL || acct_suspended) { 364152328Srwatson sx_sunlock(&acct_sx); 3653124Sdg return (0); 366103208Sarr } 3673124Sdg 368126586Sbde p = td->td_proc; 369126586Sbde 3703124Sdg /* 3713124Sdg * Get process accounting information. 3723124Sdg */ 3733124Sdg 374181963Sed sx_slock(&proctree_lock); 375113624Sjhb PROC_LOCK(p); 376181963Sed 377181963Sed /* (1) The terminal from which the process was started */ 378181963Sed if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) 379181963Sed acct.ac_tty = tty_udev(p->p_pgrp->pg_session->s_ttyp); 380181963Sed else 381181963Sed acct.ac_tty = NODEV; 382181963Sed sx_sunlock(&proctree_lock); 383181963Sed 384181963Sed /* (2) The name of the command that ran */ 3853124Sdg bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm); 3863124Sdg 387181963Sed /* (3) The amount of user and system time that was used */ 388170472Sattilio rufetchcalc(p, &ru, &ut, &st); 389169857Sdds acct.ac_utime = encode_timeval(ut); 390169857Sdds acct.ac_stime = encode_timeval(st); 3913124Sdg 392181963Sed /* (4) The elapsed time the command ran (and its starting time) */ 393304843Skib getboottime(&tmp); 394114434Sdes timevaladd(&tmp, &p->p_stats->p_start); 395114434Sdes acct.ac_btime = tmp.tv_sec; 396114434Sdes microuptime(&tmp); 3973124Sdg timevalsub(&tmp, &p->p_stats->p_start); 398169857Sdds acct.ac_etime = encode_timeval(tmp); 3993124Sdg 400181963Sed /* (5) The average amount of memory used */ 4013124Sdg tmp = ut; 4023124Sdg timevaladd(&tmp, &st); 403169857Sdds /* Convert tmp (i.e. u + s) into hz units to match ru_i*. */ 4043124Sdg t = tmp.tv_sec * hz + tmp.tv_usec / tick; 4053124Sdg if (t) 406170174Sjeff acct.ac_mem = encode_long((ru.ru_ixrss + ru.ru_idrss + 407170174Sjeff + ru.ru_isrss) / t); 4083124Sdg else 4093124Sdg acct.ac_mem = 0; 4103124Sdg 411181963Sed /* (6) The number of disk I/O operations done */ 412170174Sjeff acct.ac_io = encode_long(ru.ru_inblock + ru.ru_oublock); 4133124Sdg 414181963Sed /* (7) The UID and GID of the process */ 41577183Srwatson acct.ac_uid = p->p_ucred->cr_ruid; 41677183Srwatson acct.ac_gid = p->p_ucred->cr_rgid; 4173124Sdg 4183124Sdg /* (8) The boolean flags that tell how the process terminated, etc. */ 419169857Sdds acct.ac_flagx = p->p_acflag; 4203124Sdg 421169857Sdds /* Setup ancillary structure fields. */ 422169857Sdds acct.ac_flagx |= ANVER; 423169857Sdds acct.ac_zero = 0; 424169857Sdds acct.ac_version = 2; 425169857Sdds acct.ac_len = acct.ac_len2 = sizeof(acct); 426169857Sdds 4273124Sdg /* 428252422Smjg * Eliminate rlimits (file size limit in particular). 4293124Sdg */ 430125454Sjhb oldlim = p->p_limit; 431252422Smjg p->p_limit = lim_hold(acct_limit); 432125454Sjhb PROC_UNLOCK(p); 433125454Sjhb lim_free(oldlim); 43436676Sdg 435126586Sbde /* 436126586Sbde * Write the accounting information to the file. 437126586Sbde */ 438152328Srwatson ret = vn_rdwr(UIO_WRITE, acct_vp, (caddr_t)&acct, sizeof (acct), 439152328Srwatson (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, acct_cred, NOCRED, 440194296Skib NULL, td); 441152328Srwatson sx_sunlock(&acct_sx); 442103208Sarr return (ret); 4433124Sdg} 4443124Sdg 445169857Sdds/* FLOAT_CONVERSION_START (Regression testing; don't remove this line.) */ 446169857Sdds 447169857Sdds/* Convert timevals and longs into IEEE-754 bit patterns. */ 448169857Sdds 449169857Sdds/* Mantissa mask (MSB is implied, so subtract 1). */ 450169857Sdds#define MANT_MASK ((1 << (FLT_MANT_DIG - 1)) - 1) 451169857Sdds 4521541Srgrimes/* 453169857Sdds * We calculate integer values to a precision of approximately 454169857Sdds * 28 bits. 455169857Sdds * This is high-enough precision to fill the 24 float bits 456169857Sdds * and low-enough to avoid overflowing the 32 int bits. 4571541Srgrimes */ 458169857Sdds#define CALC_BITS 28 4591541Srgrimes 460169857Sdds/* log_2(1000000). */ 461169857Sdds#define LOG2_1M 20 4623124Sdg 463169857Sdds/* 464169857Sdds * Convert the elements of a timeval into a 32-bit word holding 465169857Sdds * the bits of a IEEE-754 float. 466169857Sdds * The float value represents the timeval's value in microsecond units. 467169857Sdds */ 468169857Sddsstatic uint32_t 469169857Sddsencode_timeval(struct timeval tv) 4703124Sdg{ 471169857Sdds int log2_s; 472169857Sdds int val, exp; /* Unnormalized value and exponent */ 473169857Sdds int norm_exp; /* Normalized exponent */ 474169857Sdds int shift; 4753124Sdg 476169857Sdds /* 477169857Sdds * First calculate value and exponent to about CALC_BITS precision. 478169857Sdds * Note that the following conditionals have been ordered so that 479169857Sdds * the most common cases appear first. 480169857Sdds */ 481169857Sdds if (tv.tv_sec == 0) { 482169857Sdds if (tv.tv_usec == 0) 483169857Sdds return (0); 484169857Sdds exp = 0; 485169857Sdds val = tv.tv_usec; 486169857Sdds } else { 487169857Sdds /* 488169857Sdds * Calculate the value to a precision of approximately 489169857Sdds * CALC_BITS. 490169857Sdds */ 491169857Sdds log2_s = fls(tv.tv_sec) - 1; 492169857Sdds if (log2_s + LOG2_1M < CALC_BITS) { 493169857Sdds exp = 0; 494169857Sdds val = 1000000 * tv.tv_sec + tv.tv_usec; 495169857Sdds } else { 496169857Sdds exp = log2_s + LOG2_1M - CALC_BITS; 497209390Sed val = (unsigned int)(((uint64_t)1000000 * tv.tv_sec + 498169857Sdds tv.tv_usec) >> exp); 499169857Sdds } 5003124Sdg } 501169857Sdds /* Now normalize and pack the value into an IEEE-754 float. */ 502169857Sdds norm_exp = fls(val) - 1; 503169857Sdds shift = FLT_MANT_DIG - norm_exp - 1; 504169857Sdds#ifdef ACCT_DEBUG 505169857Sdds printf("val=%d exp=%d shift=%d log2(val)=%d\n", 506169857Sdds val, exp, shift, norm_exp); 507169857Sdds printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp, 508169857Sdds ((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK)); 509169857Sdds#endif 510169857Sdds return (((FLT_MAX_EXP - 1 + exp + norm_exp) << (FLT_MANT_DIG - 1)) | 511169857Sdds ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK)); 512169857Sdds} 5133124Sdg 514169857Sdds/* 515169857Sdds * Convert a non-negative long value into the bit pattern of 516169857Sdds * an IEEE-754 float value. 517169857Sdds */ 518169857Sddsstatic uint32_t 519169857Sddsencode_long(long val) 520169857Sdds{ 521169857Sdds int norm_exp; /* Normalized exponent */ 522169857Sdds int shift; 5233124Sdg 524169857Sdds if (val == 0) 525169857Sdds return (0); 526172023Sdds if (val < 0) { 527172023Sdds log(LOG_NOTICE, 528172024Sdds "encode_long: negative value %ld in accounting record\n", 529172023Sdds val); 530172023Sdds val = LONG_MAX; 531172023Sdds } 532169857Sdds norm_exp = fls(val) - 1; 533169857Sdds shift = FLT_MANT_DIG - norm_exp - 1; 534169857Sdds#ifdef ACCT_DEBUG 535169857Sdds printf("val=%d shift=%d log2(val)=%d\n", 536169857Sdds val, shift, norm_exp); 537169857Sdds printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp, 538169857Sdds ((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK)); 539169857Sdds#endif 540169857Sdds return (((FLT_MAX_EXP - 1 + norm_exp) << (FLT_MANT_DIG - 1)) | 541169857Sdds ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK)); 5423124Sdg} 5433124Sdg 544169857Sdds/* FLOAT_CONVERSION_END (Regression testing; don't remove this line.) */ 545169857Sdds 5461541Srgrimes/* 54796755Strhodes * Periodically check the filesystem to see if accounting 5483124Sdg * should be turned on or off. Beware the case where the vnode 5493124Sdg * has been vgone()'d out from underneath us, e.g. when the file 5503124Sdg * system containing the accounting file has been forcibly unmounted. 5511541Srgrimes */ 5521541Srgrimes/* ARGSUSED */ 55312819Sphkstatic void 554155431Sjhbacctwatch(void) 5551541Srgrimes{ 556311957Skib struct statfs *sp; 5571541Srgrimes 558155431Sjhb sx_assert(&acct_sx, SX_XLOCKED); 559155431Sjhb 560155431Sjhb /* 561155431Sjhb * If accounting was disabled before our kthread was scheduled, 562155431Sjhb * then acct_vp might be NULL. If so, just ask our kthread to 563155431Sjhb * exit and return. 564155431Sjhb */ 565155431Sjhb if (acct_vp == NULL) { 566155431Sjhb acct_state |= ACCT_EXITREQ; 567155431Sjhb return; 568155431Sjhb } 569155431Sjhb 570155431Sjhb /* 571155431Sjhb * If our vnode is no longer valid, tear it down and signal the 572155431Sjhb * accounting thread to die. 573155431Sjhb */ 574152328Srwatson if (acct_vp->v_type == VBAD) { 575234927Sjhb (void) acct_disable(NULL, 1); 576155431Sjhb acct_state |= ACCT_EXITREQ; 577152328Srwatson return; 578152328Srwatson } 579155431Sjhb 580103244Sarr /* 581152328Srwatson * Stopping here is better than continuing, maybe it will be VBAD 582152328Srwatson * next time around. 583112209Sjhb */ 584311957Skib sp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 585311957Skib if (VFS_STATFS(acct_vp->v_mount, sp) < 0) { 586311957Skib free(sp, M_STATFS); 587152328Srwatson return; 588311957Skib } 589152328Srwatson if (acct_suspended) { 590311957Skib if (sp->f_bavail > (int64_t)(acctresume * sp->f_blocks / 591152328Srwatson 100)) { 592152328Srwatson acct_suspended = 0; 5931541Srgrimes log(LOG_NOTICE, "Accounting resumed\n"); 5941541Srgrimes } 59522521Sdyson } else { 596311957Skib if (sp->f_bavail <= (int64_t)(acctsuspend * sp->f_blocks / 597152328Srwatson 100)) { 598152328Srwatson acct_suspended = 1; 5991541Srgrimes log(LOG_NOTICE, "Accounting suspended\n"); 6001541Srgrimes } 60122521Sdyson } 602311957Skib free(sp, M_STATFS); 603155431Sjhb} 604155431Sjhb 605155431Sjhb/* 606155431Sjhb * The main loop for the dedicated kernel thread that periodically calls 607155431Sjhb * acctwatch(). 608155431Sjhb */ 609155431Sjhbstatic void 610155431Sjhbacct_thread(void *dummy) 611155431Sjhb{ 612155431Sjhb u_char pri; 613155431Sjhb 614155431Sjhb /* This is a low-priority kernel thread. */ 615155431Sjhb pri = PRI_MAX_KERN; 616170307Sjeff thread_lock(curthread); 617155431Sjhb sched_prio(curthread, pri); 618170307Sjeff thread_unlock(curthread); 619155431Sjhb 620155431Sjhb /* If another accounting kthread is already running, just die. */ 621155431Sjhb sx_xlock(&acct_sx); 622155431Sjhb if (acct_state & ACCT_RUNNING) { 623155431Sjhb sx_xunlock(&acct_sx); 624172836Sjulian kproc_exit(0); 625155431Sjhb } 626155431Sjhb acct_state |= ACCT_RUNNING; 627155431Sjhb 628155431Sjhb /* Loop until we are asked to exit. */ 629155431Sjhb while (!(acct_state & ACCT_EXITREQ)) { 630155431Sjhb 631155431Sjhb /* Perform our periodic checks. */ 632155431Sjhb acctwatch(); 633155431Sjhb 634155431Sjhb /* 635155431Sjhb * We check this flag again before sleeping since the 636155431Sjhb * acctwatch() might have shut down accounting and asked us 637155431Sjhb * to exit. 638155431Sjhb */ 639155431Sjhb if (!(acct_state & ACCT_EXITREQ)) { 640167389Sjhb sx_sleep(&acct_state, &acct_sx, 0, "-", 641167389Sjhb acctchkfreq * hz); 642155431Sjhb } 643155431Sjhb } 644155431Sjhb 645155431Sjhb /* 646155431Sjhb * Acknowledge the exit request and shutdown. We clear both the 647155431Sjhb * exit request and running flags. 648155431Sjhb */ 649155431Sjhb acct_state = 0; 650152328Srwatson sx_xunlock(&acct_sx); 651172836Sjulian kproc_exit(0); 6521541Srgrimes} 653