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 /* 22074e084fSml93401 * 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 #include <sys/exacct.h> 277c478bd9Sstevel@tonic-gate #include <sys/exacct_catalog.h> 287c478bd9Sstevel@tonic-gate #include <sys/disp.h> 297c478bd9Sstevel@tonic-gate #include <sys/task.h> 307c478bd9Sstevel@tonic-gate #include <sys/proc.h> 317c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 327c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 337c478bd9Sstevel@tonic-gate #include <sys/project.h> 347c478bd9Sstevel@tonic-gate #include <sys/systm.h> 357c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 367c478bd9Sstevel@tonic-gate #include <sys/file.h> 377c478bd9Sstevel@tonic-gate #include <sys/acctctl.h> 387c478bd9Sstevel@tonic-gate #include <sys/time.h> 397c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 407c478bd9Sstevel@tonic-gate #include <sys/session.h> 417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 427c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 437c478bd9Sstevel@tonic-gate #include <sys/msacct.h> 44*da14cebeSEric Cheng #include <sys/mac.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* 477c478bd9Sstevel@tonic-gate * exacct usage and recording routines 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * wracct(2), getacct(2), and the records written at process or task 507c478bd9Sstevel@tonic-gate * termination are constructed using the exacct_assemble_[task,proc]_usage() 517c478bd9Sstevel@tonic-gate * functions, which take a callback that takes the appropriate action on 527c478bd9Sstevel@tonic-gate * the packed exacct record for the task or process. For the process-related 537c478bd9Sstevel@tonic-gate * actions, we partition the routines such that the data collecting component 547c478bd9Sstevel@tonic-gate * can be performed while holding p_lock, and all sleeping or blocking 557c478bd9Sstevel@tonic-gate * operations can be performed without acquiring p_lock. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * putacct(2), which allows an application to construct a customized record 587c478bd9Sstevel@tonic-gate * associated with an existing process or task, has its own entry points: 597c478bd9Sstevel@tonic-gate * exacct_tag_task() and exacct_tag_proc(). 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate taskq_t *exacct_queue; 637c478bd9Sstevel@tonic-gate kmem_cache_t *exacct_object_cache; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION; 687c478bd9Sstevel@tonic-gate static const char exacct_header[] = "exacct"; 697c478bd9Sstevel@tonic-gate static const char exacct_creator[] = "SunOS"; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate ea_object_t * 727c478bd9Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz) 737c478bd9Sstevel@tonic-gate { 747c478bd9Sstevel@tonic-gate ea_object_t *item; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 777c478bd9Sstevel@tonic-gate bzero(item, sizeof (ea_object_t)); 787c478bd9Sstevel@tonic-gate (void) ea_set_item(item, catalog, buf, bufsz); 797c478bd9Sstevel@tonic-gate return (item); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate ea_object_t * 837c478bd9Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog) 847c478bd9Sstevel@tonic-gate { 857c478bd9Sstevel@tonic-gate ea_object_t *group; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP); 887c478bd9Sstevel@tonic-gate bzero(group, sizeof (ea_object_t)); 897c478bd9Sstevel@tonic-gate (void) ea_set_group(group, catalog); 907c478bd9Sstevel@tonic-gate return (group); 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate ea_object_t * 947c478bd9Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate ea_object_t *item; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate item = ea_alloc_item(catalog, buf, bufsz); 997c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(grp, item); 1007c478bd9Sstevel@tonic-gate return (item); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047eceb558Srh87107 * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract 1057eceb558Srh87107 * microstate accounting data and resource usage counters from one task_usage_t 1067eceb558Srh87107 * from those supplied in another. These functions do not operate on *all* 1077eceb558Srh87107 * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make 1087eceb558Srh87107 * sense. 1097eceb558Srh87107 */ 1107eceb558Srh87107 static void 1117eceb558Srh87107 exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta) 1127eceb558Srh87107 { 1137eceb558Srh87107 tu->tu_utime += delta->tu_utime; 1147eceb558Srh87107 tu->tu_stime += delta->tu_stime; 1157eceb558Srh87107 tu->tu_minflt += delta->tu_minflt; 1167eceb558Srh87107 tu->tu_majflt += delta->tu_majflt; 1177eceb558Srh87107 tu->tu_sndmsg += delta->tu_sndmsg; 1187eceb558Srh87107 tu->tu_rcvmsg += delta->tu_rcvmsg; 1197eceb558Srh87107 tu->tu_ioch += delta->tu_ioch; 1207eceb558Srh87107 tu->tu_iblk += delta->tu_iblk; 1217eceb558Srh87107 tu->tu_oblk += delta->tu_oblk; 1227eceb558Srh87107 tu->tu_vcsw += delta->tu_vcsw; 1237eceb558Srh87107 tu->tu_icsw += delta->tu_icsw; 1247eceb558Srh87107 tu->tu_nsig += delta->tu_nsig; 1257eceb558Srh87107 tu->tu_nswp += delta->tu_nswp; 1267eceb558Srh87107 tu->tu_nscl += delta->tu_nscl; 1277eceb558Srh87107 } 1287eceb558Srh87107 1297eceb558Srh87107 /* 1307eceb558Srh87107 * See the comments for exacct_add_task_mstate(), above. 1317eceb558Srh87107 */ 1327eceb558Srh87107 static void 1337eceb558Srh87107 exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta) 1347eceb558Srh87107 { 1357eceb558Srh87107 tu->tu_utime -= delta->tu_utime; 1367eceb558Srh87107 tu->tu_stime -= delta->tu_stime; 1377eceb558Srh87107 tu->tu_minflt -= delta->tu_minflt; 1387eceb558Srh87107 tu->tu_majflt -= delta->tu_majflt; 1397eceb558Srh87107 tu->tu_sndmsg -= delta->tu_sndmsg; 1407eceb558Srh87107 tu->tu_rcvmsg -= delta->tu_rcvmsg; 1417eceb558Srh87107 tu->tu_ioch -= delta->tu_ioch; 1427eceb558Srh87107 tu->tu_iblk -= delta->tu_iblk; 1437eceb558Srh87107 tu->tu_oblk -= delta->tu_oblk; 1447eceb558Srh87107 tu->tu_vcsw -= delta->tu_vcsw; 1457eceb558Srh87107 tu->tu_icsw -= delta->tu_icsw; 1467eceb558Srh87107 tu->tu_nsig -= delta->tu_nsig; 1477eceb558Srh87107 tu->tu_nswp -= delta->tu_nswp; 1487eceb558Srh87107 tu->tu_nscl -= delta->tu_nscl; 1497eceb558Srh87107 } 1507eceb558Srh87107 1517eceb558Srh87107 /* 152074e084fSml93401 * Wrapper for vn_rdwr() used by exacct_vn_write() and exacct_write_header() 153074e084fSml93401 * to write to the accounting file without corrupting it in case of an I/O or 154074e084fSml93401 * filesystem error. 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate static int 157074e084fSml93401 exacct_vn_write_impl(ac_info_t *info, void *buf, ssize_t bufsize) 1587c478bd9Sstevel@tonic-gate { 159074e084fSml93401 int error; 1607c478bd9Sstevel@tonic-gate ssize_t resid; 1617c478bd9Sstevel@tonic-gate struct vattr va; 1627c478bd9Sstevel@tonic-gate 163074e084fSml93401 ASSERT(info != NULL); 164074e084fSml93401 ASSERT(info->ac_vnode != NULL); 165074e084fSml93401 ASSERT(MUTEX_HELD(&info->ac_lock)); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Save the size. If vn_rdwr fails, reset the size to avoid corrupting 1697c478bd9Sstevel@tonic-gate * the present accounting file. 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 172da6c28aaSamw error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1737c478bd9Sstevel@tonic-gate if (error == 0) { 1747c478bd9Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf, 1757c478bd9Sstevel@tonic-gate bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T, 1767c478bd9Sstevel@tonic-gate kcred, &resid); 1777c478bd9Sstevel@tonic-gate if (error) { 1787c478bd9Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1797c478bd9Sstevel@tonic-gate } else if (resid != 0) { 1807c478bd9Sstevel@tonic-gate (void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL); 1817c478bd9Sstevel@tonic-gate error = ENOSPC; 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate } 184074e084fSml93401 return (error); 185074e084fSml93401 } 186074e084fSml93401 187074e084fSml93401 /* 188074e084fSml93401 * exacct_vn_write() safely writes to an accounting file. acctctl() prevents 189074e084fSml93401 * the two accounting vnodes from being equal, and the appropriate ac_lock is 190074e084fSml93401 * held across the call, so we're single threaded through this code for each 191074e084fSml93401 * file. 192074e084fSml93401 */ 193074e084fSml93401 static int 194074e084fSml93401 exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize) 195074e084fSml93401 { 196074e084fSml93401 int error; 197074e084fSml93401 198074e084fSml93401 if (info == NULL) 199074e084fSml93401 return (0); 200074e084fSml93401 201074e084fSml93401 mutex_enter(&info->ac_lock); 202074e084fSml93401 203074e084fSml93401 /* 204074e084fSml93401 * Don't do anything unless accounting file is set. 205074e084fSml93401 */ 206074e084fSml93401 if (info->ac_vnode == NULL) { 207074e084fSml93401 mutex_exit(&info->ac_lock); 208074e084fSml93401 return (0); 209074e084fSml93401 } 210074e084fSml93401 error = exacct_vn_write_impl(info, buf, bufsize); 2117c478bd9Sstevel@tonic-gate mutex_exit(&info->ac_lock); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate return (error); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * void *exacct_create_header(size_t *) 2187c478bd9Sstevel@tonic-gate * 2197c478bd9Sstevel@tonic-gate * Overview 2207c478bd9Sstevel@tonic-gate * exacct_create_header() constructs an exacct file header identifying the 2217c478bd9Sstevel@tonic-gate * accounting file as the output of the kernel. exacct_create_header() and 2227c478bd9Sstevel@tonic-gate * the static write_header() and verify_header() routines in libexacct must 2237c478bd9Sstevel@tonic-gate * remain synchronized. 2247c478bd9Sstevel@tonic-gate * 2257c478bd9Sstevel@tonic-gate * Return values 2267c478bd9Sstevel@tonic-gate * A pointer to a packed exacct buffer containing the appropriate header is 2277c478bd9Sstevel@tonic-gate * returned; the size of the buffer is placed in the location indicated by 2287c478bd9Sstevel@tonic-gate * sizep. 2297c478bd9Sstevel@tonic-gate * 2307c478bd9Sstevel@tonic-gate * Caller's context 2317c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate void * 2347c478bd9Sstevel@tonic-gate exacct_create_header(size_t *sizep) 2357c478bd9Sstevel@tonic-gate { 2367c478bd9Sstevel@tonic-gate ea_object_t *hdr_grp; 2377c478bd9Sstevel@tonic-gate uint32_t bskip; 2387c478bd9Sstevel@tonic-gate void *buf; 2397c478bd9Sstevel@tonic-gate size_t bufsize; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER); 2427c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0, 2437c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_VERSION); 2447c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_header, 0, 2457c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_FILETYPE); 2467c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0, 2477c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_CREATOR); 2487c478bd9Sstevel@tonic-gate (void) ea_attach_item(hdr_grp, uts_nodename(), 0, 2497c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(hdr_grp, NULL, 0); 2527c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 2537c478bd9Sstevel@tonic-gate (void) ea_pack_object(hdr_grp, buf, bufsize); 2547c478bd9Sstevel@tonic-gate ea_free_object(hdr_grp, EUP_ALLOC); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * To prevent reading the header when reading the file backwards, 2587c478bd9Sstevel@tonic-gate * set the large backskip of the header group to 0 (last 4 bytes). 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate bskip = 0; 2617c478bd9Sstevel@tonic-gate exacct_order32(&bskip); 2627c478bd9Sstevel@tonic-gate bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip), 2637c478bd9Sstevel@tonic-gate sizeof (bskip)); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate *sizep = bufsize; 2667c478bd9Sstevel@tonic-gate return (buf); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * int exacct_write_header(ac_info_t *, void *, size_t) 2717c478bd9Sstevel@tonic-gate * 2727c478bd9Sstevel@tonic-gate * Overview 2737c478bd9Sstevel@tonic-gate * exacct_write_header() writes the given header buffer to the indicated 274074e084fSml93401 * vnode. 2757c478bd9Sstevel@tonic-gate * 2767c478bd9Sstevel@tonic-gate * Return values 2777c478bd9Sstevel@tonic-gate * The result of the write operation is returned. 2787c478bd9Sstevel@tonic-gate * 2797c478bd9Sstevel@tonic-gate * Caller's context 280074e084fSml93401 * Caller must hold the ac_lock of the appropriate accounting file 2817c478bd9Sstevel@tonic-gate * information block (ac_info_t). 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate int 2847c478bd9Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize) 2857c478bd9Sstevel@tonic-gate { 286074e084fSml93401 if (info != NULL && info->ac_vnode != NULL) 287074e084fSml93401 return (exacct_vn_write_impl(info, hdr, hdrsize)); 2887c478bd9Sstevel@tonic-gate 289074e084fSml93401 return (0); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate static void 2937c478bd9Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu, 2947c478bd9Sstevel@tonic-gate task_usage_t **tu_buf) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate task_usage_t *oldtu, *newtu; 2977c478bd9Sstevel@tonic-gate task_usage_t **prevusage; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tk->tk_usage_lock)); 3007c478bd9Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) { 3017c478bd9Sstevel@tonic-gate prevusage = &tk->tk_zoneusage; 3027c478bd9Sstevel@tonic-gate } else { 3037c478bd9Sstevel@tonic-gate prevusage = &tk->tk_prevusage; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate if ((oldtu = *prevusage) != NULL) { 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * In case we have any accounting information 3087c478bd9Sstevel@tonic-gate * saved from the previous interval record. 3097c478bd9Sstevel@tonic-gate */ 3107c478bd9Sstevel@tonic-gate newtu = *tu_buf; 3117c478bd9Sstevel@tonic-gate bcopy(tu, newtu, sizeof (task_usage_t)); 3127c478bd9Sstevel@tonic-gate tu->tu_minflt -= oldtu->tu_minflt; 3137c478bd9Sstevel@tonic-gate tu->tu_majflt -= oldtu->tu_majflt; 3147c478bd9Sstevel@tonic-gate tu->tu_sndmsg -= oldtu->tu_sndmsg; 3157c478bd9Sstevel@tonic-gate tu->tu_rcvmsg -= oldtu->tu_rcvmsg; 3167c478bd9Sstevel@tonic-gate tu->tu_ioch -= oldtu->tu_ioch; 3177c478bd9Sstevel@tonic-gate tu->tu_iblk -= oldtu->tu_iblk; 3187c478bd9Sstevel@tonic-gate tu->tu_oblk -= oldtu->tu_oblk; 3197c478bd9Sstevel@tonic-gate tu->tu_vcsw -= oldtu->tu_vcsw; 3207c478bd9Sstevel@tonic-gate tu->tu_icsw -= oldtu->tu_icsw; 3217c478bd9Sstevel@tonic-gate tu->tu_nsig -= oldtu->tu_nsig; 3227c478bd9Sstevel@tonic-gate tu->tu_nswp -= oldtu->tu_nswp; 3237c478bd9Sstevel@tonic-gate tu->tu_nscl -= oldtu->tu_nscl; 3247c478bd9Sstevel@tonic-gate tu->tu_utime -= oldtu->tu_utime; 3257c478bd9Sstevel@tonic-gate tu->tu_stime -= oldtu->tu_stime; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate tu->tu_startsec = oldtu->tu_finishsec; 3287c478bd9Sstevel@tonic-gate tu->tu_startnsec = oldtu->tu_finishnsec; 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * Copy the data from our temporary storage to the task's 3317c478bd9Sstevel@tonic-gate * previous interval usage structure for future reference. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate bcopy(newtu, oldtu, sizeof (task_usage_t)); 3347c478bd9Sstevel@tonic-gate } else { 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * Store current statistics in the task's previous interval 3377c478bd9Sstevel@tonic-gate * usage structure for future references. 3387c478bd9Sstevel@tonic-gate */ 3397c478bd9Sstevel@tonic-gate *prevusage = *tu_buf; 3407c478bd9Sstevel@tonic-gate bcopy(tu, *prevusage, sizeof (task_usage_t)); 3417c478bd9Sstevel@tonic-gate *tu_buf = NULL; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate static void 3467c478bd9Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu) 3477c478bd9Sstevel@tonic-gate { 3487c478bd9Sstevel@tonic-gate timestruc_t ts; 3497c478bd9Sstevel@tonic-gate proc_t *p; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if ((p = tk->tk_memb_list) == NULL) 3547c478bd9Sstevel@tonic-gate return; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * exacct_snapshot_task_usage() provides an approximate snapshot of the 3587c478bd9Sstevel@tonic-gate * usage of the potentially many members of the task. Since we don't 3597c478bd9Sstevel@tonic-gate * guarantee exactness, we don't acquire the p_lock of any of the member 3607c478bd9Sstevel@tonic-gate * processes. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate do { 3637c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3647c478bd9Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 3657c478bd9Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 3667c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3677c478bd9Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 3687c478bd9Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 3697c478bd9Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 3707c478bd9Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 3717c478bd9Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 3727c478bd9Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 3737c478bd9Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 3747c478bd9Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 3757c478bd9Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 3767c478bd9Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 3777c478bd9Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 3787c478bd9Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 3797c478bd9Sstevel@tonic-gate } while ((p = p->p_tasknext) != tk->tk_memb_list); 3807c478bd9Sstevel@tonic-gate 3817eceb558Srh87107 /* 3827eceb558Srh87107 * The resource usage accounted for so far will include that 3837eceb558Srh87107 * contributed by the task's first process. If this process 3847eceb558Srh87107 * came from another task, then its accumulated resource usage 3857eceb558Srh87107 * will include a contribution from work performed there. 3867eceb558Srh87107 * We must therefore subtract any resource usage that was 3877eceb558Srh87107 * inherited with the first process. 3887eceb558Srh87107 */ 3897eceb558Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 3907eceb558Srh87107 3917c478bd9Sstevel@tonic-gate gethrestime(&ts); 3927c478bd9Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 3937c478bd9Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977eceb558Srh87107 * void exacct_update_task_mstate(proc_t *) 3987eceb558Srh87107 * 3997eceb558Srh87107 * Overview 4007eceb558Srh87107 * exacct_update_task_mstate() updates the task usage; it is intended 4017eceb558Srh87107 * to be called from proc_exit(). 4027eceb558Srh87107 * 4037eceb558Srh87107 * Return values 4047eceb558Srh87107 * None. 4057eceb558Srh87107 * 4067eceb558Srh87107 * Caller's context 4077eceb558Srh87107 * p_lock must be held at entry. 4087c478bd9Sstevel@tonic-gate */ 4097eceb558Srh87107 void 4107c478bd9Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p) 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate task_usage_t *tu; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate mutex_enter(&p->p_task->tk_usage_lock); 4157c478bd9Sstevel@tonic-gate tu = p->p_task->tk_usage; 4167c478bd9Sstevel@tonic-gate tu->tu_utime += mstate_aggr_state(p, LMS_USER); 4177c478bd9Sstevel@tonic-gate tu->tu_stime += mstate_aggr_state(p, LMS_SYSTEM); 4187c478bd9Sstevel@tonic-gate tu->tu_minflt += p->p_ru.minflt; 4197c478bd9Sstevel@tonic-gate tu->tu_majflt += p->p_ru.majflt; 4207c478bd9Sstevel@tonic-gate tu->tu_sndmsg += p->p_ru.msgsnd; 4217c478bd9Sstevel@tonic-gate tu->tu_rcvmsg += p->p_ru.msgrcv; 4227c478bd9Sstevel@tonic-gate tu->tu_ioch += p->p_ru.ioch; 4237c478bd9Sstevel@tonic-gate tu->tu_iblk += p->p_ru.inblock; 4247c478bd9Sstevel@tonic-gate tu->tu_oblk += p->p_ru.oublock; 4257c478bd9Sstevel@tonic-gate tu->tu_vcsw += p->p_ru.nvcsw; 4267c478bd9Sstevel@tonic-gate tu->tu_icsw += p->p_ru.nivcsw; 4277c478bd9Sstevel@tonic-gate tu->tu_nsig += p->p_ru.nsignals; 4287c478bd9Sstevel@tonic-gate tu->tu_nswp += p->p_ru.nswap; 4297c478bd9Sstevel@tonic-gate tu->tu_nscl += p->p_ru.sysc; 4307c478bd9Sstevel@tonic-gate mutex_exit(&p->p_task->tk_usage_lock); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate static void 4347c478bd9Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate timestruc_t ts; 4377c478bd9Sstevel@tonic-gate task_usage_t *tu_buf; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate switch (flag) { 4407c478bd9Sstevel@tonic-gate case EW_PARTIAL: 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * For partial records we must report the sum of current 4437c478bd9Sstevel@tonic-gate * accounting statistics with previously accumulated 4447c478bd9Sstevel@tonic-gate * statistics. 4457c478bd9Sstevel@tonic-gate */ 4467c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 4477c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4507c478bd9Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4537c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 4547c478bd9Sstevel@tonic-gate break; 4557c478bd9Sstevel@tonic-gate case EW_INTERVAL: 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * We need to allocate spare task_usage_t buffer before 4587c478bd9Sstevel@tonic-gate * grabbing pidlock because we might need it later in 4597c478bd9Sstevel@tonic-gate * exacct_get_interval_task_usage(). 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 4627c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 4637c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * For interval records, we deduct the previous microstate 4677c478bd9Sstevel@tonic-gate * accounting data and cpu usage times from previously saved 4687c478bd9Sstevel@tonic-gate * results and update the previous task usage structure. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4717c478bd9Sstevel@tonic-gate exacct_snapshot_task_usage(tk, tu); 4727c478bd9Sstevel@tonic-gate exacct_get_interval_task_usage(tk, tu, &tu_buf); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4757c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (tu_buf != NULL) 4787c478bd9Sstevel@tonic-gate kmem_free(tu_buf, sizeof (task_usage_t)); 4797c478bd9Sstevel@tonic-gate break; 4807c478bd9Sstevel@tonic-gate case EW_FINAL: 4817c478bd9Sstevel@tonic-gate /* 4827eceb558Srh87107 * For final records, we deduct, from the task's current 4837eceb558Srh87107 * usage, any usage that was inherited with the arrival 4847eceb558Srh87107 * of a process from a previous task. We then record 4857eceb558Srh87107 * the task's finish time. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 4887c478bd9Sstevel@tonic-gate (void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t)); 4897eceb558Srh87107 exacct_sub_task_mstate(tu, tk->tk_inherited); 4907c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate gethrestime(&ts); 4937c478bd9Sstevel@tonic-gate tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 4947c478bd9Sstevel@tonic-gate tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate break; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate static int 5017c478bd9Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record, 5027c478bd9Sstevel@tonic-gate int res) 5037c478bd9Sstevel@tonic-gate { 5047c478bd9Sstevel@tonic-gate int attached = 1; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate switch (res) { 5077c478bd9Sstevel@tonic-gate case AC_TASK_TASKID: 5087c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_tkid, 5097c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID); 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate case AC_TASK_PROJID: 5127c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tk->tk_proj->kpj_id, 5137c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID); 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate case AC_TASK_CPU: { 5167c478bd9Sstevel@tonic-gate timestruc_t ts; 5177c478bd9Sstevel@tonic-gate uint64_t ui; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate hrt2ts(tu->tu_stime, &ts); 5207c478bd9Sstevel@tonic-gate ui = ts.tv_sec; 5217c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5227c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_SEC); 5237c478bd9Sstevel@tonic-gate ui = ts.tv_nsec; 5247c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5257c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC); 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate hrt2ts(tu->tu_utime, &ts); 5287c478bd9Sstevel@tonic-gate ui = ts.tv_sec; 5297c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5307c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_SEC); 5317c478bd9Sstevel@tonic-gate ui = ts.tv_nsec; 5327c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &ui, sizeof (uint64_t), 5337c478bd9Sstevel@tonic-gate EXT_UINT64 | EXD_TASK_CPU_USER_NSEC); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate break; 5367c478bd9Sstevel@tonic-gate case AC_TASK_TIME: 5377c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startsec, 5387c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC); 5397c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_startnsec, 5407c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC); 5417c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishsec, 5427c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC); 5437c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_finishnsec, 5447c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC); 5457c478bd9Sstevel@tonic-gate break; 5467c478bd9Sstevel@tonic-gate case AC_TASK_HOSTNAME: 5477c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_nodename, 5487c478bd9Sstevel@tonic-gate strlen(tk->tk_zone->zone_nodename) + 1, 5497c478bd9Sstevel@tonic-gate EXT_STRING | EXD_TASK_HOSTNAME); 5507c478bd9Sstevel@tonic-gate break; 5517c478bd9Sstevel@tonic-gate case AC_TASK_MICROSTATE: 5527c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_majflt, 5537c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR); 5547c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_minflt, 5557c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR); 5567c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_sndmsg, 5577c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND); 5587c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_rcvmsg, 5597c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV); 5607c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_iblk, 5617c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN); 5627c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_oblk, 5637c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT); 5647c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_ioch, 5657c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR); 5667c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_vcsw, 5677c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL); 5687c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_icsw, 5697c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV); 5707c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nsig, 5717c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS); 5727c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nswp, 5737c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS); 5747c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_nscl, 5757c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS); 5767c478bd9Sstevel@tonic-gate break; 5777c478bd9Sstevel@tonic-gate case AC_TASK_ANCTASKID: 5787c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &tu->tu_anctaskid, 5797c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID); 5807c478bd9Sstevel@tonic-gate break; 5817c478bd9Sstevel@tonic-gate case AC_TASK_ZONENAME: 5827c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, tk->tk_zone->zone_name, 5837c478bd9Sstevel@tonic-gate strlen(tk->tk_zone->zone_name) + 1, 5847c478bd9Sstevel@tonic-gate EXT_STRING | EXD_TASK_ZONENAME); 5857c478bd9Sstevel@tonic-gate break; 5867c478bd9Sstevel@tonic-gate default: 5877c478bd9Sstevel@tonic-gate attached = 0; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate return (attached); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate static ea_object_t * 5937c478bd9Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask, 5947c478bd9Sstevel@tonic-gate ea_catalog_t record_type) 5957c478bd9Sstevel@tonic-gate { 5967c478bd9Sstevel@tonic-gate int res, count; 5977c478bd9Sstevel@tonic-gate ea_object_t *record; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * Assemble usage values into group. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 6037c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++) 6047c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res)) 6057c478bd9Sstevel@tonic-gate count += exacct_attach_task_item(tk, tu, record, res); 6067c478bd9Sstevel@tonic-gate if (count == 0) { 6077c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 6087c478bd9Sstevel@tonic-gate record = NULL; 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate return (record); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* 6147c478bd9Sstevel@tonic-gate * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *, 6157c478bd9Sstevel@tonic-gate * size_t, size_t *), void *, size_t, size_t *, int) 6167c478bd9Sstevel@tonic-gate * 6177c478bd9Sstevel@tonic-gate * Overview 6187c478bd9Sstevel@tonic-gate * exacct_assemble_task_usage() builds the packed exacct buffer for the 6197c478bd9Sstevel@tonic-gate * indicated task, executes the given callback function, and free the packed 6207c478bd9Sstevel@tonic-gate * buffer. 6217c478bd9Sstevel@tonic-gate * 6227c478bd9Sstevel@tonic-gate * Return values 6237c478bd9Sstevel@tonic-gate * Returns 0 on success; otherwise the appropriate error code is returned. 6247c478bd9Sstevel@tonic-gate * 6257c478bd9Sstevel@tonic-gate * Caller's context 6267c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 6277c478bd9Sstevel@tonic-gate */ 6287c478bd9Sstevel@tonic-gate int 6297c478bd9Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk, 6307c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 6317c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 6347c478bd9Sstevel@tonic-gate ea_object_t *task_record; 6357c478bd9Sstevel@tonic-gate ea_catalog_t record_type; 6367c478bd9Sstevel@tonic-gate task_usage_t *tu; 6377c478bd9Sstevel@tonic-gate void *buf; 6387c478bd9Sstevel@tonic-gate size_t bufsize; 6397c478bd9Sstevel@tonic-gate int ret; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 6447c478bd9Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF) { 6457c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6467c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ); 6497c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate switch (flag) { 6527c478bd9Sstevel@tonic-gate case EW_FINAL: 6537c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_TASK; 6547c478bd9Sstevel@tonic-gate break; 6557c478bd9Sstevel@tonic-gate case EW_PARTIAL: 6567c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_TASK_PARTIAL; 6577c478bd9Sstevel@tonic-gate break; 6587c478bd9Sstevel@tonic-gate case EW_INTERVAL: 6597c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_TASK_INTERVAL; 6607c478bd9Sstevel@tonic-gate break; 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Calculate task usage and assemble it into the task record. 6657c478bd9Sstevel@tonic-gate */ 6667c478bd9Sstevel@tonic-gate tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 6677c478bd9Sstevel@tonic-gate exacct_calculate_task_usage(tk, tu, flag); 6687c478bd9Sstevel@tonic-gate task_record = exacct_assemble_task_record(tk, tu, mask, record_type); 6697c478bd9Sstevel@tonic-gate if (task_record == NULL) { 6707c478bd9Sstevel@tonic-gate /* 6717c478bd9Sstevel@tonic-gate * The current configuration of the accounting system has 6727c478bd9Sstevel@tonic-gate * resulted in records with no data; accordingly, we don't write 6737c478bd9Sstevel@tonic-gate * these, but we return success. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6767c478bd9Sstevel@tonic-gate return (0); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * Pack object into buffer and run callback on it. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(task_record, NULL, 0); 6837c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 6847c478bd9Sstevel@tonic-gate (void) ea_pack_object(task_record, buf, bufsize); 6857c478bd9Sstevel@tonic-gate ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * Free all previously allocated structures. 6897c478bd9Sstevel@tonic-gate */ 6907c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 6917c478bd9Sstevel@tonic-gate ea_free_object(task_record, EUP_ALLOC); 6927c478bd9Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t)); 6937c478bd9Sstevel@tonic-gate return (ret); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * void exacct_commit_task(void *) 6987c478bd9Sstevel@tonic-gate * 6997c478bd9Sstevel@tonic-gate * Overview 7007c478bd9Sstevel@tonic-gate * exacct_commit_task() calculates the final usage for a task, updating the 7017c478bd9Sstevel@tonic-gate * task usage if task accounting is active, and writing a task record if task 7027c478bd9Sstevel@tonic-gate * accounting is active. exacct_commit_task() is intended for being called 7037c478bd9Sstevel@tonic-gate * from a task queue (taskq_t). 7047c478bd9Sstevel@tonic-gate * 7057c478bd9Sstevel@tonic-gate * Return values 7067c478bd9Sstevel@tonic-gate * None. 7077c478bd9Sstevel@tonic-gate * 7087c478bd9Sstevel@tonic-gate * Caller's context 7097c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 7107c478bd9Sstevel@tonic-gate */ 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate void 7137c478bd9Sstevel@tonic-gate exacct_commit_task(void *arg) 7147c478bd9Sstevel@tonic-gate { 7157c478bd9Sstevel@tonic-gate task_t *tk = (task_t *)arg; 7167c478bd9Sstevel@tonic-gate size_t size; 7177c478bd9Sstevel@tonic-gate zone_t *zone = tk->tk_zone; 7187c478bd9Sstevel@tonic-gate struct exacct_globals *acg; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate ASSERT(tk != task0p); 7217c478bd9Sstevel@tonic-gate ASSERT(tk->tk_memb_list == NULL); 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate /* 7247c478bd9Sstevel@tonic-gate * Don't do any extra work if the acctctl module isn't loaded. 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) { 7277c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 7287c478bd9Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7297c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7307c478bd9Sstevel@tonic-gate if (tk->tk_zone != global_zone) { 7317c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 7327c478bd9Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk, 7337c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate /* 7377c478bd9Sstevel@tonic-gate * Release associated project and finalize task. 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate task_end(tk); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate static int 7437c478bd9Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res) 7447c478bd9Sstevel@tonic-gate { 7457c478bd9Sstevel@tonic-gate int attached = 1; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate switch (res) { 7487c478bd9Sstevel@tonic-gate case AC_PROC_PID: 7497c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_pid, 7507c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID); 7517c478bd9Sstevel@tonic-gate break; 7527c478bd9Sstevel@tonic-gate case AC_PROC_UID: 7537c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ruid, 7547c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID); 7557c478bd9Sstevel@tonic-gate break; 7567c478bd9Sstevel@tonic-gate case AC_PROC_FLAG: 7577c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_acflag, 7587c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS); 7597c478bd9Sstevel@tonic-gate break; 7607c478bd9Sstevel@tonic-gate case AC_PROC_GID: 7617c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rgid, 7627c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID); 7637c478bd9Sstevel@tonic-gate break; 7647c478bd9Sstevel@tonic-gate case AC_PROC_PROJID: 7657c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_projid, 7667c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID); 7677c478bd9Sstevel@tonic-gate break; 7687c478bd9Sstevel@tonic-gate case AC_PROC_TASKID: 7697c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_taskid, 7707c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID); 7717c478bd9Sstevel@tonic-gate break; 7727c478bd9Sstevel@tonic-gate case AC_PROC_CPU: 7737c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimesec, 7747c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC); 7757c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimensec, 7767c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC); 7777c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimesec, 7787c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC); 7797c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimensec, 7807c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC); 7817c478bd9Sstevel@tonic-gate break; 7827c478bd9Sstevel@tonic-gate case AC_PROC_TIME: 7837c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startsec, 7847c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC); 7857c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startnsec, 7867c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC); 7877c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishsec, 7887c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC); 7897c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishnsec, 7907c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC); 7917c478bd9Sstevel@tonic-gate break; 7927c478bd9Sstevel@tonic-gate case AC_PROC_COMMAND: 7937c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_command, 7947c478bd9Sstevel@tonic-gate strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND); 7957c478bd9Sstevel@tonic-gate break; 7967c478bd9Sstevel@tonic-gate case AC_PROC_HOSTNAME: 7977c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_nodename, 7987c478bd9Sstevel@tonic-gate strlen(pu->pu_nodename) + 1, 7997c478bd9Sstevel@tonic-gate EXT_STRING | EXD_PROC_HOSTNAME); 8007c478bd9Sstevel@tonic-gate break; 8017c478bd9Sstevel@tonic-gate case AC_PROC_TTY: 8027c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_major, 8037c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR); 8047c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minor, 8057c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR); 8067c478bd9Sstevel@tonic-gate break; 8077c478bd9Sstevel@tonic-gate case AC_PROC_MICROSTATE: 8087c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_majflt, 8097c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR); 8107c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minflt, 8117c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR); 8127c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_sndmsg, 8137c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND); 8147c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rcvmsg, 8157c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV); 8167c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_iblk, 8177c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN); 8187c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_oblk, 8197c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT); 8207c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ioch, 8217c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR); 8227c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_vcsw, 8237c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL); 8247c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_icsw, 8257c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV); 8267c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nsig, 8277c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS); 8287c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nswp, 8297c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS); 8307c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nscl, 8317c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS); 8327c478bd9Sstevel@tonic-gate break; 8337c478bd9Sstevel@tonic-gate case AC_PROC_ANCPID: 8347c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ancpid, 8357c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID); 8367c478bd9Sstevel@tonic-gate break; 8377c478bd9Sstevel@tonic-gate case AC_PROC_WAIT_STATUS: 8387c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_wstat, 8397c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS); 8407c478bd9Sstevel@tonic-gate break; 8417c478bd9Sstevel@tonic-gate case AC_PROC_ZONENAME: 8427c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_zonename, 8437c478bd9Sstevel@tonic-gate strlen(pu->pu_zonename) + 1, 8447c478bd9Sstevel@tonic-gate EXT_STRING | EXD_PROC_ZONENAME); 8457c478bd9Sstevel@tonic-gate break; 8467c478bd9Sstevel@tonic-gate case AC_PROC_MEM: 8477c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_avg, 8487c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K); 8497c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_max, 8507c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K); 8517c478bd9Sstevel@tonic-gate break; 8527c478bd9Sstevel@tonic-gate default: 8537c478bd9Sstevel@tonic-gate attached = 0; 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate return (attached); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate static ea_object_t * 8597c478bd9Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask, 8607c478bd9Sstevel@tonic-gate ea_catalog_t record_type) 8617c478bd9Sstevel@tonic-gate { 8627c478bd9Sstevel@tonic-gate int res, count; 8637c478bd9Sstevel@tonic-gate ea_object_t *record; 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * Assemble usage values into group. 8677c478bd9Sstevel@tonic-gate */ 8687c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 8697c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++) 8707c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res)) 8717c478bd9Sstevel@tonic-gate count += exacct_attach_proc_item(pu, record, res); 8727c478bd9Sstevel@tonic-gate if (count == 0) { 8737c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 8747c478bd9Sstevel@tonic-gate record = NULL; 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate return (record); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate /* 8807c478bd9Sstevel@tonic-gate * The following two routines assume that process's p_lock is held or 8817c478bd9Sstevel@tonic-gate * exacct_commit_proc has been called from exit() when all lwps are stopped. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate static void 8847c478bd9Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate kthread_t *t; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 8897c478bd9Sstevel@tonic-gate if ((t = p->p_tlist) == NULL) 8907c478bd9Sstevel@tonic-gate return; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate do { 8937c478bd9Sstevel@tonic-gate pu->pu_minflt += t->t_lwp->lwp_ru.minflt; 8947c478bd9Sstevel@tonic-gate pu->pu_majflt += t->t_lwp->lwp_ru.majflt; 8957c478bd9Sstevel@tonic-gate pu->pu_sndmsg += t->t_lwp->lwp_ru.msgsnd; 8967c478bd9Sstevel@tonic-gate pu->pu_rcvmsg += t->t_lwp->lwp_ru.msgrcv; 8977c478bd9Sstevel@tonic-gate pu->pu_ioch += t->t_lwp->lwp_ru.ioch; 8987c478bd9Sstevel@tonic-gate pu->pu_iblk += t->t_lwp->lwp_ru.inblock; 8997c478bd9Sstevel@tonic-gate pu->pu_oblk += t->t_lwp->lwp_ru.oublock; 9007c478bd9Sstevel@tonic-gate pu->pu_vcsw += t->t_lwp->lwp_ru.nvcsw; 9017c478bd9Sstevel@tonic-gate pu->pu_icsw += t->t_lwp->lwp_ru.nivcsw; 9027c478bd9Sstevel@tonic-gate pu->pu_nsig += t->t_lwp->lwp_ru.nsignals; 9037c478bd9Sstevel@tonic-gate pu->pu_nswp += t->t_lwp->lwp_ru.nswap; 9047c478bd9Sstevel@tonic-gate pu->pu_nscl += t->t_lwp->lwp_ru.sysc; 9057c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate static void 9097c478bd9Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu) 9107c478bd9Sstevel@tonic-gate { 9117c478bd9Sstevel@tonic-gate pu->pu_minflt = p->p_ru.minflt; 9127c478bd9Sstevel@tonic-gate pu->pu_majflt = p->p_ru.majflt; 9137c478bd9Sstevel@tonic-gate pu->pu_sndmsg = p->p_ru.msgsnd; 9147c478bd9Sstevel@tonic-gate pu->pu_rcvmsg = p->p_ru.msgrcv; 9157c478bd9Sstevel@tonic-gate pu->pu_ioch = p->p_ru.ioch; 9167c478bd9Sstevel@tonic-gate pu->pu_iblk = p->p_ru.inblock; 9177c478bd9Sstevel@tonic-gate pu->pu_oblk = p->p_ru.oublock; 9187c478bd9Sstevel@tonic-gate pu->pu_vcsw = p->p_ru.nvcsw; 9197c478bd9Sstevel@tonic-gate pu->pu_icsw = p->p_ru.nivcsw; 9207c478bd9Sstevel@tonic-gate pu->pu_nsig = p->p_ru.nsignals; 9217c478bd9Sstevel@tonic-gate pu->pu_nswp = p->p_ru.nswap; 9227c478bd9Sstevel@tonic-gate pu->pu_nscl = p->p_ru.sysc; 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate void 9267c478bd9Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask, 9277c478bd9Sstevel@tonic-gate int flag, int wstat) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate timestruc_t ts, ts_run; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * Convert CPU and execution times to sec/nsec format. 9357c478bd9Sstevel@tonic-gate */ 9367c478bd9Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_CPU)) { 9377c478bd9Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_USER), &ts); 9387c478bd9Sstevel@tonic-gate pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec; 9397c478bd9Sstevel@tonic-gate pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9407c478bd9Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts); 9417c478bd9Sstevel@tonic-gate pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec; 9427c478bd9Sstevel@tonic-gate pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_TIME)) { 9457c478bd9Sstevel@tonic-gate gethrestime(&ts); 9467c478bd9Sstevel@tonic-gate pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec; 9477c478bd9Sstevel@tonic-gate pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9487c478bd9Sstevel@tonic-gate hrt2ts(gethrtime() - p->p_mstart, &ts_run); 9497c478bd9Sstevel@tonic-gate ts.tv_sec -= ts_run.tv_sec; 9507c478bd9Sstevel@tonic-gate ts.tv_nsec -= ts_run.tv_nsec; 9517c478bd9Sstevel@tonic-gate if (ts.tv_nsec < 0) { 9527c478bd9Sstevel@tonic-gate ts.tv_sec--; 9537c478bd9Sstevel@tonic-gate if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) { 9547c478bd9Sstevel@tonic-gate ts.tv_sec++; 9557c478bd9Sstevel@tonic-gate ts.tv_nsec -= NANOSEC; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec; 9597c478bd9Sstevel@tonic-gate pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate pu->pu_pid = p->p_pidp->pid_id; 9637c478bd9Sstevel@tonic-gate pu->pu_acflag = p->p_user.u_acflag; 9647c478bd9Sstevel@tonic-gate pu->pu_projid = p->p_task->tk_proj->kpj_id; 9657c478bd9Sstevel@tonic-gate pu->pu_taskid = p->p_task->tk_tkid; 9667c478bd9Sstevel@tonic-gate pu->pu_major = getmajor(p->p_sessp->s_dev); 9677c478bd9Sstevel@tonic-gate pu->pu_minor = getminor(p->p_sessp->s_dev); 9687c478bd9Sstevel@tonic-gate pu->pu_ancpid = p->p_ancpid; 9697c478bd9Sstevel@tonic-gate pu->pu_wstat = wstat; 9707c478bd9Sstevel@tonic-gate /* 9717c478bd9Sstevel@tonic-gate * Compute average RSS in K. The denominator is the number of 9727c478bd9Sstevel@tonic-gate * samples: the number of clock ticks plus the initial value. 9737c478bd9Sstevel@tonic-gate */ 9747c478bd9Sstevel@tonic-gate pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) * 9757c478bd9Sstevel@tonic-gate (PAGESIZE / 1024); 9767c478bd9Sstevel@tonic-gate pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024); 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate mutex_enter(&p->p_crlock); 9797c478bd9Sstevel@tonic-gate pu->pu_ruid = crgetruid(p->p_cred); 9807c478bd9Sstevel@tonic-gate pu->pu_rgid = crgetrgid(p->p_cred); 9817c478bd9Sstevel@tonic-gate mutex_exit(&p->p_crlock); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1); 9847c478bd9Sstevel@tonic-gate bcopy(p->p_zone->zone_name, pu->pu_zonename, 9857c478bd9Sstevel@tonic-gate strlen(p->p_zone->zone_name) + 1); 9867c478bd9Sstevel@tonic-gate bcopy(p->p_zone->zone_nodename, pu->pu_nodename, 9877c478bd9Sstevel@tonic-gate strlen(p->p_zone->zone_nodename) + 1); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * Calculate microstate accounting data for a process that is still 9917c478bd9Sstevel@tonic-gate * running. Presently, we explicitly collect all of the LWP usage into 9927c478bd9Sstevel@tonic-gate * the proc usage structure here. 9937c478bd9Sstevel@tonic-gate */ 9947c478bd9Sstevel@tonic-gate if (flag & EW_PARTIAL) 9957c478bd9Sstevel@tonic-gate exacct_calculate_proc_mstate(p, pu); 9967c478bd9Sstevel@tonic-gate if (flag & EW_FINAL) 9977c478bd9Sstevel@tonic-gate exacct_copy_proc_mstate(p, pu); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate /* 10017c478bd9Sstevel@tonic-gate * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void 10027c478bd9Sstevel@tonic-gate * *, size_t, size_t *), void *, size_t, size_t *) 10037c478bd9Sstevel@tonic-gate * 10047c478bd9Sstevel@tonic-gate * Overview 10057c478bd9Sstevel@tonic-gate * Assemble record with miscellaneous accounting information about the process 10067c478bd9Sstevel@tonic-gate * and execute the callback on it. It is the callback's job to set "actual" to 10077c478bd9Sstevel@tonic-gate * the size of record. 10087c478bd9Sstevel@tonic-gate * 10097c478bd9Sstevel@tonic-gate * Return values 10107c478bd9Sstevel@tonic-gate * The result of the callback function, unless the extended process accounting 10117c478bd9Sstevel@tonic-gate * feature is not active, in which case ENOTACTIVE is returned. 10127c478bd9Sstevel@tonic-gate * 10137c478bd9Sstevel@tonic-gate * Caller's context 10147c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate int 10177c478bd9Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu, 10187c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 10197c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag) 10207c478bd9Sstevel@tonic-gate { 10217c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 10227c478bd9Sstevel@tonic-gate ea_object_t *proc_record; 10237c478bd9Sstevel@tonic-gate ea_catalog_t record_type; 10247c478bd9Sstevel@tonic-gate void *buf; 10257c478bd9Sstevel@tonic-gate size_t bufsize; 10267c478bd9Sstevel@tonic-gate int ret; 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 10317c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF) { 10327c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10337c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 10367c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate switch (flag) { 10397c478bd9Sstevel@tonic-gate case EW_FINAL: 10407c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_PROC; 10417c478bd9Sstevel@tonic-gate break; 10427c478bd9Sstevel@tonic-gate case EW_PARTIAL: 10437c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_PROC_PARTIAL; 10447c478bd9Sstevel@tonic-gate break; 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate proc_record = exacct_assemble_proc_record(pu, mask, record_type); 10487c478bd9Sstevel@tonic-gate if (proc_record == NULL) 10497c478bd9Sstevel@tonic-gate return (0); 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate /* 10527c478bd9Sstevel@tonic-gate * Pack object into buffer and pass to callback. 10537c478bd9Sstevel@tonic-gate */ 10547c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(proc_record, NULL, 0); 10557c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 10567c478bd9Sstevel@tonic-gate (void) ea_pack_object(proc_record, buf, bufsize); 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual); 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate /* 10617c478bd9Sstevel@tonic-gate * Free all previously allocations. 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 10647c478bd9Sstevel@tonic-gate ea_free_object(proc_record, EUP_ALLOC); 10657c478bd9Sstevel@tonic-gate return (ret); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /* 10697c478bd9Sstevel@tonic-gate * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t, 10707c478bd9Sstevel@tonic-gate * size_t *) 10717c478bd9Sstevel@tonic-gate * 10727c478bd9Sstevel@tonic-gate * Overview 10737c478bd9Sstevel@tonic-gate * exacct_commit_callback() writes the indicated buffer to the indicated 10747c478bd9Sstevel@tonic-gate * extended accounting file. 10757c478bd9Sstevel@tonic-gate * 10767c478bd9Sstevel@tonic-gate * Return values 10777c478bd9Sstevel@tonic-gate * The result of the write operation is returned. "actual" is updated to 10787c478bd9Sstevel@tonic-gate * contain the number of bytes actually written. 10797c478bd9Sstevel@tonic-gate * 10807c478bd9Sstevel@tonic-gate * Caller's context 10817c478bd9Sstevel@tonic-gate * Suitable for a vn_rdwr() operation. 10827c478bd9Sstevel@tonic-gate */ 10837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10847c478bd9Sstevel@tonic-gate int 10857c478bd9Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize, 10867c478bd9Sstevel@tonic-gate void *buf, size_t bufsize, size_t *actual) 10877c478bd9Sstevel@tonic-gate { 10887c478bd9Sstevel@tonic-gate int error = 0; 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate *actual = 0; 10917c478bd9Sstevel@tonic-gate if ((error = exacct_vn_write(info, buf, bufsize)) == 0) 10927c478bd9Sstevel@tonic-gate *actual = bufsize; 10937c478bd9Sstevel@tonic-gate return (error); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate static void 10977c478bd9Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat) 10987c478bd9Sstevel@tonic-gate { 10997c478bd9Sstevel@tonic-gate size_t size; 11007c478bd9Sstevel@tonic-gate proc_usage_t *pu; 11017c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 11047c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_ON) { 11057c478bd9Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ); 11067c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 11077c478bd9Sstevel@tonic-gate } else { 11087c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 11097c478bd9Sstevel@tonic-gate return; 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 11137c478bd9Sstevel@tonic-gate size = strlen(p->p_user.u_comm) + 1; 11147c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP); 11177c478bd9Sstevel@tonic-gate pu->pu_command = kmem_alloc(size, KM_SLEEP); 11187c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 11197c478bd9Sstevel@tonic-gate exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat); 11207c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate (void) exacct_assemble_proc_usage(ac_proc, pu, 11237c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL); 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate kmem_free(pu->pu_command, strlen(pu->pu_command) + 1); 11267c478bd9Sstevel@tonic-gate kmem_free(pu, sizeof (proc_usage_t)); 11277c478bd9Sstevel@tonic-gate } 11287eceb558Srh87107 11297c478bd9Sstevel@tonic-gate /* 11307c478bd9Sstevel@tonic-gate * void exacct_commit_proc(proc_t *, int) 11317c478bd9Sstevel@tonic-gate * 11327c478bd9Sstevel@tonic-gate * Overview 11337c478bd9Sstevel@tonic-gate * exacct_commit_proc() calculates the final usage for a process, updating the 11347c478bd9Sstevel@tonic-gate * task usage if task accounting is active, and writing a process record if 11357c478bd9Sstevel@tonic-gate * process accounting is active. exacct_commit_proc() is intended for being 11367c478bd9Sstevel@tonic-gate * called from proc_exit(). 11377c478bd9Sstevel@tonic-gate * 11387c478bd9Sstevel@tonic-gate * Return values 11397c478bd9Sstevel@tonic-gate * None. 11407c478bd9Sstevel@tonic-gate * 11417c478bd9Sstevel@tonic-gate * Caller's context 11427c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. p_lock must not be held at entry. 11437c478bd9Sstevel@tonic-gate */ 11447c478bd9Sstevel@tonic-gate void 11457c478bd9Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat) 11467c478bd9Sstevel@tonic-gate { 11477c478bd9Sstevel@tonic-gate zone_t *zone = p->p_zone; 11487c478bd9Sstevel@tonic-gate struct exacct_globals *acg, *gacg = NULL; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 11517c478bd9Sstevel@tonic-gate /* 11527c478bd9Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate return; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone); 11577c478bd9Sstevel@tonic-gate exacct_do_commit_proc(&acg->ac_proc, p, wstat); 11587eceb558Srh87107 if (zone != global_zone) { 11597eceb558Srh87107 gacg = zone_getspecific(exacct_zone_key, global_zone); 11607c478bd9Sstevel@tonic-gate exacct_do_commit_proc(&gacg->ac_proc, p, wstat); 11617c478bd9Sstevel@tonic-gate } 11627eceb558Srh87107 } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate static int 1165*da14cebeSEric Cheng exacct_attach_netstat_item(net_stat_t *ns, ea_object_t *record, int res) 1166*da14cebeSEric Cheng { 1167*da14cebeSEric Cheng int attached = 1; 1168*da14cebeSEric Cheng 1169*da14cebeSEric Cheng switch (res) { 1170*da14cebeSEric Cheng case AC_NET_NAME: 1171*da14cebeSEric Cheng (void) ea_attach_item(record, ns->ns_name, 1172*da14cebeSEric Cheng strlen(ns->ns_name) + 1, EXT_STRING | EXD_NET_STATS_NAME); 1173*da14cebeSEric Cheng break; 1174*da14cebeSEric Cheng case AC_NET_CURTIME: 1175*da14cebeSEric Cheng { 1176*da14cebeSEric Cheng uint64_t now; 1177*da14cebeSEric Cheng timestruc_t ts; 1178*da14cebeSEric Cheng 1179*da14cebeSEric Cheng gethrestime(&ts); 1180*da14cebeSEric Cheng now = (uint64_t)(ulong_t)ts.tv_sec; 1181*da14cebeSEric Cheng (void) ea_attach_item(record, &now, sizeof (uint64_t), 1182*da14cebeSEric Cheng EXT_UINT64 | EXD_NET_STATS_CURTIME); 1183*da14cebeSEric Cheng } 1184*da14cebeSEric Cheng break; 1185*da14cebeSEric Cheng case AC_NET_IBYTES: 1186*da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_ibytes, 1187*da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IBYTES); 1188*da14cebeSEric Cheng break; 1189*da14cebeSEric Cheng case AC_NET_OBYTES: 1190*da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_obytes, 1191*da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OBYTES); 1192*da14cebeSEric Cheng break; 1193*da14cebeSEric Cheng case AC_NET_IPKTS: 1194*da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_ipackets, 1195*da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IPKTS); 1196*da14cebeSEric Cheng break; 1197*da14cebeSEric Cheng case AC_NET_OPKTS: 1198*da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_opackets, 1199*da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OPKTS); 1200*da14cebeSEric Cheng break; 1201*da14cebeSEric Cheng case AC_NET_IERRPKTS: 1202*da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_ierrors, 1203*da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IERRPKTS); 1204*da14cebeSEric Cheng break; 1205*da14cebeSEric Cheng case AC_NET_OERRPKTS: 1206*da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_oerrors, 1207*da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OERRPKTS); 1208*da14cebeSEric Cheng break; 1209*da14cebeSEric Cheng default: 1210*da14cebeSEric Cheng attached = 0; 1211*da14cebeSEric Cheng } 1212*da14cebeSEric Cheng return (attached); 1213*da14cebeSEric Cheng } 1214*da14cebeSEric Cheng 1215*da14cebeSEric Cheng static int 1216*da14cebeSEric Cheng exacct_attach_netdesc_item(net_desc_t *nd, ea_object_t *record, int res) 1217*da14cebeSEric Cheng { 1218*da14cebeSEric Cheng int attached = 1; 1219*da14cebeSEric Cheng 1220*da14cebeSEric Cheng switch (res) { 1221*da14cebeSEric Cheng case AC_NET_NAME: 1222*da14cebeSEric Cheng (void) ea_attach_item(record, nd->nd_name, 1223*da14cebeSEric Cheng strlen(nd->nd_name) + 1, EXT_STRING | EXD_NET_DESC_NAME); 1224*da14cebeSEric Cheng break; 1225*da14cebeSEric Cheng case AC_NET_DEVNAME: 1226*da14cebeSEric Cheng (void) ea_attach_item(record, nd->nd_devname, 1227*da14cebeSEric Cheng strlen(nd->nd_devname) + 1, EXT_STRING | 1228*da14cebeSEric Cheng EXD_NET_DESC_DEVNAME); 1229*da14cebeSEric Cheng break; 1230*da14cebeSEric Cheng case AC_NET_EHOST: 1231*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_ehost, 1232*da14cebeSEric Cheng sizeof (nd->nd_ehost), EXT_RAW | EXD_NET_DESC_EHOST); 1233*da14cebeSEric Cheng break; 1234*da14cebeSEric Cheng case AC_NET_EDEST: 1235*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_edest, 1236*da14cebeSEric Cheng sizeof (nd->nd_edest), EXT_RAW | EXD_NET_DESC_EDEST); 1237*da14cebeSEric Cheng break; 1238*da14cebeSEric Cheng case AC_NET_VLAN_TPID: 1239*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tpid, 1240*da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TPID); 1241*da14cebeSEric Cheng break; 1242*da14cebeSEric Cheng case AC_NET_VLAN_TCI: 1243*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tci, 1244*da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TCI); 1245*da14cebeSEric Cheng break; 1246*da14cebeSEric Cheng case AC_NET_SAP: 1247*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_sap, 1248*da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_SAP); 1249*da14cebeSEric Cheng break; 1250*da14cebeSEric Cheng case AC_NET_PRIORITY: 1251*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_priority, 1252*da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_PRIORITY); 1253*da14cebeSEric Cheng break; 1254*da14cebeSEric Cheng case AC_NET_BWLIMIT: 1255*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_bw_limit, 1256*da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_DESC_BWLIMIT); 1257*da14cebeSEric Cheng break; 1258*da14cebeSEric Cheng case AC_NET_SADDR: 1259*da14cebeSEric Cheng if (nd->nd_isv4) { 1260*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_saddr[3], 1261*da14cebeSEric Cheng sizeof (uint32_t), EXT_UINT32 | 1262*da14cebeSEric Cheng EXD_NET_DESC_V4SADDR); 1263*da14cebeSEric Cheng } else { 1264*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_saddr, 1265*da14cebeSEric Cheng sizeof (nd->nd_saddr), EXT_RAW | 1266*da14cebeSEric Cheng EXD_NET_DESC_V6SADDR); 1267*da14cebeSEric Cheng } 1268*da14cebeSEric Cheng break; 1269*da14cebeSEric Cheng case AC_NET_DADDR: 1270*da14cebeSEric Cheng if (nd->nd_isv4) { 1271*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_daddr[3], 1272*da14cebeSEric Cheng sizeof (uint32_t), EXT_UINT32 | 1273*da14cebeSEric Cheng EXD_NET_DESC_V4DADDR); 1274*da14cebeSEric Cheng } else { 1275*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_daddr, 1276*da14cebeSEric Cheng sizeof (nd->nd_daddr), EXT_RAW | 1277*da14cebeSEric Cheng EXD_NET_DESC_V6DADDR); 1278*da14cebeSEric Cheng } 1279*da14cebeSEric Cheng break; 1280*da14cebeSEric Cheng case AC_NET_SPORT: 1281*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_sport, 1282*da14cebeSEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_SPORT); 1283*da14cebeSEric Cheng break; 1284*da14cebeSEric Cheng case AC_NET_DPORT: 1285*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_dport, 1286*da14cebeSEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_DPORT); 1287*da14cebeSEric Cheng break; 1288*da14cebeSEric Cheng case AC_NET_PROTOCOL: 1289*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_protocol, 1290*da14cebeSEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_PROTOCOL); 1291*da14cebeSEric Cheng break; 1292*da14cebeSEric Cheng case AC_NET_DSFIELD: 1293*da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_dsfield, 1294*da14cebeSEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_DSFIELD); 1295*da14cebeSEric Cheng break; 1296*da14cebeSEric Cheng default: 1297*da14cebeSEric Cheng attached = 0; 1298*da14cebeSEric Cheng } 1299*da14cebeSEric Cheng return (attached); 1300*da14cebeSEric Cheng } 1301*da14cebeSEric Cheng 1302*da14cebeSEric Cheng static ea_object_t * 1303*da14cebeSEric Cheng exacct_assemble_net_record(void *ninfo, ulong_t *mask, ea_catalog_t record_type, 1304*da14cebeSEric Cheng int what) 1305*da14cebeSEric Cheng { 1306*da14cebeSEric Cheng int res; 1307*da14cebeSEric Cheng int count; 1308*da14cebeSEric Cheng ea_object_t *record; 1309*da14cebeSEric Cheng 1310*da14cebeSEric Cheng /* 1311*da14cebeSEric Cheng * Assemble usage values into group. 1312*da14cebeSEric Cheng */ 1313*da14cebeSEric Cheng record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 1314*da14cebeSEric Cheng for (res = 1, count = 0; res <= AC_NET_MAX_RES; res++) 1315*da14cebeSEric Cheng if (BT_TEST(mask, res)) { 1316*da14cebeSEric Cheng if (what == EX_NET_LNDESC_REC || 1317*da14cebeSEric Cheng what == EX_NET_FLDESC_REC) { 1318*da14cebeSEric Cheng count += exacct_attach_netdesc_item( 1319*da14cebeSEric Cheng (net_desc_t *)ninfo, record, res); 1320*da14cebeSEric Cheng } else { 1321*da14cebeSEric Cheng count += exacct_attach_netstat_item( 1322*da14cebeSEric Cheng (net_stat_t *)ninfo, record, res); 1323*da14cebeSEric Cheng } 1324*da14cebeSEric Cheng } 1325*da14cebeSEric Cheng if (count == 0) { 1326*da14cebeSEric Cheng ea_free_object(record, EUP_ALLOC); 1327*da14cebeSEric Cheng record = NULL; 1328*da14cebeSEric Cheng } 1329*da14cebeSEric Cheng return (record); 1330*da14cebeSEric Cheng } 1331*da14cebeSEric Cheng 1332*da14cebeSEric Cheng int 1333*da14cebeSEric Cheng exacct_assemble_net_usage(ac_info_t *ac_net, void *ninfo, 1334*da14cebeSEric Cheng int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 1335*da14cebeSEric Cheng void *ubuf, size_t ubufsize, size_t *actual, int what) 1336*da14cebeSEric Cheng { 1337*da14cebeSEric Cheng ulong_t mask[AC_MASK_SZ]; 1338*da14cebeSEric Cheng ea_object_t *net_desc; 1339*da14cebeSEric Cheng ea_catalog_t record_type; 1340*da14cebeSEric Cheng void *buf; 1341*da14cebeSEric Cheng size_t bufsize; 1342*da14cebeSEric Cheng int ret; 1343*da14cebeSEric Cheng 1344*da14cebeSEric Cheng mutex_enter(&ac_net->ac_lock); 1345*da14cebeSEric Cheng if (ac_net->ac_state == AC_OFF) { 1346*da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock); 1347*da14cebeSEric Cheng return (ENOTACTIVE); 1348*da14cebeSEric Cheng } 1349*da14cebeSEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ); 1350*da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock); 1351*da14cebeSEric Cheng 1352*da14cebeSEric Cheng switch (what) { 1353*da14cebeSEric Cheng case EX_NET_LNDESC_REC: 1354*da14cebeSEric Cheng record_type = EXD_GROUP_NET_LINK_DESC; 1355*da14cebeSEric Cheng break; 1356*da14cebeSEric Cheng case EX_NET_LNSTAT_REC: 1357*da14cebeSEric Cheng record_type = EXD_GROUP_NET_LINK_STATS; 1358*da14cebeSEric Cheng break; 1359*da14cebeSEric Cheng case EX_NET_FLDESC_REC: 1360*da14cebeSEric Cheng record_type = EXD_GROUP_NET_FLOW_DESC; 1361*da14cebeSEric Cheng break; 1362*da14cebeSEric Cheng case EX_NET_FLSTAT_REC: 1363*da14cebeSEric Cheng record_type = EXD_GROUP_NET_FLOW_STATS; 1364*da14cebeSEric Cheng break; 1365*da14cebeSEric Cheng } 1366*da14cebeSEric Cheng 1367*da14cebeSEric Cheng net_desc = exacct_assemble_net_record(ninfo, mask, record_type, what); 1368*da14cebeSEric Cheng if (net_desc == NULL) 1369*da14cebeSEric Cheng return (0); 1370*da14cebeSEric Cheng 1371*da14cebeSEric Cheng /* 1372*da14cebeSEric Cheng * Pack object into buffer and pass to callback. 1373*da14cebeSEric Cheng */ 1374*da14cebeSEric Cheng bufsize = ea_pack_object(net_desc, NULL, 0); 1375*da14cebeSEric Cheng buf = kmem_alloc(bufsize, KM_NOSLEEP); 1376*da14cebeSEric Cheng if (buf == NULL) 1377*da14cebeSEric Cheng return (ENOMEM); 1378*da14cebeSEric Cheng 1379*da14cebeSEric Cheng (void) ea_pack_object(net_desc, buf, bufsize); 1380*da14cebeSEric Cheng 1381*da14cebeSEric Cheng ret = callback(ac_net, ubuf, ubufsize, buf, bufsize, actual); 1382*da14cebeSEric Cheng 1383*da14cebeSEric Cheng /* 1384*da14cebeSEric Cheng * Free all previously allocations. 1385*da14cebeSEric Cheng */ 1386*da14cebeSEric Cheng kmem_free(buf, bufsize); 1387*da14cebeSEric Cheng ea_free_object(net_desc, EUP_ALLOC); 1388*da14cebeSEric Cheng return (ret); 1389*da14cebeSEric Cheng } 1390*da14cebeSEric Cheng 1391*da14cebeSEric Cheng int 1392*da14cebeSEric Cheng exacct_commit_netinfo(void *arg, int what) 1393*da14cebeSEric Cheng { 1394*da14cebeSEric Cheng size_t size; 1395*da14cebeSEric Cheng ulong_t mask[AC_MASK_SZ]; 1396*da14cebeSEric Cheng struct exacct_globals *acg; 1397*da14cebeSEric Cheng ac_info_t *ac_net; 1398*da14cebeSEric Cheng 1399*da14cebeSEric Cheng if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 1400*da14cebeSEric Cheng /* 1401*da14cebeSEric Cheng * acctctl module not loaded. Nothing to do. 1402*da14cebeSEric Cheng */ 1403*da14cebeSEric Cheng return (ENOTACTIVE); 1404*da14cebeSEric Cheng } 1405*da14cebeSEric Cheng 1406*da14cebeSEric Cheng /* 1407*da14cebeSEric Cheng * Even though each zone nominally has its own flow accounting settings 1408*da14cebeSEric Cheng * (ac_flow), these are only maintained by and for the global zone. 1409*da14cebeSEric Cheng * 1410*da14cebeSEric Cheng * If this were to change in the future, this function should grow a 1411*da14cebeSEric Cheng * second zoneid (or zone) argument, and use the corresponding zone's 1412*da14cebeSEric Cheng * settings rather than always using those of the global zone. 1413*da14cebeSEric Cheng */ 1414*da14cebeSEric Cheng acg = zone_getspecific(exacct_zone_key, global_zone); 1415*da14cebeSEric Cheng ac_net = &acg->ac_net; 1416*da14cebeSEric Cheng 1417*da14cebeSEric Cheng mutex_enter(&ac_net->ac_lock); 1418*da14cebeSEric Cheng if (ac_net->ac_state == AC_OFF) { 1419*da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock); 1420*da14cebeSEric Cheng return (ENOTACTIVE); 1421*da14cebeSEric Cheng } 1422*da14cebeSEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ); 1423*da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock); 1424*da14cebeSEric Cheng 1425*da14cebeSEric Cheng return (exacct_assemble_net_usage(ac_net, arg, exacct_commit_callback, 1426*da14cebeSEric Cheng NULL, 0, &size, what)); 1427*da14cebeSEric Cheng } 1428*da14cebeSEric Cheng 1429*da14cebeSEric Cheng static int 14307c478bd9Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res) 14317c478bd9Sstevel@tonic-gate { 14327c478bd9Sstevel@tonic-gate int attached = 1; 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate switch (res) { 14357c478bd9Sstevel@tonic-gate case AC_FLOW_SADDR: 14367c478bd9Sstevel@tonic-gate if (fu->fu_isv4) { 14377c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr[3], 14387c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR); 14397c478bd9Sstevel@tonic-gate } else { 14407c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr, 14417c478bd9Sstevel@tonic-gate sizeof (fu->fu_saddr), EXT_RAW | 14427c478bd9Sstevel@tonic-gate EXD_FLOW_V6SADDR); 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate break; 14457c478bd9Sstevel@tonic-gate case AC_FLOW_DADDR: 14467c478bd9Sstevel@tonic-gate if (fu->fu_isv4) { 14477c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr[3], 14487c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR); 14497c478bd9Sstevel@tonic-gate } else { 14507c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr, 14517c478bd9Sstevel@tonic-gate sizeof (fu->fu_daddr), EXT_RAW | 14527c478bd9Sstevel@tonic-gate EXD_FLOW_V6DADDR); 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate break; 14557c478bd9Sstevel@tonic-gate case AC_FLOW_SPORT: 14567c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_sport, 14577c478bd9Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT); 14587c478bd9Sstevel@tonic-gate break; 14597c478bd9Sstevel@tonic-gate case AC_FLOW_DPORT: 14607c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dport, 14617c478bd9Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT); 14627c478bd9Sstevel@tonic-gate break; 14637c478bd9Sstevel@tonic-gate case AC_FLOW_PROTOCOL: 14647c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_protocol, 14657c478bd9Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL); 14667c478bd9Sstevel@tonic-gate break; 14677c478bd9Sstevel@tonic-gate case AC_FLOW_DSFIELD: 14687c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dsfield, 14697c478bd9Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD); 14707c478bd9Sstevel@tonic-gate break; 14717c478bd9Sstevel@tonic-gate case AC_FLOW_CTIME: 14727c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_ctime, 14737c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME); 14747c478bd9Sstevel@tonic-gate break; 14757c478bd9Sstevel@tonic-gate case AC_FLOW_LSEEN: 14767c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_lseen, 14777c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN); 14787c478bd9Sstevel@tonic-gate break; 14797c478bd9Sstevel@tonic-gate case AC_FLOW_NBYTES: 14807c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_nbytes, 14817c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES); 14827c478bd9Sstevel@tonic-gate break; 14837c478bd9Sstevel@tonic-gate case AC_FLOW_NPKTS: 14847c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_npackets, 14857c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS); 14867c478bd9Sstevel@tonic-gate break; 14877c478bd9Sstevel@tonic-gate case AC_FLOW_PROJID: 14887c478bd9Sstevel@tonic-gate if (fu->fu_projid >= 0) { 14897c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_projid, 14907c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID); 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate break; 14937c478bd9Sstevel@tonic-gate case AC_FLOW_UID: 14947c478bd9Sstevel@tonic-gate if (fu->fu_userid >= 0) { 14957c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_userid, 14967c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID); 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate break; 14997c478bd9Sstevel@tonic-gate case AC_FLOW_ANAME: 15007c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, fu->fu_aname, 15017c478bd9Sstevel@tonic-gate strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME); 15027c478bd9Sstevel@tonic-gate break; 15037c478bd9Sstevel@tonic-gate default: 15047c478bd9Sstevel@tonic-gate attached = 0; 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate return (attached); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate static ea_object_t * 15107c478bd9Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask, 15117c478bd9Sstevel@tonic-gate ea_catalog_t record_type) 15127c478bd9Sstevel@tonic-gate { 15137c478bd9Sstevel@tonic-gate int res, count; 15147c478bd9Sstevel@tonic-gate ea_object_t *record; 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate /* 15177c478bd9Sstevel@tonic-gate * Assemble usage values into group. 15187c478bd9Sstevel@tonic-gate */ 15197c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type); 15207c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++) 15217c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res)) 15227c478bd9Sstevel@tonic-gate count += exacct_attach_flow_item(fu, record, res); 15237c478bd9Sstevel@tonic-gate if (count == 0) { 15247c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC); 15257c478bd9Sstevel@tonic-gate record = NULL; 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate return (record); 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate int 15317c478bd9Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu, 15327c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *), 15337c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual) 15347c478bd9Sstevel@tonic-gate { 15357c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 15367c478bd9Sstevel@tonic-gate ea_object_t *flow_usage; 15377c478bd9Sstevel@tonic-gate ea_catalog_t record_type; 15387c478bd9Sstevel@tonic-gate void *buf; 15397c478bd9Sstevel@tonic-gate size_t bufsize; 15407c478bd9Sstevel@tonic-gate int ret; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 15437c478bd9Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 15447c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 15457c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 15487c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_FLOW; 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate flow_usage = exacct_assemble_flow_record(fu, mask, record_type); 15537c478bd9Sstevel@tonic-gate if (flow_usage == NULL) { 15547c478bd9Sstevel@tonic-gate return (0); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate /* 15587c478bd9Sstevel@tonic-gate * Pack object into buffer and pass to callback. 15597c478bd9Sstevel@tonic-gate */ 15607c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(flow_usage, NULL, 0); 15617c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_NOSLEEP); 15627c478bd9Sstevel@tonic-gate if (buf == NULL) { 15637c478bd9Sstevel@tonic-gate return (ENOMEM); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate (void) ea_pack_object(flow_usage, buf, bufsize); 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate /* 15717c478bd9Sstevel@tonic-gate * Free all previously allocations. 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 15747c478bd9Sstevel@tonic-gate ea_free_object(flow_usage, EUP_ALLOC); 15757c478bd9Sstevel@tonic-gate return (ret); 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate void 15797c478bd9Sstevel@tonic-gate exacct_commit_flow(void *arg) 15807c478bd9Sstevel@tonic-gate { 15817c478bd9Sstevel@tonic-gate flow_usage_t *f = (flow_usage_t *)arg; 15827c478bd9Sstevel@tonic-gate size_t size; 15837c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ]; 15847c478bd9Sstevel@tonic-gate struct exacct_globals *acg; 15857c478bd9Sstevel@tonic-gate ac_info_t *ac_flow; 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) { 15887c478bd9Sstevel@tonic-gate /* 15897c478bd9Sstevel@tonic-gate * acctctl module not loaded. Nothing to do. 15907c478bd9Sstevel@tonic-gate */ 15917c478bd9Sstevel@tonic-gate return; 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate /* 15957c478bd9Sstevel@tonic-gate * Even though each zone nominally has its own flow accounting settings 15967c478bd9Sstevel@tonic-gate * (ac_flow), these are only maintained by and for the global zone. 15977c478bd9Sstevel@tonic-gate * 15987c478bd9Sstevel@tonic-gate * If this were to change in the future, this function should grow a 15997c478bd9Sstevel@tonic-gate * second zoneid (or zone) argument, and use the corresponding zone's 16007c478bd9Sstevel@tonic-gate * settings rather than always using those of the global zone. 16017c478bd9Sstevel@tonic-gate */ 16027c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone); 16037c478bd9Sstevel@tonic-gate ac_flow = &acg->ac_flow; 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock); 16067c478bd9Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) { 16077c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 16087c478bd9Sstevel@tonic-gate return; 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ); 16117c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock); 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate (void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback, 16147c478bd9Sstevel@tonic-gate NULL, 0, &size); 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * int exacct_tag_task(task_t *, void *, size_t, int) 16197c478bd9Sstevel@tonic-gate * 16207c478bd9Sstevel@tonic-gate * Overview 16217c478bd9Sstevel@tonic-gate * exacct_tag_task() provides the exacct record construction and writing 16227c478bd9Sstevel@tonic-gate * support required by putacct(2) for task entities. 16237c478bd9Sstevel@tonic-gate * 16247c478bd9Sstevel@tonic-gate * Return values 16257c478bd9Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 16267c478bd9Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 16277c478bd9Sstevel@tonic-gate * 16287c478bd9Sstevel@tonic-gate * Caller's context 16297c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 16307c478bd9Sstevel@tonic-gate */ 16317c478bd9Sstevel@tonic-gate int 16327c478bd9Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz, 16337c478bd9Sstevel@tonic-gate int flags) 16347c478bd9Sstevel@tonic-gate { 16357c478bd9Sstevel@tonic-gate int error = 0; 16367c478bd9Sstevel@tonic-gate void *buf; 16377c478bd9Sstevel@tonic-gate size_t bufsize; 16387c478bd9Sstevel@tonic-gate ea_catalog_t cat; 16397c478bd9Sstevel@tonic-gate ea_object_t *tag; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock); 16427c478bd9Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) { 16437c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 16447c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock); 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG); 16497c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &tk->tk_tkid, 0, 16507c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 16517c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0, 16527c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 16537c478bd9Sstevel@tonic-gate if (flags == EP_RAW) 16547c478bd9Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG; 16557c478bd9Sstevel@tonic-gate else 16567c478bd9Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG; 16577c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 16607c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 16617c478bd9Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 16627c478bd9Sstevel@tonic-gate error = exacct_vn_write(ac_task, buf, bufsize); 16637c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 16647c478bd9Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 16657c478bd9Sstevel@tonic-gate return (error); 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *) 16707c478bd9Sstevel@tonic-gate * 16717c478bd9Sstevel@tonic-gate * Overview 16727c478bd9Sstevel@tonic-gate * exacct_tag_proc() provides the exacct record construction and writing 16737c478bd9Sstevel@tonic-gate * support required by putacct(2) for processes. 16747c478bd9Sstevel@tonic-gate * 16757c478bd9Sstevel@tonic-gate * Return values 16767c478bd9Sstevel@tonic-gate * The result of the write operation is returned, unless the extended 16777c478bd9Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned. 16787c478bd9Sstevel@tonic-gate * 16797c478bd9Sstevel@tonic-gate * Caller's context 16807c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 16817c478bd9Sstevel@tonic-gate */ 16827c478bd9Sstevel@tonic-gate int 16837c478bd9Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf, 16847c478bd9Sstevel@tonic-gate size_t ubufsz, int flags, const char *hostname) 16857c478bd9Sstevel@tonic-gate { 16867c478bd9Sstevel@tonic-gate int error = 0; 16877c478bd9Sstevel@tonic-gate void *buf; 16887c478bd9Sstevel@tonic-gate size_t bufsize; 16897c478bd9Sstevel@tonic-gate ea_catalog_t cat; 16907c478bd9Sstevel@tonic-gate ea_object_t *tag; 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock); 16937c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) { 16947c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 16957c478bd9Sstevel@tonic-gate return (ENOTACTIVE); 16967c478bd9Sstevel@tonic-gate } 16977c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock); 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG); 17007c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &pid, sizeof (uint32_t), 17017c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID); 17027c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &tkid, 0, 17037c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID); 17047c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, (void *)hostname, 0, 17057c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME); 17067c478bd9Sstevel@tonic-gate if (flags == EP_RAW) 17077c478bd9Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG; 17087c478bd9Sstevel@tonic-gate else 17097c478bd9Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG; 17107c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat); 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0); 17137c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP); 17147c478bd9Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize); 17157c478bd9Sstevel@tonic-gate error = exacct_vn_write(ac_proc, buf, bufsize); 17167c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize); 17177c478bd9Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC); 17187c478bd9Sstevel@tonic-gate return (error); 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate /* 17227c478bd9Sstevel@tonic-gate * void exacct_init(void) 17237c478bd9Sstevel@tonic-gate * 17247c478bd9Sstevel@tonic-gate * Overview 17257c478bd9Sstevel@tonic-gate * Initialized the extended accounting subsystem. 17267c478bd9Sstevel@tonic-gate * 17277c478bd9Sstevel@tonic-gate * Return values 17287c478bd9Sstevel@tonic-gate * None. 17297c478bd9Sstevel@tonic-gate * 17307c478bd9Sstevel@tonic-gate * Caller's context 17317c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. 17327c478bd9Sstevel@tonic-gate */ 17337c478bd9Sstevel@tonic-gate void 17347c478bd9Sstevel@tonic-gate exacct_init() 17357c478bd9Sstevel@tonic-gate { 17367c478bd9Sstevel@tonic-gate exacct_queue = system_taskq; 17377c478bd9Sstevel@tonic-gate exacct_object_cache = kmem_cache_create("exacct_object_cache", 17387c478bd9Sstevel@tonic-gate sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 17397c478bd9Sstevel@tonic-gate } 17407eceb558Srh87107 17417eceb558Srh87107 /* 17427eceb558Srh87107 * exacct_snapshot_proc_mstate() copies a process's microstate accounting data 17437eceb558Srh87107 * and resource usage counters into a given task_usage_t. It differs from 17447eceb558Srh87107 * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t, 17457eceb558Srh87107 * b) p_lock will have been acquired earlier in the call path and c) we 17467eceb558Srh87107 * are here including the process's user and system times. 17477eceb558Srh87107 */ 17487eceb558Srh87107 static void 17497eceb558Srh87107 exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu) 17507eceb558Srh87107 { 17517eceb558Srh87107 tu->tu_utime = mstate_aggr_state(p, LMS_USER); 17527eceb558Srh87107 tu->tu_stime = mstate_aggr_state(p, LMS_SYSTEM); 17537eceb558Srh87107 tu->tu_minflt = p->p_ru.minflt; 17547eceb558Srh87107 tu->tu_majflt = p->p_ru.majflt; 17557eceb558Srh87107 tu->tu_sndmsg = p->p_ru.msgsnd; 17567eceb558Srh87107 tu->tu_rcvmsg = p->p_ru.msgrcv; 17577eceb558Srh87107 tu->tu_ioch = p->p_ru.ioch; 17587eceb558Srh87107 tu->tu_iblk = p->p_ru.inblock; 17597eceb558Srh87107 tu->tu_oblk = p->p_ru.oublock; 17607eceb558Srh87107 tu->tu_vcsw = p->p_ru.nvcsw; 17617eceb558Srh87107 tu->tu_icsw = p->p_ru.nivcsw; 17627eceb558Srh87107 tu->tu_nsig = p->p_ru.nsignals; 17637eceb558Srh87107 tu->tu_nswp = p->p_ru.nswap; 17647eceb558Srh87107 tu->tu_nscl = p->p_ru.sysc; 17657eceb558Srh87107 } 17667eceb558Srh87107 17677eceb558Srh87107 /* 17687eceb558Srh87107 * void exacct_move_mstate(proc_t *, task_t *, task_t *) 17697eceb558Srh87107 * 17707eceb558Srh87107 * Overview 17717eceb558Srh87107 * exacct_move_mstate() is called by task_change() and accounts for 17727eceb558Srh87107 * a process's resource usage when it is moved from one task to another. 17737eceb558Srh87107 * 17747eceb558Srh87107 * The process's usage at this point is recorded in the new task so 17757eceb558Srh87107 * that it can be excluded from the calculation of resources consumed 17767eceb558Srh87107 * by that task. 17777eceb558Srh87107 * 17787eceb558Srh87107 * The resource usage inherited by the new task is also added to the 17797eceb558Srh87107 * aggregate maintained by the old task for processes that have exited. 17807eceb558Srh87107 * 17817eceb558Srh87107 * Return values 17827eceb558Srh87107 * None. 17837eceb558Srh87107 * 17847eceb558Srh87107 * Caller's context 17857eceb558Srh87107 * pidlock and p_lock held across exacct_move_mstate(). 17867eceb558Srh87107 */ 17877eceb558Srh87107 void 17887eceb558Srh87107 exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk) 17897eceb558Srh87107 { 17907eceb558Srh87107 task_usage_t tu; 17917eceb558Srh87107 17927eceb558Srh87107 /* Take a snapshot of this process's mstate and RU counters */ 17937eceb558Srh87107 exacct_snapshot_proc_mstate(p, &tu); 17947eceb558Srh87107 17957eceb558Srh87107 /* 17967eceb558Srh87107 * Use the snapshot to increment the aggregate usage of the old 17977eceb558Srh87107 * task, and the inherited usage of the new one. 17987eceb558Srh87107 */ 17997eceb558Srh87107 mutex_enter(&oldtk->tk_usage_lock); 18007eceb558Srh87107 exacct_add_task_mstate(oldtk->tk_usage, &tu); 18017eceb558Srh87107 mutex_exit(&oldtk->tk_usage_lock); 18027eceb558Srh87107 mutex_enter(&newtk->tk_usage_lock); 18037eceb558Srh87107 exacct_add_task_mstate(newtk->tk_inherited, &tu); 18047eceb558Srh87107 mutex_exit(&newtk->tk_usage_lock); 18057eceb558Srh87107 } 1806