10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
54584Srh87107 * Common Development and Distribution License (the "License").
64584Srh87107 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
2212725SMenno.Lageman@Sun.COM * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <sys/exacct.h>
260Sstevel@tonic-gate #include <sys/exacct_catalog.h>
270Sstevel@tonic-gate #include <sys/disp.h>
280Sstevel@tonic-gate #include <sys/task.h>
290Sstevel@tonic-gate #include <sys/proc.h>
300Sstevel@tonic-gate #include <sys/cmn_err.h>
310Sstevel@tonic-gate #include <sys/kmem.h>
320Sstevel@tonic-gate #include <sys/project.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/vnode.h>
350Sstevel@tonic-gate #include <sys/file.h>
360Sstevel@tonic-gate #include <sys/acctctl.h>
370Sstevel@tonic-gate #include <sys/time.h>
380Sstevel@tonic-gate #include <sys/utsname.h>
390Sstevel@tonic-gate #include <sys/session.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <sys/bitmap.h>
420Sstevel@tonic-gate #include <sys/msacct.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate * exacct usage and recording routines
460Sstevel@tonic-gate *
470Sstevel@tonic-gate * wracct(2), getacct(2), and the records written at process or task
480Sstevel@tonic-gate * termination are constructed using the exacct_assemble_[task,proc]_usage()
490Sstevel@tonic-gate * functions, which take a callback that takes the appropriate action on
500Sstevel@tonic-gate * the packed exacct record for the task or process. For the process-related
510Sstevel@tonic-gate * actions, we partition the routines such that the data collecting component
520Sstevel@tonic-gate * can be performed while holding p_lock, and all sleeping or blocking
530Sstevel@tonic-gate * operations can be performed without acquiring p_lock.
540Sstevel@tonic-gate *
550Sstevel@tonic-gate * putacct(2), which allows an application to construct a customized record
560Sstevel@tonic-gate * associated with an existing process or task, has its own entry points:
570Sstevel@tonic-gate * exacct_tag_task() and exacct_tag_proc().
580Sstevel@tonic-gate */
590Sstevel@tonic-gate
600Sstevel@tonic-gate taskq_t *exacct_queue;
610Sstevel@tonic-gate kmem_cache_t *exacct_object_cache;
620Sstevel@tonic-gate
630Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED;
640Sstevel@tonic-gate
650Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION;
660Sstevel@tonic-gate static const char exacct_header[] = "exacct";
670Sstevel@tonic-gate static const char exacct_creator[] = "SunOS";
680Sstevel@tonic-gate
690Sstevel@tonic-gate ea_object_t *
ea_alloc_item(ea_catalog_t catalog,void * buf,size_t bufsz)700Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate ea_object_t *item;
730Sstevel@tonic-gate
740Sstevel@tonic-gate item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
750Sstevel@tonic-gate bzero(item, sizeof (ea_object_t));
760Sstevel@tonic-gate (void) ea_set_item(item, catalog, buf, bufsz);
770Sstevel@tonic-gate return (item);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate
800Sstevel@tonic-gate ea_object_t *
ea_alloc_group(ea_catalog_t catalog)810Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog)
820Sstevel@tonic-gate {
830Sstevel@tonic-gate ea_object_t *group;
840Sstevel@tonic-gate
850Sstevel@tonic-gate group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
860Sstevel@tonic-gate bzero(group, sizeof (ea_object_t));
870Sstevel@tonic-gate (void) ea_set_group(group, catalog);
880Sstevel@tonic-gate return (group);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate
910Sstevel@tonic-gate ea_object_t *
ea_attach_item(ea_object_t * grp,void * buf,size_t bufsz,ea_catalog_t catalog)920Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog)
930Sstevel@tonic-gate {
940Sstevel@tonic-gate ea_object_t *item;
950Sstevel@tonic-gate
960Sstevel@tonic-gate item = ea_alloc_item(catalog, buf, bufsz);
970Sstevel@tonic-gate (void) ea_attach_to_group(grp, item);
980Sstevel@tonic-gate return (item);
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /*
1024584Srh87107 * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract
1034584Srh87107 * microstate accounting data and resource usage counters from one task_usage_t
1044584Srh87107 * from those supplied in another. These functions do not operate on *all*
1054584Srh87107 * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make
1064584Srh87107 * sense.
1074584Srh87107 */
1084584Srh87107 static void
exacct_add_task_mstate(task_usage_t * tu,task_usage_t * delta)1094584Srh87107 exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta)
1104584Srh87107 {
1114584Srh87107 tu->tu_utime += delta->tu_utime;
1124584Srh87107 tu->tu_stime += delta->tu_stime;
1134584Srh87107 tu->tu_minflt += delta->tu_minflt;
1144584Srh87107 tu->tu_majflt += delta->tu_majflt;
1154584Srh87107 tu->tu_sndmsg += delta->tu_sndmsg;
1164584Srh87107 tu->tu_rcvmsg += delta->tu_rcvmsg;
1174584Srh87107 tu->tu_ioch += delta->tu_ioch;
1184584Srh87107 tu->tu_iblk += delta->tu_iblk;
1194584Srh87107 tu->tu_oblk += delta->tu_oblk;
1204584Srh87107 tu->tu_vcsw += delta->tu_vcsw;
1214584Srh87107 tu->tu_icsw += delta->tu_icsw;
1224584Srh87107 tu->tu_nsig += delta->tu_nsig;
1234584Srh87107 tu->tu_nswp += delta->tu_nswp;
1244584Srh87107 tu->tu_nscl += delta->tu_nscl;
1254584Srh87107 }
1264584Srh87107
1274584Srh87107 /*
1284584Srh87107 * See the comments for exacct_add_task_mstate(), above.
1294584Srh87107 */
1304584Srh87107 static void
exacct_sub_task_mstate(task_usage_t * tu,task_usage_t * delta)1314584Srh87107 exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta)
1324584Srh87107 {
1334584Srh87107 tu->tu_utime -= delta->tu_utime;
1344584Srh87107 tu->tu_stime -= delta->tu_stime;
1354584Srh87107 tu->tu_minflt -= delta->tu_minflt;
1364584Srh87107 tu->tu_majflt -= delta->tu_majflt;
1374584Srh87107 tu->tu_sndmsg -= delta->tu_sndmsg;
1384584Srh87107 tu->tu_rcvmsg -= delta->tu_rcvmsg;
1394584Srh87107 tu->tu_ioch -= delta->tu_ioch;
1404584Srh87107 tu->tu_iblk -= delta->tu_iblk;
1414584Srh87107 tu->tu_oblk -= delta->tu_oblk;
1424584Srh87107 tu->tu_vcsw -= delta->tu_vcsw;
1434584Srh87107 tu->tu_icsw -= delta->tu_icsw;
1444584Srh87107 tu->tu_nsig -= delta->tu_nsig;
1454584Srh87107 tu->tu_nswp -= delta->tu_nswp;
1464584Srh87107 tu->tu_nscl -= delta->tu_nscl;
1474584Srh87107 }
1484584Srh87107
1494584Srh87107 /*
1507103Sml93401 * Wrapper for vn_rdwr() used by exacct_vn_write() and exacct_write_header()
1517103Sml93401 * to write to the accounting file without corrupting it in case of an I/O or
1527103Sml93401 * filesystem error.
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate static int
exacct_vn_write_impl(ac_info_t * info,void * buf,ssize_t bufsize)1557103Sml93401 exacct_vn_write_impl(ac_info_t *info, void *buf, ssize_t bufsize)
1560Sstevel@tonic-gate {
1577103Sml93401 int error;
1580Sstevel@tonic-gate ssize_t resid;
1590Sstevel@tonic-gate struct vattr va;
1600Sstevel@tonic-gate
1617103Sml93401 ASSERT(info != NULL);
1627103Sml93401 ASSERT(info->ac_vnode != NULL);
1637103Sml93401 ASSERT(MUTEX_HELD(&info->ac_lock));
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * Save the size. If vn_rdwr fails, reset the size to avoid corrupting
1670Sstevel@tonic-gate * the present accounting file.
1680Sstevel@tonic-gate */
1690Sstevel@tonic-gate va.va_mask = AT_SIZE;
1705331Samw error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1710Sstevel@tonic-gate if (error == 0) {
1720Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf,
1730Sstevel@tonic-gate bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T,
1740Sstevel@tonic-gate kcred, &resid);
1750Sstevel@tonic-gate if (error) {
1760Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1770Sstevel@tonic-gate } else if (resid != 0) {
1780Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1790Sstevel@tonic-gate error = ENOSPC;
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate }
1827103Sml93401 return (error);
1837103Sml93401 }
1847103Sml93401
1857103Sml93401 /*
1867103Sml93401 * exacct_vn_write() safely writes to an accounting file. acctctl() prevents
1877103Sml93401 * the two accounting vnodes from being equal, and the appropriate ac_lock is
1887103Sml93401 * held across the call, so we're single threaded through this code for each
1897103Sml93401 * file.
1907103Sml93401 */
1917103Sml93401 static int
exacct_vn_write(ac_info_t * info,void * buf,ssize_t bufsize)1927103Sml93401 exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize)
1937103Sml93401 {
1947103Sml93401 int error;
1957103Sml93401
1967103Sml93401 if (info == NULL)
1977103Sml93401 return (0);
1987103Sml93401
1997103Sml93401 mutex_enter(&info->ac_lock);
2007103Sml93401
2017103Sml93401 /*
2027103Sml93401 * Don't do anything unless accounting file is set.
2037103Sml93401 */
2047103Sml93401 if (info->ac_vnode == NULL) {
2057103Sml93401 mutex_exit(&info->ac_lock);
2067103Sml93401 return (0);
2077103Sml93401 }
2087103Sml93401 error = exacct_vn_write_impl(info, buf, bufsize);
2090Sstevel@tonic-gate mutex_exit(&info->ac_lock);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate return (error);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate * void *exacct_create_header(size_t *)
2160Sstevel@tonic-gate *
2170Sstevel@tonic-gate * Overview
2180Sstevel@tonic-gate * exacct_create_header() constructs an exacct file header identifying the
2190Sstevel@tonic-gate * accounting file as the output of the kernel. exacct_create_header() and
2200Sstevel@tonic-gate * the static write_header() and verify_header() routines in libexacct must
2210Sstevel@tonic-gate * remain synchronized.
2220Sstevel@tonic-gate *
2230Sstevel@tonic-gate * Return values
2240Sstevel@tonic-gate * A pointer to a packed exacct buffer containing the appropriate header is
2250Sstevel@tonic-gate * returned; the size of the buffer is placed in the location indicated by
2260Sstevel@tonic-gate * sizep.
2270Sstevel@tonic-gate *
2280Sstevel@tonic-gate * Caller's context
2290Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
2300Sstevel@tonic-gate */
2310Sstevel@tonic-gate void *
exacct_create_header(size_t * sizep)2320Sstevel@tonic-gate exacct_create_header(size_t *sizep)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate ea_object_t *hdr_grp;
2350Sstevel@tonic-gate uint32_t bskip;
2360Sstevel@tonic-gate void *buf;
2370Sstevel@tonic-gate size_t bufsize;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER);
2400Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0,
2410Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_VERSION);
2420Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_header, 0,
2430Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_FILETYPE);
2440Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0,
2450Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_CREATOR);
2460Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, uts_nodename(), 0,
2470Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME);
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate bufsize = ea_pack_object(hdr_grp, NULL, 0);
2500Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
2510Sstevel@tonic-gate (void) ea_pack_object(hdr_grp, buf, bufsize);
2520Sstevel@tonic-gate ea_free_object(hdr_grp, EUP_ALLOC);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate * To prevent reading the header when reading the file backwards,
2560Sstevel@tonic-gate * set the large backskip of the header group to 0 (last 4 bytes).
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate bskip = 0;
2590Sstevel@tonic-gate exacct_order32(&bskip);
2600Sstevel@tonic-gate bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip),
2610Sstevel@tonic-gate sizeof (bskip));
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate *sizep = bufsize;
2640Sstevel@tonic-gate return (buf);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /*
2680Sstevel@tonic-gate * int exacct_write_header(ac_info_t *, void *, size_t)
2690Sstevel@tonic-gate *
2700Sstevel@tonic-gate * Overview
2710Sstevel@tonic-gate * exacct_write_header() writes the given header buffer to the indicated
2727103Sml93401 * vnode.
2730Sstevel@tonic-gate *
2740Sstevel@tonic-gate * Return values
2750Sstevel@tonic-gate * The result of the write operation is returned.
2760Sstevel@tonic-gate *
2770Sstevel@tonic-gate * Caller's context
2787103Sml93401 * Caller must hold the ac_lock of the appropriate accounting file
2790Sstevel@tonic-gate * information block (ac_info_t).
2800Sstevel@tonic-gate */
2810Sstevel@tonic-gate int
exacct_write_header(ac_info_t * info,void * hdr,size_t hdrsize)2820Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize)
2830Sstevel@tonic-gate {
2847103Sml93401 if (info != NULL && info->ac_vnode != NULL)
2857103Sml93401 return (exacct_vn_write_impl(info, hdr, hdrsize));
2860Sstevel@tonic-gate
2877103Sml93401 return (0);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate static void
exacct_get_interval_task_usage(task_t * tk,task_usage_t * tu,task_usage_t ** tu_buf)2910Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu,
2920Sstevel@tonic-gate task_usage_t **tu_buf)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate task_usage_t *oldtu, *newtu;
2950Sstevel@tonic-gate task_usage_t **prevusage;
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tk->tk_usage_lock));
2980Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) {
2990Sstevel@tonic-gate prevusage = &tk->tk_zoneusage;
3000Sstevel@tonic-gate } else {
3010Sstevel@tonic-gate prevusage = &tk->tk_prevusage;
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate if ((oldtu = *prevusage) != NULL) {
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate * In case we have any accounting information
3060Sstevel@tonic-gate * saved from the previous interval record.
3070Sstevel@tonic-gate */
3080Sstevel@tonic-gate newtu = *tu_buf;
3090Sstevel@tonic-gate bcopy(tu, newtu, sizeof (task_usage_t));
3100Sstevel@tonic-gate tu->tu_minflt -= oldtu->tu_minflt;
3110Sstevel@tonic-gate tu->tu_majflt -= oldtu->tu_majflt;
3120Sstevel@tonic-gate tu->tu_sndmsg -= oldtu->tu_sndmsg;
3130Sstevel@tonic-gate tu->tu_rcvmsg -= oldtu->tu_rcvmsg;
3140Sstevel@tonic-gate tu->tu_ioch -= oldtu->tu_ioch;
3150Sstevel@tonic-gate tu->tu_iblk -= oldtu->tu_iblk;
3160Sstevel@tonic-gate tu->tu_oblk -= oldtu->tu_oblk;
3170Sstevel@tonic-gate tu->tu_vcsw -= oldtu->tu_vcsw;
3180Sstevel@tonic-gate tu->tu_icsw -= oldtu->tu_icsw;
3190Sstevel@tonic-gate tu->tu_nsig -= oldtu->tu_nsig;
3200Sstevel@tonic-gate tu->tu_nswp -= oldtu->tu_nswp;
3210Sstevel@tonic-gate tu->tu_nscl -= oldtu->tu_nscl;
3220Sstevel@tonic-gate tu->tu_utime -= oldtu->tu_utime;
3230Sstevel@tonic-gate tu->tu_stime -= oldtu->tu_stime;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate tu->tu_startsec = oldtu->tu_finishsec;
3260Sstevel@tonic-gate tu->tu_startnsec = oldtu->tu_finishnsec;
3270Sstevel@tonic-gate /*
3280Sstevel@tonic-gate * Copy the data from our temporary storage to the task's
3290Sstevel@tonic-gate * previous interval usage structure for future reference.
3300Sstevel@tonic-gate */
3310Sstevel@tonic-gate bcopy(newtu, oldtu, sizeof (task_usage_t));
3320Sstevel@tonic-gate } else {
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate * Store current statistics in the task's previous interval
3350Sstevel@tonic-gate * usage structure for future references.
3360Sstevel@tonic-gate */
3370Sstevel@tonic-gate *prevusage = *tu_buf;
3380Sstevel@tonic-gate bcopy(tu, *prevusage, sizeof (task_usage_t));
3390Sstevel@tonic-gate *tu_buf = NULL;
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate static void
exacct_snapshot_task_usage(task_t * tk,task_usage_t * tu)3440Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu)
3450Sstevel@tonic-gate {
3460Sstevel@tonic-gate timestruc_t ts;
3470Sstevel@tonic-gate proc_t *p;
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock));
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate if ((p = tk->tk_memb_list) == NULL)
3520Sstevel@tonic-gate return;
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * exacct_snapshot_task_usage() provides an approximate snapshot of the
3560Sstevel@tonic-gate * usage of the potentially many members of the task. Since we don't
3570Sstevel@tonic-gate * guarantee exactness, we don't acquire the p_lock of any of the member
3580Sstevel@tonic-gate * processes.
3590Sstevel@tonic-gate */
3600Sstevel@tonic-gate do {
3610Sstevel@tonic-gate mutex_enter(&p->p_lock);
3620Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER);
3630Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM);
3640Sstevel@tonic-gate mutex_exit(&p->p_lock);
3650Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt;
3660Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt;
3670Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd;
3680Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv;
3690Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch;
3700Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock;
3710Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock;
3720Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw;
3730Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw;
3740Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals;
3750Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap;
3760Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc;
3770Sstevel@tonic-gate } while ((p = p->p_tasknext) != tk->tk_memb_list);
3780Sstevel@tonic-gate
3794584Srh87107 /*
3804584Srh87107 * The resource usage accounted for so far will include that
3814584Srh87107 * contributed by the task's first process. If this process
3824584Srh87107 * came from another task, then its accumulated resource usage
3834584Srh87107 * will include a contribution from work performed there.
3844584Srh87107 * We must therefore subtract any resource usage that was
3854584Srh87107 * inherited with the first process.
3864584Srh87107 */
3874584Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited);
3884584Srh87107
3890Sstevel@tonic-gate gethrestime(&ts);
3900Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
3910Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate /*
3954584Srh87107 * void exacct_update_task_mstate(proc_t *)
3964584Srh87107 *
3974584Srh87107 * Overview
3984584Srh87107 * exacct_update_task_mstate() updates the task usage; it is intended
3994584Srh87107 * to be called from proc_exit().
4004584Srh87107 *
4014584Srh87107 * Return values
4024584Srh87107 * None.
4034584Srh87107 *
4044584Srh87107 * Caller's context
4054584Srh87107 * p_lock must be held at entry.
4060Sstevel@tonic-gate */
4074584Srh87107 void
exacct_update_task_mstate(proc_t * p)4080Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate task_usage_t *tu;
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate mutex_enter(&p->p_task->tk_usage_lock);
4130Sstevel@tonic-gate tu = p->p_task->tk_usage;
4140Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER);
4150Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM);
4160Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt;
4170Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt;
4180Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd;
4190Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv;
4200Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch;
4210Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock;
4220Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock;
4230Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw;
4240Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw;
4250Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals;
4260Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap;
4270Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc;
4280Sstevel@tonic-gate mutex_exit(&p->p_task->tk_usage_lock);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate static void
exacct_calculate_task_usage(task_t * tk,task_usage_t * tu,int flag)4320Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate timestruc_t ts;
4350Sstevel@tonic-gate task_usage_t *tu_buf;
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate switch (flag) {
4380Sstevel@tonic-gate case EW_PARTIAL:
4390Sstevel@tonic-gate /*
4400Sstevel@tonic-gate * For partial records we must report the sum of current
4410Sstevel@tonic-gate * accounting statistics with previously accumulated
4420Sstevel@tonic-gate * statistics.
4430Sstevel@tonic-gate */
4440Sstevel@tonic-gate mutex_enter(&pidlock);
4450Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock);
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4480Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu);
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock);
4510Sstevel@tonic-gate mutex_exit(&pidlock);
4520Sstevel@tonic-gate break;
4530Sstevel@tonic-gate case EW_INTERVAL:
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate * We need to allocate spare task_usage_t buffer before
4560Sstevel@tonic-gate * grabbing pidlock because we might need it later in
4570Sstevel@tonic-gate * exacct_get_interval_task_usage().
4580Sstevel@tonic-gate */
4590Sstevel@tonic-gate tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
4600Sstevel@tonic-gate mutex_enter(&pidlock);
4610Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock);
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /*
4640Sstevel@tonic-gate * For interval records, we deduct the previous microstate
4650Sstevel@tonic-gate * accounting data and cpu usage times from previously saved
4660Sstevel@tonic-gate * results and update the previous task usage structure.
4670Sstevel@tonic-gate */
4680Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4690Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu);
4700Sstevel@tonic-gate exacct_get_interval_task_usage(tk, tu, &tu_buf);
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock);
4730Sstevel@tonic-gate mutex_exit(&pidlock);
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate if (tu_buf != NULL)
4760Sstevel@tonic-gate kmem_free(tu_buf, sizeof (task_usage_t));
4770Sstevel@tonic-gate break;
4780Sstevel@tonic-gate case EW_FINAL:
4790Sstevel@tonic-gate /*
4804584Srh87107 * For final records, we deduct, from the task's current
4814584Srh87107 * usage, any usage that was inherited with the arrival
4824584Srh87107 * of a process from a previous task. We then record
4834584Srh87107 * the task's finish time.
4840Sstevel@tonic-gate */
4850Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock);
4860Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4874584Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited);
4880Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock);
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate gethrestime(&ts);
4910Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
4920Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate break;
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate static int
exacct_attach_task_item(task_t * tk,task_usage_t * tu,ea_object_t * record,int res)4990Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record,
5000Sstevel@tonic-gate int res)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate int attached = 1;
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate switch (res) {
5050Sstevel@tonic-gate case AC_TASK_TASKID:
5060Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_tkid,
5070Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID);
5080Sstevel@tonic-gate break;
5090Sstevel@tonic-gate case AC_TASK_PROJID:
5100Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_proj->kpj_id,
5110Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID);
5120Sstevel@tonic-gate break;
5130Sstevel@tonic-gate case AC_TASK_CPU: {
5140Sstevel@tonic-gate timestruc_t ts;
5150Sstevel@tonic-gate uint64_t ui;
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate hrt2ts(tu->tu_stime, &ts);
5180Sstevel@tonic-gate ui = ts.tv_sec;
5190Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t),
5200Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_SEC);
5210Sstevel@tonic-gate ui = ts.tv_nsec;
5220Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t),
5230Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC);
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate hrt2ts(tu->tu_utime, &ts);
5260Sstevel@tonic-gate ui = ts.tv_sec;
5270Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t),
5280Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_SEC);
5290Sstevel@tonic-gate ui = ts.tv_nsec;
5300Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t),
5310Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_NSEC);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate break;
5340Sstevel@tonic-gate case AC_TASK_TIME:
5350Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startsec,
5360Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC);
5370Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startnsec,
5380Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC);
5390Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishsec,
5400Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC);
5410Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishnsec,
5420Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC);
5430Sstevel@tonic-gate break;
5440Sstevel@tonic-gate case AC_TASK_HOSTNAME:
5450Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_nodename,
5460Sstevel@tonic-gate strlen(tk->tk_zone->zone_nodename) + 1,
5470Sstevel@tonic-gate EXT_STRING | EXD_TASK_HOSTNAME);
5480Sstevel@tonic-gate break;
5490Sstevel@tonic-gate case AC_TASK_MICROSTATE:
5500Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_majflt,
5510Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR);
5520Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_minflt,
5530Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR);
5540Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_sndmsg,
5550Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND);
5560Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_rcvmsg,
5570Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV);
5580Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_iblk,
5590Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN);
5600Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_oblk,
5610Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT);
5620Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_ioch,
5630Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR);
5640Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_vcsw,
5650Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL);
5660Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_icsw,
5670Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV);
5680Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nsig,
5690Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS);
5700Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nswp,
5710Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS);
5720Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nscl,
5730Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS);
5740Sstevel@tonic-gate break;
5750Sstevel@tonic-gate case AC_TASK_ANCTASKID:
5760Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_anctaskid,
5770Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID);
5780Sstevel@tonic-gate break;
5790Sstevel@tonic-gate case AC_TASK_ZONENAME:
5800Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_name,
5810Sstevel@tonic-gate strlen(tk->tk_zone->zone_name) + 1,
5820Sstevel@tonic-gate EXT_STRING | EXD_TASK_ZONENAME);
5830Sstevel@tonic-gate break;
5840Sstevel@tonic-gate default:
5850Sstevel@tonic-gate attached = 0;
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate return (attached);
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate static ea_object_t *
exacct_assemble_task_record(task_t * tk,task_usage_t * tu,ulong_t * mask,ea_catalog_t record_type)5910Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask,
5920Sstevel@tonic-gate ea_catalog_t record_type)
5930Sstevel@tonic-gate {
5940Sstevel@tonic-gate int res, count;
5950Sstevel@tonic-gate ea_object_t *record;
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate /*
5980Sstevel@tonic-gate * Assemble usage values into group.
5990Sstevel@tonic-gate */
6000Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
6010Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++)
6020Sstevel@tonic-gate if (BT_TEST(mask, res))
6030Sstevel@tonic-gate count += exacct_attach_task_item(tk, tu, record, res);
6040Sstevel@tonic-gate if (count == 0) {
6050Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC);
6060Sstevel@tonic-gate record = NULL;
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate return (record);
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate /*
6120Sstevel@tonic-gate * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *,
6130Sstevel@tonic-gate * size_t, size_t *), void *, size_t, size_t *, int)
6140Sstevel@tonic-gate *
6150Sstevel@tonic-gate * Overview
6160Sstevel@tonic-gate * exacct_assemble_task_usage() builds the packed exacct buffer for the
6170Sstevel@tonic-gate * indicated task, executes the given callback function, and free the packed
6180Sstevel@tonic-gate * buffer.
6190Sstevel@tonic-gate *
6200Sstevel@tonic-gate * Return values
6210Sstevel@tonic-gate * Returns 0 on success; otherwise the appropriate error code is returned.
6220Sstevel@tonic-gate *
6230Sstevel@tonic-gate * Caller's context
6240Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
6250Sstevel@tonic-gate */
6260Sstevel@tonic-gate int
exacct_assemble_task_usage(ac_info_t * ac_task,task_t * tk,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual,int flag)6270Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk,
6280Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
6290Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
6320Sstevel@tonic-gate ea_object_t *task_record;
6330Sstevel@tonic-gate ea_catalog_t record_type;
6340Sstevel@tonic-gate task_usage_t *tu;
6350Sstevel@tonic-gate void *buf;
6360Sstevel@tonic-gate size_t bufsize;
6370Sstevel@tonic-gate int ret;
6380Sstevel@tonic-gate
6390Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL);
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock);
6420Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF) {
6430Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock);
6440Sstevel@tonic-gate return (ENOTACTIVE);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ);
6470Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock);
6480Sstevel@tonic-gate
6490Sstevel@tonic-gate switch (flag) {
6500Sstevel@tonic-gate case EW_FINAL:
6510Sstevel@tonic-gate record_type = EXD_GROUP_TASK;
6520Sstevel@tonic-gate break;
6530Sstevel@tonic-gate case EW_PARTIAL:
6540Sstevel@tonic-gate record_type = EXD_GROUP_TASK_PARTIAL;
6550Sstevel@tonic-gate break;
6560Sstevel@tonic-gate case EW_INTERVAL:
6570Sstevel@tonic-gate record_type = EXD_GROUP_TASK_INTERVAL;
6580Sstevel@tonic-gate break;
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate * Calculate task usage and assemble it into the task record.
6630Sstevel@tonic-gate */
6640Sstevel@tonic-gate tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
6650Sstevel@tonic-gate exacct_calculate_task_usage(tk, tu, flag);
6660Sstevel@tonic-gate task_record = exacct_assemble_task_record(tk, tu, mask, record_type);
6670Sstevel@tonic-gate if (task_record == NULL) {
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate * The current configuration of the accounting system has
6700Sstevel@tonic-gate * resulted in records with no data; accordingly, we don't write
6710Sstevel@tonic-gate * these, but we return success.
6720Sstevel@tonic-gate */
6730Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t));
6740Sstevel@tonic-gate return (0);
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate /*
6780Sstevel@tonic-gate * Pack object into buffer and run callback on it.
6790Sstevel@tonic-gate */
6800Sstevel@tonic-gate bufsize = ea_pack_object(task_record, NULL, 0);
6810Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
6820Sstevel@tonic-gate (void) ea_pack_object(task_record, buf, bufsize);
6830Sstevel@tonic-gate ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual);
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate /*
6860Sstevel@tonic-gate * Free all previously allocated structures.
6870Sstevel@tonic-gate */
6880Sstevel@tonic-gate kmem_free(buf, bufsize);
6890Sstevel@tonic-gate ea_free_object(task_record, EUP_ALLOC);
6900Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t));
6910Sstevel@tonic-gate return (ret);
6920Sstevel@tonic-gate }
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate /*
6950Sstevel@tonic-gate * void exacct_commit_task(void *)
6960Sstevel@tonic-gate *
6970Sstevel@tonic-gate * Overview
6980Sstevel@tonic-gate * exacct_commit_task() calculates the final usage for a task, updating the
6990Sstevel@tonic-gate * task usage if task accounting is active, and writing a task record if task
7000Sstevel@tonic-gate * accounting is active. exacct_commit_task() is intended for being called
7010Sstevel@tonic-gate * from a task queue (taskq_t).
7020Sstevel@tonic-gate *
7030Sstevel@tonic-gate * Return values
7040Sstevel@tonic-gate * None.
7050Sstevel@tonic-gate *
7060Sstevel@tonic-gate * Caller's context
7070Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
7080Sstevel@tonic-gate */
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate void
exacct_commit_task(void * arg)7110Sstevel@tonic-gate exacct_commit_task(void *arg)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate task_t *tk = (task_t *)arg;
7140Sstevel@tonic-gate size_t size;
7150Sstevel@tonic-gate zone_t *zone = tk->tk_zone;
7160Sstevel@tonic-gate struct exacct_globals *acg;
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate ASSERT(tk != task0p);
7190Sstevel@tonic-gate ASSERT(tk->tk_memb_list == NULL);
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate /*
7220Sstevel@tonic-gate * Don't do any extra work if the acctctl module isn't loaded.
723*12982SVamsi.Krishna@Sun.COM * If acctctl module is loaded when zone is in down state then
724*12982SVamsi.Krishna@Sun.COM * zone_getspecific can return NULL for that zone.
7250Sstevel@tonic-gate */
7260Sstevel@tonic-gate if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) {
7270Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone);
728*12982SVamsi.Krishna@Sun.COM if (acg == NULL)
729*12982SVamsi.Krishna@Sun.COM goto err;
7300Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk,
7310Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7320Sstevel@tonic-gate if (tk->tk_zone != global_zone) {
7330Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone);
7340Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk,
7350Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate * Release associated project and finalize task.
7400Sstevel@tonic-gate */
741*12982SVamsi.Krishna@Sun.COM err:
7420Sstevel@tonic-gate task_end(tk);
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate static int
exacct_attach_proc_item(proc_usage_t * pu,ea_object_t * record,int res)7460Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res)
7470Sstevel@tonic-gate {
7480Sstevel@tonic-gate int attached = 1;
7490Sstevel@tonic-gate
7500Sstevel@tonic-gate switch (res) {
7510Sstevel@tonic-gate case AC_PROC_PID:
7520Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_pid,
7530Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID);
7540Sstevel@tonic-gate break;
7550Sstevel@tonic-gate case AC_PROC_UID:
7560Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ruid,
7570Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID);
7580Sstevel@tonic-gate break;
7590Sstevel@tonic-gate case AC_PROC_FLAG:
7600Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_acflag,
7610Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS);
7620Sstevel@tonic-gate break;
7630Sstevel@tonic-gate case AC_PROC_GID:
7640Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rgid,
7650Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID);
7660Sstevel@tonic-gate break;
7670Sstevel@tonic-gate case AC_PROC_PROJID:
7680Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_projid,
7690Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID);
7700Sstevel@tonic-gate break;
7710Sstevel@tonic-gate case AC_PROC_TASKID:
7720Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_taskid,
7730Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID);
7740Sstevel@tonic-gate break;
7750Sstevel@tonic-gate case AC_PROC_CPU:
7760Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimesec,
7770Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC);
7780Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimensec,
7790Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC);
7800Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimesec,
7810Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC);
7820Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimensec,
7830Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC);
7840Sstevel@tonic-gate break;
7850Sstevel@tonic-gate case AC_PROC_TIME:
7860Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startsec,
7870Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC);
7880Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startnsec,
7890Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC);
7900Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishsec,
7910Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC);
7920Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishnsec,
7930Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC);
7940Sstevel@tonic-gate break;
7950Sstevel@tonic-gate case AC_PROC_COMMAND:
7960Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_command,
7970Sstevel@tonic-gate strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND);
7980Sstevel@tonic-gate break;
7990Sstevel@tonic-gate case AC_PROC_HOSTNAME:
8000Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_nodename,
8010Sstevel@tonic-gate strlen(pu->pu_nodename) + 1,
8020Sstevel@tonic-gate EXT_STRING | EXD_PROC_HOSTNAME);
8030Sstevel@tonic-gate break;
8040Sstevel@tonic-gate case AC_PROC_TTY:
8050Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_major,
8060Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR);
8070Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minor,
8080Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR);
8090Sstevel@tonic-gate break;
8100Sstevel@tonic-gate case AC_PROC_MICROSTATE:
8110Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_majflt,
8120Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR);
8130Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minflt,
8140Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR);
8150Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_sndmsg,
8160Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND);
8170Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rcvmsg,
8180Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV);
8190Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_iblk,
8200Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN);
8210Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_oblk,
8220Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT);
8230Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ioch,
8240Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR);
8250Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_vcsw,
8260Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL);
8270Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_icsw,
8280Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV);
8290Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nsig,
8300Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS);
8310Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nswp,
8320Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS);
8330Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nscl,
8340Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS);
8350Sstevel@tonic-gate break;
8360Sstevel@tonic-gate case AC_PROC_ANCPID:
8370Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ancpid,
8380Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID);
8390Sstevel@tonic-gate break;
8400Sstevel@tonic-gate case AC_PROC_WAIT_STATUS:
8410Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_wstat,
8420Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS);
8430Sstevel@tonic-gate break;
8440Sstevel@tonic-gate case AC_PROC_ZONENAME:
8450Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_zonename,
8460Sstevel@tonic-gate strlen(pu->pu_zonename) + 1,
8470Sstevel@tonic-gate EXT_STRING | EXD_PROC_ZONENAME);
8480Sstevel@tonic-gate break;
8490Sstevel@tonic-gate case AC_PROC_MEM:
8500Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_avg,
8510Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K);
8520Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_max,
8530Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K);
8540Sstevel@tonic-gate break;
8550Sstevel@tonic-gate default:
8560Sstevel@tonic-gate attached = 0;
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate return (attached);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate static ea_object_t *
exacct_assemble_proc_record(proc_usage_t * pu,ulong_t * mask,ea_catalog_t record_type)8620Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask,
8630Sstevel@tonic-gate ea_catalog_t record_type)
8640Sstevel@tonic-gate {
8650Sstevel@tonic-gate int res, count;
8660Sstevel@tonic-gate ea_object_t *record;
8670Sstevel@tonic-gate
8680Sstevel@tonic-gate /*
8690Sstevel@tonic-gate * Assemble usage values into group.
8700Sstevel@tonic-gate */
8710Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
8720Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++)
8730Sstevel@tonic-gate if (BT_TEST(mask, res))
8744584Srh87107 count += exacct_attach_proc_item(pu, record, res);
8750Sstevel@tonic-gate if (count == 0) {
8760Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC);
8770Sstevel@tonic-gate record = NULL;
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate return (record);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate /*
8830Sstevel@tonic-gate * The following two routines assume that process's p_lock is held or
8840Sstevel@tonic-gate * exacct_commit_proc has been called from exit() when all lwps are stopped.
8850Sstevel@tonic-gate */
8860Sstevel@tonic-gate static void
exacct_calculate_proc_mstate(proc_t * p,proc_usage_t * pu)8870Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate kthread_t *t;
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock));
8920Sstevel@tonic-gate if ((t = p->p_tlist) == NULL)
8930Sstevel@tonic-gate return;
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate do {
8960Sstevel@tonic-gate pu->pu_minflt += t->t_lwp->lwp_ru.minflt;
8970Sstevel@tonic-gate pu->pu_majflt += t->t_lwp->lwp_ru.majflt;
8980Sstevel@tonic-gate pu->pu_sndmsg += t->t_lwp->lwp_ru.msgsnd;
8990Sstevel@tonic-gate pu->pu_rcvmsg += t->t_lwp->lwp_ru.msgrcv;
9000Sstevel@tonic-gate pu->pu_ioch += t->t_lwp->lwp_ru.ioch;
9010Sstevel@tonic-gate pu->pu_iblk += t->t_lwp->lwp_ru.inblock;
9020Sstevel@tonic-gate pu->pu_oblk += t->t_lwp->lwp_ru.oublock;
9030Sstevel@tonic-gate pu->pu_vcsw += t->t_lwp->lwp_ru.nvcsw;
9040Sstevel@tonic-gate pu->pu_icsw += t->t_lwp->lwp_ru.nivcsw;
9050Sstevel@tonic-gate pu->pu_nsig += t->t_lwp->lwp_ru.nsignals;
9060Sstevel@tonic-gate pu->pu_nswp += t->t_lwp->lwp_ru.nswap;
9070Sstevel@tonic-gate pu->pu_nscl += t->t_lwp->lwp_ru.sysc;
9080Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist);
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate static void
exacct_copy_proc_mstate(proc_t * p,proc_usage_t * pu)9120Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu)
9130Sstevel@tonic-gate {
9140Sstevel@tonic-gate pu->pu_minflt = p->p_ru.minflt;
9150Sstevel@tonic-gate pu->pu_majflt = p->p_ru.majflt;
9160Sstevel@tonic-gate pu->pu_sndmsg = p->p_ru.msgsnd;
9170Sstevel@tonic-gate pu->pu_rcvmsg = p->p_ru.msgrcv;
9180Sstevel@tonic-gate pu->pu_ioch = p->p_ru.ioch;
9190Sstevel@tonic-gate pu->pu_iblk = p->p_ru.inblock;
9200Sstevel@tonic-gate pu->pu_oblk = p->p_ru.oublock;
9210Sstevel@tonic-gate pu->pu_vcsw = p->p_ru.nvcsw;
9220Sstevel@tonic-gate pu->pu_icsw = p->p_ru.nivcsw;
9230Sstevel@tonic-gate pu->pu_nsig = p->p_ru.nsignals;
9240Sstevel@tonic-gate pu->pu_nswp = p->p_ru.nswap;
9250Sstevel@tonic-gate pu->pu_nscl = p->p_ru.sysc;
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate void
exacct_calculate_proc_usage(proc_t * p,proc_usage_t * pu,ulong_t * mask,int flag,int wstat)9290Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask,
9300Sstevel@tonic-gate int flag, int wstat)
9310Sstevel@tonic-gate {
9320Sstevel@tonic-gate timestruc_t ts, ts_run;
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock));
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate * Convert CPU and execution times to sec/nsec format.
9380Sstevel@tonic-gate */
9390Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_CPU)) {
9400Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_USER), &ts);
9410Sstevel@tonic-gate pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec;
9420Sstevel@tonic-gate pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9430Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts);
9440Sstevel@tonic-gate pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec;
9450Sstevel@tonic-gate pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9460Sstevel@tonic-gate }
9470Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_TIME)) {
9480Sstevel@tonic-gate gethrestime(&ts);
9490Sstevel@tonic-gate pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
9500Sstevel@tonic-gate pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9510Sstevel@tonic-gate hrt2ts(gethrtime() - p->p_mstart, &ts_run);
9520Sstevel@tonic-gate ts.tv_sec -= ts_run.tv_sec;
9530Sstevel@tonic-gate ts.tv_nsec -= ts_run.tv_nsec;
9540Sstevel@tonic-gate if (ts.tv_nsec < 0) {
9550Sstevel@tonic-gate ts.tv_sec--;
9560Sstevel@tonic-gate if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) {
9570Sstevel@tonic-gate ts.tv_sec++;
9580Sstevel@tonic-gate ts.tv_nsec -= NANOSEC;
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec;
9620Sstevel@tonic-gate pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate pu->pu_pid = p->p_pidp->pid_id;
9660Sstevel@tonic-gate pu->pu_acflag = p->p_user.u_acflag;
9670Sstevel@tonic-gate pu->pu_projid = p->p_task->tk_proj->kpj_id;
9680Sstevel@tonic-gate pu->pu_taskid = p->p_task->tk_tkid;
9690Sstevel@tonic-gate pu->pu_major = getmajor(p->p_sessp->s_dev);
9700Sstevel@tonic-gate pu->pu_minor = getminor(p->p_sessp->s_dev);
9710Sstevel@tonic-gate pu->pu_ancpid = p->p_ancpid;
9720Sstevel@tonic-gate pu->pu_wstat = wstat;
9730Sstevel@tonic-gate /*
9740Sstevel@tonic-gate * Compute average RSS in K. The denominator is the number of
9750Sstevel@tonic-gate * samples: the number of clock ticks plus the initial value.
9760Sstevel@tonic-gate */
9770Sstevel@tonic-gate pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) *
9780Sstevel@tonic-gate (PAGESIZE / 1024);
9790Sstevel@tonic-gate pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024);
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate mutex_enter(&p->p_crlock);
9820Sstevel@tonic-gate pu->pu_ruid = crgetruid(p->p_cred);
9830Sstevel@tonic-gate pu->pu_rgid = crgetrgid(p->p_cred);
9840Sstevel@tonic-gate mutex_exit(&p->p_crlock);
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1);
9870Sstevel@tonic-gate bcopy(p->p_zone->zone_name, pu->pu_zonename,
9880Sstevel@tonic-gate strlen(p->p_zone->zone_name) + 1);
9890Sstevel@tonic-gate bcopy(p->p_zone->zone_nodename, pu->pu_nodename,
9900Sstevel@tonic-gate strlen(p->p_zone->zone_nodename) + 1);
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate /*
9930Sstevel@tonic-gate * Calculate microstate accounting data for a process that is still
9940Sstevel@tonic-gate * running. Presently, we explicitly collect all of the LWP usage into
9950Sstevel@tonic-gate * the proc usage structure here.
9960Sstevel@tonic-gate */
9970Sstevel@tonic-gate if (flag & EW_PARTIAL)
9980Sstevel@tonic-gate exacct_calculate_proc_mstate(p, pu);
9990Sstevel@tonic-gate if (flag & EW_FINAL)
10000Sstevel@tonic-gate exacct_copy_proc_mstate(p, pu);
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate /*
10040Sstevel@tonic-gate * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void
10050Sstevel@tonic-gate * *, size_t, size_t *), void *, size_t, size_t *)
10060Sstevel@tonic-gate *
10070Sstevel@tonic-gate * Overview
10080Sstevel@tonic-gate * Assemble record with miscellaneous accounting information about the process
10090Sstevel@tonic-gate * and execute the callback on it. It is the callback's job to set "actual" to
10100Sstevel@tonic-gate * the size of record.
10110Sstevel@tonic-gate *
10120Sstevel@tonic-gate * Return values
10130Sstevel@tonic-gate * The result of the callback function, unless the extended process accounting
10140Sstevel@tonic-gate * feature is not active, in which case ENOTACTIVE is returned.
10150Sstevel@tonic-gate *
10160Sstevel@tonic-gate * Caller's context
10170Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
10180Sstevel@tonic-gate */
10190Sstevel@tonic-gate int
exacct_assemble_proc_usage(ac_info_t * ac_proc,proc_usage_t * pu,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual,int flag)10200Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu,
10210Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
10220Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag)
10230Sstevel@tonic-gate {
10240Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
10250Sstevel@tonic-gate ea_object_t *proc_record;
10260Sstevel@tonic-gate ea_catalog_t record_type;
10270Sstevel@tonic-gate void *buf;
10280Sstevel@tonic-gate size_t bufsize;
10290Sstevel@tonic-gate int ret;
10300Sstevel@tonic-gate
10310Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL);
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock);
10340Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF) {
10350Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
10360Sstevel@tonic-gate return (ENOTACTIVE);
10370Sstevel@tonic-gate }
10380Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
10390Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
10400Sstevel@tonic-gate
10410Sstevel@tonic-gate switch (flag) {
10420Sstevel@tonic-gate case EW_FINAL:
10430Sstevel@tonic-gate record_type = EXD_GROUP_PROC;
10440Sstevel@tonic-gate break;
10450Sstevel@tonic-gate case EW_PARTIAL:
10460Sstevel@tonic-gate record_type = EXD_GROUP_PROC_PARTIAL;
10470Sstevel@tonic-gate break;
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate proc_record = exacct_assemble_proc_record(pu, mask, record_type);
10510Sstevel@tonic-gate if (proc_record == NULL)
10520Sstevel@tonic-gate return (0);
10530Sstevel@tonic-gate
10540Sstevel@tonic-gate /*
10550Sstevel@tonic-gate * Pack object into buffer and pass to callback.
10560Sstevel@tonic-gate */
10570Sstevel@tonic-gate bufsize = ea_pack_object(proc_record, NULL, 0);
10580Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
10590Sstevel@tonic-gate (void) ea_pack_object(proc_record, buf, bufsize);
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual);
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate /*
10640Sstevel@tonic-gate * Free all previously allocations.
10650Sstevel@tonic-gate */
10660Sstevel@tonic-gate kmem_free(buf, bufsize);
10670Sstevel@tonic-gate ea_free_object(proc_record, EUP_ALLOC);
10680Sstevel@tonic-gate return (ret);
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate /*
10720Sstevel@tonic-gate * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t,
10730Sstevel@tonic-gate * size_t *)
10740Sstevel@tonic-gate *
10750Sstevel@tonic-gate * Overview
10760Sstevel@tonic-gate * exacct_commit_callback() writes the indicated buffer to the indicated
10770Sstevel@tonic-gate * extended accounting file.
10780Sstevel@tonic-gate *
10790Sstevel@tonic-gate * Return values
10800Sstevel@tonic-gate * The result of the write operation is returned. "actual" is updated to
10810Sstevel@tonic-gate * contain the number of bytes actually written.
10820Sstevel@tonic-gate *
10830Sstevel@tonic-gate * Caller's context
10840Sstevel@tonic-gate * Suitable for a vn_rdwr() operation.
10850Sstevel@tonic-gate */
10860Sstevel@tonic-gate /*ARGSUSED*/
10870Sstevel@tonic-gate int
exacct_commit_callback(ac_info_t * info,void * ubuf,size_t ubufsize,void * buf,size_t bufsize,size_t * actual)10880Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize,
10890Sstevel@tonic-gate void *buf, size_t bufsize, size_t *actual)
10900Sstevel@tonic-gate {
10910Sstevel@tonic-gate int error = 0;
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate *actual = 0;
10940Sstevel@tonic-gate if ((error = exacct_vn_write(info, buf, bufsize)) == 0)
10950Sstevel@tonic-gate *actual = bufsize;
10960Sstevel@tonic-gate return (error);
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate static void
exacct_do_commit_proc(ac_info_t * ac_proc,proc_t * p,int wstat)11000Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat)
11010Sstevel@tonic-gate {
11020Sstevel@tonic-gate size_t size;
11030Sstevel@tonic-gate proc_usage_t *pu;
11040Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
11050Sstevel@tonic-gate
11060Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock);
11070Sstevel@tonic-gate if (ac_proc->ac_state == AC_ON) {
11080Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
11090Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
11100Sstevel@tonic-gate } else {
11110Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
11120Sstevel@tonic-gate return;
11130Sstevel@tonic-gate }
11140Sstevel@tonic-gate
11150Sstevel@tonic-gate mutex_enter(&p->p_lock);
11160Sstevel@tonic-gate size = strlen(p->p_user.u_comm) + 1;
11170Sstevel@tonic-gate mutex_exit(&p->p_lock);
11180Sstevel@tonic-gate
11190Sstevel@tonic-gate pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP);
11200Sstevel@tonic-gate pu->pu_command = kmem_alloc(size, KM_SLEEP);
11210Sstevel@tonic-gate mutex_enter(&p->p_lock);
11220Sstevel@tonic-gate exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat);
11230Sstevel@tonic-gate mutex_exit(&p->p_lock);
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate (void) exacct_assemble_proc_usage(ac_proc, pu,
11260Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL);
11270Sstevel@tonic-gate
11280Sstevel@tonic-gate kmem_free(pu->pu_command, strlen(pu->pu_command) + 1);
11290Sstevel@tonic-gate kmem_free(pu, sizeof (proc_usage_t));
11300Sstevel@tonic-gate }
11314584Srh87107
11320Sstevel@tonic-gate /*
11330Sstevel@tonic-gate * void exacct_commit_proc(proc_t *, int)
11340Sstevel@tonic-gate *
11350Sstevel@tonic-gate * Overview
11360Sstevel@tonic-gate * exacct_commit_proc() calculates the final usage for a process, updating the
11370Sstevel@tonic-gate * task usage if task accounting is active, and writing a process record if
11380Sstevel@tonic-gate * process accounting is active. exacct_commit_proc() is intended for being
11390Sstevel@tonic-gate * called from proc_exit().
11400Sstevel@tonic-gate *
11410Sstevel@tonic-gate * Return values
11420Sstevel@tonic-gate * None.
11430Sstevel@tonic-gate *
11440Sstevel@tonic-gate * Caller's context
11450Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. p_lock must not be held at entry.
11460Sstevel@tonic-gate */
11470Sstevel@tonic-gate void
exacct_commit_proc(proc_t * p,int wstat)11480Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat)
11490Sstevel@tonic-gate {
11500Sstevel@tonic-gate zone_t *zone = p->p_zone;
11510Sstevel@tonic-gate struct exacct_globals *acg, *gacg = NULL;
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
11540Sstevel@tonic-gate /*
11550Sstevel@tonic-gate * acctctl module not loaded. Nothing to do.
11560Sstevel@tonic-gate */
11570Sstevel@tonic-gate return;
11580Sstevel@tonic-gate }
1159*12982SVamsi.Krishna@Sun.COM
1160*12982SVamsi.Krishna@Sun.COM /*
1161*12982SVamsi.Krishna@Sun.COM * If acctctl module is loaded when zone is in down state then
1162*12982SVamsi.Krishna@Sun.COM * zone_getspecific can return NULL for that zone.
1163*12982SVamsi.Krishna@Sun.COM */
11640Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone);
1165*12982SVamsi.Krishna@Sun.COM if (acg == NULL)
1166*12982SVamsi.Krishna@Sun.COM return;
11674584Srh87107 exacct_do_commit_proc(&acg->ac_proc, p, wstat);
11684584Srh87107 if (zone != global_zone) {
11690Sstevel@tonic-gate gacg = zone_getspecific(exacct_zone_key, global_zone);
11704584Srh87107 exacct_do_commit_proc(&gacg->ac_proc, p, wstat);
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate static int
exacct_attach_netstat_item(net_stat_t * ns,ea_object_t * record,int res)11758275SEric Cheng exacct_attach_netstat_item(net_stat_t *ns, ea_object_t *record, int res)
11768275SEric Cheng {
11778275SEric Cheng int attached = 1;
11788275SEric Cheng
11798275SEric Cheng switch (res) {
11808275SEric Cheng case AC_NET_NAME:
11818275SEric Cheng (void) ea_attach_item(record, ns->ns_name,
11828275SEric Cheng strlen(ns->ns_name) + 1, EXT_STRING | EXD_NET_STATS_NAME);
11838275SEric Cheng break;
11848275SEric Cheng case AC_NET_CURTIME:
11858275SEric Cheng {
11868275SEric Cheng uint64_t now;
11878275SEric Cheng timestruc_t ts;
11888275SEric Cheng
11898275SEric Cheng gethrestime(&ts);
11908275SEric Cheng now = (uint64_t)(ulong_t)ts.tv_sec;
11918275SEric Cheng (void) ea_attach_item(record, &now, sizeof (uint64_t),
11928275SEric Cheng EXT_UINT64 | EXD_NET_STATS_CURTIME);
11938275SEric Cheng }
11948275SEric Cheng break;
11958275SEric Cheng case AC_NET_IBYTES:
11968275SEric Cheng (void) ea_attach_item(record, &ns->ns_ibytes,
11978275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IBYTES);
11988275SEric Cheng break;
11998275SEric Cheng case AC_NET_OBYTES:
12008275SEric Cheng (void) ea_attach_item(record, &ns->ns_obytes,
12018275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OBYTES);
12028275SEric Cheng break;
12038275SEric Cheng case AC_NET_IPKTS:
12048275SEric Cheng (void) ea_attach_item(record, &ns->ns_ipackets,
12058275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IPKTS);
12068275SEric Cheng break;
12078275SEric Cheng case AC_NET_OPKTS:
12088275SEric Cheng (void) ea_attach_item(record, &ns->ns_opackets,
12098275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OPKTS);
12108275SEric Cheng break;
12118275SEric Cheng case AC_NET_IERRPKTS:
12128275SEric Cheng (void) ea_attach_item(record, &ns->ns_ierrors,
12138275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IERRPKTS);
12148275SEric Cheng break;
12158275SEric Cheng case AC_NET_OERRPKTS:
12168275SEric Cheng (void) ea_attach_item(record, &ns->ns_oerrors,
12178275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OERRPKTS);
12188275SEric Cheng break;
12198275SEric Cheng default:
12208275SEric Cheng attached = 0;
12218275SEric Cheng }
12228275SEric Cheng return (attached);
12238275SEric Cheng }
12248275SEric Cheng
12258275SEric Cheng static int
exacct_attach_netdesc_item(net_desc_t * nd,ea_object_t * record,int res)12268275SEric Cheng exacct_attach_netdesc_item(net_desc_t *nd, ea_object_t *record, int res)
12278275SEric Cheng {
12288275SEric Cheng int attached = 1;
12298275SEric Cheng
12308275SEric Cheng switch (res) {
12318275SEric Cheng case AC_NET_NAME:
12328275SEric Cheng (void) ea_attach_item(record, nd->nd_name,
12338275SEric Cheng strlen(nd->nd_name) + 1, EXT_STRING | EXD_NET_DESC_NAME);
12348275SEric Cheng break;
12358275SEric Cheng case AC_NET_DEVNAME:
12368275SEric Cheng (void) ea_attach_item(record, nd->nd_devname,
12378275SEric Cheng strlen(nd->nd_devname) + 1, EXT_STRING |
12388275SEric Cheng EXD_NET_DESC_DEVNAME);
12398275SEric Cheng break;
12408275SEric Cheng case AC_NET_EHOST:
12418275SEric Cheng (void) ea_attach_item(record, &nd->nd_ehost,
12428275SEric Cheng sizeof (nd->nd_ehost), EXT_RAW | EXD_NET_DESC_EHOST);
12438275SEric Cheng break;
12448275SEric Cheng case AC_NET_EDEST:
12458275SEric Cheng (void) ea_attach_item(record, &nd->nd_edest,
12468275SEric Cheng sizeof (nd->nd_edest), EXT_RAW | EXD_NET_DESC_EDEST);
12478275SEric Cheng break;
12488275SEric Cheng case AC_NET_VLAN_TPID:
12498275SEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tpid,
12508275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TPID);
12518275SEric Cheng break;
12528275SEric Cheng case AC_NET_VLAN_TCI:
12538275SEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tci,
12548275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TCI);
12558275SEric Cheng break;
12568275SEric Cheng case AC_NET_SAP:
12578275SEric Cheng (void) ea_attach_item(record, &nd->nd_sap,
12588275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_SAP);
12598275SEric Cheng break;
12608275SEric Cheng case AC_NET_PRIORITY:
12618275SEric Cheng (void) ea_attach_item(record, &nd->nd_priority,
12628275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_PRIORITY);
12638275SEric Cheng break;
12648275SEric Cheng case AC_NET_BWLIMIT:
12658275SEric Cheng (void) ea_attach_item(record, &nd->nd_bw_limit,
12668275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_DESC_BWLIMIT);
12678275SEric Cheng break;
12688275SEric Cheng case AC_NET_SADDR:
12698275SEric Cheng if (nd->nd_isv4) {
12708275SEric Cheng (void) ea_attach_item(record, &nd->nd_saddr[3],
12718275SEric Cheng sizeof (uint32_t), EXT_UINT32 |
12728275SEric Cheng EXD_NET_DESC_V4SADDR);
12738275SEric Cheng } else {
12748275SEric Cheng (void) ea_attach_item(record, &nd->nd_saddr,
12758275SEric Cheng sizeof (nd->nd_saddr), EXT_RAW |
12768275SEric Cheng EXD_NET_DESC_V6SADDR);
12778275SEric Cheng }
12788275SEric Cheng break;
12798275SEric Cheng case AC_NET_DADDR:
12808275SEric Cheng if (nd->nd_isv4) {
12818275SEric Cheng (void) ea_attach_item(record, &nd->nd_daddr[3],
12828275SEric Cheng sizeof (uint32_t), EXT_UINT32 |
12838275SEric Cheng EXD_NET_DESC_V4DADDR);
12848275SEric Cheng } else {
12858275SEric Cheng (void) ea_attach_item(record, &nd->nd_daddr,
12868275SEric Cheng sizeof (nd->nd_daddr), EXT_RAW |
12878275SEric Cheng EXD_NET_DESC_V6DADDR);
12888275SEric Cheng }
12898275SEric Cheng break;
12908275SEric Cheng case AC_NET_SPORT:
12918275SEric Cheng (void) ea_attach_item(record, &nd->nd_sport,
12928275SEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_SPORT);
12938275SEric Cheng break;
12948275SEric Cheng case AC_NET_DPORT:
12958275SEric Cheng (void) ea_attach_item(record, &nd->nd_dport,
12968275SEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_DPORT);
12978275SEric Cheng break;
12988275SEric Cheng case AC_NET_PROTOCOL:
12998275SEric Cheng (void) ea_attach_item(record, &nd->nd_protocol,
13008275SEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_PROTOCOL);
13018275SEric Cheng break;
13028275SEric Cheng case AC_NET_DSFIELD:
13038275SEric Cheng (void) ea_attach_item(record, &nd->nd_dsfield,
13048275SEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_DSFIELD);
13058275SEric Cheng break;
13068275SEric Cheng default:
13078275SEric Cheng attached = 0;
13088275SEric Cheng }
13098275SEric Cheng return (attached);
13108275SEric Cheng }
13118275SEric Cheng
13128275SEric Cheng static ea_object_t *
exacct_assemble_net_record(void * ninfo,ulong_t * mask,ea_catalog_t record_type,int what)13138275SEric Cheng exacct_assemble_net_record(void *ninfo, ulong_t *mask, ea_catalog_t record_type,
13148275SEric Cheng int what)
13158275SEric Cheng {
13168275SEric Cheng int res;
13178275SEric Cheng int count;
13188275SEric Cheng ea_object_t *record;
13198275SEric Cheng
13208275SEric Cheng /*
13218275SEric Cheng * Assemble usage values into group.
13228275SEric Cheng */
13238275SEric Cheng record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
13248275SEric Cheng for (res = 1, count = 0; res <= AC_NET_MAX_RES; res++)
13258275SEric Cheng if (BT_TEST(mask, res)) {
13268275SEric Cheng if (what == EX_NET_LNDESC_REC ||
13278275SEric Cheng what == EX_NET_FLDESC_REC) {
13288275SEric Cheng count += exacct_attach_netdesc_item(
13298275SEric Cheng (net_desc_t *)ninfo, record, res);
13308275SEric Cheng } else {
13318275SEric Cheng count += exacct_attach_netstat_item(
13328275SEric Cheng (net_stat_t *)ninfo, record, res);
13338275SEric Cheng }
13348275SEric Cheng }
13358275SEric Cheng if (count == 0) {
13368275SEric Cheng ea_free_object(record, EUP_ALLOC);
13378275SEric Cheng record = NULL;
13388275SEric Cheng }
13398275SEric Cheng return (record);
13408275SEric Cheng }
13418275SEric Cheng
13428275SEric Cheng int
exacct_assemble_net_usage(ac_info_t * ac_net,void * ninfo,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual,int what)13438275SEric Cheng exacct_assemble_net_usage(ac_info_t *ac_net, void *ninfo,
13448275SEric Cheng int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
13458275SEric Cheng void *ubuf, size_t ubufsize, size_t *actual, int what)
13468275SEric Cheng {
13478275SEric Cheng ulong_t mask[AC_MASK_SZ];
13488275SEric Cheng ea_object_t *net_desc;
13498275SEric Cheng ea_catalog_t record_type;
13508275SEric Cheng void *buf;
13518275SEric Cheng size_t bufsize;
13528275SEric Cheng int ret;
13538275SEric Cheng
13548275SEric Cheng mutex_enter(&ac_net->ac_lock);
13558275SEric Cheng if (ac_net->ac_state == AC_OFF) {
13568275SEric Cheng mutex_exit(&ac_net->ac_lock);
13578275SEric Cheng return (ENOTACTIVE);
13588275SEric Cheng }
13598275SEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ);
13608275SEric Cheng mutex_exit(&ac_net->ac_lock);
13618275SEric Cheng
13628275SEric Cheng switch (what) {
13638275SEric Cheng case EX_NET_LNDESC_REC:
13648275SEric Cheng record_type = EXD_GROUP_NET_LINK_DESC;
13658275SEric Cheng break;
13668275SEric Cheng case EX_NET_LNSTAT_REC:
13678275SEric Cheng record_type = EXD_GROUP_NET_LINK_STATS;
13688275SEric Cheng break;
13698275SEric Cheng case EX_NET_FLDESC_REC:
13708275SEric Cheng record_type = EXD_GROUP_NET_FLOW_DESC;
13718275SEric Cheng break;
13728275SEric Cheng case EX_NET_FLSTAT_REC:
13738275SEric Cheng record_type = EXD_GROUP_NET_FLOW_STATS;
13748275SEric Cheng break;
13758275SEric Cheng }
13768275SEric Cheng
13778275SEric Cheng net_desc = exacct_assemble_net_record(ninfo, mask, record_type, what);
13788275SEric Cheng if (net_desc == NULL)
13798275SEric Cheng return (0);
13808275SEric Cheng
13818275SEric Cheng /*
13828275SEric Cheng * Pack object into buffer and pass to callback.
13838275SEric Cheng */
13848275SEric Cheng bufsize = ea_pack_object(net_desc, NULL, 0);
13858275SEric Cheng buf = kmem_alloc(bufsize, KM_NOSLEEP);
13868275SEric Cheng if (buf == NULL)
13878275SEric Cheng return (ENOMEM);
13888275SEric Cheng
13898275SEric Cheng (void) ea_pack_object(net_desc, buf, bufsize);
13908275SEric Cheng
13918275SEric Cheng ret = callback(ac_net, ubuf, ubufsize, buf, bufsize, actual);
13928275SEric Cheng
13938275SEric Cheng /*
13948275SEric Cheng * Free all previously allocations.
13958275SEric Cheng */
13968275SEric Cheng kmem_free(buf, bufsize);
13978275SEric Cheng ea_free_object(net_desc, EUP_ALLOC);
13988275SEric Cheng return (ret);
13998275SEric Cheng }
14008275SEric Cheng
14018275SEric Cheng int
exacct_commit_netinfo(void * arg,int what)14028275SEric Cheng exacct_commit_netinfo(void *arg, int what)
14038275SEric Cheng {
14048275SEric Cheng size_t size;
14058275SEric Cheng ulong_t mask[AC_MASK_SZ];
14068275SEric Cheng struct exacct_globals *acg;
14078275SEric Cheng ac_info_t *ac_net;
14088275SEric Cheng
14098275SEric Cheng if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
14108275SEric Cheng /*
14118275SEric Cheng * acctctl module not loaded. Nothing to do.
14128275SEric Cheng */
14138275SEric Cheng return (ENOTACTIVE);
14148275SEric Cheng }
14158275SEric Cheng
14168275SEric Cheng /*
14178275SEric Cheng * Even though each zone nominally has its own flow accounting settings
14188275SEric Cheng * (ac_flow), these are only maintained by and for the global zone.
14198275SEric Cheng *
14208275SEric Cheng * If this were to change in the future, this function should grow a
14218275SEric Cheng * second zoneid (or zone) argument, and use the corresponding zone's
14228275SEric Cheng * settings rather than always using those of the global zone.
14238275SEric Cheng */
14248275SEric Cheng acg = zone_getspecific(exacct_zone_key, global_zone);
14258275SEric Cheng ac_net = &acg->ac_net;
14268275SEric Cheng
14278275SEric Cheng mutex_enter(&ac_net->ac_lock);
14288275SEric Cheng if (ac_net->ac_state == AC_OFF) {
14298275SEric Cheng mutex_exit(&ac_net->ac_lock);
14308275SEric Cheng return (ENOTACTIVE);
14318275SEric Cheng }
14328275SEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ);
14338275SEric Cheng mutex_exit(&ac_net->ac_lock);
14348275SEric Cheng
14358275SEric Cheng return (exacct_assemble_net_usage(ac_net, arg, exacct_commit_callback,
14368275SEric Cheng NULL, 0, &size, what));
14378275SEric Cheng }
14388275SEric Cheng
14398275SEric Cheng static int
exacct_attach_flow_item(flow_usage_t * fu,ea_object_t * record,int res)14400Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res)
14410Sstevel@tonic-gate {
14420Sstevel@tonic-gate int attached = 1;
14430Sstevel@tonic-gate
14440Sstevel@tonic-gate switch (res) {
14450Sstevel@tonic-gate case AC_FLOW_SADDR:
14460Sstevel@tonic-gate if (fu->fu_isv4) {
14470Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr[3],
14480Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR);
14490Sstevel@tonic-gate } else {
14500Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr,
14510Sstevel@tonic-gate sizeof (fu->fu_saddr), EXT_RAW |
14520Sstevel@tonic-gate EXD_FLOW_V6SADDR);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate break;
14550Sstevel@tonic-gate case AC_FLOW_DADDR:
14560Sstevel@tonic-gate if (fu->fu_isv4) {
14570Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr[3],
14580Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR);
14590Sstevel@tonic-gate } else {
14600Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr,
14610Sstevel@tonic-gate sizeof (fu->fu_daddr), EXT_RAW |
14620Sstevel@tonic-gate EXD_FLOW_V6DADDR);
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate break;
14650Sstevel@tonic-gate case AC_FLOW_SPORT:
14660Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_sport,
14670Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT);
14680Sstevel@tonic-gate break;
14690Sstevel@tonic-gate case AC_FLOW_DPORT:
14700Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dport,
14710Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT);
14720Sstevel@tonic-gate break;
14730Sstevel@tonic-gate case AC_FLOW_PROTOCOL:
14740Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_protocol,
14750Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL);
14760Sstevel@tonic-gate break;
14770Sstevel@tonic-gate case AC_FLOW_DSFIELD:
14780Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dsfield,
14790Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD);
14800Sstevel@tonic-gate break;
14810Sstevel@tonic-gate case AC_FLOW_CTIME:
14820Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_ctime,
14830Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME);
14840Sstevel@tonic-gate break;
14850Sstevel@tonic-gate case AC_FLOW_LSEEN:
14860Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_lseen,
14870Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN);
14880Sstevel@tonic-gate break;
14890Sstevel@tonic-gate case AC_FLOW_NBYTES:
14900Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_nbytes,
14910Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES);
14920Sstevel@tonic-gate break;
14930Sstevel@tonic-gate case AC_FLOW_NPKTS:
14940Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_npackets,
14950Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS);
14960Sstevel@tonic-gate break;
14970Sstevel@tonic-gate case AC_FLOW_PROJID:
14980Sstevel@tonic-gate if (fu->fu_projid >= 0) {
14990Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_projid,
15000Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID);
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate break;
15030Sstevel@tonic-gate case AC_FLOW_UID:
15040Sstevel@tonic-gate if (fu->fu_userid >= 0) {
15050Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_userid,
15060Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID);
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate break;
15090Sstevel@tonic-gate case AC_FLOW_ANAME:
15100Sstevel@tonic-gate (void) ea_attach_item(record, fu->fu_aname,
15110Sstevel@tonic-gate strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME);
15120Sstevel@tonic-gate break;
15130Sstevel@tonic-gate default:
15140Sstevel@tonic-gate attached = 0;
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate return (attached);
15170Sstevel@tonic-gate }
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate static ea_object_t *
exacct_assemble_flow_record(flow_usage_t * fu,ulong_t * mask,ea_catalog_t record_type)15200Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask,
15210Sstevel@tonic-gate ea_catalog_t record_type)
15220Sstevel@tonic-gate {
15230Sstevel@tonic-gate int res, count;
15240Sstevel@tonic-gate ea_object_t *record;
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate /*
15270Sstevel@tonic-gate * Assemble usage values into group.
15280Sstevel@tonic-gate */
15290Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
15300Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++)
15310Sstevel@tonic-gate if (BT_TEST(mask, res))
15320Sstevel@tonic-gate count += exacct_attach_flow_item(fu, record, res);
15330Sstevel@tonic-gate if (count == 0) {
15340Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC);
15350Sstevel@tonic-gate record = NULL;
15360Sstevel@tonic-gate }
15370Sstevel@tonic-gate return (record);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate
15400Sstevel@tonic-gate int
exacct_assemble_flow_usage(ac_info_t * ac_flow,flow_usage_t * fu,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual)15410Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu,
15420Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
15430Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual)
15440Sstevel@tonic-gate {
15450Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
15460Sstevel@tonic-gate ea_object_t *flow_usage;
15470Sstevel@tonic-gate ea_catalog_t record_type;
15480Sstevel@tonic-gate void *buf;
15490Sstevel@tonic-gate size_t bufsize;
15500Sstevel@tonic-gate int ret;
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock);
15530Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) {
15540Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
15550Sstevel@tonic-gate return (ENOTACTIVE);
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
15580Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate record_type = EXD_GROUP_FLOW;
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate flow_usage = exacct_assemble_flow_record(fu, mask, record_type);
15630Sstevel@tonic-gate if (flow_usage == NULL) {
15640Sstevel@tonic-gate return (0);
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate
15670Sstevel@tonic-gate /*
15680Sstevel@tonic-gate * Pack object into buffer and pass to callback.
15690Sstevel@tonic-gate */
15700Sstevel@tonic-gate bufsize = ea_pack_object(flow_usage, NULL, 0);
15710Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_NOSLEEP);
15720Sstevel@tonic-gate if (buf == NULL) {
15730Sstevel@tonic-gate return (ENOMEM);
15740Sstevel@tonic-gate }
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate (void) ea_pack_object(flow_usage, buf, bufsize);
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual);
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate /*
15810Sstevel@tonic-gate * Free all previously allocations.
15820Sstevel@tonic-gate */
15830Sstevel@tonic-gate kmem_free(buf, bufsize);
15840Sstevel@tonic-gate ea_free_object(flow_usage, EUP_ALLOC);
15850Sstevel@tonic-gate return (ret);
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate
15880Sstevel@tonic-gate void
exacct_commit_flow(void * arg)15890Sstevel@tonic-gate exacct_commit_flow(void *arg)
15900Sstevel@tonic-gate {
15910Sstevel@tonic-gate flow_usage_t *f = (flow_usage_t *)arg;
15920Sstevel@tonic-gate size_t size;
15930Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
15940Sstevel@tonic-gate struct exacct_globals *acg;
15950Sstevel@tonic-gate ac_info_t *ac_flow;
15960Sstevel@tonic-gate
15970Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
15980Sstevel@tonic-gate /*
15990Sstevel@tonic-gate * acctctl module not loaded. Nothing to do.
16000Sstevel@tonic-gate */
16010Sstevel@tonic-gate return;
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate * Even though each zone nominally has its own flow accounting settings
16060Sstevel@tonic-gate * (ac_flow), these are only maintained by and for the global zone.
16070Sstevel@tonic-gate *
16080Sstevel@tonic-gate * If this were to change in the future, this function should grow a
16090Sstevel@tonic-gate * second zoneid (or zone) argument, and use the corresponding zone's
16100Sstevel@tonic-gate * settings rather than always using those of the global zone.
16110Sstevel@tonic-gate */
16120Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone);
16130Sstevel@tonic-gate ac_flow = &acg->ac_flow;
16140Sstevel@tonic-gate
16150Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock);
16160Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) {
16170Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
16180Sstevel@tonic-gate return;
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
16210Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
16220Sstevel@tonic-gate
16230Sstevel@tonic-gate (void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback,
16240Sstevel@tonic-gate NULL, 0, &size);
16250Sstevel@tonic-gate }
16260Sstevel@tonic-gate
16270Sstevel@tonic-gate /*
16280Sstevel@tonic-gate * int exacct_tag_task(task_t *, void *, size_t, int)
16290Sstevel@tonic-gate *
16300Sstevel@tonic-gate * Overview
16310Sstevel@tonic-gate * exacct_tag_task() provides the exacct record construction and writing
16320Sstevel@tonic-gate * support required by putacct(2) for task entities.
16330Sstevel@tonic-gate *
16340Sstevel@tonic-gate * Return values
16350Sstevel@tonic-gate * The result of the write operation is returned, unless the extended
16360Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned.
16370Sstevel@tonic-gate *
16380Sstevel@tonic-gate * Caller's context
16390Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
16400Sstevel@tonic-gate */
16410Sstevel@tonic-gate int
exacct_tag_task(ac_info_t * ac_task,task_t * tk,void * ubuf,size_t ubufsz,int flags)16420Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz,
16430Sstevel@tonic-gate int flags)
16440Sstevel@tonic-gate {
16450Sstevel@tonic-gate int error = 0;
16460Sstevel@tonic-gate void *buf;
16470Sstevel@tonic-gate size_t bufsize;
16480Sstevel@tonic-gate ea_catalog_t cat;
16490Sstevel@tonic-gate ea_object_t *tag;
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock);
16520Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) {
16530Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock);
16540Sstevel@tonic-gate return (ENOTACTIVE);
16550Sstevel@tonic-gate }
16560Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock);
16570Sstevel@tonic-gate
16580Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG);
16590Sstevel@tonic-gate (void) ea_attach_item(tag, &tk->tk_tkid, 0,
16600Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
16610Sstevel@tonic-gate (void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0,
16620Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
16630Sstevel@tonic-gate if (flags == EP_RAW)
16640Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG;
16650Sstevel@tonic-gate else
16660Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG;
16670Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat);
16680Sstevel@tonic-gate
16690Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0);
16700Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
16710Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize);
16720Sstevel@tonic-gate error = exacct_vn_write(ac_task, buf, bufsize);
16730Sstevel@tonic-gate kmem_free(buf, bufsize);
16740Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC);
16750Sstevel@tonic-gate return (error);
16760Sstevel@tonic-gate }
16770Sstevel@tonic-gate
16780Sstevel@tonic-gate /*
16790Sstevel@tonic-gate * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *)
16800Sstevel@tonic-gate *
16810Sstevel@tonic-gate * Overview
16820Sstevel@tonic-gate * exacct_tag_proc() provides the exacct record construction and writing
16830Sstevel@tonic-gate * support required by putacct(2) for processes.
16840Sstevel@tonic-gate *
16850Sstevel@tonic-gate * Return values
16860Sstevel@tonic-gate * The result of the write operation is returned, unless the extended
16870Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned.
16880Sstevel@tonic-gate *
16890Sstevel@tonic-gate * Caller's context
16900Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
16910Sstevel@tonic-gate */
16920Sstevel@tonic-gate int
exacct_tag_proc(ac_info_t * ac_proc,pid_t pid,taskid_t tkid,void * ubuf,size_t ubufsz,int flags,const char * hostname)16930Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf,
16940Sstevel@tonic-gate size_t ubufsz, int flags, const char *hostname)
16950Sstevel@tonic-gate {
16960Sstevel@tonic-gate int error = 0;
16970Sstevel@tonic-gate void *buf;
16980Sstevel@tonic-gate size_t bufsize;
16990Sstevel@tonic-gate ea_catalog_t cat;
17000Sstevel@tonic-gate ea_object_t *tag;
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock);
17030Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) {
17040Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
17050Sstevel@tonic-gate return (ENOTACTIVE);
17060Sstevel@tonic-gate }
17070Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG);
17100Sstevel@tonic-gate (void) ea_attach_item(tag, &pid, sizeof (uint32_t),
17110Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID);
17120Sstevel@tonic-gate (void) ea_attach_item(tag, &tkid, 0,
17130Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
17140Sstevel@tonic-gate (void) ea_attach_item(tag, (void *)hostname, 0,
17150Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
17160Sstevel@tonic-gate if (flags == EP_RAW)
17170Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG;
17180Sstevel@tonic-gate else
17190Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG;
17200Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat);
17210Sstevel@tonic-gate
17220Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0);
17230Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
17240Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize);
17250Sstevel@tonic-gate error = exacct_vn_write(ac_proc, buf, bufsize);
17260Sstevel@tonic-gate kmem_free(buf, bufsize);
17270Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC);
17280Sstevel@tonic-gate return (error);
17290Sstevel@tonic-gate }
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate /*
17320Sstevel@tonic-gate * void exacct_init(void)
17330Sstevel@tonic-gate *
17340Sstevel@tonic-gate * Overview
17350Sstevel@tonic-gate * Initialized the extended accounting subsystem.
17360Sstevel@tonic-gate *
17370Sstevel@tonic-gate * Return values
17380Sstevel@tonic-gate * None.
17390Sstevel@tonic-gate *
17400Sstevel@tonic-gate * Caller's context
17410Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
17420Sstevel@tonic-gate */
17430Sstevel@tonic-gate void
exacct_init()17440Sstevel@tonic-gate exacct_init()
17450Sstevel@tonic-gate {
17460Sstevel@tonic-gate exacct_queue = system_taskq;
17470Sstevel@tonic-gate exacct_object_cache = kmem_cache_create("exacct_object_cache",
17480Sstevel@tonic-gate sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
174912725SMenno.Lageman@Sun.COM task_commit_thread_init();
17500Sstevel@tonic-gate }
17514584Srh87107
17524584Srh87107 /*
17534584Srh87107 * exacct_snapshot_proc_mstate() copies a process's microstate accounting data
17544584Srh87107 * and resource usage counters into a given task_usage_t. It differs from
17554584Srh87107 * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t,
17564584Srh87107 * b) p_lock will have been acquired earlier in the call path and c) we
17574584Srh87107 * are here including the process's user and system times.
17584584Srh87107 */
17594584Srh87107 static void
exacct_snapshot_proc_mstate(proc_t * p,task_usage_t * tu)17604584Srh87107 exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu)
17614584Srh87107 {
17624584Srh87107 tu->tu_utime = mstate_aggr_state(p, LMS_USER);
17634584Srh87107 tu->tu_stime = mstate_aggr_state(p, LMS_SYSTEM);
17644584Srh87107 tu->tu_minflt = p->p_ru.minflt;
17654584Srh87107 tu->tu_majflt = p->p_ru.majflt;
17664584Srh87107 tu->tu_sndmsg = p->p_ru.msgsnd;
17674584Srh87107 tu->tu_rcvmsg = p->p_ru.msgrcv;
17684584Srh87107 tu->tu_ioch = p->p_ru.ioch;
17694584Srh87107 tu->tu_iblk = p->p_ru.inblock;
17704584Srh87107 tu->tu_oblk = p->p_ru.oublock;
17714584Srh87107 tu->tu_vcsw = p->p_ru.nvcsw;
17724584Srh87107 tu->tu_icsw = p->p_ru.nivcsw;
17734584Srh87107 tu->tu_nsig = p->p_ru.nsignals;
17744584Srh87107 tu->tu_nswp = p->p_ru.nswap;
17754584Srh87107 tu->tu_nscl = p->p_ru.sysc;
17764584Srh87107 }
17774584Srh87107
17784584Srh87107 /*
17794584Srh87107 * void exacct_move_mstate(proc_t *, task_t *, task_t *)
17804584Srh87107 *
17814584Srh87107 * Overview
17824584Srh87107 * exacct_move_mstate() is called by task_change() and accounts for
17834584Srh87107 * a process's resource usage when it is moved from one task to another.
17844584Srh87107 *
17854584Srh87107 * The process's usage at this point is recorded in the new task so
17864584Srh87107 * that it can be excluded from the calculation of resources consumed
17874584Srh87107 * by that task.
17884584Srh87107 *
17894584Srh87107 * The resource usage inherited by the new task is also added to the
17904584Srh87107 * aggregate maintained by the old task for processes that have exited.
17914584Srh87107 *
17924584Srh87107 * Return values
17934584Srh87107 * None.
17944584Srh87107 *
17954584Srh87107 * Caller's context
17964584Srh87107 * pidlock and p_lock held across exacct_move_mstate().
17974584Srh87107 */
17984584Srh87107 void
exacct_move_mstate(proc_t * p,task_t * oldtk,task_t * newtk)17994584Srh87107 exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk)
18004584Srh87107 {
18014584Srh87107 task_usage_t tu;
18024584Srh87107
18034584Srh87107 /* Take a snapshot of this process's mstate and RU counters */
18044584Srh87107 exacct_snapshot_proc_mstate(p, &tu);
18054584Srh87107
18064584Srh87107 /*
18074584Srh87107 * Use the snapshot to increment the aggregate usage of the old
18084584Srh87107 * task, and the inherited usage of the new one.
18094584Srh87107 */
18104584Srh87107 mutex_enter(&oldtk->tk_usage_lock);
18114584Srh87107 exacct_add_task_mstate(oldtk->tk_usage, &tu);
18124584Srh87107 mutex_exit(&oldtk->tk_usage_lock);
18134584Srh87107 mutex_enter(&newtk->tk_usage_lock);
18144584Srh87107 exacct_add_task_mstate(newtk->tk_inherited, &tu);
18154584Srh87107 mutex_exit(&newtk->tk_usage_lock);
18164584Srh87107 }
1817