1df8bae1dSRodney W. Grimes /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9df8bae1dSRodney W. Grimes * 1071909edeSRobert Watson * Copyright (c) 1994 Christopher G. Demetriou 1171909edeSRobert Watson * Copyright (c) 2005 Robert N. M. Watson 1271909edeSRobert Watson * 13df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 14df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 15df8bae1dSRodney W. Grimes * are met: 16df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 18df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 19df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 20df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 21df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 22df8bae1dSRodney W. Grimes * must display the following acknowledgement: 23df8bae1dSRodney W. Grimes * This product includes software developed by the University of 24df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 25df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 26df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 27df8bae1dSRodney W. Grimes * without specific prior written permission. 28df8bae1dSRodney W. Grimes * 29df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39df8bae1dSRodney W. Grimes * SUCH DAMAGE. 40df8bae1dSRodney W. Grimes * 41c7d893deSDavid Greenman * @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44677b542eSDavid E. O'Brien #include <sys/cdefs.h> 45677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 46677b542eSDavid E. O'Brien 47e5e820fdSRobert Watson #include "opt_mac.h" 48e5e820fdSRobert Watson 49df8bae1dSRodney W. Grimes #include <sys/param.h> 500ad076d5SBruce Evans #include <sys/systm.h> 51b0864d13SJohn Baldwin #include <sys/acct.h> 52b0864d13SJohn Baldwin #include <sys/fcntl.h> 53b0864d13SJohn Baldwin #include <sys/kernel.h> 54fb919e4dSMark Murray #include <sys/lock.h> 55e5e820fdSRobert Watson #include <sys/mac.h> 56df8bae1dSRodney W. Grimes #include <sys/mount.h> 57b0864d13SJohn Baldwin #include <sys/mutex.h> 58c7d893deSDavid Greenman #include <sys/namei.h> 59b0864d13SJohn Baldwin #include <sys/proc.h> 60c7d893deSDavid Greenman #include <sys/resourcevar.h> 61b0864d13SJohn Baldwin #include <sys/sx.h> 62b0864d13SJohn Baldwin #include <sys/sysctl.h> 63b0864d13SJohn Baldwin #include <sys/sysent.h> 64b0864d13SJohn Baldwin #include <sys/syslog.h> 65b0864d13SJohn Baldwin #include <sys/sysproto.h> 66c7d893deSDavid Greenman #include <sys/tty.h> 67b0864d13SJohn Baldwin #include <sys/vnode.h> 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes /* 70c7d893deSDavid Greenman * The routines implemented in this file are described in: 71c7d893deSDavid Greenman * Leffler, et al.: The Design and Implementation of the 4.3BSD 72c7d893deSDavid Greenman * UNIX Operating System (Addison Welley, 1989) 73c7d893deSDavid Greenman * on pages 62-63. 74c7d893deSDavid Greenman * 75c7d893deSDavid Greenman * Arguably, to simplify accounting operations, this mechanism should 76c7d893deSDavid Greenman * be replaced by one in which an accounting log file (similar to /dev/klog) 77c7d893deSDavid Greenman * is read by a user process, etc. However, that has its own problems. 78df8bae1dSRodney W. Grimes */ 79df8bae1dSRodney W. Grimes 80df8bae1dSRodney W. Grimes /* 81c7d893deSDavid Greenman * Internal accounting functions. 82c7d893deSDavid Greenman * The former's operation is described in Leffler, et al., and the latter 83c7d893deSDavid Greenman * was provided by UCB with the 4.4BSD-Lite release 84df8bae1dSRodney W. Grimes */ 854d77a549SAlfred Perlstein static comp_t encode_comp_t(u_long, u_long); 864d77a549SAlfred Perlstein static void acctwatch(void *); 87c7d893deSDavid Greenman 88c7d893deSDavid Greenman /* 894f559836SJake Burkholder * Accounting callout used for periodic scheduling of acctwatch. 90ab36c067SJustin T. Gibbs */ 914f559836SJake Burkholder static struct callout acctwatch_callout; 92ab36c067SJustin T. Gibbs 93ab36c067SJustin T. Gibbs /* 945b606744SJohan Karlsson * Accounting vnode pointer, saved vnode pointer, and flags for each. 9571909edeSRobert Watson * acct_sx protects against changes to the active vnode and credentials 9671909edeSRobert Watson * while accounting records are being committed to disk. 97c7d893deSDavid Greenman */ 9871909edeSRobert Watson static int acct_suspended; 9971909edeSRobert Watson static struct vnode *acct_vp; 10071909edeSRobert Watson static struct ucred *acct_cred; 10171909edeSRobert Watson static int acct_flags; 10271909edeSRobert Watson static struct sx acct_sx; 103df8bae1dSRodney W. Grimes 10471909edeSRobert Watson SX_SYSINIT(acct, &acct_sx, "acct_sx"); 1054f39d5d5SAndrew R. Reiter 106df8bae1dSRodney W. Grimes /* 107df8bae1dSRodney W. Grimes * Values associated with enabling and disabling accounting 108df8bae1dSRodney W. Grimes */ 10987b6de2bSPoul-Henning Kamp static int acctsuspend = 2; /* stop accounting when < 2% free space left */ 11087b6de2bSPoul-Henning Kamp SYSCTL_INT(_kern, OID_AUTO, acct_suspend, CTLFLAG_RW, 11147fdd692SNeil Blakey-Milner &acctsuspend, 0, "percentage of free disk space below which accounting stops"); 11287b6de2bSPoul-Henning Kamp 11387b6de2bSPoul-Henning Kamp static int acctresume = 4; /* resume when free space risen to > 4% */ 11487b6de2bSPoul-Henning Kamp SYSCTL_INT(_kern, OID_AUTO, acct_resume, CTLFLAG_RW, 11547fdd692SNeil Blakey-Milner &acctresume, 0, "percentage of free disk space above which accounting resumes"); 11687b6de2bSPoul-Henning Kamp 11787b6de2bSPoul-Henning Kamp static int acctchkfreq = 15; /* frequency (in seconds) to check space */ 11887b6de2bSPoul-Henning Kamp SYSCTL_INT(_kern, OID_AUTO, acct_chkfreq, CTLFLAG_RW, 11947fdd692SNeil Blakey-Milner &acctchkfreq, 0, "frequency for checking the free space"); 120df8bae1dSRodney W. Grimes 12171909edeSRobert Watson SYSCTL_INT(_kern, OID_AUTO, acct_suspended, CTLFLAG_RD, &acct_suspended, 0, 12271909edeSRobert Watson "Accounting suspended or not"); 12371909edeSRobert Watson 124df8bae1dSRodney W. Grimes /* 125c7d893deSDavid Greenman * Accounting system call. Written based on the specification and 126c7d893deSDavid Greenman * previous implementation done by Mark Tinguely. 127116734c4SMatthew Dillon * 128116734c4SMatthew Dillon * MPSAFE 129df8bae1dSRodney W. Grimes */ 130c7d893deSDavid Greenman int 13171909edeSRobert Watson acct(struct thread *td, struct acct_args *uap) 132c7d893deSDavid Greenman { 133c7d893deSDavid Greenman struct nameidata nd; 134e6796b67SKirk McKusick int error, flags; 135c7d893deSDavid Greenman 136c7d893deSDavid Greenman /* Make sure that the caller is root. */ 13744731cabSJohn Baldwin error = suser(td); 138797f2d22SPoul-Henning Kamp if (error) 13916e7bc7bSJohn Baldwin return (error); 140c7d893deSDavid Greenman 141c7d893deSDavid Greenman /* 142c7d893deSDavid Greenman * If accounting is to be started to a file, open that file for 14371909edeSRobert Watson * appending and make sure it's a 'normal'. While we could 14471909edeSRobert Watson * conditionally acquire Giant here, we're actually interacting with 14571909edeSRobert Watson * vnodes from possibly two file systems, making the logic a bit 14671909edeSRobert Watson * complicated. For now, use Giant unconditionally. 147c7d893deSDavid Greenman */ 14871909edeSRobert Watson mtx_lock(&Giant); 149d1e405c5SAlfred Perlstein if (uap->path != NULL) { 150f97182acSAlfred Perlstein NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td); 15192da2e76SJohan Karlsson flags = FWRITE | O_APPEND; 1527c89f162SPoul-Henning Kamp error = vn_open(&nd, &flags, 0, -1); 153797f2d22SPoul-Henning Kamp if (error) 15471909edeSRobert Watson goto done; 155762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 156e5e820fdSRobert Watson #ifdef MAC 157e5e820fdSRobert Watson error = mac_check_system_acct(td->td_ucred, nd.ni_vp); 158e5e820fdSRobert Watson if (error) { 15908132261SRobert Watson VOP_UNLOCK(nd.ni_vp, 0, td); 160e5e820fdSRobert Watson vn_close(nd.ni_vp, flags, td->td_ucred, td); 16171909edeSRobert Watson goto done; 162e5e820fdSRobert Watson } 163e5e820fdSRobert Watson #endif 164b40ce416SJulian Elischer VOP_UNLOCK(nd.ni_vp, 0, td); 165c7d893deSDavid Greenman if (nd.ni_vp->v_type != VREG) { 1665b606744SJohan Karlsson vn_close(nd.ni_vp, flags, td->td_ucred, td); 167116734c4SMatthew Dillon error = EACCES; 16871909edeSRobert Watson goto done; 169c7d893deSDavid Greenman } 170e5e820fdSRobert Watson #ifdef MAC 171e5e820fdSRobert Watson } else { 172e5e820fdSRobert Watson error = mac_check_system_acct(td->td_ucred, NULL); 173e5e820fdSRobert Watson if (error) 17471909edeSRobert Watson goto done; 175e5e820fdSRobert Watson #endif 176c7d893deSDavid Greenman } 177c7d893deSDavid Greenman 17871909edeSRobert Watson /* 17971909edeSRobert Watson * Disallow concurrent access to the accounting vnode while we swap 18071909edeSRobert Watson * it out, in order to prevent access after close. 18171909edeSRobert Watson */ 18271909edeSRobert Watson sx_xlock(&acct_sx); 18301e3f3aeSBruce Evans 184c7d893deSDavid Greenman /* 185c7d893deSDavid Greenman * If accounting was previously enabled, kill the old space-watcher, 18671909edeSRobert Watson * close the file, and (if no new file was specified, leave). Reset 18771909edeSRobert Watson * the suspended state regardless of whether accounting remains 18871909edeSRobert Watson * enabled. 189c7d893deSDavid Greenman */ 19071909edeSRobert Watson acct_suspended = 0; 19171909edeSRobert Watson if (acct_vp != NULL) { 1924f559836SJake Burkholder callout_stop(&acctwatch_callout); 19371909edeSRobert Watson error = vn_close(acct_vp, acct_flags, acct_cred, td); 19471909edeSRobert Watson crfree(acct_cred); 19571909edeSRobert Watson acct_vp = NULL; 19671909edeSRobert Watson acct_cred = NULL; 19771909edeSRobert Watson acct_flags = 0; 19848719ca7SBosko Milekic log(LOG_NOTICE, "Accounting disabled\n"); 199c7d893deSDavid Greenman } 200d1e405c5SAlfred Perlstein if (uap->path == NULL) { 20171909edeSRobert Watson sx_xunlock(&acct_sx); 20271909edeSRobert Watson goto done; 203b4dcc46aSAndrew R. Reiter } 204c7d893deSDavid Greenman 205c7d893deSDavid Greenman /* 206c7d893deSDavid Greenman * Save the new accounting file vnode, and schedule the new 207c7d893deSDavid Greenman * free space watcher. 208c7d893deSDavid Greenman */ 20971909edeSRobert Watson acct_vp = nd.ni_vp; 21071909edeSRobert Watson acct_cred = crhold(td->td_ucred); 21171909edeSRobert Watson acct_flags = flags; 21271909edeSRobert Watson callout_init(&acctwatch_callout, CALLOUT_MPSAFE); 21371909edeSRobert Watson sx_xunlock(&acct_sx); 21448719ca7SBosko Milekic log(LOG_NOTICE, "Accounting enabled\n"); 215c7d893deSDavid Greenman acctwatch(NULL); 21671909edeSRobert Watson done: 217116734c4SMatthew Dillon mtx_unlock(&Giant); 218c7d893deSDavid Greenman return (error); 219c7d893deSDavid Greenman } 220c7d893deSDavid Greenman 221c7d893deSDavid Greenman /* 222c7d893deSDavid Greenman * Write out process accounting information, on process exit. 223c7d893deSDavid Greenman * Data to be written out is specified in Leffler, et al. 224c7d893deSDavid Greenman * and are enumerated below. (They're also noted in the system 225c7d893deSDavid Greenman * "acct.h" header file.) 226c7d893deSDavid Greenman */ 227c7d893deSDavid Greenman int 22871909edeSRobert Watson acct_process(struct thread *td) 229c7d893deSDavid Greenman { 230c7d893deSDavid Greenman struct acct acct; 231c7d893deSDavid Greenman struct timeval ut, st, tmp; 23291d5354aSJohn Baldwin struct plimit *newlim, *oldlim; 23301e3f3aeSBruce Evans struct proc *p; 23401e3f3aeSBruce Evans struct rusage *r; 23571909edeSRobert Watson int t, ret, vfslocked; 2364f39d5d5SAndrew R. Reiter 2372b05b557SRobert Watson /* 2382b05b557SRobert Watson * Lockless check of accounting condition before doing the hard 2392b05b557SRobert Watson * work. 2402b05b557SRobert Watson */ 24171909edeSRobert Watson if (acct_vp == NULL || acct_suspended) 2422b05b557SRobert Watson return (0); 2432b05b557SRobert Watson 24471909edeSRobert Watson sx_slock(&acct_sx); 245c7d893deSDavid Greenman 2462b05b557SRobert Watson /* 2472b05b557SRobert Watson * If accounting isn't enabled, don't bother. Have to check again 2482b05b557SRobert Watson * once we own the lock in case we raced with disabling of accounting 2492b05b557SRobert Watson * by another thread. 2502b05b557SRobert Watson */ 25171909edeSRobert Watson if (acct_vp == NULL || acct_suspended) { 25271909edeSRobert Watson sx_sunlock(&acct_sx); 253c7d893deSDavid Greenman return (0); 2544f39d5d5SAndrew R. Reiter } 255c7d893deSDavid Greenman 25601e3f3aeSBruce Evans p = td->td_proc; 25701e3f3aeSBruce Evans 258c7d893deSDavid Greenman /* 259c7d893deSDavid Greenman * Get process accounting information. 260c7d893deSDavid Greenman */ 261c7d893deSDavid Greenman 2627e653dbdSJohn Baldwin PROC_LOCK(p); 263c7d893deSDavid Greenman /* (1) The name of the command that ran */ 264c7d893deSDavid Greenman bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm); 265c7d893deSDavid Greenman 266c7d893deSDavid Greenman /* (2) The amount of user and system time that was used */ 26778c85e8dSJohn Baldwin calcru(p, &ut, &st); 268c7d893deSDavid Greenman acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec); 269c7d893deSDavid Greenman acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); 270c7d893deSDavid Greenman 2715f9ae8e0SGiorgos Keramidas /* (3) The elapsed time the command ran (and its starting time) */ 27287ccef7bSDag-Erling Smørgrav tmp = boottime; 27387ccef7bSDag-Erling Smørgrav timevaladd(&tmp, &p->p_stats->p_start); 27487ccef7bSDag-Erling Smørgrav acct.ac_btime = tmp.tv_sec; 27587ccef7bSDag-Erling Smørgrav microuptime(&tmp); 276c7d893deSDavid Greenman timevalsub(&tmp, &p->p_stats->p_start); 277c7d893deSDavid Greenman acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec); 278c7d893deSDavid Greenman 279c7d893deSDavid Greenman /* (4) The average amount of memory used */ 280c7d893deSDavid Greenman r = &p->p_stats->p_ru; 281c7d893deSDavid Greenman tmp = ut; 282c7d893deSDavid Greenman timevaladd(&tmp, &st); 283c7d893deSDavid Greenman t = tmp.tv_sec * hz + tmp.tv_usec / tick; 284c7d893deSDavid Greenman if (t) 285c7d893deSDavid Greenman acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t; 286c7d893deSDavid Greenman else 287c7d893deSDavid Greenman acct.ac_mem = 0; 288c7d893deSDavid Greenman 289c7d893deSDavid Greenman /* (5) The number of disk I/O operations done */ 290c7d893deSDavid Greenman acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0); 291c7d893deSDavid Greenman 292c7d893deSDavid Greenman /* (6) The UID and GID of the process */ 293b1fc0ec1SRobert Watson acct.ac_uid = p->p_ucred->cr_ruid; 294b1fc0ec1SRobert Watson acct.ac_gid = p->p_ucred->cr_rgid; 295c7d893deSDavid Greenman 296c7d893deSDavid Greenman /* (7) The terminal from which the process was started */ 297f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 298c7d893deSDavid Greenman if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) 29923d76283SPoul-Henning Kamp acct.ac_tty = dev2udev(p->p_pgrp->pg_session->s_ttyp->t_dev); 300c7d893deSDavid Greenman else 301f3732fd1SPoul-Henning Kamp acct.ac_tty = NODEV; 302f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 303c7d893deSDavid Greenman 304c7d893deSDavid Greenman /* (8) The boolean flags that tell how the process terminated, etc. */ 305c7d893deSDavid Greenman acct.ac_flag = p->p_acflag; 3067e653dbdSJohn Baldwin PROC_UNLOCK(p); 307c7d893deSDavid Greenman 308c7d893deSDavid Greenman /* 309b5afad71SDavid Greenman * Eliminate any file size rlimit. 310b5afad71SDavid Greenman */ 31191d5354aSJohn Baldwin newlim = lim_alloc(); 31291d5354aSJohn Baldwin PROC_LOCK(p); 31391d5354aSJohn Baldwin oldlim = p->p_limit; 31491d5354aSJohn Baldwin lim_copy(newlim, oldlim); 31591d5354aSJohn Baldwin newlim->pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 31691d5354aSJohn Baldwin p->p_limit = newlim; 31791d5354aSJohn Baldwin PROC_UNLOCK(p); 31891d5354aSJohn Baldwin lim_free(oldlim); 319b5afad71SDavid Greenman 32001e3f3aeSBruce Evans /* 32101e3f3aeSBruce Evans * Write the accounting information to the file. 32201e3f3aeSBruce Evans */ 32371909edeSRobert Watson vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount); 32471909edeSRobert Watson VOP_LEASE(acct_vp, td, acct_cred, LEASE_WRITE); 32571909edeSRobert Watson ret = vn_rdwr(UIO_WRITE, acct_vp, (caddr_t)&acct, sizeof (acct), 32671909edeSRobert Watson (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, acct_cred, NOCRED, 3274f39d5d5SAndrew R. Reiter (int *)0, td); 32871909edeSRobert Watson VFS_UNLOCK_GIANT(vfslocked); 32971909edeSRobert Watson sx_sunlock(&acct_sx); 3304f39d5d5SAndrew R. Reiter return (ret); 331c7d893deSDavid Greenman } 332c7d893deSDavid Greenman 333c7d893deSDavid Greenman /* 334c7d893deSDavid Greenman * Encode_comp_t converts from ticks in seconds and microseconds 335c7d893deSDavid Greenman * to ticks in 1/AHZ seconds. The encoding is described in 336c7d893deSDavid Greenman * Leffler, et al., on page 63. 337c7d893deSDavid Greenman */ 338c7d893deSDavid Greenman 339c7d893deSDavid Greenman #define MANTSIZE 13 /* 13 bit mantissa. */ 340c7d893deSDavid Greenman #define EXPSIZE 3 /* Base 8 (3 bit) exponent. */ 341c7d893deSDavid Greenman #define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */ 342c7d893deSDavid Greenman 34387b6de2bSPoul-Henning Kamp static comp_t 34471909edeSRobert Watson encode_comp_t(u_long s, u_long us) 345c7d893deSDavid Greenman { 346c7d893deSDavid Greenman int exp, rnd; 347c7d893deSDavid Greenman 348c7d893deSDavid Greenman exp = 0; 349c7d893deSDavid Greenman rnd = 0; 350c7d893deSDavid Greenman s *= AHZ; 351c7d893deSDavid Greenman s += us / (1000000 / AHZ); /* Maximize precision. */ 352c7d893deSDavid Greenman 353c7d893deSDavid Greenman while (s > MAXFRACT) { 354c7d893deSDavid Greenman rnd = s & (1 << (EXPSIZE - 1)); /* Round up? */ 355c7d893deSDavid Greenman s >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */ 356c7d893deSDavid Greenman exp++; 357c7d893deSDavid Greenman } 358c7d893deSDavid Greenman 359c7d893deSDavid Greenman /* If we need to round up, do it (and handle overflow correctly). */ 360c7d893deSDavid Greenman if (rnd && (++s > MAXFRACT)) { 361c7d893deSDavid Greenman s >>= EXPSIZE; 362c7d893deSDavid Greenman exp++; 363c7d893deSDavid Greenman } 364c7d893deSDavid Greenman 365c7d893deSDavid Greenman /* Clean it up and polish it off. */ 366c7d893deSDavid Greenman exp <<= MANTSIZE; /* Shift the exponent into place */ 367c7d893deSDavid Greenman exp += s; /* and add on the mantissa. */ 368c7d893deSDavid Greenman return (exp); 369c7d893deSDavid Greenman } 370c7d893deSDavid Greenman 371c7d893deSDavid Greenman /* 372c7d893deSDavid Greenman * Periodically check the filesystem to see if accounting 373c7d893deSDavid Greenman * should be turned on or off. Beware the case where the vnode 374c7d893deSDavid Greenman * has been vgone()'d out from underneath us, e.g. when the file 375c7d893deSDavid Greenman * system containing the accounting file has been forcibly unmounted. 376c7d893deSDavid Greenman */ 377df8bae1dSRodney W. Grimes /* ARGSUSED */ 37887b6de2bSPoul-Henning Kamp static void 37971909edeSRobert Watson acctwatch(void *a) 380df8bae1dSRodney W. Grimes { 381df8bae1dSRodney W. Grimes struct statfs sb; 38271909edeSRobert Watson int vfslocked; 383df8bae1dSRodney W. Grimes 38471909edeSRobert Watson sx_xlock(&acct_sx); 38571909edeSRobert Watson vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount); 38671909edeSRobert Watson if (acct_vp->v_type == VBAD) { 38771909edeSRobert Watson (void) vn_close(acct_vp, acct_flags, acct_cred, NULL); 38871909edeSRobert Watson VFS_UNLOCK_GIANT(vfslocked); 38971909edeSRobert Watson crfree(acct_cred); 39071909edeSRobert Watson acct_vp = NULL; 39171909edeSRobert Watson acct_cred = NULL; 39271909edeSRobert Watson acct_flags = 0; 39371909edeSRobert Watson sx_xunlock(&acct_sx); 39471909edeSRobert Watson log(LOG_NOTICE, "Accounting disabled\n"); 395c7d893deSDavid Greenman return; 396c7d893deSDavid Greenman } 39771909edeSRobert Watson /* 39871909edeSRobert Watson * Stopping here is better than continuing, maybe it will be VBAD 39971909edeSRobert Watson * next time around. 40071909edeSRobert Watson */ 40171909edeSRobert Watson if (VFS_STATFS(acct_vp->v_mount, &sb, curthread) < 0) { 40271909edeSRobert Watson VFS_UNLOCK_GIANT(vfslocked); 40371909edeSRobert Watson sx_xunlock(&acct_sx); 40471909edeSRobert Watson return; 40571909edeSRobert Watson } 40671909edeSRobert Watson VFS_UNLOCK_GIANT(vfslocked); 40771909edeSRobert Watson if (acct_suspended) { 40871909edeSRobert Watson if (sb.f_bavail > (int64_t)(acctresume * sb.f_blocks / 40971909edeSRobert Watson 100)) { 41071909edeSRobert Watson acct_suspended = 0; 411df8bae1dSRodney W. Grimes log(LOG_NOTICE, "Accounting resumed\n"); 412df8bae1dSRodney W. Grimes } 413996c772fSJohn Dyson } else { 41471909edeSRobert Watson if (sb.f_bavail <= (int64_t)(acctsuspend * sb.f_blocks / 41571909edeSRobert Watson 100)) { 41671909edeSRobert Watson acct_suspended = 1; 417df8bae1dSRodney W. Grimes log(LOG_NOTICE, "Accounting suspended\n"); 418df8bae1dSRodney W. Grimes } 419996c772fSJohn Dyson } 4204f559836SJake Burkholder callout_reset(&acctwatch_callout, acctchkfreq * hz, acctwatch, NULL); 42171909edeSRobert Watson sx_xunlock(&acct_sx); 422df8bae1dSRodney W. Grimes } 423