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