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 /* 227103Sml93401 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/exacct.h> 270Sstevel@tonic-gate #include <sys/exacct_catalog.h> 280Sstevel@tonic-gate #include <sys/disp.h> 290Sstevel@tonic-gate #include <sys/task.h> 300Sstevel@tonic-gate #include <sys/proc.h> 310Sstevel@tonic-gate #include <sys/cmn_err.h> 320Sstevel@tonic-gate #include <sys/kmem.h> 330Sstevel@tonic-gate #include <sys/project.h> 340Sstevel@tonic-gate #include <sys/systm.h> 350Sstevel@tonic-gate #include <sys/vnode.h> 360Sstevel@tonic-gate #include <sys/file.h> 370Sstevel@tonic-gate #include <sys/acctctl.h> 380Sstevel@tonic-gate #include <sys/time.h> 390Sstevel@tonic-gate #include <sys/utsname.h> 400Sstevel@tonic-gate #include <sys/session.h> 410Sstevel@tonic-gate #include <sys/sysmacros.h> 420Sstevel@tonic-gate #include <sys/bitmap.h> 430Sstevel@tonic-gate #include <sys/msacct.h> 44*8275SEric Cheng #include <sys/mac.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * exacct usage and recording routines 480Sstevel@tonic-gate * 490Sstevel@tonic-gate * wracct(2), getacct(2), and the records written at process or task 500Sstevel@tonic-gate * termination are constructed using the exacct_assemble_[task,proc]_usage() 510Sstevel@tonic-gate * functions, which take a callback that takes the appropriate action on 520Sstevel@tonic-gate * the packed exacct record for the task or process. For the process-related 530Sstevel@tonic-gate * actions, we partition the routines such that the data collecting component 540Sstevel@tonic-gate * can be performed while holding p_lock, and all sleeping or blocking 550Sstevel@tonic-gate * operations can be performed without acquiring p_lock. 560Sstevel@tonic-gate * 570Sstevel@tonic-gate * putacct(2), which allows an application to construct a customized record 580Sstevel@tonic-gate * associated with an existing process or task, has its own entry points: 590Sstevel@tonic-gate * exacct_tag_task() and exacct_tag_proc(). 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate 620Sstevel@tonic-gate taskq_t *exacct_queue; 630Sstevel@tonic-gate kmem_cache_t *exacct_object_cache; 640Sstevel@tonic-gate 650Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED; 660Sstevel@tonic-gate 670Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION; 680Sstevel@tonic-gate static const char exacct_header[] = "exacct"; 690Sstevel@tonic-gate static const char exacct_creator[] = "SunOS"; 700Sstevel@tonic-gate 710Sstevel@tonic-gate ea_object_t * 720Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz) 730Sstevel@tonic-gate { 740Sstevel@tonic-gate ea_object_t *item; 750Sstevel@tonic-gate 760Sstevel@tonic-gate item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 770Sstevel@tonic-gate bzero(item, sizeof (ea_object_t)); 780Sstevel@tonic-gate (void) ea_set_item(item, catalog, buf, bufsz); 790Sstevel@tonic-gate return (item); 800Sstevel@tonic-gate } 810Sstevel@tonic-gate 820Sstevel@tonic-gate ea_object_t * 830Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog) 840Sstevel@tonic-gate { 850Sstevel@tonic-gate ea_object_t *group; 860Sstevel@tonic-gate 870Sstevel@tonic-gate group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 880Sstevel@tonic-gate bzero(group, sizeof (ea_object_t)); 890Sstevel@tonic-gate (void) ea_set_group(group, catalog); 900Sstevel@tonic-gate return (group); 910Sstevel@tonic-gate } 920Sstevel@tonic-gate 930Sstevel@tonic-gate ea_object_t * 940Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog) 950Sstevel@tonic-gate { 960Sstevel@tonic-gate ea_object_t *item; 970Sstevel@tonic-gate 980Sstevel@tonic-gate item = ea_alloc_item(catalog, buf, bufsz); 990Sstevel@tonic-gate (void) ea_attach_to_group(grp, item); 1000Sstevel@tonic-gate return (item); 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1044584Srh87107 * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract 1054584Srh87107 * microstate accounting data and resource usage counters from one task_usage_t 1064584Srh87107 * from those supplied in another. These functions do not operate on *all* 1074584Srh87107 * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make 1084584Srh87107 * sense. 1094584Srh87107 */ 1104584Srh87107 static void 1114584Srh87107 exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta) 1124584Srh87107 { 1134584Srh87107 tu->tu_utime += delta->tu_utime; 1144584Srh87107 tu->tu_stime += delta->tu_stime; 1154584Srh87107 tu->tu_minflt += delta->tu_minflt; 1164584Srh87107 tu->tu_majflt += delta->tu_majflt; 1174584Srh87107 tu->tu_sndmsg += delta->tu_sndmsg; 1184584Srh87107 tu->tu_rcvmsg += delta->tu_rcvmsg; 1194584Srh87107 tu->tu_ioch += delta->tu_ioch; 1204584Srh87107 tu->tu_iblk += delta->tu_iblk; 1214584Srh87107 tu->tu_oblk += delta->tu_oblk; 1224584Srh87107 tu->tu_vcsw += delta->tu_vcsw; 1234584Srh87107 tu->tu_icsw += delta->tu_icsw; 1244584Srh87107 tu->tu_nsig += delta->tu_nsig; 1254584Srh87107 tu->tu_nswp += delta->tu_nswp; 1264584Srh87107 tu->tu_nscl += delta->tu_nscl; 1274584Srh87107 } 1284584Srh87107 1294584Srh87107 /* 1304584Srh87107 * See the comments for exacct_add_task_mstate(), above. 1314584Srh87107 */ 1324584Srh87107 static void 1334584Srh87107 exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta) 1344584Srh87107 { 1354584Srh87107 tu->tu_utime -= delta->tu_utime; 1364584Srh87107 tu->tu_stime -= delta->tu_stime; 1374584Srh87107 tu->tu_minflt -= delta->tu_minflt; 1384584Srh87107 tu->tu_majflt -= delta->tu_majflt; 1394584Srh87107 tu->tu_sndmsg -= delta->tu_sndmsg; 1404584Srh87107 tu->tu_rcvmsg -= delta->tu_rcvmsg; 1414584Srh87107 tu->tu_ioch -= delta->tu_ioch; 1424584Srh87107 tu->tu_iblk -= delta->tu_iblk; 1434584Srh87107 tu->tu_oblk -= delta->tu_oblk; 1444584Srh87107 tu->tu_vcsw -= delta->tu_vcsw; 1454584Srh87107 tu->tu_icsw -= delta->tu_icsw; 1464584Srh87107 tu->tu_nsig -= delta->tu_nsig; 1474584Srh87107 tu->tu_nswp -= delta->tu_nswp; 1484584Srh87107 tu->tu_nscl -= delta->tu_nscl; 1494584Srh87107 } 1504584Srh87107 1514584Srh87107 /* 1527103Sml93401 * Wrapper for vn_rdwr() used by exacct_vn_write() and exacct_write_header() 1537103Sml93401 * to write to the accounting file without corrupting it in case of an I/O or 1547103Sml93401 * filesystem error. 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate static int 1577103Sml93401 exacct_vn_write_impl(ac_info_t *info, void *buf, ssize_t bufsize) 1580Sstevel@tonic-gate { 1597103Sml93401 int error; 1600Sstevel@tonic-gate ssize_t resid; 1610Sstevel@tonic-gate struct vattr va; 1620Sstevel@tonic-gate 1637103Sml93401 ASSERT(info != NULL); 1647103Sml93401 ASSERT(info->ac_vnode != NULL); 1657103Sml93401 ASSERT(MUTEX_HELD(&info->ac_lock)); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1680Sstevel@tonic-gate * Save the size. If vn_rdwr fails, reset the size to avoid corrupting 1690Sstevel@tonic-gate * the present accounting file. 1700Sstevel@tonic-gate */ 1710Sstevel@tonic-gate va.va_mask = AT_SIZE; 1725331Samw error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1730Sstevel@tonic-gate if (error == 0) { 1740Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf, 1750Sstevel@tonic-gate bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T, 1760Sstevel@tonic-gate kcred, &resid); 1770Sstevel@tonic-gate if (error) { 1780Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1790Sstevel@tonic-gate } else if (resid != 0) { 1800Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1810Sstevel@tonic-gate error = ENOSPC; 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate } 1847103Sml93401 return (error); 1857103Sml93401 } 1867103Sml93401 1877103Sml93401 /* 1887103Sml93401 * exacct_vn_write() safely writes to an accounting file. acctctl() prevents 1897103Sml93401 * the two accounting vnodes from being equal, and the appropriate ac_lock is 1907103Sml93401 * held across the call, so we're single threaded through this code for each 1917103Sml93401 * file. 1927103Sml93401 */ 1937103Sml93401 static int 1947103Sml93401 exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize) 1957103Sml93401 { 1967103Sml93401 int error; 1977103Sml93401 1987103Sml93401 if (info == NULL) 1997103Sml93401 return (0); 2007103Sml93401 2017103Sml93401 mutex_enter(&info->ac_lock); 2027103Sml93401 2037103Sml93401 /* 2047103Sml93401 * Don't do anything unless accounting file is set. 2057103Sml93401 */ 2067103Sml93401 if (info->ac_vnode == NULL) { 2077103Sml93401 mutex_exit(&info->ac_lock); 2087103Sml93401 return (0); 2097103Sml93401 } 2107103Sml93401 error = exacct_vn_write_impl(info, buf, bufsize); 2110Sstevel@tonic-gate mutex_exit(&info->ac_lock); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate return (error); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * void *exacct_create_header(size_t *) 2180Sstevel@tonic-gate * 2190Sstevel@tonic-gate * Overview 2200Sstevel@tonic-gate * exacct_create_header() constructs an exacct file header identifying the 2210Sstevel@tonic-gate * accounting file as the output of the kernel. exacct_create_header() and 2220Sstevel@tonic-gate * the static write_header() and verify_header() routines in libexacct must 2230Sstevel@tonic-gate * remain synchronized. 2240Sstevel@tonic-gate * 2250Sstevel@tonic-gate * Return values 2260Sstevel@tonic-gate * A pointer to a packed exacct buffer containing the appropriate header is 2270Sstevel@tonic-gate * returned; the size of the buffer is placed in the location indicated by 2280Sstevel@tonic-gate * sizep. 2290Sstevel@tonic-gate * 2300Sstevel@tonic-gate * Caller's context 2310Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 2320Sstevel@tonic-gate */ 2330Sstevel@tonic-gate void * 2340Sstevel@tonic-gate exacct_create_header(size_t *sizep) 2350Sstevel@tonic-gate { 2360Sstevel@tonic-gate ea_object_t *hdr_grp; 2370Sstevel@tonic-gate uint32_t bskip; 2380Sstevel@tonic-gate void *buf; 2390Sstevel@tonic-gate size_t bufsize; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER); 2420Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0, 2430Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_VERSION); 2440Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_header, 0, 2450Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_FILETYPE); 2460Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0, 2470Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_CREATOR); 2480Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, uts_nodename(), 0, 2490Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME); 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate bufsize = ea_pack_object(hdr_grp, NULL, 0); 2520Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 2530Sstevel@tonic-gate (void) ea_pack_object(hdr_grp, buf, bufsize); 2540Sstevel@tonic-gate ea_free_object(hdr_grp, EUP_ALLOC); 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate /* 2570Sstevel@tonic-gate * To prevent reading the header when reading the file backwards, 2580Sstevel@tonic-gate * set the large backskip of the header group to 0 (last 4 bytes). 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate bskip = 0; 2610Sstevel@tonic-gate exacct_order32(&bskip); 2620Sstevel@tonic-gate bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip), 2630Sstevel@tonic-gate sizeof (bskip)); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate *sizep = bufsize; 2660Sstevel@tonic-gate return (buf); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* 2700Sstevel@tonic-gate * int exacct_write_header(ac_info_t *, void *, size_t) 2710Sstevel@tonic-gate * 2720Sstevel@tonic-gate * Overview 2730Sstevel@tonic-gate * exacct_write_header() writes the given header buffer to the indicated 2747103Sml93401 * vnode. 2750Sstevel@tonic-gate * 2760Sstevel@tonic-gate * Return values 2770Sstevel@tonic-gate * The result of the write operation is returned. 2780Sstevel@tonic-gate * 2790Sstevel@tonic-gate * Caller's context 2807103Sml93401 * Caller must hold the ac_lock of the appropriate accounting file 2810Sstevel@tonic-gate * information block (ac_info_t). 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate int 2840Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize) 2850Sstevel@tonic-gate { 2867103Sml93401 if (info != NULL && info->ac_vnode != NULL) 2877103Sml93401 return (exacct_vn_write_impl(info, hdr, hdrsize)); 2880Sstevel@tonic-gate 2897103Sml93401 return (0); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate static void 2930Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu, 2940Sstevel@tonic-gate task_usage_t **tu_buf) 2950Sstevel@tonic-gate { 2960Sstevel@tonic-gate task_usage_t *oldtu, *newtu; 2970Sstevel@tonic-gate task_usage_t **prevusage; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tk->tk_usage_lock)); 3000Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) { 3010Sstevel@tonic-gate prevusage = &tk->tk_zoneusage; 3020Sstevel@tonic-gate } else { 3030Sstevel@tonic-gate prevusage = &tk->tk_prevusage; 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate if ((oldtu = *prevusage) != NULL) { 3060Sstevel@tonic-gate /* 3070Sstevel@tonic-gate * In case we have any accounting information 3080Sstevel@tonic-gate * saved from the previous interval record. 3090Sstevel@tonic-gate */ 3100Sstevel@tonic-gate newtu = *tu_buf; 3110Sstevel@tonic-gate bcopy(tu, newtu, sizeof (task_usage_t)); 3120Sstevel@tonic-gate tu->tu_minflt -= oldtu->tu_minflt; 3130Sstevel@tonic-gate tu->tu_majflt -= oldtu->tu_majflt; 3140Sstevel@tonic-gate tu->tu_sndmsg -= oldtu->tu_sndmsg; 3150Sstevel@tonic-gate tu->tu_rcvmsg -= oldtu->tu_rcvmsg; 3160Sstevel@tonic-gate tu->tu_ioch -= oldtu->tu_ioch; 3170Sstevel@tonic-gate tu->tu_iblk -= oldtu->tu_iblk; 3180Sstevel@tonic-gate tu->tu_oblk -= oldtu->tu_oblk; 3190Sstevel@tonic-gate tu->tu_vcsw -= oldtu->tu_vcsw; 3200Sstevel@tonic-gate tu->tu_icsw -= oldtu->tu_icsw; 3210Sstevel@tonic-gate tu->tu_nsig -= oldtu->tu_nsig; 3220Sstevel@tonic-gate tu->tu_nswp -= oldtu->tu_nswp; 3230Sstevel@tonic-gate tu->tu_nscl -= oldtu->tu_nscl; 3240Sstevel@tonic-gate tu->tu_utime -= oldtu->tu_utime; 3250Sstevel@tonic-gate tu->tu_stime -= oldtu->tu_stime; 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate tu->tu_startsec = oldtu->tu_finishsec; 3280Sstevel@tonic-gate tu->tu_startnsec = oldtu->tu_finishnsec; 3290Sstevel@tonic-gate /* 3300Sstevel@tonic-gate * Copy the data from our temporary storage to the task's 3310Sstevel@tonic-gate * previous interval usage structure for future reference. 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate bcopy(newtu, oldtu, sizeof (task_usage_t)); 3340Sstevel@tonic-gate } else { 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * Store current statistics in the task's previous interval 3370Sstevel@tonic-gate * usage structure for future references. 3380Sstevel@tonic-gate */ 3390Sstevel@tonic-gate *prevusage = *tu_buf; 3400Sstevel@tonic-gate bcopy(tu, *prevusage, sizeof (task_usage_t)); 3410Sstevel@tonic-gate *tu_buf = NULL; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate static void 3460Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu) 3470Sstevel@tonic-gate { 3480Sstevel@tonic-gate timestruc_t ts; 3490Sstevel@tonic-gate proc_t *p; 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate if ((p = tk->tk_memb_list) == NULL) 3540Sstevel@tonic-gate return; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate /* 3570Sstevel@tonic-gate * exacct_snapshot_task_usage() provides an approximate snapshot of the 3580Sstevel@tonic-gate * usage of the potentially many members of the task. Since we don't 3590Sstevel@tonic-gate * guarantee exactness, we don't acquire the p_lock of any of the member 3600Sstevel@tonic-gate * processes. 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate do { 3630Sstevel@tonic-gate mutex_enter(&p->p_lock); 3640Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 3650Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 3660Sstevel@tonic-gate mutex_exit(&p->p_lock); 3670Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 3680Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 3690Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 3700Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 3710Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 3720Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 3730Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 3740Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 3750Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 3760Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 3770Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 3780Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 3790Sstevel@tonic-gate } while ((p = p->p_tasknext) != tk->tk_memb_list); 3800Sstevel@tonic-gate 3814584Srh87107 /* 3824584Srh87107 * The resource usage accounted for so far will include that 3834584Srh87107 * contributed by the task's first process. If this process 3844584Srh87107 * came from another task, then its accumulated resource usage 3854584Srh87107 * will include a contribution from work performed there. 3864584Srh87107 * We must therefore subtract any resource usage that was 3874584Srh87107 * inherited with the first process. 3884584Srh87107 */ 3894584Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 3904584Srh87107 3910Sstevel@tonic-gate gethrestime(&ts); 3920Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 3930Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3974584Srh87107 * void exacct_update_task_mstate(proc_t *) 3984584Srh87107 * 3994584Srh87107 * Overview 4004584Srh87107 * exacct_update_task_mstate() updates the task usage; it is intended 4014584Srh87107 * to be called from proc_exit(). 4024584Srh87107 * 4034584Srh87107 * Return values 4044584Srh87107 * None. 4054584Srh87107 * 4064584Srh87107 * Caller's context 4074584Srh87107 * p_lock must be held at entry. 4080Sstevel@tonic-gate */ 4094584Srh87107 void 4100Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p) 4110Sstevel@tonic-gate { 4120Sstevel@tonic-gate task_usage_t *tu; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate mutex_enter(&p->p_task->tk_usage_lock); 4150Sstevel@tonic-gate tu = p->p_task->tk_usage; 4160Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 4170Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 4180Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 4190Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 4200Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 4210Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 4220Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 4230Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 4240Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 4250Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 4260Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 4270Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 4280Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 4290Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 4300Sstevel@tonic-gate mutex_exit(&p->p_task->tk_usage_lock); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate static void 4340Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag) 4350Sstevel@tonic-gate { 4360Sstevel@tonic-gate timestruc_t ts; 4370Sstevel@tonic-gate task_usage_t *tu_buf; 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate switch (flag) { 4400Sstevel@tonic-gate case EW_PARTIAL: 4410Sstevel@tonic-gate /* 4420Sstevel@tonic-gate * For partial records we must report the sum of current 4430Sstevel@tonic-gate * accounting statistics with previously accumulated 4440Sstevel@tonic-gate * statistics. 4450Sstevel@tonic-gate */ 4460Sstevel@tonic-gate mutex_enter(&pidlock); 4470Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4500Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4530Sstevel@tonic-gate mutex_exit(&pidlock); 4540Sstevel@tonic-gate break; 4550Sstevel@tonic-gate case EW_INTERVAL: 4560Sstevel@tonic-gate /* 4570Sstevel@tonic-gate * We need to allocate spare task_usage_t buffer before 4580Sstevel@tonic-gate * grabbing pidlock because we might need it later in 4590Sstevel@tonic-gate * exacct_get_interval_task_usage(). 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 4620Sstevel@tonic-gate mutex_enter(&pidlock); 4630Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* 4660Sstevel@tonic-gate * For interval records, we deduct the previous microstate 4670Sstevel@tonic-gate * accounting data and cpu usage times from previously saved 4680Sstevel@tonic-gate * results and update the previous task usage structure. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4710Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4720Sstevel@tonic-gate exacct_get_interval_task_usage(tk, tu, &tu_buf); 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4750Sstevel@tonic-gate mutex_exit(&pidlock); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate if (tu_buf != NULL) 4780Sstevel@tonic-gate kmem_free(tu_buf, sizeof (task_usage_t)); 4790Sstevel@tonic-gate break; 4800Sstevel@tonic-gate case EW_FINAL: 4810Sstevel@tonic-gate /* 4824584Srh87107 * For final records, we deduct, from the task's current 4834584Srh87107 * usage, any usage that was inherited with the arrival 4844584Srh87107 * of a process from a previous task. We then record 4854584Srh87107 * the task's finish time. 4860Sstevel@tonic-gate */ 4870Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4880Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4894584Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 4900Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate gethrestime(&ts); 4930Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 4940Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate break; 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate static int 5010Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record, 5020Sstevel@tonic-gate int res) 5030Sstevel@tonic-gate { 5040Sstevel@tonic-gate int attached = 1; 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate switch (res) { 5070Sstevel@tonic-gate case AC_TASK_TASKID: 5080Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_tkid, 5090Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID); 5100Sstevel@tonic-gate break; 5110Sstevel@tonic-gate case AC_TASK_PROJID: 5120Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_proj->kpj_id, 5130Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID); 5140Sstevel@tonic-gate break; 5150Sstevel@tonic-gate case AC_TASK_CPU: { 5160Sstevel@tonic-gate timestruc_t ts; 5170Sstevel@tonic-gate uint64_t ui; 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate hrt2ts(tu->tu_stime, &ts); 5200Sstevel@tonic-gate ui = ts.tv_sec; 5210Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5220Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_SEC); 5230Sstevel@tonic-gate ui = ts.tv_nsec; 5240Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5250Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate hrt2ts(tu->tu_utime, &ts); 5280Sstevel@tonic-gate ui = ts.tv_sec; 5290Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5300Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_SEC); 5310Sstevel@tonic-gate ui = ts.tv_nsec; 5320Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5330Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_NSEC); 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate break; 5360Sstevel@tonic-gate case AC_TASK_TIME: 5370Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startsec, 5380Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC); 5390Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startnsec, 5400Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC); 5410Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishsec, 5420Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC); 5430Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishnsec, 5440Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC); 5450Sstevel@tonic-gate break; 5460Sstevel@tonic-gate case AC_TASK_HOSTNAME: 5470Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_nodename, 5480Sstevel@tonic-gate strlen(tk->tk_zone->zone_nodename) + 1, 5490Sstevel@tonic-gate EXT_STRING | EXD_TASK_HOSTNAME); 5500Sstevel@tonic-gate break; 5510Sstevel@tonic-gate case AC_TASK_MICROSTATE: 5520Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_majflt, 5530Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR); 5540Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_minflt, 5550Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR); 5560Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_sndmsg, 5570Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND); 5580Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_rcvmsg, 5590Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV); 5600Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_iblk, 5610Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN); 5620Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_oblk, 5630Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT); 5640Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_ioch, 5650Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR); 5660Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_vcsw, 5670Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL); 5680Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_icsw, 5690Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV); 5700Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nsig, 5710Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS); 5720Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nswp, 5730Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS); 5740Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nscl, 5750Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS); 5760Sstevel@tonic-gate break; 5770Sstevel@tonic-gate case AC_TASK_ANCTASKID: 5780Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_anctaskid, 5790Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID); 5800Sstevel@tonic-gate break; 5810Sstevel@tonic-gate case AC_TASK_ZONENAME: 5820Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_name, 5830Sstevel@tonic-gate strlen(tk->tk_zone->zone_name) + 1, 5840Sstevel@tonic-gate EXT_STRING | EXD_TASK_ZONENAME); 5850Sstevel@tonic-gate break; 5860Sstevel@tonic-gate default: 5870Sstevel@tonic-gate attached = 0; 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate return (attached); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate static ea_object_t * 5930Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask, 5940Sstevel@tonic-gate ea_catalog_t record_type) 5950Sstevel@tonic-gate { 5960Sstevel@tonic-gate int res, count; 5970Sstevel@tonic-gate ea_object_t *record; 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * Assemble usage values into group. 6010Sstevel@tonic-gate */ 6020Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 6030Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++) 6040Sstevel@tonic-gate if (BT_TEST(mask, res)) 6050Sstevel@tonic-gate count += exacct_attach_task_item(tk, tu, record, res); 6060Sstevel@tonic-gate if (count == 0) { 6070Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 6080Sstevel@tonic-gate record = NULL; 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate return (record); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate /* 6140Sstevel@tonic-gate * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *, 6150Sstevel@tonic-gate * size_t, size_t *), void *, size_t, size_t *, int) 6160Sstevel@tonic-gate * 6170Sstevel@tonic-gate * Overview 6180Sstevel@tonic-gate * exacct_assemble_task_usage() builds the packed exacct buffer for the 6190Sstevel@tonic-gate * indicated task, executes the given callback function, and free the packed 6200Sstevel@tonic-gate * buffer. 6210Sstevel@tonic-gate * 6220Sstevel@tonic-gate * Return values 6230Sstevel@tonic-gate * Returns 0 on success; otherwise the appropriate error code is returned. 6240Sstevel@tonic-gate * 6250Sstevel@tonic-gate * Caller's context 6260Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 6270Sstevel@tonic-gate */ 6280Sstevel@tonic-gate int 6290Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk, 6300Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 6310Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 6320Sstevel@tonic-gate { 6330Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 6340Sstevel@tonic-gate ea_object_t *task_record; 6350Sstevel@tonic-gate ea_catalog_t record_type; 6360Sstevel@tonic-gate task_usage_t *tu; 6370Sstevel@tonic-gate void *buf; 6380Sstevel@tonic-gate size_t bufsize; 6390Sstevel@tonic-gate int ret; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 6440Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF) { 6450Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6460Sstevel@tonic-gate return (ENOTACTIVE); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ); 6490Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate switch (flag) { 6520Sstevel@tonic-gate case EW_FINAL: 6530Sstevel@tonic-gate record_type = EXD_GROUP_TASK; 6540Sstevel@tonic-gate break; 6550Sstevel@tonic-gate case EW_PARTIAL: 6560Sstevel@tonic-gate record_type = EXD_GROUP_TASK_PARTIAL; 6570Sstevel@tonic-gate break; 6580Sstevel@tonic-gate case EW_INTERVAL: 6590Sstevel@tonic-gate record_type = EXD_GROUP_TASK_INTERVAL; 6600Sstevel@tonic-gate break; 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate /* 6640Sstevel@tonic-gate * Calculate task usage and assemble it into the task record. 6650Sstevel@tonic-gate */ 6660Sstevel@tonic-gate tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 6670Sstevel@tonic-gate exacct_calculate_task_usage(tk, tu, flag); 6680Sstevel@tonic-gate task_record = exacct_assemble_task_record(tk, tu, mask, record_type); 6690Sstevel@tonic-gate if (task_record == NULL) { 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * The current configuration of the accounting system has 6720Sstevel@tonic-gate * resulted in records with no data; accordingly, we don't write 6730Sstevel@tonic-gate * these, but we return success. 6740Sstevel@tonic-gate */ 6750Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6760Sstevel@tonic-gate return (0); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate /* 6800Sstevel@tonic-gate * Pack object into buffer and run callback on it. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate bufsize = ea_pack_object(task_record, NULL, 0); 6830Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 6840Sstevel@tonic-gate (void) ea_pack_object(task_record, buf, bufsize); 6850Sstevel@tonic-gate ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* 6880Sstevel@tonic-gate * Free all previously allocated structures. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate kmem_free(buf, bufsize); 6910Sstevel@tonic-gate ea_free_object(task_record, EUP_ALLOC); 6920Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6930Sstevel@tonic-gate return (ret); 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate /* 6970Sstevel@tonic-gate * void exacct_commit_task(void *) 6980Sstevel@tonic-gate * 6990Sstevel@tonic-gate * Overview 7000Sstevel@tonic-gate * exacct_commit_task() calculates the final usage for a task, updating the 7010Sstevel@tonic-gate * task usage if task accounting is active, and writing a task record if task 7020Sstevel@tonic-gate * accounting is active. exacct_commit_task() is intended for being called 7030Sstevel@tonic-gate * from a task queue (taskq_t). 7040Sstevel@tonic-gate * 7050Sstevel@tonic-gate * Return values 7060Sstevel@tonic-gate * None. 7070Sstevel@tonic-gate * 7080Sstevel@tonic-gate * Caller's context 7090Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 7100Sstevel@tonic-gate */ 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate void 7130Sstevel@tonic-gate exacct_commit_task(void *arg) 7140Sstevel@tonic-gate { 7150Sstevel@tonic-gate task_t *tk = (task_t *)arg; 7160Sstevel@tonic-gate size_t size; 7170Sstevel@tonic-gate zone_t *zone = tk->tk_zone; 7180Sstevel@tonic-gate struct exacct_globals *acg; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate ASSERT(tk != task0p); 7210Sstevel@tonic-gate ASSERT(tk->tk_memb_list == NULL); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate /* 7240Sstevel@tonic-gate * Don't do any extra work if the acctctl module isn't loaded. 7250Sstevel@tonic-gate */ 7260Sstevel@tonic-gate if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) { 7270Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 7280Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7290Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7300Sstevel@tonic-gate if (tk->tk_zone != global_zone) { 7310Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 7320Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7330Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate /* 7370Sstevel@tonic-gate * Release associated project and finalize task. 7380Sstevel@tonic-gate */ 7390Sstevel@tonic-gate task_end(tk); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate static int 7430Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res) 7440Sstevel@tonic-gate { 7450Sstevel@tonic-gate int attached = 1; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate switch (res) { 7480Sstevel@tonic-gate case AC_PROC_PID: 7490Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_pid, 7500Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID); 7510Sstevel@tonic-gate break; 7520Sstevel@tonic-gate case AC_PROC_UID: 7530Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ruid, 7540Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID); 7550Sstevel@tonic-gate break; 7560Sstevel@tonic-gate case AC_PROC_FLAG: 7570Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_acflag, 7580Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS); 7590Sstevel@tonic-gate break; 7600Sstevel@tonic-gate case AC_PROC_GID: 7610Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rgid, 7620Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID); 7630Sstevel@tonic-gate break; 7640Sstevel@tonic-gate case AC_PROC_PROJID: 7650Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_projid, 7660Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID); 7670Sstevel@tonic-gate break; 7680Sstevel@tonic-gate case AC_PROC_TASKID: 7690Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_taskid, 7700Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID); 7710Sstevel@tonic-gate break; 7720Sstevel@tonic-gate case AC_PROC_CPU: 7730Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimesec, 7740Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC); 7750Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimensec, 7760Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC); 7770Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimesec, 7780Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC); 7790Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimensec, 7800Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC); 7810Sstevel@tonic-gate break; 7820Sstevel@tonic-gate case AC_PROC_TIME: 7830Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startsec, 7840Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC); 7850Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startnsec, 7860Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC); 7870Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishsec, 7880Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC); 7890Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishnsec, 7900Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC); 7910Sstevel@tonic-gate break; 7920Sstevel@tonic-gate case AC_PROC_COMMAND: 7930Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_command, 7940Sstevel@tonic-gate strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND); 7950Sstevel@tonic-gate break; 7960Sstevel@tonic-gate case AC_PROC_HOSTNAME: 7970Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_nodename, 7980Sstevel@tonic-gate strlen(pu->pu_nodename) + 1, 7990Sstevel@tonic-gate EXT_STRING | EXD_PROC_HOSTNAME); 8000Sstevel@tonic-gate break; 8010Sstevel@tonic-gate case AC_PROC_TTY: 8020Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_major, 8030Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR); 8040Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minor, 8050Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR); 8060Sstevel@tonic-gate break; 8070Sstevel@tonic-gate case AC_PROC_MICROSTATE: 8080Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_majflt, 8090Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR); 8100Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minflt, 8110Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR); 8120Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_sndmsg, 8130Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND); 8140Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rcvmsg, 8150Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV); 8160Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_iblk, 8170Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN); 8180Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_oblk, 8190Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT); 8200Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ioch, 8210Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR); 8220Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_vcsw, 8230Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL); 8240Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_icsw, 8250Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV); 8260Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nsig, 8270Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS); 8280Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nswp, 8290Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS); 8300Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nscl, 8310Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS); 8320Sstevel@tonic-gate break; 8330Sstevel@tonic-gate case AC_PROC_ANCPID: 8340Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ancpid, 8350Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID); 8360Sstevel@tonic-gate break; 8370Sstevel@tonic-gate case AC_PROC_WAIT_STATUS: 8380Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_wstat, 8390Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS); 8400Sstevel@tonic-gate break; 8410Sstevel@tonic-gate case AC_PROC_ZONENAME: 8420Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_zonename, 8430Sstevel@tonic-gate strlen(pu->pu_zonename) + 1, 8440Sstevel@tonic-gate EXT_STRING | EXD_PROC_ZONENAME); 8450Sstevel@tonic-gate break; 8460Sstevel@tonic-gate case AC_PROC_MEM: 8470Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_avg, 8480Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K); 8490Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_max, 8500Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K); 8510Sstevel@tonic-gate break; 8520Sstevel@tonic-gate default: 8530Sstevel@tonic-gate attached = 0; 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate return (attached); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate static ea_object_t * 8590Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask, 8600Sstevel@tonic-gate ea_catalog_t record_type) 8610Sstevel@tonic-gate { 8620Sstevel@tonic-gate int res, count; 8630Sstevel@tonic-gate ea_object_t *record; 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate /* 8660Sstevel@tonic-gate * Assemble usage values into group. 8670Sstevel@tonic-gate */ 8680Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 8690Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++) 8700Sstevel@tonic-gate if (BT_TEST(mask, res)) 8714584Srh87107 count += exacct_attach_proc_item(pu, record, res); 8720Sstevel@tonic-gate if (count == 0) { 8730Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 8740Sstevel@tonic-gate record = NULL; 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate return (record); 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate /* 8800Sstevel@tonic-gate * The following two routines assume that process's p_lock is held or 8810Sstevel@tonic-gate * exacct_commit_proc has been called from exit() when all lwps are stopped. 8820Sstevel@tonic-gate */ 8830Sstevel@tonic-gate static void 8840Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu) 8850Sstevel@tonic-gate { 8860Sstevel@tonic-gate kthread_t *t; 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 8890Sstevel@tonic-gate if ((t = p->p_tlist) == NULL) 8900Sstevel@tonic-gate return; 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate do { 8930Sstevel@tonic-gate pu->pu_minflt += t->t_lwp->lwp_ru.minflt; 8940Sstevel@tonic-gate pu->pu_majflt += t->t_lwp->lwp_ru.majflt; 8950Sstevel@tonic-gate pu->pu_sndmsg += t->t_lwp->lwp_ru.msgsnd; 8960Sstevel@tonic-gate pu->pu_rcvmsg += t->t_lwp->lwp_ru.msgrcv; 8970Sstevel@tonic-gate pu->pu_ioch += t->t_lwp->lwp_ru.ioch; 8980Sstevel@tonic-gate pu->pu_iblk += t->t_lwp->lwp_ru.inblock; 8990Sstevel@tonic-gate pu->pu_oblk += t->t_lwp->lwp_ru.oublock; 9000Sstevel@tonic-gate pu->pu_vcsw += t->t_lwp->lwp_ru.nvcsw; 9010Sstevel@tonic-gate pu->pu_icsw += t->t_lwp->lwp_ru.nivcsw; 9020Sstevel@tonic-gate pu->pu_nsig += t->t_lwp->lwp_ru.nsignals; 9030Sstevel@tonic-gate pu->pu_nswp += t->t_lwp->lwp_ru.nswap; 9040Sstevel@tonic-gate pu->pu_nscl += t->t_lwp->lwp_ru.sysc; 9050Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate static void 9090Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu) 9100Sstevel@tonic-gate { 9110Sstevel@tonic-gate pu->pu_minflt = p->p_ru.minflt; 9120Sstevel@tonic-gate pu->pu_majflt = p->p_ru.majflt; 9130Sstevel@tonic-gate pu->pu_sndmsg = p->p_ru.msgsnd; 9140Sstevel@tonic-gate pu->pu_rcvmsg = p->p_ru.msgrcv; 9150Sstevel@tonic-gate pu->pu_ioch = p->p_ru.ioch; 9160Sstevel@tonic-gate pu->pu_iblk = p->p_ru.inblock; 9170Sstevel@tonic-gate pu->pu_oblk = p->p_ru.oublock; 9180Sstevel@tonic-gate pu->pu_vcsw = p->p_ru.nvcsw; 9190Sstevel@tonic-gate pu->pu_icsw = p->p_ru.nivcsw; 9200Sstevel@tonic-gate pu->pu_nsig = p->p_ru.nsignals; 9210Sstevel@tonic-gate pu->pu_nswp = p->p_ru.nswap; 9220Sstevel@tonic-gate pu->pu_nscl = p->p_ru.sysc; 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate void 9260Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask, 9270Sstevel@tonic-gate int flag, int wstat) 9280Sstevel@tonic-gate { 9290Sstevel@tonic-gate timestruc_t ts, ts_run; 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate /* 9340Sstevel@tonic-gate * Convert CPU and execution times to sec/nsec format. 9350Sstevel@tonic-gate */ 9360Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_CPU)) { 9370Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_USER), &ts); 9380Sstevel@tonic-gate pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec; 9390Sstevel@tonic-gate pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9400Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts); 9410Sstevel@tonic-gate pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec; 9420Sstevel@tonic-gate pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_TIME)) { 9450Sstevel@tonic-gate gethrestime(&ts); 9460Sstevel@tonic-gate pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 9470Sstevel@tonic-gate pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9480Sstevel@tonic-gate hrt2ts(gethrtime() - p->p_mstart, &ts_run); 9490Sstevel@tonic-gate ts.tv_sec -= ts_run.tv_sec; 9500Sstevel@tonic-gate ts.tv_nsec -= ts_run.tv_nsec; 9510Sstevel@tonic-gate if (ts.tv_nsec < 0) { 9520Sstevel@tonic-gate ts.tv_sec--; 9530Sstevel@tonic-gate if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) { 9540Sstevel@tonic-gate ts.tv_sec++; 9550Sstevel@tonic-gate ts.tv_nsec -= NANOSEC; 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec; 9590Sstevel@tonic-gate pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate pu->pu_pid = p->p_pidp->pid_id; 9630Sstevel@tonic-gate pu->pu_acflag = p->p_user.u_acflag; 9640Sstevel@tonic-gate pu->pu_projid = p->p_task->tk_proj->kpj_id; 9650Sstevel@tonic-gate pu->pu_taskid = p->p_task->tk_tkid; 9660Sstevel@tonic-gate pu->pu_major = getmajor(p->p_sessp->s_dev); 9670Sstevel@tonic-gate pu->pu_minor = getminor(p->p_sessp->s_dev); 9680Sstevel@tonic-gate pu->pu_ancpid = p->p_ancpid; 9690Sstevel@tonic-gate pu->pu_wstat = wstat; 9700Sstevel@tonic-gate /* 9710Sstevel@tonic-gate * Compute average RSS in K. The denominator is the number of 9720Sstevel@tonic-gate * samples: the number of clock ticks plus the initial value. 9730Sstevel@tonic-gate */ 9740Sstevel@tonic-gate pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) * 9750Sstevel@tonic-gate (PAGESIZE / 1024); 9760Sstevel@tonic-gate pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate mutex_enter(&p->p_crlock); 9790Sstevel@tonic-gate pu->pu_ruid = crgetruid(p->p_cred); 9800Sstevel@tonic-gate pu->pu_rgid = crgetrgid(p->p_cred); 9810Sstevel@tonic-gate mutex_exit(&p->p_crlock); 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1); 9840Sstevel@tonic-gate bcopy(p->p_zone->zone_name, pu->pu_zonename, 9850Sstevel@tonic-gate strlen(p->p_zone->zone_name) + 1); 9860Sstevel@tonic-gate bcopy(p->p_zone->zone_nodename, pu->pu_nodename, 9870Sstevel@tonic-gate strlen(p->p_zone->zone_nodename) + 1); 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate /* 9900Sstevel@tonic-gate * Calculate microstate accounting data for a process that is still 9910Sstevel@tonic-gate * running. Presently, we explicitly collect all of the LWP usage into 9920Sstevel@tonic-gate * the proc usage structure here. 9930Sstevel@tonic-gate */ 9940Sstevel@tonic-gate if (flag & EW_PARTIAL) 9950Sstevel@tonic-gate exacct_calculate_proc_mstate(p, pu); 9960Sstevel@tonic-gate if (flag & EW_FINAL) 9970Sstevel@tonic-gate exacct_copy_proc_mstate(p, pu); 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate /* 10010Sstevel@tonic-gate * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void 10020Sstevel@tonic-gate * *, size_t, size_t *), void *, size_t, size_t *) 10030Sstevel@tonic-gate * 10040Sstevel@tonic-gate * Overview 10050Sstevel@tonic-gate * Assemble record with miscellaneous accounting information about the process 10060Sstevel@tonic-gate * and execute the callback on it. It is the callback's job to set "actual" to 10070Sstevel@tonic-gate * the size of record. 10080Sstevel@tonic-gate * 10090Sstevel@tonic-gate * Return values 10100Sstevel@tonic-gate * The result of the callback function, unless the extended process accounting 10110Sstevel@tonic-gate * feature is not active, in which case ENOTACTIVE is returned. 10120Sstevel@tonic-gate * 10130Sstevel@tonic-gate * Caller's context 10140Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 10150Sstevel@tonic-gate */ 10160Sstevel@tonic-gate int 10170Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu, 10180Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 10190Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 10200Sstevel@tonic-gate { 10210Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 10220Sstevel@tonic-gate ea_object_t *proc_record; 10230Sstevel@tonic-gate ea_catalog_t record_type; 10240Sstevel@tonic-gate void *buf; 10250Sstevel@tonic-gate size_t bufsize; 10260Sstevel@tonic-gate int ret; 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 10310Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF) { 10320Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10330Sstevel@tonic-gate return (ENOTACTIVE); 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 10360Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate switch (flag) { 10390Sstevel@tonic-gate case EW_FINAL: 10400Sstevel@tonic-gate record_type = EXD_GROUP_PROC; 10410Sstevel@tonic-gate break; 10420Sstevel@tonic-gate case EW_PARTIAL: 10430Sstevel@tonic-gate record_type = EXD_GROUP_PROC_PARTIAL; 10440Sstevel@tonic-gate break; 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate proc_record = exacct_assemble_proc_record(pu, mask, record_type); 10480Sstevel@tonic-gate if (proc_record == NULL) 10490Sstevel@tonic-gate return (0); 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate /* 10520Sstevel@tonic-gate * Pack object into buffer and pass to callback. 10530Sstevel@tonic-gate */ 10540Sstevel@tonic-gate bufsize = ea_pack_object(proc_record, NULL, 0); 10550Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 10560Sstevel@tonic-gate (void) ea_pack_object(proc_record, buf, bufsize); 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual); 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate /* 10610Sstevel@tonic-gate * Free all previously allocations. 10620Sstevel@tonic-gate */ 10630Sstevel@tonic-gate kmem_free(buf, bufsize); 10640Sstevel@tonic-gate ea_free_object(proc_record, EUP_ALLOC); 10650Sstevel@tonic-gate return (ret); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate /* 10690Sstevel@tonic-gate * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t, 10700Sstevel@tonic-gate * size_t *) 10710Sstevel@tonic-gate * 10720Sstevel@tonic-gate * Overview 10730Sstevel@tonic-gate * exacct_commit_callback() writes the indicated buffer to the indicated 10740Sstevel@tonic-gate * extended accounting file. 10750Sstevel@tonic-gate * 10760Sstevel@tonic-gate * Return values 10770Sstevel@tonic-gate * The result of the write operation is returned. "actual" is updated to 10780Sstevel@tonic-gate * contain the number of bytes actually written. 10790Sstevel@tonic-gate * 10800Sstevel@tonic-gate * Caller's context 10810Sstevel@tonic-gate * Suitable for a vn_rdwr() operation. 10820Sstevel@tonic-gate */ 10830Sstevel@tonic-gate /*ARGSUSED*/ 10840Sstevel@tonic-gate int 10850Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize, 10860Sstevel@tonic-gate void *buf, size_t bufsize, size_t *actual) 10870Sstevel@tonic-gate { 10880Sstevel@tonic-gate int error = 0; 10890Sstevel@tonic-gate 10900Sstevel@tonic-gate *actual = 0; 10910Sstevel@tonic-gate if ((error = exacct_vn_write(info, buf, bufsize)) == 0) 10920Sstevel@tonic-gate *actual = bufsize; 10930Sstevel@tonic-gate return (error); 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate static void 10970Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat) 10980Sstevel@tonic-gate { 10990Sstevel@tonic-gate size_t size; 11000Sstevel@tonic-gate proc_usage_t *pu; 11010Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 11040Sstevel@tonic-gate if (ac_proc->ac_state == AC_ON) { 11050Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 11060Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 11070Sstevel@tonic-gate } else { 11080Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 11090Sstevel@tonic-gate return; 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate mutex_enter(&p->p_lock); 11130Sstevel@tonic-gate size = strlen(p->p_user.u_comm) + 1; 11140Sstevel@tonic-gate mutex_exit(&p->p_lock); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP); 11170Sstevel@tonic-gate pu->pu_command = kmem_alloc(size, KM_SLEEP); 11180Sstevel@tonic-gate mutex_enter(&p->p_lock); 11190Sstevel@tonic-gate exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat); 11200Sstevel@tonic-gate mutex_exit(&p->p_lock); 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate (void) exacct_assemble_proc_usage(ac_proc, pu, 11230Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate kmem_free(pu->pu_command, strlen(pu->pu_command) + 1); 11260Sstevel@tonic-gate kmem_free(pu, sizeof (proc_usage_t)); 11270Sstevel@tonic-gate } 11284584Srh87107 11290Sstevel@tonic-gate /* 11300Sstevel@tonic-gate * void exacct_commit_proc(proc_t *, int) 11310Sstevel@tonic-gate * 11320Sstevel@tonic-gate * Overview 11330Sstevel@tonic-gate * exacct_commit_proc() calculates the final usage for a process, updating the 11340Sstevel@tonic-gate * task usage if task accounting is active, and writing a process record if 11350Sstevel@tonic-gate * process accounting is active. exacct_commit_proc() is intended for being 11360Sstevel@tonic-gate * called from proc_exit(). 11370Sstevel@tonic-gate * 11380Sstevel@tonic-gate * Return values 11390Sstevel@tonic-gate * None. 11400Sstevel@tonic-gate * 11410Sstevel@tonic-gate * Caller's context 11420Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. p_lock must not be held at entry. 11430Sstevel@tonic-gate */ 11440Sstevel@tonic-gate void 11450Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat) 11460Sstevel@tonic-gate { 11470Sstevel@tonic-gate zone_t *zone = p->p_zone; 11480Sstevel@tonic-gate struct exacct_globals *acg, *gacg = NULL; 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 11510Sstevel@tonic-gate /* 11520Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 11530Sstevel@tonic-gate */ 11540Sstevel@tonic-gate return; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 11574584Srh87107 exacct_do_commit_proc(&acg->ac_proc, p, wstat); 11584584Srh87107 if (zone != global_zone) { 11590Sstevel@tonic-gate gacg = zone_getspecific(exacct_zone_key, global_zone); 11604584Srh87107 exacct_do_commit_proc(&gacg->ac_proc, p, wstat); 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate static int 1165*8275SEric Cheng exacct_attach_netstat_item(net_stat_t *ns, ea_object_t *record, int res) 1166*8275SEric Cheng { 1167*8275SEric Cheng int attached = 1; 1168*8275SEric Cheng 1169*8275SEric Cheng switch (res) { 1170*8275SEric Cheng case AC_NET_NAME: 1171*8275SEric Cheng (void) ea_attach_item(record, ns->ns_name, 1172*8275SEric Cheng strlen(ns->ns_name) + 1, EXT_STRING | EXD_NET_STATS_NAME); 1173*8275SEric Cheng break; 1174*8275SEric Cheng case AC_NET_CURTIME: 1175*8275SEric Cheng { 1176*8275SEric Cheng uint64_t now; 1177*8275SEric Cheng timestruc_t ts; 1178*8275SEric Cheng 1179*8275SEric Cheng gethrestime(&ts); 1180*8275SEric Cheng now = (uint64_t)(ulong_t)ts.tv_sec; 1181*8275SEric Cheng (void) ea_attach_item(record, &now, sizeof (uint64_t), 1182*8275SEric Cheng EXT_UINT64 | EXD_NET_STATS_CURTIME); 1183*8275SEric Cheng } 1184*8275SEric Cheng break; 1185*8275SEric Cheng case AC_NET_IBYTES: 1186*8275SEric Cheng (void) ea_attach_item(record, &ns->ns_ibytes, 1187*8275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IBYTES); 1188*8275SEric Cheng break; 1189*8275SEric Cheng case AC_NET_OBYTES: 1190*8275SEric Cheng (void) ea_attach_item(record, &ns->ns_obytes, 1191*8275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OBYTES); 1192*8275SEric Cheng break; 1193*8275SEric Cheng case AC_NET_IPKTS: 1194*8275SEric Cheng (void) ea_attach_item(record, &ns->ns_ipackets, 1195*8275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IPKTS); 1196*8275SEric Cheng break; 1197*8275SEric Cheng case AC_NET_OPKTS: 1198*8275SEric Cheng (void) ea_attach_item(record, &ns->ns_opackets, 1199*8275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OPKTS); 1200*8275SEric Cheng break; 1201*8275SEric Cheng case AC_NET_IERRPKTS: 1202*8275SEric Cheng (void) ea_attach_item(record, &ns->ns_ierrors, 1203*8275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IERRPKTS); 1204*8275SEric Cheng break; 1205*8275SEric Cheng case AC_NET_OERRPKTS: 1206*8275SEric Cheng (void) ea_attach_item(record, &ns->ns_oerrors, 1207*8275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OERRPKTS); 1208*8275SEric Cheng break; 1209*8275SEric Cheng default: 1210*8275SEric Cheng attached = 0; 1211*8275SEric Cheng } 1212*8275SEric Cheng return (attached); 1213*8275SEric Cheng } 1214*8275SEric Cheng 1215*8275SEric Cheng static int 1216*8275SEric Cheng exacct_attach_netdesc_item(net_desc_t *nd, ea_object_t *record, int res) 1217*8275SEric Cheng { 1218*8275SEric Cheng int attached = 1; 1219*8275SEric Cheng 1220*8275SEric Cheng switch (res) { 1221*8275SEric Cheng case AC_NET_NAME: 1222*8275SEric Cheng (void) ea_attach_item(record, nd->nd_name, 1223*8275SEric Cheng strlen(nd->nd_name) + 1, EXT_STRING | EXD_NET_DESC_NAME); 1224*8275SEric Cheng break; 1225*8275SEric Cheng case AC_NET_DEVNAME: 1226*8275SEric Cheng (void) ea_attach_item(record, nd->nd_devname, 1227*8275SEric Cheng strlen(nd->nd_devname) + 1, EXT_STRING | 1228*8275SEric Cheng EXD_NET_DESC_DEVNAME); 1229*8275SEric Cheng break; 1230*8275SEric Cheng case AC_NET_EHOST: 1231*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_ehost, 1232*8275SEric Cheng sizeof (nd->nd_ehost), EXT_RAW | EXD_NET_DESC_EHOST); 1233*8275SEric Cheng break; 1234*8275SEric Cheng case AC_NET_EDEST: 1235*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_edest, 1236*8275SEric Cheng sizeof (nd->nd_edest), EXT_RAW | EXD_NET_DESC_EDEST); 1237*8275SEric Cheng break; 1238*8275SEric Cheng case AC_NET_VLAN_TPID: 1239*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tpid, 1240*8275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TPID); 1241*8275SEric Cheng break; 1242*8275SEric Cheng case AC_NET_VLAN_TCI: 1243*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tci, 1244*8275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TCI); 1245*8275SEric Cheng break; 1246*8275SEric Cheng case AC_NET_SAP: 1247*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_sap, 1248*8275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_SAP); 1249*8275SEric Cheng break; 1250*8275SEric Cheng case AC_NET_PRIORITY: 1251*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_priority, 1252*8275SEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_PRIORITY); 1253*8275SEric Cheng break; 1254*8275SEric Cheng case AC_NET_BWLIMIT: 1255*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_bw_limit, 1256*8275SEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_DESC_BWLIMIT); 1257*8275SEric Cheng break; 1258*8275SEric Cheng case AC_NET_SADDR: 1259*8275SEric Cheng if (nd->nd_isv4) { 1260*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_saddr[3], 1261*8275SEric Cheng sizeof (uint32_t), EXT_UINT32 | 1262*8275SEric Cheng EXD_NET_DESC_V4SADDR); 1263*8275SEric Cheng } else { 1264*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_saddr, 1265*8275SEric Cheng sizeof (nd->nd_saddr), EXT_RAW | 1266*8275SEric Cheng EXD_NET_DESC_V6SADDR); 1267*8275SEric Cheng } 1268*8275SEric Cheng break; 1269*8275SEric Cheng case AC_NET_DADDR: 1270*8275SEric Cheng if (nd->nd_isv4) { 1271*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_daddr[3], 1272*8275SEric Cheng sizeof (uint32_t), EXT_UINT32 | 1273*8275SEric Cheng EXD_NET_DESC_V4DADDR); 1274*8275SEric Cheng } else { 1275*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_daddr, 1276*8275SEric Cheng sizeof (nd->nd_daddr), EXT_RAW | 1277*8275SEric Cheng EXD_NET_DESC_V6DADDR); 1278*8275SEric Cheng } 1279*8275SEric Cheng break; 1280*8275SEric Cheng case AC_NET_SPORT: 1281*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_sport, 1282*8275SEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_SPORT); 1283*8275SEric Cheng break; 1284*8275SEric Cheng case AC_NET_DPORT: 1285*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_dport, 1286*8275SEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_DPORT); 1287*8275SEric Cheng break; 1288*8275SEric Cheng case AC_NET_PROTOCOL: 1289*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_protocol, 1290*8275SEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_PROTOCOL); 1291*8275SEric Cheng break; 1292*8275SEric Cheng case AC_NET_DSFIELD: 1293*8275SEric Cheng (void) ea_attach_item(record, &nd->nd_dsfield, 1294*8275SEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_DSFIELD); 1295*8275SEric Cheng break; 1296*8275SEric Cheng default: 1297*8275SEric Cheng attached = 0; 1298*8275SEric Cheng } 1299*8275SEric Cheng return (attached); 1300*8275SEric Cheng } 1301*8275SEric Cheng 1302*8275SEric Cheng static ea_object_t * 1303*8275SEric Cheng exacct_assemble_net_record(void *ninfo, ulong_t *mask, ea_catalog_t record_type, 1304*8275SEric Cheng int what) 1305*8275SEric Cheng { 1306*8275SEric Cheng int res; 1307*8275SEric Cheng int count; 1308*8275SEric Cheng ea_object_t *record; 1309*8275SEric Cheng 1310*8275SEric Cheng /* 1311*8275SEric Cheng * Assemble usage values into group. 1312*8275SEric Cheng */ 1313*8275SEric Cheng record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 1314*8275SEric Cheng for (res = 1, count = 0; res <= AC_NET_MAX_RES; res++) 1315*8275SEric Cheng if (BT_TEST(mask, res)) { 1316*8275SEric Cheng if (what == EX_NET_LNDESC_REC || 1317*8275SEric Cheng what == EX_NET_FLDESC_REC) { 1318*8275SEric Cheng count += exacct_attach_netdesc_item( 1319*8275SEric Cheng (net_desc_t *)ninfo, record, res); 1320*8275SEric Cheng } else { 1321*8275SEric Cheng count += exacct_attach_netstat_item( 1322*8275SEric Cheng (net_stat_t *)ninfo, record, res); 1323*8275SEric Cheng } 1324*8275SEric Cheng } 1325*8275SEric Cheng if (count == 0) { 1326*8275SEric Cheng ea_free_object(record, EUP_ALLOC); 1327*8275SEric Cheng record = NULL; 1328*8275SEric Cheng } 1329*8275SEric Cheng return (record); 1330*8275SEric Cheng } 1331*8275SEric Cheng 1332*8275SEric Cheng int 1333*8275SEric Cheng exacct_assemble_net_usage(ac_info_t *ac_net, void *ninfo, 1334*8275SEric Cheng int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 1335*8275SEric Cheng void *ubuf, size_t ubufsize, size_t *actual, int what) 1336*8275SEric Cheng { 1337*8275SEric Cheng ulong_t mask[AC_MASK_SZ]; 1338*8275SEric Cheng ea_object_t *net_desc; 1339*8275SEric Cheng ea_catalog_t record_type; 1340*8275SEric Cheng void *buf; 1341*8275SEric Cheng size_t bufsize; 1342*8275SEric Cheng int ret; 1343*8275SEric Cheng 1344*8275SEric Cheng mutex_enter(&ac_net->ac_lock); 1345*8275SEric Cheng if (ac_net->ac_state == AC_OFF) { 1346*8275SEric Cheng mutex_exit(&ac_net->ac_lock); 1347*8275SEric Cheng return (ENOTACTIVE); 1348*8275SEric Cheng } 1349*8275SEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ); 1350*8275SEric Cheng mutex_exit(&ac_net->ac_lock); 1351*8275SEric Cheng 1352*8275SEric Cheng switch (what) { 1353*8275SEric Cheng case EX_NET_LNDESC_REC: 1354*8275SEric Cheng record_type = EXD_GROUP_NET_LINK_DESC; 1355*8275SEric Cheng break; 1356*8275SEric Cheng case EX_NET_LNSTAT_REC: 1357*8275SEric Cheng record_type = EXD_GROUP_NET_LINK_STATS; 1358*8275SEric Cheng break; 1359*8275SEric Cheng case EX_NET_FLDESC_REC: 1360*8275SEric Cheng record_type = EXD_GROUP_NET_FLOW_DESC; 1361*8275SEric Cheng break; 1362*8275SEric Cheng case EX_NET_FLSTAT_REC: 1363*8275SEric Cheng record_type = EXD_GROUP_NET_FLOW_STATS; 1364*8275SEric Cheng break; 1365*8275SEric Cheng } 1366*8275SEric Cheng 1367*8275SEric Cheng net_desc = exacct_assemble_net_record(ninfo, mask, record_type, what); 1368*8275SEric Cheng if (net_desc == NULL) 1369*8275SEric Cheng return (0); 1370*8275SEric Cheng 1371*8275SEric Cheng /* 1372*8275SEric Cheng * Pack object into buffer and pass to callback. 1373*8275SEric Cheng */ 1374*8275SEric Cheng bufsize = ea_pack_object(net_desc, NULL, 0); 1375*8275SEric Cheng buf = kmem_alloc(bufsize, KM_NOSLEEP); 1376*8275SEric Cheng if (buf == NULL) 1377*8275SEric Cheng return (ENOMEM); 1378*8275SEric Cheng 1379*8275SEric Cheng (void) ea_pack_object(net_desc, buf, bufsize); 1380*8275SEric Cheng 1381*8275SEric Cheng ret = callback(ac_net, ubuf, ubufsize, buf, bufsize, actual); 1382*8275SEric Cheng 1383*8275SEric Cheng /* 1384*8275SEric Cheng * Free all previously allocations. 1385*8275SEric Cheng */ 1386*8275SEric Cheng kmem_free(buf, bufsize); 1387*8275SEric Cheng ea_free_object(net_desc, EUP_ALLOC); 1388*8275SEric Cheng return (ret); 1389*8275SEric Cheng } 1390*8275SEric Cheng 1391*8275SEric Cheng int 1392*8275SEric Cheng exacct_commit_netinfo(void *arg, int what) 1393*8275SEric Cheng { 1394*8275SEric Cheng size_t size; 1395*8275SEric Cheng ulong_t mask[AC_MASK_SZ]; 1396*8275SEric Cheng struct exacct_globals *acg; 1397*8275SEric Cheng ac_info_t *ac_net; 1398*8275SEric Cheng 1399*8275SEric Cheng if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 1400*8275SEric Cheng /* 1401*8275SEric Cheng * acctctl module not loaded. Nothing to do. 1402*8275SEric Cheng */ 1403*8275SEric Cheng return (ENOTACTIVE); 1404*8275SEric Cheng } 1405*8275SEric Cheng 1406*8275SEric Cheng /* 1407*8275SEric Cheng * Even though each zone nominally has its own flow accounting settings 1408*8275SEric Cheng * (ac_flow), these are only maintained by and for the global zone. 1409*8275SEric Cheng * 1410*8275SEric Cheng * If this were to change in the future, this function should grow a 1411*8275SEric Cheng * second zoneid (or zone) argument, and use the corresponding zone's 1412*8275SEric Cheng * settings rather than always using those of the global zone. 1413*8275SEric Cheng */ 1414*8275SEric Cheng acg = zone_getspecific(exacct_zone_key, global_zone); 1415*8275SEric Cheng ac_net = &acg->ac_net; 1416*8275SEric Cheng 1417*8275SEric Cheng mutex_enter(&ac_net->ac_lock); 1418*8275SEric Cheng if (ac_net->ac_state == AC_OFF) { 1419*8275SEric Cheng mutex_exit(&ac_net->ac_lock); 1420*8275SEric Cheng return (ENOTACTIVE); 1421*8275SEric Cheng } 1422*8275SEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ); 1423*8275SEric Cheng mutex_exit(&ac_net->ac_lock); 1424*8275SEric Cheng 1425*8275SEric Cheng return (exacct_assemble_net_usage(ac_net, arg, exacct_commit_callback, 1426*8275SEric Cheng NULL, 0, &size, what)); 1427*8275SEric Cheng } 1428*8275SEric Cheng 1429*8275SEric Cheng static int 14300Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res) 14310Sstevel@tonic-gate { 14320Sstevel@tonic-gate int attached = 1; 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate switch (res) { 14350Sstevel@tonic-gate case AC_FLOW_SADDR: 14360Sstevel@tonic-gate if (fu->fu_isv4) { 14370Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr[3], 14380Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR); 14390Sstevel@tonic-gate } else { 14400Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr, 14410Sstevel@tonic-gate sizeof (fu->fu_saddr), EXT_RAW | 14420Sstevel@tonic-gate EXD_FLOW_V6SADDR); 14430Sstevel@tonic-gate } 14440Sstevel@tonic-gate break; 14450Sstevel@tonic-gate case AC_FLOW_DADDR: 14460Sstevel@tonic-gate if (fu->fu_isv4) { 14470Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr[3], 14480Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR); 14490Sstevel@tonic-gate } else { 14500Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr, 14510Sstevel@tonic-gate sizeof (fu->fu_daddr), EXT_RAW | 14520Sstevel@tonic-gate EXD_FLOW_V6DADDR); 14530Sstevel@tonic-gate } 14540Sstevel@tonic-gate break; 14550Sstevel@tonic-gate case AC_FLOW_SPORT: 14560Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_sport, 14570Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT); 14580Sstevel@tonic-gate break; 14590Sstevel@tonic-gate case AC_FLOW_DPORT: 14600Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dport, 14610Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT); 14620Sstevel@tonic-gate break; 14630Sstevel@tonic-gate case AC_FLOW_PROTOCOL: 14640Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_protocol, 14650Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL); 14660Sstevel@tonic-gate break; 14670Sstevel@tonic-gate case AC_FLOW_DSFIELD: 14680Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dsfield, 14690Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD); 14700Sstevel@tonic-gate break; 14710Sstevel@tonic-gate case AC_FLOW_CTIME: 14720Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_ctime, 14730Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME); 14740Sstevel@tonic-gate break; 14750Sstevel@tonic-gate case AC_FLOW_LSEEN: 14760Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_lseen, 14770Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN); 14780Sstevel@tonic-gate break; 14790Sstevel@tonic-gate case AC_FLOW_NBYTES: 14800Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_nbytes, 14810Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES); 14820Sstevel@tonic-gate break; 14830Sstevel@tonic-gate case AC_FLOW_NPKTS: 14840Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_npackets, 14850Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS); 14860Sstevel@tonic-gate break; 14870Sstevel@tonic-gate case AC_FLOW_PROJID: 14880Sstevel@tonic-gate if (fu->fu_projid >= 0) { 14890Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_projid, 14900Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID); 14910Sstevel@tonic-gate } 14920Sstevel@tonic-gate break; 14930Sstevel@tonic-gate case AC_FLOW_UID: 14940Sstevel@tonic-gate if (fu->fu_userid >= 0) { 14950Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_userid, 14960Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID); 14970Sstevel@tonic-gate } 14980Sstevel@tonic-gate break; 14990Sstevel@tonic-gate case AC_FLOW_ANAME: 15000Sstevel@tonic-gate (void) ea_attach_item(record, fu->fu_aname, 15010Sstevel@tonic-gate strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME); 15020Sstevel@tonic-gate break; 15030Sstevel@tonic-gate default: 15040Sstevel@tonic-gate attached = 0; 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate return (attached); 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate static ea_object_t * 15100Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask, 15110Sstevel@tonic-gate ea_catalog_t record_type) 15120Sstevel@tonic-gate { 15130Sstevel@tonic-gate int res, count; 15140Sstevel@tonic-gate ea_object_t *record; 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate /* 15170Sstevel@tonic-gate * Assemble usage values into group. 15180Sstevel@tonic-gate */ 15190Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 15200Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++) 15210Sstevel@tonic-gate if (BT_TEST(mask, res)) 15220Sstevel@tonic-gate count += exacct_attach_flow_item(fu, record, res); 15230Sstevel@tonic-gate if (count == 0) { 15240Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 15250Sstevel@tonic-gate record = NULL; 15260Sstevel@tonic-gate } 15270Sstevel@tonic-gate return (record); 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate 15300Sstevel@tonic-gate int 15310Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu, 15320Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 15330Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual) 15340Sstevel@tonic-gate { 15350Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 15360Sstevel@tonic-gate ea_object_t *flow_usage; 15370Sstevel@tonic-gate ea_catalog_t record_type; 15380Sstevel@tonic-gate void *buf; 15390Sstevel@tonic-gate size_t bufsize; 15400Sstevel@tonic-gate int ret; 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 15430Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 15440Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 15450Sstevel@tonic-gate return (ENOTACTIVE); 15460Sstevel@tonic-gate } 15470Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 15480Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate record_type = EXD_GROUP_FLOW; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate flow_usage = exacct_assemble_flow_record(fu, mask, record_type); 15530Sstevel@tonic-gate if (flow_usage == NULL) { 15540Sstevel@tonic-gate return (0); 15550Sstevel@tonic-gate } 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate /* 15580Sstevel@tonic-gate * Pack object into buffer and pass to callback. 15590Sstevel@tonic-gate */ 15600Sstevel@tonic-gate bufsize = ea_pack_object(flow_usage, NULL, 0); 15610Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_NOSLEEP); 15620Sstevel@tonic-gate if (buf == NULL) { 15630Sstevel@tonic-gate return (ENOMEM); 15640Sstevel@tonic-gate } 15650Sstevel@tonic-gate 15660Sstevel@tonic-gate (void) ea_pack_object(flow_usage, buf, bufsize); 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual); 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate /* 15710Sstevel@tonic-gate * Free all previously allocations. 15720Sstevel@tonic-gate */ 15730Sstevel@tonic-gate kmem_free(buf, bufsize); 15740Sstevel@tonic-gate ea_free_object(flow_usage, EUP_ALLOC); 15750Sstevel@tonic-gate return (ret); 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate void 15790Sstevel@tonic-gate exacct_commit_flow(void *arg) 15800Sstevel@tonic-gate { 15810Sstevel@tonic-gate flow_usage_t *f = (flow_usage_t *)arg; 15820Sstevel@tonic-gate size_t size; 15830Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 15840Sstevel@tonic-gate struct exacct_globals *acg; 15850Sstevel@tonic-gate ac_info_t *ac_flow; 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 15880Sstevel@tonic-gate /* 15890Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 15900Sstevel@tonic-gate */ 15910Sstevel@tonic-gate return; 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate /* 15950Sstevel@tonic-gate * Even though each zone nominally has its own flow accounting settings 15960Sstevel@tonic-gate * (ac_flow), these are only maintained by and for the global zone. 15970Sstevel@tonic-gate * 15980Sstevel@tonic-gate * If this were to change in the future, this function should grow a 15990Sstevel@tonic-gate * second zoneid (or zone) argument, and use the corresponding zone's 16000Sstevel@tonic-gate * settings rather than always using those of the global zone. 16010Sstevel@tonic-gate */ 16020Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 16030Sstevel@tonic-gate ac_flow = &acg->ac_flow; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 16060Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 16070Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 16080Sstevel@tonic-gate return; 16090Sstevel@tonic-gate } 16100Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 16110Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 16120Sstevel@tonic-gate 16130Sstevel@tonic-gate (void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback, 16140Sstevel@tonic-gate NULL, 0, &size); 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate /* 16180Sstevel@tonic-gate * int exacct_tag_task(task_t *, void *, size_t, int) 16190Sstevel@tonic-gate * 16200Sstevel@tonic-gate * Overview 16210Sstevel@tonic-gate * exacct_tag_task() provides the exacct record construction and writing 16220Sstevel@tonic-gate * support required by putacct(2) for task entities. 16230Sstevel@tonic-gate * 16240Sstevel@tonic-gate * Return values 16250Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 16260Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 16270Sstevel@tonic-gate * 16280Sstevel@tonic-gate * Caller's context 16290Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 16300Sstevel@tonic-gate */ 16310Sstevel@tonic-gate int 16320Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz, 16330Sstevel@tonic-gate int flags) 16340Sstevel@tonic-gate { 16350Sstevel@tonic-gate int error = 0; 16360Sstevel@tonic-gate void *buf; 16370Sstevel@tonic-gate size_t bufsize; 16380Sstevel@tonic-gate ea_catalog_t cat; 16390Sstevel@tonic-gate ea_object_t *tag; 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 16420Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) { 16430Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 16440Sstevel@tonic-gate return (ENOTACTIVE); 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG); 16490Sstevel@tonic-gate (void) ea_attach_item(tag, &tk->tk_tkid, 0, 16500Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 16510Sstevel@tonic-gate (void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0, 16520Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 16530Sstevel@tonic-gate if (flags == EP_RAW) 16540Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG; 16550Sstevel@tonic-gate else 16560Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG; 16570Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 16580Sstevel@tonic-gate 16590Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 16600Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 16610Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 16620Sstevel@tonic-gate error = exacct_vn_write(ac_task, buf, bufsize); 16630Sstevel@tonic-gate kmem_free(buf, bufsize); 16640Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 16650Sstevel@tonic-gate return (error); 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate /* 16690Sstevel@tonic-gate * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *) 16700Sstevel@tonic-gate * 16710Sstevel@tonic-gate * Overview 16720Sstevel@tonic-gate * exacct_tag_proc() provides the exacct record construction and writing 16730Sstevel@tonic-gate * support required by putacct(2) for processes. 16740Sstevel@tonic-gate * 16750Sstevel@tonic-gate * Return values 16760Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 16770Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 16780Sstevel@tonic-gate * 16790Sstevel@tonic-gate * Caller's context 16800Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 16810Sstevel@tonic-gate */ 16820Sstevel@tonic-gate int 16830Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf, 16840Sstevel@tonic-gate size_t ubufsz, int flags, const char *hostname) 16850Sstevel@tonic-gate { 16860Sstevel@tonic-gate int error = 0; 16870Sstevel@tonic-gate void *buf; 16880Sstevel@tonic-gate size_t bufsize; 16890Sstevel@tonic-gate ea_catalog_t cat; 16900Sstevel@tonic-gate ea_object_t *tag; 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 16930Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) { 16940Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 16950Sstevel@tonic-gate return (ENOTACTIVE); 16960Sstevel@tonic-gate } 16970Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 16980Sstevel@tonic-gate 16990Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG); 17000Sstevel@tonic-gate (void) ea_attach_item(tag, &pid, sizeof (uint32_t), 17010Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID); 17020Sstevel@tonic-gate (void) ea_attach_item(tag, &tkid, 0, 17030Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 17040Sstevel@tonic-gate (void) ea_attach_item(tag, (void *)hostname, 0, 17050Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 17060Sstevel@tonic-gate if (flags == EP_RAW) 17070Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG; 17080Sstevel@tonic-gate else 17090Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG; 17100Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 17110Sstevel@tonic-gate 17120Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 17130Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 17140Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 17150Sstevel@tonic-gate error = exacct_vn_write(ac_proc, buf, bufsize); 17160Sstevel@tonic-gate kmem_free(buf, bufsize); 17170Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 17180Sstevel@tonic-gate return (error); 17190Sstevel@tonic-gate } 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate /* 17220Sstevel@tonic-gate * void exacct_init(void) 17230Sstevel@tonic-gate * 17240Sstevel@tonic-gate * Overview 17250Sstevel@tonic-gate * Initialized the extended accounting subsystem. 17260Sstevel@tonic-gate * 17270Sstevel@tonic-gate * Return values 17280Sstevel@tonic-gate * None. 17290Sstevel@tonic-gate * 17300Sstevel@tonic-gate * Caller's context 17310Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 17320Sstevel@tonic-gate */ 17330Sstevel@tonic-gate void 17340Sstevel@tonic-gate exacct_init() 17350Sstevel@tonic-gate { 17360Sstevel@tonic-gate exacct_queue = system_taskq; 17370Sstevel@tonic-gate exacct_object_cache = kmem_cache_create("exacct_object_cache", 17380Sstevel@tonic-gate sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 17390Sstevel@tonic-gate } 17404584Srh87107 17414584Srh87107 /* 17424584Srh87107 * exacct_snapshot_proc_mstate() copies a process's microstate accounting data 17434584Srh87107 * and resource usage counters into a given task_usage_t. It differs from 17444584Srh87107 * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t, 17454584Srh87107 * b) p_lock will have been acquired earlier in the call path and c) we 17464584Srh87107 * are here including the process's user and system times. 17474584Srh87107 */ 17484584Srh87107 static void 17494584Srh87107 exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu) 17504584Srh87107 { 17514584Srh87107 tu->tu_utime = mstate_aggr_state(p, LMS_USER); 17524584Srh87107 tu->tu_stime = mstate_aggr_state(p, LMS_SYSTEM); 17534584Srh87107 tu->tu_minflt = p->p_ru.minflt; 17544584Srh87107 tu->tu_majflt = p->p_ru.majflt; 17554584Srh87107 tu->tu_sndmsg = p->p_ru.msgsnd; 17564584Srh87107 tu->tu_rcvmsg = p->p_ru.msgrcv; 17574584Srh87107 tu->tu_ioch = p->p_ru.ioch; 17584584Srh87107 tu->tu_iblk = p->p_ru.inblock; 17594584Srh87107 tu->tu_oblk = p->p_ru.oublock; 17604584Srh87107 tu->tu_vcsw = p->p_ru.nvcsw; 17614584Srh87107 tu->tu_icsw = p->p_ru.nivcsw; 17624584Srh87107 tu->tu_nsig = p->p_ru.nsignals; 17634584Srh87107 tu->tu_nswp = p->p_ru.nswap; 17644584Srh87107 tu->tu_nscl = p->p_ru.sysc; 17654584Srh87107 } 17664584Srh87107 17674584Srh87107 /* 17684584Srh87107 * void exacct_move_mstate(proc_t *, task_t *, task_t *) 17694584Srh87107 * 17704584Srh87107 * Overview 17714584Srh87107 * exacct_move_mstate() is called by task_change() and accounts for 17724584Srh87107 * a process's resource usage when it is moved from one task to another. 17734584Srh87107 * 17744584Srh87107 * The process's usage at this point is recorded in the new task so 17754584Srh87107 * that it can be excluded from the calculation of resources consumed 17764584Srh87107 * by that task. 17774584Srh87107 * 17784584Srh87107 * The resource usage inherited by the new task is also added to the 17794584Srh87107 * aggregate maintained by the old task for processes that have exited. 17804584Srh87107 * 17814584Srh87107 * Return values 17824584Srh87107 * None. 17834584Srh87107 * 17844584Srh87107 * Caller's context 17854584Srh87107 * pidlock and p_lock held across exacct_move_mstate(). 17864584Srh87107 */ 17874584Srh87107 void 17884584Srh87107 exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk) 17894584Srh87107 { 17904584Srh87107 task_usage_t tu; 17914584Srh87107 17924584Srh87107 /* Take a snapshot of this process's mstate and RU counters */ 17934584Srh87107 exacct_snapshot_proc_mstate(p, &tu); 17944584Srh87107 17954584Srh87107 /* 17964584Srh87107 * Use the snapshot to increment the aggregate usage of the old 17974584Srh87107 * task, and the inherited usage of the new one. 17984584Srh87107 */ 17994584Srh87107 mutex_enter(&oldtk->tk_usage_lock); 18004584Srh87107 exacct_add_task_mstate(oldtk->tk_usage, &tu); 18014584Srh87107 mutex_exit(&oldtk->tk_usage_lock); 18024584Srh87107 mutex_enter(&newtk->tk_usage_lock); 18034584Srh87107 exacct_add_task_mstate(newtk->tk_inherited, &tu); 18044584Srh87107 mutex_exit(&newtk->tk_usage_lock); 18054584Srh87107 } 1806