The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_acct.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: kern_acct.c,v 1.47 2022/08/14 01:58:27 jsg Exp $      */
    2 /*      $NetBSD: kern_acct.c,v 1.42 1996/02/04 02:15:12 christos Exp $  */
    3 
    4 /*-
    5  * Copyright (c) 1994 Christopher G. Demetriou
    6  * Copyright (c) 1982, 1986, 1989, 1993
    7  *      The Regents of the University of California.  All rights reserved.
    8  * (c) UNIX System Laboratories, Inc.
    9  * All or some portions of this file are derived from material licensed
   10  * to the University of California by American Telephone and Telegraph
   11  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   12  * the permission of UNIX System Laboratories, Inc.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  * 3. Neither the name of the University nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  *
   38  *      @(#)kern_acct.c 8.1 (Berkeley) 6/14/93
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/proc.h>
   44 #include <sys/mount.h>
   45 #include <sys/vnode.h>
   46 #include <sys/fcntl.h>
   47 #include <sys/syslog.h>
   48 #include <sys/kernel.h>
   49 #include <sys/namei.h>
   50 #include <sys/errno.h>
   51 #include <sys/acct.h>
   52 #include <sys/resourcevar.h>
   53 #include <sys/tty.h>
   54 #include <sys/kthread.h>
   55 #include <sys/rwlock.h>
   56 
   57 #include <sys/syscallargs.h>
   58 
   59 /*
   60  * The routines implemented in this file are described in:
   61  *      Leffler, et al.: The Design and Implementation of the 4.3BSD
   62  *          UNIX Operating System (Addison Welley, 1989)
   63  * on pages 62-63.
   64  *
   65  * Arguably, to simplify accounting operations, this mechanism should
   66  * be replaced by one in which an accounting log file (similar to /dev/klog)
   67  * is read by a user process, etc.  However, that has its own problems.
   68  */
   69 
   70 /*
   71  * Internal accounting functions.
   72  */
   73 comp_t  encode_comp_t(u_long, u_long);
   74 int     acct_start(void);
   75 void    acct_thread(void *);
   76 void    acct_shutdown(void);
   77 
   78 /*
   79  * Accounting vnode pointer, and saved vnode pointer.
   80  */
   81 struct  vnode *acctp;
   82 struct  vnode *savacctp;
   83 
   84 /*
   85  * Lock protecting acctp and savacctp.
   86  */
   87 struct  rwlock acct_lock = RWLOCK_INITIALIZER("acctlk");
   88 
   89 /*
   90  * Values associated with enabling and disabling accounting
   91  */
   92 int     acctsuspend = 2;        /* stop accounting when < 2% free space left */
   93 int     acctresume = 4;         /* resume when free space risen to > 4% */
   94 int     acctrate = 15;          /* delay (in seconds) between space checks */
   95 
   96 struct proc *acct_proc;
   97 
   98 /*
   99  * Accounting system call.  Written based on the specification and
  100  * previous implementation done by Mark Tinguely.
  101  */
  102 int
  103 sys_acct(struct proc *p, void *v, register_t *retval)
  104 {
  105         struct sys_acct_args /* {
  106                 syscallarg(const char *) path;
  107         } */ *uap = v;
  108         struct nameidata nd;
  109         int error;
  110 
  111         /* Make sure that the caller is root. */
  112         if ((error = suser(p)) != 0)
  113                 return (error);
  114 
  115         /*
  116          * If accounting is to be started to a file, open that file for
  117          * writing and make sure it's 'normal'.
  118          */
  119         if (SCARG(uap, path) != NULL) {
  120                 NDINIT(&nd, 0, 0, UIO_USERSPACE, SCARG(uap, path), p);
  121                 if ((error = vn_open(&nd, FWRITE|O_APPEND, 0)) != 0)
  122                         return (error);
  123                 VOP_UNLOCK(nd.ni_vp);
  124                 if (nd.ni_vp->v_type != VREG) {
  125                         vn_close(nd.ni_vp, FWRITE, p->p_ucred, p);
  126                         return (EACCES);
  127                 }
  128         }
  129 
  130         rw_enter_write(&acct_lock);
  131 
  132         /*
  133          * If accounting was previously enabled, kill the old space-watcher,
  134          * close the file, and (if no new file was specified, leave).
  135          */
  136         if (acctp != NULL || savacctp != NULL) {
  137                 wakeup(&acct_proc);
  138                 (void)vn_close((acctp != NULL ? acctp : savacctp), FWRITE,
  139                     p->p_ucred, p);
  140                 acctp = savacctp = NULL;
  141         }
  142         if (SCARG(uap, path) == NULL)
  143                 goto out;
  144 
  145         /*
  146          * Save the new accounting file vnode, and schedule the new
  147          * free space watcher.
  148          */
  149         acctp = nd.ni_vp;
  150         if ((error = acct_start()) != 0) {
  151                 acctp = NULL;
  152                 (void)vn_close(nd.ni_vp, FWRITE, p->p_ucred, p);
  153         }
  154 
  155 out:
  156         rw_exit_write(&acct_lock);
  157         return (error);
  158 }
  159 
  160 /*
  161  * Write out process accounting information, on process exit.
  162  * Data to be written out is specified in Leffler, et al.
  163  * and are enumerated below.  (They're also noted in the system
  164  * "acct.h" header file.)
  165  */
  166 int
  167 acct_process(struct proc *p)
  168 {
  169         struct acct acct;
  170         struct process *pr = p->p_p;
  171         struct rusage *r;
  172         struct timespec booted, elapsed, realstart, st, tmp, uptime, ut;
  173         int t;
  174         struct vnode *vp;
  175         int error = 0;
  176 
  177         /* If accounting isn't enabled, don't bother */
  178         if (acctp == NULL)
  179                 return (0);
  180 
  181         rw_enter_read(&acct_lock);
  182 
  183         /*
  184          * Check the vnode again in case accounting got disabled while waiting
  185          * for the lock.
  186          */
  187         vp = acctp;
  188         if (vp == NULL)
  189                 goto out;
  190 
  191         /*
  192          * Get process accounting information.
  193          */
  194 
  195         /* (1) The name of the command that ran */
  196         memcpy(acct.ac_comm, pr->ps_comm, sizeof acct.ac_comm);
  197 
  198         /* (2) The amount of user and system time that was used */
  199         calctsru(&pr->ps_tu, &ut, &st, NULL);
  200         acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_nsec);
  201         acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_nsec);
  202 
  203         /* (3) The elapsed time the command ran (and its starting time) */
  204         nanouptime(&uptime);
  205         nanoboottime(&booted);
  206         timespecadd(&booted, &pr->ps_start, &realstart);
  207         acct.ac_btime = realstart.tv_sec;
  208         timespecsub(&uptime, &pr->ps_start, &elapsed);
  209         acct.ac_etime = encode_comp_t(elapsed.tv_sec, elapsed.tv_nsec);
  210 
  211         /* (4) The average amount of memory used */
  212         r = &p->p_ru;
  213         timespecadd(&ut, &st, &tmp);
  214         t = tmp.tv_sec * hz + tmp.tv_nsec / (1000 * tick);
  215         if (t)
  216                 acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t;
  217         else
  218                 acct.ac_mem = 0;
  219 
  220         /* (5) The number of disk I/O operations done */
  221         acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0);
  222 
  223         /* (6) The UID and GID of the process */
  224         acct.ac_uid = pr->ps_ucred->cr_ruid;
  225         acct.ac_gid = pr->ps_ucred->cr_rgid;
  226 
  227         /* (7) The terminal from which the process was started */
  228         if ((pr->ps_flags & PS_CONTROLT) &&
  229             pr->ps_pgrp->pg_session->s_ttyp)
  230                 acct.ac_tty = pr->ps_pgrp->pg_session->s_ttyp->t_dev;
  231         else
  232                 acct.ac_tty = -1;
  233 
  234         /* (8) The boolean flags that tell how process terminated or misbehaved. */
  235         acct.ac_flag = pr->ps_acflag;
  236 
  237         /* Extensions */
  238         acct.ac_pid = pr->ps_pid;
  239 
  240         /*
  241          * Now, just write the accounting information to the file.
  242          */
  243         error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct),
  244             (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT|IO_NOLIMIT,
  245             p->p_ucred, NULL, p);
  246 
  247 out:
  248         rw_exit_read(&acct_lock);
  249         return (error);
  250 }
  251 
  252 /*
  253  * Encode_comp_t converts from ticks in seconds and microseconds
  254  * to ticks in 1/AHZ seconds.  The encoding is described in
  255  * Leffler, et al., on page 63.
  256  */
  257 
  258 #define MANTSIZE        13                      /* 13 bit mantissa. */
  259 #define EXPSIZE         3                       /* Base 8 (3 bit) exponent. */
  260 #define MAXFRACT        ((1 << MANTSIZE) - 1)   /* Maximum fractional value. */
  261 
  262 comp_t
  263 encode_comp_t(u_long s, u_long ns)
  264 {
  265         int exp, rnd;
  266 
  267         exp = 0;
  268         rnd = 0;
  269         s *= AHZ;
  270         s += ns / (1000000000 / AHZ);   /* Maximize precision. */
  271 
  272         while (s > MAXFRACT) {
  273         rnd = s & (1 << (EXPSIZE - 1)); /* Round up? */
  274                 s >>= EXPSIZE;          /* Base 8 exponent == 3 bit shift. */
  275                 exp++;
  276         }
  277 
  278         /* If we need to round up, do it (and handle overflow correctly). */
  279         if (rnd && (++s > MAXFRACT)) {
  280                 s >>= EXPSIZE;
  281                 exp++;
  282         }
  283 
  284         /* Clean it up and polish it off. */
  285         exp <<= MANTSIZE;               /* Shift the exponent into place */
  286         exp += s;                       /* and add on the mantissa. */
  287         return (exp);
  288 }
  289 
  290 int
  291 acct_start(void)
  292 {
  293         /* Already running. */
  294         if (acct_proc != NULL)
  295                 return (0);
  296 
  297         return (kthread_create(acct_thread, NULL, &acct_proc, "acct"));
  298 }
  299 
  300 /*
  301  * Periodically check the file system to see if accounting
  302  * should be turned on or off.  Beware the case where the vnode
  303  * has been vgone()'d out from underneath us, e.g. when the file
  304  * system containing the accounting file has been forcibly unmounted.
  305  */
  306 void
  307 acct_thread(void *arg)
  308 {
  309         struct statfs sb;
  310         struct proc *p = curproc;
  311 
  312         rw_enter_write(&acct_lock);
  313         for (;;) {
  314                 if (savacctp != NULL) {
  315                         if (savacctp->v_type == VBAD) {
  316                                 (void) vn_close(savacctp, FWRITE, NOCRED, p);
  317                                 savacctp = NULL;
  318                                 break;
  319                         }
  320                         (void)VFS_STATFS(savacctp->v_mount, &sb, NULL);
  321                         if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
  322                                 acctp = savacctp;
  323                                 savacctp = NULL;
  324                                 log(LOG_NOTICE, "Accounting resumed\n");
  325                         }
  326                 } else if (acctp != NULL) {
  327                         if (acctp->v_type == VBAD) {
  328                                 (void) vn_close(acctp, FWRITE, NOCRED, p);
  329                                 acctp = NULL;
  330                                 break;
  331                         }
  332                         (void)VFS_STATFS(acctp->v_mount, &sb, NULL);
  333                         if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
  334                                 savacctp = acctp;
  335                                 acctp = NULL;
  336                                 log(LOG_NOTICE, "Accounting suspended\n");
  337                         }
  338                 } else {
  339                         break;
  340                 }
  341                 rwsleep_nsec(&acct_proc, &acct_lock, PPAUSE, "acct",
  342                     SEC_TO_NSEC(acctrate));
  343         }
  344         acct_proc = NULL;
  345         rw_exit_write(&acct_lock);
  346         kthread_exit(0);
  347 }
  348 
  349 void
  350 acct_shutdown(void)
  351 {
  352 
  353         struct proc *p = curproc;
  354 
  355         rw_enter_write(&acct_lock);
  356         if (acctp != NULL || savacctp != NULL) {
  357                 vn_close((acctp != NULL ? acctp : savacctp), FWRITE,
  358                     NOCRED, p);
  359                 acctp = savacctp = NULL;
  360         }
  361         rw_exit_write(&acct_lock);
  362 }

Cache object: 314c3f9aeac86e9291c6d9a5997c6674


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.