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