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 /* 224584Srh87107 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/exacct.h> 290Sstevel@tonic-gate #include <sys/exacct_catalog.h> 300Sstevel@tonic-gate #include <sys/disp.h> 310Sstevel@tonic-gate #include <sys/task.h> 320Sstevel@tonic-gate #include <sys/proc.h> 330Sstevel@tonic-gate #include <sys/cmn_err.h> 340Sstevel@tonic-gate #include <sys/kmem.h> 350Sstevel@tonic-gate #include <sys/project.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/vnode.h> 380Sstevel@tonic-gate #include <sys/file.h> 390Sstevel@tonic-gate #include <sys/acctctl.h> 400Sstevel@tonic-gate #include <sys/time.h> 410Sstevel@tonic-gate #include <sys/utsname.h> 420Sstevel@tonic-gate #include <sys/session.h> 430Sstevel@tonic-gate #include <sys/sysmacros.h> 440Sstevel@tonic-gate #include <sys/bitmap.h> 450Sstevel@tonic-gate #include <sys/msacct.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * exacct usage and recording routines 490Sstevel@tonic-gate * 500Sstevel@tonic-gate * wracct(2), getacct(2), and the records written at process or task 510Sstevel@tonic-gate * termination are constructed using the exacct_assemble_[task,proc]_usage() 520Sstevel@tonic-gate * functions, which take a callback that takes the appropriate action on 530Sstevel@tonic-gate * the packed exacct record for the task or process. For the process-related 540Sstevel@tonic-gate * actions, we partition the routines such that the data collecting component 550Sstevel@tonic-gate * can be performed while holding p_lock, and all sleeping or blocking 560Sstevel@tonic-gate * operations can be performed without acquiring p_lock. 570Sstevel@tonic-gate * 580Sstevel@tonic-gate * putacct(2), which allows an application to construct a customized record 590Sstevel@tonic-gate * associated with an existing process or task, has its own entry points: 600Sstevel@tonic-gate * exacct_tag_task() and exacct_tag_proc(). 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate taskq_t *exacct_queue; 640Sstevel@tonic-gate kmem_cache_t *exacct_object_cache; 650Sstevel@tonic-gate 660Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED; 670Sstevel@tonic-gate 680Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION; 690Sstevel@tonic-gate static const char exacct_header[] = "exacct"; 700Sstevel@tonic-gate static const char exacct_creator[] = "SunOS"; 710Sstevel@tonic-gate 720Sstevel@tonic-gate ea_object_t * 730Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz) 740Sstevel@tonic-gate { 750Sstevel@tonic-gate ea_object_t *item; 760Sstevel@tonic-gate 770Sstevel@tonic-gate item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 780Sstevel@tonic-gate bzero(item, sizeof (ea_object_t)); 790Sstevel@tonic-gate (void) ea_set_item(item, catalog, buf, bufsz); 800Sstevel@tonic-gate return (item); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate ea_object_t * 840Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog) 850Sstevel@tonic-gate { 860Sstevel@tonic-gate ea_object_t *group; 870Sstevel@tonic-gate 880Sstevel@tonic-gate group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 890Sstevel@tonic-gate bzero(group, sizeof (ea_object_t)); 900Sstevel@tonic-gate (void) ea_set_group(group, catalog); 910Sstevel@tonic-gate return (group); 920Sstevel@tonic-gate } 930Sstevel@tonic-gate 940Sstevel@tonic-gate ea_object_t * 950Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog) 960Sstevel@tonic-gate { 970Sstevel@tonic-gate ea_object_t *item; 980Sstevel@tonic-gate 990Sstevel@tonic-gate item = ea_alloc_item(catalog, buf, bufsz); 1000Sstevel@tonic-gate (void) ea_attach_to_group(grp, item); 1010Sstevel@tonic-gate return (item); 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /* 1054584Srh87107 * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract 1064584Srh87107 * microstate accounting data and resource usage counters from one task_usage_t 1074584Srh87107 * from those supplied in another. These functions do not operate on *all* 1084584Srh87107 * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make 1094584Srh87107 * sense. 1104584Srh87107 */ 1114584Srh87107 static void 1124584Srh87107 exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta) 1134584Srh87107 { 1144584Srh87107 tu->tu_utime += delta->tu_utime; 1154584Srh87107 tu->tu_stime += delta->tu_stime; 1164584Srh87107 tu->tu_minflt += delta->tu_minflt; 1174584Srh87107 tu->tu_majflt += delta->tu_majflt; 1184584Srh87107 tu->tu_sndmsg += delta->tu_sndmsg; 1194584Srh87107 tu->tu_rcvmsg += delta->tu_rcvmsg; 1204584Srh87107 tu->tu_ioch += delta->tu_ioch; 1214584Srh87107 tu->tu_iblk += delta->tu_iblk; 1224584Srh87107 tu->tu_oblk += delta->tu_oblk; 1234584Srh87107 tu->tu_vcsw += delta->tu_vcsw; 1244584Srh87107 tu->tu_icsw += delta->tu_icsw; 1254584Srh87107 tu->tu_nsig += delta->tu_nsig; 1264584Srh87107 tu->tu_nswp += delta->tu_nswp; 1274584Srh87107 tu->tu_nscl += delta->tu_nscl; 1284584Srh87107 } 1294584Srh87107 1304584Srh87107 /* 1314584Srh87107 * See the comments for exacct_add_task_mstate(), above. 1324584Srh87107 */ 1334584Srh87107 static void 1344584Srh87107 exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta) 1354584Srh87107 { 1364584Srh87107 tu->tu_utime -= delta->tu_utime; 1374584Srh87107 tu->tu_stime -= delta->tu_stime; 1384584Srh87107 tu->tu_minflt -= delta->tu_minflt; 1394584Srh87107 tu->tu_majflt -= delta->tu_majflt; 1404584Srh87107 tu->tu_sndmsg -= delta->tu_sndmsg; 1414584Srh87107 tu->tu_rcvmsg -= delta->tu_rcvmsg; 1424584Srh87107 tu->tu_ioch -= delta->tu_ioch; 1434584Srh87107 tu->tu_iblk -= delta->tu_iblk; 1444584Srh87107 tu->tu_oblk -= delta->tu_oblk; 1454584Srh87107 tu->tu_vcsw -= delta->tu_vcsw; 1464584Srh87107 tu->tu_icsw -= delta->tu_icsw; 1474584Srh87107 tu->tu_nsig -= delta->tu_nsig; 1484584Srh87107 tu->tu_nswp -= delta->tu_nswp; 1494584Srh87107 tu->tu_nscl -= delta->tu_nscl; 1504584Srh87107 } 1514584Srh87107 1524584Srh87107 /* 1530Sstevel@tonic-gate * exacct_vn_write() is a vn_rdwr wrapper that protects us from corrupting the 1540Sstevel@tonic-gate * accounting file in case of an I/O or filesystem error. acctctl() prevents 1550Sstevel@tonic-gate * the two accounting vnodes from being equal, and the appropriate ac_lock is 1560Sstevel@tonic-gate * held across the call, so we're single threaded through this code for each 1570Sstevel@tonic-gate * file. 1580Sstevel@tonic-gate */ 1590Sstevel@tonic-gate static int 1600Sstevel@tonic-gate exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize) 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate int error = 0; 1630Sstevel@tonic-gate ssize_t resid; 1640Sstevel@tonic-gate struct vattr va; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate if (info == NULL) 1670Sstevel@tonic-gate return (0); 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate mutex_enter(&info->ac_lock); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* 1720Sstevel@tonic-gate * Don't do anything unless accounting file is set. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate if (info->ac_vnode == NULL) { 1750Sstevel@tonic-gate mutex_exit(&info->ac_lock); 1760Sstevel@tonic-gate return (0); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * Save the size. If vn_rdwr fails, reset the size to avoid corrupting 1810Sstevel@tonic-gate * the present accounting file. 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate va.va_mask = AT_SIZE; 184*5331Samw error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1850Sstevel@tonic-gate if (error == 0) { 1860Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf, 1870Sstevel@tonic-gate bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T, 1880Sstevel@tonic-gate kcred, &resid); 1890Sstevel@tonic-gate if (error) { 1900Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1910Sstevel@tonic-gate } else if (resid != 0) { 1920Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1930Sstevel@tonic-gate error = ENOSPC; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate mutex_exit(&info->ac_lock); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate return (error); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * void *exacct_create_header(size_t *) 2030Sstevel@tonic-gate * 2040Sstevel@tonic-gate * Overview 2050Sstevel@tonic-gate * exacct_create_header() constructs an exacct file header identifying the 2060Sstevel@tonic-gate * accounting file as the output of the kernel. exacct_create_header() and 2070Sstevel@tonic-gate * the static write_header() and verify_header() routines in libexacct must 2080Sstevel@tonic-gate * remain synchronized. 2090Sstevel@tonic-gate * 2100Sstevel@tonic-gate * Return values 2110Sstevel@tonic-gate * A pointer to a packed exacct buffer containing the appropriate header is 2120Sstevel@tonic-gate * returned; the size of the buffer is placed in the location indicated by 2130Sstevel@tonic-gate * sizep. 2140Sstevel@tonic-gate * 2150Sstevel@tonic-gate * Caller's context 2160Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate void * 2190Sstevel@tonic-gate exacct_create_header(size_t *sizep) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate ea_object_t *hdr_grp; 2220Sstevel@tonic-gate uint32_t bskip; 2230Sstevel@tonic-gate void *buf; 2240Sstevel@tonic-gate size_t bufsize; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER); 2270Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0, 2280Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_VERSION); 2290Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_header, 0, 2300Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_FILETYPE); 2310Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0, 2320Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_CREATOR); 2330Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, uts_nodename(), 0, 2340Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate bufsize = ea_pack_object(hdr_grp, NULL, 0); 2370Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 2380Sstevel@tonic-gate (void) ea_pack_object(hdr_grp, buf, bufsize); 2390Sstevel@tonic-gate ea_free_object(hdr_grp, EUP_ALLOC); 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * To prevent reading the header when reading the file backwards, 2430Sstevel@tonic-gate * set the large backskip of the header group to 0 (last 4 bytes). 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate bskip = 0; 2460Sstevel@tonic-gate exacct_order32(&bskip); 2470Sstevel@tonic-gate bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip), 2480Sstevel@tonic-gate sizeof (bskip)); 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate *sizep = bufsize; 2510Sstevel@tonic-gate return (buf); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* 2550Sstevel@tonic-gate * int exacct_write_header(ac_info_t *, void *, size_t) 2560Sstevel@tonic-gate * 2570Sstevel@tonic-gate * Overview 2580Sstevel@tonic-gate * exacct_write_header() writes the given header buffer to the indicated 2590Sstevel@tonic-gate * vnode, and frees the buffer. 2600Sstevel@tonic-gate * 2610Sstevel@tonic-gate * Return values 2620Sstevel@tonic-gate * The result of the write operation is returned. 2630Sstevel@tonic-gate * 2640Sstevel@tonic-gate * Caller's context 2650Sstevel@tonic-gate * Caller must not hold the ac_lock of the appropriate accounting file 2660Sstevel@tonic-gate * information block (ac_info_t). 2670Sstevel@tonic-gate */ 2680Sstevel@tonic-gate int 2690Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize) 2700Sstevel@tonic-gate { 2710Sstevel@tonic-gate int error; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate error = exacct_vn_write(info, hdr, hdrsize); 2740Sstevel@tonic-gate kmem_free(hdr, hdrsize); 2750Sstevel@tonic-gate return (error); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate static void 2790Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu, 2800Sstevel@tonic-gate task_usage_t **tu_buf) 2810Sstevel@tonic-gate { 2820Sstevel@tonic-gate task_usage_t *oldtu, *newtu; 2830Sstevel@tonic-gate task_usage_t **prevusage; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tk->tk_usage_lock)); 2860Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) { 2870Sstevel@tonic-gate prevusage = &tk->tk_zoneusage; 2880Sstevel@tonic-gate } else { 2890Sstevel@tonic-gate prevusage = &tk->tk_prevusage; 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate if ((oldtu = *prevusage) != NULL) { 2920Sstevel@tonic-gate /* 2930Sstevel@tonic-gate * In case we have any accounting information 2940Sstevel@tonic-gate * saved from the previous interval record. 2950Sstevel@tonic-gate */ 2960Sstevel@tonic-gate newtu = *tu_buf; 2970Sstevel@tonic-gate bcopy(tu, newtu, sizeof (task_usage_t)); 2980Sstevel@tonic-gate tu->tu_minflt -= oldtu->tu_minflt; 2990Sstevel@tonic-gate tu->tu_majflt -= oldtu->tu_majflt; 3000Sstevel@tonic-gate tu->tu_sndmsg -= oldtu->tu_sndmsg; 3010Sstevel@tonic-gate tu->tu_rcvmsg -= oldtu->tu_rcvmsg; 3020Sstevel@tonic-gate tu->tu_ioch -= oldtu->tu_ioch; 3030Sstevel@tonic-gate tu->tu_iblk -= oldtu->tu_iblk; 3040Sstevel@tonic-gate tu->tu_oblk -= oldtu->tu_oblk; 3050Sstevel@tonic-gate tu->tu_vcsw -= oldtu->tu_vcsw; 3060Sstevel@tonic-gate tu->tu_icsw -= oldtu->tu_icsw; 3070Sstevel@tonic-gate tu->tu_nsig -= oldtu->tu_nsig; 3080Sstevel@tonic-gate tu->tu_nswp -= oldtu->tu_nswp; 3090Sstevel@tonic-gate tu->tu_nscl -= oldtu->tu_nscl; 3100Sstevel@tonic-gate tu->tu_utime -= oldtu->tu_utime; 3110Sstevel@tonic-gate tu->tu_stime -= oldtu->tu_stime; 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate tu->tu_startsec = oldtu->tu_finishsec; 3140Sstevel@tonic-gate tu->tu_startnsec = oldtu->tu_finishnsec; 3150Sstevel@tonic-gate /* 3160Sstevel@tonic-gate * Copy the data from our temporary storage to the task's 3170Sstevel@tonic-gate * previous interval usage structure for future reference. 3180Sstevel@tonic-gate */ 3190Sstevel@tonic-gate bcopy(newtu, oldtu, sizeof (task_usage_t)); 3200Sstevel@tonic-gate } else { 3210Sstevel@tonic-gate /* 3220Sstevel@tonic-gate * Store current statistics in the task's previous interval 3230Sstevel@tonic-gate * usage structure for future references. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate *prevusage = *tu_buf; 3260Sstevel@tonic-gate bcopy(tu, *prevusage, sizeof (task_usage_t)); 3270Sstevel@tonic-gate *tu_buf = NULL; 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate static void 3320Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu) 3330Sstevel@tonic-gate { 3340Sstevel@tonic-gate timestruc_t ts; 3350Sstevel@tonic-gate proc_t *p; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate if ((p = tk->tk_memb_list) == NULL) 3400Sstevel@tonic-gate return; 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate /* 3430Sstevel@tonic-gate * exacct_snapshot_task_usage() provides an approximate snapshot of the 3440Sstevel@tonic-gate * usage of the potentially many members of the task. Since we don't 3450Sstevel@tonic-gate * guarantee exactness, we don't acquire the p_lock of any of the member 3460Sstevel@tonic-gate * processes. 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate do { 3490Sstevel@tonic-gate mutex_enter(&p->p_lock); 3500Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 3510Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 3520Sstevel@tonic-gate mutex_exit(&p->p_lock); 3530Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 3540Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 3550Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 3560Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 3570Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 3580Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 3590Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 3600Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 3610Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 3620Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 3630Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 3640Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 3650Sstevel@tonic-gate } while ((p = p->p_tasknext) != tk->tk_memb_list); 3660Sstevel@tonic-gate 3674584Srh87107 /* 3684584Srh87107 * The resource usage accounted for so far will include that 3694584Srh87107 * contributed by the task's first process. If this process 3704584Srh87107 * came from another task, then its accumulated resource usage 3714584Srh87107 * will include a contribution from work performed there. 3724584Srh87107 * We must therefore subtract any resource usage that was 3734584Srh87107 * inherited with the first process. 3744584Srh87107 */ 3754584Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 3764584Srh87107 3770Sstevel@tonic-gate gethrestime(&ts); 3780Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 3790Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 3834584Srh87107 * void exacct_update_task_mstate(proc_t *) 3844584Srh87107 * 3854584Srh87107 * Overview 3864584Srh87107 * exacct_update_task_mstate() updates the task usage; it is intended 3874584Srh87107 * to be called from proc_exit(). 3884584Srh87107 * 3894584Srh87107 * Return values 3904584Srh87107 * None. 3914584Srh87107 * 3924584Srh87107 * Caller's context 3934584Srh87107 * p_lock must be held at entry. 3940Sstevel@tonic-gate */ 3954584Srh87107 void 3960Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p) 3970Sstevel@tonic-gate { 3980Sstevel@tonic-gate task_usage_t *tu; 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate mutex_enter(&p->p_task->tk_usage_lock); 4010Sstevel@tonic-gate tu = p->p_task->tk_usage; 4020Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 4030Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 4040Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 4050Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 4060Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 4070Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 4080Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 4090Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 4100Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 4110Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 4120Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 4130Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 4140Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 4150Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 4160Sstevel@tonic-gate mutex_exit(&p->p_task->tk_usage_lock); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate static void 4200Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag) 4210Sstevel@tonic-gate { 4220Sstevel@tonic-gate timestruc_t ts; 4230Sstevel@tonic-gate task_usage_t *tu_buf; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate switch (flag) { 4260Sstevel@tonic-gate case EW_PARTIAL: 4270Sstevel@tonic-gate /* 4280Sstevel@tonic-gate * For partial records we must report the sum of current 4290Sstevel@tonic-gate * accounting statistics with previously accumulated 4300Sstevel@tonic-gate * statistics. 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate mutex_enter(&pidlock); 4330Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4360Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4390Sstevel@tonic-gate mutex_exit(&pidlock); 4400Sstevel@tonic-gate break; 4410Sstevel@tonic-gate case EW_INTERVAL: 4420Sstevel@tonic-gate /* 4430Sstevel@tonic-gate * We need to allocate spare task_usage_t buffer before 4440Sstevel@tonic-gate * grabbing pidlock because we might need it later in 4450Sstevel@tonic-gate * exacct_get_interval_task_usage(). 4460Sstevel@tonic-gate */ 4470Sstevel@tonic-gate tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 4480Sstevel@tonic-gate mutex_enter(&pidlock); 4490Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * For interval records, we deduct the previous microstate 4530Sstevel@tonic-gate * accounting data and cpu usage times from previously saved 4540Sstevel@tonic-gate * results and update the previous task usage structure. 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4570Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4580Sstevel@tonic-gate exacct_get_interval_task_usage(tk, tu, &tu_buf); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4610Sstevel@tonic-gate mutex_exit(&pidlock); 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate if (tu_buf != NULL) 4640Sstevel@tonic-gate kmem_free(tu_buf, sizeof (task_usage_t)); 4650Sstevel@tonic-gate break; 4660Sstevel@tonic-gate case EW_FINAL: 4670Sstevel@tonic-gate /* 4684584Srh87107 * For final records, we deduct, from the task's current 4694584Srh87107 * usage, any usage that was inherited with the arrival 4704584Srh87107 * of a process from a previous task. We then record 4714584Srh87107 * the task's finish time. 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4740Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4754584Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 4760Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate gethrestime(&ts); 4790Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 4800Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate break; 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate static int 4870Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record, 4880Sstevel@tonic-gate int res) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate int attached = 1; 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate switch (res) { 4930Sstevel@tonic-gate case AC_TASK_TASKID: 4940Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_tkid, 4950Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID); 4960Sstevel@tonic-gate break; 4970Sstevel@tonic-gate case AC_TASK_PROJID: 4980Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_proj->kpj_id, 4990Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID); 5000Sstevel@tonic-gate break; 5010Sstevel@tonic-gate case AC_TASK_CPU: { 5020Sstevel@tonic-gate timestruc_t ts; 5030Sstevel@tonic-gate uint64_t ui; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate hrt2ts(tu->tu_stime, &ts); 5060Sstevel@tonic-gate ui = ts.tv_sec; 5070Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5080Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_SEC); 5090Sstevel@tonic-gate ui = ts.tv_nsec; 5100Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5110Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC); 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate hrt2ts(tu->tu_utime, &ts); 5140Sstevel@tonic-gate ui = ts.tv_sec; 5150Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5160Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_SEC); 5170Sstevel@tonic-gate ui = ts.tv_nsec; 5180Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5190Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_NSEC); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate break; 5220Sstevel@tonic-gate case AC_TASK_TIME: 5230Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startsec, 5240Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC); 5250Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startnsec, 5260Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC); 5270Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishsec, 5280Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC); 5290Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishnsec, 5300Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC); 5310Sstevel@tonic-gate break; 5320Sstevel@tonic-gate case AC_TASK_HOSTNAME: 5330Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_nodename, 5340Sstevel@tonic-gate strlen(tk->tk_zone->zone_nodename) + 1, 5350Sstevel@tonic-gate EXT_STRING | EXD_TASK_HOSTNAME); 5360Sstevel@tonic-gate break; 5370Sstevel@tonic-gate case AC_TASK_MICROSTATE: 5380Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_majflt, 5390Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR); 5400Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_minflt, 5410Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR); 5420Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_sndmsg, 5430Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND); 5440Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_rcvmsg, 5450Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV); 5460Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_iblk, 5470Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN); 5480Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_oblk, 5490Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT); 5500Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_ioch, 5510Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR); 5520Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_vcsw, 5530Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL); 5540Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_icsw, 5550Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV); 5560Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nsig, 5570Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS); 5580Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nswp, 5590Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS); 5600Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nscl, 5610Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS); 5620Sstevel@tonic-gate break; 5630Sstevel@tonic-gate case AC_TASK_ANCTASKID: 5640Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_anctaskid, 5650Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID); 5660Sstevel@tonic-gate break; 5670Sstevel@tonic-gate case AC_TASK_ZONENAME: 5680Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_name, 5690Sstevel@tonic-gate strlen(tk->tk_zone->zone_name) + 1, 5700Sstevel@tonic-gate EXT_STRING | EXD_TASK_ZONENAME); 5710Sstevel@tonic-gate break; 5720Sstevel@tonic-gate default: 5730Sstevel@tonic-gate attached = 0; 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate return (attached); 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate static ea_object_t * 5790Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask, 5800Sstevel@tonic-gate ea_catalog_t record_type) 5810Sstevel@tonic-gate { 5820Sstevel@tonic-gate int res, count; 5830Sstevel@tonic-gate ea_object_t *record; 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* 5860Sstevel@tonic-gate * Assemble usage values into group. 5870Sstevel@tonic-gate */ 5880Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 5890Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++) 5900Sstevel@tonic-gate if (BT_TEST(mask, res)) 5910Sstevel@tonic-gate count += exacct_attach_task_item(tk, tu, record, res); 5920Sstevel@tonic-gate if (count == 0) { 5930Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 5940Sstevel@tonic-gate record = NULL; 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate return (record); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *, 6010Sstevel@tonic-gate * size_t, size_t *), void *, size_t, size_t *, int) 6020Sstevel@tonic-gate * 6030Sstevel@tonic-gate * Overview 6040Sstevel@tonic-gate * exacct_assemble_task_usage() builds the packed exacct buffer for the 6050Sstevel@tonic-gate * indicated task, executes the given callback function, and free the packed 6060Sstevel@tonic-gate * buffer. 6070Sstevel@tonic-gate * 6080Sstevel@tonic-gate * Return values 6090Sstevel@tonic-gate * Returns 0 on success; otherwise the appropriate error code is returned. 6100Sstevel@tonic-gate * 6110Sstevel@tonic-gate * Caller's context 6120Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate int 6150Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk, 6160Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 6170Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 6180Sstevel@tonic-gate { 6190Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 6200Sstevel@tonic-gate ea_object_t *task_record; 6210Sstevel@tonic-gate ea_catalog_t record_type; 6220Sstevel@tonic-gate task_usage_t *tu; 6230Sstevel@tonic-gate void *buf; 6240Sstevel@tonic-gate size_t bufsize; 6250Sstevel@tonic-gate int ret; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL); 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 6300Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF) { 6310Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6320Sstevel@tonic-gate return (ENOTACTIVE); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ); 6350Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate switch (flag) { 6380Sstevel@tonic-gate case EW_FINAL: 6390Sstevel@tonic-gate record_type = EXD_GROUP_TASK; 6400Sstevel@tonic-gate break; 6410Sstevel@tonic-gate case EW_PARTIAL: 6420Sstevel@tonic-gate record_type = EXD_GROUP_TASK_PARTIAL; 6430Sstevel@tonic-gate break; 6440Sstevel@tonic-gate case EW_INTERVAL: 6450Sstevel@tonic-gate record_type = EXD_GROUP_TASK_INTERVAL; 6460Sstevel@tonic-gate break; 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * Calculate task usage and assemble it into the task record. 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 6530Sstevel@tonic-gate exacct_calculate_task_usage(tk, tu, flag); 6540Sstevel@tonic-gate task_record = exacct_assemble_task_record(tk, tu, mask, record_type); 6550Sstevel@tonic-gate if (task_record == NULL) { 6560Sstevel@tonic-gate /* 6570Sstevel@tonic-gate * The current configuration of the accounting system has 6580Sstevel@tonic-gate * resulted in records with no data; accordingly, we don't write 6590Sstevel@tonic-gate * these, but we return success. 6600Sstevel@tonic-gate */ 6610Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6620Sstevel@tonic-gate return (0); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* 6660Sstevel@tonic-gate * Pack object into buffer and run callback on it. 6670Sstevel@tonic-gate */ 6680Sstevel@tonic-gate bufsize = ea_pack_object(task_record, NULL, 0); 6690Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 6700Sstevel@tonic-gate (void) ea_pack_object(task_record, buf, bufsize); 6710Sstevel@tonic-gate ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual); 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* 6740Sstevel@tonic-gate * Free all previously allocated structures. 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate kmem_free(buf, bufsize); 6770Sstevel@tonic-gate ea_free_object(task_record, EUP_ALLOC); 6780Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6790Sstevel@tonic-gate return (ret); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate /* 6830Sstevel@tonic-gate * void exacct_commit_task(void *) 6840Sstevel@tonic-gate * 6850Sstevel@tonic-gate * Overview 6860Sstevel@tonic-gate * exacct_commit_task() calculates the final usage for a task, updating the 6870Sstevel@tonic-gate * task usage if task accounting is active, and writing a task record if task 6880Sstevel@tonic-gate * accounting is active. exacct_commit_task() is intended for being called 6890Sstevel@tonic-gate * from a task queue (taskq_t). 6900Sstevel@tonic-gate * 6910Sstevel@tonic-gate * Return values 6920Sstevel@tonic-gate * None. 6930Sstevel@tonic-gate * 6940Sstevel@tonic-gate * Caller's context 6950Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate void 6990Sstevel@tonic-gate exacct_commit_task(void *arg) 7000Sstevel@tonic-gate { 7010Sstevel@tonic-gate task_t *tk = (task_t *)arg; 7020Sstevel@tonic-gate size_t size; 7030Sstevel@tonic-gate zone_t *zone = tk->tk_zone; 7040Sstevel@tonic-gate struct exacct_globals *acg; 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate ASSERT(tk != task0p); 7070Sstevel@tonic-gate ASSERT(tk->tk_memb_list == NULL); 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * Don't do any extra work if the acctctl module isn't loaded. 7110Sstevel@tonic-gate */ 7120Sstevel@tonic-gate if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) { 7130Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 7140Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7150Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7160Sstevel@tonic-gate if (tk->tk_zone != global_zone) { 7170Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 7180Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7190Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * Release associated project and finalize task. 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate task_end(tk); 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate static int 7290Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res) 7300Sstevel@tonic-gate { 7310Sstevel@tonic-gate int attached = 1; 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate switch (res) { 7340Sstevel@tonic-gate case AC_PROC_PID: 7350Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_pid, 7360Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID); 7370Sstevel@tonic-gate break; 7380Sstevel@tonic-gate case AC_PROC_UID: 7390Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ruid, 7400Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID); 7410Sstevel@tonic-gate break; 7420Sstevel@tonic-gate case AC_PROC_FLAG: 7430Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_acflag, 7440Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS); 7450Sstevel@tonic-gate break; 7460Sstevel@tonic-gate case AC_PROC_GID: 7470Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rgid, 7480Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID); 7490Sstevel@tonic-gate break; 7500Sstevel@tonic-gate case AC_PROC_PROJID: 7510Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_projid, 7520Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID); 7530Sstevel@tonic-gate break; 7540Sstevel@tonic-gate case AC_PROC_TASKID: 7550Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_taskid, 7560Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID); 7570Sstevel@tonic-gate break; 7580Sstevel@tonic-gate case AC_PROC_CPU: 7590Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimesec, 7600Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC); 7610Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimensec, 7620Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC); 7630Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimesec, 7640Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC); 7650Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimensec, 7660Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC); 7670Sstevel@tonic-gate break; 7680Sstevel@tonic-gate case AC_PROC_TIME: 7690Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startsec, 7700Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC); 7710Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startnsec, 7720Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC); 7730Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishsec, 7740Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC); 7750Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishnsec, 7760Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC); 7770Sstevel@tonic-gate break; 7780Sstevel@tonic-gate case AC_PROC_COMMAND: 7790Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_command, 7800Sstevel@tonic-gate strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND); 7810Sstevel@tonic-gate break; 7820Sstevel@tonic-gate case AC_PROC_HOSTNAME: 7830Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_nodename, 7840Sstevel@tonic-gate strlen(pu->pu_nodename) + 1, 7850Sstevel@tonic-gate EXT_STRING | EXD_PROC_HOSTNAME); 7860Sstevel@tonic-gate break; 7870Sstevel@tonic-gate case AC_PROC_TTY: 7880Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_major, 7890Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR); 7900Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minor, 7910Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR); 7920Sstevel@tonic-gate break; 7930Sstevel@tonic-gate case AC_PROC_MICROSTATE: 7940Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_majflt, 7950Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR); 7960Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minflt, 7970Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR); 7980Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_sndmsg, 7990Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND); 8000Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rcvmsg, 8010Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV); 8020Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_iblk, 8030Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN); 8040Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_oblk, 8050Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT); 8060Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ioch, 8070Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR); 8080Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_vcsw, 8090Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL); 8100Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_icsw, 8110Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV); 8120Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nsig, 8130Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS); 8140Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nswp, 8150Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS); 8160Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nscl, 8170Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS); 8180Sstevel@tonic-gate break; 8190Sstevel@tonic-gate case AC_PROC_ANCPID: 8200Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ancpid, 8210Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID); 8220Sstevel@tonic-gate break; 8230Sstevel@tonic-gate case AC_PROC_WAIT_STATUS: 8240Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_wstat, 8250Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS); 8260Sstevel@tonic-gate break; 8270Sstevel@tonic-gate case AC_PROC_ZONENAME: 8280Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_zonename, 8290Sstevel@tonic-gate strlen(pu->pu_zonename) + 1, 8300Sstevel@tonic-gate EXT_STRING | EXD_PROC_ZONENAME); 8310Sstevel@tonic-gate break; 8320Sstevel@tonic-gate case AC_PROC_MEM: 8330Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_avg, 8340Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K); 8350Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_max, 8360Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K); 8370Sstevel@tonic-gate break; 8380Sstevel@tonic-gate default: 8390Sstevel@tonic-gate attached = 0; 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate return (attached); 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate static ea_object_t * 8450Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask, 8460Sstevel@tonic-gate ea_catalog_t record_type) 8470Sstevel@tonic-gate { 8480Sstevel@tonic-gate int res, count; 8490Sstevel@tonic-gate ea_object_t *record; 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate /* 8520Sstevel@tonic-gate * Assemble usage values into group. 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 8550Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++) 8560Sstevel@tonic-gate if (BT_TEST(mask, res)) 8574584Srh87107 count += exacct_attach_proc_item(pu, record, res); 8580Sstevel@tonic-gate if (count == 0) { 8590Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 8600Sstevel@tonic-gate record = NULL; 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate return (record); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate /* 8660Sstevel@tonic-gate * The following two routines assume that process's p_lock is held or 8670Sstevel@tonic-gate * exacct_commit_proc has been called from exit() when all lwps are stopped. 8680Sstevel@tonic-gate */ 8690Sstevel@tonic-gate static void 8700Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu) 8710Sstevel@tonic-gate { 8720Sstevel@tonic-gate kthread_t *t; 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 8750Sstevel@tonic-gate if ((t = p->p_tlist) == NULL) 8760Sstevel@tonic-gate return; 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate do { 8790Sstevel@tonic-gate pu->pu_minflt += t->t_lwp->lwp_ru.minflt; 8800Sstevel@tonic-gate pu->pu_majflt += t->t_lwp->lwp_ru.majflt; 8810Sstevel@tonic-gate pu->pu_sndmsg += t->t_lwp->lwp_ru.msgsnd; 8820Sstevel@tonic-gate pu->pu_rcvmsg += t->t_lwp->lwp_ru.msgrcv; 8830Sstevel@tonic-gate pu->pu_ioch += t->t_lwp->lwp_ru.ioch; 8840Sstevel@tonic-gate pu->pu_iblk += t->t_lwp->lwp_ru.inblock; 8850Sstevel@tonic-gate pu->pu_oblk += t->t_lwp->lwp_ru.oublock; 8860Sstevel@tonic-gate pu->pu_vcsw += t->t_lwp->lwp_ru.nvcsw; 8870Sstevel@tonic-gate pu->pu_icsw += t->t_lwp->lwp_ru.nivcsw; 8880Sstevel@tonic-gate pu->pu_nsig += t->t_lwp->lwp_ru.nsignals; 8890Sstevel@tonic-gate pu->pu_nswp += t->t_lwp->lwp_ru.nswap; 8900Sstevel@tonic-gate pu->pu_nscl += t->t_lwp->lwp_ru.sysc; 8910Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate static void 8950Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu) 8960Sstevel@tonic-gate { 8970Sstevel@tonic-gate pu->pu_minflt = p->p_ru.minflt; 8980Sstevel@tonic-gate pu->pu_majflt = p->p_ru.majflt; 8990Sstevel@tonic-gate pu->pu_sndmsg = p->p_ru.msgsnd; 9000Sstevel@tonic-gate pu->pu_rcvmsg = p->p_ru.msgrcv; 9010Sstevel@tonic-gate pu->pu_ioch = p->p_ru.ioch; 9020Sstevel@tonic-gate pu->pu_iblk = p->p_ru.inblock; 9030Sstevel@tonic-gate pu->pu_oblk = p->p_ru.oublock; 9040Sstevel@tonic-gate pu->pu_vcsw = p->p_ru.nvcsw; 9050Sstevel@tonic-gate pu->pu_icsw = p->p_ru.nivcsw; 9060Sstevel@tonic-gate pu->pu_nsig = p->p_ru.nsignals; 9070Sstevel@tonic-gate pu->pu_nswp = p->p_ru.nswap; 9080Sstevel@tonic-gate pu->pu_nscl = p->p_ru.sysc; 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate void 9120Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask, 9130Sstevel@tonic-gate int flag, int wstat) 9140Sstevel@tonic-gate { 9150Sstevel@tonic-gate timestruc_t ts, ts_run; 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate /* 9200Sstevel@tonic-gate * Convert CPU and execution times to sec/nsec format. 9210Sstevel@tonic-gate */ 9220Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_CPU)) { 9230Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_USER), &ts); 9240Sstevel@tonic-gate pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec; 9250Sstevel@tonic-gate pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9260Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts); 9270Sstevel@tonic-gate pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec; 9280Sstevel@tonic-gate pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_TIME)) { 9310Sstevel@tonic-gate gethrestime(&ts); 9320Sstevel@tonic-gate pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 9330Sstevel@tonic-gate pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9340Sstevel@tonic-gate hrt2ts(gethrtime() - p->p_mstart, &ts_run); 9350Sstevel@tonic-gate ts.tv_sec -= ts_run.tv_sec; 9360Sstevel@tonic-gate ts.tv_nsec -= ts_run.tv_nsec; 9370Sstevel@tonic-gate if (ts.tv_nsec < 0) { 9380Sstevel@tonic-gate ts.tv_sec--; 9390Sstevel@tonic-gate if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) { 9400Sstevel@tonic-gate ts.tv_sec++; 9410Sstevel@tonic-gate ts.tv_nsec -= NANOSEC; 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec; 9450Sstevel@tonic-gate pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate pu->pu_pid = p->p_pidp->pid_id; 9490Sstevel@tonic-gate pu->pu_acflag = p->p_user.u_acflag; 9500Sstevel@tonic-gate pu->pu_projid = p->p_task->tk_proj->kpj_id; 9510Sstevel@tonic-gate pu->pu_taskid = p->p_task->tk_tkid; 9520Sstevel@tonic-gate pu->pu_major = getmajor(p->p_sessp->s_dev); 9530Sstevel@tonic-gate pu->pu_minor = getminor(p->p_sessp->s_dev); 9540Sstevel@tonic-gate pu->pu_ancpid = p->p_ancpid; 9550Sstevel@tonic-gate pu->pu_wstat = wstat; 9560Sstevel@tonic-gate /* 9570Sstevel@tonic-gate * Compute average RSS in K. The denominator is the number of 9580Sstevel@tonic-gate * samples: the number of clock ticks plus the initial value. 9590Sstevel@tonic-gate */ 9600Sstevel@tonic-gate pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) * 9610Sstevel@tonic-gate (PAGESIZE / 1024); 9620Sstevel@tonic-gate pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024); 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate mutex_enter(&p->p_crlock); 9650Sstevel@tonic-gate pu->pu_ruid = crgetruid(p->p_cred); 9660Sstevel@tonic-gate pu->pu_rgid = crgetrgid(p->p_cred); 9670Sstevel@tonic-gate mutex_exit(&p->p_crlock); 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1); 9700Sstevel@tonic-gate bcopy(p->p_zone->zone_name, pu->pu_zonename, 9710Sstevel@tonic-gate strlen(p->p_zone->zone_name) + 1); 9720Sstevel@tonic-gate bcopy(p->p_zone->zone_nodename, pu->pu_nodename, 9730Sstevel@tonic-gate strlen(p->p_zone->zone_nodename) + 1); 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * Calculate microstate accounting data for a process that is still 9770Sstevel@tonic-gate * running. Presently, we explicitly collect all of the LWP usage into 9780Sstevel@tonic-gate * the proc usage structure here. 9790Sstevel@tonic-gate */ 9800Sstevel@tonic-gate if (flag & EW_PARTIAL) 9810Sstevel@tonic-gate exacct_calculate_proc_mstate(p, pu); 9820Sstevel@tonic-gate if (flag & EW_FINAL) 9830Sstevel@tonic-gate exacct_copy_proc_mstate(p, pu); 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate /* 9870Sstevel@tonic-gate * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void 9880Sstevel@tonic-gate * *, size_t, size_t *), void *, size_t, size_t *) 9890Sstevel@tonic-gate * 9900Sstevel@tonic-gate * Overview 9910Sstevel@tonic-gate * Assemble record with miscellaneous accounting information about the process 9920Sstevel@tonic-gate * and execute the callback on it. It is the callback's job to set "actual" to 9930Sstevel@tonic-gate * the size of record. 9940Sstevel@tonic-gate * 9950Sstevel@tonic-gate * Return values 9960Sstevel@tonic-gate * The result of the callback function, unless the extended process accounting 9970Sstevel@tonic-gate * feature is not active, in which case ENOTACTIVE is returned. 9980Sstevel@tonic-gate * 9990Sstevel@tonic-gate * Caller's context 10000Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 10010Sstevel@tonic-gate */ 10020Sstevel@tonic-gate int 10030Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu, 10040Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 10050Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 10060Sstevel@tonic-gate { 10070Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 10080Sstevel@tonic-gate ea_object_t *proc_record; 10090Sstevel@tonic-gate ea_catalog_t record_type; 10100Sstevel@tonic-gate void *buf; 10110Sstevel@tonic-gate size_t bufsize; 10120Sstevel@tonic-gate int ret; 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL); 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 10170Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF) { 10180Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10190Sstevel@tonic-gate return (ENOTACTIVE); 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 10220Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate switch (flag) { 10250Sstevel@tonic-gate case EW_FINAL: 10260Sstevel@tonic-gate record_type = EXD_GROUP_PROC; 10270Sstevel@tonic-gate break; 10280Sstevel@tonic-gate case EW_PARTIAL: 10290Sstevel@tonic-gate record_type = EXD_GROUP_PROC_PARTIAL; 10300Sstevel@tonic-gate break; 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate proc_record = exacct_assemble_proc_record(pu, mask, record_type); 10340Sstevel@tonic-gate if (proc_record == NULL) 10350Sstevel@tonic-gate return (0); 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate /* 10380Sstevel@tonic-gate * Pack object into buffer and pass to callback. 10390Sstevel@tonic-gate */ 10400Sstevel@tonic-gate bufsize = ea_pack_object(proc_record, NULL, 0); 10410Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 10420Sstevel@tonic-gate (void) ea_pack_object(proc_record, buf, bufsize); 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual); 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate /* 10470Sstevel@tonic-gate * Free all previously allocations. 10480Sstevel@tonic-gate */ 10490Sstevel@tonic-gate kmem_free(buf, bufsize); 10500Sstevel@tonic-gate ea_free_object(proc_record, EUP_ALLOC); 10510Sstevel@tonic-gate return (ret); 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate /* 10550Sstevel@tonic-gate * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t, 10560Sstevel@tonic-gate * size_t *) 10570Sstevel@tonic-gate * 10580Sstevel@tonic-gate * Overview 10590Sstevel@tonic-gate * exacct_commit_callback() writes the indicated buffer to the indicated 10600Sstevel@tonic-gate * extended accounting file. 10610Sstevel@tonic-gate * 10620Sstevel@tonic-gate * Return values 10630Sstevel@tonic-gate * The result of the write operation is returned. "actual" is updated to 10640Sstevel@tonic-gate * contain the number of bytes actually written. 10650Sstevel@tonic-gate * 10660Sstevel@tonic-gate * Caller's context 10670Sstevel@tonic-gate * Suitable for a vn_rdwr() operation. 10680Sstevel@tonic-gate */ 10690Sstevel@tonic-gate /*ARGSUSED*/ 10700Sstevel@tonic-gate int 10710Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize, 10720Sstevel@tonic-gate void *buf, size_t bufsize, size_t *actual) 10730Sstevel@tonic-gate { 10740Sstevel@tonic-gate int error = 0; 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate *actual = 0; 10770Sstevel@tonic-gate if ((error = exacct_vn_write(info, buf, bufsize)) == 0) 10780Sstevel@tonic-gate *actual = bufsize; 10790Sstevel@tonic-gate return (error); 10800Sstevel@tonic-gate } 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate static void 10830Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat) 10840Sstevel@tonic-gate { 10850Sstevel@tonic-gate size_t size; 10860Sstevel@tonic-gate proc_usage_t *pu; 10870Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 10900Sstevel@tonic-gate if (ac_proc->ac_state == AC_ON) { 10910Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 10920Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10930Sstevel@tonic-gate } else { 10940Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10950Sstevel@tonic-gate return; 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate mutex_enter(&p->p_lock); 10990Sstevel@tonic-gate size = strlen(p->p_user.u_comm) + 1; 11000Sstevel@tonic-gate mutex_exit(&p->p_lock); 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP); 11030Sstevel@tonic-gate pu->pu_command = kmem_alloc(size, KM_SLEEP); 11040Sstevel@tonic-gate mutex_enter(&p->p_lock); 11050Sstevel@tonic-gate exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat); 11060Sstevel@tonic-gate mutex_exit(&p->p_lock); 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate (void) exacct_assemble_proc_usage(ac_proc, pu, 11090Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate kmem_free(pu->pu_command, strlen(pu->pu_command) + 1); 11120Sstevel@tonic-gate kmem_free(pu, sizeof (proc_usage_t)); 11130Sstevel@tonic-gate } 11144584Srh87107 11150Sstevel@tonic-gate /* 11160Sstevel@tonic-gate * void exacct_commit_proc(proc_t *, int) 11170Sstevel@tonic-gate * 11180Sstevel@tonic-gate * Overview 11190Sstevel@tonic-gate * exacct_commit_proc() calculates the final usage for a process, updating the 11200Sstevel@tonic-gate * task usage if task accounting is active, and writing a process record if 11210Sstevel@tonic-gate * process accounting is active. exacct_commit_proc() is intended for being 11220Sstevel@tonic-gate * called from proc_exit(). 11230Sstevel@tonic-gate * 11240Sstevel@tonic-gate * Return values 11250Sstevel@tonic-gate * None. 11260Sstevel@tonic-gate * 11270Sstevel@tonic-gate * Caller's context 11280Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. p_lock must not be held at entry. 11290Sstevel@tonic-gate */ 11300Sstevel@tonic-gate void 11310Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat) 11320Sstevel@tonic-gate { 11330Sstevel@tonic-gate zone_t *zone = p->p_zone; 11340Sstevel@tonic-gate struct exacct_globals *acg, *gacg = NULL; 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 11370Sstevel@tonic-gate /* 11380Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 11390Sstevel@tonic-gate */ 11400Sstevel@tonic-gate return; 11410Sstevel@tonic-gate } 11420Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 11434584Srh87107 exacct_do_commit_proc(&acg->ac_proc, p, wstat); 11444584Srh87107 if (zone != global_zone) { 11450Sstevel@tonic-gate gacg = zone_getspecific(exacct_zone_key, global_zone); 11464584Srh87107 exacct_do_commit_proc(&gacg->ac_proc, p, wstat); 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate } 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate static int 11510Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res) 11520Sstevel@tonic-gate { 11530Sstevel@tonic-gate int attached = 1; 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate switch (res) { 11560Sstevel@tonic-gate case AC_FLOW_SADDR: 11570Sstevel@tonic-gate if (fu->fu_isv4) { 11580Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr[3], 11590Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR); 11600Sstevel@tonic-gate } else { 11610Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr, 11620Sstevel@tonic-gate sizeof (fu->fu_saddr), EXT_RAW | 11630Sstevel@tonic-gate EXD_FLOW_V6SADDR); 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate break; 11660Sstevel@tonic-gate case AC_FLOW_DADDR: 11670Sstevel@tonic-gate if (fu->fu_isv4) { 11680Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr[3], 11690Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR); 11700Sstevel@tonic-gate } else { 11710Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr, 11720Sstevel@tonic-gate sizeof (fu->fu_daddr), EXT_RAW | 11730Sstevel@tonic-gate EXD_FLOW_V6DADDR); 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate break; 11760Sstevel@tonic-gate case AC_FLOW_SPORT: 11770Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_sport, 11780Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT); 11790Sstevel@tonic-gate break; 11800Sstevel@tonic-gate case AC_FLOW_DPORT: 11810Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dport, 11820Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT); 11830Sstevel@tonic-gate break; 11840Sstevel@tonic-gate case AC_FLOW_PROTOCOL: 11850Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_protocol, 11860Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL); 11870Sstevel@tonic-gate break; 11880Sstevel@tonic-gate case AC_FLOW_DSFIELD: 11890Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dsfield, 11900Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD); 11910Sstevel@tonic-gate break; 11920Sstevel@tonic-gate case AC_FLOW_CTIME: 11930Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_ctime, 11940Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME); 11950Sstevel@tonic-gate break; 11960Sstevel@tonic-gate case AC_FLOW_LSEEN: 11970Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_lseen, 11980Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN); 11990Sstevel@tonic-gate break; 12000Sstevel@tonic-gate case AC_FLOW_NBYTES: 12010Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_nbytes, 12020Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES); 12030Sstevel@tonic-gate break; 12040Sstevel@tonic-gate case AC_FLOW_NPKTS: 12050Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_npackets, 12060Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS); 12070Sstevel@tonic-gate break; 12080Sstevel@tonic-gate case AC_FLOW_PROJID: 12090Sstevel@tonic-gate if (fu->fu_projid >= 0) { 12100Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_projid, 12110Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID); 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate break; 12140Sstevel@tonic-gate case AC_FLOW_UID: 12150Sstevel@tonic-gate if (fu->fu_userid >= 0) { 12160Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_userid, 12170Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID); 12180Sstevel@tonic-gate } 12190Sstevel@tonic-gate break; 12200Sstevel@tonic-gate case AC_FLOW_ANAME: 12210Sstevel@tonic-gate (void) ea_attach_item(record, fu->fu_aname, 12220Sstevel@tonic-gate strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME); 12230Sstevel@tonic-gate break; 12240Sstevel@tonic-gate default: 12250Sstevel@tonic-gate attached = 0; 12260Sstevel@tonic-gate } 12270Sstevel@tonic-gate return (attached); 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate static ea_object_t * 12310Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask, 12320Sstevel@tonic-gate ea_catalog_t record_type) 12330Sstevel@tonic-gate { 12340Sstevel@tonic-gate int res, count; 12350Sstevel@tonic-gate ea_object_t *record; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate /* 12380Sstevel@tonic-gate * Assemble usage values into group. 12390Sstevel@tonic-gate */ 12400Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 12410Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++) 12420Sstevel@tonic-gate if (BT_TEST(mask, res)) 12430Sstevel@tonic-gate count += exacct_attach_flow_item(fu, record, res); 12440Sstevel@tonic-gate if (count == 0) { 12450Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 12460Sstevel@tonic-gate record = NULL; 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate return (record); 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate int 12520Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu, 12530Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 12540Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual) 12550Sstevel@tonic-gate { 12560Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 12570Sstevel@tonic-gate ea_object_t *flow_usage; 12580Sstevel@tonic-gate ea_catalog_t record_type; 12590Sstevel@tonic-gate void *buf; 12600Sstevel@tonic-gate size_t bufsize; 12610Sstevel@tonic-gate int ret; 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 12640Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 12650Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 12660Sstevel@tonic-gate return (ENOTACTIVE); 12670Sstevel@tonic-gate } 12680Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 12690Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate record_type = EXD_GROUP_FLOW; 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate flow_usage = exacct_assemble_flow_record(fu, mask, record_type); 12740Sstevel@tonic-gate if (flow_usage == NULL) { 12750Sstevel@tonic-gate return (0); 12760Sstevel@tonic-gate } 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate /* 12790Sstevel@tonic-gate * Pack object into buffer and pass to callback. 12800Sstevel@tonic-gate */ 12810Sstevel@tonic-gate bufsize = ea_pack_object(flow_usage, NULL, 0); 12820Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_NOSLEEP); 12830Sstevel@tonic-gate if (buf == NULL) { 12840Sstevel@tonic-gate return (ENOMEM); 12850Sstevel@tonic-gate } 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate (void) ea_pack_object(flow_usage, buf, bufsize); 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual); 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate /* 12920Sstevel@tonic-gate * Free all previously allocations. 12930Sstevel@tonic-gate */ 12940Sstevel@tonic-gate kmem_free(buf, bufsize); 12950Sstevel@tonic-gate ea_free_object(flow_usage, EUP_ALLOC); 12960Sstevel@tonic-gate return (ret); 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate void 13000Sstevel@tonic-gate exacct_commit_flow(void *arg) 13010Sstevel@tonic-gate { 13020Sstevel@tonic-gate flow_usage_t *f = (flow_usage_t *)arg; 13030Sstevel@tonic-gate size_t size; 13040Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 13050Sstevel@tonic-gate struct exacct_globals *acg; 13060Sstevel@tonic-gate ac_info_t *ac_flow; 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 13090Sstevel@tonic-gate /* 13100Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 13110Sstevel@tonic-gate */ 13120Sstevel@tonic-gate return; 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate /* 13160Sstevel@tonic-gate * Even though each zone nominally has its own flow accounting settings 13170Sstevel@tonic-gate * (ac_flow), these are only maintained by and for the global zone. 13180Sstevel@tonic-gate * 13190Sstevel@tonic-gate * If this were to change in the future, this function should grow a 13200Sstevel@tonic-gate * second zoneid (or zone) argument, and use the corresponding zone's 13210Sstevel@tonic-gate * settings rather than always using those of the global zone. 13220Sstevel@tonic-gate */ 13230Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 13240Sstevel@tonic-gate ac_flow = &acg->ac_flow; 13250Sstevel@tonic-gate 13260Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 13270Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 13280Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 13290Sstevel@tonic-gate return; 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 13320Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate (void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback, 13350Sstevel@tonic-gate NULL, 0, &size); 13360Sstevel@tonic-gate } 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate /* 13390Sstevel@tonic-gate * int exacct_tag_task(task_t *, void *, size_t, int) 13400Sstevel@tonic-gate * 13410Sstevel@tonic-gate * Overview 13420Sstevel@tonic-gate * exacct_tag_task() provides the exacct record construction and writing 13430Sstevel@tonic-gate * support required by putacct(2) for task entities. 13440Sstevel@tonic-gate * 13450Sstevel@tonic-gate * Return values 13460Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 13470Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 13480Sstevel@tonic-gate * 13490Sstevel@tonic-gate * Caller's context 13500Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 13510Sstevel@tonic-gate */ 13520Sstevel@tonic-gate int 13530Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz, 13540Sstevel@tonic-gate int flags) 13550Sstevel@tonic-gate { 13560Sstevel@tonic-gate int error = 0; 13570Sstevel@tonic-gate void *buf; 13580Sstevel@tonic-gate size_t bufsize; 13590Sstevel@tonic-gate ea_catalog_t cat; 13600Sstevel@tonic-gate ea_object_t *tag; 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 13630Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) { 13640Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 13650Sstevel@tonic-gate return (ENOTACTIVE); 13660Sstevel@tonic-gate } 13670Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG); 13700Sstevel@tonic-gate (void) ea_attach_item(tag, &tk->tk_tkid, 0, 13710Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 13720Sstevel@tonic-gate (void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0, 13730Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 13740Sstevel@tonic-gate if (flags == EP_RAW) 13750Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG; 13760Sstevel@tonic-gate else 13770Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG; 13780Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 13810Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 13820Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 13830Sstevel@tonic-gate error = exacct_vn_write(ac_task, buf, bufsize); 13840Sstevel@tonic-gate kmem_free(buf, bufsize); 13850Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 13860Sstevel@tonic-gate return (error); 13870Sstevel@tonic-gate } 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate /* 13900Sstevel@tonic-gate * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *) 13910Sstevel@tonic-gate * 13920Sstevel@tonic-gate * Overview 13930Sstevel@tonic-gate * exacct_tag_proc() provides the exacct record construction and writing 13940Sstevel@tonic-gate * support required by putacct(2) for processes. 13950Sstevel@tonic-gate * 13960Sstevel@tonic-gate * Return values 13970Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 13980Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 13990Sstevel@tonic-gate * 14000Sstevel@tonic-gate * Caller's context 14010Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 14020Sstevel@tonic-gate */ 14030Sstevel@tonic-gate int 14040Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf, 14050Sstevel@tonic-gate size_t ubufsz, int flags, const char *hostname) 14060Sstevel@tonic-gate { 14070Sstevel@tonic-gate int error = 0; 14080Sstevel@tonic-gate void *buf; 14090Sstevel@tonic-gate size_t bufsize; 14100Sstevel@tonic-gate ea_catalog_t cat; 14110Sstevel@tonic-gate ea_object_t *tag; 14120Sstevel@tonic-gate 14130Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 14140Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) { 14150Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 14160Sstevel@tonic-gate return (ENOTACTIVE); 14170Sstevel@tonic-gate } 14180Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 14190Sstevel@tonic-gate 14200Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG); 14210Sstevel@tonic-gate (void) ea_attach_item(tag, &pid, sizeof (uint32_t), 14220Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID); 14230Sstevel@tonic-gate (void) ea_attach_item(tag, &tkid, 0, 14240Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 14250Sstevel@tonic-gate (void) ea_attach_item(tag, (void *)hostname, 0, 14260Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 14270Sstevel@tonic-gate if (flags == EP_RAW) 14280Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG; 14290Sstevel@tonic-gate else 14300Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG; 14310Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 14340Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 14350Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 14360Sstevel@tonic-gate error = exacct_vn_write(ac_proc, buf, bufsize); 14370Sstevel@tonic-gate kmem_free(buf, bufsize); 14380Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 14390Sstevel@tonic-gate return (error); 14400Sstevel@tonic-gate } 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate /* 14430Sstevel@tonic-gate * void exacct_init(void) 14440Sstevel@tonic-gate * 14450Sstevel@tonic-gate * Overview 14460Sstevel@tonic-gate * Initialized the extended accounting subsystem. 14470Sstevel@tonic-gate * 14480Sstevel@tonic-gate * Return values 14490Sstevel@tonic-gate * None. 14500Sstevel@tonic-gate * 14510Sstevel@tonic-gate * Caller's context 14520Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 14530Sstevel@tonic-gate */ 14540Sstevel@tonic-gate void 14550Sstevel@tonic-gate exacct_init() 14560Sstevel@tonic-gate { 14570Sstevel@tonic-gate exacct_queue = system_taskq; 14580Sstevel@tonic-gate exacct_object_cache = kmem_cache_create("exacct_object_cache", 14590Sstevel@tonic-gate sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 14600Sstevel@tonic-gate } 14614584Srh87107 14624584Srh87107 /* 14634584Srh87107 * exacct_snapshot_proc_mstate() copies a process's microstate accounting data 14644584Srh87107 * and resource usage counters into a given task_usage_t. It differs from 14654584Srh87107 * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t, 14664584Srh87107 * b) p_lock will have been acquired earlier in the call path and c) we 14674584Srh87107 * are here including the process's user and system times. 14684584Srh87107 */ 14694584Srh87107 static void 14704584Srh87107 exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu) 14714584Srh87107 { 14724584Srh87107 tu->tu_utime = mstate_aggr_state(p, LMS_USER); 14734584Srh87107 tu->tu_stime = mstate_aggr_state(p, LMS_SYSTEM); 14744584Srh87107 tu->tu_minflt = p->p_ru.minflt; 14754584Srh87107 tu->tu_majflt = p->p_ru.majflt; 14764584Srh87107 tu->tu_sndmsg = p->p_ru.msgsnd; 14774584Srh87107 tu->tu_rcvmsg = p->p_ru.msgrcv; 14784584Srh87107 tu->tu_ioch = p->p_ru.ioch; 14794584Srh87107 tu->tu_iblk = p->p_ru.inblock; 14804584Srh87107 tu->tu_oblk = p->p_ru.oublock; 14814584Srh87107 tu->tu_vcsw = p->p_ru.nvcsw; 14824584Srh87107 tu->tu_icsw = p->p_ru.nivcsw; 14834584Srh87107 tu->tu_nsig = p->p_ru.nsignals; 14844584Srh87107 tu->tu_nswp = p->p_ru.nswap; 14854584Srh87107 tu->tu_nscl = p->p_ru.sysc; 14864584Srh87107 } 14874584Srh87107 14884584Srh87107 /* 14894584Srh87107 * void exacct_move_mstate(proc_t *, task_t *, task_t *) 14904584Srh87107 * 14914584Srh87107 * Overview 14924584Srh87107 * exacct_move_mstate() is called by task_change() and accounts for 14934584Srh87107 * a process's resource usage when it is moved from one task to another. 14944584Srh87107 * 14954584Srh87107 * The process's usage at this point is recorded in the new task so 14964584Srh87107 * that it can be excluded from the calculation of resources consumed 14974584Srh87107 * by that task. 14984584Srh87107 * 14994584Srh87107 * The resource usage inherited by the new task is also added to the 15004584Srh87107 * aggregate maintained by the old task for processes that have exited. 15014584Srh87107 * 15024584Srh87107 * Return values 15034584Srh87107 * None. 15044584Srh87107 * 15054584Srh87107 * Caller's context 15064584Srh87107 * pidlock and p_lock held across exacct_move_mstate(). 15074584Srh87107 */ 15084584Srh87107 void 15094584Srh87107 exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk) 15104584Srh87107 { 15114584Srh87107 task_usage_t tu; 15124584Srh87107 15134584Srh87107 /* Take a snapshot of this process's mstate and RU counters */ 15144584Srh87107 exacct_snapshot_proc_mstate(p, &tu); 15154584Srh87107 15164584Srh87107 /* 15174584Srh87107 * Use the snapshot to increment the aggregate usage of the old 15184584Srh87107 * task, and the inherited usage of the new one. 15194584Srh87107 */ 15204584Srh87107 mutex_enter(&oldtk->tk_usage_lock); 15214584Srh87107 exacct_add_task_mstate(oldtk->tk_usage, &tu); 15224584Srh87107 mutex_exit(&oldtk->tk_usage_lock); 15234584Srh87107 mutex_enter(&newtk->tk_usage_lock); 15244584Srh87107 exacct_add_task_mstate(newtk->tk_inherited, &tu); 15254584Srh87107 mutex_exit(&newtk->tk_usage_lock); 15264584Srh87107 } 1527