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