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
57eceb558Srh * Common Development and Distribution License (the "License").
67eceb558Srh * 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 *
ea_alloc_item(ea_catalog_t catalog,void * buf,size_t bufsz)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 *
ea_alloc_group(ea_catalog_t catalog)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 *
ea_attach_item(ea_object_t * grp,void * buf,size_t bufsz,ea_catalog_t catalog)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
1017eceb558Srh /*
1027eceb558Srh * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract
1037eceb558Srh * microstate accounting data and resource usage counters from one task_usage_t
1047eceb558Srh * from those supplied in another. These functions do not operate on *all*
1057eceb558Srh * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make
1067eceb558Srh * sense.
1077eceb558Srh */
1087eceb558Srh static void
exacct_add_task_mstate(task_usage_t * tu,task_usage_t * delta)1097eceb558Srh exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta)
1107eceb558Srh {
1117eceb558Srh tu->tu_utime += delta->tu_utime;
1127eceb558Srh tu->tu_stime += delta->tu_stime;
1137eceb558Srh tu->tu_minflt += delta->tu_minflt;
1147eceb558Srh tu->tu_majflt += delta->tu_majflt;
1157eceb558Srh tu->tu_sndmsg += delta->tu_sndmsg;
1167eceb558Srh tu->tu_rcvmsg += delta->tu_rcvmsg;
1177eceb558Srh tu->tu_ioch += delta->tu_ioch;
1187eceb558Srh tu->tu_iblk += delta->tu_iblk;
1197eceb558Srh tu->tu_oblk += delta->tu_oblk;
1207eceb558Srh tu->tu_vcsw += delta->tu_vcsw;
1217eceb558Srh tu->tu_icsw += delta->tu_icsw;
1227eceb558Srh tu->tu_nsig += delta->tu_nsig;
1237eceb558Srh tu->tu_nswp += delta->tu_nswp;
1247eceb558Srh tu->tu_nscl += delta->tu_nscl;
1257eceb558Srh }
1267eceb558Srh
1277eceb558Srh /*
1287eceb558Srh * See the comments for exacct_add_task_mstate(), above.
1297eceb558Srh */
1307eceb558Srh static void
exacct_sub_task_mstate(task_usage_t * tu,task_usage_t * delta)1317eceb558Srh exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta)
1327eceb558Srh {
1337eceb558Srh tu->tu_utime -= delta->tu_utime;
1347eceb558Srh tu->tu_stime -= delta->tu_stime;
1357eceb558Srh tu->tu_minflt -= delta->tu_minflt;
1367eceb558Srh tu->tu_majflt -= delta->tu_majflt;
1377eceb558Srh tu->tu_sndmsg -= delta->tu_sndmsg;
1387eceb558Srh tu->tu_rcvmsg -= delta->tu_rcvmsg;
1397eceb558Srh tu->tu_ioch -= delta->tu_ioch;
1407eceb558Srh tu->tu_iblk -= delta->tu_iblk;
1417eceb558Srh tu->tu_oblk -= delta->tu_oblk;
1427eceb558Srh tu->tu_vcsw -= delta->tu_vcsw;
1437eceb558Srh tu->tu_icsw -= delta->tu_icsw;
1447eceb558Srh tu->tu_nsig -= delta->tu_nsig;
1457eceb558Srh tu->tu_nswp -= delta->tu_nswp;
1467eceb558Srh tu->tu_nscl -= delta->tu_nscl;
1477eceb558Srh }
1487eceb558Srh
1497c478bd9Sstevel@tonic-gate /*
150074e084fSml * Wrapper for vn_rdwr() used by exacct_vn_write() and exacct_write_header()
151074e084fSml * to write to the accounting file without corrupting it in case of an I/O or
152074e084fSml * filesystem error.
1537c478bd9Sstevel@tonic-gate */
1547c478bd9Sstevel@tonic-gate static int
exacct_vn_write_impl(ac_info_t * info,void * buf,ssize_t bufsize)155074e084fSml exacct_vn_write_impl(ac_info_t *info, void *buf, ssize_t bufsize)
1567c478bd9Sstevel@tonic-gate {
157074e084fSml int error;
1587c478bd9Sstevel@tonic-gate ssize_t resid;
1597c478bd9Sstevel@tonic-gate struct vattr va;
1607c478bd9Sstevel@tonic-gate
161074e084fSml ASSERT(info != NULL);
162074e084fSml ASSERT(info->ac_vnode != NULL);
163074e084fSml 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 }
182074e084fSml return (error);
183074e084fSml }
184074e084fSml
185074e084fSml /*
186074e084fSml * exacct_vn_write() safely writes to an accounting file. acctctl() prevents
187074e084fSml * the two accounting vnodes from being equal, and the appropriate ac_lock is
188074e084fSml * held across the call, so we're single threaded through this code for each
189074e084fSml * file.
190074e084fSml */
191074e084fSml static int
exacct_vn_write(ac_info_t * info,void * buf,ssize_t bufsize)192074e084fSml exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize)
193074e084fSml {
194074e084fSml int error;
195074e084fSml
196074e084fSml if (info == NULL)
197074e084fSml return (0);
198074e084fSml
199074e084fSml mutex_enter(&info->ac_lock);
200074e084fSml
201074e084fSml /*
202074e084fSml * Don't do anything unless accounting file is set.
203074e084fSml */
204074e084fSml if (info->ac_vnode == NULL) {
205074e084fSml mutex_exit(&info->ac_lock);
206074e084fSml return (0);
207074e084fSml }
208074e084fSml 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 *
exacct_create_header(size_t * sizep)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
272074e084fSml * 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
278074e084fSml * 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
exacct_write_header(ac_info_t * info,void * hdr,size_t hdrsize)2827c478bd9Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize)
2837c478bd9Sstevel@tonic-gate {
284074e084fSml if (info != NULL && info->ac_vnode != NULL)
285074e084fSml return (exacct_vn_write_impl(info, hdr, hdrsize));
2867c478bd9Sstevel@tonic-gate
287074e084fSml return (0);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate static void
exacct_get_interval_task_usage(task_t * tk,task_usage_t * tu,task_usage_t ** tu_buf)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
exacct_snapshot_task_usage(task_t * tk,task_usage_t * tu)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
3797eceb558Srh /*
3807eceb558Srh * The resource usage accounted for so far will include that
3817eceb558Srh * contributed by the task's first process. If this process
3827eceb558Srh * came from another task, then its accumulated resource usage
3837eceb558Srh * will include a contribution from work performed there.
3847eceb558Srh * We must therefore subtract any resource usage that was
3857eceb558Srh * inherited with the first process.
3867eceb558Srh */
3877eceb558Srh exacct_sub_task_mstate(tu, tk->tk_inherited);
3887eceb558Srh
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 /*
3957eceb558Srh * void exacct_update_task_mstate(proc_t *)
3967eceb558Srh *
3977eceb558Srh * Overview
3987eceb558Srh * exacct_update_task_mstate() updates the task usage; it is intended
3997eceb558Srh * to be called from proc_exit().
4007eceb558Srh *
4017eceb558Srh * Return values
4027eceb558Srh * None.
4037eceb558Srh *
4047eceb558Srh * Caller's context
4057eceb558Srh * p_lock must be held at entry.
4067c478bd9Sstevel@tonic-gate */
4077eceb558Srh void
exacct_update_task_mstate(proc_t * p)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
exacct_calculate_task_usage(task_t * tk,task_usage_t * tu,int flag)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 /*
4807eceb558Srh * For final records, we deduct, from the task's current
4817eceb558Srh * usage, any usage that was inherited with the arrival
4827eceb558Srh * of a process from a previous task. We then record
4837eceb558Srh * 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));
4877eceb558Srh 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
exacct_attach_task_item(task_t * tk,task_usage_t * tu,ea_object_t * record,int res)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 *
exacct_assemble_task_record(task_t * tk,task_usage_t * tu,ulong_t * mask,ea_catalog_t record_type)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
exacct_assemble_task_usage(ac_info_t * ac_task,task_t * tk,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual,int flag)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;
659c6f039c7SToomas Soome default:
660c6f039c7SToomas Soome return (0);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate * Calculate task usage and assemble it into the task record.
6657c478bd9Sstevel@tonic-gate */
6667c478bd9Sstevel@tonic-gate tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
6677c478bd9Sstevel@tonic-gate exacct_calculate_task_usage(tk, tu, flag);
6687c478bd9Sstevel@tonic-gate task_record = exacct_assemble_task_record(tk, tu, mask, record_type);
6697c478bd9Sstevel@tonic-gate if (task_record == NULL) {
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate * The current configuration of the accounting system has
6727c478bd9Sstevel@tonic-gate * resulted in records with no data; accordingly, we don't write
6737c478bd9Sstevel@tonic-gate * these, but we return success.
6747c478bd9Sstevel@tonic-gate */
6757c478bd9Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t));
6767c478bd9Sstevel@tonic-gate return (0);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate * Pack object into buffer and run callback on it.
6817c478bd9Sstevel@tonic-gate */
6827c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(task_record, NULL, 0);
6837c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
6847c478bd9Sstevel@tonic-gate (void) ea_pack_object(task_record, buf, bufsize);
6857c478bd9Sstevel@tonic-gate ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual);
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate * Free all previously allocated structures.
6897c478bd9Sstevel@tonic-gate */
6907c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize);
6917c478bd9Sstevel@tonic-gate ea_free_object(task_record, EUP_ALLOC);
6927c478bd9Sstevel@tonic-gate kmem_free(tu, sizeof (task_usage_t));
6937c478bd9Sstevel@tonic-gate return (ret);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate * void exacct_commit_task(void *)
6987c478bd9Sstevel@tonic-gate *
6997c478bd9Sstevel@tonic-gate * Overview
7007c478bd9Sstevel@tonic-gate * exacct_commit_task() calculates the final usage for a task, updating the
7017c478bd9Sstevel@tonic-gate * task usage if task accounting is active, and writing a task record if task
7027c478bd9Sstevel@tonic-gate * accounting is active. exacct_commit_task() is intended for being called
7037c478bd9Sstevel@tonic-gate * from a task queue (taskq_t).
7047c478bd9Sstevel@tonic-gate *
7057c478bd9Sstevel@tonic-gate * Return values
7067c478bd9Sstevel@tonic-gate * None.
7077c478bd9Sstevel@tonic-gate *
7087c478bd9Sstevel@tonic-gate * Caller's context
7097c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
7107c478bd9Sstevel@tonic-gate */
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate void
exacct_commit_task(void * arg)7137c478bd9Sstevel@tonic-gate exacct_commit_task(void *arg)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate task_t *tk = (task_t *)arg;
7167c478bd9Sstevel@tonic-gate size_t size;
7177c478bd9Sstevel@tonic-gate zone_t *zone = tk->tk_zone;
7187c478bd9Sstevel@tonic-gate struct exacct_globals *acg;
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate ASSERT(tk != task0p);
7217c478bd9Sstevel@tonic-gate ASSERT(tk->tk_memb_list == NULL);
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate * Don't do any extra work if the acctctl module isn't loaded.
7258cb09440SVamsi Nagineni * If acctctl module is loaded when zone is in down state then
7268cb09440SVamsi Nagineni * zone_getspecific can return NULL for that zone.
7277c478bd9Sstevel@tonic-gate */
7287c478bd9Sstevel@tonic-gate if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) {
7297c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone);
7308cb09440SVamsi Nagineni if (acg == NULL)
7318cb09440SVamsi Nagineni goto err;
7327c478bd9Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk,
7337c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7347c478bd9Sstevel@tonic-gate if (tk->tk_zone != global_zone) {
7357c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone);
7367c478bd9Sstevel@tonic-gate (void) exacct_assemble_task_usage(&acg->ac_task, tk,
7377c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate * Release associated project and finalize task.
7427c478bd9Sstevel@tonic-gate */
7438cb09440SVamsi Nagineni err:
7447c478bd9Sstevel@tonic-gate task_end(tk);
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate static int
exacct_attach_proc_item(proc_usage_t * pu,ea_object_t * record,int res)7487c478bd9Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate int attached = 1;
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate switch (res) {
7537c478bd9Sstevel@tonic-gate case AC_PROC_PID:
7547c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_pid,
7557c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID);
7567c478bd9Sstevel@tonic-gate break;
7577c478bd9Sstevel@tonic-gate case AC_PROC_UID:
7587c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ruid,
7597c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID);
7607c478bd9Sstevel@tonic-gate break;
7617c478bd9Sstevel@tonic-gate case AC_PROC_FLAG:
7627c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_acflag,
7637c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS);
7647c478bd9Sstevel@tonic-gate break;
7657c478bd9Sstevel@tonic-gate case AC_PROC_GID:
7667c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rgid,
7677c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID);
7687c478bd9Sstevel@tonic-gate break;
7697c478bd9Sstevel@tonic-gate case AC_PROC_PROJID:
7707c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_projid,
7717c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID);
7727c478bd9Sstevel@tonic-gate break;
7737c478bd9Sstevel@tonic-gate case AC_PROC_TASKID:
7747c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_taskid,
7757c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID);
7767c478bd9Sstevel@tonic-gate break;
7777c478bd9Sstevel@tonic-gate case AC_PROC_CPU:
7787c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimesec,
7797c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC);
7807c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_utimensec,
7817c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC);
7827c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimesec,
7837c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC);
7847c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_stimensec,
7857c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC);
7867c478bd9Sstevel@tonic-gate break;
7877c478bd9Sstevel@tonic-gate case AC_PROC_TIME:
7887c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startsec,
7897c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC);
7907c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_startnsec,
7917c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC);
7927c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishsec,
7937c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC);
7947c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_finishnsec,
7957c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC);
7967c478bd9Sstevel@tonic-gate break;
7977c478bd9Sstevel@tonic-gate case AC_PROC_COMMAND:
7987c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_command,
7997c478bd9Sstevel@tonic-gate strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND);
8007c478bd9Sstevel@tonic-gate break;
8017c478bd9Sstevel@tonic-gate case AC_PROC_HOSTNAME:
8027c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_nodename,
8037c478bd9Sstevel@tonic-gate strlen(pu->pu_nodename) + 1,
8047c478bd9Sstevel@tonic-gate EXT_STRING | EXD_PROC_HOSTNAME);
8057c478bd9Sstevel@tonic-gate break;
8067c478bd9Sstevel@tonic-gate case AC_PROC_TTY:
8077c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_major,
8087c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR);
8097c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minor,
8107c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR);
8117c478bd9Sstevel@tonic-gate break;
8127c478bd9Sstevel@tonic-gate case AC_PROC_MICROSTATE:
8137c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_majflt,
8147c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR);
8157c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_minflt,
8167c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR);
8177c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_sndmsg,
8187c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND);
8197c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_rcvmsg,
8207c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV);
8217c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_iblk,
8227c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN);
8237c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_oblk,
8247c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT);
8257c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ioch,
8267c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR);
8277c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_vcsw,
8287c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL);
8297c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_icsw,
8307c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV);
8317c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nsig,
8327c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS);
8337c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nswp,
8347c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS);
8357c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_nscl,
8367c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS);
8377c478bd9Sstevel@tonic-gate break;
8387c478bd9Sstevel@tonic-gate case AC_PROC_ANCPID:
8397c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_ancpid,
8407c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID);
8417c478bd9Sstevel@tonic-gate break;
8427c478bd9Sstevel@tonic-gate case AC_PROC_WAIT_STATUS:
8437c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_wstat,
8447c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS);
8457c478bd9Sstevel@tonic-gate break;
8467c478bd9Sstevel@tonic-gate case AC_PROC_ZONENAME:
8477c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, pu->pu_zonename,
8487c478bd9Sstevel@tonic-gate strlen(pu->pu_zonename) + 1,
8497c478bd9Sstevel@tonic-gate EXT_STRING | EXD_PROC_ZONENAME);
8507c478bd9Sstevel@tonic-gate break;
8517c478bd9Sstevel@tonic-gate case AC_PROC_MEM:
8527c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_avg,
8537c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K);
8547c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &pu->pu_mem_rss_max,
8557c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K);
8567c478bd9Sstevel@tonic-gate break;
8577c478bd9Sstevel@tonic-gate default:
8587c478bd9Sstevel@tonic-gate attached = 0;
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate return (attached);
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate static ea_object_t *
exacct_assemble_proc_record(proc_usage_t * pu,ulong_t * mask,ea_catalog_t record_type)8647c478bd9Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask,
8657c478bd9Sstevel@tonic-gate ea_catalog_t record_type)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate int res, count;
8687c478bd9Sstevel@tonic-gate ea_object_t *record;
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate * Assemble usage values into group.
8727c478bd9Sstevel@tonic-gate */
8737c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
8747c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++)
8757c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res))
8767eceb558Srh count += exacct_attach_proc_item(pu, record, res);
8777c478bd9Sstevel@tonic-gate if (count == 0) {
8787c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC);
8797c478bd9Sstevel@tonic-gate record = NULL;
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate return (record);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate * The following two routines assume that process's p_lock is held or
8867c478bd9Sstevel@tonic-gate * exacct_commit_proc has been called from exit() when all lwps are stopped.
8877c478bd9Sstevel@tonic-gate */
8887c478bd9Sstevel@tonic-gate static void
exacct_calculate_proc_mstate(proc_t * p,proc_usage_t * pu)8897c478bd9Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate kthread_t *t;
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock));
8947c478bd9Sstevel@tonic-gate if ((t = p->p_tlist) == NULL)
8957c478bd9Sstevel@tonic-gate return;
8967c478bd9Sstevel@tonic-gate
8977c478bd9Sstevel@tonic-gate do {
8987c478bd9Sstevel@tonic-gate pu->pu_minflt += t->t_lwp->lwp_ru.minflt;
8997c478bd9Sstevel@tonic-gate pu->pu_majflt += t->t_lwp->lwp_ru.majflt;
9007c478bd9Sstevel@tonic-gate pu->pu_sndmsg += t->t_lwp->lwp_ru.msgsnd;
9017c478bd9Sstevel@tonic-gate pu->pu_rcvmsg += t->t_lwp->lwp_ru.msgrcv;
9027c478bd9Sstevel@tonic-gate pu->pu_ioch += t->t_lwp->lwp_ru.ioch;
9037c478bd9Sstevel@tonic-gate pu->pu_iblk += t->t_lwp->lwp_ru.inblock;
9047c478bd9Sstevel@tonic-gate pu->pu_oblk += t->t_lwp->lwp_ru.oublock;
9057c478bd9Sstevel@tonic-gate pu->pu_vcsw += t->t_lwp->lwp_ru.nvcsw;
9067c478bd9Sstevel@tonic-gate pu->pu_icsw += t->t_lwp->lwp_ru.nivcsw;
9077c478bd9Sstevel@tonic-gate pu->pu_nsig += t->t_lwp->lwp_ru.nsignals;
9087c478bd9Sstevel@tonic-gate pu->pu_nswp += t->t_lwp->lwp_ru.nswap;
9097c478bd9Sstevel@tonic-gate pu->pu_nscl += t->t_lwp->lwp_ru.sysc;
9107c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist);
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate static void
exacct_copy_proc_mstate(proc_t * p,proc_usage_t * pu)9147c478bd9Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate pu->pu_minflt = p->p_ru.minflt;
9177c478bd9Sstevel@tonic-gate pu->pu_majflt = p->p_ru.majflt;
9187c478bd9Sstevel@tonic-gate pu->pu_sndmsg = p->p_ru.msgsnd;
9197c478bd9Sstevel@tonic-gate pu->pu_rcvmsg = p->p_ru.msgrcv;
9207c478bd9Sstevel@tonic-gate pu->pu_ioch = p->p_ru.ioch;
9217c478bd9Sstevel@tonic-gate pu->pu_iblk = p->p_ru.inblock;
9227c478bd9Sstevel@tonic-gate pu->pu_oblk = p->p_ru.oublock;
9237c478bd9Sstevel@tonic-gate pu->pu_vcsw = p->p_ru.nvcsw;
9247c478bd9Sstevel@tonic-gate pu->pu_icsw = p->p_ru.nivcsw;
9257c478bd9Sstevel@tonic-gate pu->pu_nsig = p->p_ru.nsignals;
9267c478bd9Sstevel@tonic-gate pu->pu_nswp = p->p_ru.nswap;
9277c478bd9Sstevel@tonic-gate pu->pu_nscl = p->p_ru.sysc;
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate void
exacct_calculate_proc_usage(proc_t * p,proc_usage_t * pu,ulong_t * mask,int flag,int wstat)9317c478bd9Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask,
9327c478bd9Sstevel@tonic-gate int flag, int wstat)
9337c478bd9Sstevel@tonic-gate {
9347c478bd9Sstevel@tonic-gate timestruc_t ts, ts_run;
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock));
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate /*
9397c478bd9Sstevel@tonic-gate * Convert CPU and execution times to sec/nsec format.
9407c478bd9Sstevel@tonic-gate */
9417c478bd9Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_CPU)) {
9427c478bd9Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_USER), &ts);
9437c478bd9Sstevel@tonic-gate pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec;
9447c478bd9Sstevel@tonic-gate pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9457c478bd9Sstevel@tonic-gate hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts);
9467c478bd9Sstevel@tonic-gate pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec;
9477c478bd9Sstevel@tonic-gate pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate if (BT_TEST(mask, AC_PROC_TIME)) {
9507c478bd9Sstevel@tonic-gate gethrestime(&ts);
9517c478bd9Sstevel@tonic-gate pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
9527c478bd9Sstevel@tonic-gate pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9537c478bd9Sstevel@tonic-gate hrt2ts(gethrtime() - p->p_mstart, &ts_run);
9547c478bd9Sstevel@tonic-gate ts.tv_sec -= ts_run.tv_sec;
9557c478bd9Sstevel@tonic-gate ts.tv_nsec -= ts_run.tv_nsec;
9567c478bd9Sstevel@tonic-gate if (ts.tv_nsec < 0) {
9577c478bd9Sstevel@tonic-gate ts.tv_sec--;
9587c478bd9Sstevel@tonic-gate if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) {
9597c478bd9Sstevel@tonic-gate ts.tv_sec++;
9607c478bd9Sstevel@tonic-gate ts.tv_nsec -= NANOSEC;
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec;
9647c478bd9Sstevel@tonic-gate pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate pu->pu_pid = p->p_pidp->pid_id;
9687c478bd9Sstevel@tonic-gate pu->pu_acflag = p->p_user.u_acflag;
9697c478bd9Sstevel@tonic-gate pu->pu_projid = p->p_task->tk_proj->kpj_id;
9707c478bd9Sstevel@tonic-gate pu->pu_taskid = p->p_task->tk_tkid;
9717c478bd9Sstevel@tonic-gate pu->pu_major = getmajor(p->p_sessp->s_dev);
9727c478bd9Sstevel@tonic-gate pu->pu_minor = getminor(p->p_sessp->s_dev);
9737c478bd9Sstevel@tonic-gate pu->pu_ancpid = p->p_ancpid;
9747c478bd9Sstevel@tonic-gate pu->pu_wstat = wstat;
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate * Compute average RSS in K. The denominator is the number of
9777c478bd9Sstevel@tonic-gate * samples: the number of clock ticks plus the initial value.
9787c478bd9Sstevel@tonic-gate */
9797c478bd9Sstevel@tonic-gate pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) *
9807c478bd9Sstevel@tonic-gate (PAGESIZE / 1024);
9817c478bd9Sstevel@tonic-gate pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024);
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate mutex_enter(&p->p_crlock);
9847c478bd9Sstevel@tonic-gate pu->pu_ruid = crgetruid(p->p_cred);
9857c478bd9Sstevel@tonic-gate pu->pu_rgid = crgetrgid(p->p_cred);
9867c478bd9Sstevel@tonic-gate mutex_exit(&p->p_crlock);
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1);
9897c478bd9Sstevel@tonic-gate bcopy(p->p_zone->zone_name, pu->pu_zonename,
9907c478bd9Sstevel@tonic-gate strlen(p->p_zone->zone_name) + 1);
9917c478bd9Sstevel@tonic-gate bcopy(p->p_zone->zone_nodename, pu->pu_nodename,
9927c478bd9Sstevel@tonic-gate strlen(p->p_zone->zone_nodename) + 1);
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate /*
9957c478bd9Sstevel@tonic-gate * Calculate microstate accounting data for a process that is still
9967c478bd9Sstevel@tonic-gate * running. Presently, we explicitly collect all of the LWP usage into
9977c478bd9Sstevel@tonic-gate * the proc usage structure here.
9987c478bd9Sstevel@tonic-gate */
9997c478bd9Sstevel@tonic-gate if (flag & EW_PARTIAL)
10007c478bd9Sstevel@tonic-gate exacct_calculate_proc_mstate(p, pu);
10017c478bd9Sstevel@tonic-gate if (flag & EW_FINAL)
10027c478bd9Sstevel@tonic-gate exacct_copy_proc_mstate(p, pu);
10037c478bd9Sstevel@tonic-gate }
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate /*
10067c478bd9Sstevel@tonic-gate * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void
10077c478bd9Sstevel@tonic-gate * *, size_t, size_t *), void *, size_t, size_t *)
10087c478bd9Sstevel@tonic-gate *
10097c478bd9Sstevel@tonic-gate * Overview
10107c478bd9Sstevel@tonic-gate * Assemble record with miscellaneous accounting information about the process
10117c478bd9Sstevel@tonic-gate * and execute the callback on it. It is the callback's job to set "actual" to
10127c478bd9Sstevel@tonic-gate * the size of record.
10137c478bd9Sstevel@tonic-gate *
10147c478bd9Sstevel@tonic-gate * Return values
10157c478bd9Sstevel@tonic-gate * The result of the callback function, unless the extended process accounting
10167c478bd9Sstevel@tonic-gate * feature is not active, in which case ENOTACTIVE is returned.
10177c478bd9Sstevel@tonic-gate *
10187c478bd9Sstevel@tonic-gate * Caller's context
10197c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
10207c478bd9Sstevel@tonic-gate */
10217c478bd9Sstevel@tonic-gate int
exacct_assemble_proc_usage(ac_info_t * ac_proc,proc_usage_t * pu,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual,int flag)10227c478bd9Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu,
10237c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
10247c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual, int flag)
10257c478bd9Sstevel@tonic-gate {
10267c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
10277c478bd9Sstevel@tonic-gate ea_object_t *proc_record;
10287c478bd9Sstevel@tonic-gate ea_catalog_t record_type;
10297c478bd9Sstevel@tonic-gate void *buf;
10307c478bd9Sstevel@tonic-gate size_t bufsize;
10317c478bd9Sstevel@tonic-gate int ret;
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate ASSERT(flag == EW_FINAL || flag == EW_PARTIAL);
10347c478bd9Sstevel@tonic-gate
10357c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock);
10367c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF) {
10377c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
10387c478bd9Sstevel@tonic-gate return (ENOTACTIVE);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
10417c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
10427c478bd9Sstevel@tonic-gate
10437c478bd9Sstevel@tonic-gate switch (flag) {
10447c478bd9Sstevel@tonic-gate case EW_FINAL:
10457c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_PROC;
10467c478bd9Sstevel@tonic-gate break;
10477c478bd9Sstevel@tonic-gate case EW_PARTIAL:
10487c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_PROC_PARTIAL;
10497c478bd9Sstevel@tonic-gate break;
1050c6f039c7SToomas Soome default:
1051c6f039c7SToomas Soome record_type = EXD_NONE;
1052c6f039c7SToomas Soome break;
10537c478bd9Sstevel@tonic-gate }
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate proc_record = exacct_assemble_proc_record(pu, mask, record_type);
10567c478bd9Sstevel@tonic-gate if (proc_record == NULL)
10577c478bd9Sstevel@tonic-gate return (0);
10587c478bd9Sstevel@tonic-gate
10597c478bd9Sstevel@tonic-gate /*
10607c478bd9Sstevel@tonic-gate * Pack object into buffer and pass to callback.
10617c478bd9Sstevel@tonic-gate */
10627c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(proc_record, NULL, 0);
10637c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
10647c478bd9Sstevel@tonic-gate (void) ea_pack_object(proc_record, buf, bufsize);
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual);
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate /*
10697c478bd9Sstevel@tonic-gate * Free all previously allocations.
10707c478bd9Sstevel@tonic-gate */
10717c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize);
10727c478bd9Sstevel@tonic-gate ea_free_object(proc_record, EUP_ALLOC);
10737c478bd9Sstevel@tonic-gate return (ret);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t,
10787c478bd9Sstevel@tonic-gate * size_t *)
10797c478bd9Sstevel@tonic-gate *
10807c478bd9Sstevel@tonic-gate * Overview
10817c478bd9Sstevel@tonic-gate * exacct_commit_callback() writes the indicated buffer to the indicated
10827c478bd9Sstevel@tonic-gate * extended accounting file.
10837c478bd9Sstevel@tonic-gate *
10847c478bd9Sstevel@tonic-gate * Return values
10857c478bd9Sstevel@tonic-gate * The result of the write operation is returned. "actual" is updated to
10867c478bd9Sstevel@tonic-gate * contain the number of bytes actually written.
10877c478bd9Sstevel@tonic-gate *
10887c478bd9Sstevel@tonic-gate * Caller's context
10897c478bd9Sstevel@tonic-gate * Suitable for a vn_rdwr() operation.
10907c478bd9Sstevel@tonic-gate */
10917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10927c478bd9Sstevel@tonic-gate int
exacct_commit_callback(ac_info_t * info,void * ubuf,size_t ubufsize,void * buf,size_t bufsize,size_t * actual)10937c478bd9Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize,
10947c478bd9Sstevel@tonic-gate void *buf, size_t bufsize, size_t *actual)
10957c478bd9Sstevel@tonic-gate {
10967c478bd9Sstevel@tonic-gate int error = 0;
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate *actual = 0;
10997c478bd9Sstevel@tonic-gate if ((error = exacct_vn_write(info, buf, bufsize)) == 0)
11007c478bd9Sstevel@tonic-gate *actual = bufsize;
11017c478bd9Sstevel@tonic-gate return (error);
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate static void
exacct_do_commit_proc(ac_info_t * ac_proc,proc_t * p,int wstat)11057c478bd9Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate size_t size;
11087c478bd9Sstevel@tonic-gate proc_usage_t *pu;
11097c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock);
11127c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_ON) {
11137c478bd9Sstevel@tonic-gate bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
11147c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
11157c478bd9Sstevel@tonic-gate } else {
11167c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
11177c478bd9Sstevel@tonic-gate return;
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
11217c478bd9Sstevel@tonic-gate size = strlen(p->p_user.u_comm) + 1;
11227c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP);
11257c478bd9Sstevel@tonic-gate pu->pu_command = kmem_alloc(size, KM_SLEEP);
11267c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
11277c478bd9Sstevel@tonic-gate exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat);
11287c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate (void) exacct_assemble_proc_usage(ac_proc, pu,
11317c478bd9Sstevel@tonic-gate exacct_commit_callback, NULL, 0, &size, EW_FINAL);
11327c478bd9Sstevel@tonic-gate
11337c478bd9Sstevel@tonic-gate kmem_free(pu->pu_command, strlen(pu->pu_command) + 1);
11347c478bd9Sstevel@tonic-gate kmem_free(pu, sizeof (proc_usage_t));
11357c478bd9Sstevel@tonic-gate }
11367eceb558Srh
11377c478bd9Sstevel@tonic-gate /*
11387c478bd9Sstevel@tonic-gate * void exacct_commit_proc(proc_t *, int)
11397c478bd9Sstevel@tonic-gate *
11407c478bd9Sstevel@tonic-gate * Overview
11417c478bd9Sstevel@tonic-gate * exacct_commit_proc() calculates the final usage for a process, updating the
11427c478bd9Sstevel@tonic-gate * task usage if task accounting is active, and writing a process record if
11437c478bd9Sstevel@tonic-gate * process accounting is active. exacct_commit_proc() is intended for being
11447c478bd9Sstevel@tonic-gate * called from proc_exit().
11457c478bd9Sstevel@tonic-gate *
11467c478bd9Sstevel@tonic-gate * Return values
11477c478bd9Sstevel@tonic-gate * None.
11487c478bd9Sstevel@tonic-gate *
11497c478bd9Sstevel@tonic-gate * Caller's context
11507c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations. p_lock must not be held at entry.
11517c478bd9Sstevel@tonic-gate */
11527c478bd9Sstevel@tonic-gate void
exacct_commit_proc(proc_t * p,int wstat)11537c478bd9Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat)
11547c478bd9Sstevel@tonic-gate {
11557c478bd9Sstevel@tonic-gate zone_t *zone = p->p_zone;
11567c478bd9Sstevel@tonic-gate struct exacct_globals *acg, *gacg = NULL;
11577c478bd9Sstevel@tonic-gate
11587c478bd9Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
11597c478bd9Sstevel@tonic-gate /*
11607c478bd9Sstevel@tonic-gate * acctctl module not loaded. Nothing to do.
11617c478bd9Sstevel@tonic-gate */
11627c478bd9Sstevel@tonic-gate return;
11637c478bd9Sstevel@tonic-gate }
11648cb09440SVamsi Nagineni
11658cb09440SVamsi Nagineni /*
11668cb09440SVamsi Nagineni * If acctctl module is loaded when zone is in down state then
11678cb09440SVamsi Nagineni * zone_getspecific can return NULL for that zone.
11688cb09440SVamsi Nagineni */
11697c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, zone);
11708cb09440SVamsi Nagineni if (acg == NULL)
11718cb09440SVamsi Nagineni return;
11727c478bd9Sstevel@tonic-gate exacct_do_commit_proc(&acg->ac_proc, p, wstat);
11737eceb558Srh if (zone != global_zone) {
11747eceb558Srh gacg = zone_getspecific(exacct_zone_key, global_zone);
11757c478bd9Sstevel@tonic-gate exacct_do_commit_proc(&gacg->ac_proc, p, wstat);
11767eceb558Srh }
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate
1179da14cebeSEric Cheng static int
exacct_attach_netstat_item(net_stat_t * ns,ea_object_t * record,int res)1180da14cebeSEric Cheng exacct_attach_netstat_item(net_stat_t *ns, ea_object_t *record, int res)
1181da14cebeSEric Cheng {
1182da14cebeSEric Cheng int attached = 1;
1183da14cebeSEric Cheng
1184da14cebeSEric Cheng switch (res) {
1185da14cebeSEric Cheng case AC_NET_NAME:
1186da14cebeSEric Cheng (void) ea_attach_item(record, ns->ns_name,
1187da14cebeSEric Cheng strlen(ns->ns_name) + 1, EXT_STRING | EXD_NET_STATS_NAME);
1188da14cebeSEric Cheng break;
1189da14cebeSEric Cheng case AC_NET_CURTIME:
1190da14cebeSEric Cheng {
1191da14cebeSEric Cheng uint64_t now;
1192da14cebeSEric Cheng timestruc_t ts;
1193da14cebeSEric Cheng
1194da14cebeSEric Cheng gethrestime(&ts);
1195da14cebeSEric Cheng now = (uint64_t)(ulong_t)ts.tv_sec;
1196da14cebeSEric Cheng (void) ea_attach_item(record, &now, sizeof (uint64_t),
1197da14cebeSEric Cheng EXT_UINT64 | EXD_NET_STATS_CURTIME);
1198da14cebeSEric Cheng }
1199da14cebeSEric Cheng break;
1200da14cebeSEric Cheng case AC_NET_IBYTES:
1201da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_ibytes,
1202da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IBYTES);
1203da14cebeSEric Cheng break;
1204da14cebeSEric Cheng case AC_NET_OBYTES:
1205da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_obytes,
1206da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OBYTES);
1207da14cebeSEric Cheng break;
1208da14cebeSEric Cheng case AC_NET_IPKTS:
1209da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_ipackets,
1210da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IPKTS);
1211da14cebeSEric Cheng break;
1212da14cebeSEric Cheng case AC_NET_OPKTS:
1213da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_opackets,
1214da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OPKTS);
1215da14cebeSEric Cheng break;
1216da14cebeSEric Cheng case AC_NET_IERRPKTS:
1217da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_ierrors,
1218da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IERRPKTS);
1219da14cebeSEric Cheng break;
1220da14cebeSEric Cheng case AC_NET_OERRPKTS:
1221da14cebeSEric Cheng (void) ea_attach_item(record, &ns->ns_oerrors,
1222da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OERRPKTS);
1223da14cebeSEric Cheng break;
1224da14cebeSEric Cheng default:
1225da14cebeSEric Cheng attached = 0;
1226da14cebeSEric Cheng }
1227da14cebeSEric Cheng return (attached);
1228da14cebeSEric Cheng }
1229da14cebeSEric Cheng
1230da14cebeSEric Cheng static int
exacct_attach_netdesc_item(net_desc_t * nd,ea_object_t * record,int res)1231da14cebeSEric Cheng exacct_attach_netdesc_item(net_desc_t *nd, ea_object_t *record, int res)
1232da14cebeSEric Cheng {
1233da14cebeSEric Cheng int attached = 1;
1234da14cebeSEric Cheng
1235da14cebeSEric Cheng switch (res) {
1236da14cebeSEric Cheng case AC_NET_NAME:
1237da14cebeSEric Cheng (void) ea_attach_item(record, nd->nd_name,
1238da14cebeSEric Cheng strlen(nd->nd_name) + 1, EXT_STRING | EXD_NET_DESC_NAME);
1239da14cebeSEric Cheng break;
1240da14cebeSEric Cheng case AC_NET_DEVNAME:
1241da14cebeSEric Cheng (void) ea_attach_item(record, nd->nd_devname,
1242da14cebeSEric Cheng strlen(nd->nd_devname) + 1, EXT_STRING |
1243da14cebeSEric Cheng EXD_NET_DESC_DEVNAME);
1244da14cebeSEric Cheng break;
1245da14cebeSEric Cheng case AC_NET_EHOST:
1246da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_ehost,
1247da14cebeSEric Cheng sizeof (nd->nd_ehost), EXT_RAW | EXD_NET_DESC_EHOST);
1248da14cebeSEric Cheng break;
1249da14cebeSEric Cheng case AC_NET_EDEST:
1250da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_edest,
1251da14cebeSEric Cheng sizeof (nd->nd_edest), EXT_RAW | EXD_NET_DESC_EDEST);
1252da14cebeSEric Cheng break;
1253da14cebeSEric Cheng case AC_NET_VLAN_TPID:
1254da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tpid,
1255da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TPID);
1256da14cebeSEric Cheng break;
1257da14cebeSEric Cheng case AC_NET_VLAN_TCI:
1258da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_vlan_tci,
1259da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TCI);
1260da14cebeSEric Cheng break;
1261da14cebeSEric Cheng case AC_NET_SAP:
1262da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_sap,
1263da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_SAP);
1264da14cebeSEric Cheng break;
1265da14cebeSEric Cheng case AC_NET_PRIORITY:
1266da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_priority,
1267da14cebeSEric Cheng sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_PRIORITY);
1268da14cebeSEric Cheng break;
1269da14cebeSEric Cheng case AC_NET_BWLIMIT:
1270da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_bw_limit,
1271da14cebeSEric Cheng sizeof (uint64_t), EXT_UINT64 | EXD_NET_DESC_BWLIMIT);
1272da14cebeSEric Cheng break;
1273da14cebeSEric Cheng case AC_NET_SADDR:
1274da14cebeSEric Cheng if (nd->nd_isv4) {
1275da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_saddr[3],
1276da14cebeSEric Cheng sizeof (uint32_t), EXT_UINT32 |
1277da14cebeSEric Cheng EXD_NET_DESC_V4SADDR);
1278da14cebeSEric Cheng } else {
1279da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_saddr,
1280da14cebeSEric Cheng sizeof (nd->nd_saddr), EXT_RAW |
1281da14cebeSEric Cheng EXD_NET_DESC_V6SADDR);
1282da14cebeSEric Cheng }
1283da14cebeSEric Cheng break;
1284da14cebeSEric Cheng case AC_NET_DADDR:
1285da14cebeSEric Cheng if (nd->nd_isv4) {
1286da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_daddr[3],
1287da14cebeSEric Cheng sizeof (uint32_t), EXT_UINT32 |
1288da14cebeSEric Cheng EXD_NET_DESC_V4DADDR);
1289da14cebeSEric Cheng } else {
1290da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_daddr,
1291da14cebeSEric Cheng sizeof (nd->nd_daddr), EXT_RAW |
1292da14cebeSEric Cheng EXD_NET_DESC_V6DADDR);
1293da14cebeSEric Cheng }
1294da14cebeSEric Cheng break;
1295da14cebeSEric Cheng case AC_NET_SPORT:
1296da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_sport,
1297da14cebeSEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_SPORT);
1298da14cebeSEric Cheng break;
1299da14cebeSEric Cheng case AC_NET_DPORT:
1300da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_dport,
1301da14cebeSEric Cheng sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_DPORT);
1302da14cebeSEric Cheng break;
1303da14cebeSEric Cheng case AC_NET_PROTOCOL:
1304da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_protocol,
1305da14cebeSEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_PROTOCOL);
1306da14cebeSEric Cheng break;
1307da14cebeSEric Cheng case AC_NET_DSFIELD:
1308da14cebeSEric Cheng (void) ea_attach_item(record, &nd->nd_dsfield,
1309da14cebeSEric Cheng sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_DSFIELD);
1310da14cebeSEric Cheng break;
1311da14cebeSEric Cheng default:
1312da14cebeSEric Cheng attached = 0;
1313da14cebeSEric Cheng }
1314da14cebeSEric Cheng return (attached);
1315da14cebeSEric Cheng }
1316da14cebeSEric Cheng
1317da14cebeSEric Cheng static ea_object_t *
exacct_assemble_net_record(void * ninfo,ulong_t * mask,ea_catalog_t record_type,int what)1318da14cebeSEric Cheng exacct_assemble_net_record(void *ninfo, ulong_t *mask, ea_catalog_t record_type,
1319da14cebeSEric Cheng int what)
1320da14cebeSEric Cheng {
1321da14cebeSEric Cheng int res;
1322da14cebeSEric Cheng int count;
1323da14cebeSEric Cheng ea_object_t *record;
1324da14cebeSEric Cheng
1325da14cebeSEric Cheng /*
1326da14cebeSEric Cheng * Assemble usage values into group.
1327da14cebeSEric Cheng */
1328da14cebeSEric Cheng record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
1329da14cebeSEric Cheng for (res = 1, count = 0; res <= AC_NET_MAX_RES; res++)
1330da14cebeSEric Cheng if (BT_TEST(mask, res)) {
1331da14cebeSEric Cheng if (what == EX_NET_LNDESC_REC ||
1332da14cebeSEric Cheng what == EX_NET_FLDESC_REC) {
1333da14cebeSEric Cheng count += exacct_attach_netdesc_item(
1334da14cebeSEric Cheng (net_desc_t *)ninfo, record, res);
1335da14cebeSEric Cheng } else {
1336da14cebeSEric Cheng count += exacct_attach_netstat_item(
1337da14cebeSEric Cheng (net_stat_t *)ninfo, record, res);
1338da14cebeSEric Cheng }
1339da14cebeSEric Cheng }
1340da14cebeSEric Cheng if (count == 0) {
1341da14cebeSEric Cheng ea_free_object(record, EUP_ALLOC);
1342da14cebeSEric Cheng record = NULL;
1343da14cebeSEric Cheng }
1344da14cebeSEric Cheng return (record);
1345da14cebeSEric Cheng }
1346da14cebeSEric Cheng
1347da14cebeSEric Cheng int
exacct_assemble_net_usage(ac_info_t * ac_net,void * ninfo,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual,int what)1348da14cebeSEric Cheng exacct_assemble_net_usage(ac_info_t *ac_net, void *ninfo,
1349da14cebeSEric Cheng int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
1350da14cebeSEric Cheng void *ubuf, size_t ubufsize, size_t *actual, int what)
1351da14cebeSEric Cheng {
1352da14cebeSEric Cheng ulong_t mask[AC_MASK_SZ];
1353da14cebeSEric Cheng ea_object_t *net_desc;
1354da14cebeSEric Cheng ea_catalog_t record_type;
1355da14cebeSEric Cheng void *buf;
1356da14cebeSEric Cheng size_t bufsize;
1357da14cebeSEric Cheng int ret;
1358da14cebeSEric Cheng
1359da14cebeSEric Cheng mutex_enter(&ac_net->ac_lock);
1360da14cebeSEric Cheng if (ac_net->ac_state == AC_OFF) {
1361da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock);
1362da14cebeSEric Cheng return (ENOTACTIVE);
1363da14cebeSEric Cheng }
1364da14cebeSEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ);
1365da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock);
1366da14cebeSEric Cheng
1367da14cebeSEric Cheng switch (what) {
1368da14cebeSEric Cheng case EX_NET_LNDESC_REC:
1369da14cebeSEric Cheng record_type = EXD_GROUP_NET_LINK_DESC;
1370da14cebeSEric Cheng break;
1371da14cebeSEric Cheng case EX_NET_LNSTAT_REC:
1372da14cebeSEric Cheng record_type = EXD_GROUP_NET_LINK_STATS;
1373da14cebeSEric Cheng break;
1374da14cebeSEric Cheng case EX_NET_FLDESC_REC:
1375da14cebeSEric Cheng record_type = EXD_GROUP_NET_FLOW_DESC;
1376da14cebeSEric Cheng break;
1377da14cebeSEric Cheng case EX_NET_FLSTAT_REC:
1378da14cebeSEric Cheng record_type = EXD_GROUP_NET_FLOW_STATS;
1379da14cebeSEric Cheng break;
1380c6f039c7SToomas Soome default:
1381c6f039c7SToomas Soome return (0);
1382da14cebeSEric Cheng }
1383da14cebeSEric Cheng
1384da14cebeSEric Cheng net_desc = exacct_assemble_net_record(ninfo, mask, record_type, what);
1385da14cebeSEric Cheng if (net_desc == NULL)
1386da14cebeSEric Cheng return (0);
1387da14cebeSEric Cheng
1388da14cebeSEric Cheng /*
1389da14cebeSEric Cheng * Pack object into buffer and pass to callback.
1390da14cebeSEric Cheng */
1391da14cebeSEric Cheng bufsize = ea_pack_object(net_desc, NULL, 0);
1392da14cebeSEric Cheng buf = kmem_alloc(bufsize, KM_NOSLEEP);
1393da14cebeSEric Cheng if (buf == NULL)
1394da14cebeSEric Cheng return (ENOMEM);
1395da14cebeSEric Cheng
1396da14cebeSEric Cheng (void) ea_pack_object(net_desc, buf, bufsize);
1397da14cebeSEric Cheng
1398da14cebeSEric Cheng ret = callback(ac_net, ubuf, ubufsize, buf, bufsize, actual);
1399da14cebeSEric Cheng
1400da14cebeSEric Cheng /*
1401da14cebeSEric Cheng * Free all previously allocations.
1402da14cebeSEric Cheng */
1403da14cebeSEric Cheng kmem_free(buf, bufsize);
1404da14cebeSEric Cheng ea_free_object(net_desc, EUP_ALLOC);
1405da14cebeSEric Cheng return (ret);
1406da14cebeSEric Cheng }
1407da14cebeSEric Cheng
1408da14cebeSEric Cheng int
exacct_commit_netinfo(void * arg,int what)1409da14cebeSEric Cheng exacct_commit_netinfo(void *arg, int what)
1410da14cebeSEric Cheng {
1411da14cebeSEric Cheng size_t size;
1412da14cebeSEric Cheng ulong_t mask[AC_MASK_SZ];
1413da14cebeSEric Cheng struct exacct_globals *acg;
1414da14cebeSEric Cheng ac_info_t *ac_net;
1415da14cebeSEric Cheng
1416da14cebeSEric Cheng if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
1417da14cebeSEric Cheng /*
1418da14cebeSEric Cheng * acctctl module not loaded. Nothing to do.
1419da14cebeSEric Cheng */
1420da14cebeSEric Cheng return (ENOTACTIVE);
1421da14cebeSEric Cheng }
1422da14cebeSEric Cheng
1423da14cebeSEric Cheng /*
1424da14cebeSEric Cheng * Even though each zone nominally has its own flow accounting settings
1425da14cebeSEric Cheng * (ac_flow), these are only maintained by and for the global zone.
1426da14cebeSEric Cheng *
1427da14cebeSEric Cheng * If this were to change in the future, this function should grow a
1428da14cebeSEric Cheng * second zoneid (or zone) argument, and use the corresponding zone's
1429da14cebeSEric Cheng * settings rather than always using those of the global zone.
1430da14cebeSEric Cheng */
1431da14cebeSEric Cheng acg = zone_getspecific(exacct_zone_key, global_zone);
1432da14cebeSEric Cheng ac_net = &acg->ac_net;
1433da14cebeSEric Cheng
1434da14cebeSEric Cheng mutex_enter(&ac_net->ac_lock);
1435da14cebeSEric Cheng if (ac_net->ac_state == AC_OFF) {
1436da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock);
1437da14cebeSEric Cheng return (ENOTACTIVE);
1438da14cebeSEric Cheng }
1439da14cebeSEric Cheng bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ);
1440da14cebeSEric Cheng mutex_exit(&ac_net->ac_lock);
1441da14cebeSEric Cheng
1442da14cebeSEric Cheng return (exacct_assemble_net_usage(ac_net, arg, exacct_commit_callback,
1443da14cebeSEric Cheng NULL, 0, &size, what));
1444da14cebeSEric Cheng }
1445da14cebeSEric Cheng
14467c478bd9Sstevel@tonic-gate static int
exacct_attach_flow_item(flow_usage_t * fu,ea_object_t * record,int res)14477c478bd9Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res)
14487c478bd9Sstevel@tonic-gate {
14497c478bd9Sstevel@tonic-gate int attached = 1;
14507c478bd9Sstevel@tonic-gate
14517c478bd9Sstevel@tonic-gate switch (res) {
14527c478bd9Sstevel@tonic-gate case AC_FLOW_SADDR:
14537c478bd9Sstevel@tonic-gate if (fu->fu_isv4) {
14547c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr[3],
14557c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR);
14567c478bd9Sstevel@tonic-gate } else {
14577c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_saddr,
14587c478bd9Sstevel@tonic-gate sizeof (fu->fu_saddr), EXT_RAW |
14597c478bd9Sstevel@tonic-gate EXD_FLOW_V6SADDR);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate break;
14627c478bd9Sstevel@tonic-gate case AC_FLOW_DADDR:
14637c478bd9Sstevel@tonic-gate if (fu->fu_isv4) {
14647c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr[3],
14657c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR);
14667c478bd9Sstevel@tonic-gate } else {
14677c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_daddr,
14687c478bd9Sstevel@tonic-gate sizeof (fu->fu_daddr), EXT_RAW |
14697c478bd9Sstevel@tonic-gate EXD_FLOW_V6DADDR);
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate break;
14727c478bd9Sstevel@tonic-gate case AC_FLOW_SPORT:
14737c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_sport,
14747c478bd9Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT);
14757c478bd9Sstevel@tonic-gate break;
14767c478bd9Sstevel@tonic-gate case AC_FLOW_DPORT:
14777c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dport,
14787c478bd9Sstevel@tonic-gate sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT);
14797c478bd9Sstevel@tonic-gate break;
14807c478bd9Sstevel@tonic-gate case AC_FLOW_PROTOCOL:
14817c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_protocol,
14827c478bd9Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL);
14837c478bd9Sstevel@tonic-gate break;
14847c478bd9Sstevel@tonic-gate case AC_FLOW_DSFIELD:
14857c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_dsfield,
14867c478bd9Sstevel@tonic-gate sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD);
14877c478bd9Sstevel@tonic-gate break;
14887c478bd9Sstevel@tonic-gate case AC_FLOW_CTIME:
14897c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_ctime,
14907c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME);
14917c478bd9Sstevel@tonic-gate break;
14927c478bd9Sstevel@tonic-gate case AC_FLOW_LSEEN:
14937c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_lseen,
14947c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN);
14957c478bd9Sstevel@tonic-gate break;
14967c478bd9Sstevel@tonic-gate case AC_FLOW_NBYTES:
14977c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_nbytes,
14987c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES);
14997c478bd9Sstevel@tonic-gate break;
15007c478bd9Sstevel@tonic-gate case AC_FLOW_NPKTS:
15017c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_npackets,
15027c478bd9Sstevel@tonic-gate sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS);
15037c478bd9Sstevel@tonic-gate break;
15047c478bd9Sstevel@tonic-gate case AC_FLOW_PROJID:
15057c478bd9Sstevel@tonic-gate if (fu->fu_projid >= 0) {
15067c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, &fu->fu_projid,
15077c478bd9Sstevel@tonic-gate sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID);
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate break;
15107c478bd9Sstevel@tonic-gate case AC_FLOW_UID:
1511*3df2e8b2SRobert Mustacchi (void) ea_attach_item(record, &fu->fu_userid,
1512*3df2e8b2SRobert Mustacchi sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID);
15137c478bd9Sstevel@tonic-gate break;
15147c478bd9Sstevel@tonic-gate case AC_FLOW_ANAME:
15157c478bd9Sstevel@tonic-gate (void) ea_attach_item(record, fu->fu_aname,
15167c478bd9Sstevel@tonic-gate strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME);
15177c478bd9Sstevel@tonic-gate break;
15187c478bd9Sstevel@tonic-gate default:
15197c478bd9Sstevel@tonic-gate attached = 0;
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate return (attached);
15227c478bd9Sstevel@tonic-gate }
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate static ea_object_t *
exacct_assemble_flow_record(flow_usage_t * fu,ulong_t * mask,ea_catalog_t record_type)15257c478bd9Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask,
15267c478bd9Sstevel@tonic-gate ea_catalog_t record_type)
15277c478bd9Sstevel@tonic-gate {
15287c478bd9Sstevel@tonic-gate int res, count;
15297c478bd9Sstevel@tonic-gate ea_object_t *record;
15307c478bd9Sstevel@tonic-gate
15317c478bd9Sstevel@tonic-gate /*
15327c478bd9Sstevel@tonic-gate * Assemble usage values into group.
15337c478bd9Sstevel@tonic-gate */
15347c478bd9Sstevel@tonic-gate record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
15357c478bd9Sstevel@tonic-gate for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++)
15367c478bd9Sstevel@tonic-gate if (BT_TEST(mask, res))
15377c478bd9Sstevel@tonic-gate count += exacct_attach_flow_item(fu, record, res);
15387c478bd9Sstevel@tonic-gate if (count == 0) {
15397c478bd9Sstevel@tonic-gate ea_free_object(record, EUP_ALLOC);
15407c478bd9Sstevel@tonic-gate record = NULL;
15417c478bd9Sstevel@tonic-gate }
15427c478bd9Sstevel@tonic-gate return (record);
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate
15457c478bd9Sstevel@tonic-gate int
exacct_assemble_flow_usage(ac_info_t * ac_flow,flow_usage_t * fu,int (* callback)(ac_info_t *,void *,size_t,void *,size_t,size_t *),void * ubuf,size_t ubufsize,size_t * actual)15467c478bd9Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu,
15477c478bd9Sstevel@tonic-gate int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
15487c478bd9Sstevel@tonic-gate void *ubuf, size_t ubufsize, size_t *actual)
15497c478bd9Sstevel@tonic-gate {
15507c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
15517c478bd9Sstevel@tonic-gate ea_object_t *flow_usage;
15527c478bd9Sstevel@tonic-gate ea_catalog_t record_type;
15537c478bd9Sstevel@tonic-gate void *buf;
15547c478bd9Sstevel@tonic-gate size_t bufsize;
15557c478bd9Sstevel@tonic-gate int ret;
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock);
15587c478bd9Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) {
15597c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
15607c478bd9Sstevel@tonic-gate return (ENOTACTIVE);
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
15637c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
15647c478bd9Sstevel@tonic-gate
15657c478bd9Sstevel@tonic-gate record_type = EXD_GROUP_FLOW;
15667c478bd9Sstevel@tonic-gate
15677c478bd9Sstevel@tonic-gate flow_usage = exacct_assemble_flow_record(fu, mask, record_type);
15687c478bd9Sstevel@tonic-gate if (flow_usage == NULL) {
15697c478bd9Sstevel@tonic-gate return (0);
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate /*
15737c478bd9Sstevel@tonic-gate * Pack object into buffer and pass to callback.
15747c478bd9Sstevel@tonic-gate */
15757c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(flow_usage, NULL, 0);
15767c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_NOSLEEP);
15777c478bd9Sstevel@tonic-gate if (buf == NULL) {
15787c478bd9Sstevel@tonic-gate return (ENOMEM);
15797c478bd9Sstevel@tonic-gate }
15807c478bd9Sstevel@tonic-gate
15817c478bd9Sstevel@tonic-gate (void) ea_pack_object(flow_usage, buf, bufsize);
15827c478bd9Sstevel@tonic-gate
15837c478bd9Sstevel@tonic-gate ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual);
15847c478bd9Sstevel@tonic-gate
15857c478bd9Sstevel@tonic-gate /*
15867c478bd9Sstevel@tonic-gate * Free all previously allocations.
15877c478bd9Sstevel@tonic-gate */
15887c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize);
15897c478bd9Sstevel@tonic-gate ea_free_object(flow_usage, EUP_ALLOC);
15907c478bd9Sstevel@tonic-gate return (ret);
15917c478bd9Sstevel@tonic-gate }
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate void
exacct_commit_flow(void * arg)15947c478bd9Sstevel@tonic-gate exacct_commit_flow(void *arg)
15957c478bd9Sstevel@tonic-gate {
15967c478bd9Sstevel@tonic-gate flow_usage_t *f = (flow_usage_t *)arg;
15977c478bd9Sstevel@tonic-gate size_t size;
15987c478bd9Sstevel@tonic-gate ulong_t mask[AC_MASK_SZ];
15997c478bd9Sstevel@tonic-gate struct exacct_globals *acg;
16007c478bd9Sstevel@tonic-gate ac_info_t *ac_flow;
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
16037c478bd9Sstevel@tonic-gate /*
16047c478bd9Sstevel@tonic-gate * acctctl module not loaded. Nothing to do.
16057c478bd9Sstevel@tonic-gate */
16067c478bd9Sstevel@tonic-gate return;
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate
16097c478bd9Sstevel@tonic-gate /*
16107c478bd9Sstevel@tonic-gate * Even though each zone nominally has its own flow accounting settings
16117c478bd9Sstevel@tonic-gate * (ac_flow), these are only maintained by and for the global zone.
16127c478bd9Sstevel@tonic-gate *
16137c478bd9Sstevel@tonic-gate * If this were to change in the future, this function should grow a
16147c478bd9Sstevel@tonic-gate * second zoneid (or zone) argument, and use the corresponding zone's
16157c478bd9Sstevel@tonic-gate * settings rather than always using those of the global zone.
16167c478bd9Sstevel@tonic-gate */
16177c478bd9Sstevel@tonic-gate acg = zone_getspecific(exacct_zone_key, global_zone);
16187c478bd9Sstevel@tonic-gate ac_flow = &acg->ac_flow;
16197c478bd9Sstevel@tonic-gate
16207c478bd9Sstevel@tonic-gate mutex_enter(&ac_flow->ac_lock);
16217c478bd9Sstevel@tonic-gate if (ac_flow->ac_state == AC_OFF) {
16227c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
16237c478bd9Sstevel@tonic-gate return;
16247c478bd9Sstevel@tonic-gate }
16257c478bd9Sstevel@tonic-gate bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
16267c478bd9Sstevel@tonic-gate mutex_exit(&ac_flow->ac_lock);
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate (void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback,
16297c478bd9Sstevel@tonic-gate NULL, 0, &size);
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate /*
16337c478bd9Sstevel@tonic-gate * int exacct_tag_task(task_t *, void *, size_t, int)
16347c478bd9Sstevel@tonic-gate *
16357c478bd9Sstevel@tonic-gate * Overview
16367c478bd9Sstevel@tonic-gate * exacct_tag_task() provides the exacct record construction and writing
16377c478bd9Sstevel@tonic-gate * support required by putacct(2) for task entities.
16387c478bd9Sstevel@tonic-gate *
16397c478bd9Sstevel@tonic-gate * Return values
16407c478bd9Sstevel@tonic-gate * The result of the write operation is returned, unless the extended
16417c478bd9Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned.
16427c478bd9Sstevel@tonic-gate *
16437c478bd9Sstevel@tonic-gate * Caller's context
16447c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
16457c478bd9Sstevel@tonic-gate */
16467c478bd9Sstevel@tonic-gate int
exacct_tag_task(ac_info_t * ac_task,task_t * tk,void * ubuf,size_t ubufsz,int flags)16477c478bd9Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz,
16487c478bd9Sstevel@tonic-gate int flags)
16497c478bd9Sstevel@tonic-gate {
16507c478bd9Sstevel@tonic-gate int error = 0;
16517c478bd9Sstevel@tonic-gate void *buf;
16527c478bd9Sstevel@tonic-gate size_t bufsize;
16537c478bd9Sstevel@tonic-gate ea_catalog_t cat;
16547c478bd9Sstevel@tonic-gate ea_object_t *tag;
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate mutex_enter(&ac_task->ac_lock);
16577c478bd9Sstevel@tonic-gate if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) {
16587c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock);
16597c478bd9Sstevel@tonic-gate return (ENOTACTIVE);
16607c478bd9Sstevel@tonic-gate }
16617c478bd9Sstevel@tonic-gate mutex_exit(&ac_task->ac_lock);
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG);
16647c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &tk->tk_tkid, 0,
16657c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
16667c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0,
16677c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
16687c478bd9Sstevel@tonic-gate if (flags == EP_RAW)
16697c478bd9Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG;
16707c478bd9Sstevel@tonic-gate else
16717c478bd9Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG;
16727c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat);
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0);
16757c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
16767c478bd9Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize);
16777c478bd9Sstevel@tonic-gate error = exacct_vn_write(ac_task, buf, bufsize);
16787c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize);
16797c478bd9Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC);
16807c478bd9Sstevel@tonic-gate return (error);
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate /*
16847c478bd9Sstevel@tonic-gate * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *)
16857c478bd9Sstevel@tonic-gate *
16867c478bd9Sstevel@tonic-gate * Overview
16877c478bd9Sstevel@tonic-gate * exacct_tag_proc() provides the exacct record construction and writing
16887c478bd9Sstevel@tonic-gate * support required by putacct(2) for processes.
16897c478bd9Sstevel@tonic-gate *
16907c478bd9Sstevel@tonic-gate * Return values
16917c478bd9Sstevel@tonic-gate * The result of the write operation is returned, unless the extended
16927c478bd9Sstevel@tonic-gate * accounting facility is not active, in which case ENOTACTIVE is returned.
16937c478bd9Sstevel@tonic-gate *
16947c478bd9Sstevel@tonic-gate * Caller's context
16957c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
16967c478bd9Sstevel@tonic-gate */
16977c478bd9Sstevel@tonic-gate int
exacct_tag_proc(ac_info_t * ac_proc,pid_t pid,taskid_t tkid,void * ubuf,size_t ubufsz,int flags,const char * hostname)16987c478bd9Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf,
16997c478bd9Sstevel@tonic-gate size_t ubufsz, int flags, const char *hostname)
17007c478bd9Sstevel@tonic-gate {
17017c478bd9Sstevel@tonic-gate int error = 0;
17027c478bd9Sstevel@tonic-gate void *buf;
17037c478bd9Sstevel@tonic-gate size_t bufsize;
17047c478bd9Sstevel@tonic-gate ea_catalog_t cat;
17057c478bd9Sstevel@tonic-gate ea_object_t *tag;
17067c478bd9Sstevel@tonic-gate
17077c478bd9Sstevel@tonic-gate mutex_enter(&ac_proc->ac_lock);
17087c478bd9Sstevel@tonic-gate if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) {
17097c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
17107c478bd9Sstevel@tonic-gate return (ENOTACTIVE);
17117c478bd9Sstevel@tonic-gate }
17127c478bd9Sstevel@tonic-gate mutex_exit(&ac_proc->ac_lock);
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG);
17157c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &pid, sizeof (uint32_t),
17167c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID);
17177c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, &tkid, 0,
17187c478bd9Sstevel@tonic-gate EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
17197c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, (void *)hostname, 0,
17207c478bd9Sstevel@tonic-gate EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
17217c478bd9Sstevel@tonic-gate if (flags == EP_RAW)
17227c478bd9Sstevel@tonic-gate cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG;
17237c478bd9Sstevel@tonic-gate else
17247c478bd9Sstevel@tonic-gate cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG;
17257c478bd9Sstevel@tonic-gate (void) ea_attach_item(tag, ubuf, ubufsz, cat);
17267c478bd9Sstevel@tonic-gate
17277c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(tag, NULL, 0);
17287c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_SLEEP);
17297c478bd9Sstevel@tonic-gate (void) ea_pack_object(tag, buf, bufsize);
17307c478bd9Sstevel@tonic-gate error = exacct_vn_write(ac_proc, buf, bufsize);
17317c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize);
17327c478bd9Sstevel@tonic-gate ea_free_object(tag, EUP_ALLOC);
17337c478bd9Sstevel@tonic-gate return (error);
17347c478bd9Sstevel@tonic-gate }
17357c478bd9Sstevel@tonic-gate
17367c478bd9Sstevel@tonic-gate /*
17377c478bd9Sstevel@tonic-gate * void exacct_init(void)
17387c478bd9Sstevel@tonic-gate *
17397c478bd9Sstevel@tonic-gate * Overview
17407c478bd9Sstevel@tonic-gate * Initialized the extended accounting subsystem.
17417c478bd9Sstevel@tonic-gate *
17427c478bd9Sstevel@tonic-gate * Return values
17437c478bd9Sstevel@tonic-gate * None.
17447c478bd9Sstevel@tonic-gate *
17457c478bd9Sstevel@tonic-gate * Caller's context
17467c478bd9Sstevel@tonic-gate * Suitable for KM_SLEEP allocations.
17477c478bd9Sstevel@tonic-gate */
17487c478bd9Sstevel@tonic-gate void
exacct_init()17497c478bd9Sstevel@tonic-gate exacct_init()
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate exacct_queue = system_taskq;
17527c478bd9Sstevel@tonic-gate exacct_object_cache = kmem_cache_create("exacct_object_cache",
17537c478bd9Sstevel@tonic-gate sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
1754ff19e029SMenno Lageman task_commit_thread_init();
17557c478bd9Sstevel@tonic-gate }
17567eceb558Srh
17577eceb558Srh /*
17587eceb558Srh * exacct_snapshot_proc_mstate() copies a process's microstate accounting data
17597eceb558Srh * and resource usage counters into a given task_usage_t. It differs from
17607eceb558Srh * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t,
17617eceb558Srh * b) p_lock will have been acquired earlier in the call path and c) we
17627eceb558Srh * are here including the process's user and system times.
17637eceb558Srh */
17647eceb558Srh static void
exacct_snapshot_proc_mstate(proc_t * p,task_usage_t * tu)17657eceb558Srh exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu)
17667eceb558Srh {
17677eceb558Srh tu->tu_utime = mstate_aggr_state(p, LMS_USER);
17687eceb558Srh tu->tu_stime = mstate_aggr_state(p, LMS_SYSTEM);
17697eceb558Srh tu->tu_minflt = p->p_ru.minflt;
17707eceb558Srh tu->tu_majflt = p->p_ru.majflt;
17717eceb558Srh tu->tu_sndmsg = p->p_ru.msgsnd;
17727eceb558Srh tu->tu_rcvmsg = p->p_ru.msgrcv;
17737eceb558Srh tu->tu_ioch = p->p_ru.ioch;
17747eceb558Srh tu->tu_iblk = p->p_ru.inblock;
17757eceb558Srh tu->tu_oblk = p->p_ru.oublock;
17767eceb558Srh tu->tu_vcsw = p->p_ru.nvcsw;
17777eceb558Srh tu->tu_icsw = p->p_ru.nivcsw;
17787eceb558Srh tu->tu_nsig = p->p_ru.nsignals;
17797eceb558Srh tu->tu_nswp = p->p_ru.nswap;
17807eceb558Srh tu->tu_nscl = p->p_ru.sysc;
17817eceb558Srh }
17827eceb558Srh
17837eceb558Srh /*
17847eceb558Srh * void exacct_move_mstate(proc_t *, task_t *, task_t *)
17857eceb558Srh *
17867eceb558Srh * Overview
17877eceb558Srh * exacct_move_mstate() is called by task_change() and accounts for
17887eceb558Srh * a process's resource usage when it is moved from one task to another.
17897eceb558Srh *
17907eceb558Srh * The process's usage at this point is recorded in the new task so
17917eceb558Srh * that it can be excluded from the calculation of resources consumed
17927eceb558Srh * by that task.
17937eceb558Srh *
17947eceb558Srh * The resource usage inherited by the new task is also added to the
17957eceb558Srh * aggregate maintained by the old task for processes that have exited.
17967eceb558Srh *
17977eceb558Srh * Return values
17987eceb558Srh * None.
17997eceb558Srh *
18007eceb558Srh * Caller's context
18017eceb558Srh * pidlock and p_lock held across exacct_move_mstate().
18027eceb558Srh */
18037eceb558Srh void
exacct_move_mstate(proc_t * p,task_t * oldtk,task_t * newtk)18047eceb558Srh exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk)
18057eceb558Srh {
18067eceb558Srh task_usage_t tu;
18077eceb558Srh
18087eceb558Srh /* Take a snapshot of this process's mstate and RU counters */
18097eceb558Srh exacct_snapshot_proc_mstate(p, &tu);
18107eceb558Srh
18117eceb558Srh /*
18127eceb558Srh * Use the snapshot to increment the aggregate usage of the old
18137eceb558Srh * task, and the inherited usage of the new one.
18147eceb558Srh */
18157eceb558Srh mutex_enter(&oldtk->tk_usage_lock);
18167eceb558Srh exacct_add_task_mstate(oldtk->tk_usage, &tu);
18177eceb558Srh mutex_exit(&oldtk->tk_usage_lock);
18187eceb558Srh mutex_enter(&newtk->tk_usage_lock);
18197eceb558Srh exacct_add_task_mstate(newtk->tk_inherited, &tu);
18207eceb558Srh mutex_exit(&newtk->tk_usage_lock);
18217eceb558Srh }
1822