xref: /onnv-gate/usr/src/uts/common/os/exacct.c (revision 8275:7c223a798022)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54584Srh87107  * Common Development and Distribution License (the "License").
64584Srh87107  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
227103Sml93401  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/exacct.h>
270Sstevel@tonic-gate #include <sys/exacct_catalog.h>
280Sstevel@tonic-gate #include <sys/disp.h>
290Sstevel@tonic-gate #include <sys/task.h>
300Sstevel@tonic-gate #include <sys/proc.h>
310Sstevel@tonic-gate #include <sys/cmn_err.h>
320Sstevel@tonic-gate #include <sys/kmem.h>
330Sstevel@tonic-gate #include <sys/project.h>
340Sstevel@tonic-gate #include <sys/systm.h>
350Sstevel@tonic-gate #include <sys/vnode.h>
360Sstevel@tonic-gate #include <sys/file.h>
370Sstevel@tonic-gate #include <sys/acctctl.h>
380Sstevel@tonic-gate #include <sys/time.h>
390Sstevel@tonic-gate #include <sys/utsname.h>
400Sstevel@tonic-gate #include <sys/session.h>
410Sstevel@tonic-gate #include <sys/sysmacros.h>
420Sstevel@tonic-gate #include <sys/bitmap.h>
430Sstevel@tonic-gate #include <sys/msacct.h>
44*8275SEric Cheng #include <sys/mac.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * exacct usage and recording routines
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * wracct(2), getacct(2), and the records written at process or task
500Sstevel@tonic-gate  * termination are constructed using the exacct_assemble_[task,proc]_usage()
510Sstevel@tonic-gate  * functions, which take a callback that takes the appropriate action on
520Sstevel@tonic-gate  * the packed exacct record for the task or process.  For the process-related
530Sstevel@tonic-gate  * actions, we partition the routines such that the data collecting component
540Sstevel@tonic-gate  * can be performed while holding p_lock, and all sleeping or blocking
550Sstevel@tonic-gate  * operations can be performed without acquiring p_lock.
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * putacct(2), which allows an application to construct a customized record
580Sstevel@tonic-gate  * associated with an existing process or task, has its own entry points:
590Sstevel@tonic-gate  * exacct_tag_task() and exacct_tag_proc().
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate 
620Sstevel@tonic-gate taskq_t *exacct_queue;
630Sstevel@tonic-gate kmem_cache_t *exacct_object_cache;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION;
680Sstevel@tonic-gate static const char exacct_header[] = "exacct";
690Sstevel@tonic-gate static const char exacct_creator[] = "SunOS";
700Sstevel@tonic-gate 
710Sstevel@tonic-gate ea_object_t *
720Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	ea_object_t *item;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
770Sstevel@tonic-gate 	bzero(item, sizeof (ea_object_t));
780Sstevel@tonic-gate 	(void) ea_set_item(item, catalog, buf, bufsz);
790Sstevel@tonic-gate 	return (item);
800Sstevel@tonic-gate }
810Sstevel@tonic-gate 
820Sstevel@tonic-gate ea_object_t *
830Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	ea_object_t *group;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
880Sstevel@tonic-gate 	bzero(group, sizeof (ea_object_t));
890Sstevel@tonic-gate 	(void) ea_set_group(group, catalog);
900Sstevel@tonic-gate 	return (group);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate ea_object_t *
940Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	ea_object_t *item;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	item = ea_alloc_item(catalog, buf, bufsz);
990Sstevel@tonic-gate 	(void) ea_attach_to_group(grp, item);
1000Sstevel@tonic-gate 	return (item);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
1044584Srh87107  * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract
1054584Srh87107  * microstate accounting data and resource usage counters from one task_usage_t
1064584Srh87107  * from those supplied in another. These functions do not operate on *all*
1074584Srh87107  * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make
1084584Srh87107  * sense.
1094584Srh87107  */
1104584Srh87107 static void
1114584Srh87107 exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta)
1124584Srh87107 {
1134584Srh87107 	tu->tu_utime  += delta->tu_utime;
1144584Srh87107 	tu->tu_stime  += delta->tu_stime;
1154584Srh87107 	tu->tu_minflt += delta->tu_minflt;
1164584Srh87107 	tu->tu_majflt += delta->tu_majflt;
1174584Srh87107 	tu->tu_sndmsg += delta->tu_sndmsg;
1184584Srh87107 	tu->tu_rcvmsg += delta->tu_rcvmsg;
1194584Srh87107 	tu->tu_ioch   += delta->tu_ioch;
1204584Srh87107 	tu->tu_iblk   += delta->tu_iblk;
1214584Srh87107 	tu->tu_oblk   += delta->tu_oblk;
1224584Srh87107 	tu->tu_vcsw   += delta->tu_vcsw;
1234584Srh87107 	tu->tu_icsw   += delta->tu_icsw;
1244584Srh87107 	tu->tu_nsig   += delta->tu_nsig;
1254584Srh87107 	tu->tu_nswp   += delta->tu_nswp;
1264584Srh87107 	tu->tu_nscl   += delta->tu_nscl;
1274584Srh87107 }
1284584Srh87107 
1294584Srh87107 /*
1304584Srh87107  * See the comments for exacct_add_task_mstate(), above.
1314584Srh87107  */
1324584Srh87107 static void
1334584Srh87107 exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta)
1344584Srh87107 {
1354584Srh87107 	tu->tu_utime  -= delta->tu_utime;
1364584Srh87107 	tu->tu_stime  -= delta->tu_stime;
1374584Srh87107 	tu->tu_minflt -= delta->tu_minflt;
1384584Srh87107 	tu->tu_majflt -= delta->tu_majflt;
1394584Srh87107 	tu->tu_sndmsg -= delta->tu_sndmsg;
1404584Srh87107 	tu->tu_rcvmsg -= delta->tu_rcvmsg;
1414584Srh87107 	tu->tu_ioch   -= delta->tu_ioch;
1424584Srh87107 	tu->tu_iblk   -= delta->tu_iblk;
1434584Srh87107 	tu->tu_oblk   -= delta->tu_oblk;
1444584Srh87107 	tu->tu_vcsw   -= delta->tu_vcsw;
1454584Srh87107 	tu->tu_icsw   -= delta->tu_icsw;
1464584Srh87107 	tu->tu_nsig   -= delta->tu_nsig;
1474584Srh87107 	tu->tu_nswp   -= delta->tu_nswp;
1484584Srh87107 	tu->tu_nscl   -= delta->tu_nscl;
1494584Srh87107 }
1504584Srh87107 
1514584Srh87107 /*
1527103Sml93401  * Wrapper for vn_rdwr() used by exacct_vn_write() and exacct_write_header()
1537103Sml93401  * to write to the accounting file without corrupting it in case of an I/O or
1547103Sml93401  * filesystem error.
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate static int
1577103Sml93401 exacct_vn_write_impl(ac_info_t *info, void *buf, ssize_t bufsize)
1580Sstevel@tonic-gate {
1597103Sml93401 	int error;
1600Sstevel@tonic-gate 	ssize_t resid;
1610Sstevel@tonic-gate 	struct vattr va;
1620Sstevel@tonic-gate 
1637103Sml93401 	ASSERT(info != NULL);
1647103Sml93401 	ASSERT(info->ac_vnode != NULL);
1657103Sml93401 	ASSERT(MUTEX_HELD(&info->ac_lock));
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	/*
1680Sstevel@tonic-gate 	 * Save the size. If vn_rdwr fails, reset the size to avoid corrupting
1690Sstevel@tonic-gate 	 * the present accounting file.
1700Sstevel@tonic-gate 	 */
1710Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
1725331Samw 	error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1730Sstevel@tonic-gate 	if (error == 0) {
1740Sstevel@tonic-gate 		error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf,
1750Sstevel@tonic-gate 		    bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T,
1760Sstevel@tonic-gate 		    kcred, &resid);
1770Sstevel@tonic-gate 		if (error) {
1780Sstevel@tonic-gate 			(void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1790Sstevel@tonic-gate 		} else if (resid != 0) {
1800Sstevel@tonic-gate 			(void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1810Sstevel@tonic-gate 			error = ENOSPC;
1820Sstevel@tonic-gate 		}
1830Sstevel@tonic-gate 	}
1847103Sml93401 	return (error);
1857103Sml93401 }
1867103Sml93401 
1877103Sml93401 /*
1887103Sml93401  * exacct_vn_write() safely writes to an accounting file.  acctctl() prevents
1897103Sml93401  * the two accounting vnodes from being equal, and the appropriate ac_lock is
1907103Sml93401  * held across the call, so we're single threaded through this code for each
1917103Sml93401  * file.
1927103Sml93401  */
1937103Sml93401 static int
1947103Sml93401 exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize)
1957103Sml93401 {
1967103Sml93401 	int error;
1977103Sml93401 
1987103Sml93401 	if (info == NULL)
1997103Sml93401 		return (0);
2007103Sml93401 
2017103Sml93401 	mutex_enter(&info->ac_lock);
2027103Sml93401 
2037103Sml93401 	/*
2047103Sml93401 	 * Don't do anything unless accounting file is set.
2057103Sml93401 	 */
2067103Sml93401 	if (info->ac_vnode == NULL) {
2077103Sml93401 		mutex_exit(&info->ac_lock);
2087103Sml93401 		return (0);
2097103Sml93401 	}
2107103Sml93401 	error = exacct_vn_write_impl(info, buf, bufsize);
2110Sstevel@tonic-gate 	mutex_exit(&info->ac_lock);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	return (error);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate  * void *exacct_create_header(size_t *)
2180Sstevel@tonic-gate  *
2190Sstevel@tonic-gate  * Overview
2200Sstevel@tonic-gate  *   exacct_create_header() constructs an exacct file header identifying the
2210Sstevel@tonic-gate  *   accounting file as the output of the kernel.  exacct_create_header() and
2220Sstevel@tonic-gate  *   the static write_header() and verify_header() routines in libexacct must
2230Sstevel@tonic-gate  *   remain synchronized.
2240Sstevel@tonic-gate  *
2250Sstevel@tonic-gate  * Return values
2260Sstevel@tonic-gate  *   A pointer to a packed exacct buffer containing the appropriate header is
2270Sstevel@tonic-gate  *   returned; the size of the buffer is placed in the location indicated by
2280Sstevel@tonic-gate  *   sizep.
2290Sstevel@tonic-gate  *
2300Sstevel@tonic-gate  * Caller's context
2310Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate void *
2340Sstevel@tonic-gate exacct_create_header(size_t *sizep)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	ea_object_t *hdr_grp;
2370Sstevel@tonic-gate 	uint32_t bskip;
2380Sstevel@tonic-gate 	void *buf;
2390Sstevel@tonic-gate 	size_t bufsize;
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER);
2420Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0,
2430Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_VERSION);
2440Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)exacct_header, 0,
2450Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_FILETYPE);
2460Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0,
2470Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_CREATOR);
2480Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, uts_nodename(), 0,
2490Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	bufsize = ea_pack_object(hdr_grp, NULL, 0);
2520Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
2530Sstevel@tonic-gate 	(void) ea_pack_object(hdr_grp, buf, bufsize);
2540Sstevel@tonic-gate 	ea_free_object(hdr_grp, EUP_ALLOC);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	/*
2570Sstevel@tonic-gate 	 * To prevent reading the header when reading the file backwards,
2580Sstevel@tonic-gate 	 * set the large backskip of the header group to 0 (last 4 bytes).
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	bskip = 0;
2610Sstevel@tonic-gate 	exacct_order32(&bskip);
2620Sstevel@tonic-gate 	bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip),
2630Sstevel@tonic-gate 	    sizeof (bskip));
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	*sizep = bufsize;
2660Sstevel@tonic-gate 	return (buf);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate  * int exacct_write_header(ac_info_t *, void *, size_t)
2710Sstevel@tonic-gate  *
2720Sstevel@tonic-gate  * Overview
2730Sstevel@tonic-gate  *   exacct_write_header() writes the given header buffer to the indicated
2747103Sml93401  *   vnode.
2750Sstevel@tonic-gate  *
2760Sstevel@tonic-gate  * Return values
2770Sstevel@tonic-gate  *   The result of the write operation is returned.
2780Sstevel@tonic-gate  *
2790Sstevel@tonic-gate  * Caller's context
2807103Sml93401  *   Caller must hold the ac_lock of the appropriate accounting file
2810Sstevel@tonic-gate  *   information block (ac_info_t).
2820Sstevel@tonic-gate  */
2830Sstevel@tonic-gate int
2840Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize)
2850Sstevel@tonic-gate {
2867103Sml93401 	if (info != NULL && info->ac_vnode != NULL)
2877103Sml93401 		return (exacct_vn_write_impl(info, hdr, hdrsize));
2880Sstevel@tonic-gate 
2897103Sml93401 	return (0);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate static void
2930Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu,
2940Sstevel@tonic-gate     task_usage_t **tu_buf)
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate 	task_usage_t *oldtu, *newtu;
2970Sstevel@tonic-gate 	task_usage_t **prevusage;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&tk->tk_usage_lock));
3000Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID) {
3010Sstevel@tonic-gate 		prevusage = &tk->tk_zoneusage;
3020Sstevel@tonic-gate 	} else {
3030Sstevel@tonic-gate 		prevusage = &tk->tk_prevusage;
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 	if ((oldtu = *prevusage) != NULL) {
3060Sstevel@tonic-gate 		/*
3070Sstevel@tonic-gate 		 * In case we have any accounting information
3080Sstevel@tonic-gate 		 * saved from the previous interval record.
3090Sstevel@tonic-gate 		 */
3100Sstevel@tonic-gate 		newtu = *tu_buf;
3110Sstevel@tonic-gate 		bcopy(tu, newtu, sizeof (task_usage_t));
3120Sstevel@tonic-gate 		tu->tu_minflt	-= oldtu->tu_minflt;
3130Sstevel@tonic-gate 		tu->tu_majflt	-= oldtu->tu_majflt;
3140Sstevel@tonic-gate 		tu->tu_sndmsg	-= oldtu->tu_sndmsg;
3150Sstevel@tonic-gate 		tu->tu_rcvmsg	-= oldtu->tu_rcvmsg;
3160Sstevel@tonic-gate 		tu->tu_ioch	-= oldtu->tu_ioch;
3170Sstevel@tonic-gate 		tu->tu_iblk	-= oldtu->tu_iblk;
3180Sstevel@tonic-gate 		tu->tu_oblk	-= oldtu->tu_oblk;
3190Sstevel@tonic-gate 		tu->tu_vcsw	-= oldtu->tu_vcsw;
3200Sstevel@tonic-gate 		tu->tu_icsw	-= oldtu->tu_icsw;
3210Sstevel@tonic-gate 		tu->tu_nsig	-= oldtu->tu_nsig;
3220Sstevel@tonic-gate 		tu->tu_nswp	-= oldtu->tu_nswp;
3230Sstevel@tonic-gate 		tu->tu_nscl	-= oldtu->tu_nscl;
3240Sstevel@tonic-gate 		tu->tu_utime	-= oldtu->tu_utime;
3250Sstevel@tonic-gate 		tu->tu_stime	-= oldtu->tu_stime;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 		tu->tu_startsec = oldtu->tu_finishsec;
3280Sstevel@tonic-gate 		tu->tu_startnsec = oldtu->tu_finishnsec;
3290Sstevel@tonic-gate 		/*
3300Sstevel@tonic-gate 		 * Copy the data from our temporary storage to the task's
3310Sstevel@tonic-gate 		 * previous interval usage structure for future reference.
3320Sstevel@tonic-gate 		 */
3330Sstevel@tonic-gate 		bcopy(newtu, oldtu, sizeof (task_usage_t));
3340Sstevel@tonic-gate 	} else {
3350Sstevel@tonic-gate 		/*
3360Sstevel@tonic-gate 		 * Store current statistics in the task's previous interval
3370Sstevel@tonic-gate 		 * usage structure for future references.
3380Sstevel@tonic-gate 		 */
3390Sstevel@tonic-gate 		*prevusage = *tu_buf;
3400Sstevel@tonic-gate 		bcopy(tu, *prevusage, sizeof (task_usage_t));
3410Sstevel@tonic-gate 		*tu_buf = NULL;
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate static void
3460Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	timestruc_t ts;
3490Sstevel@tonic-gate 	proc_t *p;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if ((p = tk->tk_memb_list) == NULL)
3540Sstevel@tonic-gate 		return;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/*
3570Sstevel@tonic-gate 	 * exacct_snapshot_task_usage() provides an approximate snapshot of the
3580Sstevel@tonic-gate 	 * usage of the potentially many members of the task.  Since we don't
3590Sstevel@tonic-gate 	 * guarantee exactness, we don't acquire the p_lock of any of the member
3600Sstevel@tonic-gate 	 * processes.
3610Sstevel@tonic-gate 	 */
3620Sstevel@tonic-gate 	do {
3630Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
3640Sstevel@tonic-gate 		tu->tu_utime	+= mstate_aggr_state(p, LMS_USER);
3650Sstevel@tonic-gate 		tu->tu_stime	+= mstate_aggr_state(p, LMS_SYSTEM);
3660Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3670Sstevel@tonic-gate 		tu->tu_minflt	+= p->p_ru.minflt;
3680Sstevel@tonic-gate 		tu->tu_majflt	+= p->p_ru.majflt;
3690Sstevel@tonic-gate 		tu->tu_sndmsg	+= p->p_ru.msgsnd;
3700Sstevel@tonic-gate 		tu->tu_rcvmsg	+= p->p_ru.msgrcv;
3710Sstevel@tonic-gate 		tu->tu_ioch	+= p->p_ru.ioch;
3720Sstevel@tonic-gate 		tu->tu_iblk	+= p->p_ru.inblock;
3730Sstevel@tonic-gate 		tu->tu_oblk	+= p->p_ru.oublock;
3740Sstevel@tonic-gate 		tu->tu_vcsw	+= p->p_ru.nvcsw;
3750Sstevel@tonic-gate 		tu->tu_icsw	+= p->p_ru.nivcsw;
3760Sstevel@tonic-gate 		tu->tu_nsig	+= p->p_ru.nsignals;
3770Sstevel@tonic-gate 		tu->tu_nswp	+= p->p_ru.nswap;
3780Sstevel@tonic-gate 		tu->tu_nscl	+= p->p_ru.sysc;
3790Sstevel@tonic-gate 	} while ((p = p->p_tasknext) != tk->tk_memb_list);
3800Sstevel@tonic-gate 
3814584Srh87107 	/*
3824584Srh87107 	 * The resource usage accounted for so far will include that
3834584Srh87107 	 * contributed by the task's first process. If this process
3844584Srh87107 	 * came from another task, then its accumulated resource usage
3854584Srh87107 	 * will include a contribution from work performed there.
3864584Srh87107 	 * We must therefore subtract any resource usage that was
3874584Srh87107 	 * inherited with the first process.
3884584Srh87107 	 */
3894584Srh87107 	exacct_sub_task_mstate(tu, tk->tk_inherited);
3904584Srh87107 
3910Sstevel@tonic-gate 	gethrestime(&ts);
3920Sstevel@tonic-gate 	tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
3930Sstevel@tonic-gate 	tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate /*
3974584Srh87107  * void exacct_update_task_mstate(proc_t *)
3984584Srh87107  *
3994584Srh87107  * Overview
4004584Srh87107  *   exacct_update_task_mstate() updates the task usage; it is intended
4014584Srh87107  *   to be called from proc_exit().
4024584Srh87107  *
4034584Srh87107  * Return values
4044584Srh87107  *   None.
4054584Srh87107  *
4064584Srh87107  * Caller's context
4074584Srh87107  *   p_lock must be held at entry.
4080Sstevel@tonic-gate  */
4094584Srh87107 void
4100Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p)
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate 	task_usage_t *tu;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	mutex_enter(&p->p_task->tk_usage_lock);
4150Sstevel@tonic-gate 	tu = p->p_task->tk_usage;
4160Sstevel@tonic-gate 	tu->tu_utime	+= mstate_aggr_state(p, LMS_USER);
4170Sstevel@tonic-gate 	tu->tu_stime	+= mstate_aggr_state(p, LMS_SYSTEM);
4180Sstevel@tonic-gate 	tu->tu_minflt	+= p->p_ru.minflt;
4190Sstevel@tonic-gate 	tu->tu_majflt	+= p->p_ru.majflt;
4200Sstevel@tonic-gate 	tu->tu_sndmsg	+= p->p_ru.msgsnd;
4210Sstevel@tonic-gate 	tu->tu_rcvmsg	+= p->p_ru.msgrcv;
4220Sstevel@tonic-gate 	tu->tu_ioch	+= p->p_ru.ioch;
4230Sstevel@tonic-gate 	tu->tu_iblk	+= p->p_ru.inblock;
4240Sstevel@tonic-gate 	tu->tu_oblk	+= p->p_ru.oublock;
4250Sstevel@tonic-gate 	tu->tu_vcsw	+= p->p_ru.nvcsw;
4260Sstevel@tonic-gate 	tu->tu_icsw	+= p->p_ru.nivcsw;
4270Sstevel@tonic-gate 	tu->tu_nsig	+= p->p_ru.nsignals;
4280Sstevel@tonic-gate 	tu->tu_nswp	+= p->p_ru.nswap;
4290Sstevel@tonic-gate 	tu->tu_nscl	+= p->p_ru.sysc;
4300Sstevel@tonic-gate 	mutex_exit(&p->p_task->tk_usage_lock);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate static void
4340Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	timestruc_t ts;
4370Sstevel@tonic-gate 	task_usage_t *tu_buf;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	switch (flag) {
4400Sstevel@tonic-gate 	case EW_PARTIAL:
4410Sstevel@tonic-gate 		/*
4420Sstevel@tonic-gate 		 * For partial records we must report the sum of current
4430Sstevel@tonic-gate 		 * accounting statistics with previously accumulated
4440Sstevel@tonic-gate 		 * statistics.
4450Sstevel@tonic-gate 		 */
4460Sstevel@tonic-gate 		mutex_enter(&pidlock);
4470Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4500Sstevel@tonic-gate 		exacct_snapshot_task_usage(tk, tu);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
4530Sstevel@tonic-gate 		mutex_exit(&pidlock);
4540Sstevel@tonic-gate 		break;
4550Sstevel@tonic-gate 	case EW_INTERVAL:
4560Sstevel@tonic-gate 		/*
4570Sstevel@tonic-gate 		 * We need to allocate spare task_usage_t buffer before
4580Sstevel@tonic-gate 		 * grabbing pidlock because we might need it later in
4590Sstevel@tonic-gate 		 * exacct_get_interval_task_usage().
4600Sstevel@tonic-gate 		 */
4610Sstevel@tonic-gate 		tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
4620Sstevel@tonic-gate 		mutex_enter(&pidlock);
4630Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 		/*
4660Sstevel@tonic-gate 		 * For interval records, we deduct the previous microstate
4670Sstevel@tonic-gate 		 * accounting data and cpu usage times from previously saved
4680Sstevel@tonic-gate 		 * results and update the previous task usage structure.
4690Sstevel@tonic-gate 		 */
4700Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4710Sstevel@tonic-gate 		exacct_snapshot_task_usage(tk, tu);
4720Sstevel@tonic-gate 		exacct_get_interval_task_usage(tk, tu, &tu_buf);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
4750Sstevel@tonic-gate 		mutex_exit(&pidlock);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		if (tu_buf != NULL)
4780Sstevel@tonic-gate 			kmem_free(tu_buf, sizeof (task_usage_t));
4790Sstevel@tonic-gate 		break;
4800Sstevel@tonic-gate 	case EW_FINAL:
4810Sstevel@tonic-gate 		/*
4824584Srh87107 		 * For final records, we deduct, from the task's current
4834584Srh87107 		 * usage, any usage that was inherited with the arrival
4844584Srh87107 		 * of a process from a previous task. We then record
4854584Srh87107 		 * the task's finish time.
4860Sstevel@tonic-gate 		 */
4870Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
4880Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4894584Srh87107 		exacct_sub_task_mstate(tu, tk->tk_inherited);
4900Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		gethrestime(&ts);
4930Sstevel@tonic-gate 		tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
4940Sstevel@tonic-gate 		tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		break;
4970Sstevel@tonic-gate 	}
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate static int
5010Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record,
5020Sstevel@tonic-gate     int res)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate 	int attached = 1;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	switch (res) {
5070Sstevel@tonic-gate 	case AC_TASK_TASKID:
5080Sstevel@tonic-gate 		(void) ea_attach_item(record, &tk->tk_tkid,
5090Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID);
5100Sstevel@tonic-gate 		break;
5110Sstevel@tonic-gate 	case AC_TASK_PROJID:
5120Sstevel@tonic-gate 		(void) ea_attach_item(record, &tk->tk_proj->kpj_id,
5130Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID);
5140Sstevel@tonic-gate 		break;
5150Sstevel@tonic-gate 	case AC_TASK_CPU: {
5160Sstevel@tonic-gate 			timestruc_t ts;
5170Sstevel@tonic-gate 			uint64_t ui;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 			hrt2ts(tu->tu_stime, &ts);
5200Sstevel@tonic-gate 			ui = ts.tv_sec;
5210Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5220Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_SYS_SEC);
5230Sstevel@tonic-gate 			ui = ts.tv_nsec;
5240Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5250Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 			hrt2ts(tu->tu_utime, &ts);
5280Sstevel@tonic-gate 			ui = ts.tv_sec;
5290Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5300Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_USER_SEC);
5310Sstevel@tonic-gate 			ui = ts.tv_nsec;
5320Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5330Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_USER_NSEC);
5340Sstevel@tonic-gate 		}
5350Sstevel@tonic-gate 		break;
5360Sstevel@tonic-gate 	case AC_TASK_TIME:
5370Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_startsec,
5380Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC);
5390Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_startnsec,
5400Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC);
5410Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_finishsec,
5420Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC);
5430Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_finishnsec,
5440Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC);
5450Sstevel@tonic-gate 		break;
5460Sstevel@tonic-gate 	case AC_TASK_HOSTNAME:
5470Sstevel@tonic-gate 		(void) ea_attach_item(record, tk->tk_zone->zone_nodename,
5480Sstevel@tonic-gate 		    strlen(tk->tk_zone->zone_nodename) + 1,
5490Sstevel@tonic-gate 		    EXT_STRING | EXD_TASK_HOSTNAME);
5500Sstevel@tonic-gate 			break;
5510Sstevel@tonic-gate 	case AC_TASK_MICROSTATE:
5520Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_majflt,
5530Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR);
5540Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_minflt,
5550Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR);
5560Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_sndmsg,
5570Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND);
5580Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_rcvmsg,
5590Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV);
5600Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_iblk,
5610Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN);
5620Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_oblk,
5630Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT);
5640Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_ioch,
5650Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR);
5660Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_vcsw,
5670Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL);
5680Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_icsw,
5690Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV);
5700Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nsig,
5710Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS);
5720Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nswp,
5730Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS);
5740Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nscl,
5750Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS);
5760Sstevel@tonic-gate 		break;
5770Sstevel@tonic-gate 	case AC_TASK_ANCTASKID:
5780Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_anctaskid,
5790Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID);
5800Sstevel@tonic-gate 		break;
5810Sstevel@tonic-gate 	case AC_TASK_ZONENAME:
5820Sstevel@tonic-gate 		(void) ea_attach_item(record, tk->tk_zone->zone_name,
5830Sstevel@tonic-gate 		    strlen(tk->tk_zone->zone_name) + 1,
5840Sstevel@tonic-gate 		    EXT_STRING | EXD_TASK_ZONENAME);
5850Sstevel@tonic-gate 		break;
5860Sstevel@tonic-gate 	default:
5870Sstevel@tonic-gate 		attached = 0;
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 	return (attached);
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate static ea_object_t *
5930Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask,
5940Sstevel@tonic-gate     ea_catalog_t record_type)
5950Sstevel@tonic-gate {
5960Sstevel@tonic-gate 	int res, count;
5970Sstevel@tonic-gate 	ea_object_t *record;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	/*
6000Sstevel@tonic-gate 	 * Assemble usage values into group.
6010Sstevel@tonic-gate 	 */
6020Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
6030Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++)
6040Sstevel@tonic-gate 		if (BT_TEST(mask, res))
6050Sstevel@tonic-gate 			count += exacct_attach_task_item(tk, tu, record, res);
6060Sstevel@tonic-gate 	if (count == 0) {
6070Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
6080Sstevel@tonic-gate 		record = NULL;
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 	return (record);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate  * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *,
6150Sstevel@tonic-gate  *	size_t, size_t *), void *, size_t, size_t *, int)
6160Sstevel@tonic-gate  *
6170Sstevel@tonic-gate  * Overview
6180Sstevel@tonic-gate  *   exacct_assemble_task_usage() builds the packed exacct buffer for the
6190Sstevel@tonic-gate  *   indicated task, executes the given callback function, and free the packed
6200Sstevel@tonic-gate  *   buffer.
6210Sstevel@tonic-gate  *
6220Sstevel@tonic-gate  * Return values
6230Sstevel@tonic-gate  *   Returns 0 on success; otherwise the appropriate error code is returned.
6240Sstevel@tonic-gate  *
6250Sstevel@tonic-gate  * Caller's context
6260Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
6270Sstevel@tonic-gate  */
6280Sstevel@tonic-gate int
6290Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk,
6300Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
6310Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual, int flag)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
6340Sstevel@tonic-gate 	ea_object_t *task_record;
6350Sstevel@tonic-gate 	ea_catalog_t record_type;
6360Sstevel@tonic-gate 	task_usage_t *tu;
6370Sstevel@tonic-gate 	void *buf;
6380Sstevel@tonic-gate 	size_t bufsize;
6390Sstevel@tonic-gate 	int ret;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	mutex_enter(&ac_task->ac_lock);
6440Sstevel@tonic-gate 	if (ac_task->ac_state == AC_OFF) {
6450Sstevel@tonic-gate 		mutex_exit(&ac_task->ac_lock);
6460Sstevel@tonic-gate 		return (ENOTACTIVE);
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 	bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ);
6490Sstevel@tonic-gate 	mutex_exit(&ac_task->ac_lock);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	switch (flag) {
6520Sstevel@tonic-gate 	case EW_FINAL:
6530Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK;
6540Sstevel@tonic-gate 		break;
6550Sstevel@tonic-gate 	case EW_PARTIAL:
6560Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK_PARTIAL;
6570Sstevel@tonic-gate 		break;
6580Sstevel@tonic-gate 	case EW_INTERVAL:
6590Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK_INTERVAL;
6600Sstevel@tonic-gate 		break;
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	/*
6640Sstevel@tonic-gate 	 * Calculate task usage and assemble it into the task record.
6650Sstevel@tonic-gate 	 */
6660Sstevel@tonic-gate 	tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
6670Sstevel@tonic-gate 	exacct_calculate_task_usage(tk, tu, flag);
6680Sstevel@tonic-gate 	task_record = exacct_assemble_task_record(tk, tu, mask, record_type);
6690Sstevel@tonic-gate 	if (task_record == NULL) {
6700Sstevel@tonic-gate 		/*
6710Sstevel@tonic-gate 		 * The current configuration of the accounting system has
6720Sstevel@tonic-gate 		 * resulted in records with no data; accordingly, we don't write
6730Sstevel@tonic-gate 		 * these, but we return success.
6740Sstevel@tonic-gate 		 */
6750Sstevel@tonic-gate 		kmem_free(tu, sizeof (task_usage_t));
6760Sstevel@tonic-gate 		return (0);
6770Sstevel@tonic-gate 	}
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	/*
6800Sstevel@tonic-gate 	 * Pack object into buffer and run callback on it.
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	bufsize = ea_pack_object(task_record, NULL, 0);
6830Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
6840Sstevel@tonic-gate 	(void) ea_pack_object(task_record, buf, bufsize);
6850Sstevel@tonic-gate 	ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/*
6880Sstevel@tonic-gate 	 * Free all previously allocated structures.
6890Sstevel@tonic-gate 	 */
6900Sstevel@tonic-gate 	kmem_free(buf, bufsize);
6910Sstevel@tonic-gate 	ea_free_object(task_record, EUP_ALLOC);
6920Sstevel@tonic-gate 	kmem_free(tu, sizeof (task_usage_t));
6930Sstevel@tonic-gate 	return (ret);
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate /*
6970Sstevel@tonic-gate  * void exacct_commit_task(void *)
6980Sstevel@tonic-gate  *
6990Sstevel@tonic-gate  * Overview
7000Sstevel@tonic-gate  *   exacct_commit_task() calculates the final usage for a task, updating the
7010Sstevel@tonic-gate  *   task usage if task accounting is active, and writing a task record if task
7020Sstevel@tonic-gate  *   accounting is active.  exacct_commit_task() is intended for being called
7030Sstevel@tonic-gate  *   from a task queue (taskq_t).
7040Sstevel@tonic-gate  *
7050Sstevel@tonic-gate  * Return values
7060Sstevel@tonic-gate  *   None.
7070Sstevel@tonic-gate  *
7080Sstevel@tonic-gate  * Caller's context
7090Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
7100Sstevel@tonic-gate  */
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate void
7130Sstevel@tonic-gate exacct_commit_task(void *arg)
7140Sstevel@tonic-gate {
7150Sstevel@tonic-gate 	task_t *tk = (task_t *)arg;
7160Sstevel@tonic-gate 	size_t size;
7170Sstevel@tonic-gate 	zone_t *zone = tk->tk_zone;
7180Sstevel@tonic-gate 	struct exacct_globals *acg;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	ASSERT(tk != task0p);
7210Sstevel@tonic-gate 	ASSERT(tk->tk_memb_list == NULL);
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	/*
7240Sstevel@tonic-gate 	 * Don't do any extra work if the acctctl module isn't loaded.
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) {
7270Sstevel@tonic-gate 		acg = zone_getspecific(exacct_zone_key, zone);
7280Sstevel@tonic-gate 		(void) exacct_assemble_task_usage(&acg->ac_task, tk,
7290Sstevel@tonic-gate 		    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7300Sstevel@tonic-gate 		if (tk->tk_zone != global_zone) {
7310Sstevel@tonic-gate 			acg = zone_getspecific(exacct_zone_key, global_zone);
7320Sstevel@tonic-gate 			(void) exacct_assemble_task_usage(&acg->ac_task, tk,
7330Sstevel@tonic-gate 			    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7340Sstevel@tonic-gate 		}
7350Sstevel@tonic-gate 	}
7360Sstevel@tonic-gate 	/*
7370Sstevel@tonic-gate 	 * Release associated project and finalize task.
7380Sstevel@tonic-gate 	 */
7390Sstevel@tonic-gate 	task_end(tk);
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate static int
7430Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res)
7440Sstevel@tonic-gate {
7450Sstevel@tonic-gate 	int attached = 1;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	switch (res) {
7480Sstevel@tonic-gate 	case AC_PROC_PID:
7490Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_pid,
7500Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID);
7510Sstevel@tonic-gate 		break;
7520Sstevel@tonic-gate 	case AC_PROC_UID:
7530Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ruid,
7540Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID);
7550Sstevel@tonic-gate 		break;
7560Sstevel@tonic-gate 	case AC_PROC_FLAG:
7570Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_acflag,
7580Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS);
7590Sstevel@tonic-gate 		break;
7600Sstevel@tonic-gate 	case AC_PROC_GID:
7610Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_rgid,
7620Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID);
7630Sstevel@tonic-gate 		break;
7640Sstevel@tonic-gate 	case AC_PROC_PROJID:
7650Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_projid,
7660Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID);
7670Sstevel@tonic-gate 		break;
7680Sstevel@tonic-gate 	case AC_PROC_TASKID:
7690Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_taskid,
7700Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID);
7710Sstevel@tonic-gate 		break;
7720Sstevel@tonic-gate 	case AC_PROC_CPU:
7730Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_utimesec,
7740Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC);
7750Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_utimensec,
7760Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC);
7770Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_stimesec,
7780Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC);
7790Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_stimensec,
7800Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC);
7810Sstevel@tonic-gate 		break;
7820Sstevel@tonic-gate 	case AC_PROC_TIME:
7830Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_startsec,
7840Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC);
7850Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_startnsec,
7860Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC);
7870Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_finishsec,
7880Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC);
7890Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_finishnsec,
7900Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC);
7910Sstevel@tonic-gate 		break;
7920Sstevel@tonic-gate 	case AC_PROC_COMMAND:
7930Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_command,
7940Sstevel@tonic-gate 		    strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND);
7950Sstevel@tonic-gate 		break;
7960Sstevel@tonic-gate 	case AC_PROC_HOSTNAME:
7970Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_nodename,
7980Sstevel@tonic-gate 		    strlen(pu->pu_nodename) + 1,
7990Sstevel@tonic-gate 		    EXT_STRING | EXD_PROC_HOSTNAME);
8000Sstevel@tonic-gate 		break;
8010Sstevel@tonic-gate 	case AC_PROC_TTY:
8020Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_major,
8030Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR);
8040Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_minor,
8050Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR);
8060Sstevel@tonic-gate 		break;
8070Sstevel@tonic-gate 	case AC_PROC_MICROSTATE:
8080Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_majflt,
8090Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR);
8100Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_minflt,
8110Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR);
8120Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_sndmsg,
8130Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND);
8140Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_rcvmsg,
8150Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV);
8160Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_iblk,
8170Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN);
8180Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_oblk,
8190Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT);
8200Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ioch,
8210Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR);
8220Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_vcsw,
8230Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL);
8240Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_icsw,
8250Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV);
8260Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nsig,
8270Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS);
8280Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nswp,
8290Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS);
8300Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nscl,
8310Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS);
8320Sstevel@tonic-gate 		break;
8330Sstevel@tonic-gate 	case AC_PROC_ANCPID:
8340Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ancpid,
8350Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID);
8360Sstevel@tonic-gate 		break;
8370Sstevel@tonic-gate 	case AC_PROC_WAIT_STATUS:
8380Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_wstat,
8390Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS);
8400Sstevel@tonic-gate 		break;
8410Sstevel@tonic-gate 	case AC_PROC_ZONENAME:
8420Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_zonename,
8430Sstevel@tonic-gate 		    strlen(pu->pu_zonename) + 1,
8440Sstevel@tonic-gate 		    EXT_STRING | EXD_PROC_ZONENAME);
8450Sstevel@tonic-gate 		break;
8460Sstevel@tonic-gate 	case AC_PROC_MEM:
8470Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_mem_rss_avg,
8480Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K);
8490Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_mem_rss_max,
8500Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K);
8510Sstevel@tonic-gate 		break;
8520Sstevel@tonic-gate 	default:
8530Sstevel@tonic-gate 		attached = 0;
8540Sstevel@tonic-gate 	}
8550Sstevel@tonic-gate 	return (attached);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate static ea_object_t *
8590Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask,
8600Sstevel@tonic-gate     ea_catalog_t record_type)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	int res, count;
8630Sstevel@tonic-gate 	ea_object_t *record;
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	/*
8660Sstevel@tonic-gate 	 * Assemble usage values into group.
8670Sstevel@tonic-gate 	 */
8680Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
8690Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++)
8700Sstevel@tonic-gate 		if (BT_TEST(mask, res))
8714584Srh87107 			count += exacct_attach_proc_item(pu, record, res);
8720Sstevel@tonic-gate 	if (count == 0) {
8730Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
8740Sstevel@tonic-gate 		record = NULL;
8750Sstevel@tonic-gate 	}
8760Sstevel@tonic-gate 	return (record);
8770Sstevel@tonic-gate }
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate /*
8800Sstevel@tonic-gate  * The following two routines assume that process's p_lock is held or
8810Sstevel@tonic-gate  * exacct_commit_proc has been called from exit() when all lwps are stopped.
8820Sstevel@tonic-gate  */
8830Sstevel@tonic-gate static void
8840Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu)
8850Sstevel@tonic-gate {
8860Sstevel@tonic-gate 	kthread_t *t;
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8890Sstevel@tonic-gate 	if ((t = p->p_tlist) == NULL)
8900Sstevel@tonic-gate 		return;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	do {
8930Sstevel@tonic-gate 		pu->pu_minflt	+= t->t_lwp->lwp_ru.minflt;
8940Sstevel@tonic-gate 		pu->pu_majflt	+= t->t_lwp->lwp_ru.majflt;
8950Sstevel@tonic-gate 		pu->pu_sndmsg	+= t->t_lwp->lwp_ru.msgsnd;
8960Sstevel@tonic-gate 		pu->pu_rcvmsg	+= t->t_lwp->lwp_ru.msgrcv;
8970Sstevel@tonic-gate 		pu->pu_ioch	+= t->t_lwp->lwp_ru.ioch;
8980Sstevel@tonic-gate 		pu->pu_iblk	+= t->t_lwp->lwp_ru.inblock;
8990Sstevel@tonic-gate 		pu->pu_oblk	+= t->t_lwp->lwp_ru.oublock;
9000Sstevel@tonic-gate 		pu->pu_vcsw	+= t->t_lwp->lwp_ru.nvcsw;
9010Sstevel@tonic-gate 		pu->pu_icsw	+= t->t_lwp->lwp_ru.nivcsw;
9020Sstevel@tonic-gate 		pu->pu_nsig	+= t->t_lwp->lwp_ru.nsignals;
9030Sstevel@tonic-gate 		pu->pu_nswp	+= t->t_lwp->lwp_ru.nswap;
9040Sstevel@tonic-gate 		pu->pu_nscl	+= t->t_lwp->lwp_ru.sysc;
9050Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate static void
9090Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu)
9100Sstevel@tonic-gate {
9110Sstevel@tonic-gate 	pu->pu_minflt	= p->p_ru.minflt;
9120Sstevel@tonic-gate 	pu->pu_majflt	= p->p_ru.majflt;
9130Sstevel@tonic-gate 	pu->pu_sndmsg	= p->p_ru.msgsnd;
9140Sstevel@tonic-gate 	pu->pu_rcvmsg	= p->p_ru.msgrcv;
9150Sstevel@tonic-gate 	pu->pu_ioch	= p->p_ru.ioch;
9160Sstevel@tonic-gate 	pu->pu_iblk	= p->p_ru.inblock;
9170Sstevel@tonic-gate 	pu->pu_oblk	= p->p_ru.oublock;
9180Sstevel@tonic-gate 	pu->pu_vcsw	= p->p_ru.nvcsw;
9190Sstevel@tonic-gate 	pu->pu_icsw	= p->p_ru.nivcsw;
9200Sstevel@tonic-gate 	pu->pu_nsig	= p->p_ru.nsignals;
9210Sstevel@tonic-gate 	pu->pu_nswp	= p->p_ru.nswap;
9220Sstevel@tonic-gate 	pu->pu_nscl	= p->p_ru.sysc;
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate void
9260Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask,
9270Sstevel@tonic-gate     int flag, int wstat)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	timestruc_t ts, ts_run;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	/*
9340Sstevel@tonic-gate 	 * Convert CPU and execution times to sec/nsec format.
9350Sstevel@tonic-gate 	 */
9360Sstevel@tonic-gate 	if (BT_TEST(mask, AC_PROC_CPU)) {
9370Sstevel@tonic-gate 		hrt2ts(mstate_aggr_state(p, LMS_USER), &ts);
9380Sstevel@tonic-gate 		pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec;
9390Sstevel@tonic-gate 		pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9400Sstevel@tonic-gate 		hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts);
9410Sstevel@tonic-gate 		pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec;
9420Sstevel@tonic-gate 		pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 	if (BT_TEST(mask, AC_PROC_TIME)) {
9450Sstevel@tonic-gate 		gethrestime(&ts);
9460Sstevel@tonic-gate 		pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
9470Sstevel@tonic-gate 		pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9480Sstevel@tonic-gate 		hrt2ts(gethrtime() - p->p_mstart, &ts_run);
9490Sstevel@tonic-gate 		ts.tv_sec -= ts_run.tv_sec;
9500Sstevel@tonic-gate 		ts.tv_nsec -= ts_run.tv_nsec;
9510Sstevel@tonic-gate 		if (ts.tv_nsec < 0) {
9520Sstevel@tonic-gate 			ts.tv_sec--;
9530Sstevel@tonic-gate 			if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) {
9540Sstevel@tonic-gate 				ts.tv_sec++;
9550Sstevel@tonic-gate 				ts.tv_nsec -= NANOSEC;
9560Sstevel@tonic-gate 			}
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 		pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec;
9590Sstevel@tonic-gate 		pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	pu->pu_pid = p->p_pidp->pid_id;
9630Sstevel@tonic-gate 	pu->pu_acflag = p->p_user.u_acflag;
9640Sstevel@tonic-gate 	pu->pu_projid = p->p_task->tk_proj->kpj_id;
9650Sstevel@tonic-gate 	pu->pu_taskid = p->p_task->tk_tkid;
9660Sstevel@tonic-gate 	pu->pu_major = getmajor(p->p_sessp->s_dev);
9670Sstevel@tonic-gate 	pu->pu_minor = getminor(p->p_sessp->s_dev);
9680Sstevel@tonic-gate 	pu->pu_ancpid = p->p_ancpid;
9690Sstevel@tonic-gate 	pu->pu_wstat = wstat;
9700Sstevel@tonic-gate 	/*
9710Sstevel@tonic-gate 	 * Compute average RSS in K.  The denominator is the number of
9720Sstevel@tonic-gate 	 * samples:  the number of clock ticks plus the initial value.
9730Sstevel@tonic-gate 	 */
9740Sstevel@tonic-gate 	pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) *
9750Sstevel@tonic-gate 	    (PAGESIZE / 1024);
9760Sstevel@tonic-gate 	pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
9790Sstevel@tonic-gate 	pu->pu_ruid = crgetruid(p->p_cred);
9800Sstevel@tonic-gate 	pu->pu_rgid = crgetrgid(p->p_cred);
9810Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1);
9840Sstevel@tonic-gate 	bcopy(p->p_zone->zone_name, pu->pu_zonename,
9850Sstevel@tonic-gate 	    strlen(p->p_zone->zone_name) + 1);
9860Sstevel@tonic-gate 	bcopy(p->p_zone->zone_nodename, pu->pu_nodename,
9870Sstevel@tonic-gate 	    strlen(p->p_zone->zone_nodename) + 1);
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	/*
9900Sstevel@tonic-gate 	 * Calculate microstate accounting data for a process that is still
9910Sstevel@tonic-gate 	 * running.  Presently, we explicitly collect all of the LWP usage into
9920Sstevel@tonic-gate 	 * the proc usage structure here.
9930Sstevel@tonic-gate 	 */
9940Sstevel@tonic-gate 	if (flag & EW_PARTIAL)
9950Sstevel@tonic-gate 		exacct_calculate_proc_mstate(p, pu);
9960Sstevel@tonic-gate 	if (flag & EW_FINAL)
9970Sstevel@tonic-gate 		exacct_copy_proc_mstate(p, pu);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate /*
10010Sstevel@tonic-gate  * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void
10020Sstevel@tonic-gate  *	*, size_t, size_t *), void *, size_t, size_t *)
10030Sstevel@tonic-gate  *
10040Sstevel@tonic-gate  * Overview
10050Sstevel@tonic-gate  *   Assemble record with miscellaneous accounting information about the process
10060Sstevel@tonic-gate  *   and execute the callback on it. It is the callback's job to set "actual" to
10070Sstevel@tonic-gate  *   the size of record.
10080Sstevel@tonic-gate  *
10090Sstevel@tonic-gate  * Return values
10100Sstevel@tonic-gate  *   The result of the callback function, unless the extended process accounting
10110Sstevel@tonic-gate  *   feature is not active, in which case ENOTACTIVE is returned.
10120Sstevel@tonic-gate  *
10130Sstevel@tonic-gate  * Caller's context
10140Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
10150Sstevel@tonic-gate  */
10160Sstevel@tonic-gate int
10170Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu,
10180Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
10190Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual, int flag)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
10220Sstevel@tonic-gate 	ea_object_t *proc_record;
10230Sstevel@tonic-gate 	ea_catalog_t record_type;
10240Sstevel@tonic-gate 	void *buf;
10250Sstevel@tonic-gate 	size_t bufsize;
10260Sstevel@tonic-gate 	int ret;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL);
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
10310Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_OFF) {
10320Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
10330Sstevel@tonic-gate 		return (ENOTACTIVE);
10340Sstevel@tonic-gate 	}
10350Sstevel@tonic-gate 	bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
10360Sstevel@tonic-gate 	mutex_exit(&ac_proc->ac_lock);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	switch (flag) {
10390Sstevel@tonic-gate 	case EW_FINAL:
10400Sstevel@tonic-gate 		record_type = EXD_GROUP_PROC;
10410Sstevel@tonic-gate 		break;
10420Sstevel@tonic-gate 	case EW_PARTIAL:
10430Sstevel@tonic-gate 		record_type = EXD_GROUP_PROC_PARTIAL;
10440Sstevel@tonic-gate 		break;
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	proc_record = exacct_assemble_proc_record(pu, mask, record_type);
10480Sstevel@tonic-gate 	if (proc_record == NULL)
10490Sstevel@tonic-gate 		return (0);
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/*
10520Sstevel@tonic-gate 	 * Pack object into buffer and pass to callback.
10530Sstevel@tonic-gate 	 */
10540Sstevel@tonic-gate 	bufsize = ea_pack_object(proc_record, NULL, 0);
10550Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
10560Sstevel@tonic-gate 	(void) ea_pack_object(proc_record, buf, bufsize);
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual);
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	/*
10610Sstevel@tonic-gate 	 * Free all previously allocations.
10620Sstevel@tonic-gate 	 */
10630Sstevel@tonic-gate 	kmem_free(buf, bufsize);
10640Sstevel@tonic-gate 	ea_free_object(proc_record, EUP_ALLOC);
10650Sstevel@tonic-gate 	return (ret);
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate  * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t,
10700Sstevel@tonic-gate  * 	size_t *)
10710Sstevel@tonic-gate  *
10720Sstevel@tonic-gate  * Overview
10730Sstevel@tonic-gate  *   exacct_commit_callback() writes the indicated buffer to the indicated
10740Sstevel@tonic-gate  *   extended accounting file.
10750Sstevel@tonic-gate  *
10760Sstevel@tonic-gate  * Return values
10770Sstevel@tonic-gate  *   The result of the write operation is returned.  "actual" is updated to
10780Sstevel@tonic-gate  *   contain the number of bytes actually written.
10790Sstevel@tonic-gate  *
10800Sstevel@tonic-gate  * Caller's context
10810Sstevel@tonic-gate  *   Suitable for a vn_rdwr() operation.
10820Sstevel@tonic-gate  */
10830Sstevel@tonic-gate /*ARGSUSED*/
10840Sstevel@tonic-gate int
10850Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize,
10860Sstevel@tonic-gate     void *buf, size_t bufsize, size_t *actual)
10870Sstevel@tonic-gate {
10880Sstevel@tonic-gate 	int error = 0;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	*actual = 0;
10910Sstevel@tonic-gate 	if ((error = exacct_vn_write(info, buf, bufsize)) == 0)
10920Sstevel@tonic-gate 		*actual = bufsize;
10930Sstevel@tonic-gate 	return (error);
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate static void
10970Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat)
10980Sstevel@tonic-gate {
10990Sstevel@tonic-gate 	size_t size;
11000Sstevel@tonic-gate 	proc_usage_t *pu;
11010Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
11040Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_ON) {
11050Sstevel@tonic-gate 		bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
11060Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
11070Sstevel@tonic-gate 	} else {
11080Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
11090Sstevel@tonic-gate 		return;
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
11130Sstevel@tonic-gate 	size = strlen(p->p_user.u_comm) + 1;
11140Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP);
11170Sstevel@tonic-gate 	pu->pu_command = kmem_alloc(size, KM_SLEEP);
11180Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
11190Sstevel@tonic-gate 	exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat);
11200Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	(void) exacct_assemble_proc_usage(ac_proc, pu,
11230Sstevel@tonic-gate 	    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	kmem_free(pu->pu_command, strlen(pu->pu_command) + 1);
11260Sstevel@tonic-gate 	kmem_free(pu, sizeof (proc_usage_t));
11270Sstevel@tonic-gate }
11284584Srh87107 
11290Sstevel@tonic-gate /*
11300Sstevel@tonic-gate  * void exacct_commit_proc(proc_t *, int)
11310Sstevel@tonic-gate  *
11320Sstevel@tonic-gate  * Overview
11330Sstevel@tonic-gate  *   exacct_commit_proc() calculates the final usage for a process, updating the
11340Sstevel@tonic-gate  *   task usage if task accounting is active, and writing a process record if
11350Sstevel@tonic-gate  *   process accounting is active.  exacct_commit_proc() is intended for being
11360Sstevel@tonic-gate  *   called from proc_exit().
11370Sstevel@tonic-gate  *
11380Sstevel@tonic-gate  * Return values
11390Sstevel@tonic-gate  *   None.
11400Sstevel@tonic-gate  *
11410Sstevel@tonic-gate  * Caller's context
11420Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.  p_lock must not be held at entry.
11430Sstevel@tonic-gate  */
11440Sstevel@tonic-gate void
11450Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat)
11460Sstevel@tonic-gate {
11470Sstevel@tonic-gate 	zone_t *zone = p->p_zone;
11480Sstevel@tonic-gate 	struct exacct_globals *acg, *gacg = NULL;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
11510Sstevel@tonic-gate 		/*
11520Sstevel@tonic-gate 		 * acctctl module not loaded.  Nothing to do.
11530Sstevel@tonic-gate 		 */
11540Sstevel@tonic-gate 		return;
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 	acg = zone_getspecific(exacct_zone_key, zone);
11574584Srh87107 	exacct_do_commit_proc(&acg->ac_proc, p, wstat);
11584584Srh87107 	if (zone != global_zone) {
11590Sstevel@tonic-gate 		gacg = zone_getspecific(exacct_zone_key, global_zone);
11604584Srh87107 		exacct_do_commit_proc(&gacg->ac_proc, p, wstat);
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate static int
1165*8275SEric Cheng exacct_attach_netstat_item(net_stat_t *ns, ea_object_t *record, int res)
1166*8275SEric Cheng {
1167*8275SEric Cheng 	int		attached = 1;
1168*8275SEric Cheng 
1169*8275SEric Cheng 	switch (res) {
1170*8275SEric Cheng 	case AC_NET_NAME:
1171*8275SEric Cheng 		(void) ea_attach_item(record, ns->ns_name,
1172*8275SEric Cheng 		    strlen(ns->ns_name) + 1, EXT_STRING | EXD_NET_STATS_NAME);
1173*8275SEric Cheng 		break;
1174*8275SEric Cheng 	case AC_NET_CURTIME:
1175*8275SEric Cheng 		{
1176*8275SEric Cheng 			uint64_t	now;
1177*8275SEric Cheng 			timestruc_t	ts;
1178*8275SEric Cheng 
1179*8275SEric Cheng 			gethrestime(&ts);
1180*8275SEric Cheng 			now = (uint64_t)(ulong_t)ts.tv_sec;
1181*8275SEric Cheng 			(void) ea_attach_item(record,  &now, sizeof (uint64_t),
1182*8275SEric Cheng 			    EXT_UINT64 | EXD_NET_STATS_CURTIME);
1183*8275SEric Cheng 		}
1184*8275SEric Cheng 		break;
1185*8275SEric Cheng 	case AC_NET_IBYTES:
1186*8275SEric Cheng 		(void) ea_attach_item(record, &ns->ns_ibytes,
1187*8275SEric Cheng 		    sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IBYTES);
1188*8275SEric Cheng 		break;
1189*8275SEric Cheng 	case AC_NET_OBYTES:
1190*8275SEric Cheng 		(void) ea_attach_item(record, &ns->ns_obytes,
1191*8275SEric Cheng 		    sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OBYTES);
1192*8275SEric Cheng 		break;
1193*8275SEric Cheng 	case AC_NET_IPKTS:
1194*8275SEric Cheng 		(void) ea_attach_item(record, &ns->ns_ipackets,
1195*8275SEric Cheng 		    sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IPKTS);
1196*8275SEric Cheng 		break;
1197*8275SEric Cheng 	case AC_NET_OPKTS:
1198*8275SEric Cheng 		(void) ea_attach_item(record, &ns->ns_opackets,
1199*8275SEric Cheng 		    sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OPKTS);
1200*8275SEric Cheng 		break;
1201*8275SEric Cheng 	case AC_NET_IERRPKTS:
1202*8275SEric Cheng 		(void) ea_attach_item(record, &ns->ns_ierrors,
1203*8275SEric Cheng 		    sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_IERRPKTS);
1204*8275SEric Cheng 		break;
1205*8275SEric Cheng 	case AC_NET_OERRPKTS:
1206*8275SEric Cheng 		(void) ea_attach_item(record, &ns->ns_oerrors,
1207*8275SEric Cheng 		    sizeof (uint64_t), EXT_UINT64 | EXD_NET_STATS_OERRPKTS);
1208*8275SEric Cheng 		break;
1209*8275SEric Cheng 	default:
1210*8275SEric Cheng 		attached = 0;
1211*8275SEric Cheng 	}
1212*8275SEric Cheng 	return (attached);
1213*8275SEric Cheng }
1214*8275SEric Cheng 
1215*8275SEric Cheng static int
1216*8275SEric Cheng exacct_attach_netdesc_item(net_desc_t *nd, ea_object_t *record, int res)
1217*8275SEric Cheng {
1218*8275SEric Cheng 	int attached = 1;
1219*8275SEric Cheng 
1220*8275SEric Cheng 	switch (res) {
1221*8275SEric Cheng 	case AC_NET_NAME:
1222*8275SEric Cheng 		(void) ea_attach_item(record, nd->nd_name,
1223*8275SEric Cheng 		    strlen(nd->nd_name) + 1, EXT_STRING | EXD_NET_DESC_NAME);
1224*8275SEric Cheng 		break;
1225*8275SEric Cheng 	case AC_NET_DEVNAME:
1226*8275SEric Cheng 		(void) ea_attach_item(record, nd->nd_devname,
1227*8275SEric Cheng 		    strlen(nd->nd_devname) + 1, EXT_STRING |
1228*8275SEric Cheng 		    EXD_NET_DESC_DEVNAME);
1229*8275SEric Cheng 		break;
1230*8275SEric Cheng 	case AC_NET_EHOST:
1231*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_ehost,
1232*8275SEric Cheng 		    sizeof (nd->nd_ehost), EXT_RAW | EXD_NET_DESC_EHOST);
1233*8275SEric Cheng 		break;
1234*8275SEric Cheng 	case AC_NET_EDEST:
1235*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_edest,
1236*8275SEric Cheng 		    sizeof (nd->nd_edest), EXT_RAW | EXD_NET_DESC_EDEST);
1237*8275SEric Cheng 		break;
1238*8275SEric Cheng 	case AC_NET_VLAN_TPID:
1239*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_vlan_tpid,
1240*8275SEric Cheng 		    sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TPID);
1241*8275SEric Cheng 		break;
1242*8275SEric Cheng 	case AC_NET_VLAN_TCI:
1243*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_vlan_tci,
1244*8275SEric Cheng 		    sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_VLAN_TCI);
1245*8275SEric Cheng 		break;
1246*8275SEric Cheng 	case AC_NET_SAP:
1247*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_sap,
1248*8275SEric Cheng 		    sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_SAP);
1249*8275SEric Cheng 		break;
1250*8275SEric Cheng 	case AC_NET_PRIORITY:
1251*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_priority,
1252*8275SEric Cheng 		    sizeof (ushort_t), EXT_UINT16 | EXD_NET_DESC_PRIORITY);
1253*8275SEric Cheng 		break;
1254*8275SEric Cheng 	case AC_NET_BWLIMIT:
1255*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_bw_limit,
1256*8275SEric Cheng 		    sizeof (uint64_t), EXT_UINT64 | EXD_NET_DESC_BWLIMIT);
1257*8275SEric Cheng 		break;
1258*8275SEric Cheng 	case AC_NET_SADDR:
1259*8275SEric Cheng 		if (nd->nd_isv4) {
1260*8275SEric Cheng 			(void) ea_attach_item(record, &nd->nd_saddr[3],
1261*8275SEric Cheng 			    sizeof (uint32_t), EXT_UINT32 |
1262*8275SEric Cheng 			    EXD_NET_DESC_V4SADDR);
1263*8275SEric Cheng 		} else {
1264*8275SEric Cheng 			(void) ea_attach_item(record, &nd->nd_saddr,
1265*8275SEric Cheng 			    sizeof (nd->nd_saddr), EXT_RAW |
1266*8275SEric Cheng 			    EXD_NET_DESC_V6SADDR);
1267*8275SEric Cheng 		}
1268*8275SEric Cheng 		break;
1269*8275SEric Cheng 	case AC_NET_DADDR:
1270*8275SEric Cheng 		if (nd->nd_isv4) {
1271*8275SEric Cheng 			(void) ea_attach_item(record, &nd->nd_daddr[3],
1272*8275SEric Cheng 			    sizeof (uint32_t), EXT_UINT32 |
1273*8275SEric Cheng 			    EXD_NET_DESC_V4DADDR);
1274*8275SEric Cheng 		} else {
1275*8275SEric Cheng 			(void) ea_attach_item(record, &nd->nd_daddr,
1276*8275SEric Cheng 			    sizeof (nd->nd_daddr), EXT_RAW |
1277*8275SEric Cheng 			    EXD_NET_DESC_V6DADDR);
1278*8275SEric Cheng 		}
1279*8275SEric Cheng 		break;
1280*8275SEric Cheng 	case AC_NET_SPORT:
1281*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_sport,
1282*8275SEric Cheng 		    sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_SPORT);
1283*8275SEric Cheng 		break;
1284*8275SEric Cheng 	case AC_NET_DPORT:
1285*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_dport,
1286*8275SEric Cheng 		    sizeof (uint16_t), EXT_UINT16 | EXD_NET_DESC_DPORT);
1287*8275SEric Cheng 		break;
1288*8275SEric Cheng 	case AC_NET_PROTOCOL:
1289*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_protocol,
1290*8275SEric Cheng 		    sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_PROTOCOL);
1291*8275SEric Cheng 		break;
1292*8275SEric Cheng 	case AC_NET_DSFIELD:
1293*8275SEric Cheng 		(void) ea_attach_item(record, &nd->nd_dsfield,
1294*8275SEric Cheng 		    sizeof (uint8_t), EXT_UINT8 | EXD_NET_DESC_DSFIELD);
1295*8275SEric Cheng 		break;
1296*8275SEric Cheng 	default:
1297*8275SEric Cheng 		attached = 0;
1298*8275SEric Cheng 	}
1299*8275SEric Cheng 	return (attached);
1300*8275SEric Cheng }
1301*8275SEric Cheng 
1302*8275SEric Cheng static ea_object_t *
1303*8275SEric Cheng exacct_assemble_net_record(void *ninfo, ulong_t *mask, ea_catalog_t record_type,
1304*8275SEric Cheng     int what)
1305*8275SEric Cheng {
1306*8275SEric Cheng 	int		res;
1307*8275SEric Cheng 	int		count;
1308*8275SEric Cheng 	ea_object_t	*record;
1309*8275SEric Cheng 
1310*8275SEric Cheng 	/*
1311*8275SEric Cheng 	 * Assemble usage values into group.
1312*8275SEric Cheng 	 */
1313*8275SEric Cheng 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
1314*8275SEric Cheng 	for (res = 1, count = 0; res <= AC_NET_MAX_RES; res++)
1315*8275SEric Cheng 		if (BT_TEST(mask, res)) {
1316*8275SEric Cheng 			if (what == EX_NET_LNDESC_REC ||
1317*8275SEric Cheng 			    what == EX_NET_FLDESC_REC) {
1318*8275SEric Cheng 				count += exacct_attach_netdesc_item(
1319*8275SEric Cheng 				    (net_desc_t *)ninfo, record, res);
1320*8275SEric Cheng 			} else {
1321*8275SEric Cheng 				count += exacct_attach_netstat_item(
1322*8275SEric Cheng 				    (net_stat_t *)ninfo, record, res);
1323*8275SEric Cheng 			}
1324*8275SEric Cheng 		}
1325*8275SEric Cheng 	if (count == 0) {
1326*8275SEric Cheng 		ea_free_object(record, EUP_ALLOC);
1327*8275SEric Cheng 		record = NULL;
1328*8275SEric Cheng 	}
1329*8275SEric Cheng 	return (record);
1330*8275SEric Cheng }
1331*8275SEric Cheng 
1332*8275SEric Cheng int
1333*8275SEric Cheng exacct_assemble_net_usage(ac_info_t *ac_net, void *ninfo,
1334*8275SEric Cheng     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
1335*8275SEric Cheng     void *ubuf, size_t ubufsize, size_t *actual, int what)
1336*8275SEric Cheng {
1337*8275SEric Cheng 	ulong_t		mask[AC_MASK_SZ];
1338*8275SEric Cheng 	ea_object_t	*net_desc;
1339*8275SEric Cheng 	ea_catalog_t	record_type;
1340*8275SEric Cheng 	void		*buf;
1341*8275SEric Cheng 	size_t		bufsize;
1342*8275SEric Cheng 	int		ret;
1343*8275SEric Cheng 
1344*8275SEric Cheng 	mutex_enter(&ac_net->ac_lock);
1345*8275SEric Cheng 	if (ac_net->ac_state == AC_OFF) {
1346*8275SEric Cheng 		mutex_exit(&ac_net->ac_lock);
1347*8275SEric Cheng 		return (ENOTACTIVE);
1348*8275SEric Cheng 	}
1349*8275SEric Cheng 	bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ);
1350*8275SEric Cheng 	mutex_exit(&ac_net->ac_lock);
1351*8275SEric Cheng 
1352*8275SEric Cheng 	switch (what) {
1353*8275SEric Cheng 	case EX_NET_LNDESC_REC:
1354*8275SEric Cheng 		record_type = EXD_GROUP_NET_LINK_DESC;
1355*8275SEric Cheng 		break;
1356*8275SEric Cheng 	case EX_NET_LNSTAT_REC:
1357*8275SEric Cheng 		record_type = EXD_GROUP_NET_LINK_STATS;
1358*8275SEric Cheng 		break;
1359*8275SEric Cheng 	case EX_NET_FLDESC_REC:
1360*8275SEric Cheng 		record_type = EXD_GROUP_NET_FLOW_DESC;
1361*8275SEric Cheng 		break;
1362*8275SEric Cheng 	case EX_NET_FLSTAT_REC:
1363*8275SEric Cheng 		record_type = EXD_GROUP_NET_FLOW_STATS;
1364*8275SEric Cheng 		break;
1365*8275SEric Cheng 	}
1366*8275SEric Cheng 
1367*8275SEric Cheng 	net_desc = exacct_assemble_net_record(ninfo, mask, record_type, what);
1368*8275SEric Cheng 	if (net_desc == NULL)
1369*8275SEric Cheng 		return (0);
1370*8275SEric Cheng 
1371*8275SEric Cheng 	/*
1372*8275SEric Cheng 	 * Pack object into buffer and pass to callback.
1373*8275SEric Cheng 	 */
1374*8275SEric Cheng 	bufsize = ea_pack_object(net_desc, NULL, 0);
1375*8275SEric Cheng 	buf = kmem_alloc(bufsize, KM_NOSLEEP);
1376*8275SEric Cheng 	if (buf == NULL)
1377*8275SEric Cheng 		return (ENOMEM);
1378*8275SEric Cheng 
1379*8275SEric Cheng 	(void) ea_pack_object(net_desc, buf, bufsize);
1380*8275SEric Cheng 
1381*8275SEric Cheng 	ret = callback(ac_net, ubuf, ubufsize, buf, bufsize, actual);
1382*8275SEric Cheng 
1383*8275SEric Cheng 	/*
1384*8275SEric Cheng 	 * Free all previously allocations.
1385*8275SEric Cheng 	 */
1386*8275SEric Cheng 	kmem_free(buf, bufsize);
1387*8275SEric Cheng 	ea_free_object(net_desc, EUP_ALLOC);
1388*8275SEric Cheng 	return (ret);
1389*8275SEric Cheng }
1390*8275SEric Cheng 
1391*8275SEric Cheng int
1392*8275SEric Cheng exacct_commit_netinfo(void *arg, int what)
1393*8275SEric Cheng {
1394*8275SEric Cheng 	size_t			size;
1395*8275SEric Cheng 	ulong_t			mask[AC_MASK_SZ];
1396*8275SEric Cheng 	struct exacct_globals	*acg;
1397*8275SEric Cheng 	ac_info_t		*ac_net;
1398*8275SEric Cheng 
1399*8275SEric Cheng 	if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
1400*8275SEric Cheng 		/*
1401*8275SEric Cheng 		 * acctctl module not loaded. Nothing to do.
1402*8275SEric Cheng 		 */
1403*8275SEric Cheng 		return (ENOTACTIVE);
1404*8275SEric Cheng 	}
1405*8275SEric Cheng 
1406*8275SEric Cheng 	/*
1407*8275SEric Cheng 	 * Even though each zone nominally has its own flow accounting settings
1408*8275SEric Cheng 	 * (ac_flow), these are only maintained by and for the global zone.
1409*8275SEric Cheng 	 *
1410*8275SEric Cheng 	 * If this were to change in the future, this function should grow a
1411*8275SEric Cheng 	 * second zoneid (or zone) argument, and use the corresponding zone's
1412*8275SEric Cheng 	 * settings rather than always using those of the global zone.
1413*8275SEric Cheng 	 */
1414*8275SEric Cheng 	acg = zone_getspecific(exacct_zone_key, global_zone);
1415*8275SEric Cheng 	ac_net = &acg->ac_net;
1416*8275SEric Cheng 
1417*8275SEric Cheng 	mutex_enter(&ac_net->ac_lock);
1418*8275SEric Cheng 	if (ac_net->ac_state == AC_OFF) {
1419*8275SEric Cheng 		mutex_exit(&ac_net->ac_lock);
1420*8275SEric Cheng 		return (ENOTACTIVE);
1421*8275SEric Cheng 	}
1422*8275SEric Cheng 	bt_copy(&ac_net->ac_mask[0], mask, AC_MASK_SZ);
1423*8275SEric Cheng 	mutex_exit(&ac_net->ac_lock);
1424*8275SEric Cheng 
1425*8275SEric Cheng 	return (exacct_assemble_net_usage(ac_net, arg, exacct_commit_callback,
1426*8275SEric Cheng 	    NULL, 0, &size, what));
1427*8275SEric Cheng }
1428*8275SEric Cheng 
1429*8275SEric Cheng static int
14300Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res)
14310Sstevel@tonic-gate {
14320Sstevel@tonic-gate 	int attached = 1;
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	switch (res) {
14350Sstevel@tonic-gate 	case AC_FLOW_SADDR:
14360Sstevel@tonic-gate 		if (fu->fu_isv4) {
14370Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_saddr[3],
14380Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR);
14390Sstevel@tonic-gate 		} else {
14400Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_saddr,
14410Sstevel@tonic-gate 			    sizeof (fu->fu_saddr), EXT_RAW |
14420Sstevel@tonic-gate 			    EXD_FLOW_V6SADDR);
14430Sstevel@tonic-gate 		}
14440Sstevel@tonic-gate 		break;
14450Sstevel@tonic-gate 	case AC_FLOW_DADDR:
14460Sstevel@tonic-gate 		if (fu->fu_isv4) {
14470Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_daddr[3],
14480Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR);
14490Sstevel@tonic-gate 		} else {
14500Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_daddr,
14510Sstevel@tonic-gate 			    sizeof (fu->fu_daddr), EXT_RAW |
14520Sstevel@tonic-gate 			    EXD_FLOW_V6DADDR);
14530Sstevel@tonic-gate 		}
14540Sstevel@tonic-gate 		break;
14550Sstevel@tonic-gate 	case AC_FLOW_SPORT:
14560Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_sport,
14570Sstevel@tonic-gate 		    sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT);
14580Sstevel@tonic-gate 		break;
14590Sstevel@tonic-gate 	case AC_FLOW_DPORT:
14600Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_dport,
14610Sstevel@tonic-gate 		    sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT);
14620Sstevel@tonic-gate 		break;
14630Sstevel@tonic-gate 	case AC_FLOW_PROTOCOL:
14640Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_protocol,
14650Sstevel@tonic-gate 		    sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL);
14660Sstevel@tonic-gate 		break;
14670Sstevel@tonic-gate 	case AC_FLOW_DSFIELD:
14680Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_dsfield,
14690Sstevel@tonic-gate 		    sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD);
14700Sstevel@tonic-gate 		break;
14710Sstevel@tonic-gate 	case AC_FLOW_CTIME:
14720Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_ctime,
14730Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME);
14740Sstevel@tonic-gate 		break;
14750Sstevel@tonic-gate 	case AC_FLOW_LSEEN:
14760Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_lseen,
14770Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN);
14780Sstevel@tonic-gate 		break;
14790Sstevel@tonic-gate 	case AC_FLOW_NBYTES:
14800Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_nbytes,
14810Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES);
14820Sstevel@tonic-gate 		break;
14830Sstevel@tonic-gate 	case AC_FLOW_NPKTS:
14840Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_npackets,
14850Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS);
14860Sstevel@tonic-gate 		break;
14870Sstevel@tonic-gate 	case AC_FLOW_PROJID:
14880Sstevel@tonic-gate 		if (fu->fu_projid >= 0) {
14890Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_projid,
14900Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID);
14910Sstevel@tonic-gate 		}
14920Sstevel@tonic-gate 		break;
14930Sstevel@tonic-gate 	case AC_FLOW_UID:
14940Sstevel@tonic-gate 		if (fu->fu_userid >= 0) {
14950Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_userid,
14960Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID);
14970Sstevel@tonic-gate 		}
14980Sstevel@tonic-gate 		break;
14990Sstevel@tonic-gate 	case AC_FLOW_ANAME:
15000Sstevel@tonic-gate 		(void) ea_attach_item(record, fu->fu_aname,
15010Sstevel@tonic-gate 		    strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME);
15020Sstevel@tonic-gate 		break;
15030Sstevel@tonic-gate 	default:
15040Sstevel@tonic-gate 		attached = 0;
15050Sstevel@tonic-gate 	}
15060Sstevel@tonic-gate 	return (attached);
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate static ea_object_t *
15100Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask,
15110Sstevel@tonic-gate     ea_catalog_t record_type)
15120Sstevel@tonic-gate {
15130Sstevel@tonic-gate 	int res, count;
15140Sstevel@tonic-gate 	ea_object_t *record;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	/*
15170Sstevel@tonic-gate 	 * Assemble usage values into group.
15180Sstevel@tonic-gate 	 */
15190Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
15200Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++)
15210Sstevel@tonic-gate 		if (BT_TEST(mask, res))
15220Sstevel@tonic-gate 			count += exacct_attach_flow_item(fu, record, res);
15230Sstevel@tonic-gate 	if (count == 0) {
15240Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
15250Sstevel@tonic-gate 		record = NULL;
15260Sstevel@tonic-gate 	}
15270Sstevel@tonic-gate 	return (record);
15280Sstevel@tonic-gate }
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate int
15310Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu,
15320Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
15330Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual)
15340Sstevel@tonic-gate {
15350Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
15360Sstevel@tonic-gate 	ea_object_t *flow_usage;
15370Sstevel@tonic-gate 	ea_catalog_t record_type;
15380Sstevel@tonic-gate 	void *buf;
15390Sstevel@tonic-gate 	size_t bufsize;
15400Sstevel@tonic-gate 	int ret;
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	mutex_enter(&ac_flow->ac_lock);
15430Sstevel@tonic-gate 	if (ac_flow->ac_state == AC_OFF) {
15440Sstevel@tonic-gate 		mutex_exit(&ac_flow->ac_lock);
15450Sstevel@tonic-gate 		return (ENOTACTIVE);
15460Sstevel@tonic-gate 	}
15470Sstevel@tonic-gate 	bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
15480Sstevel@tonic-gate 	mutex_exit(&ac_flow->ac_lock);
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	record_type = EXD_GROUP_FLOW;
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	flow_usage = exacct_assemble_flow_record(fu, mask, record_type);
15530Sstevel@tonic-gate 	if (flow_usage == NULL) {
15540Sstevel@tonic-gate 		return (0);
15550Sstevel@tonic-gate 	}
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	/*
15580Sstevel@tonic-gate 	 * Pack object into buffer and pass to callback.
15590Sstevel@tonic-gate 	 */
15600Sstevel@tonic-gate 	bufsize = ea_pack_object(flow_usage, NULL, 0);
15610Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_NOSLEEP);
15620Sstevel@tonic-gate 	if (buf == NULL) {
15630Sstevel@tonic-gate 		return (ENOMEM);
15640Sstevel@tonic-gate 	}
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	(void) ea_pack_object(flow_usage, buf, bufsize);
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 	ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual);
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	/*
15710Sstevel@tonic-gate 	 * Free all previously allocations.
15720Sstevel@tonic-gate 	 */
15730Sstevel@tonic-gate 	kmem_free(buf, bufsize);
15740Sstevel@tonic-gate 	ea_free_object(flow_usage, EUP_ALLOC);
15750Sstevel@tonic-gate 	return (ret);
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate void
15790Sstevel@tonic-gate exacct_commit_flow(void *arg)
15800Sstevel@tonic-gate {
15810Sstevel@tonic-gate 	flow_usage_t *f = (flow_usage_t *)arg;
15820Sstevel@tonic-gate 	size_t size;
15830Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
15840Sstevel@tonic-gate 	struct exacct_globals *acg;
15850Sstevel@tonic-gate 	ac_info_t *ac_flow;
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 	if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
15880Sstevel@tonic-gate 		/*
15890Sstevel@tonic-gate 		 * acctctl module not loaded. Nothing to do.
15900Sstevel@tonic-gate 		 */
15910Sstevel@tonic-gate 		return;
15920Sstevel@tonic-gate 	}
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 	/*
15950Sstevel@tonic-gate 	 * Even though each zone nominally has its own flow accounting settings
15960Sstevel@tonic-gate 	 * (ac_flow), these are only maintained by and for the global zone.
15970Sstevel@tonic-gate 	 *
15980Sstevel@tonic-gate 	 * If this were to change in the future, this function should grow a
15990Sstevel@tonic-gate 	 * second zoneid (or zone) argument, and use the corresponding zone's
16000Sstevel@tonic-gate 	 * settings rather than always using those of the global zone.
16010Sstevel@tonic-gate 	 */
16020Sstevel@tonic-gate 	acg = zone_getspecific(exacct_zone_key, global_zone);
16030Sstevel@tonic-gate 	ac_flow = &acg->ac_flow;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	mutex_enter(&ac_flow->ac_lock);
16060Sstevel@tonic-gate 	if (ac_flow->ac_state == AC_OFF) {
16070Sstevel@tonic-gate 		mutex_exit(&ac_flow->ac_lock);
16080Sstevel@tonic-gate 		return;
16090Sstevel@tonic-gate 	}
16100Sstevel@tonic-gate 	bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
16110Sstevel@tonic-gate 	mutex_exit(&ac_flow->ac_lock);
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	(void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback,
16140Sstevel@tonic-gate 	    NULL, 0, &size);
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate /*
16180Sstevel@tonic-gate  * int exacct_tag_task(task_t *, void *, size_t, int)
16190Sstevel@tonic-gate  *
16200Sstevel@tonic-gate  * Overview
16210Sstevel@tonic-gate  *   exacct_tag_task() provides the exacct record construction and writing
16220Sstevel@tonic-gate  *   support required by putacct(2) for task entities.
16230Sstevel@tonic-gate  *
16240Sstevel@tonic-gate  * Return values
16250Sstevel@tonic-gate  *   The result of the write operation is returned, unless the extended
16260Sstevel@tonic-gate  *   accounting facility is not active, in which case ENOTACTIVE is returned.
16270Sstevel@tonic-gate  *
16280Sstevel@tonic-gate  * Caller's context
16290Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
16300Sstevel@tonic-gate  */
16310Sstevel@tonic-gate int
16320Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz,
16330Sstevel@tonic-gate     int flags)
16340Sstevel@tonic-gate {
16350Sstevel@tonic-gate 	int error = 0;
16360Sstevel@tonic-gate 	void *buf;
16370Sstevel@tonic-gate 	size_t bufsize;
16380Sstevel@tonic-gate 	ea_catalog_t cat;
16390Sstevel@tonic-gate 	ea_object_t *tag;
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	mutex_enter(&ac_task->ac_lock);
16420Sstevel@tonic-gate 	if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) {
16430Sstevel@tonic-gate 		mutex_exit(&ac_task->ac_lock);
16440Sstevel@tonic-gate 		return (ENOTACTIVE);
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 	mutex_exit(&ac_task->ac_lock);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG);
16490Sstevel@tonic-gate 	(void) ea_attach_item(tag, &tk->tk_tkid, 0,
16500Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
16510Sstevel@tonic-gate 	(void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0,
16520Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
16530Sstevel@tonic-gate 	if (flags == EP_RAW)
16540Sstevel@tonic-gate 		cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG;
16550Sstevel@tonic-gate 	else
16560Sstevel@tonic-gate 		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG;
16570Sstevel@tonic-gate 	(void) ea_attach_item(tag, ubuf, ubufsz, cat);
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	bufsize = ea_pack_object(tag, NULL, 0);
16600Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
16610Sstevel@tonic-gate 	(void) ea_pack_object(tag, buf, bufsize);
16620Sstevel@tonic-gate 	error = exacct_vn_write(ac_task, buf, bufsize);
16630Sstevel@tonic-gate 	kmem_free(buf, bufsize);
16640Sstevel@tonic-gate 	ea_free_object(tag, EUP_ALLOC);
16650Sstevel@tonic-gate 	return (error);
16660Sstevel@tonic-gate }
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate /*
16690Sstevel@tonic-gate  * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *)
16700Sstevel@tonic-gate  *
16710Sstevel@tonic-gate  * Overview
16720Sstevel@tonic-gate  *   exacct_tag_proc() provides the exacct record construction and writing
16730Sstevel@tonic-gate  *   support required by putacct(2) for processes.
16740Sstevel@tonic-gate  *
16750Sstevel@tonic-gate  * Return values
16760Sstevel@tonic-gate  *   The result of the write operation is returned, unless the extended
16770Sstevel@tonic-gate  *   accounting facility is not active, in which case ENOTACTIVE is returned.
16780Sstevel@tonic-gate  *
16790Sstevel@tonic-gate  * Caller's context
16800Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
16810Sstevel@tonic-gate  */
16820Sstevel@tonic-gate int
16830Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf,
16840Sstevel@tonic-gate     size_t ubufsz, int flags, const char *hostname)
16850Sstevel@tonic-gate {
16860Sstevel@tonic-gate 	int error = 0;
16870Sstevel@tonic-gate 	void *buf;
16880Sstevel@tonic-gate 	size_t bufsize;
16890Sstevel@tonic-gate 	ea_catalog_t cat;
16900Sstevel@tonic-gate 	ea_object_t *tag;
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
16930Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) {
16940Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
16950Sstevel@tonic-gate 		return (ENOTACTIVE);
16960Sstevel@tonic-gate 	}
16970Sstevel@tonic-gate 	mutex_exit(&ac_proc->ac_lock);
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG);
17000Sstevel@tonic-gate 	(void) ea_attach_item(tag, &pid, sizeof (uint32_t),
17010Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID);
17020Sstevel@tonic-gate 	(void) ea_attach_item(tag, &tkid, 0,
17030Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
17040Sstevel@tonic-gate 	(void) ea_attach_item(tag, (void *)hostname, 0,
17050Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
17060Sstevel@tonic-gate 	if (flags == EP_RAW)
17070Sstevel@tonic-gate 		cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG;
17080Sstevel@tonic-gate 	else
17090Sstevel@tonic-gate 		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG;
17100Sstevel@tonic-gate 	(void) ea_attach_item(tag, ubuf, ubufsz, cat);
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	bufsize = ea_pack_object(tag, NULL, 0);
17130Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
17140Sstevel@tonic-gate 	(void) ea_pack_object(tag, buf, bufsize);
17150Sstevel@tonic-gate 	error = exacct_vn_write(ac_proc, buf, bufsize);
17160Sstevel@tonic-gate 	kmem_free(buf, bufsize);
17170Sstevel@tonic-gate 	ea_free_object(tag, EUP_ALLOC);
17180Sstevel@tonic-gate 	return (error);
17190Sstevel@tonic-gate }
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate /*
17220Sstevel@tonic-gate  * void exacct_init(void)
17230Sstevel@tonic-gate  *
17240Sstevel@tonic-gate  * Overview
17250Sstevel@tonic-gate  *   Initialized the extended accounting subsystem.
17260Sstevel@tonic-gate  *
17270Sstevel@tonic-gate  * Return values
17280Sstevel@tonic-gate  *   None.
17290Sstevel@tonic-gate  *
17300Sstevel@tonic-gate  * Caller's context
17310Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
17320Sstevel@tonic-gate  */
17330Sstevel@tonic-gate void
17340Sstevel@tonic-gate exacct_init()
17350Sstevel@tonic-gate {
17360Sstevel@tonic-gate 	exacct_queue = system_taskq;
17370Sstevel@tonic-gate 	exacct_object_cache = kmem_cache_create("exacct_object_cache",
17380Sstevel@tonic-gate 	    sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
17390Sstevel@tonic-gate }
17404584Srh87107 
17414584Srh87107 /*
17424584Srh87107  * exacct_snapshot_proc_mstate() copies a process's microstate accounting data
17434584Srh87107  * and resource usage counters into a given task_usage_t. It differs from
17444584Srh87107  * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t,
17454584Srh87107  * b) p_lock will have been acquired earlier in the call path and c) we
17464584Srh87107  * are here including the process's user and system times.
17474584Srh87107  */
17484584Srh87107 static void
17494584Srh87107 exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu)
17504584Srh87107 {
17514584Srh87107 	tu->tu_utime  = mstate_aggr_state(p, LMS_USER);
17524584Srh87107 	tu->tu_stime  = mstate_aggr_state(p, LMS_SYSTEM);
17534584Srh87107 	tu->tu_minflt = p->p_ru.minflt;
17544584Srh87107 	tu->tu_majflt = p->p_ru.majflt;
17554584Srh87107 	tu->tu_sndmsg = p->p_ru.msgsnd;
17564584Srh87107 	tu->tu_rcvmsg = p->p_ru.msgrcv;
17574584Srh87107 	tu->tu_ioch   = p->p_ru.ioch;
17584584Srh87107 	tu->tu_iblk   = p->p_ru.inblock;
17594584Srh87107 	tu->tu_oblk   = p->p_ru.oublock;
17604584Srh87107 	tu->tu_vcsw   = p->p_ru.nvcsw;
17614584Srh87107 	tu->tu_icsw   = p->p_ru.nivcsw;
17624584Srh87107 	tu->tu_nsig   = p->p_ru.nsignals;
17634584Srh87107 	tu->tu_nswp   = p->p_ru.nswap;
17644584Srh87107 	tu->tu_nscl   = p->p_ru.sysc;
17654584Srh87107 }
17664584Srh87107 
17674584Srh87107 /*
17684584Srh87107  * void exacct_move_mstate(proc_t *, task_t *, task_t *)
17694584Srh87107  *
17704584Srh87107  * Overview
17714584Srh87107  *   exacct_move_mstate() is called by task_change() and accounts for
17724584Srh87107  *   a process's resource usage when it is moved from one task to another.
17734584Srh87107  *
17744584Srh87107  *   The process's usage at this point is recorded in the new task so
17754584Srh87107  *   that it can be excluded from the calculation of resources consumed
17764584Srh87107  *   by that task.
17774584Srh87107  *
17784584Srh87107  *   The resource usage inherited by the new task is also added to the
17794584Srh87107  *   aggregate maintained by the old task for processes that have exited.
17804584Srh87107  *
17814584Srh87107  * Return values
17824584Srh87107  *   None.
17834584Srh87107  *
17844584Srh87107  * Caller's context
17854584Srh87107  *   pidlock and p_lock held across exacct_move_mstate().
17864584Srh87107  */
17874584Srh87107 void
17884584Srh87107 exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk)
17894584Srh87107 {
17904584Srh87107 	task_usage_t tu;
17914584Srh87107 
17924584Srh87107 	/* Take a snapshot of this process's mstate and RU counters */
17934584Srh87107 	exacct_snapshot_proc_mstate(p, &tu);
17944584Srh87107 
17954584Srh87107 	/*
17964584Srh87107 	 * Use the snapshot to increment the aggregate usage of the old
17974584Srh87107 	 * task, and the inherited usage of the new one.
17984584Srh87107 	 */
17994584Srh87107 	mutex_enter(&oldtk->tk_usage_lock);
18004584Srh87107 	exacct_add_task_mstate(oldtk->tk_usage, &tu);
18014584Srh87107 	mutex_exit(&oldtk->tk_usage_lock);
18024584Srh87107 	mutex_enter(&newtk->tk_usage_lock);
18034584Srh87107 	exacct_add_task_mstate(newtk->tk_inherited, &tu);
18044584Srh87107 	mutex_exit(&newtk->tk_usage_lock);
18054584Srh87107 }
1806