17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57eceb558Srh87107 * Common Development and Distribution License (the "License"). 67eceb558Srh87107 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 227eceb558Srh87107 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/exacct.h> 297c478bd9Sstevel@tonic-gate #include <sys/exacct_catalog.h> 307c478bd9Sstevel@tonic-gate #include <sys/disp.h> 317c478bd9Sstevel@tonic-gate #include <sys/task.h> 327c478bd9Sstevel@tonic-gate #include <sys/proc.h> 337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/project.h> 367c478bd9Sstevel@tonic-gate #include <sys/systm.h> 377c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 387c478bd9Sstevel@tonic-gate #include <sys/file.h> 397c478bd9Sstevel@tonic-gate #include <sys/acctctl.h> 407c478bd9Sstevel@tonic-gate #include <sys/time.h> 417c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 427c478bd9Sstevel@tonic-gate #include <sys/session.h> 437c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 447c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 457c478bd9Sstevel@tonic-gate #include <sys/msacct.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* 487c478bd9Sstevel@tonic-gate * exacct usage and recording routines 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * wracct(2), getacct(2), and the records written at process or task 517c478bd9Sstevel@tonic-gate * termination are constructed using the exacct_assemble_[task,proc]_usage() 527c478bd9Sstevel@tonic-gate * functions, which take a callback that takes the appropriate action on 537c478bd9Sstevel@tonic-gate * the packed exacct record for the task or process. For the process-related 547c478bd9Sstevel@tonic-gate * actions, we partition the routines such that the data collecting component 557c478bd9Sstevel@tonic-gate * can be performed while holding p_lock, and all sleeping or blocking 567c478bd9Sstevel@tonic-gate * operations can be performed without acquiring p_lock. 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * putacct(2), which allows an application to construct a customized record 597c478bd9Sstevel@tonic-gate * associated with an existing process or task, has its own entry points: 607c478bd9Sstevel@tonic-gate * exacct_tag_task() and exacct_tag_proc(). 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate taskq_t *exacct_queue; 647c478bd9Sstevel@tonic-gate kmem_cache_t *exacct_object_cache; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION; 697c478bd9Sstevel@tonic-gate static const char exacct_header[] = "exacct"; 707c478bd9Sstevel@tonic-gate static const char exacct_creator[] = "SunOS"; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate ea_object_t * 737c478bd9Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz) 747c478bd9Sstevel@tonic-gate { 757c478bd9Sstevel@tonic-gate ea_object_t *item; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 787c478bd9Sstevel@tonic-gate bzero(item, sizeof (ea_object_t)); 797c478bd9Sstevel@tonic-gate (void) ea_set_item(item, catalog, buf, bufsz); 807c478bd9Sstevel@tonic-gate return (item); 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate ea_object_t * 847c478bd9Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog) 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate ea_object_t *group; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 897c478bd9Sstevel@tonic-gate bzero(group, sizeof (ea_object_t)); 907c478bd9Sstevel@tonic-gate (void) ea_set_group(group, catalog); 917c478bd9Sstevel@tonic-gate return (group); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate ea_object_t * 957c478bd9Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog) 967c478bd9Sstevel@tonic-gate { 977c478bd9Sstevel@tonic-gate ea_object_t *item; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate item = ea_alloc_item(catalog, buf, bufsz); 1007c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(grp, item); 1017c478bd9Sstevel@tonic-gate return (item); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 1057eceb558Srh87107 * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract 1067eceb558Srh87107 * microstate accounting data and resource usage counters from one task_usage_t 1077eceb558Srh87107 * from those supplied in another. These functions do not operate on *all* 1087eceb558Srh87107 * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make 1097eceb558Srh87107 * sense. 1107eceb558Srh87107 */ 1117eceb558Srh87107 static void 1127eceb558Srh87107 exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta) 1137eceb558Srh87107 { 1147eceb558Srh87107 tu->tu_utime += delta->tu_utime; 1157eceb558Srh87107 tu->tu_stime += delta->tu_stime; 1167eceb558Srh87107 tu->tu_minflt += delta->tu_minflt; 1177eceb558Srh87107 tu->tu_majflt += delta->tu_majflt; 1187eceb558Srh87107 tu->tu_sndmsg += delta->tu_sndmsg; 1197eceb558Srh87107 tu->tu_rcvmsg += delta->tu_rcvmsg; 1207eceb558Srh87107 tu->tu_ioch += delta->tu_ioch; 1217eceb558Srh87107 tu->tu_iblk += delta->tu_iblk; 1227eceb558Srh87107 tu->tu_oblk += delta->tu_oblk; 1237eceb558Srh87107 tu->tu_vcsw += delta->tu_vcsw; 1247eceb558Srh87107 tu->tu_icsw += delta->tu_icsw; 1257eceb558Srh87107 tu->tu_nsig += delta->tu_nsig; 1267eceb558Srh87107 tu->tu_nswp += delta->tu_nswp; 1277eceb558Srh87107 tu->tu_nscl += delta->tu_nscl; 1287eceb558Srh87107 } 1297eceb558Srh87107 1307eceb558Srh87107 /* 1317eceb558Srh87107 * See the comments for exacct_add_task_mstate(), above. 1327eceb558Srh87107 */ 1337eceb558Srh87107 static void 1347eceb558Srh87107 exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta) 1357eceb558Srh87107 { 1367eceb558Srh87107 tu->tu_utime -= delta->tu_utime; 1377eceb558Srh87107 tu->tu_stime -= delta->tu_stime; 1387eceb558Srh87107 tu->tu_minflt -= delta->tu_minflt; 1397eceb558Srh87107 tu->tu_majflt -= delta->tu_majflt; 1407eceb558Srh87107 tu->tu_sndmsg -= delta->tu_sndmsg; 1417eceb558Srh87107 tu->tu_rcvmsg -= delta->tu_rcvmsg; 1427eceb558Srh87107 tu->tu_ioch -= delta->tu_ioch; 1437eceb558Srh87107 tu->tu_iblk -= delta->tu_iblk; 1447eceb558Srh87107 tu->tu_oblk -= delta->tu_oblk; 1457eceb558Srh87107 tu->tu_vcsw -= delta->tu_vcsw; 1467eceb558Srh87107 tu->tu_icsw -= delta->tu_icsw; 1477eceb558Srh87107 tu->tu_nsig -= delta->tu_nsig; 1487eceb558Srh87107 tu->tu_nswp -= delta->tu_nswp; 1497eceb558Srh87107 tu->tu_nscl -= delta->tu_nscl; 1507eceb558Srh87107 } 1517eceb558Srh87107 1527eceb558Srh87107 /* 1537c478bd9Sstevel@tonic-gate * exacct_vn_write() is a vn_rdwr wrapper that protects us from corrupting the 1547c478bd9Sstevel@tonic-gate * accounting file in case of an I/O or filesystem error. acctctl() prevents 1557c478bd9Sstevel@tonic-gate * the two accounting vnodes from being equal, and the appropriate ac_lock is 1567c478bd9Sstevel@tonic-gate * held across the call, so we're single threaded through this code for each 1577c478bd9Sstevel@tonic-gate * file. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate static int 1607c478bd9Sstevel@tonic-gate exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate int error = 0; 1637c478bd9Sstevel@tonic-gate ssize_t resid; 1647c478bd9Sstevel@tonic-gate struct vattr va; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate if (info == NULL) 1677c478bd9Sstevel@tonic-gate return (0); 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate mutex_enter(&info->ac_lock); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Don't do anything unless accounting file is set. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate if (info->ac_vnode == NULL) { 1757c478bd9Sstevel@tonic-gate mutex_exit(&info->ac_lock); 1767c478bd9Sstevel@tonic-gate return (0); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Save the size. If vn_rdwr fails, reset the size to avoid corrupting 1817c478bd9Sstevel@tonic-gate * the present accounting file. 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 184*da6c28aaSamw error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1857c478bd9Sstevel@tonic-gate if (error == 0) { 1867c478bd9Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf, 1877c478bd9Sstevel@tonic-gate bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T, 1887c478bd9Sstevel@tonic-gate kcred, &resid); 1897c478bd9Sstevel@tonic-gate if (error) { 1907c478bd9Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1917c478bd9Sstevel@tonic-gate } else if (resid != 0) { 1927c478bd9Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1937c478bd9Sstevel@tonic-gate error = ENOSPC; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate mutex_exit(&info->ac_lock); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate return (error); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * void *exacct_create_header(size_t *) 2037c478bd9Sstevel@tonic-gate * 2047c478bd9Sstevel@tonic-gate * Overview 2057c478bd9Sstevel@tonic-gate * exacct_create_header() constructs an exacct file header identifying the 2067c478bd9Sstevel@tonic-gate * accounting file as the output of the kernel. exacct_create_header() and 2077c478bd9Sstevel@tonic-gate * the static write_header() and verify_header() routines in libexacct must 2087c478bd9Sstevel@tonic-gate * remain synchronized. 2097c478bd9Sstevel@tonic-gate * 2107c478bd9Sstevel@tonic-gate * Return values 2117c478bd9Sstevel@tonic-gate * A pointer to a packed exacct buffer containing the appropriate header is 2127c478bd9Sstevel@tonic-gate * returned; the size of the buffer is placed in the location indicated by 2137c478bd9Sstevel@tonic-gate * sizep. 2147c478bd9Sstevel@tonic-gate * 2157c478bd9Sstevel@tonic-gate * Caller's context 2167c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate void * 2197c478bd9Sstevel@tonic-gate exacct_create_header(size_t *sizep) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate ea_object_t *hdr_grp; 2227c478bd9Sstevel@tonic-gate uint32_t bskip; 2237c478bd9Sstevel@tonic-gate void *buf; 2247c478bd9Sstevel@tonic-gate size_t bufsize; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER); 2277c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0, 2287c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_VERSION); 2297c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_header, 0, 2307c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_FILETYPE); 2317c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0, 2327c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_CREATOR); 2337c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, uts_nodename(), 0, 2347c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(hdr_grp, NULL, 0); 2377c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 2387c478bd9Sstevel@tonic-gate (void) ea_pack_object(hdr_grp, buf, bufsize); 2397c478bd9Sstevel@tonic-gate ea_free_object(hdr_grp, EUP_ALLOC); 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* 2427c478bd9Sstevel@tonic-gate * To prevent reading the header when reading the file backwards, 2437c478bd9Sstevel@tonic-gate * set the large backskip of the header group to 0 (last 4 bytes). 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate bskip = 0; 2467c478bd9Sstevel@tonic-gate exacct_order32(&bskip); 2477c478bd9Sstevel@tonic-gate bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip), 2487c478bd9Sstevel@tonic-gate sizeof (bskip)); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate *sizep = bufsize; 2517c478bd9Sstevel@tonic-gate return (buf); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* 2557c478bd9Sstevel@tonic-gate * int exacct_write_header(ac_info_t *, void *, size_t) 2567c478bd9Sstevel@tonic-gate * 2577c478bd9Sstevel@tonic-gate * Overview 2587c478bd9Sstevel@tonic-gate * exacct_write_header() writes the given header buffer to the indicated 2597c478bd9Sstevel@tonic-gate * vnode, and frees the buffer. 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * Return values 2627c478bd9Sstevel@tonic-gate * The result of the write operation is returned. 2637c478bd9Sstevel@tonic-gate * 2647c478bd9Sstevel@tonic-gate * Caller's context 2657c478bd9Sstevel@tonic-gate * Caller must not hold the ac_lock of the appropriate accounting file 2667c478bd9Sstevel@tonic-gate * information block (ac_info_t). 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate int 2697c478bd9Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize) 2707c478bd9Sstevel@tonic-gate { 2717c478bd9Sstevel@tonic-gate int error; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate error = exacct_vn_write(info, hdr, hdrsize); 2747c478bd9Sstevel@tonic-gate kmem_free(hdr, hdrsize); 2757c478bd9Sstevel@tonic-gate return (error); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate static void 2797c478bd9Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu, 2807c478bd9Sstevel@tonic-gate task_usage_t **tu_buf) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate task_usage_t *oldtu, *newtu; 2837c478bd9Sstevel@tonic-gate task_usage_t **prevusage; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tk->tk_usage_lock)); 2867c478bd9Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) { 2877c478bd9Sstevel@tonic-gate prevusage = &tk->tk_zoneusage; 2887c478bd9Sstevel@tonic-gate } else { 2897c478bd9Sstevel@tonic-gate prevusage = &tk->tk_prevusage; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate if ((oldtu = *prevusage) != NULL) { 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * In case we have any accounting information 2947c478bd9Sstevel@tonic-gate * saved from the previous interval record. 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate newtu = *tu_buf; 2977c478bd9Sstevel@tonic-gate bcopy(tu, newtu, sizeof (task_usage_t)); 2987c478bd9Sstevel@tonic-gate tu->tu_minflt -= oldtu->tu_minflt; 2997c478bd9Sstevel@tonic-gate tu->tu_majflt -= oldtu->tu_majflt; 3007c478bd9Sstevel@tonic-gate tu->tu_sndmsg -= oldtu->tu_sndmsg; 3017c478bd9Sstevel@tonic-gate tu->tu_rcvmsg -= oldtu->tu_rcvmsg; 3027c478bd9Sstevel@tonic-gate tu->tu_ioch -= oldtu->tu_ioch; 3037c478bd9Sstevel@tonic-gate tu->tu_iblk -= oldtu->tu_iblk; 3047c478bd9Sstevel@tonic-gate tu->tu_oblk -= oldtu->tu_oblk; 3057c478bd9Sstevel@tonic-gate tu->tu_vcsw -= oldtu->tu_vcsw; 3067c478bd9Sstevel@tonic-gate tu->tu_icsw -= oldtu->tu_icsw; 3077c478bd9Sstevel@tonic-gate tu->tu_nsig -= oldtu->tu_nsig; 3087c478bd9Sstevel@tonic-gate tu->tu_nswp -= oldtu->tu_nswp; 3097c478bd9Sstevel@tonic-gate tu->tu_nscl -= oldtu->tu_nscl; 3107c478bd9Sstevel@tonic-gate tu->tu_utime -= oldtu->tu_utime; 3117c478bd9Sstevel@tonic-gate tu->tu_stime -= oldtu->tu_stime; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate tu->tu_startsec = oldtu->tu_finishsec; 3147c478bd9Sstevel@tonic-gate tu->tu_startnsec = oldtu->tu_finishnsec; 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * Copy the data from our temporary storage to the task's 3177c478bd9Sstevel@tonic-gate * previous interval usage structure for future reference. 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate bcopy(newtu, oldtu, sizeof (task_usage_t)); 3207c478bd9Sstevel@tonic-gate } else { 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * Store current statistics in the task's previous interval 3237c478bd9Sstevel@tonic-gate * usage structure for future references. 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate *prevusage = *tu_buf; 3267c478bd9Sstevel@tonic-gate bcopy(tu, *prevusage, sizeof (task_usage_t)); 3277c478bd9Sstevel@tonic-gate *tu_buf = NULL; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate static void 3327c478bd9Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu) 3337c478bd9Sstevel@tonic-gate { 3347c478bd9Sstevel@tonic-gate timestruc_t ts; 3357c478bd9Sstevel@tonic-gate proc_t *p; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if ((p = tk->tk_memb_list) == NULL) 3407c478bd9Sstevel@tonic-gate return; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * exacct_snapshot_task_usage() provides an approximate snapshot of the 3447c478bd9Sstevel@tonic-gate * usage of the potentially many members of the task. Since we don't 3457c478bd9Sstevel@tonic-gate * guarantee exactness, we don't acquire the p_lock of any of the member 3467c478bd9Sstevel@tonic-gate * processes. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate do { 3497c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3507c478bd9Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 3517c478bd9Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 3527c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3537c478bd9Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 3547c478bd9Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 3557c478bd9Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 3567c478bd9Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 3577c478bd9Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 3587c478bd9Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 3597c478bd9Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 3607c478bd9Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 3617c478bd9Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 3627c478bd9Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 3637c478bd9Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 3647c478bd9Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 3657c478bd9Sstevel@tonic-gate } while ((p = p->p_tasknext) != tk->tk_memb_list); 3667c478bd9Sstevel@tonic-gate 3677eceb558Srh87107 /* 3687eceb558Srh87107 * The resource usage accounted for so far will include that 3697eceb558Srh87107 * contributed by the task's first process. If this process 3707eceb558Srh87107 * came from another task, then its accumulated resource usage 3717eceb558Srh87107 * will include a contribution from work performed there. 3727eceb558Srh87107 * We must therefore subtract any resource usage that was 3737eceb558Srh87107 * inherited with the first process. 3747eceb558Srh87107 */ 3757eceb558Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 3767eceb558Srh87107 3777c478bd9Sstevel@tonic-gate gethrestime(&ts); 3787c478bd9Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 3797c478bd9Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837eceb558Srh87107 * void exacct_update_task_mstate(proc_t *) 3847eceb558Srh87107 * 3857eceb558Srh87107 * Overview 3867eceb558Srh87107 * exacct_update_task_mstate() updates the task usage; it is intended 3877eceb558Srh87107 * to be called from proc_exit(). 3887eceb558Srh87107 * 3897eceb558Srh87107 * Return values 3907eceb558Srh87107 * None. 3917eceb558Srh87107 * 3927eceb558Srh87107 * Caller's context 3937eceb558Srh87107 * p_lock must be held at entry. 3947c478bd9Sstevel@tonic-gate */ 3957eceb558Srh87107 void 3967c478bd9Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p) 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate task_usage_t *tu; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate mutex_enter(&p->p_task->tk_usage_lock); 4017c478bd9Sstevel@tonic-gate tu = p->p_task->tk_usage; 4027c478bd9Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 4037c478bd9Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 4047c478bd9Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 4057c478bd9Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 4067c478bd9Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 4077c478bd9Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 4087c478bd9Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 4097c478bd9Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 4107c478bd9Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 4117c478bd9Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 4127c478bd9Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 4137c478bd9Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 4147c478bd9Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 4157c478bd9Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 4167c478bd9Sstevel@tonic-gate mutex_exit(&p->p_task->tk_usage_lock); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate static void 4207c478bd9Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag) 4217c478bd9Sstevel@tonic-gate { 4227c478bd9Sstevel@tonic-gate timestruc_t ts; 4237c478bd9Sstevel@tonic-gate task_usage_t *tu_buf; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate switch (flag) { 4267c478bd9Sstevel@tonic-gate case EW_PARTIAL: 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * For partial records we must report the sum of current 4297c478bd9Sstevel@tonic-gate * accounting statistics with previously accumulated 4307c478bd9Sstevel@tonic-gate * statistics. 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 4337c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4367c478bd9Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4397c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 4407c478bd9Sstevel@tonic-gate break; 4417c478bd9Sstevel@tonic-gate case EW_INTERVAL: 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * We need to allocate spare task_usage_t buffer before 4447c478bd9Sstevel@tonic-gate * grabbing pidlock because we might need it later in 4457c478bd9Sstevel@tonic-gate * exacct_get_interval_task_usage(). 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 4487c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 4497c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * For interval records, we deduct the previous microstate 4537c478bd9Sstevel@tonic-gate * accounting data and cpu usage times from previously saved 4547c478bd9Sstevel@tonic-gate * results and update the previous task usage structure. 4557c478bd9Sstevel@tonic-gate */ 4567c478bd9Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4577c478bd9Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4587c478bd9Sstevel@tonic-gate exacct_get_interval_task_usage(tk, tu, &tu_buf); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4617c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if (tu_buf != NULL) 4647c478bd9Sstevel@tonic-gate kmem_free(tu_buf, sizeof (task_usage_t)); 4657c478bd9Sstevel@tonic-gate break; 4667c478bd9Sstevel@tonic-gate case EW_FINAL: 4677c478bd9Sstevel@tonic-gate /* 4687eceb558Srh87107 * For final records, we deduct, from the task's current 4697eceb558Srh87107 * usage, any usage that was inherited with the arrival 4707eceb558Srh87107 * of a process from a previous task. We then record 4717eceb558Srh87107 * the task's finish time. 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4747c478bd9Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4757eceb558Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 4767c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate gethrestime(&ts); 4797c478bd9Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 4807c478bd9Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate break; 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate static int 4877c478bd9Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record, 4887c478bd9Sstevel@tonic-gate int res) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate int attached = 1; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate switch (res) { 4937c478bd9Sstevel@tonic-gate case AC_TASK_TASKID: 4947c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_tkid, 4957c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID); 4967c478bd9Sstevel@tonic-gate break; 4977c478bd9Sstevel@tonic-gate case AC_TASK_PROJID: 4987c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_proj->kpj_id, 4997c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID); 5007c478bd9Sstevel@tonic-gate break; 5017c478bd9Sstevel@tonic-gate case AC_TASK_CPU: { 5027c478bd9Sstevel@tonic-gate timestruc_t ts; 5037c478bd9Sstevel@tonic-gate uint64_t ui; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate hrt2ts(tu->tu_stime, &ts); 5067c478bd9Sstevel@tonic-gate ui = ts.tv_sec; 5077c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5087c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_SEC); 5097c478bd9Sstevel@tonic-gate ui = ts.tv_nsec; 5107c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5117c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate hrt2ts(tu->tu_utime, &ts); 5147c478bd9Sstevel@tonic-gate ui = ts.tv_sec; 5157c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5167c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_SEC); 5177c478bd9Sstevel@tonic-gate ui = ts.tv_nsec; 5187c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5197c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_NSEC); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate break; 5227c478bd9Sstevel@tonic-gate case AC_TASK_TIME: 5237c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startsec, 5247c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC); 5257c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startnsec, 5267c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC); 5277c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishsec, 5287c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC); 5297c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishnsec, 5307c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC); 5317c478bd9Sstevel@tonic-gate break; 5327c478bd9Sstevel@tonic-gate case AC_TASK_HOSTNAME: 5337c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_nodename, 5347c478bd9Sstevel@tonic-gate strlen(tk->tk_zone->zone_nodename) + 1, 5357c478bd9Sstevel@tonic-gate EXT_STRING | EXD_TASK_HOSTNAME); 5367c478bd9Sstevel@tonic-gate break; 5377c478bd9Sstevel@tonic-gate case AC_TASK_MICROSTATE: 5387c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_majflt, 5397c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR); 5407c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_minflt, 5417c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR); 5427c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_sndmsg, 5437c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND); 5447c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_rcvmsg, 5457c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV); 5467c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_iblk, 5477c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN); 5487c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_oblk, 5497c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT); 5507c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_ioch, 5517c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR); 5527c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_vcsw, 5537c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL); 5547c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_icsw, 5557c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV); 5567c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nsig, 5577c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS); 5587c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nswp, 5597c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS); 5607c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nscl, 5617c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS); 5627c478bd9Sstevel@tonic-gate break; 5637c478bd9Sstevel@tonic-gate case AC_TASK_ANCTASKID: 5647c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_anctaskid, 5657c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID); 5667c478bd9Sstevel@tonic-gate break; 5677c478bd9Sstevel@tonic-gate case AC_TASK_ZONENAME: 5687c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_name, 5697c478bd9Sstevel@tonic-gate strlen(tk->tk_zone->zone_name) + 1, 5707c478bd9Sstevel@tonic-gate EXT_STRING | EXD_TASK_ZONENAME); 5717c478bd9Sstevel@tonic-gate break; 5727c478bd9Sstevel@tonic-gate default: 5737c478bd9Sstevel@tonic-gate attached = 0; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate return (attached); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate static ea_object_t * 5797c478bd9Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask, 5807c478bd9Sstevel@tonic-gate ea_catalog_t record_type) 5817c478bd9Sstevel@tonic-gate { 5827c478bd9Sstevel@tonic-gate int res, count; 5837c478bd9Sstevel@tonic-gate ea_object_t *record; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * Assemble usage values into group. 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 5897c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++) 5907c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res)) 5917c478bd9Sstevel@tonic-gate count += exacct_attach_task_item(tk, tu, record, res); 5927c478bd9Sstevel@tonic-gate if (count == 0) { 5937c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 5947c478bd9Sstevel@tonic-gate record = NULL; 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate return (record); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *, 6017c478bd9Sstevel@tonic-gate * size_t, size_t *), void *, size_t, size_t *, int) 6027c478bd9Sstevel@tonic-gate * 6037c478bd9Sstevel@tonic-gate * Overview 6047c478bd9Sstevel@tonic-gate * exacct_assemble_task_usage() builds the packed exacct buffer for the 6057c478bd9Sstevel@tonic-gate * indicated task, executes the given callback function, and free the packed 6067c478bd9Sstevel@tonic-gate * buffer. 6077c478bd9Sstevel@tonic-gate * 6087c478bd9Sstevel@tonic-gate * Return values 6097c478bd9Sstevel@tonic-gate * Returns 0 on success; otherwise the appropriate error code is returned. 6107c478bd9Sstevel@tonic-gate * 6117c478bd9Sstevel@tonic-gate * Caller's context 6127c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 6137c478bd9Sstevel@tonic-gate */ 6147c478bd9Sstevel@tonic-gate int 6157c478bd9Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk, 6167c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 6177c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 6187c478bd9Sstevel@tonic-gate { 6197c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 6207c478bd9Sstevel@tonic-gate ea_object_t *task_record; 6217c478bd9Sstevel@tonic-gate ea_catalog_t record_type; 6227c478bd9Sstevel@tonic-gate task_usage_t *tu; 6237c478bd9Sstevel@tonic-gate void *buf; 6247c478bd9Sstevel@tonic-gate size_t bufsize; 6257c478bd9Sstevel@tonic-gate int ret; 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 6307c478bd9Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF) { 6317c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6327c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ); 6357c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate switch (flag) { 6387c478bd9Sstevel@tonic-gate case EW_FINAL: 6397c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_TASK; 6407c478bd9Sstevel@tonic-gate break; 6417c478bd9Sstevel@tonic-gate case EW_PARTIAL: 6427c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_TASK_PARTIAL; 6437c478bd9Sstevel@tonic-gate break; 6447c478bd9Sstevel@tonic-gate case EW_INTERVAL: 6457c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_TASK_INTERVAL; 6467c478bd9Sstevel@tonic-gate break; 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * Calculate task usage and assemble it into the task record. 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 6537c478bd9Sstevel@tonic-gate exacct_calculate_task_usage(tk, tu, flag); 6547c478bd9Sstevel@tonic-gate task_record = exacct_assemble_task_record(tk, tu, mask, record_type); 6557c478bd9Sstevel@tonic-gate if (task_record == NULL) { 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * The current configuration of the accounting system has 6587c478bd9Sstevel@tonic-gate * resulted in records with no data; accordingly, we don't write 6597c478bd9Sstevel@tonic-gate * these, but we return success. 6607c478bd9Sstevel@tonic-gate */ 6617c478bd9Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6627c478bd9Sstevel@tonic-gate return (0); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* 6667c478bd9Sstevel@tonic-gate * Pack object into buffer and run callback on it. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(task_record, NULL, 0); 6697c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 6707c478bd9Sstevel@tonic-gate (void) ea_pack_object(task_record, buf, bufsize); 6717c478bd9Sstevel@tonic-gate ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* 6747c478bd9Sstevel@tonic-gate * Free all previously allocated structures. 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 6777c478bd9Sstevel@tonic-gate ea_free_object(task_record, EUP_ALLOC); 6787c478bd9Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6797c478bd9Sstevel@tonic-gate return (ret); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* 6837c478bd9Sstevel@tonic-gate * void exacct_commit_task(void *) 6847c478bd9Sstevel@tonic-gate * 6857c478bd9Sstevel@tonic-gate * Overview 6867c478bd9Sstevel@tonic-gate * exacct_commit_task() calculates the final usage for a task, updating the 6877c478bd9Sstevel@tonic-gate * task usage if task accounting is active, and writing a task record if task 6887c478bd9Sstevel@tonic-gate * accounting is active. exacct_commit_task() is intended for being called 6897c478bd9Sstevel@tonic-gate * from a task queue (taskq_t). 6907c478bd9Sstevel@tonic-gate * 6917c478bd9Sstevel@tonic-gate * Return values 6927c478bd9Sstevel@tonic-gate * None. 6937c478bd9Sstevel@tonic-gate * 6947c478bd9Sstevel@tonic-gate * Caller's context 6957c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate void 6997c478bd9Sstevel@tonic-gate exacct_commit_task(void *arg) 7007c478bd9Sstevel@tonic-gate { 7017c478bd9Sstevel@tonic-gate task_t *tk = (task_t *)arg; 7027c478bd9Sstevel@tonic-gate size_t size; 7037c478bd9Sstevel@tonic-gate zone_t *zone = tk->tk_zone; 7047c478bd9Sstevel@tonic-gate struct exacct_globals *acg; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate ASSERT(tk != task0p); 7077c478bd9Sstevel@tonic-gate ASSERT(tk->tk_memb_list == NULL); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * Don't do any extra work if the acctctl module isn't loaded. 7117c478bd9Sstevel@tonic-gate */ 7127c478bd9Sstevel@tonic-gate if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) { 7137c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 7147c478bd9Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7157c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7167c478bd9Sstevel@tonic-gate if (tk->tk_zone != global_zone) { 7177c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 7187c478bd9Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7197c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * Release associated project and finalize task. 7247c478bd9Sstevel@tonic-gate */ 7257c478bd9Sstevel@tonic-gate task_end(tk); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate static int 7297c478bd9Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate int attached = 1; 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate switch (res) { 7347c478bd9Sstevel@tonic-gate case AC_PROC_PID: 7357c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_pid, 7367c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID); 7377c478bd9Sstevel@tonic-gate break; 7387c478bd9Sstevel@tonic-gate case AC_PROC_UID: 7397c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ruid, 7407c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID); 7417c478bd9Sstevel@tonic-gate break; 7427c478bd9Sstevel@tonic-gate case AC_PROC_FLAG: 7437c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_acflag, 7447c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS); 7457c478bd9Sstevel@tonic-gate break; 7467c478bd9Sstevel@tonic-gate case AC_PROC_GID: 7477c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rgid, 7487c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID); 7497c478bd9Sstevel@tonic-gate break; 7507c478bd9Sstevel@tonic-gate case AC_PROC_PROJID: 7517c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_projid, 7527c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID); 7537c478bd9Sstevel@tonic-gate break; 7547c478bd9Sstevel@tonic-gate case AC_PROC_TASKID: 7557c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_taskid, 7567c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID); 7577c478bd9Sstevel@tonic-gate break; 7587c478bd9Sstevel@tonic-gate case AC_PROC_CPU: 7597c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimesec, 7607c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC); 7617c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimensec, 7627c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC); 7637c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimesec, 7647c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC); 7657c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimensec, 7667c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC); 7677c478bd9Sstevel@tonic-gate break; 7687c478bd9Sstevel@tonic-gate case AC_PROC_TIME: 7697c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startsec, 7707c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC); 7717c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startnsec, 7727c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC); 7737c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishsec, 7747c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC); 7757c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishnsec, 7767c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC); 7777c478bd9Sstevel@tonic-gate break; 7787c478bd9Sstevel@tonic-gate case AC_PROC_COMMAND: 7797c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_command, 7807c478bd9Sstevel@tonic-gate strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND); 7817c478bd9Sstevel@tonic-gate break; 7827c478bd9Sstevel@tonic-gate case AC_PROC_HOSTNAME: 7837c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_nodename, 7847c478bd9Sstevel@tonic-gate strlen(pu->pu_nodename) + 1, 7857c478bd9Sstevel@tonic-gate EXT_STRING | EXD_PROC_HOSTNAME); 7867c478bd9Sstevel@tonic-gate break; 7877c478bd9Sstevel@tonic-gate case AC_PROC_TTY: 7887c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_major, 7897c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR); 7907c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minor, 7917c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR); 7927c478bd9Sstevel@tonic-gate break; 7937c478bd9Sstevel@tonic-gate case AC_PROC_MICROSTATE: 7947c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_majflt, 7957c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR); 7967c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minflt, 7977c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR); 7987c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_sndmsg, 7997c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND); 8007c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rcvmsg, 8017c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV); 8027c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_iblk, 8037c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN); 8047c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_oblk, 8057c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT); 8067c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ioch, 8077c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR); 8087c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_vcsw, 8097c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL); 8107c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_icsw, 8117c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV); 8127c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nsig, 8137c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS); 8147c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nswp, 8157c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS); 8167c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nscl, 8177c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS); 8187c478bd9Sstevel@tonic-gate break; 8197c478bd9Sstevel@tonic-gate case AC_PROC_ANCPID: 8207c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ancpid, 8217c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID); 8227c478bd9Sstevel@tonic-gate break; 8237c478bd9Sstevel@tonic-gate case AC_PROC_WAIT_STATUS: 8247c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_wstat, 8257c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS); 8267c478bd9Sstevel@tonic-gate break; 8277c478bd9Sstevel@tonic-gate case AC_PROC_ZONENAME: 8287c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_zonename, 8297c478bd9Sstevel@tonic-gate strlen(pu->pu_zonename) + 1, 8307c478bd9Sstevel@tonic-gate EXT_STRING | EXD_PROC_ZONENAME); 8317c478bd9Sstevel@tonic-gate break; 8327c478bd9Sstevel@tonic-gate case AC_PROC_MEM: 8337c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_avg, 8347c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K); 8357c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_max, 8367c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K); 8377c478bd9Sstevel@tonic-gate break; 8387c478bd9Sstevel@tonic-gate default: 8397c478bd9Sstevel@tonic-gate attached = 0; 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate return (attached); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate static ea_object_t * 8457c478bd9Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask, 8467c478bd9Sstevel@tonic-gate ea_catalog_t record_type) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate int res, count; 8497c478bd9Sstevel@tonic-gate ea_object_t *record; 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Assemble usage values into group. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 8557c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++) 8567c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res)) 8577c478bd9Sstevel@tonic-gate count += exacct_attach_proc_item(pu, record, res); 8587c478bd9Sstevel@tonic-gate if (count == 0) { 8597c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 8607c478bd9Sstevel@tonic-gate record = NULL; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate return (record); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * The following two routines assume that process's p_lock is held or 8677c478bd9Sstevel@tonic-gate * exacct_commit_proc has been called from exit() when all lwps are stopped. 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate static void 8707c478bd9Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu) 8717c478bd9Sstevel@tonic-gate { 8727c478bd9Sstevel@tonic-gate kthread_t *t; 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 8757c478bd9Sstevel@tonic-gate if ((t = p->p_tlist) == NULL) 8767c478bd9Sstevel@tonic-gate return; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate do { 8797c478bd9Sstevel@tonic-gate pu->pu_minflt += t->t_lwp->lwp_ru.minflt; 8807c478bd9Sstevel@tonic-gate pu->pu_majflt += t->t_lwp->lwp_ru.majflt; 8817c478bd9Sstevel@tonic-gate pu->pu_sndmsg += t->t_lwp->lwp_ru.msgsnd; 8827c478bd9Sstevel@tonic-gate pu->pu_rcvmsg += t->t_lwp->lwp_ru.msgrcv; 8837c478bd9Sstevel@tonic-gate pu->pu_ioch += t->t_lwp->lwp_ru.ioch; 8847c478bd9Sstevel@tonic-gate pu->pu_iblk += t->t_lwp->lwp_ru.inblock; 8857c478bd9Sstevel@tonic-gate pu->pu_oblk += t->t_lwp->lwp_ru.oublock; 8867c478bd9Sstevel@tonic-gate pu->pu_vcsw += t->t_lwp->lwp_ru.nvcsw; 8877c478bd9Sstevel@tonic-gate pu->pu_icsw += t->t_lwp->lwp_ru.nivcsw; 8887c478bd9Sstevel@tonic-gate pu->pu_nsig += t->t_lwp->lwp_ru.nsignals; 8897c478bd9Sstevel@tonic-gate pu->pu_nswp += t->t_lwp->lwp_ru.nswap; 8907c478bd9Sstevel@tonic-gate pu->pu_nscl += t->t_lwp->lwp_ru.sysc; 8917c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate static void 8957c478bd9Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu) 8967c478bd9Sstevel@tonic-gate { 8977c478bd9Sstevel@tonic-gate pu->pu_minflt = p->p_ru.minflt; 8987c478bd9Sstevel@tonic-gate pu->pu_majflt = p->p_ru.majflt; 8997c478bd9Sstevel@tonic-gate pu->pu_sndmsg = p->p_ru.msgsnd; 9007c478bd9Sstevel@tonic-gate pu->pu_rcvmsg = p->p_ru.msgrcv; 9017c478bd9Sstevel@tonic-gate pu->pu_ioch = p->p_ru.ioch; 9027c478bd9Sstevel@tonic-gate pu->pu_iblk = p->p_ru.inblock; 9037c478bd9Sstevel@tonic-gate pu->pu_oblk = p->p_ru.oublock; 9047c478bd9Sstevel@tonic-gate pu->pu_vcsw = p->p_ru.nvcsw; 9057c478bd9Sstevel@tonic-gate pu->pu_icsw = p->p_ru.nivcsw; 9067c478bd9Sstevel@tonic-gate pu->pu_nsig = p->p_ru.nsignals; 9077c478bd9Sstevel@tonic-gate pu->pu_nswp = p->p_ru.nswap; 9087c478bd9Sstevel@tonic-gate pu->pu_nscl = p->p_ru.sysc; 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate void 9127c478bd9Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask, 9137c478bd9Sstevel@tonic-gate int flag, int wstat) 9147c478bd9Sstevel@tonic-gate { 9157c478bd9Sstevel@tonic-gate timestruc_t ts, ts_run; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * Convert CPU and execution times to sec/nsec format. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_CPU)) { 9237c478bd9Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_USER), &ts); 9247c478bd9Sstevel@tonic-gate pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec; 9257c478bd9Sstevel@tonic-gate pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9267c478bd9Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts); 9277c478bd9Sstevel@tonic-gate pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec; 9287c478bd9Sstevel@tonic-gate pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_TIME)) { 9317c478bd9Sstevel@tonic-gate gethrestime(&ts); 9327c478bd9Sstevel@tonic-gate pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 9337c478bd9Sstevel@tonic-gate pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9347c478bd9Sstevel@tonic-gate hrt2ts(gethrtime() - p->p_mstart, &ts_run); 9357c478bd9Sstevel@tonic-gate ts.tv_sec -= ts_run.tv_sec; 9367c478bd9Sstevel@tonic-gate ts.tv_nsec -= ts_run.tv_nsec; 9377c478bd9Sstevel@tonic-gate if (ts.tv_nsec < 0) { 9387c478bd9Sstevel@tonic-gate ts.tv_sec--; 9397c478bd9Sstevel@tonic-gate if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) { 9407c478bd9Sstevel@tonic-gate ts.tv_sec++; 9417c478bd9Sstevel@tonic-gate ts.tv_nsec -= NANOSEC; 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec; 9457c478bd9Sstevel@tonic-gate pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate pu->pu_pid = p->p_pidp->pid_id; 9497c478bd9Sstevel@tonic-gate pu->pu_acflag = p->p_user.u_acflag; 9507c478bd9Sstevel@tonic-gate pu->pu_projid = p->p_task->tk_proj->kpj_id; 9517c478bd9Sstevel@tonic-gate pu->pu_taskid = p->p_task->tk_tkid; 9527c478bd9Sstevel@tonic-gate pu->pu_major = getmajor(p->p_sessp->s_dev); 9537c478bd9Sstevel@tonic-gate pu->pu_minor = getminor(p->p_sessp->s_dev); 9547c478bd9Sstevel@tonic-gate pu->pu_ancpid = p->p_ancpid; 9557c478bd9Sstevel@tonic-gate pu->pu_wstat = wstat; 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * Compute average RSS in K. The denominator is the number of 9587c478bd9Sstevel@tonic-gate * samples: the number of clock ticks plus the initial value. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) * 9617c478bd9Sstevel@tonic-gate (PAGESIZE / 1024); 9627c478bd9Sstevel@tonic-gate pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate mutex_enter(&p->p_crlock); 9657c478bd9Sstevel@tonic-gate pu->pu_ruid = crgetruid(p->p_cred); 9667c478bd9Sstevel@tonic-gate pu->pu_rgid = crgetrgid(p->p_cred); 9677c478bd9Sstevel@tonic-gate mutex_exit(&p->p_crlock); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1); 9707c478bd9Sstevel@tonic-gate bcopy(p->p_zone->zone_name, pu->pu_zonename, 9717c478bd9Sstevel@tonic-gate strlen(p->p_zone->zone_name) + 1); 9727c478bd9Sstevel@tonic-gate bcopy(p->p_zone->zone_nodename, pu->pu_nodename, 9737c478bd9Sstevel@tonic-gate strlen(p->p_zone->zone_nodename) + 1); 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* 9767c478bd9Sstevel@tonic-gate * Calculate microstate accounting data for a process that is still 9777c478bd9Sstevel@tonic-gate * running. Presently, we explicitly collect all of the LWP usage into 9787c478bd9Sstevel@tonic-gate * the proc usage structure here. 9797c478bd9Sstevel@tonic-gate */ 9807c478bd9Sstevel@tonic-gate if (flag & EW_PARTIAL) 9817c478bd9Sstevel@tonic-gate exacct_calculate_proc_mstate(p, pu); 9827c478bd9Sstevel@tonic-gate if (flag & EW_FINAL) 9837c478bd9Sstevel@tonic-gate exacct_copy_proc_mstate(p, pu); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate /* 9877c478bd9Sstevel@tonic-gate * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void 9887c478bd9Sstevel@tonic-gate * *, size_t, size_t *), void *, size_t, size_t *) 9897c478bd9Sstevel@tonic-gate * 9907c478bd9Sstevel@tonic-gate * Overview 9917c478bd9Sstevel@tonic-gate * Assemble record with miscellaneous accounting information about the process 9927c478bd9Sstevel@tonic-gate * and execute the callback on it. It is the callback's job to set "actual" to 9937c478bd9Sstevel@tonic-gate * the size of record. 9947c478bd9Sstevel@tonic-gate * 9957c478bd9Sstevel@tonic-gate * Return values 9967c478bd9Sstevel@tonic-gate * The result of the callback function, unless the extended process accounting 9977c478bd9Sstevel@tonic-gate * feature is not active, in which case ENOTACTIVE is returned. 9987c478bd9Sstevel@tonic-gate * 9997c478bd9Sstevel@tonic-gate * Caller's context 10007c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 10017c478bd9Sstevel@tonic-gate */ 10027c478bd9Sstevel@tonic-gate int 10037c478bd9Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu, 10047c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 10057c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 10067c478bd9Sstevel@tonic-gate { 10077c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 10087c478bd9Sstevel@tonic-gate ea_object_t *proc_record; 10097c478bd9Sstevel@tonic-gate ea_catalog_t record_type; 10107c478bd9Sstevel@tonic-gate void *buf; 10117c478bd9Sstevel@tonic-gate size_t bufsize; 10127c478bd9Sstevel@tonic-gate int ret; 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL); 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 10177c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF) { 10187c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10197c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 10227c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate switch (flag) { 10257c478bd9Sstevel@tonic-gate case EW_FINAL: 10267c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_PROC; 10277c478bd9Sstevel@tonic-gate break; 10287c478bd9Sstevel@tonic-gate case EW_PARTIAL: 10297c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_PROC_PARTIAL; 10307c478bd9Sstevel@tonic-gate break; 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate proc_record = exacct_assemble_proc_record(pu, mask, record_type); 10347c478bd9Sstevel@tonic-gate if (proc_record == NULL) 10357c478bd9Sstevel@tonic-gate return (0); 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * Pack object into buffer and pass to callback. 10397c478bd9Sstevel@tonic-gate */ 10407c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(proc_record, NULL, 0); 10417c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 10427c478bd9Sstevel@tonic-gate (void) ea_pack_object(proc_record, buf, bufsize); 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual); 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate /* 10477c478bd9Sstevel@tonic-gate * Free all previously allocations. 10487c478bd9Sstevel@tonic-gate */ 10497c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 10507c478bd9Sstevel@tonic-gate ea_free_object(proc_record, EUP_ALLOC); 10517c478bd9Sstevel@tonic-gate return (ret); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* 10557c478bd9Sstevel@tonic-gate * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t, 10567c478bd9Sstevel@tonic-gate * size_t *) 10577c478bd9Sstevel@tonic-gate * 10587c478bd9Sstevel@tonic-gate * Overview 10597c478bd9Sstevel@tonic-gate * exacct_commit_callback() writes the indicated buffer to the indicated 10607c478bd9Sstevel@tonic-gate * extended accounting file. 10617c478bd9Sstevel@tonic-gate * 10627c478bd9Sstevel@tonic-gate * Return values 10637c478bd9Sstevel@tonic-gate * The result of the write operation is returned. "actual" is updated to 10647c478bd9Sstevel@tonic-gate * contain the number of bytes actually written. 10657c478bd9Sstevel@tonic-gate * 10667c478bd9Sstevel@tonic-gate * Caller's context 10677c478bd9Sstevel@tonic-gate * Suitable for a vn_rdwr() operation. 10687c478bd9Sstevel@tonic-gate */ 10697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10707c478bd9Sstevel@tonic-gate int 10717c478bd9Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize, 10727c478bd9Sstevel@tonic-gate void *buf, size_t bufsize, size_t *actual) 10737c478bd9Sstevel@tonic-gate { 10747c478bd9Sstevel@tonic-gate int error = 0; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate *actual = 0; 10777c478bd9Sstevel@tonic-gate if ((error = exacct_vn_write(info, buf, bufsize)) == 0) 10787c478bd9Sstevel@tonic-gate *actual = bufsize; 10797c478bd9Sstevel@tonic-gate return (error); 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate static void 10837c478bd9Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat) 10847c478bd9Sstevel@tonic-gate { 10857c478bd9Sstevel@tonic-gate size_t size; 10867c478bd9Sstevel@tonic-gate proc_usage_t *pu; 10877c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 10907c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_ON) { 10917c478bd9Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 10927c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10937c478bd9Sstevel@tonic-gate } else { 10947c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10957c478bd9Sstevel@tonic-gate return; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 10997c478bd9Sstevel@tonic-gate size = strlen(p->p_user.u_comm) + 1; 11007c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP); 11037c478bd9Sstevel@tonic-gate pu->pu_command = kmem_alloc(size, KM_SLEEP); 11047c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 11057c478bd9Sstevel@tonic-gate exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat); 11067c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate (void) exacct_assemble_proc_usage(ac_proc, pu, 11097c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate kmem_free(pu->pu_command, strlen(pu->pu_command) + 1); 11127c478bd9Sstevel@tonic-gate kmem_free(pu, sizeof (proc_usage_t)); 11137c478bd9Sstevel@tonic-gate } 11147eceb558Srh87107 11157c478bd9Sstevel@tonic-gate /* 11167c478bd9Sstevel@tonic-gate * void exacct_commit_proc(proc_t *, int) 11177c478bd9Sstevel@tonic-gate * 11187c478bd9Sstevel@tonic-gate * Overview 11197c478bd9Sstevel@tonic-gate * exacct_commit_proc() calculates the final usage for a process, updating the 11207c478bd9Sstevel@tonic-gate * task usage if task accounting is active, and writing a process record if 11217c478bd9Sstevel@tonic-gate * process accounting is active. exacct_commit_proc() is intended for being 11227c478bd9Sstevel@tonic-gate * called from proc_exit(). 11237c478bd9Sstevel@tonic-gate * 11247c478bd9Sstevel@tonic-gate * Return values 11257c478bd9Sstevel@tonic-gate * None. 11267c478bd9Sstevel@tonic-gate * 11277c478bd9Sstevel@tonic-gate * Caller's context 11287c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. p_lock must not be held at entry. 11297c478bd9Sstevel@tonic-gate */ 11307c478bd9Sstevel@tonic-gate void 11317c478bd9Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat) 11327c478bd9Sstevel@tonic-gate { 11337c478bd9Sstevel@tonic-gate zone_t *zone = p->p_zone; 11347c478bd9Sstevel@tonic-gate struct exacct_globals *acg, *gacg = NULL; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 11377c478bd9Sstevel@tonic-gate /* 11387c478bd9Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 11397c478bd9Sstevel@tonic-gate */ 11407c478bd9Sstevel@tonic-gate return; 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 11437c478bd9Sstevel@tonic-gate exacct_do_commit_proc(&acg->ac_proc, p, wstat); 11447eceb558Srh87107 if (zone != global_zone) { 11457eceb558Srh87107 gacg = zone_getspecific(exacct_zone_key, global_zone); 11467c478bd9Sstevel@tonic-gate exacct_do_commit_proc(&gacg->ac_proc, p, wstat); 11477c478bd9Sstevel@tonic-gate } 11487eceb558Srh87107 } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate static int 11517c478bd9Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate int attached = 1; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate switch (res) { 11567c478bd9Sstevel@tonic-gate case AC_FLOW_SADDR: 11577c478bd9Sstevel@tonic-gate if (fu->fu_isv4) { 11587c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr[3], 11597c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR); 11607c478bd9Sstevel@tonic-gate } else { 11617c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr, 11627c478bd9Sstevel@tonic-gate sizeof (fu->fu_saddr), EXT_RAW | 11637c478bd9Sstevel@tonic-gate EXD_FLOW_V6SADDR); 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate break; 11667c478bd9Sstevel@tonic-gate case AC_FLOW_DADDR: 11677c478bd9Sstevel@tonic-gate if (fu->fu_isv4) { 11687c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr[3], 11697c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR); 11707c478bd9Sstevel@tonic-gate } else { 11717c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr, 11727c478bd9Sstevel@tonic-gate sizeof (fu->fu_daddr), EXT_RAW | 11737c478bd9Sstevel@tonic-gate EXD_FLOW_V6DADDR); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate break; 11767c478bd9Sstevel@tonic-gate case AC_FLOW_SPORT: 11777c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_sport, 11787c478bd9Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT); 11797c478bd9Sstevel@tonic-gate break; 11807c478bd9Sstevel@tonic-gate case AC_FLOW_DPORT: 11817c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dport, 11827c478bd9Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT); 11837c478bd9Sstevel@tonic-gate break; 11847c478bd9Sstevel@tonic-gate case AC_FLOW_PROTOCOL: 11857c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_protocol, 11867c478bd9Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL); 11877c478bd9Sstevel@tonic-gate break; 11887c478bd9Sstevel@tonic-gate case AC_FLOW_DSFIELD: 11897c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dsfield, 11907c478bd9Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD); 11917c478bd9Sstevel@tonic-gate break; 11927c478bd9Sstevel@tonic-gate case AC_FLOW_CTIME: 11937c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_ctime, 11947c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME); 11957c478bd9Sstevel@tonic-gate break; 11967c478bd9Sstevel@tonic-gate case AC_FLOW_LSEEN: 11977c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_lseen, 11987c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN); 11997c478bd9Sstevel@tonic-gate break; 12007c478bd9Sstevel@tonic-gate case AC_FLOW_NBYTES: 12017c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_nbytes, 12027c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES); 12037c478bd9Sstevel@tonic-gate break; 12047c478bd9Sstevel@tonic-gate case AC_FLOW_NPKTS: 12057c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_npackets, 12067c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS); 12077c478bd9Sstevel@tonic-gate break; 12087c478bd9Sstevel@tonic-gate case AC_FLOW_PROJID: 12097c478bd9Sstevel@tonic-gate if (fu->fu_projid >= 0) { 12107c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_projid, 12117c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate break; 12147c478bd9Sstevel@tonic-gate case AC_FLOW_UID: 12157c478bd9Sstevel@tonic-gate if (fu->fu_userid >= 0) { 12167c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_userid, 12177c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate break; 12207c478bd9Sstevel@tonic-gate case AC_FLOW_ANAME: 12217c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, fu->fu_aname, 12227c478bd9Sstevel@tonic-gate strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME); 12237c478bd9Sstevel@tonic-gate break; 12247c478bd9Sstevel@tonic-gate default: 12257c478bd9Sstevel@tonic-gate attached = 0; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate return (attached); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate static ea_object_t * 12317c478bd9Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask, 12327c478bd9Sstevel@tonic-gate ea_catalog_t record_type) 12337c478bd9Sstevel@tonic-gate { 12347c478bd9Sstevel@tonic-gate int res, count; 12357c478bd9Sstevel@tonic-gate ea_object_t *record; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate /* 12387c478bd9Sstevel@tonic-gate * Assemble usage values into group. 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 12417c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++) 12427c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res)) 12437c478bd9Sstevel@tonic-gate count += exacct_attach_flow_item(fu, record, res); 12447c478bd9Sstevel@tonic-gate if (count == 0) { 12457c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 12467c478bd9Sstevel@tonic-gate record = NULL; 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate return (record); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate int 12527c478bd9Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu, 12537c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 12547c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual) 12557c478bd9Sstevel@tonic-gate { 12567c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 12577c478bd9Sstevel@tonic-gate ea_object_t *flow_usage; 12587c478bd9Sstevel@tonic-gate ea_catalog_t record_type; 12597c478bd9Sstevel@tonic-gate void *buf; 12607c478bd9Sstevel@tonic-gate size_t bufsize; 12617c478bd9Sstevel@tonic-gate int ret; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 12647c478bd9Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 12657c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 12667c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 12697c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_FLOW; 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate flow_usage = exacct_assemble_flow_record(fu, mask, record_type); 12747c478bd9Sstevel@tonic-gate if (flow_usage == NULL) { 12757c478bd9Sstevel@tonic-gate return (0); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate /* 12797c478bd9Sstevel@tonic-gate * Pack object into buffer and pass to callback. 12807c478bd9Sstevel@tonic-gate */ 12817c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(flow_usage, NULL, 0); 12827c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_NOSLEEP); 12837c478bd9Sstevel@tonic-gate if (buf == NULL) { 12847c478bd9Sstevel@tonic-gate return (ENOMEM); 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate (void) ea_pack_object(flow_usage, buf, bufsize); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * Free all previously allocations. 12937c478bd9Sstevel@tonic-gate */ 12947c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 12957c478bd9Sstevel@tonic-gate ea_free_object(flow_usage, EUP_ALLOC); 12967c478bd9Sstevel@tonic-gate return (ret); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate void 13007c478bd9Sstevel@tonic-gate exacct_commit_flow(void *arg) 13017c478bd9Sstevel@tonic-gate { 13027c478bd9Sstevel@tonic-gate flow_usage_t *f = (flow_usage_t *)arg; 13037c478bd9Sstevel@tonic-gate size_t size; 13047c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 13057c478bd9Sstevel@tonic-gate struct exacct_globals *acg; 13067c478bd9Sstevel@tonic-gate ac_info_t *ac_flow; 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 13117c478bd9Sstevel@tonic-gate */ 13127c478bd9Sstevel@tonic-gate return; 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate /* 13167c478bd9Sstevel@tonic-gate * Even though each zone nominally has its own flow accounting settings 13177c478bd9Sstevel@tonic-gate * (ac_flow), these are only maintained by and for the global zone. 13187c478bd9Sstevel@tonic-gate * 13197c478bd9Sstevel@tonic-gate * If this were to change in the future, this function should grow a 13207c478bd9Sstevel@tonic-gate * second zoneid (or zone) argument, and use the corresponding zone's 13217c478bd9Sstevel@tonic-gate * settings rather than always using those of the global zone. 13227c478bd9Sstevel@tonic-gate */ 13237c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 13247c478bd9Sstevel@tonic-gate ac_flow = &acg->ac_flow; 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 13277c478bd9Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 13287c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 13297c478bd9Sstevel@tonic-gate return; 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 13327c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate (void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback, 13357c478bd9Sstevel@tonic-gate NULL, 0, &size); 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate /* 13397c478bd9Sstevel@tonic-gate * int exacct_tag_task(task_t *, void *, size_t, int) 13407c478bd9Sstevel@tonic-gate * 13417c478bd9Sstevel@tonic-gate * Overview 13427c478bd9Sstevel@tonic-gate * exacct_tag_task() provides the exacct record construction and writing 13437c478bd9Sstevel@tonic-gate * support required by putacct(2) for task entities. 13447c478bd9Sstevel@tonic-gate * 13457c478bd9Sstevel@tonic-gate * Return values 13467c478bd9Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 13477c478bd9Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 13487c478bd9Sstevel@tonic-gate * 13497c478bd9Sstevel@tonic-gate * Caller's context 13507c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 13517c478bd9Sstevel@tonic-gate */ 13527c478bd9Sstevel@tonic-gate int 13537c478bd9Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz, 13547c478bd9Sstevel@tonic-gate int flags) 13557c478bd9Sstevel@tonic-gate { 13567c478bd9Sstevel@tonic-gate int error = 0; 13577c478bd9Sstevel@tonic-gate void *buf; 13587c478bd9Sstevel@tonic-gate size_t bufsize; 13597c478bd9Sstevel@tonic-gate ea_catalog_t cat; 13607c478bd9Sstevel@tonic-gate ea_object_t *tag; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 13637c478bd9Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) { 13647c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 13657c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG); 13707c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &tk->tk_tkid, 0, 13717c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 13727c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0, 13737c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 13747c478bd9Sstevel@tonic-gate if (flags == EP_RAW) 13757c478bd9Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG; 13767c478bd9Sstevel@tonic-gate else 13777c478bd9Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG; 13787c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 13817c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 13827c478bd9Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 13837c478bd9Sstevel@tonic-gate error = exacct_vn_write(ac_task, buf, bufsize); 13847c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 13857c478bd9Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 13867c478bd9Sstevel@tonic-gate return (error); 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *) 13917c478bd9Sstevel@tonic-gate * 13927c478bd9Sstevel@tonic-gate * Overview 13937c478bd9Sstevel@tonic-gate * exacct_tag_proc() provides the exacct record construction and writing 13947c478bd9Sstevel@tonic-gate * support required by putacct(2) for processes. 13957c478bd9Sstevel@tonic-gate * 13967c478bd9Sstevel@tonic-gate * Return values 13977c478bd9Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 13987c478bd9Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 13997c478bd9Sstevel@tonic-gate * 14007c478bd9Sstevel@tonic-gate * Caller's context 14017c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 14027c478bd9Sstevel@tonic-gate */ 14037c478bd9Sstevel@tonic-gate int 14047c478bd9Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf, 14057c478bd9Sstevel@tonic-gate size_t ubufsz, int flags, const char *hostname) 14067c478bd9Sstevel@tonic-gate { 14077c478bd9Sstevel@tonic-gate int error = 0; 14087c478bd9Sstevel@tonic-gate void *buf; 14097c478bd9Sstevel@tonic-gate size_t bufsize; 14107c478bd9Sstevel@tonic-gate ea_catalog_t cat; 14117c478bd9Sstevel@tonic-gate ea_object_t *tag; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 14147c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) { 14157c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 14167c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG); 14217c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &pid, sizeof (uint32_t), 14227c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID); 14237c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &tkid, 0, 14247c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 14257c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, (void *)hostname, 0, 14267c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 14277c478bd9Sstevel@tonic-gate if (flags == EP_RAW) 14287c478bd9Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG; 14297c478bd9Sstevel@tonic-gate else 14307c478bd9Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG; 14317c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 14347c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 14357c478bd9Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 14367c478bd9Sstevel@tonic-gate error = exacct_vn_write(ac_proc, buf, bufsize); 14377c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 14387c478bd9Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 14397c478bd9Sstevel@tonic-gate return (error); 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /* 14437c478bd9Sstevel@tonic-gate * void exacct_init(void) 14447c478bd9Sstevel@tonic-gate * 14457c478bd9Sstevel@tonic-gate * Overview 14467c478bd9Sstevel@tonic-gate * Initialized the extended accounting subsystem. 14477c478bd9Sstevel@tonic-gate * 14487c478bd9Sstevel@tonic-gate * Return values 14497c478bd9Sstevel@tonic-gate * None. 14507c478bd9Sstevel@tonic-gate * 14517c478bd9Sstevel@tonic-gate * Caller's context 14527c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 14537c478bd9Sstevel@tonic-gate */ 14547c478bd9Sstevel@tonic-gate void 14557c478bd9Sstevel@tonic-gate exacct_init() 14567c478bd9Sstevel@tonic-gate { 14577c478bd9Sstevel@tonic-gate exacct_queue = system_taskq; 14587c478bd9Sstevel@tonic-gate exacct_object_cache = kmem_cache_create("exacct_object_cache", 14597c478bd9Sstevel@tonic-gate sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 14607c478bd9Sstevel@tonic-gate } 14617eceb558Srh87107 14627eceb558Srh87107 /* 14637eceb558Srh87107 * exacct_snapshot_proc_mstate() copies a process's microstate accounting data 14647eceb558Srh87107 * and resource usage counters into a given task_usage_t. It differs from 14657eceb558Srh87107 * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t, 14667eceb558Srh87107 * b) p_lock will have been acquired earlier in the call path and c) we 14677eceb558Srh87107 * are here including the process's user and system times. 14687eceb558Srh87107 */ 14697eceb558Srh87107 static void 14707eceb558Srh87107 exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu) 14717eceb558Srh87107 { 14727eceb558Srh87107 tu->tu_utime = mstate_aggr_state(p, LMS_USER); 14737eceb558Srh87107 tu->tu_stime = mstate_aggr_state(p, LMS_SYSTEM); 14747eceb558Srh87107 tu->tu_minflt = p->p_ru.minflt; 14757eceb558Srh87107 tu->tu_majflt = p->p_ru.majflt; 14767eceb558Srh87107 tu->tu_sndmsg = p->p_ru.msgsnd; 14777eceb558Srh87107 tu->tu_rcvmsg = p->p_ru.msgrcv; 14787eceb558Srh87107 tu->tu_ioch = p->p_ru.ioch; 14797eceb558Srh87107 tu->tu_iblk = p->p_ru.inblock; 14807eceb558Srh87107 tu->tu_oblk = p->p_ru.oublock; 14817eceb558Srh87107 tu->tu_vcsw = p->p_ru.nvcsw; 14827eceb558Srh87107 tu->tu_icsw = p->p_ru.nivcsw; 14837eceb558Srh87107 tu->tu_nsig = p->p_ru.nsignals; 14847eceb558Srh87107 tu->tu_nswp = p->p_ru.nswap; 14857eceb558Srh87107 tu->tu_nscl = p->p_ru.sysc; 14867eceb558Srh87107 } 14877eceb558Srh87107 14887eceb558Srh87107 /* 14897eceb558Srh87107 * void exacct_move_mstate(proc_t *, task_t *, task_t *) 14907eceb558Srh87107 * 14917eceb558Srh87107 * Overview 14927eceb558Srh87107 * exacct_move_mstate() is called by task_change() and accounts for 14937eceb558Srh87107 * a process's resource usage when it is moved from one task to another. 14947eceb558Srh87107 * 14957eceb558Srh87107 * The process's usage at this point is recorded in the new task so 14967eceb558Srh87107 * that it can be excluded from the calculation of resources consumed 14977eceb558Srh87107 * by that task. 14987eceb558Srh87107 * 14997eceb558Srh87107 * The resource usage inherited by the new task is also added to the 15007eceb558Srh87107 * aggregate maintained by the old task for processes that have exited. 15017eceb558Srh87107 * 15027eceb558Srh87107 * Return values 15037eceb558Srh87107 * None. 15047eceb558Srh87107 * 15057eceb558Srh87107 * Caller's context 15067eceb558Srh87107 * pidlock and p_lock held across exacct_move_mstate(). 15077eceb558Srh87107 */ 15087eceb558Srh87107 void 15097eceb558Srh87107 exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk) 15107eceb558Srh87107 { 15117eceb558Srh87107 task_usage_t tu; 15127eceb558Srh87107 15137eceb558Srh87107 /* Take a snapshot of this process's mstate and RU counters */ 15147eceb558Srh87107 exacct_snapshot_proc_mstate(p, &tu); 15157eceb558Srh87107 15167eceb558Srh87107 /* 15177eceb558Srh87107 * Use the snapshot to increment the aggregate usage of the old 15187eceb558Srh87107 * task, and the inherited usage of the new one. 15197eceb558Srh87107 */ 15207eceb558Srh87107 mutex_enter(&oldtk->tk_usage_lock); 15217eceb558Srh87107 exacct_add_task_mstate(oldtk->tk_usage, &tu); 15227eceb558Srh87107 mutex_exit(&oldtk->tk_usage_lock); 15237eceb558Srh87107 mutex_enter(&newtk->tk_usage_lock); 15247eceb558Srh87107 exacct_add_task_mstate(newtk->tk_inherited, &tu); 15257eceb558Srh87107 mutex_exit(&newtk->tk_usage_lock); 15267eceb558Srh87107 } 1527