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 /*      $NetBSD: kern_acct.c,v 1.69 2006/11/01 10:17:58 yamt Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 1982, 1986, 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  * (c) UNIX System Laboratories, Inc.
    7  * All or some portions of this file are derived from material licensed
    8  * to the University of California by American Telephone and Telegraph
    9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   10  * the permission of UNIX System Laboratories, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)kern_acct.c 8.8 (Berkeley) 5/14/95
   37  */
   38 
   39 /*-
   40  * Copyright (c) 1994 Christopher G. Demetriou
   41  *
   42  * Redistribution and use in source and binary forms, with or without
   43  * modification, are permitted provided that the following conditions
   44  * are met:
   45  * 1. Redistributions of source code must retain the above copyright
   46  *    notice, this list of conditions and the following disclaimer.
   47  * 2. Redistributions in binary form must reproduce the above copyright
   48  *    notice, this list of conditions and the following disclaimer in the
   49  *    documentation and/or other materials provided with the distribution.
   50  * 3. All advertising materials mentioning features or use of this software
   51  *    must display the following acknowledgement:
   52  *      This product includes software developed by the University of
   53  *      California, Berkeley and its contributors.
   54  * 4. Neither the name of the University nor the names of its contributors
   55  *    may be used to endorse or promote products derived from this software
   56  *    without specific prior written permission.
   57  *
   58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   68  * SUCH DAMAGE.
   69  *
   70  *      @(#)kern_acct.c 8.8 (Berkeley) 5/14/95
   71  */
   72 
   73 #include <sys/cdefs.h>
   74 __KERNEL_RCSID(0, "$NetBSD: kern_acct.c,v 1.69 2006/11/01 10:17:58 yamt Exp $");
   75 
   76 #include <sys/param.h>
   77 #include <sys/systm.h>
   78 #include <sys/proc.h>
   79 #include <sys/mount.h>
   80 #include <sys/vnode.h>
   81 #include <sys/file.h>
   82 #include <sys/syslog.h>
   83 #include <sys/kernel.h>
   84 #include <sys/kthread.h>
   85 #include <sys/lock.h>
   86 #include <sys/malloc.h>
   87 #include <sys/namei.h>
   88 #include <sys/errno.h>
   89 #include <sys/acct.h>
   90 #include <sys/resourcevar.h>
   91 #include <sys/ioctl.h>
   92 #include <sys/tty.h>
   93 #include <sys/kauth.h>
   94 
   95 #include <sys/sa.h>
   96 #include <sys/syscallargs.h>
   97 
   98 /*
   99  * The routines implemented in this file are described in:
  100  *      Leffler, et al.: The Design and Implementation of the 4.3BSD
  101  *          UNIX Operating System (Addison Welley, 1989)
  102  * on pages 62-63.
  103  *
  104  * Arguably, to simplify accounting operations, this mechanism should
  105  * be replaced by one in which an accounting log file (similar to /dev/klog)
  106  * is read by a user process, etc.  However, that has its own problems.
  107  */
  108 
  109 /*
  110  * Lock to serialize system calls and kernel threads.
  111  */
  112 static struct lock acct_lock;
  113 #define ACCT_LOCK()                                             \
  114 do {                                                            \
  115         (void) lockmgr(&acct_lock, LK_EXCLUSIVE, NULL);         \
  116 } while (/* CONSTCOND */0)
  117 #define ACCT_UNLOCK()                                           \
  118 do {                                                            \
  119         (void) lockmgr(&acct_lock, LK_RELEASE, NULL);           \
  120 } while (/* CONSTCOND */0)
  121 
  122 /*
  123  * The global accounting state and related data.  Gain the lock before
  124  * accessing these variables.
  125  */
  126 static enum {
  127         ACCT_STOP,
  128         ACCT_ACTIVE,
  129         ACCT_SUSPENDED
  130 } acct_state;                           /* The current accounting state. */
  131 static struct vnode *acct_vp;           /* Accounting vnode pointer. */
  132 static kauth_cred_t acct_cred;          /* Credential of accounting file
  133                                            owner (i.e root).  Used when
  134                                            accounting file i/o.  */
  135 static struct proc *acct_dkwatcher;     /* Free disk space checker. */
  136 
  137 /*
  138  * Values associated with enabling and disabling accounting
  139  */
  140 int     acctsuspend = 2;        /* stop accounting when < 2% free space left */
  141 int     acctresume = 4;         /* resume when free space risen to > 4% */
  142 int     acctchkfreq = 15;       /* frequency (in seconds) to check space */
  143 
  144 /*
  145  * Encode_comp_t converts from ticks in seconds and microseconds
  146  * to ticks in 1/AHZ seconds.  The encoding is described in
  147  * Leffler, et al., on page 63.
  148  */
  149 
  150 #define MANTSIZE        13                      /* 13 bit mantissa. */
  151 #define EXPSIZE         3                       /* Base 8 (3 bit) exponent. */
  152 #define MAXFRACT        ((1 << MANTSIZE) - 1)   /* Maximum fractional value. */
  153 
  154 static comp_t
  155 encode_comp_t(u_long s, u_long us)
  156 {
  157         int exp, rnd;
  158 
  159         exp = 0;
  160         rnd = 0;
  161         s *= AHZ;
  162         s += us / (1000000 / AHZ);      /* Maximize precision. */
  163 
  164         while (s > MAXFRACT) {
  165         rnd = s & (1 << (EXPSIZE - 1)); /* Round up? */
  166                 s >>= EXPSIZE;          /* Base 8 exponent == 3 bit shift. */
  167                 exp++;
  168         }
  169 
  170         /* If we need to round up, do it (and handle overflow correctly). */
  171         if (rnd && (++s > MAXFRACT)) {
  172                 s >>= EXPSIZE;
  173                 exp++;
  174         }
  175 
  176         /* Clean it up and polish it off. */
  177         exp <<= MANTSIZE;               /* Shift the exponent into place */
  178         exp += s;                       /* and add on the mantissa. */
  179         return (exp);
  180 }
  181 
  182 static int
  183 acct_chkfree(void)
  184 {
  185         int error;
  186         struct statvfs *sb;
  187         int64_t bavail;
  188 
  189         sb = malloc(sizeof(*sb), M_TEMP, M_WAITOK);
  190         error = VFS_STATVFS(acct_vp->v_mount, sb, NULL);
  191         if (error != 0)
  192                 return (error);
  193 
  194         bavail = sb->f_bfree - sb->f_bresvd;
  195 
  196         switch (acct_state) {
  197         case ACCT_SUSPENDED:
  198                 if (bavail > acctresume * sb->f_blocks / 100) {
  199                         acct_state = ACCT_ACTIVE;
  200                         log(LOG_NOTICE, "Accounting resumed\n");
  201                 }
  202                 break;
  203         case ACCT_ACTIVE:
  204                 if (bavail <= acctsuspend * sb->f_blocks / 100) {
  205                         acct_state = ACCT_SUSPENDED;
  206                         log(LOG_NOTICE, "Accounting suspended\n");
  207                 }
  208                 break;
  209         case ACCT_STOP:
  210                 break;
  211         }
  212         free(sb, M_TEMP);
  213         return (0);
  214 }
  215 
  216 static void
  217 acct_stop(void)
  218 {
  219         int error;
  220 
  221         if (acct_vp != NULLVP && acct_vp->v_type != VBAD) {
  222                 error = vn_close(acct_vp, FWRITE, acct_cred, NULL);
  223 #ifdef DIAGNOSTIC
  224                 if (error != 0)
  225                         printf("acct_stop: failed to close, errno = %d\n",
  226                             error);
  227 #endif
  228                 acct_vp = NULLVP;
  229         }
  230         if (acct_cred != NULL) {
  231                 kauth_cred_free(acct_cred);
  232                 acct_cred = NULL;
  233         }
  234         acct_state = ACCT_STOP;
  235 }
  236 
  237 /*
  238  * Periodically check the file system to see if accounting
  239  * should be turned on or off.  Beware the case where the vnode
  240  * has been vgone()'d out from underneath us, e.g. when the file
  241  * system containing the accounting file has been forcibly unmounted.
  242  */
  243 static void
  244 acctwatch(void *arg)
  245 {
  246         int error;
  247 
  248         log(LOG_NOTICE, "Accounting started\n");
  249         ACCT_LOCK();
  250         while (acct_state != ACCT_STOP) {
  251                 if (acct_vp->v_type == VBAD) {
  252                         log(LOG_NOTICE, "Accounting terminated\n");
  253                         acct_stop();
  254                         continue;
  255                 }
  256 
  257                 error = acct_chkfree();
  258 #ifdef DIAGNOSTIC
  259                 if (error != 0)
  260                         printf("acctwatch: failed to statvfs, error = %d\n",
  261                             error);
  262 #endif
  263 
  264                 ACCT_UNLOCK();
  265                 error = tsleep(acctwatch, PSWP, "actwat", acctchkfreq * hz);
  266                 ACCT_LOCK();
  267 #ifdef DIAGNOSTIC
  268                 if (error != 0 && error != EWOULDBLOCK)
  269                         printf("acctwatch: sleep error %d\n", error);
  270 #endif
  271         }
  272         acct_dkwatcher = NULL;
  273         ACCT_UNLOCK();
  274 
  275         kthread_exit(0);
  276 }
  277 
  278 void
  279 acct_init(void)
  280 {
  281 
  282         acct_state = ACCT_STOP;
  283         acct_vp = NULLVP;
  284         acct_cred = NULL;
  285         lockinit(&acct_lock, PWAIT, "acctlk", 0, 0);
  286 }
  287 
  288 /*
  289  * Accounting system call.  Written based on the specification and
  290  * previous implementation done by Mark Tinguely.
  291  */
  292 int
  293 sys_acct(struct lwp *l, void *v, register_t *retval)
  294 {
  295         struct sys_acct_args /* {
  296                 syscallarg(const char *) path;
  297         } */ *uap = v;
  298         struct nameidata nd;
  299         int error;
  300 
  301         /* Make sure that the caller is root. */
  302         if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_ACCOUNTING,
  303             0, NULL, NULL, NULL)))
  304                 return (error);
  305 
  306         /*
  307          * If accounting is to be started to a file, open that file for
  308          * writing and make sure it's a 'normal'.
  309          */
  310         if (SCARG(uap, path) != NULL) {
  311                 struct vattr va;
  312                 size_t pad;
  313                 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path),
  314                     l);
  315                 if ((error = vn_open(&nd, FWRITE|O_APPEND, 0)) != 0)
  316                         return (error);
  317                 if (nd.ni_vp->v_type != VREG) {
  318                         VOP_UNLOCK(nd.ni_vp, 0);
  319                         error = EACCES;
  320                         goto bad;
  321                 }
  322                 if ((error = VOP_GETATTR(nd.ni_vp, &va, l->l_cred, l)) != 0) {
  323                         VOP_UNLOCK(nd.ni_vp, 0);
  324                         goto bad;
  325                 }
  326 
  327                 if ((pad = (va.va_size % sizeof(struct acct))) != 0) {
  328                         u_quad_t size = va.va_size - pad;
  329 #ifdef DIAGNOSTIC
  330                         printf("Size of accounting file not a multiple of "
  331                             "%lu - incomplete record truncated\n",
  332                             (unsigned long)sizeof(struct acct));
  333 #endif
  334                         VATTR_NULL(&va);
  335                         va.va_size = size;
  336                         error = VOP_SETATTR(nd.ni_vp, &va, l->l_cred, l);
  337                         if (error != 0) {
  338                                 VOP_UNLOCK(nd.ni_vp, 0);
  339                                 goto bad;
  340                         }
  341                 }
  342                 VOP_UNLOCK(nd.ni_vp, 0);
  343         }
  344 
  345         ACCT_LOCK();
  346 
  347         /*
  348          * If accounting was previously enabled, kill the old space-watcher,
  349          * free credential for accounting file i/o,
  350          * ... (and, if no new file was specified, leave).
  351          */
  352         acct_stop();
  353         if (SCARG(uap, path) == NULL)
  354                 goto out;
  355 
  356         /*
  357          * Save the new accounting file vnode and credential,
  358          * and schedule the new free space watcher.
  359          */
  360         acct_state = ACCT_ACTIVE;
  361         acct_vp = nd.ni_vp;
  362         acct_cred = l->l_cred;
  363         kauth_cred_hold(acct_cred);
  364 
  365         error = acct_chkfree();         /* Initial guess. */
  366         if (error != 0) {
  367                 acct_stop();
  368                 goto out;
  369         }
  370 
  371         if (acct_dkwatcher == NULL) {
  372                 error = kthread_create1(acctwatch, NULL, &acct_dkwatcher,
  373                     "acctwatch");
  374                 if (error != 0)
  375                         acct_stop();
  376         }
  377 
  378  out:
  379         ACCT_UNLOCK();
  380         return (error);
  381  bad:
  382         vn_close(nd.ni_vp, FWRITE, l->l_cred, l);
  383         return error;
  384 }
  385 
  386 /*
  387  * Write out process accounting information, on process exit.
  388  * Data to be written out is specified in Leffler, et al.
  389  * and are enumerated below.  (They're also noted in the system
  390  * "acct.h" header file.)
  391  */
  392 int
  393 acct_process(struct lwp *l)
  394 {
  395         struct acct acct;
  396         struct timeval ut, st, tmp;
  397         struct rusage *r;
  398         int t, error = 0;
  399         struct plimit *oplim = NULL;
  400         struct proc *p = l->l_proc;
  401 
  402         ACCT_LOCK();
  403 
  404         /* If accounting isn't enabled, don't bother */
  405         if (acct_state != ACCT_ACTIVE)
  406                 goto out;
  407 
  408         /*
  409          * Raise the file limit so that accounting can't be stopped by
  410          * the user.
  411          *
  412          * XXX We should think about the CPU limit, too.
  413          */
  414         if (p->p_limit->p_refcnt > 1) {
  415                 oplim = p->p_limit;
  416                 p->p_limit = limcopy(p->p_limit);
  417         }
  418         p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
  419 
  420         /*
  421          * Get process accounting information.
  422          */
  423 
  424         /* (1) The name of the command that ran */
  425         memcpy(acct.ac_comm, p->p_comm, sizeof(acct.ac_comm));
  426 
  427         /* (2) The amount of user and system time that was used */
  428         calcru(p, &ut, &st, NULL);
  429         acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec);
  430         acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec);
  431 
  432         /* (3) The elapsed time the commmand ran (and its starting time) */
  433         acct.ac_btime = p->p_stats->p_start.tv_sec;
  434         getmicrotime(&tmp);
  435         timersub(&tmp, &p->p_stats->p_start, &tmp);
  436         acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec);
  437 
  438         /* (4) The average amount of memory used */
  439         r = &p->p_stats->p_ru;
  440         timeradd(&ut, &st, &tmp);
  441         t = tmp.tv_sec * hz + tmp.tv_usec / tick;
  442         if (t)
  443                 acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t;
  444         else
  445                 acct.ac_mem = 0;
  446 
  447         /* (5) The number of disk I/O operations done */
  448         acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0);
  449 
  450         /* (6) The UID and GID of the process */
  451         acct.ac_uid = kauth_cred_getuid(l->l_cred);
  452         acct.ac_gid = kauth_cred_getgid(l->l_cred);
  453 
  454         /* (7) The terminal from which the process was started */
  455         if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp)
  456                 acct.ac_tty = p->p_pgrp->pg_session->s_ttyp->t_dev;
  457         else
  458                 acct.ac_tty = NODEV;
  459 
  460         /* (8) The boolean flags that tell how the process terminated, etc. */
  461         acct.ac_flag = p->p_acflag;
  462 
  463         /*
  464          * Now, just write the accounting information to the file.
  465          */
  466         VOP_LEASE(acct_vp, l, l->l_cred, LEASE_WRITE);
  467         error = vn_rdwr(UIO_WRITE, acct_vp, (caddr_t)&acct,
  468             sizeof(acct), (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT,
  469             acct_cred, NULL, NULL);
  470         if (error != 0)
  471                 log(LOG_ERR, "Accounting: write failed %d\n", error);
  472 
  473         if (oplim) {
  474                 limfree(p->p_limit);
  475                 p->p_limit = oplim;
  476         }
  477 
  478  out:
  479         ACCT_UNLOCK();
  480         return (error);
  481 }

Cache object: f8e730eaa1957190807d0351b2c4c21f


[ 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.