xref: /onnv-gate/usr/src/uts/common/os/exacct.c (revision 5331:3047ad28a67b)
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 /*
224584Srh87107  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/exacct.h>
290Sstevel@tonic-gate #include <sys/exacct_catalog.h>
300Sstevel@tonic-gate #include <sys/disp.h>
310Sstevel@tonic-gate #include <sys/task.h>
320Sstevel@tonic-gate #include <sys/proc.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/kmem.h>
350Sstevel@tonic-gate #include <sys/project.h>
360Sstevel@tonic-gate #include <sys/systm.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/file.h>
390Sstevel@tonic-gate #include <sys/acctctl.h>
400Sstevel@tonic-gate #include <sys/time.h>
410Sstevel@tonic-gate #include <sys/utsname.h>
420Sstevel@tonic-gate #include <sys/session.h>
430Sstevel@tonic-gate #include <sys/sysmacros.h>
440Sstevel@tonic-gate #include <sys/bitmap.h>
450Sstevel@tonic-gate #include <sys/msacct.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate  * exacct usage and recording routines
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  * wracct(2), getacct(2), and the records written at process or task
510Sstevel@tonic-gate  * termination are constructed using the exacct_assemble_[task,proc]_usage()
520Sstevel@tonic-gate  * functions, which take a callback that takes the appropriate action on
530Sstevel@tonic-gate  * the packed exacct record for the task or process.  For the process-related
540Sstevel@tonic-gate  * actions, we partition the routines such that the data collecting component
550Sstevel@tonic-gate  * can be performed while holding p_lock, and all sleeping or blocking
560Sstevel@tonic-gate  * operations can be performed without acquiring p_lock.
570Sstevel@tonic-gate  *
580Sstevel@tonic-gate  * putacct(2), which allows an application to construct a customized record
590Sstevel@tonic-gate  * associated with an existing process or task, has its own entry points:
600Sstevel@tonic-gate  * exacct_tag_task() and exacct_tag_proc().
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate 
630Sstevel@tonic-gate taskq_t *exacct_queue;
640Sstevel@tonic-gate kmem_cache_t *exacct_object_cache;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION;
690Sstevel@tonic-gate static const char exacct_header[] = "exacct";
700Sstevel@tonic-gate static const char exacct_creator[] = "SunOS";
710Sstevel@tonic-gate 
720Sstevel@tonic-gate ea_object_t *
730Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz)
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	ea_object_t *item;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
780Sstevel@tonic-gate 	bzero(item, sizeof (ea_object_t));
790Sstevel@tonic-gate 	(void) ea_set_item(item, catalog, buf, bufsz);
800Sstevel@tonic-gate 	return (item);
810Sstevel@tonic-gate }
820Sstevel@tonic-gate 
830Sstevel@tonic-gate ea_object_t *
840Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	ea_object_t *group;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
890Sstevel@tonic-gate 	bzero(group, sizeof (ea_object_t));
900Sstevel@tonic-gate 	(void) ea_set_group(group, catalog);
910Sstevel@tonic-gate 	return (group);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate ea_object_t *
950Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	ea_object_t *item;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	item = ea_alloc_item(catalog, buf, bufsz);
1000Sstevel@tonic-gate 	(void) ea_attach_to_group(grp, item);
1010Sstevel@tonic-gate 	return (item);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1054584Srh87107  * exacct_add_task_mstate() and exacct_sub_task_mstate() add and subtract
1064584Srh87107  * microstate accounting data and resource usage counters from one task_usage_t
1074584Srh87107  * from those supplied in another. These functions do not operate on *all*
1084584Srh87107  * members of a task_usage_t: for some (e.g. tu_anctaskid) it would not make
1094584Srh87107  * sense.
1104584Srh87107  */
1114584Srh87107 static void
1124584Srh87107 exacct_add_task_mstate(task_usage_t *tu, task_usage_t *delta)
1134584Srh87107 {
1144584Srh87107 	tu->tu_utime  += delta->tu_utime;
1154584Srh87107 	tu->tu_stime  += delta->tu_stime;
1164584Srh87107 	tu->tu_minflt += delta->tu_minflt;
1174584Srh87107 	tu->tu_majflt += delta->tu_majflt;
1184584Srh87107 	tu->tu_sndmsg += delta->tu_sndmsg;
1194584Srh87107 	tu->tu_rcvmsg += delta->tu_rcvmsg;
1204584Srh87107 	tu->tu_ioch   += delta->tu_ioch;
1214584Srh87107 	tu->tu_iblk   += delta->tu_iblk;
1224584Srh87107 	tu->tu_oblk   += delta->tu_oblk;
1234584Srh87107 	tu->tu_vcsw   += delta->tu_vcsw;
1244584Srh87107 	tu->tu_icsw   += delta->tu_icsw;
1254584Srh87107 	tu->tu_nsig   += delta->tu_nsig;
1264584Srh87107 	tu->tu_nswp   += delta->tu_nswp;
1274584Srh87107 	tu->tu_nscl   += delta->tu_nscl;
1284584Srh87107 }
1294584Srh87107 
1304584Srh87107 /*
1314584Srh87107  * See the comments for exacct_add_task_mstate(), above.
1324584Srh87107  */
1334584Srh87107 static void
1344584Srh87107 exacct_sub_task_mstate(task_usage_t *tu, task_usage_t *delta)
1354584Srh87107 {
1364584Srh87107 	tu->tu_utime  -= delta->tu_utime;
1374584Srh87107 	tu->tu_stime  -= delta->tu_stime;
1384584Srh87107 	tu->tu_minflt -= delta->tu_minflt;
1394584Srh87107 	tu->tu_majflt -= delta->tu_majflt;
1404584Srh87107 	tu->tu_sndmsg -= delta->tu_sndmsg;
1414584Srh87107 	tu->tu_rcvmsg -= delta->tu_rcvmsg;
1424584Srh87107 	tu->tu_ioch   -= delta->tu_ioch;
1434584Srh87107 	tu->tu_iblk   -= delta->tu_iblk;
1444584Srh87107 	tu->tu_oblk   -= delta->tu_oblk;
1454584Srh87107 	tu->tu_vcsw   -= delta->tu_vcsw;
1464584Srh87107 	tu->tu_icsw   -= delta->tu_icsw;
1474584Srh87107 	tu->tu_nsig   -= delta->tu_nsig;
1484584Srh87107 	tu->tu_nswp   -= delta->tu_nswp;
1494584Srh87107 	tu->tu_nscl   -= delta->tu_nscl;
1504584Srh87107 }
1514584Srh87107 
1524584Srh87107 /*
1530Sstevel@tonic-gate  * exacct_vn_write() is a vn_rdwr wrapper that protects us from corrupting the
1540Sstevel@tonic-gate  * accounting file in case of an I/O or filesystem error.  acctctl() prevents
1550Sstevel@tonic-gate  * the two accounting vnodes from being equal, and the appropriate ac_lock is
1560Sstevel@tonic-gate  * held across the call, so we're single threaded through this code for each
1570Sstevel@tonic-gate  * file.
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate static int
1600Sstevel@tonic-gate exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate 	int error = 0;
1630Sstevel@tonic-gate 	ssize_t resid;
1640Sstevel@tonic-gate 	struct vattr va;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (info == NULL)
1670Sstevel@tonic-gate 		return (0);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	mutex_enter(&info->ac_lock);
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/*
1720Sstevel@tonic-gate 	 * Don't do anything unless accounting file is set.
1730Sstevel@tonic-gate 	 */
1740Sstevel@tonic-gate 	if (info->ac_vnode == NULL) {
1750Sstevel@tonic-gate 		mutex_exit(&info->ac_lock);
1760Sstevel@tonic-gate 		return (0);
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	/*
1800Sstevel@tonic-gate 	 * Save the size. If vn_rdwr fails, reset the size to avoid corrupting
1810Sstevel@tonic-gate 	 * the present accounting file.
1820Sstevel@tonic-gate 	 */
1830Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
184*5331Samw 	error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1850Sstevel@tonic-gate 	if (error == 0) {
1860Sstevel@tonic-gate 		error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf,
1870Sstevel@tonic-gate 		    bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T,
1880Sstevel@tonic-gate 		    kcred, &resid);
1890Sstevel@tonic-gate 		if (error) {
1900Sstevel@tonic-gate 			(void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1910Sstevel@tonic-gate 		} else if (resid != 0) {
1920Sstevel@tonic-gate 			(void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
1930Sstevel@tonic-gate 			error = ENOSPC;
1940Sstevel@tonic-gate 		}
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 	mutex_exit(&info->ac_lock);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	return (error);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate  * void *exacct_create_header(size_t *)
2030Sstevel@tonic-gate  *
2040Sstevel@tonic-gate  * Overview
2050Sstevel@tonic-gate  *   exacct_create_header() constructs an exacct file header identifying the
2060Sstevel@tonic-gate  *   accounting file as the output of the kernel.  exacct_create_header() and
2070Sstevel@tonic-gate  *   the static write_header() and verify_header() routines in libexacct must
2080Sstevel@tonic-gate  *   remain synchronized.
2090Sstevel@tonic-gate  *
2100Sstevel@tonic-gate  * Return values
2110Sstevel@tonic-gate  *   A pointer to a packed exacct buffer containing the appropriate header is
2120Sstevel@tonic-gate  *   returned; the size of the buffer is placed in the location indicated by
2130Sstevel@tonic-gate  *   sizep.
2140Sstevel@tonic-gate  *
2150Sstevel@tonic-gate  * Caller's context
2160Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate void *
2190Sstevel@tonic-gate exacct_create_header(size_t *sizep)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	ea_object_t *hdr_grp;
2220Sstevel@tonic-gate 	uint32_t bskip;
2230Sstevel@tonic-gate 	void *buf;
2240Sstevel@tonic-gate 	size_t bufsize;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER);
2270Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0,
2280Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_VERSION);
2290Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)exacct_header, 0,
2300Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_FILETYPE);
2310Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0,
2320Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_CREATOR);
2330Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, uts_nodename(), 0,
2340Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	bufsize = ea_pack_object(hdr_grp, NULL, 0);
2370Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
2380Sstevel@tonic-gate 	(void) ea_pack_object(hdr_grp, buf, bufsize);
2390Sstevel@tonic-gate 	ea_free_object(hdr_grp, EUP_ALLOC);
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	/*
2420Sstevel@tonic-gate 	 * To prevent reading the header when reading the file backwards,
2430Sstevel@tonic-gate 	 * set the large backskip of the header group to 0 (last 4 bytes).
2440Sstevel@tonic-gate 	 */
2450Sstevel@tonic-gate 	bskip = 0;
2460Sstevel@tonic-gate 	exacct_order32(&bskip);
2470Sstevel@tonic-gate 	bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip),
2480Sstevel@tonic-gate 	    sizeof (bskip));
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	*sizep = bufsize;
2510Sstevel@tonic-gate 	return (buf);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  * int exacct_write_header(ac_info_t *, void *, size_t)
2560Sstevel@tonic-gate  *
2570Sstevel@tonic-gate  * Overview
2580Sstevel@tonic-gate  *   exacct_write_header() writes the given header buffer to the indicated
2590Sstevel@tonic-gate  *   vnode, and frees the buffer.
2600Sstevel@tonic-gate  *
2610Sstevel@tonic-gate  * Return values
2620Sstevel@tonic-gate  *   The result of the write operation is returned.
2630Sstevel@tonic-gate  *
2640Sstevel@tonic-gate  * Caller's context
2650Sstevel@tonic-gate  *   Caller must not hold the ac_lock of the appropriate accounting file
2660Sstevel@tonic-gate  *   information block (ac_info_t).
2670Sstevel@tonic-gate  */
2680Sstevel@tonic-gate int
2690Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	int error;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	error = exacct_vn_write(info, hdr, hdrsize);
2740Sstevel@tonic-gate 	kmem_free(hdr, hdrsize);
2750Sstevel@tonic-gate 	return (error);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate static void
2790Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu,
2800Sstevel@tonic-gate     task_usage_t **tu_buf)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	task_usage_t *oldtu, *newtu;
2830Sstevel@tonic-gate 	task_usage_t **prevusage;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&tk->tk_usage_lock));
2860Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID) {
2870Sstevel@tonic-gate 		prevusage = &tk->tk_zoneusage;
2880Sstevel@tonic-gate 	} else {
2890Sstevel@tonic-gate 		prevusage = &tk->tk_prevusage;
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 	if ((oldtu = *prevusage) != NULL) {
2920Sstevel@tonic-gate 		/*
2930Sstevel@tonic-gate 		 * In case we have any accounting information
2940Sstevel@tonic-gate 		 * saved from the previous interval record.
2950Sstevel@tonic-gate 		 */
2960Sstevel@tonic-gate 		newtu = *tu_buf;
2970Sstevel@tonic-gate 		bcopy(tu, newtu, sizeof (task_usage_t));
2980Sstevel@tonic-gate 		tu->tu_minflt	-= oldtu->tu_minflt;
2990Sstevel@tonic-gate 		tu->tu_majflt	-= oldtu->tu_majflt;
3000Sstevel@tonic-gate 		tu->tu_sndmsg	-= oldtu->tu_sndmsg;
3010Sstevel@tonic-gate 		tu->tu_rcvmsg	-= oldtu->tu_rcvmsg;
3020Sstevel@tonic-gate 		tu->tu_ioch	-= oldtu->tu_ioch;
3030Sstevel@tonic-gate 		tu->tu_iblk	-= oldtu->tu_iblk;
3040Sstevel@tonic-gate 		tu->tu_oblk	-= oldtu->tu_oblk;
3050Sstevel@tonic-gate 		tu->tu_vcsw	-= oldtu->tu_vcsw;
3060Sstevel@tonic-gate 		tu->tu_icsw	-= oldtu->tu_icsw;
3070Sstevel@tonic-gate 		tu->tu_nsig	-= oldtu->tu_nsig;
3080Sstevel@tonic-gate 		tu->tu_nswp	-= oldtu->tu_nswp;
3090Sstevel@tonic-gate 		tu->tu_nscl	-= oldtu->tu_nscl;
3100Sstevel@tonic-gate 		tu->tu_utime	-= oldtu->tu_utime;
3110Sstevel@tonic-gate 		tu->tu_stime	-= oldtu->tu_stime;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		tu->tu_startsec = oldtu->tu_finishsec;
3140Sstevel@tonic-gate 		tu->tu_startnsec = oldtu->tu_finishnsec;
3150Sstevel@tonic-gate 		/*
3160Sstevel@tonic-gate 		 * Copy the data from our temporary storage to the task's
3170Sstevel@tonic-gate 		 * previous interval usage structure for future reference.
3180Sstevel@tonic-gate 		 */
3190Sstevel@tonic-gate 		bcopy(newtu, oldtu, sizeof (task_usage_t));
3200Sstevel@tonic-gate 	} else {
3210Sstevel@tonic-gate 		/*
3220Sstevel@tonic-gate 		 * Store current statistics in the task's previous interval
3230Sstevel@tonic-gate 		 * usage structure for future references.
3240Sstevel@tonic-gate 		 */
3250Sstevel@tonic-gate 		*prevusage = *tu_buf;
3260Sstevel@tonic-gate 		bcopy(tu, *prevusage, sizeof (task_usage_t));
3270Sstevel@tonic-gate 		*tu_buf = NULL;
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate static void
3320Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu)
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate 	timestruc_t ts;
3350Sstevel@tonic-gate 	proc_t *p;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if ((p = tk->tk_memb_list) == NULL)
3400Sstevel@tonic-gate 		return;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	/*
3430Sstevel@tonic-gate 	 * exacct_snapshot_task_usage() provides an approximate snapshot of the
3440Sstevel@tonic-gate 	 * usage of the potentially many members of the task.  Since we don't
3450Sstevel@tonic-gate 	 * guarantee exactness, we don't acquire the p_lock of any of the member
3460Sstevel@tonic-gate 	 * processes.
3470Sstevel@tonic-gate 	 */
3480Sstevel@tonic-gate 	do {
3490Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
3500Sstevel@tonic-gate 		tu->tu_utime	+= mstate_aggr_state(p, LMS_USER);
3510Sstevel@tonic-gate 		tu->tu_stime	+= mstate_aggr_state(p, LMS_SYSTEM);
3520Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3530Sstevel@tonic-gate 		tu->tu_minflt	+= p->p_ru.minflt;
3540Sstevel@tonic-gate 		tu->tu_majflt	+= p->p_ru.majflt;
3550Sstevel@tonic-gate 		tu->tu_sndmsg	+= p->p_ru.msgsnd;
3560Sstevel@tonic-gate 		tu->tu_rcvmsg	+= p->p_ru.msgrcv;
3570Sstevel@tonic-gate 		tu->tu_ioch	+= p->p_ru.ioch;
3580Sstevel@tonic-gate 		tu->tu_iblk	+= p->p_ru.inblock;
3590Sstevel@tonic-gate 		tu->tu_oblk	+= p->p_ru.oublock;
3600Sstevel@tonic-gate 		tu->tu_vcsw	+= p->p_ru.nvcsw;
3610Sstevel@tonic-gate 		tu->tu_icsw	+= p->p_ru.nivcsw;
3620Sstevel@tonic-gate 		tu->tu_nsig	+= p->p_ru.nsignals;
3630Sstevel@tonic-gate 		tu->tu_nswp	+= p->p_ru.nswap;
3640Sstevel@tonic-gate 		tu->tu_nscl	+= p->p_ru.sysc;
3650Sstevel@tonic-gate 	} while ((p = p->p_tasknext) != tk->tk_memb_list);
3660Sstevel@tonic-gate 
3674584Srh87107 	/*
3684584Srh87107 	 * The resource usage accounted for so far will include that
3694584Srh87107 	 * contributed by the task's first process. If this process
3704584Srh87107 	 * came from another task, then its accumulated resource usage
3714584Srh87107 	 * will include a contribution from work performed there.
3724584Srh87107 	 * We must therefore subtract any resource usage that was
3734584Srh87107 	 * inherited with the first process.
3744584Srh87107 	 */
3754584Srh87107 	exacct_sub_task_mstate(tu, tk->tk_inherited);
3764584Srh87107 
3770Sstevel@tonic-gate 	gethrestime(&ts);
3780Sstevel@tonic-gate 	tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
3790Sstevel@tonic-gate 	tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate /*
3834584Srh87107  * void exacct_update_task_mstate(proc_t *)
3844584Srh87107  *
3854584Srh87107  * Overview
3864584Srh87107  *   exacct_update_task_mstate() updates the task usage; it is intended
3874584Srh87107  *   to be called from proc_exit().
3884584Srh87107  *
3894584Srh87107  * Return values
3904584Srh87107  *   None.
3914584Srh87107  *
3924584Srh87107  * Caller's context
3934584Srh87107  *   p_lock must be held at entry.
3940Sstevel@tonic-gate  */
3954584Srh87107 void
3960Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	task_usage_t *tu;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	mutex_enter(&p->p_task->tk_usage_lock);
4010Sstevel@tonic-gate 	tu = p->p_task->tk_usage;
4020Sstevel@tonic-gate 	tu->tu_utime	+= mstate_aggr_state(p, LMS_USER);
4030Sstevel@tonic-gate 	tu->tu_stime	+= mstate_aggr_state(p, LMS_SYSTEM);
4040Sstevel@tonic-gate 	tu->tu_minflt	+= p->p_ru.minflt;
4050Sstevel@tonic-gate 	tu->tu_majflt	+= p->p_ru.majflt;
4060Sstevel@tonic-gate 	tu->tu_sndmsg	+= p->p_ru.msgsnd;
4070Sstevel@tonic-gate 	tu->tu_rcvmsg	+= p->p_ru.msgrcv;
4080Sstevel@tonic-gate 	tu->tu_ioch	+= p->p_ru.ioch;
4090Sstevel@tonic-gate 	tu->tu_iblk	+= p->p_ru.inblock;
4100Sstevel@tonic-gate 	tu->tu_oblk	+= p->p_ru.oublock;
4110Sstevel@tonic-gate 	tu->tu_vcsw	+= p->p_ru.nvcsw;
4120Sstevel@tonic-gate 	tu->tu_icsw	+= p->p_ru.nivcsw;
4130Sstevel@tonic-gate 	tu->tu_nsig	+= p->p_ru.nsignals;
4140Sstevel@tonic-gate 	tu->tu_nswp	+= p->p_ru.nswap;
4150Sstevel@tonic-gate 	tu->tu_nscl	+= p->p_ru.sysc;
4160Sstevel@tonic-gate 	mutex_exit(&p->p_task->tk_usage_lock);
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate static void
4200Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag)
4210Sstevel@tonic-gate {
4220Sstevel@tonic-gate 	timestruc_t ts;
4230Sstevel@tonic-gate 	task_usage_t *tu_buf;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	switch (flag) {
4260Sstevel@tonic-gate 	case EW_PARTIAL:
4270Sstevel@tonic-gate 		/*
4280Sstevel@tonic-gate 		 * For partial records we must report the sum of current
4290Sstevel@tonic-gate 		 * accounting statistics with previously accumulated
4300Sstevel@tonic-gate 		 * statistics.
4310Sstevel@tonic-gate 		 */
4320Sstevel@tonic-gate 		mutex_enter(&pidlock);
4330Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4360Sstevel@tonic-gate 		exacct_snapshot_task_usage(tk, tu);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
4390Sstevel@tonic-gate 		mutex_exit(&pidlock);
4400Sstevel@tonic-gate 		break;
4410Sstevel@tonic-gate 	case EW_INTERVAL:
4420Sstevel@tonic-gate 		/*
4430Sstevel@tonic-gate 		 * We need to allocate spare task_usage_t buffer before
4440Sstevel@tonic-gate 		 * grabbing pidlock because we might need it later in
4450Sstevel@tonic-gate 		 * exacct_get_interval_task_usage().
4460Sstevel@tonic-gate 		 */
4470Sstevel@tonic-gate 		tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
4480Sstevel@tonic-gate 		mutex_enter(&pidlock);
4490Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 		/*
4520Sstevel@tonic-gate 		 * For interval records, we deduct the previous microstate
4530Sstevel@tonic-gate 		 * accounting data and cpu usage times from previously saved
4540Sstevel@tonic-gate 		 * results and update the previous task usage structure.
4550Sstevel@tonic-gate 		 */
4560Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4570Sstevel@tonic-gate 		exacct_snapshot_task_usage(tk, tu);
4580Sstevel@tonic-gate 		exacct_get_interval_task_usage(tk, tu, &tu_buf);
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
4610Sstevel@tonic-gate 		mutex_exit(&pidlock);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		if (tu_buf != NULL)
4640Sstevel@tonic-gate 			kmem_free(tu_buf, sizeof (task_usage_t));
4650Sstevel@tonic-gate 		break;
4660Sstevel@tonic-gate 	case EW_FINAL:
4670Sstevel@tonic-gate 		/*
4684584Srh87107 		 * For final records, we deduct, from the task's current
4694584Srh87107 		 * usage, any usage that was inherited with the arrival
4704584Srh87107 		 * of a process from a previous task. We then record
4714584Srh87107 		 * the task's finish time.
4720Sstevel@tonic-gate 		 */
4730Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
4740Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
4754584Srh87107 		exacct_sub_task_mstate(tu, tk->tk_inherited);
4760Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		gethrestime(&ts);
4790Sstevel@tonic-gate 		tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
4800Sstevel@tonic-gate 		tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 		break;
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate static int
4870Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record,
4880Sstevel@tonic-gate     int res)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	int attached = 1;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	switch (res) {
4930Sstevel@tonic-gate 	case AC_TASK_TASKID:
4940Sstevel@tonic-gate 		(void) ea_attach_item(record, &tk->tk_tkid,
4950Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID);
4960Sstevel@tonic-gate 		break;
4970Sstevel@tonic-gate 	case AC_TASK_PROJID:
4980Sstevel@tonic-gate 		(void) ea_attach_item(record, &tk->tk_proj->kpj_id,
4990Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID);
5000Sstevel@tonic-gate 		break;
5010Sstevel@tonic-gate 	case AC_TASK_CPU: {
5020Sstevel@tonic-gate 			timestruc_t ts;
5030Sstevel@tonic-gate 			uint64_t ui;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 			hrt2ts(tu->tu_stime, &ts);
5060Sstevel@tonic-gate 			ui = ts.tv_sec;
5070Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5080Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_SYS_SEC);
5090Sstevel@tonic-gate 			ui = ts.tv_nsec;
5100Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5110Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC);
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 			hrt2ts(tu->tu_utime, &ts);
5140Sstevel@tonic-gate 			ui = ts.tv_sec;
5150Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5160Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_USER_SEC);
5170Sstevel@tonic-gate 			ui = ts.tv_nsec;
5180Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
5190Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_USER_NSEC);
5200Sstevel@tonic-gate 		}
5210Sstevel@tonic-gate 		break;
5220Sstevel@tonic-gate 	case AC_TASK_TIME:
5230Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_startsec,
5240Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC);
5250Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_startnsec,
5260Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC);
5270Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_finishsec,
5280Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC);
5290Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_finishnsec,
5300Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC);
5310Sstevel@tonic-gate 		break;
5320Sstevel@tonic-gate 	case AC_TASK_HOSTNAME:
5330Sstevel@tonic-gate 		(void) ea_attach_item(record, tk->tk_zone->zone_nodename,
5340Sstevel@tonic-gate 		    strlen(tk->tk_zone->zone_nodename) + 1,
5350Sstevel@tonic-gate 		    EXT_STRING | EXD_TASK_HOSTNAME);
5360Sstevel@tonic-gate 			break;
5370Sstevel@tonic-gate 	case AC_TASK_MICROSTATE:
5380Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_majflt,
5390Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR);
5400Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_minflt,
5410Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR);
5420Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_sndmsg,
5430Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND);
5440Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_rcvmsg,
5450Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV);
5460Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_iblk,
5470Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN);
5480Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_oblk,
5490Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT);
5500Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_ioch,
5510Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR);
5520Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_vcsw,
5530Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL);
5540Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_icsw,
5550Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV);
5560Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nsig,
5570Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS);
5580Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nswp,
5590Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS);
5600Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nscl,
5610Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS);
5620Sstevel@tonic-gate 		break;
5630Sstevel@tonic-gate 	case AC_TASK_ANCTASKID:
5640Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_anctaskid,
5650Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID);
5660Sstevel@tonic-gate 		break;
5670Sstevel@tonic-gate 	case AC_TASK_ZONENAME:
5680Sstevel@tonic-gate 		(void) ea_attach_item(record, tk->tk_zone->zone_name,
5690Sstevel@tonic-gate 		    strlen(tk->tk_zone->zone_name) + 1,
5700Sstevel@tonic-gate 		    EXT_STRING | EXD_TASK_ZONENAME);
5710Sstevel@tonic-gate 		break;
5720Sstevel@tonic-gate 	default:
5730Sstevel@tonic-gate 		attached = 0;
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 	return (attached);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate static ea_object_t *
5790Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask,
5800Sstevel@tonic-gate     ea_catalog_t record_type)
5810Sstevel@tonic-gate {
5820Sstevel@tonic-gate 	int res, count;
5830Sstevel@tonic-gate 	ea_object_t *record;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	/*
5860Sstevel@tonic-gate 	 * Assemble usage values into group.
5870Sstevel@tonic-gate 	 */
5880Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
5890Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++)
5900Sstevel@tonic-gate 		if (BT_TEST(mask, res))
5910Sstevel@tonic-gate 			count += exacct_attach_task_item(tk, tu, record, res);
5920Sstevel@tonic-gate 	if (count == 0) {
5930Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
5940Sstevel@tonic-gate 		record = NULL;
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 	return (record);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate  * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *,
6010Sstevel@tonic-gate  *	size_t, size_t *), void *, size_t, size_t *, int)
6020Sstevel@tonic-gate  *
6030Sstevel@tonic-gate  * Overview
6040Sstevel@tonic-gate  *   exacct_assemble_task_usage() builds the packed exacct buffer for the
6050Sstevel@tonic-gate  *   indicated task, executes the given callback function, and free the packed
6060Sstevel@tonic-gate  *   buffer.
6070Sstevel@tonic-gate  *
6080Sstevel@tonic-gate  * Return values
6090Sstevel@tonic-gate  *   Returns 0 on success; otherwise the appropriate error code is returned.
6100Sstevel@tonic-gate  *
6110Sstevel@tonic-gate  * Caller's context
6120Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
6130Sstevel@tonic-gate  */
6140Sstevel@tonic-gate int
6150Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk,
6160Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
6170Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual, int flag)
6180Sstevel@tonic-gate {
6190Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
6200Sstevel@tonic-gate 	ea_object_t *task_record;
6210Sstevel@tonic-gate 	ea_catalog_t record_type;
6220Sstevel@tonic-gate 	task_usage_t *tu;
6230Sstevel@tonic-gate 	void *buf;
6240Sstevel@tonic-gate 	size_t bufsize;
6250Sstevel@tonic-gate 	int ret;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	mutex_enter(&ac_task->ac_lock);
6300Sstevel@tonic-gate 	if (ac_task->ac_state == AC_OFF) {
6310Sstevel@tonic-gate 		mutex_exit(&ac_task->ac_lock);
6320Sstevel@tonic-gate 		return (ENOTACTIVE);
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 	bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ);
6350Sstevel@tonic-gate 	mutex_exit(&ac_task->ac_lock);
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	switch (flag) {
6380Sstevel@tonic-gate 	case EW_FINAL:
6390Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK;
6400Sstevel@tonic-gate 		break;
6410Sstevel@tonic-gate 	case EW_PARTIAL:
6420Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK_PARTIAL;
6430Sstevel@tonic-gate 		break;
6440Sstevel@tonic-gate 	case EW_INTERVAL:
6450Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK_INTERVAL;
6460Sstevel@tonic-gate 		break;
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	/*
6500Sstevel@tonic-gate 	 * Calculate task usage and assemble it into the task record.
6510Sstevel@tonic-gate 	 */
6520Sstevel@tonic-gate 	tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
6530Sstevel@tonic-gate 	exacct_calculate_task_usage(tk, tu, flag);
6540Sstevel@tonic-gate 	task_record = exacct_assemble_task_record(tk, tu, mask, record_type);
6550Sstevel@tonic-gate 	if (task_record == NULL) {
6560Sstevel@tonic-gate 		/*
6570Sstevel@tonic-gate 		 * The current configuration of the accounting system has
6580Sstevel@tonic-gate 		 * resulted in records with no data; accordingly, we don't write
6590Sstevel@tonic-gate 		 * these, but we return success.
6600Sstevel@tonic-gate 		 */
6610Sstevel@tonic-gate 		kmem_free(tu, sizeof (task_usage_t));
6620Sstevel@tonic-gate 		return (0);
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	/*
6660Sstevel@tonic-gate 	 * Pack object into buffer and run callback on it.
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	bufsize = ea_pack_object(task_record, NULL, 0);
6690Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
6700Sstevel@tonic-gate 	(void) ea_pack_object(task_record, buf, bufsize);
6710Sstevel@tonic-gate 	ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/*
6740Sstevel@tonic-gate 	 * Free all previously allocated structures.
6750Sstevel@tonic-gate 	 */
6760Sstevel@tonic-gate 	kmem_free(buf, bufsize);
6770Sstevel@tonic-gate 	ea_free_object(task_record, EUP_ALLOC);
6780Sstevel@tonic-gate 	kmem_free(tu, sizeof (task_usage_t));
6790Sstevel@tonic-gate 	return (ret);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate /*
6830Sstevel@tonic-gate  * void exacct_commit_task(void *)
6840Sstevel@tonic-gate  *
6850Sstevel@tonic-gate  * Overview
6860Sstevel@tonic-gate  *   exacct_commit_task() calculates the final usage for a task, updating the
6870Sstevel@tonic-gate  *   task usage if task accounting is active, and writing a task record if task
6880Sstevel@tonic-gate  *   accounting is active.  exacct_commit_task() is intended for being called
6890Sstevel@tonic-gate  *   from a task queue (taskq_t).
6900Sstevel@tonic-gate  *
6910Sstevel@tonic-gate  * Return values
6920Sstevel@tonic-gate  *   None.
6930Sstevel@tonic-gate  *
6940Sstevel@tonic-gate  * Caller's context
6950Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
6960Sstevel@tonic-gate  */
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate void
6990Sstevel@tonic-gate exacct_commit_task(void *arg)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	task_t *tk = (task_t *)arg;
7020Sstevel@tonic-gate 	size_t size;
7030Sstevel@tonic-gate 	zone_t *zone = tk->tk_zone;
7040Sstevel@tonic-gate 	struct exacct_globals *acg;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	ASSERT(tk != task0p);
7070Sstevel@tonic-gate 	ASSERT(tk->tk_memb_list == NULL);
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	/*
7100Sstevel@tonic-gate 	 * Don't do any extra work if the acctctl module isn't loaded.
7110Sstevel@tonic-gate 	 */
7120Sstevel@tonic-gate 	if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) {
7130Sstevel@tonic-gate 		acg = zone_getspecific(exacct_zone_key, zone);
7140Sstevel@tonic-gate 		(void) exacct_assemble_task_usage(&acg->ac_task, tk,
7150Sstevel@tonic-gate 		    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7160Sstevel@tonic-gate 		if (tk->tk_zone != global_zone) {
7170Sstevel@tonic-gate 			acg = zone_getspecific(exacct_zone_key, global_zone);
7180Sstevel@tonic-gate 			(void) exacct_assemble_task_usage(&acg->ac_task, tk,
7190Sstevel@tonic-gate 			    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 	}
7220Sstevel@tonic-gate 	/*
7230Sstevel@tonic-gate 	 * Release associated project and finalize task.
7240Sstevel@tonic-gate 	 */
7250Sstevel@tonic-gate 	task_end(tk);
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate static int
7290Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res)
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate 	int attached = 1;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	switch (res) {
7340Sstevel@tonic-gate 	case AC_PROC_PID:
7350Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_pid,
7360Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID);
7370Sstevel@tonic-gate 		break;
7380Sstevel@tonic-gate 	case AC_PROC_UID:
7390Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ruid,
7400Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID);
7410Sstevel@tonic-gate 		break;
7420Sstevel@tonic-gate 	case AC_PROC_FLAG:
7430Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_acflag,
7440Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS);
7450Sstevel@tonic-gate 		break;
7460Sstevel@tonic-gate 	case AC_PROC_GID:
7470Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_rgid,
7480Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID);
7490Sstevel@tonic-gate 		break;
7500Sstevel@tonic-gate 	case AC_PROC_PROJID:
7510Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_projid,
7520Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID);
7530Sstevel@tonic-gate 		break;
7540Sstevel@tonic-gate 	case AC_PROC_TASKID:
7550Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_taskid,
7560Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID);
7570Sstevel@tonic-gate 		break;
7580Sstevel@tonic-gate 	case AC_PROC_CPU:
7590Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_utimesec,
7600Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC);
7610Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_utimensec,
7620Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC);
7630Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_stimesec,
7640Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC);
7650Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_stimensec,
7660Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC);
7670Sstevel@tonic-gate 		break;
7680Sstevel@tonic-gate 	case AC_PROC_TIME:
7690Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_startsec,
7700Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC);
7710Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_startnsec,
7720Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC);
7730Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_finishsec,
7740Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC);
7750Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_finishnsec,
7760Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC);
7770Sstevel@tonic-gate 		break;
7780Sstevel@tonic-gate 	case AC_PROC_COMMAND:
7790Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_command,
7800Sstevel@tonic-gate 		    strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND);
7810Sstevel@tonic-gate 		break;
7820Sstevel@tonic-gate 	case AC_PROC_HOSTNAME:
7830Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_nodename,
7840Sstevel@tonic-gate 		    strlen(pu->pu_nodename) + 1,
7850Sstevel@tonic-gate 		    EXT_STRING | EXD_PROC_HOSTNAME);
7860Sstevel@tonic-gate 		break;
7870Sstevel@tonic-gate 	case AC_PROC_TTY:
7880Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_major,
7890Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR);
7900Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_minor,
7910Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR);
7920Sstevel@tonic-gate 		break;
7930Sstevel@tonic-gate 	case AC_PROC_MICROSTATE:
7940Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_majflt,
7950Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR);
7960Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_minflt,
7970Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR);
7980Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_sndmsg,
7990Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND);
8000Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_rcvmsg,
8010Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV);
8020Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_iblk,
8030Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN);
8040Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_oblk,
8050Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT);
8060Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ioch,
8070Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR);
8080Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_vcsw,
8090Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL);
8100Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_icsw,
8110Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV);
8120Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nsig,
8130Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS);
8140Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nswp,
8150Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS);
8160Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nscl,
8170Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS);
8180Sstevel@tonic-gate 		break;
8190Sstevel@tonic-gate 	case AC_PROC_ANCPID:
8200Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ancpid,
8210Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID);
8220Sstevel@tonic-gate 		break;
8230Sstevel@tonic-gate 	case AC_PROC_WAIT_STATUS:
8240Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_wstat,
8250Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS);
8260Sstevel@tonic-gate 		break;
8270Sstevel@tonic-gate 	case AC_PROC_ZONENAME:
8280Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_zonename,
8290Sstevel@tonic-gate 		    strlen(pu->pu_zonename) + 1,
8300Sstevel@tonic-gate 		    EXT_STRING | EXD_PROC_ZONENAME);
8310Sstevel@tonic-gate 		break;
8320Sstevel@tonic-gate 	case AC_PROC_MEM:
8330Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_mem_rss_avg,
8340Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K);
8350Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_mem_rss_max,
8360Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K);
8370Sstevel@tonic-gate 		break;
8380Sstevel@tonic-gate 	default:
8390Sstevel@tonic-gate 		attached = 0;
8400Sstevel@tonic-gate 	}
8410Sstevel@tonic-gate 	return (attached);
8420Sstevel@tonic-gate }
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate static ea_object_t *
8450Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask,
8460Sstevel@tonic-gate     ea_catalog_t record_type)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate 	int res, count;
8490Sstevel@tonic-gate 	ea_object_t *record;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	/*
8520Sstevel@tonic-gate 	 * Assemble usage values into group.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
8550Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++)
8560Sstevel@tonic-gate 		if (BT_TEST(mask, res))
8574584Srh87107 			count += exacct_attach_proc_item(pu, record, res);
8580Sstevel@tonic-gate 	if (count == 0) {
8590Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
8600Sstevel@tonic-gate 		record = NULL;
8610Sstevel@tonic-gate 	}
8620Sstevel@tonic-gate 	return (record);
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate  * The following two routines assume that process's p_lock is held or
8670Sstevel@tonic-gate  * exacct_commit_proc has been called from exit() when all lwps are stopped.
8680Sstevel@tonic-gate  */
8690Sstevel@tonic-gate static void
8700Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu)
8710Sstevel@tonic-gate {
8720Sstevel@tonic-gate 	kthread_t *t;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8750Sstevel@tonic-gate 	if ((t = p->p_tlist) == NULL)
8760Sstevel@tonic-gate 		return;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	do {
8790Sstevel@tonic-gate 		pu->pu_minflt	+= t->t_lwp->lwp_ru.minflt;
8800Sstevel@tonic-gate 		pu->pu_majflt	+= t->t_lwp->lwp_ru.majflt;
8810Sstevel@tonic-gate 		pu->pu_sndmsg	+= t->t_lwp->lwp_ru.msgsnd;
8820Sstevel@tonic-gate 		pu->pu_rcvmsg	+= t->t_lwp->lwp_ru.msgrcv;
8830Sstevel@tonic-gate 		pu->pu_ioch	+= t->t_lwp->lwp_ru.ioch;
8840Sstevel@tonic-gate 		pu->pu_iblk	+= t->t_lwp->lwp_ru.inblock;
8850Sstevel@tonic-gate 		pu->pu_oblk	+= t->t_lwp->lwp_ru.oublock;
8860Sstevel@tonic-gate 		pu->pu_vcsw	+= t->t_lwp->lwp_ru.nvcsw;
8870Sstevel@tonic-gate 		pu->pu_icsw	+= t->t_lwp->lwp_ru.nivcsw;
8880Sstevel@tonic-gate 		pu->pu_nsig	+= t->t_lwp->lwp_ru.nsignals;
8890Sstevel@tonic-gate 		pu->pu_nswp	+= t->t_lwp->lwp_ru.nswap;
8900Sstevel@tonic-gate 		pu->pu_nscl	+= t->t_lwp->lwp_ru.sysc;
8910Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate static void
8950Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate 	pu->pu_minflt	= p->p_ru.minflt;
8980Sstevel@tonic-gate 	pu->pu_majflt	= p->p_ru.majflt;
8990Sstevel@tonic-gate 	pu->pu_sndmsg	= p->p_ru.msgsnd;
9000Sstevel@tonic-gate 	pu->pu_rcvmsg	= p->p_ru.msgrcv;
9010Sstevel@tonic-gate 	pu->pu_ioch	= p->p_ru.ioch;
9020Sstevel@tonic-gate 	pu->pu_iblk	= p->p_ru.inblock;
9030Sstevel@tonic-gate 	pu->pu_oblk	= p->p_ru.oublock;
9040Sstevel@tonic-gate 	pu->pu_vcsw	= p->p_ru.nvcsw;
9050Sstevel@tonic-gate 	pu->pu_icsw	= p->p_ru.nivcsw;
9060Sstevel@tonic-gate 	pu->pu_nsig	= p->p_ru.nsignals;
9070Sstevel@tonic-gate 	pu->pu_nswp	= p->p_ru.nswap;
9080Sstevel@tonic-gate 	pu->pu_nscl	= p->p_ru.sysc;
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate void
9120Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask,
9130Sstevel@tonic-gate     int flag, int wstat)
9140Sstevel@tonic-gate {
9150Sstevel@tonic-gate 	timestruc_t ts, ts_run;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	/*
9200Sstevel@tonic-gate 	 * Convert CPU and execution times to sec/nsec format.
9210Sstevel@tonic-gate 	 */
9220Sstevel@tonic-gate 	if (BT_TEST(mask, AC_PROC_CPU)) {
9230Sstevel@tonic-gate 		hrt2ts(mstate_aggr_state(p, LMS_USER), &ts);
9240Sstevel@tonic-gate 		pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec;
9250Sstevel@tonic-gate 		pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9260Sstevel@tonic-gate 		hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts);
9270Sstevel@tonic-gate 		pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec;
9280Sstevel@tonic-gate 		pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec;
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 	if (BT_TEST(mask, AC_PROC_TIME)) {
9310Sstevel@tonic-gate 		gethrestime(&ts);
9320Sstevel@tonic-gate 		pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
9330Sstevel@tonic-gate 		pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9340Sstevel@tonic-gate 		hrt2ts(gethrtime() - p->p_mstart, &ts_run);
9350Sstevel@tonic-gate 		ts.tv_sec -= ts_run.tv_sec;
9360Sstevel@tonic-gate 		ts.tv_nsec -= ts_run.tv_nsec;
9370Sstevel@tonic-gate 		if (ts.tv_nsec < 0) {
9380Sstevel@tonic-gate 			ts.tv_sec--;
9390Sstevel@tonic-gate 			if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) {
9400Sstevel@tonic-gate 				ts.tv_sec++;
9410Sstevel@tonic-gate 				ts.tv_nsec -= NANOSEC;
9420Sstevel@tonic-gate 			}
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 		pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec;
9450Sstevel@tonic-gate 		pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec;
9460Sstevel@tonic-gate 	}
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	pu->pu_pid = p->p_pidp->pid_id;
9490Sstevel@tonic-gate 	pu->pu_acflag = p->p_user.u_acflag;
9500Sstevel@tonic-gate 	pu->pu_projid = p->p_task->tk_proj->kpj_id;
9510Sstevel@tonic-gate 	pu->pu_taskid = p->p_task->tk_tkid;
9520Sstevel@tonic-gate 	pu->pu_major = getmajor(p->p_sessp->s_dev);
9530Sstevel@tonic-gate 	pu->pu_minor = getminor(p->p_sessp->s_dev);
9540Sstevel@tonic-gate 	pu->pu_ancpid = p->p_ancpid;
9550Sstevel@tonic-gate 	pu->pu_wstat = wstat;
9560Sstevel@tonic-gate 	/*
9570Sstevel@tonic-gate 	 * Compute average RSS in K.  The denominator is the number of
9580Sstevel@tonic-gate 	 * samples:  the number of clock ticks plus the initial value.
9590Sstevel@tonic-gate 	 */
9600Sstevel@tonic-gate 	pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) *
9610Sstevel@tonic-gate 	    (PAGESIZE / 1024);
9620Sstevel@tonic-gate 	pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024);
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
9650Sstevel@tonic-gate 	pu->pu_ruid = crgetruid(p->p_cred);
9660Sstevel@tonic-gate 	pu->pu_rgid = crgetrgid(p->p_cred);
9670Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1);
9700Sstevel@tonic-gate 	bcopy(p->p_zone->zone_name, pu->pu_zonename,
9710Sstevel@tonic-gate 	    strlen(p->p_zone->zone_name) + 1);
9720Sstevel@tonic-gate 	bcopy(p->p_zone->zone_nodename, pu->pu_nodename,
9730Sstevel@tonic-gate 	    strlen(p->p_zone->zone_nodename) + 1);
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	/*
9760Sstevel@tonic-gate 	 * Calculate microstate accounting data for a process that is still
9770Sstevel@tonic-gate 	 * running.  Presently, we explicitly collect all of the LWP usage into
9780Sstevel@tonic-gate 	 * the proc usage structure here.
9790Sstevel@tonic-gate 	 */
9800Sstevel@tonic-gate 	if (flag & EW_PARTIAL)
9810Sstevel@tonic-gate 		exacct_calculate_proc_mstate(p, pu);
9820Sstevel@tonic-gate 	if (flag & EW_FINAL)
9830Sstevel@tonic-gate 		exacct_copy_proc_mstate(p, pu);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate  * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void
9880Sstevel@tonic-gate  *	*, size_t, size_t *), void *, size_t, size_t *)
9890Sstevel@tonic-gate  *
9900Sstevel@tonic-gate  * Overview
9910Sstevel@tonic-gate  *   Assemble record with miscellaneous accounting information about the process
9920Sstevel@tonic-gate  *   and execute the callback on it. It is the callback's job to set "actual" to
9930Sstevel@tonic-gate  *   the size of record.
9940Sstevel@tonic-gate  *
9950Sstevel@tonic-gate  * Return values
9960Sstevel@tonic-gate  *   The result of the callback function, unless the extended process accounting
9970Sstevel@tonic-gate  *   feature is not active, in which case ENOTACTIVE is returned.
9980Sstevel@tonic-gate  *
9990Sstevel@tonic-gate  * Caller's context
10000Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
10010Sstevel@tonic-gate  */
10020Sstevel@tonic-gate int
10030Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu,
10040Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
10050Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual, int flag)
10060Sstevel@tonic-gate {
10070Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
10080Sstevel@tonic-gate 	ea_object_t *proc_record;
10090Sstevel@tonic-gate 	ea_catalog_t record_type;
10100Sstevel@tonic-gate 	void *buf;
10110Sstevel@tonic-gate 	size_t bufsize;
10120Sstevel@tonic-gate 	int ret;
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
10170Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_OFF) {
10180Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
10190Sstevel@tonic-gate 		return (ENOTACTIVE);
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 	bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
10220Sstevel@tonic-gate 	mutex_exit(&ac_proc->ac_lock);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	switch (flag) {
10250Sstevel@tonic-gate 	case EW_FINAL:
10260Sstevel@tonic-gate 		record_type = EXD_GROUP_PROC;
10270Sstevel@tonic-gate 		break;
10280Sstevel@tonic-gate 	case EW_PARTIAL:
10290Sstevel@tonic-gate 		record_type = EXD_GROUP_PROC_PARTIAL;
10300Sstevel@tonic-gate 		break;
10310Sstevel@tonic-gate 	}
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	proc_record = exacct_assemble_proc_record(pu, mask, record_type);
10340Sstevel@tonic-gate 	if (proc_record == NULL)
10350Sstevel@tonic-gate 		return (0);
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	/*
10380Sstevel@tonic-gate 	 * Pack object into buffer and pass to callback.
10390Sstevel@tonic-gate 	 */
10400Sstevel@tonic-gate 	bufsize = ea_pack_object(proc_record, NULL, 0);
10410Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
10420Sstevel@tonic-gate 	(void) ea_pack_object(proc_record, buf, bufsize);
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	/*
10470Sstevel@tonic-gate 	 * Free all previously allocations.
10480Sstevel@tonic-gate 	 */
10490Sstevel@tonic-gate 	kmem_free(buf, bufsize);
10500Sstevel@tonic-gate 	ea_free_object(proc_record, EUP_ALLOC);
10510Sstevel@tonic-gate 	return (ret);
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate /*
10550Sstevel@tonic-gate  * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t,
10560Sstevel@tonic-gate  * 	size_t *)
10570Sstevel@tonic-gate  *
10580Sstevel@tonic-gate  * Overview
10590Sstevel@tonic-gate  *   exacct_commit_callback() writes the indicated buffer to the indicated
10600Sstevel@tonic-gate  *   extended accounting file.
10610Sstevel@tonic-gate  *
10620Sstevel@tonic-gate  * Return values
10630Sstevel@tonic-gate  *   The result of the write operation is returned.  "actual" is updated to
10640Sstevel@tonic-gate  *   contain the number of bytes actually written.
10650Sstevel@tonic-gate  *
10660Sstevel@tonic-gate  * Caller's context
10670Sstevel@tonic-gate  *   Suitable for a vn_rdwr() operation.
10680Sstevel@tonic-gate  */
10690Sstevel@tonic-gate /*ARGSUSED*/
10700Sstevel@tonic-gate int
10710Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize,
10720Sstevel@tonic-gate     void *buf, size_t bufsize, size_t *actual)
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate 	int error = 0;
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	*actual = 0;
10770Sstevel@tonic-gate 	if ((error = exacct_vn_write(info, buf, bufsize)) == 0)
10780Sstevel@tonic-gate 		*actual = bufsize;
10790Sstevel@tonic-gate 	return (error);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate static void
10830Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat)
10840Sstevel@tonic-gate {
10850Sstevel@tonic-gate 	size_t size;
10860Sstevel@tonic-gate 	proc_usage_t *pu;
10870Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
10900Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_ON) {
10910Sstevel@tonic-gate 		bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
10920Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
10930Sstevel@tonic-gate 	} else {
10940Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
10950Sstevel@tonic-gate 		return;
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
10990Sstevel@tonic-gate 	size = strlen(p->p_user.u_comm) + 1;
11000Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP);
11030Sstevel@tonic-gate 	pu->pu_command = kmem_alloc(size, KM_SLEEP);
11040Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
11050Sstevel@tonic-gate 	exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat);
11060Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 	(void) exacct_assemble_proc_usage(ac_proc, pu,
11090Sstevel@tonic-gate 	    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	kmem_free(pu->pu_command, strlen(pu->pu_command) + 1);
11120Sstevel@tonic-gate 	kmem_free(pu, sizeof (proc_usage_t));
11130Sstevel@tonic-gate }
11144584Srh87107 
11150Sstevel@tonic-gate /*
11160Sstevel@tonic-gate  * void exacct_commit_proc(proc_t *, int)
11170Sstevel@tonic-gate  *
11180Sstevel@tonic-gate  * Overview
11190Sstevel@tonic-gate  *   exacct_commit_proc() calculates the final usage for a process, updating the
11200Sstevel@tonic-gate  *   task usage if task accounting is active, and writing a process record if
11210Sstevel@tonic-gate  *   process accounting is active.  exacct_commit_proc() is intended for being
11220Sstevel@tonic-gate  *   called from proc_exit().
11230Sstevel@tonic-gate  *
11240Sstevel@tonic-gate  * Return values
11250Sstevel@tonic-gate  *   None.
11260Sstevel@tonic-gate  *
11270Sstevel@tonic-gate  * Caller's context
11280Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.  p_lock must not be held at entry.
11290Sstevel@tonic-gate  */
11300Sstevel@tonic-gate void
11310Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate 	zone_t *zone = p->p_zone;
11340Sstevel@tonic-gate 	struct exacct_globals *acg, *gacg = NULL;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
11370Sstevel@tonic-gate 		/*
11380Sstevel@tonic-gate 		 * acctctl module not loaded.  Nothing to do.
11390Sstevel@tonic-gate 		 */
11400Sstevel@tonic-gate 		return;
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 	acg = zone_getspecific(exacct_zone_key, zone);
11434584Srh87107 	exacct_do_commit_proc(&acg->ac_proc, p, wstat);
11444584Srh87107 	if (zone != global_zone) {
11450Sstevel@tonic-gate 		gacg = zone_getspecific(exacct_zone_key, global_zone);
11464584Srh87107 		exacct_do_commit_proc(&gacg->ac_proc, p, wstat);
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate }
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate static int
11510Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res)
11520Sstevel@tonic-gate {
11530Sstevel@tonic-gate 	int attached = 1;
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	switch (res) {
11560Sstevel@tonic-gate 	case AC_FLOW_SADDR:
11570Sstevel@tonic-gate 		if (fu->fu_isv4) {
11580Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_saddr[3],
11590Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR);
11600Sstevel@tonic-gate 		} else {
11610Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_saddr,
11620Sstevel@tonic-gate 			    sizeof (fu->fu_saddr), EXT_RAW |
11630Sstevel@tonic-gate 			    EXD_FLOW_V6SADDR);
11640Sstevel@tonic-gate 		}
11650Sstevel@tonic-gate 		break;
11660Sstevel@tonic-gate 	case AC_FLOW_DADDR:
11670Sstevel@tonic-gate 		if (fu->fu_isv4) {
11680Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_daddr[3],
11690Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR);
11700Sstevel@tonic-gate 		} else {
11710Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_daddr,
11720Sstevel@tonic-gate 			    sizeof (fu->fu_daddr), EXT_RAW |
11730Sstevel@tonic-gate 			    EXD_FLOW_V6DADDR);
11740Sstevel@tonic-gate 		}
11750Sstevel@tonic-gate 		break;
11760Sstevel@tonic-gate 	case AC_FLOW_SPORT:
11770Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_sport,
11780Sstevel@tonic-gate 		    sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT);
11790Sstevel@tonic-gate 		break;
11800Sstevel@tonic-gate 	case AC_FLOW_DPORT:
11810Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_dport,
11820Sstevel@tonic-gate 		    sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT);
11830Sstevel@tonic-gate 		break;
11840Sstevel@tonic-gate 	case AC_FLOW_PROTOCOL:
11850Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_protocol,
11860Sstevel@tonic-gate 		    sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL);
11870Sstevel@tonic-gate 		break;
11880Sstevel@tonic-gate 	case AC_FLOW_DSFIELD:
11890Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_dsfield,
11900Sstevel@tonic-gate 		    sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD);
11910Sstevel@tonic-gate 		break;
11920Sstevel@tonic-gate 	case AC_FLOW_CTIME:
11930Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_ctime,
11940Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME);
11950Sstevel@tonic-gate 		break;
11960Sstevel@tonic-gate 	case AC_FLOW_LSEEN:
11970Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_lseen,
11980Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN);
11990Sstevel@tonic-gate 		break;
12000Sstevel@tonic-gate 	case AC_FLOW_NBYTES:
12010Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_nbytes,
12020Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES);
12030Sstevel@tonic-gate 		break;
12040Sstevel@tonic-gate 	case AC_FLOW_NPKTS:
12050Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_npackets,
12060Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS);
12070Sstevel@tonic-gate 		break;
12080Sstevel@tonic-gate 	case AC_FLOW_PROJID:
12090Sstevel@tonic-gate 		if (fu->fu_projid >= 0) {
12100Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_projid,
12110Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID);
12120Sstevel@tonic-gate 		}
12130Sstevel@tonic-gate 		break;
12140Sstevel@tonic-gate 	case AC_FLOW_UID:
12150Sstevel@tonic-gate 		if (fu->fu_userid >= 0) {
12160Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_userid,
12170Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID);
12180Sstevel@tonic-gate 		}
12190Sstevel@tonic-gate 		break;
12200Sstevel@tonic-gate 	case AC_FLOW_ANAME:
12210Sstevel@tonic-gate 		(void) ea_attach_item(record, fu->fu_aname,
12220Sstevel@tonic-gate 		    strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME);
12230Sstevel@tonic-gate 		break;
12240Sstevel@tonic-gate 	default:
12250Sstevel@tonic-gate 		attached = 0;
12260Sstevel@tonic-gate 	}
12270Sstevel@tonic-gate 	return (attached);
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate static ea_object_t *
12310Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask,
12320Sstevel@tonic-gate     ea_catalog_t record_type)
12330Sstevel@tonic-gate {
12340Sstevel@tonic-gate 	int res, count;
12350Sstevel@tonic-gate 	ea_object_t *record;
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	/*
12380Sstevel@tonic-gate 	 * Assemble usage values into group.
12390Sstevel@tonic-gate 	 */
12400Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
12410Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++)
12420Sstevel@tonic-gate 		if (BT_TEST(mask, res))
12430Sstevel@tonic-gate 			count += exacct_attach_flow_item(fu, record, res);
12440Sstevel@tonic-gate 	if (count == 0) {
12450Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
12460Sstevel@tonic-gate 		record = NULL;
12470Sstevel@tonic-gate 	}
12480Sstevel@tonic-gate 	return (record);
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate int
12520Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu,
12530Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
12540Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual)
12550Sstevel@tonic-gate {
12560Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
12570Sstevel@tonic-gate 	ea_object_t *flow_usage;
12580Sstevel@tonic-gate 	ea_catalog_t record_type;
12590Sstevel@tonic-gate 	void *buf;
12600Sstevel@tonic-gate 	size_t bufsize;
12610Sstevel@tonic-gate 	int ret;
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	mutex_enter(&ac_flow->ac_lock);
12640Sstevel@tonic-gate 	if (ac_flow->ac_state == AC_OFF) {
12650Sstevel@tonic-gate 		mutex_exit(&ac_flow->ac_lock);
12660Sstevel@tonic-gate 		return (ENOTACTIVE);
12670Sstevel@tonic-gate 	}
12680Sstevel@tonic-gate 	bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
12690Sstevel@tonic-gate 	mutex_exit(&ac_flow->ac_lock);
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 	record_type = EXD_GROUP_FLOW;
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	flow_usage = exacct_assemble_flow_record(fu, mask, record_type);
12740Sstevel@tonic-gate 	if (flow_usage == NULL) {
12750Sstevel@tonic-gate 		return (0);
12760Sstevel@tonic-gate 	}
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	/*
12790Sstevel@tonic-gate 	 * Pack object into buffer and pass to callback.
12800Sstevel@tonic-gate 	 */
12810Sstevel@tonic-gate 	bufsize = ea_pack_object(flow_usage, NULL, 0);
12820Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_NOSLEEP);
12830Sstevel@tonic-gate 	if (buf == NULL) {
12840Sstevel@tonic-gate 		return (ENOMEM);
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	(void) ea_pack_object(flow_usage, buf, bufsize);
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual);
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	/*
12920Sstevel@tonic-gate 	 * Free all previously allocations.
12930Sstevel@tonic-gate 	 */
12940Sstevel@tonic-gate 	kmem_free(buf, bufsize);
12950Sstevel@tonic-gate 	ea_free_object(flow_usage, EUP_ALLOC);
12960Sstevel@tonic-gate 	return (ret);
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate void
13000Sstevel@tonic-gate exacct_commit_flow(void *arg)
13010Sstevel@tonic-gate {
13020Sstevel@tonic-gate 	flow_usage_t *f = (flow_usage_t *)arg;
13030Sstevel@tonic-gate 	size_t size;
13040Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
13050Sstevel@tonic-gate 	struct exacct_globals *acg;
13060Sstevel@tonic-gate 	ac_info_t *ac_flow;
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
13090Sstevel@tonic-gate 		/*
13100Sstevel@tonic-gate 		 * acctctl module not loaded. Nothing to do.
13110Sstevel@tonic-gate 		 */
13120Sstevel@tonic-gate 		return;
13130Sstevel@tonic-gate 	}
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	/*
13160Sstevel@tonic-gate 	 * Even though each zone nominally has its own flow accounting settings
13170Sstevel@tonic-gate 	 * (ac_flow), these are only maintained by and for the global zone.
13180Sstevel@tonic-gate 	 *
13190Sstevel@tonic-gate 	 * If this were to change in the future, this function should grow a
13200Sstevel@tonic-gate 	 * second zoneid (or zone) argument, and use the corresponding zone's
13210Sstevel@tonic-gate 	 * settings rather than always using those of the global zone.
13220Sstevel@tonic-gate 	 */
13230Sstevel@tonic-gate 	acg = zone_getspecific(exacct_zone_key, global_zone);
13240Sstevel@tonic-gate 	ac_flow = &acg->ac_flow;
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	mutex_enter(&ac_flow->ac_lock);
13270Sstevel@tonic-gate 	if (ac_flow->ac_state == AC_OFF) {
13280Sstevel@tonic-gate 		mutex_exit(&ac_flow->ac_lock);
13290Sstevel@tonic-gate 		return;
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate 	bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
13320Sstevel@tonic-gate 	mutex_exit(&ac_flow->ac_lock);
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	(void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback,
13350Sstevel@tonic-gate 	    NULL, 0, &size);
13360Sstevel@tonic-gate }
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate /*
13390Sstevel@tonic-gate  * int exacct_tag_task(task_t *, void *, size_t, int)
13400Sstevel@tonic-gate  *
13410Sstevel@tonic-gate  * Overview
13420Sstevel@tonic-gate  *   exacct_tag_task() provides the exacct record construction and writing
13430Sstevel@tonic-gate  *   support required by putacct(2) for task entities.
13440Sstevel@tonic-gate  *
13450Sstevel@tonic-gate  * Return values
13460Sstevel@tonic-gate  *   The result of the write operation is returned, unless the extended
13470Sstevel@tonic-gate  *   accounting facility is not active, in which case ENOTACTIVE is returned.
13480Sstevel@tonic-gate  *
13490Sstevel@tonic-gate  * Caller's context
13500Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
13510Sstevel@tonic-gate  */
13520Sstevel@tonic-gate int
13530Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz,
13540Sstevel@tonic-gate     int flags)
13550Sstevel@tonic-gate {
13560Sstevel@tonic-gate 	int error = 0;
13570Sstevel@tonic-gate 	void *buf;
13580Sstevel@tonic-gate 	size_t bufsize;
13590Sstevel@tonic-gate 	ea_catalog_t cat;
13600Sstevel@tonic-gate 	ea_object_t *tag;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	mutex_enter(&ac_task->ac_lock);
13630Sstevel@tonic-gate 	if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) {
13640Sstevel@tonic-gate 		mutex_exit(&ac_task->ac_lock);
13650Sstevel@tonic-gate 		return (ENOTACTIVE);
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 	mutex_exit(&ac_task->ac_lock);
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG);
13700Sstevel@tonic-gate 	(void) ea_attach_item(tag, &tk->tk_tkid, 0,
13710Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
13720Sstevel@tonic-gate 	(void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0,
13730Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
13740Sstevel@tonic-gate 	if (flags == EP_RAW)
13750Sstevel@tonic-gate 		cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG;
13760Sstevel@tonic-gate 	else
13770Sstevel@tonic-gate 		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG;
13780Sstevel@tonic-gate 	(void) ea_attach_item(tag, ubuf, ubufsz, cat);
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	bufsize = ea_pack_object(tag, NULL, 0);
13810Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
13820Sstevel@tonic-gate 	(void) ea_pack_object(tag, buf, bufsize);
13830Sstevel@tonic-gate 	error = exacct_vn_write(ac_task, buf, bufsize);
13840Sstevel@tonic-gate 	kmem_free(buf, bufsize);
13850Sstevel@tonic-gate 	ea_free_object(tag, EUP_ALLOC);
13860Sstevel@tonic-gate 	return (error);
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate /*
13900Sstevel@tonic-gate  * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *)
13910Sstevel@tonic-gate  *
13920Sstevel@tonic-gate  * Overview
13930Sstevel@tonic-gate  *   exacct_tag_proc() provides the exacct record construction and writing
13940Sstevel@tonic-gate  *   support required by putacct(2) for processes.
13950Sstevel@tonic-gate  *
13960Sstevel@tonic-gate  * Return values
13970Sstevel@tonic-gate  *   The result of the write operation is returned, unless the extended
13980Sstevel@tonic-gate  *   accounting facility is not active, in which case ENOTACTIVE is returned.
13990Sstevel@tonic-gate  *
14000Sstevel@tonic-gate  * Caller's context
14010Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
14020Sstevel@tonic-gate  */
14030Sstevel@tonic-gate int
14040Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf,
14050Sstevel@tonic-gate     size_t ubufsz, int flags, const char *hostname)
14060Sstevel@tonic-gate {
14070Sstevel@tonic-gate 	int error = 0;
14080Sstevel@tonic-gate 	void *buf;
14090Sstevel@tonic-gate 	size_t bufsize;
14100Sstevel@tonic-gate 	ea_catalog_t cat;
14110Sstevel@tonic-gate 	ea_object_t *tag;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
14140Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) {
14150Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
14160Sstevel@tonic-gate 		return (ENOTACTIVE);
14170Sstevel@tonic-gate 	}
14180Sstevel@tonic-gate 	mutex_exit(&ac_proc->ac_lock);
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG);
14210Sstevel@tonic-gate 	(void) ea_attach_item(tag, &pid, sizeof (uint32_t),
14220Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID);
14230Sstevel@tonic-gate 	(void) ea_attach_item(tag, &tkid, 0,
14240Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
14250Sstevel@tonic-gate 	(void) ea_attach_item(tag, (void *)hostname, 0,
14260Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
14270Sstevel@tonic-gate 	if (flags == EP_RAW)
14280Sstevel@tonic-gate 		cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG;
14290Sstevel@tonic-gate 	else
14300Sstevel@tonic-gate 		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG;
14310Sstevel@tonic-gate 	(void) ea_attach_item(tag, ubuf, ubufsz, cat);
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	bufsize = ea_pack_object(tag, NULL, 0);
14340Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
14350Sstevel@tonic-gate 	(void) ea_pack_object(tag, buf, bufsize);
14360Sstevel@tonic-gate 	error = exacct_vn_write(ac_proc, buf, bufsize);
14370Sstevel@tonic-gate 	kmem_free(buf, bufsize);
14380Sstevel@tonic-gate 	ea_free_object(tag, EUP_ALLOC);
14390Sstevel@tonic-gate 	return (error);
14400Sstevel@tonic-gate }
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate /*
14430Sstevel@tonic-gate  * void exacct_init(void)
14440Sstevel@tonic-gate  *
14450Sstevel@tonic-gate  * Overview
14460Sstevel@tonic-gate  *   Initialized the extended accounting subsystem.
14470Sstevel@tonic-gate  *
14480Sstevel@tonic-gate  * Return values
14490Sstevel@tonic-gate  *   None.
14500Sstevel@tonic-gate  *
14510Sstevel@tonic-gate  * Caller's context
14520Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
14530Sstevel@tonic-gate  */
14540Sstevel@tonic-gate void
14550Sstevel@tonic-gate exacct_init()
14560Sstevel@tonic-gate {
14570Sstevel@tonic-gate 	exacct_queue = system_taskq;
14580Sstevel@tonic-gate 	exacct_object_cache = kmem_cache_create("exacct_object_cache",
14590Sstevel@tonic-gate 	    sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
14600Sstevel@tonic-gate }
14614584Srh87107 
14624584Srh87107 /*
14634584Srh87107  * exacct_snapshot_proc_mstate() copies a process's microstate accounting data
14644584Srh87107  * and resource usage counters into a given task_usage_t. It differs from
14654584Srh87107  * exacct_copy_proc_mstate() in that here a) we are copying to a task_usage_t,
14664584Srh87107  * b) p_lock will have been acquired earlier in the call path and c) we
14674584Srh87107  * are here including the process's user and system times.
14684584Srh87107  */
14694584Srh87107 static void
14704584Srh87107 exacct_snapshot_proc_mstate(proc_t *p, task_usage_t *tu)
14714584Srh87107 {
14724584Srh87107 	tu->tu_utime  = mstate_aggr_state(p, LMS_USER);
14734584Srh87107 	tu->tu_stime  = mstate_aggr_state(p, LMS_SYSTEM);
14744584Srh87107 	tu->tu_minflt = p->p_ru.minflt;
14754584Srh87107 	tu->tu_majflt = p->p_ru.majflt;
14764584Srh87107 	tu->tu_sndmsg = p->p_ru.msgsnd;
14774584Srh87107 	tu->tu_rcvmsg = p->p_ru.msgrcv;
14784584Srh87107 	tu->tu_ioch   = p->p_ru.ioch;
14794584Srh87107 	tu->tu_iblk   = p->p_ru.inblock;
14804584Srh87107 	tu->tu_oblk   = p->p_ru.oublock;
14814584Srh87107 	tu->tu_vcsw   = p->p_ru.nvcsw;
14824584Srh87107 	tu->tu_icsw   = p->p_ru.nivcsw;
14834584Srh87107 	tu->tu_nsig   = p->p_ru.nsignals;
14844584Srh87107 	tu->tu_nswp   = p->p_ru.nswap;
14854584Srh87107 	tu->tu_nscl   = p->p_ru.sysc;
14864584Srh87107 }
14874584Srh87107 
14884584Srh87107 /*
14894584Srh87107  * void exacct_move_mstate(proc_t *, task_t *, task_t *)
14904584Srh87107  *
14914584Srh87107  * Overview
14924584Srh87107  *   exacct_move_mstate() is called by task_change() and accounts for
14934584Srh87107  *   a process's resource usage when it is moved from one task to another.
14944584Srh87107  *
14954584Srh87107  *   The process's usage at this point is recorded in the new task so
14964584Srh87107  *   that it can be excluded from the calculation of resources consumed
14974584Srh87107  *   by that task.
14984584Srh87107  *
14994584Srh87107  *   The resource usage inherited by the new task is also added to the
15004584Srh87107  *   aggregate maintained by the old task for processes that have exited.
15014584Srh87107  *
15024584Srh87107  * Return values
15034584Srh87107  *   None.
15044584Srh87107  *
15054584Srh87107  * Caller's context
15064584Srh87107  *   pidlock and p_lock held across exacct_move_mstate().
15074584Srh87107  */
15084584Srh87107 void
15094584Srh87107 exacct_move_mstate(proc_t *p, task_t *oldtk, task_t *newtk)
15104584Srh87107 {
15114584Srh87107 	task_usage_t tu;
15124584Srh87107 
15134584Srh87107 	/* Take a snapshot of this process's mstate and RU counters */
15144584Srh87107 	exacct_snapshot_proc_mstate(p, &tu);
15154584Srh87107 
15164584Srh87107 	/*
15174584Srh87107 	 * Use the snapshot to increment the aggregate usage of the old
15184584Srh87107 	 * task, and the inherited usage of the new one.
15194584Srh87107 	 */
15204584Srh87107 	mutex_enter(&oldtk->tk_usage_lock);
15214584Srh87107 	exacct_add_task_mstate(oldtk->tk_usage, &tu);
15224584Srh87107 	mutex_exit(&oldtk->tk_usage_lock);
15234584Srh87107 	mutex_enter(&newtk->tk_usage_lock);
15244584Srh87107 	exacct_add_task_mstate(newtk->tk_inherited, &tu);
15254584Srh87107 	mutex_exit(&newtk->tk_usage_lock);
15264584Srh87107 }
1527