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