]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/kern/kern_acct.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / kern / kern_acct.c
1 /*-
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * Copyright (c) 2005 Robert N. M. Watson
6  * All rights reserved.
7  *
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * Copyright (c) 1994 Christopher G. Demetriou
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *      This product includes software developed by the University of
50  *      California, Berkeley and its contributors.
51  * 4. Neither the name of the University nor the names of its contributors
52  *    may be used to endorse or promote products derived from this software
53  *    without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  *
67  *      @(#)kern_acct.c 8.1 (Berkeley) 6/14/93
68  */
69
70 #include <sys/cdefs.h>
71 __FBSDID("$FreeBSD$");
72
73 #include "opt_mac.h"
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/acct.h>
78 #include <sys/fcntl.h>
79 #include <sys/kernel.h>
80 #include <sys/kthread.h>
81 #include <sys/limits.h>
82 #include <sys/lock.h>
83 #include <sys/mount.h>
84 #include <sys/mutex.h>
85 #include <sys/namei.h>
86 #include <sys/priv.h>
87 #include <sys/proc.h>
88 #include <sys/resourcevar.h>
89 #include <sys/sched.h>
90 #include <sys/sx.h>
91 #include <sys/sysctl.h>
92 #include <sys/sysent.h>
93 #include <sys/syslog.h>
94 #include <sys/sysproto.h>
95 #include <sys/tty.h>
96 #include <sys/vnode.h>
97
98 #include <security/mac/mac_framework.h>
99
100 /*
101  * The routines implemented in this file are described in:
102  *      Leffler, et al.: The Design and Implementation of the 4.3BSD
103  *          UNIX Operating System (Addison Welley, 1989)
104  * on pages 62-63.
105  * On May 2007 the historic 3 bits base 8 exponent, 13 bit fraction
106  * compt_t representation described in the above reference was replaced
107  * with that of IEEE-754 floats.
108  *
109  * Arguably, to simplify accounting operations, this mechanism should
110  * be replaced by one in which an accounting log file (similar to /dev/klog)
111  * is read by a user process, etc.  However, that has its own problems.
112  */
113
114 /* Floating point definitions from <float.h>. */
115 #define FLT_MANT_DIG    24              /* p */
116 #define FLT_MAX_EXP     128             /* emax */
117
118 /*
119  * Internal accounting functions.
120  * The former's operation is described in Leffler, et al., and the latter
121  * was provided by UCB with the 4.4BSD-Lite release
122  */
123 static uint32_t encode_timeval(struct timeval);
124 static uint32_t encode_long(long);
125 static void     acctwatch(void);
126 static void     acct_thread(void *);
127 static int      acct_disable(struct thread *);
128
129 /*
130  * Accounting vnode pointer, saved vnode pointer, and flags for each.
131  * acct_sx protects against changes to the active vnode and credentials
132  * while accounting records are being committed to disk.
133  */
134 static int               acct_configured;
135 static int               acct_suspended;
136 static struct vnode     *acct_vp;
137 static struct ucred     *acct_cred;
138 static int               acct_flags;
139 static struct sx         acct_sx;
140
141 SX_SYSINIT(acct, &acct_sx, "acct_sx");
142
143 /*
144  * State of the accounting kthread.
145  */
146 static int               acct_state;
147
148 #define ACCT_RUNNING    1       /* Accounting kthread is running. */
149 #define ACCT_EXITREQ    2       /* Accounting kthread should exit. */
150
151 /*
152  * Values associated with enabling and disabling accounting
153  */
154 static int acctsuspend = 2;     /* stop accounting when < 2% free space left */
155 SYSCTL_INT(_kern, OID_AUTO, acct_suspend, CTLFLAG_RW,
156         &acctsuspend, 0, "percentage of free disk space below which accounting stops");
157
158 static int acctresume = 4;      /* resume when free space risen to > 4% */
159 SYSCTL_INT(_kern, OID_AUTO, acct_resume, CTLFLAG_RW,
160         &acctresume, 0, "percentage of free disk space above which accounting resumes");
161
162 static int acctchkfreq = 15;    /* frequency (in seconds) to check space */
163
164 static int
165 sysctl_acct_chkfreq(SYSCTL_HANDLER_ARGS)
166 {
167         int error, value;
168
169         /* Write out the old value. */
170         error = SYSCTL_OUT(req, &acctchkfreq, sizeof(int));
171         if (error || req->newptr == NULL)
172                 return (error);
173
174         /* Read in and verify the new value. */
175         error = SYSCTL_IN(req, &value, sizeof(int));
176         if (error)
177                 return (error);
178         if (value <= 0)
179                 return (EINVAL);
180         acctchkfreq = value;
181         return (0);
182 }
183 SYSCTL_PROC(_kern, OID_AUTO, acct_chkfreq, CTLTYPE_INT|CTLFLAG_RW,
184     &acctchkfreq, 0, sysctl_acct_chkfreq, "I",
185     "frequency for checking the free space");
186
187 SYSCTL_INT(_kern, OID_AUTO, acct_configured, CTLFLAG_RD, &acct_configured, 0,
188         "Accounting configured or not");
189
190 SYSCTL_INT(_kern, OID_AUTO, acct_suspended, CTLFLAG_RD, &acct_suspended, 0,
191         "Accounting suspended or not");
192
193 /*
194  * Accounting system call.  Written based on the specification and previous
195  * implementation done by Mark Tinguely.
196  */
197 int
198 acct(struct thread *td, struct acct_args *uap)
199 {
200         struct nameidata nd;
201         int error, flags, vfslocked;
202
203         error = priv_check(td, PRIV_ACCT);
204         if (error)
205                 return (error);
206
207         /*
208          * If accounting is to be started to a file, open that file for
209          * appending and make sure it's a 'normal'.
210          */
211         if (uap->path != NULL) {
212                 NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1,
213                     UIO_USERSPACE, uap->path, td);
214                 flags = FWRITE | O_APPEND;
215                 error = vn_open(&nd, &flags, 0, NULL);
216                 if (error)
217                         return (error);
218                 vfslocked = NDHASGIANT(&nd);
219                 NDFREE(&nd, NDF_ONLY_PNBUF);
220 #ifdef MAC
221                 error = mac_check_system_acct(td->td_ucred, nd.ni_vp);
222                 if (error) {
223                         VOP_UNLOCK(nd.ni_vp, 0, td);
224                         vn_close(nd.ni_vp, flags, td->td_ucred, td);
225                         VFS_UNLOCK_GIANT(vfslocked);
226                         return (error);
227                 }
228 #endif
229                 VOP_UNLOCK(nd.ni_vp, 0, td);
230                 if (nd.ni_vp->v_type != VREG) {
231                         vn_close(nd.ni_vp, flags, td->td_ucred, td);
232                         VFS_UNLOCK_GIANT(vfslocked);
233                         return (EACCES);
234                 }
235                 VFS_UNLOCK_GIANT(vfslocked);
236 #ifdef MAC
237         } else {
238                 error = mac_check_system_acct(td->td_ucred, NULL);
239                 if (error)
240                         return (error);
241 #endif
242         }
243
244         /*
245          * Disallow concurrent access to the accounting vnode while we swap
246          * it out, in order to prevent access after close.
247          */
248         sx_xlock(&acct_sx);
249
250         /*
251          * If accounting was previously enabled, kill the old space-watcher,
252          * close the file, and (if no new file was specified, leave).  Reset
253          * the suspended state regardless of whether accounting remains
254          * enabled.
255          */
256         acct_suspended = 0;
257         if (acct_vp != NULL) {
258                 vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount);
259                 error = acct_disable(td);
260                 VFS_UNLOCK_GIANT(vfslocked);
261         }
262         if (uap->path == NULL) {
263                 if (acct_state & ACCT_RUNNING) {
264                         acct_state |= ACCT_EXITREQ;
265                         wakeup(&acct_state);
266                 }
267                 sx_xunlock(&acct_sx);
268                 return (error);
269         }
270
271         /*
272          * Save the new accounting file vnode, and schedule the new
273          * free space watcher.
274          */
275         acct_vp = nd.ni_vp;
276         acct_cred = crhold(td->td_ucred);
277         acct_flags = flags;
278         if (acct_state & ACCT_RUNNING)
279                 acct_state &= ~ACCT_EXITREQ;
280         else {
281                 /*
282                  * Try to start up an accounting kthread.  We may start more
283                  * than one, but if so the extras will commit suicide as
284                  * soon as they start up.
285                  */
286                 error = kthread_create(acct_thread, NULL, NULL, 0, 0,
287                     "accounting");
288                 if (error) {
289                         vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount);
290                         (void) vn_close(acct_vp, acct_flags, acct_cred, td);
291                         VFS_UNLOCK_GIANT(vfslocked);
292                         crfree(acct_cred);
293                         acct_configured = 0;
294                         acct_vp = NULL;
295                         acct_cred = NULL;
296                         acct_flags = 0;
297                         sx_xunlock(&acct_sx);
298                         log(LOG_NOTICE, "Unable to start accounting thread\n");
299                         return (error);
300                 }
301         }
302         acct_configured = 1;
303         sx_xunlock(&acct_sx);
304         log(LOG_NOTICE, "Accounting enabled\n");
305         return (error);
306 }
307
308 /*
309  * Disable currently in-progress accounting by closing the vnode, dropping
310  * our reference to the credential, and clearing the vnode's flags.
311  */
312 static int
313 acct_disable(struct thread *td)
314 {
315         int error;
316
317         sx_assert(&acct_sx, SX_XLOCKED);
318         error = vn_close(acct_vp, acct_flags, acct_cred, td);
319         crfree(acct_cred);
320         acct_configured = 0;
321         acct_vp = NULL;
322         acct_cred = NULL;
323         acct_flags = 0;
324         log(LOG_NOTICE, "Accounting disabled\n");
325         return (error);
326 }
327
328 /*
329  * Write out process accounting information, on process exit.
330  * Data to be written out is specified in Leffler, et al.
331  * and are enumerated below.  (They're also noted in the system
332  * "acct.h" header file.)
333  */
334 int
335 acct_process(struct thread *td)
336 {
337         struct acctv2 acct;
338         struct timeval ut, st, tmp;
339         struct plimit *newlim, *oldlim;
340         struct proc *p;
341         struct rusage ru;
342         int t, ret, vfslocked;
343
344         /*
345          * Lockless check of accounting condition before doing the hard
346          * work.
347          */
348         if (acct_vp == NULL || acct_suspended)
349                 return (0);
350
351         sx_slock(&acct_sx);
352
353         /*
354          * If accounting isn't enabled, don't bother.  Have to check again
355          * once we own the lock in case we raced with disabling of accounting
356          * by another thread.
357          */
358         if (acct_vp == NULL || acct_suspended) {
359                 sx_sunlock(&acct_sx);
360                 return (0);
361         }
362
363         p = td->td_proc;
364
365         /*
366          * Get process accounting information.
367          */
368
369         PROC_LOCK(p);
370         /* (1) The name of the command that ran */
371         bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm);
372
373         /* (2) The amount of user and system time that was used */
374         rufetchcalc(p, &ru, &ut, &st);
375         acct.ac_utime = encode_timeval(ut);
376         acct.ac_stime = encode_timeval(st);
377
378         /* (3) The elapsed time the command ran (and its starting time) */
379         tmp = boottime;
380         timevaladd(&tmp, &p->p_stats->p_start);
381         acct.ac_btime = tmp.tv_sec;
382         microuptime(&tmp);
383         timevalsub(&tmp, &p->p_stats->p_start);
384         acct.ac_etime = encode_timeval(tmp);
385
386         /* (4) The average amount of memory used */
387         tmp = ut;
388         timevaladd(&tmp, &st);
389         /* Convert tmp (i.e. u + s) into hz units to match ru_i*. */
390         t = tmp.tv_sec * hz + tmp.tv_usec / tick;
391         if (t)
392                 acct.ac_mem = encode_long((ru.ru_ixrss + ru.ru_idrss +
393                     + ru.ru_isrss) / t);
394         else
395                 acct.ac_mem = 0;
396
397         /* (5) The number of disk I/O operations done */
398         acct.ac_io = encode_long(ru.ru_inblock + ru.ru_oublock);
399
400         /* (6) The UID and GID of the process */
401         acct.ac_uid = p->p_ucred->cr_ruid;
402         acct.ac_gid = p->p_ucred->cr_rgid;
403
404         /* (7) The terminal from which the process was started */
405         SESS_LOCK(p->p_session);
406         if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp)
407                 acct.ac_tty = dev2udev(p->p_pgrp->pg_session->s_ttyp->t_dev);
408         else
409                 acct.ac_tty = NODEV;
410         SESS_UNLOCK(p->p_session);
411
412         /* (8) The boolean flags that tell how the process terminated, etc. */
413         acct.ac_flagx = p->p_acflag;
414         PROC_UNLOCK(p);
415
416         /* Setup ancillary structure fields. */
417         acct.ac_flagx |= ANVER;
418         acct.ac_zero = 0;
419         acct.ac_version = 2;
420         acct.ac_len = acct.ac_len2 = sizeof(acct);
421
422         /*
423          * Eliminate any file size rlimit.
424          */
425         newlim = lim_alloc();
426         PROC_LOCK(p);
427         oldlim = p->p_limit;
428         lim_copy(newlim, oldlim);
429         newlim->pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
430         p->p_limit = newlim;
431         PROC_UNLOCK(p);
432         lim_free(oldlim);
433
434         /*
435          * Write the accounting information to the file.
436          */
437         vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount);
438         VOP_LEASE(acct_vp, td, acct_cred, LEASE_WRITE);
439         ret = vn_rdwr(UIO_WRITE, acct_vp, (caddr_t)&acct, sizeof (acct),
440             (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, acct_cred, NOCRED,
441             (int *)0, td);
442         VFS_UNLOCK_GIANT(vfslocked);
443         sx_sunlock(&acct_sx);
444         return (ret);
445 }
446
447 /* FLOAT_CONVERSION_START (Regression testing; don't remove this line.) */
448
449 /* Convert timevals and longs into IEEE-754 bit patterns. */
450
451 /* Mantissa mask (MSB is implied, so subtract 1). */
452 #define MANT_MASK ((1 << (FLT_MANT_DIG - 1)) - 1)
453
454 /*
455  * We calculate integer values to a precision of approximately
456  * 28 bits.
457  * This is high-enough precision to fill the 24 float bits
458  * and low-enough to avoid overflowing the 32 int bits.
459  */
460 #define CALC_BITS 28
461
462 /* log_2(1000000). */
463 #define LOG2_1M 20
464
465 /*
466  * Convert the elements of a timeval into a 32-bit word holding
467  * the bits of a IEEE-754 float.
468  * The float value represents the timeval's value in microsecond units.
469  */
470 static uint32_t
471 encode_timeval(struct timeval tv)
472 {
473         int log2_s;
474         int val, exp;   /* Unnormalized value and exponent */
475         int norm_exp;   /* Normalized exponent */
476         int shift;
477
478         /*
479          * First calculate value and exponent to about CALC_BITS precision.
480          * Note that the following conditionals have been ordered so that
481          * the most common cases appear first.
482          */
483         if (tv.tv_sec == 0) {
484                 if (tv.tv_usec == 0)
485                         return (0);
486                 exp = 0;
487                 val = tv.tv_usec;
488         } else {
489                 /*
490                  * Calculate the value to a precision of approximately
491                  * CALC_BITS.
492                  */
493                 log2_s = fls(tv.tv_sec) - 1;
494                 if (log2_s + LOG2_1M < CALC_BITS) {
495                         exp = 0;
496                         val = 1000000 * tv.tv_sec + tv.tv_usec;
497                 } else {
498                         exp = log2_s + LOG2_1M - CALC_BITS;
499                         val = (unsigned int)(((u_int64_t)1000000 * tv.tv_sec +
500                             tv.tv_usec) >> exp);
501                 }
502         }
503         /* Now normalize and pack the value into an IEEE-754 float. */
504         norm_exp = fls(val) - 1;
505         shift = FLT_MANT_DIG - norm_exp - 1;
506 #ifdef ACCT_DEBUG
507         printf("val=%d exp=%d shift=%d log2(val)=%d\n",
508             val, exp, shift, norm_exp);
509         printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp,
510             ((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK));
511 #endif
512         return (((FLT_MAX_EXP - 1 + exp + norm_exp) << (FLT_MANT_DIG - 1)) |
513             ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
514 }
515
516 /*
517  * Convert a non-negative long value into the bit pattern of
518  * an IEEE-754 float value.
519  */
520 static uint32_t
521 encode_long(long val)
522 {
523         int norm_exp;   /* Normalized exponent */
524         int shift;
525
526         if (val == 0)
527                 return (0);
528         if (val < 0) {
529                 log(LOG_NOTICE,
530                     "encode_long: negative value %ld in accounting record\n",
531                     val);
532                 val = LONG_MAX;
533         }
534         norm_exp = fls(val) - 1;
535         shift = FLT_MANT_DIG - norm_exp - 1;
536 #ifdef ACCT_DEBUG
537         printf("val=%d shift=%d log2(val)=%d\n",
538             val, shift, norm_exp);
539         printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp,
540             ((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK));
541 #endif
542         return (((FLT_MAX_EXP - 1 + norm_exp) << (FLT_MANT_DIG - 1)) |
543             ((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
544 }
545
546 /* FLOAT_CONVERSION_END (Regression testing; don't remove this line.) */
547
548 /*
549  * Periodically check the filesystem to see if accounting
550  * should be turned on or off.  Beware the case where the vnode
551  * has been vgone()'d out from underneath us, e.g. when the file
552  * system containing the accounting file has been forcibly unmounted.
553  */
554 /* ARGSUSED */
555 static void
556 acctwatch(void)
557 {
558         struct statfs sb;
559         int vfslocked;
560
561         sx_assert(&acct_sx, SX_XLOCKED);
562
563         /*
564          * If accounting was disabled before our kthread was scheduled,
565          * then acct_vp might be NULL.  If so, just ask our kthread to
566          * exit and return.
567          */
568         if (acct_vp == NULL) {
569                 acct_state |= ACCT_EXITREQ;
570                 return;
571         }
572
573         /*
574          * If our vnode is no longer valid, tear it down and signal the
575          * accounting thread to die.
576          */
577         vfslocked = VFS_LOCK_GIANT(acct_vp->v_mount);
578         if (acct_vp->v_type == VBAD) {
579                 (void) acct_disable(NULL);
580                 VFS_UNLOCK_GIANT(vfslocked);
581                 acct_state |= ACCT_EXITREQ;
582                 return;
583         }
584
585         /*
586          * Stopping here is better than continuing, maybe it will be VBAD
587          * next time around.
588          */
589         if (VFS_STATFS(acct_vp->v_mount, &sb, curthread) < 0) {
590                 VFS_UNLOCK_GIANT(vfslocked);
591                 return;
592         }
593         VFS_UNLOCK_GIANT(vfslocked);
594         if (acct_suspended) {
595                 if (sb.f_bavail > (int64_t)(acctresume * sb.f_blocks /
596                     100)) {
597                         acct_suspended = 0;
598                         log(LOG_NOTICE, "Accounting resumed\n");
599                 }
600         } else {
601                 if (sb.f_bavail <= (int64_t)(acctsuspend * sb.f_blocks /
602                     100)) {
603                         acct_suspended = 1;
604                         log(LOG_NOTICE, "Accounting suspended\n");
605                 }
606         }
607 }
608
609 /*
610  * The main loop for the dedicated kernel thread that periodically calls
611  * acctwatch().
612  */
613 static void
614 acct_thread(void *dummy)
615 {
616         u_char pri;
617
618         /* This is a low-priority kernel thread. */
619         pri = PRI_MAX_KERN;
620         thread_lock(curthread);
621         sched_prio(curthread, pri);
622         thread_unlock(curthread);
623
624         /* If another accounting kthread is already running, just die. */
625         sx_xlock(&acct_sx);
626         if (acct_state & ACCT_RUNNING) {
627                 sx_xunlock(&acct_sx);
628                 kthread_exit(0);
629         }
630         acct_state |= ACCT_RUNNING;
631
632         /* Loop until we are asked to exit. */
633         while (!(acct_state & ACCT_EXITREQ)) {
634
635                 /* Perform our periodic checks. */
636                 acctwatch();
637
638                 /*
639                  * We check this flag again before sleeping since the
640                  * acctwatch() might have shut down accounting and asked us
641                  * to exit.
642                  */
643                 if (!(acct_state & ACCT_EXITREQ)) {
644                         sx_sleep(&acct_state, &acct_sx, 0, "-",
645                             acctchkfreq * hz);
646                 }
647         }
648
649         /*
650          * Acknowledge the exit request and shutdown.  We clear both the
651          * exit request and running flags.
652          */
653         acct_state = 0;
654         sx_xunlock(&acct_sx);
655         kthread_exit(0);
656 }