kern_acct.c revision 167211
1246828Sdes/*- 2246828Sdes * Copyright (c) 1982, 1986, 1989, 1993 3246828Sdes * The Regents of the University of California. All rights reserved. 4246828Sdes * (c) UNIX System Laboratories, Inc. 5246828Sdes * Copyright (c) 2005 Robert N. M. Watson 6246828Sdes * All rights reserved. 7246828Sdes * 8246828Sdes * All or some portions of this file are derived from material licensed 9246828Sdes * to the University of California by American Telephone and Telegraph 10246828Sdes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11269257Sdes * the permission of UNIX System Laboratories, Inc. 12246828Sdes * 13246828Sdes * Redistribution and use in source and binary forms, with or without 14246828Sdes * modification, are permitted provided that the following conditions 15246828Sdes * are met: 16246828Sdes * 1. Redistributions of source code must retain the above copyright 17246828Sdes * notice, this list of conditions and the following disclaimer. 18246828Sdes * 2. Redistributions in binary form must reproduce the above copyright 19269257Sdes * notice, this list of conditions and the following disclaimer in the 20246828Sdes * documentation and/or other materials provided with the distribution. 21269257Sdes * 4. Neither the name of the University nor the names of its contributors 22269257Sdes * may be used to endorse or promote products derived from this software 23246828Sdes * without specific prior written permission. 24269257Sdes * 25246828Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26246828Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27246828Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28246828Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29246828Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30246828Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31246828Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32246828Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33246828Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34246828Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35246828Sdes * SUCH DAMAGE. 36246828Sdes * 37246828Sdes * Copyright (c) 1994 Christopher G. Demetriou 38246828Sdes * 39246828Sdes * Redistribution and use in source and binary forms, with or without 40246828Sdes * modification, are permitted provided that the following conditions 41246828Sdes * are met: 42246828Sdes * 1. Redistributions of source code must retain the above copyright 43246828Sdes * notice, this list of conditions and the following disclaimer. 44246828Sdes * 2. Redistributions in binary form must reproduce the above copyright 45246828Sdes * notice, this list of conditions and the following disclaimer in the 46246828Sdes * documentation and/or other materials provided with the distribution. 47246828Sdes * 3. All advertising materials mentioning features or use of this software 48246828Sdes * must display the following acknowledgement: 49246828Sdes * This product includes software developed by the University of 50246828Sdes * California, Berkeley and its contributors. 51246828Sdes * 4. Neither the name of the University nor the names of its contributors 52246828Sdes * may be used to endorse or promote products derived from this software 53246828Sdes * without specific prior written permission. 54246828Sdes * 55246828Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56246828Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57246828Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58246828Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59246828Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60246828Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61246828Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62246828Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63246828Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64246828Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65246828Sdes * SUCH DAMAGE. 66246828Sdes * 67246828Sdes * @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 68246828Sdes */ 69246828Sdes 70246828Sdes#include <sys/cdefs.h> 71246828Sdes__FBSDID("$FreeBSD: head/sys/kern/kern_acct.c 167211 2007-03-04 22:36:48Z rwatson $"); 72246828Sdes 73246828Sdes#include "opt_mac.h" 74246828Sdes 75246828Sdes#include <sys/param.h> 76246828Sdes#include <sys/systm.h> 77246828Sdes#include <sys/acct.h> 78246828Sdes#include <sys/fcntl.h> 79246828Sdes#include <sys/kernel.h> 80246828Sdes#include <sys/kthread.h> 81246828Sdes#include <sys/lock.h> 82246828Sdes#include <sys/mount.h> 83246828Sdes#include <sys/mutex.h> 84246828Sdes#include <sys/namei.h> 85246828Sdes#include <sys/priv.h> 86246828Sdes#include <sys/proc.h> 87246828Sdes#include <sys/resourcevar.h> 88246828Sdes#include <sys/sched.h> 89246828Sdes#include <sys/sx.h> 90246828Sdes#include <sys/sysctl.h> 91246828Sdes#include <sys/sysent.h> 92246828Sdes#include <sys/syslog.h> 93246828Sdes#include <sys/sysproto.h> 94246828Sdes#include <sys/tty.h> 95246828Sdes#include <sys/vnode.h> 96246828Sdes 97246828Sdes#include <security/mac/mac_framework.h> 98246828Sdes 99246828Sdes/* 100246828Sdes * The routines implemented in this file are described in: 101246828Sdes * Leffler, et al.: The Design and Implementation of the 4.3BSD 102246828Sdes * UNIX Operating System (Addison Welley, 1989) 103246828Sdes * on pages 62-63. 104246828Sdes * 105246828Sdes * Arguably, to simplify accounting operations, this mechanism should 106246828Sdes * be replaced by one in which an accounting log file (similar to /dev/klog) 107246828Sdes * is read by a user process, etc. However, that has its own problems. 108246828Sdes */ 109246828Sdes 110246828Sdes/* 111246828Sdes * Internal accounting functions. 112246828Sdes * The former's operation is described in Leffler, et al., and the latter 113246828Sdes * was provided by UCB with the 4.4BSD-Lite release 114246828Sdes */ 115246828Sdesstatic comp_t encode_comp_t(u_long, u_long); 116246828Sdesstatic void acctwatch(void); 117246828Sdesstatic void acct_thread(void *); 118246828Sdesstatic int acct_disable(struct thread *); 119246828Sdes 120246828Sdes/* 121246828Sdes * Accounting vnode pointer, saved vnode pointer, and flags for each. 122246828Sdes * acct_sx protects against changes to the active vnode and credentials 123246828Sdes * while accounting records are being committed to disk. 124246828Sdes */ 125246828Sdesstatic int acct_configured; 126246828Sdesstatic int acct_suspended; 127269257Sdesstatic struct vnode *acct_vp; 128246828Sdesstatic struct ucred *acct_cred; 129246828Sdesstatic int acct_flags; 130246828Sdesstatic struct sx acct_sx; 131246828Sdes 132246828SdesSX_SYSINIT(acct, &acct_sx, "acct_sx"); 133269257Sdes 134246828Sdes/* 135246828Sdes * State of the accounting kthread. 136246828Sdes */ 137246828Sdesstatic int acct_state; 138246828Sdes 139246828Sdes#define ACCT_RUNNING 1 /* Accounting kthread is running. */ 140246828Sdes#define ACCT_EXITREQ 2 /* Accounting kthread should exit. */ 141246828Sdes 142269257Sdes/* 143246828Sdes * Values associated with enabling and disabling accounting 144246828Sdes */ 145246828Sdesstatic int acctsuspend = 2; /* stop accounting when < 2% free space left */ 146246828SdesSYSCTL_INT(_kern, OID_AUTO, acct_suspend, CTLFLAG_RW, 147246828Sdes &acctsuspend, 0, "percentage of free disk space below which accounting stops"); 148269257Sdes 149246828Sdesstatic int acctresume = 4; /* resume when free space risen to > 4% */ 150246828SdesSYSCTL_INT(_kern, OID_AUTO, acct_resume, CTLFLAG_RW, 151246828Sdes &acctresume, 0, "percentage of free disk space above which accounting resumes"); 152246828Sdes 153246828Sdesstatic int acctchkfreq = 15; /* frequency (in seconds) to check space */ 154246828Sdes 155246828Sdesstatic int 156246828Sdessysctl_acct_chkfreq(SYSCTL_HANDLER_ARGS) 157246828Sdes{ 158246828Sdes int error, value; 159246828Sdes 160246828Sdes /* Write out the old value. */ 161246828Sdes error = SYSCTL_OUT(req, &acctchkfreq, sizeof(int)); 162246828Sdes if (error || req->newptr == NULL) 163246828Sdes return (error); 164246828Sdes 165246828Sdes /* Read in and verify the new value. */ 166246828Sdes error = SYSCTL_IN(req, &value, sizeof(int)); 167246828Sdes if (error) 168246828Sdes return (error); 169246828Sdes if (value <= 0) 170246828Sdes return (EINVAL); 171246828Sdes acctchkfreq = value; 172246828Sdes return (0); 173246828Sdes} 174246828SdesSYSCTL_PROC(_kern, OID_AUTO, acct_chkfreq, CTLTYPE_INT|CTLFLAG_RW, 175246828Sdes &acctchkfreq, 0, sysctl_acct_chkfreq, "I", 176246828Sdes "frequency for checking the free space"); 177246828Sdes 178246828SdesSYSCTL_INT(_kern, OID_AUTO, acct_configured, CTLFLAG_RD, &acct_configured, 0, 179246828Sdes "Accounting configured or not"); 180246828Sdes 181246828SdesSYSCTL_INT(_kern, OID_AUTO, acct_suspended, CTLFLAG_RD, &acct_suspended, 0, 182246828Sdes "Accounting suspended or not"); 183246828Sdes 184246828Sdes/* 185246828Sdes * Accounting system call. Written based on the specification and previous 186246828Sdes * implementation done by Mark Tinguely. 187246828Sdes */ 188246828Sdesint 189246828Sdesacct(struct thread *td, struct acct_args *uap) 190246828Sdes{ 191246828Sdes struct nameidata nd; 192246828Sdes int error, flags, vfslocked; 193246828Sdes 194246828Sdes error = priv_check(td, PRIV_ACCT); 195246828Sdes if (error) 196246828Sdes return (error); 197246828Sdes 198246828Sdes /* 199246828Sdes * If accounting is to be started to a file, open that file for 200246828Sdes * appending and make sure it's a 'normal'. 201246828Sdes */ 202246828Sdes if (uap->path != NULL) { 203246828Sdes NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, 204246828Sdes UIO_USERSPACE, uap->path, td); 205246828Sdes flags = FWRITE | O_APPEND; 206246828Sdes error = vn_open(&nd, &flags, 0, -1); 207246828Sdes if (error) 208246828Sdes return (error); 209246828Sdes vfslocked = NDHASGIANT(&nd); 210246828Sdes NDFREE(&nd, NDF_ONLY_PNBUF); 211246828Sdes#ifdef MAC 212246828Sdes error = mac_check_system_acct(td->td_ucred, nd.ni_vp); 213246828Sdes if (error) { 214246828Sdes VOP_UNLOCK(nd.ni_vp, 0, td); 215246828Sdes vn_close(nd.ni_vp, flags, td->td_ucred, td); 216246828Sdes VFS_UNLOCK_GIANT(vfslocked); 217246828Sdes return (error); 218246828Sdes } 219246828Sdes#endif 220246828Sdes VOP_UNLOCK(nd.ni_vp, 0, td); 221246828Sdes if (nd.ni_vp->v_type != VREG) { 222246828Sdes vn_close(nd.ni_vp, flags, td->td_ucred, td); 223246828Sdes VFS_UNLOCK_GIANT(vfslocked); 224246828Sdes return (EACCES); 225246828Sdes } 226246828Sdes VFS_UNLOCK_GIANT(vfslocked); 227246828Sdes#ifdef MAC 228246828Sdes } else { 229246828Sdes error = mac_check_system_acct(td->td_ucred, NULL); 230246828Sdes if (error) 231246828Sdes return (error); 232246828Sdes#endif 233246828Sdes } 234246828Sdes 235246828Sdes /* 236246828Sdes * Disallow concurrent access to the accounting vnode while we swap 237246828Sdes * it out, in order to prevent access after close. 238246828Sdes */ 239246828Sdes sx_xlock(&acct_sx); 240246828Sdes 241246828Sdes /* 242246828Sdes * If accounting was previously enabled, kill the old space-watcher, 243246828Sdes * close the file, and (if no new file was specified, leave). Reset 244246828Sdes * the suspended state regardless of whether accounting remains 245246828Sdes * enabled. 246246828Sdes */ 247246828Sdes acct_suspended = 0; 248246828Sdes if (acct_vp != NULL) { 249246828Sdes vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount); 250246828Sdes error = acct_disable(td); 251246828Sdes VFS_UNLOCK_GIANT(vfslocked); 252246828Sdes } 253246828Sdes if (uap->path == NULL) { 254246828Sdes if (acct_state & ACCT_RUNNING) { 255246828Sdes acct_state |= ACCT_EXITREQ; 256246828Sdes wakeup(&acct_state); 257246828Sdes } 258246828Sdes sx_xunlock(&acct_sx); 259246828Sdes return (error); 260246828Sdes } 261246828Sdes 262246828Sdes /* 263246828Sdes * Save the new accounting file vnode, and schedule the new 264246828Sdes * free space watcher. 265246828Sdes */ 266246828Sdes acct_vp = nd.ni_vp; 267246828Sdes acct_cred = crhold(td->td_ucred); 268246828Sdes acct_flags = flags; 269246828Sdes if (acct_state & ACCT_RUNNING) 270246828Sdes acct_state &= ~ACCT_EXITREQ; 271246828Sdes else { 272246828Sdes /* 273246828Sdes * Try to start up an accounting kthread. We may start more 274246828Sdes * than one, but if so the extras will commit suicide as 275246828Sdes * soon as they start up. 276246828Sdes */ 277246828Sdes error = kthread_create(acct_thread, NULL, NULL, 0, 0, 278246828Sdes "accounting"); 279246828Sdes if (error) { 280246828Sdes vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount); 281246828Sdes (void) vn_close(acct_vp, acct_flags, acct_cred, td); 282246828Sdes VFS_UNLOCK_GIANT(vfslocked); 283246828Sdes crfree(acct_cred); 284246828Sdes acct_configured = 0; 285246828Sdes acct_vp = NULL; 286246828Sdes acct_cred = NULL; 287246828Sdes acct_flags = 0; 288246828Sdes sx_xunlock(&acct_sx); 289246828Sdes log(LOG_NOTICE, "Unable to start accounting thread\n"); 290246828Sdes return (error); 291246828Sdes } 292246828Sdes } 293246828Sdes acct_configured = 1; 294246828Sdes sx_xunlock(&acct_sx); 295246828Sdes log(LOG_NOTICE, "Accounting enabled\n"); 296246828Sdes return (error); 297246828Sdes} 298246828Sdes 299246828Sdes/* 300246828Sdes * Disable currently in-progress accounting by closing the vnode, dropping 301246828Sdes * our reference to the credential, and clearing the vnode's flags. 302246828Sdes */ 303246828Sdesstatic int 304246828Sdesacct_disable(struct thread *td) 305246828Sdes{ 306246828Sdes int error; 307246828Sdes 308246828Sdes sx_assert(&acct_sx, SX_XLOCKED); 309246828Sdes error = vn_close(acct_vp, acct_flags, acct_cred, td); 310246828Sdes crfree(acct_cred); 311246828Sdes acct_configured = 0; 312246828Sdes acct_vp = NULL; 313246828Sdes acct_cred = NULL; 314246828Sdes acct_flags = 0; 315246828Sdes log(LOG_NOTICE, "Accounting disabled\n"); 316246828Sdes return (error); 317246828Sdes} 318246828Sdes 319246828Sdes/* 320246828Sdes * Write out process accounting information, on process exit. 321246828Sdes * Data to be written out is specified in Leffler, et al. 322246828Sdes * and are enumerated below. (They're also noted in the system 323246828Sdes * "acct.h" header file.) 324246828Sdes */ 325246828Sdesint 326246828Sdesacct_process(struct thread *td) 327246828Sdes{ 328246828Sdes struct acct acct; 329246828Sdes struct timeval ut, st, tmp; 330246828Sdes struct plimit *newlim, *oldlim; 331246828Sdes struct proc *p; 332246828Sdes struct rusage *r; 333246828Sdes int t, ret, vfslocked; 334246828Sdes 335246828Sdes /* 336246828Sdes * Lockless check of accounting condition before doing the hard 337246828Sdes * work. 338246828Sdes */ 339246828Sdes if (acct_vp == NULL || acct_suspended) 340246828Sdes return (0); 341246828Sdes 342246828Sdes sx_slock(&acct_sx); 343246828Sdes 344246828Sdes /* 345246828Sdes * If accounting isn't enabled, don't bother. Have to check again 346246828Sdes * once we own the lock in case we raced with disabling of accounting 347246828Sdes * by another thread. 348246828Sdes */ 349246828Sdes if (acct_vp == NULL || acct_suspended) { 350246828Sdes sx_sunlock(&acct_sx); 351246828Sdes return (0); 352246828Sdes } 353246828Sdes 354246828Sdes p = td->td_proc; 355246828Sdes 356246828Sdes /* 357246828Sdes * Get process accounting information. 358246828Sdes */ 359246828Sdes 360246828Sdes PROC_LOCK(p); 361246828Sdes /* (1) The name of the command that ran */ 362246828Sdes bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm); 363246828Sdes 364246828Sdes /* (2) The amount of user and system time that was used */ 365246828Sdes calcru(p, &ut, &st); 366246828Sdes acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec); 367246828Sdes acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); 368246828Sdes 369246828Sdes /* (3) The elapsed time the command ran (and its starting time) */ 370246828Sdes tmp = boottime; 371246828Sdes timevaladd(&tmp, &p->p_stats->p_start); 372246828Sdes acct.ac_btime = tmp.tv_sec; 373246828Sdes microuptime(&tmp); 374246828Sdes timevalsub(&tmp, &p->p_stats->p_start); 375246828Sdes acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec); 376246828Sdes 377246828Sdes /* (4) The average amount of memory used */ 378246828Sdes r = &p->p_stats->p_ru; 379246828Sdes tmp = ut; 380246828Sdes timevaladd(&tmp, &st); 381246828Sdes t = tmp.tv_sec * hz + tmp.tv_usec / tick; 382246828Sdes if (t) 383246828Sdes acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t; 384246828Sdes else 385246828Sdes acct.ac_mem = 0; 386246828Sdes 387246828Sdes /* (5) The number of disk I/O operations done */ 388246828Sdes acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0); 389246828Sdes 390246828Sdes /* (6) The UID and GID of the process */ 391246828Sdes acct.ac_uid = p->p_ucred->cr_ruid; 392246828Sdes acct.ac_gid = p->p_ucred->cr_rgid; 393246828Sdes 394246828Sdes /* (7) The terminal from which the process was started */ 395246828Sdes SESS_LOCK(p->p_session); 396246828Sdes if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) 397246828Sdes acct.ac_tty = dev2udev(p->p_pgrp->pg_session->s_ttyp->t_dev); 398246828Sdes else 399246828Sdes acct.ac_tty = NODEV; 400246828Sdes SESS_UNLOCK(p->p_session); 401246828Sdes 402246828Sdes /* (8) The boolean flags that tell how the process terminated, etc. */ 403246828Sdes acct.ac_flag = p->p_acflag; 404246828Sdes PROC_UNLOCK(p); 405246828Sdes 406246828Sdes /* 407246828Sdes * Eliminate any file size rlimit. 408246828Sdes */ 409246828Sdes newlim = lim_alloc(); 410246828Sdes PROC_LOCK(p); 411246828Sdes oldlim = p->p_limit; 412246828Sdes lim_copy(newlim, oldlim); 413246828Sdes newlim->pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 414246828Sdes p->p_limit = newlim; 415246828Sdes PROC_UNLOCK(p); 416246828Sdes lim_free(oldlim); 417246828Sdes 418246828Sdes /* 419246828Sdes * Write the accounting information to the file. 420246828Sdes */ 421246828Sdes vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount); 422246828Sdes VOP_LEASE(acct_vp, td, acct_cred, LEASE_WRITE); 423246828Sdes ret = vn_rdwr(UIO_WRITE, acct_vp, (caddr_t)&acct, sizeof (acct), 424246828Sdes (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, acct_cred, NOCRED, 425246828Sdes (int *)0, td); 426246828Sdes VFS_UNLOCK_GIANT(vfslocked); 427246828Sdes sx_sunlock(&acct_sx); 428246828Sdes return (ret); 429246828Sdes} 430246828Sdes 431246828Sdes/* 432246828Sdes * Encode_comp_t converts from ticks in seconds and microseconds 433246828Sdes * to ticks in 1/AHZ seconds. The encoding is described in 434246828Sdes * Leffler, et al., on page 63. 435246828Sdes */ 436246828Sdes 437246828Sdes#define MANTSIZE 13 /* 13 bit mantissa. */ 438246828Sdes#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */ 439246828Sdes#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */ 440246828Sdes 441246828Sdesstatic comp_t 442246828Sdesencode_comp_t(u_long s, u_long us) 443246828Sdes{ 444246828Sdes int exp, rnd; 445246828Sdes 446246828Sdes exp = 0; 447246828Sdes rnd = 0; 448246828Sdes s *= AHZ; 449246828Sdes s += us / (1000000 / AHZ); /* Maximize precision. */ 450246828Sdes 451246828Sdes while (s > MAXFRACT) { 452246828Sdes rnd = s & (1 << (EXPSIZE - 1)); /* Round up? */ 453246828Sdes s >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */ 454246828Sdes exp++; 455246828Sdes } 456246828Sdes 457246828Sdes /* If we need to round up, do it (and handle overflow correctly). */ 458246828Sdes if (rnd && (++s > MAXFRACT)) { 459246828Sdes s >>= EXPSIZE; 460246828Sdes exp++; 461246828Sdes } 462246828Sdes 463246828Sdes /* Clean it up and polish it off. */ 464246828Sdes exp <<= MANTSIZE; /* Shift the exponent into place */ 465246828Sdes exp += s; /* and add on the mantissa. */ 466246828Sdes return (exp); 467246828Sdes} 468246828Sdes 469246828Sdes/* 470246828Sdes * Periodically check the filesystem to see if accounting 471246828Sdes * should be turned on or off. Beware the case where the vnode 472246828Sdes * has been vgone()'d out from underneath us, e.g. when the file 473246828Sdes * system containing the accounting file has been forcibly unmounted. 474246828Sdes */ 475246828Sdes/* ARGSUSED */ 476246828Sdesstatic void 477246828Sdesacctwatch(void) 478246828Sdes{ 479246828Sdes struct statfs sb; 480246828Sdes int vfslocked; 481246828Sdes 482246828Sdes sx_assert(&acct_sx, SX_XLOCKED); 483246828Sdes 484246828Sdes /* 485246828Sdes * If accounting was disabled before our kthread was scheduled, 486246828Sdes * then acct_vp might be NULL. If so, just ask our kthread to 487246828Sdes * exit and return. 488246828Sdes */ 489246828Sdes if (acct_vp == NULL) { 490246828Sdes acct_state |= ACCT_EXITREQ; 491246828Sdes return; 492246828Sdes } 493246828Sdes 494246828Sdes /* 495246828Sdes * If our vnode is no longer valid, tear it down and signal the 496246828Sdes * accounting thread to die. 497246828Sdes */ 498246828Sdes vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount); 499246828Sdes if (acct_vp->v_type == VBAD) { 500246828Sdes (void) acct_disable(NULL); 501246828Sdes VFS_UNLOCK_GIANT(vfslocked); 502246828Sdes acct_state |= ACCT_EXITREQ; 503246828Sdes return; 504246828Sdes } 505246828Sdes 506246828Sdes /* 507246828Sdes * Stopping here is better than continuing, maybe it will be VBAD 508246828Sdes * next time around. 509246828Sdes */ 510246828Sdes if (VFS_STATFS(acct_vp->v_mount, &sb, curthread) < 0) { 511246828Sdes VFS_UNLOCK_GIANT(vfslocked); 512246828Sdes return; 513246828Sdes } 514246828Sdes VFS_UNLOCK_GIANT(vfslocked); 515246828Sdes if (acct_suspended) { 516246828Sdes if (sb.f_bavail > (int64_t)(acctresume * sb.f_blocks / 517246828Sdes 100)) { 518246828Sdes acct_suspended = 0; 519246828Sdes log(LOG_NOTICE, "Accounting resumed\n"); 520246828Sdes } 521246828Sdes } else { 522246828Sdes if (sb.f_bavail <= (int64_t)(acctsuspend * sb.f_blocks / 523246828Sdes 100)) { 524246828Sdes acct_suspended = 1; 525246828Sdes log(LOG_NOTICE, "Accounting suspended\n"); 526246828Sdes } 527246828Sdes } 528246828Sdes} 529246828Sdes 530246828Sdes/* 531246828Sdes * The main loop for the dedicated kernel thread that periodically calls 532246828Sdes * acctwatch(). 533246828Sdes */ 534246828Sdesstatic void 535246828Sdesacct_thread(void *dummy) 536246828Sdes{ 537246828Sdes u_char pri; 538246828Sdes 539246828Sdes /* This is a low-priority kernel thread. */ 540246828Sdes pri = PRI_MAX_KERN; 541246828Sdes mtx_lock_spin(&sched_lock); 542246828Sdes sched_prio(curthread, pri); 543246828Sdes mtx_unlock_spin(&sched_lock); 544246828Sdes 545246828Sdes /* If another accounting kthread is already running, just die. */ 546246828Sdes sx_xlock(&acct_sx); 547246828Sdes if (acct_state & ACCT_RUNNING) { 548246828Sdes sx_xunlock(&acct_sx); 549246828Sdes kthread_exit(0); 550246828Sdes } 551246828Sdes acct_state |= ACCT_RUNNING; 552246828Sdes 553246828Sdes /* Loop until we are asked to exit. */ 554246828Sdes while (!(acct_state & ACCT_EXITREQ)) { 555246828Sdes 556246828Sdes /* Perform our periodic checks. */ 557246828Sdes acctwatch(); 558246828Sdes 559246828Sdes /* 560246828Sdes * We check this flag again before sleeping since the 561246828Sdes * acctwatch() might have shut down accounting and asked us 562246828Sdes * to exit. 563246828Sdes */ 564246828Sdes if (!(acct_state & ACCT_EXITREQ)) { 565246828Sdes sx_xunlock(&acct_sx); 566246828Sdes tsleep(&acct_state, pri, "-", acctchkfreq * hz); 567246828Sdes sx_xlock(&acct_sx); 568246828Sdes } 569246828Sdes } 570246828Sdes 571246828Sdes /* 572246828Sdes * Acknowledge the exit request and shutdown. We clear both the 573246828Sdes * exit request and running flags. 574246828Sdes */ 575246828Sdes acct_state = 0; 576246828Sdes sx_xunlock(&acct_sx); 577246828Sdes kthread_exit(0); 578246828Sdes} 579246828Sdes