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