xref: /titanic_53/usr/src/uts/common/os/exacct.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/exacct.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/exacct_catalog.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/disp.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/task.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/project.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/acctctl.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/session.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/msacct.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * exacct usage and recording routines
50*7c478bd9Sstevel@tonic-gate  *
51*7c478bd9Sstevel@tonic-gate  * wracct(2), getacct(2), and the records written at process or task
52*7c478bd9Sstevel@tonic-gate  * termination are constructed using the exacct_assemble_[task,proc]_usage()
53*7c478bd9Sstevel@tonic-gate  * functions, which take a callback that takes the appropriate action on
54*7c478bd9Sstevel@tonic-gate  * the packed exacct record for the task or process.  For the process-related
55*7c478bd9Sstevel@tonic-gate  * actions, we partition the routines such that the data collecting component
56*7c478bd9Sstevel@tonic-gate  * can be performed while holding p_lock, and all sleeping or blocking
57*7c478bd9Sstevel@tonic-gate  * operations can be performed without acquiring p_lock.
58*7c478bd9Sstevel@tonic-gate  *
59*7c478bd9Sstevel@tonic-gate  * putacct(2), which allows an application to construct a customized record
60*7c478bd9Sstevel@tonic-gate  * associated with an existing process or task, has its own entry points:
61*7c478bd9Sstevel@tonic-gate  * exacct_tag_task() and exacct_tag_proc().
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate taskq_t *exacct_queue;
65*7c478bd9Sstevel@tonic-gate kmem_cache_t *exacct_object_cache;
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate zone_key_t exacct_zone_key = ZONE_KEY_UNINITIALIZED;
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static const uint32_t exacct_version = EXACCT_VERSION;
70*7c478bd9Sstevel@tonic-gate static const char exacct_header[] = "exacct";
71*7c478bd9Sstevel@tonic-gate static const char exacct_creator[] = "SunOS";
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate ea_object_t *
74*7c478bd9Sstevel@tonic-gate ea_alloc_item(ea_catalog_t catalog, void *buf, size_t bufsz)
75*7c478bd9Sstevel@tonic-gate {
76*7c478bd9Sstevel@tonic-gate 	ea_object_t *item;
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate 	item = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
79*7c478bd9Sstevel@tonic-gate 	bzero(item, sizeof (ea_object_t));
80*7c478bd9Sstevel@tonic-gate 	(void) ea_set_item(item, catalog, buf, bufsz);
81*7c478bd9Sstevel@tonic-gate 	return (item);
82*7c478bd9Sstevel@tonic-gate }
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate ea_object_t *
85*7c478bd9Sstevel@tonic-gate ea_alloc_group(ea_catalog_t catalog)
86*7c478bd9Sstevel@tonic-gate {
87*7c478bd9Sstevel@tonic-gate 	ea_object_t *group;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	group = kmem_cache_alloc(exacct_object_cache, KM_SLEEP);
90*7c478bd9Sstevel@tonic-gate 	bzero(group, sizeof (ea_object_t));
91*7c478bd9Sstevel@tonic-gate 	(void) ea_set_group(group, catalog);
92*7c478bd9Sstevel@tonic-gate 	return (group);
93*7c478bd9Sstevel@tonic-gate }
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate ea_object_t *
96*7c478bd9Sstevel@tonic-gate ea_attach_item(ea_object_t *grp, void *buf, size_t bufsz, ea_catalog_t catalog)
97*7c478bd9Sstevel@tonic-gate {
98*7c478bd9Sstevel@tonic-gate 	ea_object_t *item;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	item = ea_alloc_item(catalog, buf, bufsz);
101*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_to_group(grp, item);
102*7c478bd9Sstevel@tonic-gate 	return (item);
103*7c478bd9Sstevel@tonic-gate }
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * exacct_vn_write() is a vn_rdwr wrapper that protects us from corrupting the
107*7c478bd9Sstevel@tonic-gate  * accounting file in case of an I/O or filesystem error.  acctctl() prevents
108*7c478bd9Sstevel@tonic-gate  * the two accounting vnodes from being equal, and the appropriate ac_lock is
109*7c478bd9Sstevel@tonic-gate  * held across the call, so we're single threaded through this code for each
110*7c478bd9Sstevel@tonic-gate  * file.
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate static int
113*7c478bd9Sstevel@tonic-gate exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize)
114*7c478bd9Sstevel@tonic-gate {
115*7c478bd9Sstevel@tonic-gate 	int error = 0;
116*7c478bd9Sstevel@tonic-gate 	ssize_t resid;
117*7c478bd9Sstevel@tonic-gate 	struct vattr va;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	if (info == NULL)
120*7c478bd9Sstevel@tonic-gate 		return (0);
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	mutex_enter(&info->ac_lock);
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	/*
125*7c478bd9Sstevel@tonic-gate 	 * Don't do anything unless accounting file is set.
126*7c478bd9Sstevel@tonic-gate 	 */
127*7c478bd9Sstevel@tonic-gate 	if (info->ac_vnode == NULL) {
128*7c478bd9Sstevel@tonic-gate 		mutex_exit(&info->ac_lock);
129*7c478bd9Sstevel@tonic-gate 		return (0);
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	/*
133*7c478bd9Sstevel@tonic-gate 	 * Save the size. If vn_rdwr fails, reset the size to avoid corrupting
134*7c478bd9Sstevel@tonic-gate 	 * the present accounting file.
135*7c478bd9Sstevel@tonic-gate 	 */
136*7c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
137*7c478bd9Sstevel@tonic-gate 	error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred);
138*7c478bd9Sstevel@tonic-gate 	if (error == 0) {
139*7c478bd9Sstevel@tonic-gate 		error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf,
140*7c478bd9Sstevel@tonic-gate 		    bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T,
141*7c478bd9Sstevel@tonic-gate 		    kcred, &resid);
142*7c478bd9Sstevel@tonic-gate 		if (error) {
143*7c478bd9Sstevel@tonic-gate 			(void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
144*7c478bd9Sstevel@tonic-gate 		} else if (resid != 0) {
145*7c478bd9Sstevel@tonic-gate 			(void) VOP_SETATTR(info->ac_vnode, &va, 0, kcred, NULL);
146*7c478bd9Sstevel@tonic-gate 			error = ENOSPC;
147*7c478bd9Sstevel@tonic-gate 		}
148*7c478bd9Sstevel@tonic-gate 	}
149*7c478bd9Sstevel@tonic-gate 	mutex_exit(&info->ac_lock);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	return (error);
152*7c478bd9Sstevel@tonic-gate }
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate /*
155*7c478bd9Sstevel@tonic-gate  * void *exacct_create_header(size_t *)
156*7c478bd9Sstevel@tonic-gate  *
157*7c478bd9Sstevel@tonic-gate  * Overview
158*7c478bd9Sstevel@tonic-gate  *   exacct_create_header() constructs an exacct file header identifying the
159*7c478bd9Sstevel@tonic-gate  *   accounting file as the output of the kernel.  exacct_create_header() and
160*7c478bd9Sstevel@tonic-gate  *   the static write_header() and verify_header() routines in libexacct must
161*7c478bd9Sstevel@tonic-gate  *   remain synchronized.
162*7c478bd9Sstevel@tonic-gate  *
163*7c478bd9Sstevel@tonic-gate  * Return values
164*7c478bd9Sstevel@tonic-gate  *   A pointer to a packed exacct buffer containing the appropriate header is
165*7c478bd9Sstevel@tonic-gate  *   returned; the size of the buffer is placed in the location indicated by
166*7c478bd9Sstevel@tonic-gate  *   sizep.
167*7c478bd9Sstevel@tonic-gate  *
168*7c478bd9Sstevel@tonic-gate  * Caller's context
169*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
170*7c478bd9Sstevel@tonic-gate  */
171*7c478bd9Sstevel@tonic-gate void *
172*7c478bd9Sstevel@tonic-gate exacct_create_header(size_t *sizep)
173*7c478bd9Sstevel@tonic-gate {
174*7c478bd9Sstevel@tonic-gate 	ea_object_t *hdr_grp;
175*7c478bd9Sstevel@tonic-gate 	uint32_t bskip;
176*7c478bd9Sstevel@tonic-gate 	void *buf;
177*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER);
180*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0,
181*7c478bd9Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_VERSION);
182*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)exacct_header, 0,
183*7c478bd9Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_FILETYPE);
184*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0,
185*7c478bd9Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_CREATOR);
186*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(hdr_grp, uts_nodename(), 0,
187*7c478bd9Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	bufsize = ea_pack_object(hdr_grp, NULL, 0);
190*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
191*7c478bd9Sstevel@tonic-gate 	(void) ea_pack_object(hdr_grp, buf, bufsize);
192*7c478bd9Sstevel@tonic-gate 	ea_free_object(hdr_grp, EUP_ALLOC);
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	/*
195*7c478bd9Sstevel@tonic-gate 	 * To prevent reading the header when reading the file backwards,
196*7c478bd9Sstevel@tonic-gate 	 * set the large backskip of the header group to 0 (last 4 bytes).
197*7c478bd9Sstevel@tonic-gate 	 */
198*7c478bd9Sstevel@tonic-gate 	bskip = 0;
199*7c478bd9Sstevel@tonic-gate 	exacct_order32(&bskip);
200*7c478bd9Sstevel@tonic-gate 	bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip),
201*7c478bd9Sstevel@tonic-gate 	    sizeof (bskip));
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	*sizep = bufsize;
204*7c478bd9Sstevel@tonic-gate 	return (buf);
205*7c478bd9Sstevel@tonic-gate }
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate /*
208*7c478bd9Sstevel@tonic-gate  * int exacct_write_header(ac_info_t *, void *, size_t)
209*7c478bd9Sstevel@tonic-gate  *
210*7c478bd9Sstevel@tonic-gate  * Overview
211*7c478bd9Sstevel@tonic-gate  *   exacct_write_header() writes the given header buffer to the indicated
212*7c478bd9Sstevel@tonic-gate  *   vnode, and frees the buffer.
213*7c478bd9Sstevel@tonic-gate  *
214*7c478bd9Sstevel@tonic-gate  * Return values
215*7c478bd9Sstevel@tonic-gate  *   The result of the write operation is returned.
216*7c478bd9Sstevel@tonic-gate  *
217*7c478bd9Sstevel@tonic-gate  * Caller's context
218*7c478bd9Sstevel@tonic-gate  *   Caller must not hold the ac_lock of the appropriate accounting file
219*7c478bd9Sstevel@tonic-gate  *   information block (ac_info_t).
220*7c478bd9Sstevel@tonic-gate  */
221*7c478bd9Sstevel@tonic-gate int
222*7c478bd9Sstevel@tonic-gate exacct_write_header(ac_info_t *info, void *hdr, size_t hdrsize)
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 	int error;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	error = exacct_vn_write(info, hdr, hdrsize);
227*7c478bd9Sstevel@tonic-gate 	kmem_free(hdr, hdrsize);
228*7c478bd9Sstevel@tonic-gate 	return (error);
229*7c478bd9Sstevel@tonic-gate }
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate static void
232*7c478bd9Sstevel@tonic-gate exacct_get_interval_task_usage(task_t *tk, task_usage_t *tu,
233*7c478bd9Sstevel@tonic-gate     task_usage_t **tu_buf)
234*7c478bd9Sstevel@tonic-gate {
235*7c478bd9Sstevel@tonic-gate 	task_usage_t *oldtu, *newtu;
236*7c478bd9Sstevel@tonic-gate 	task_usage_t **prevusage;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&tk->tk_usage_lock));
239*7c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID) {
240*7c478bd9Sstevel@tonic-gate 		prevusage = &tk->tk_zoneusage;
241*7c478bd9Sstevel@tonic-gate 	} else {
242*7c478bd9Sstevel@tonic-gate 		prevusage = &tk->tk_prevusage;
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 	if ((oldtu = *prevusage) != NULL) {
245*7c478bd9Sstevel@tonic-gate 		/*
246*7c478bd9Sstevel@tonic-gate 		 * In case we have any accounting information
247*7c478bd9Sstevel@tonic-gate 		 * saved from the previous interval record.
248*7c478bd9Sstevel@tonic-gate 		 */
249*7c478bd9Sstevel@tonic-gate 		newtu = *tu_buf;
250*7c478bd9Sstevel@tonic-gate 		bcopy(tu, newtu, sizeof (task_usage_t));
251*7c478bd9Sstevel@tonic-gate 		tu->tu_minflt	-= oldtu->tu_minflt;
252*7c478bd9Sstevel@tonic-gate 		tu->tu_majflt	-= oldtu->tu_majflt;
253*7c478bd9Sstevel@tonic-gate 		tu->tu_sndmsg	-= oldtu->tu_sndmsg;
254*7c478bd9Sstevel@tonic-gate 		tu->tu_rcvmsg	-= oldtu->tu_rcvmsg;
255*7c478bd9Sstevel@tonic-gate 		tu->tu_ioch	-= oldtu->tu_ioch;
256*7c478bd9Sstevel@tonic-gate 		tu->tu_iblk	-= oldtu->tu_iblk;
257*7c478bd9Sstevel@tonic-gate 		tu->tu_oblk	-= oldtu->tu_oblk;
258*7c478bd9Sstevel@tonic-gate 		tu->tu_vcsw	-= oldtu->tu_vcsw;
259*7c478bd9Sstevel@tonic-gate 		tu->tu_icsw	-= oldtu->tu_icsw;
260*7c478bd9Sstevel@tonic-gate 		tu->tu_nsig	-= oldtu->tu_nsig;
261*7c478bd9Sstevel@tonic-gate 		tu->tu_nswp	-= oldtu->tu_nswp;
262*7c478bd9Sstevel@tonic-gate 		tu->tu_nscl	-= oldtu->tu_nscl;
263*7c478bd9Sstevel@tonic-gate 		tu->tu_utime	-= oldtu->tu_utime;
264*7c478bd9Sstevel@tonic-gate 		tu->tu_stime	-= oldtu->tu_stime;
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 		tu->tu_startsec = oldtu->tu_finishsec;
267*7c478bd9Sstevel@tonic-gate 		tu->tu_startnsec = oldtu->tu_finishnsec;
268*7c478bd9Sstevel@tonic-gate 		/*
269*7c478bd9Sstevel@tonic-gate 		 * Copy the data from our temporary storage to the task's
270*7c478bd9Sstevel@tonic-gate 		 * previous interval usage structure for future reference.
271*7c478bd9Sstevel@tonic-gate 		 */
272*7c478bd9Sstevel@tonic-gate 		bcopy(newtu, oldtu, sizeof (task_usage_t));
273*7c478bd9Sstevel@tonic-gate 	} else {
274*7c478bd9Sstevel@tonic-gate 		/*
275*7c478bd9Sstevel@tonic-gate 		 * Store current statistics in the task's previous interval
276*7c478bd9Sstevel@tonic-gate 		 * usage structure for future references.
277*7c478bd9Sstevel@tonic-gate 		 */
278*7c478bd9Sstevel@tonic-gate 		*prevusage = *tu_buf;
279*7c478bd9Sstevel@tonic-gate 		bcopy(tu, *prevusage, sizeof (task_usage_t));
280*7c478bd9Sstevel@tonic-gate 		*tu_buf = NULL;
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate }
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate static void
285*7c478bd9Sstevel@tonic-gate exacct_snapshot_task_usage(task_t *tk, task_usage_t *tu)
286*7c478bd9Sstevel@tonic-gate {
287*7c478bd9Sstevel@tonic-gate 	timestruc_t ts;
288*7c478bd9Sstevel@tonic-gate 	proc_t *p;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	if ((p = tk->tk_memb_list) == NULL)
293*7c478bd9Sstevel@tonic-gate 		return;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/*
296*7c478bd9Sstevel@tonic-gate 	 * exacct_snapshot_task_usage() provides an approximate snapshot of the
297*7c478bd9Sstevel@tonic-gate 	 * usage of the potentially many members of the task.  Since we don't
298*7c478bd9Sstevel@tonic-gate 	 * guarantee exactness, we don't acquire the p_lock of any of the member
299*7c478bd9Sstevel@tonic-gate 	 * processes.
300*7c478bd9Sstevel@tonic-gate 	 */
301*7c478bd9Sstevel@tonic-gate 	do {
302*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
303*7c478bd9Sstevel@tonic-gate 		tu->tu_utime	+= mstate_aggr_state(p, LMS_USER);
304*7c478bd9Sstevel@tonic-gate 		tu->tu_stime	+= mstate_aggr_state(p, LMS_SYSTEM);
305*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
306*7c478bd9Sstevel@tonic-gate 		tu->tu_minflt	+= p->p_ru.minflt;
307*7c478bd9Sstevel@tonic-gate 		tu->tu_majflt	+= p->p_ru.majflt;
308*7c478bd9Sstevel@tonic-gate 		tu->tu_sndmsg	+= p->p_ru.msgsnd;
309*7c478bd9Sstevel@tonic-gate 		tu->tu_rcvmsg	+= p->p_ru.msgrcv;
310*7c478bd9Sstevel@tonic-gate 		tu->tu_ioch	+= p->p_ru.ioch;
311*7c478bd9Sstevel@tonic-gate 		tu->tu_iblk	+= p->p_ru.inblock;
312*7c478bd9Sstevel@tonic-gate 		tu->tu_oblk	+= p->p_ru.oublock;
313*7c478bd9Sstevel@tonic-gate 		tu->tu_vcsw	+= p->p_ru.nvcsw;
314*7c478bd9Sstevel@tonic-gate 		tu->tu_icsw	+= p->p_ru.nivcsw;
315*7c478bd9Sstevel@tonic-gate 		tu->tu_nsig	+= p->p_ru.nsignals;
316*7c478bd9Sstevel@tonic-gate 		tu->tu_nswp	+= p->p_ru.nswap;
317*7c478bd9Sstevel@tonic-gate 		tu->tu_nscl	+= p->p_ru.sysc;
318*7c478bd9Sstevel@tonic-gate 	} while ((p = p->p_tasknext) != tk->tk_memb_list);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	gethrestime(&ts);
321*7c478bd9Sstevel@tonic-gate 	tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
322*7c478bd9Sstevel@tonic-gate 	tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
323*7c478bd9Sstevel@tonic-gate }
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate /*
326*7c478bd9Sstevel@tonic-gate  * exacct_update_task_mstate() updates the task's microstate accounting
327*7c478bd9Sstevel@tonic-gate  * statistics with accumulated counters for the exiting process.
328*7c478bd9Sstevel@tonic-gate  */
329*7c478bd9Sstevel@tonic-gate static void
330*7c478bd9Sstevel@tonic-gate exacct_update_task_mstate(proc_t *p)
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	task_usage_t *tu;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_task->tk_usage_lock);
335*7c478bd9Sstevel@tonic-gate 	tu = p->p_task->tk_usage;
336*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
337*7c478bd9Sstevel@tonic-gate 	tu->tu_utime	+= mstate_aggr_state(p, LMS_USER);
338*7c478bd9Sstevel@tonic-gate 	tu->tu_stime	+= mstate_aggr_state(p, LMS_SYSTEM);
339*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
340*7c478bd9Sstevel@tonic-gate 	tu->tu_minflt	+= p->p_ru.minflt;
341*7c478bd9Sstevel@tonic-gate 	tu->tu_majflt	+= p->p_ru.majflt;
342*7c478bd9Sstevel@tonic-gate 	tu->tu_sndmsg	+= p->p_ru.msgsnd;
343*7c478bd9Sstevel@tonic-gate 	tu->tu_rcvmsg	+= p->p_ru.msgrcv;
344*7c478bd9Sstevel@tonic-gate 	tu->tu_ioch	+= p->p_ru.ioch;
345*7c478bd9Sstevel@tonic-gate 	tu->tu_iblk	+= p->p_ru.inblock;
346*7c478bd9Sstevel@tonic-gate 	tu->tu_oblk	+= p->p_ru.oublock;
347*7c478bd9Sstevel@tonic-gate 	tu->tu_vcsw	+= p->p_ru.nvcsw;
348*7c478bd9Sstevel@tonic-gate 	tu->tu_icsw	+= p->p_ru.nivcsw;
349*7c478bd9Sstevel@tonic-gate 	tu->tu_nsig	+= p->p_ru.nsignals;
350*7c478bd9Sstevel@tonic-gate 	tu->tu_nswp	+= p->p_ru.nswap;
351*7c478bd9Sstevel@tonic-gate 	tu->tu_nscl	+= p->p_ru.sysc;
352*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_task->tk_usage_lock);
353*7c478bd9Sstevel@tonic-gate }
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate static void
356*7c478bd9Sstevel@tonic-gate exacct_calculate_task_usage(task_t *tk, task_usage_t *tu, int flag)
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	timestruc_t ts;
359*7c478bd9Sstevel@tonic-gate 	task_usage_t *tu_buf;
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	switch (flag) {
362*7c478bd9Sstevel@tonic-gate 	case EW_PARTIAL:
363*7c478bd9Sstevel@tonic-gate 		/*
364*7c478bd9Sstevel@tonic-gate 		 * For partial records we must report the sum of current
365*7c478bd9Sstevel@tonic-gate 		 * accounting statistics with previously accumulated
366*7c478bd9Sstevel@tonic-gate 		 * statistics.
367*7c478bd9Sstevel@tonic-gate 		 */
368*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
369*7c478bd9Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
372*7c478bd9Sstevel@tonic-gate 		exacct_snapshot_task_usage(tk, tu);
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
375*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
376*7c478bd9Sstevel@tonic-gate 		break;
377*7c478bd9Sstevel@tonic-gate 	case EW_INTERVAL:
378*7c478bd9Sstevel@tonic-gate 		/*
379*7c478bd9Sstevel@tonic-gate 		 * We need to allocate spare task_usage_t buffer before
380*7c478bd9Sstevel@tonic-gate 		 * grabbing pidlock because we might need it later in
381*7c478bd9Sstevel@tonic-gate 		 * exacct_get_interval_task_usage().
382*7c478bd9Sstevel@tonic-gate 		 */
383*7c478bd9Sstevel@tonic-gate 		tu_buf = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
384*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
385*7c478bd9Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 		/*
388*7c478bd9Sstevel@tonic-gate 		 * For interval records, we deduct the previous microstate
389*7c478bd9Sstevel@tonic-gate 		 * accounting data and cpu usage times from previously saved
390*7c478bd9Sstevel@tonic-gate 		 * results and update the previous task usage structure.
391*7c478bd9Sstevel@tonic-gate 		 */
392*7c478bd9Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
393*7c478bd9Sstevel@tonic-gate 		exacct_snapshot_task_usage(tk, tu);
394*7c478bd9Sstevel@tonic-gate 		exacct_get_interval_task_usage(tk, tu, &tu_buf);
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
397*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 		if (tu_buf != NULL)
400*7c478bd9Sstevel@tonic-gate 			kmem_free(tu_buf, sizeof (task_usage_t));
401*7c478bd9Sstevel@tonic-gate 		break;
402*7c478bd9Sstevel@tonic-gate 	case EW_FINAL:
403*7c478bd9Sstevel@tonic-gate 		/*
404*7c478bd9Sstevel@tonic-gate 		 * For final records, we only have to record task's finish
405*7c478bd9Sstevel@tonic-gate 		 * time because all other stuff has been calculated already.
406*7c478bd9Sstevel@tonic-gate 		 */
407*7c478bd9Sstevel@tonic-gate 		mutex_enter(&tk->tk_usage_lock);
408*7c478bd9Sstevel@tonic-gate 		(void) bcopy(tk->tk_usage, tu, sizeof (task_usage_t));
409*7c478bd9Sstevel@tonic-gate 		mutex_exit(&tk->tk_usage_lock);
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 		gethrestime(&ts);
412*7c478bd9Sstevel@tonic-gate 		tu->tu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
413*7c478bd9Sstevel@tonic-gate 		tu->tu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 		break;
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate static int
420*7c478bd9Sstevel@tonic-gate exacct_attach_task_item(task_t *tk, task_usage_t *tu, ea_object_t *record,
421*7c478bd9Sstevel@tonic-gate     int res)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	int attached = 1;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	switch (res) {
426*7c478bd9Sstevel@tonic-gate 	case AC_TASK_TASKID:
427*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tk->tk_tkid,
428*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_TASKID);
429*7c478bd9Sstevel@tonic-gate 		break;
430*7c478bd9Sstevel@tonic-gate 	case AC_TASK_PROJID:
431*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tk->tk_proj->kpj_id,
432*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_PROJID);
433*7c478bd9Sstevel@tonic-gate 		break;
434*7c478bd9Sstevel@tonic-gate 	case AC_TASK_CPU: {
435*7c478bd9Sstevel@tonic-gate 			timestruc_t ts;
436*7c478bd9Sstevel@tonic-gate 			uint64_t ui;
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 			hrt2ts(tu->tu_stime, &ts);
439*7c478bd9Sstevel@tonic-gate 			ui = ts.tv_sec;
440*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
441*7c478bd9Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_SYS_SEC);
442*7c478bd9Sstevel@tonic-gate 			ui = ts.tv_nsec;
443*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
444*7c478bd9Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_SYS_NSEC);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 			hrt2ts(tu->tu_utime, &ts);
447*7c478bd9Sstevel@tonic-gate 			ui = ts.tv_sec;
448*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
449*7c478bd9Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_USER_SEC);
450*7c478bd9Sstevel@tonic-gate 			ui = ts.tv_nsec;
451*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &ui, sizeof (uint64_t),
452*7c478bd9Sstevel@tonic-gate 			    EXT_UINT64 | EXD_TASK_CPU_USER_NSEC);
453*7c478bd9Sstevel@tonic-gate 		}
454*7c478bd9Sstevel@tonic-gate 		break;
455*7c478bd9Sstevel@tonic-gate 	case AC_TASK_TIME:
456*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_startsec,
457*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_SEC);
458*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_startnsec,
459*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_START_NSEC);
460*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_finishsec,
461*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_SEC);
462*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_finishnsec,
463*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FINISH_NSEC);
464*7c478bd9Sstevel@tonic-gate 		break;
465*7c478bd9Sstevel@tonic-gate 	case AC_TASK_HOSTNAME:
466*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, tk->tk_zone->zone_nodename,
467*7c478bd9Sstevel@tonic-gate 		    strlen(tk->tk_zone->zone_nodename) + 1,
468*7c478bd9Sstevel@tonic-gate 		    EXT_STRING | EXD_TASK_HOSTNAME);
469*7c478bd9Sstevel@tonic-gate 			break;
470*7c478bd9Sstevel@tonic-gate 	case AC_TASK_MICROSTATE:
471*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_majflt,
472*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MAJOR);
473*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_minflt,
474*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_FAULTS_MINOR);
475*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_sndmsg,
476*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_SND);
477*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_rcvmsg,
478*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_MESSAGES_RCV);
479*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_iblk,
480*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_IN);
481*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_oblk,
482*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_BLOCKS_OUT);
483*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_ioch,
484*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CHARS_RDWR);
485*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_vcsw,
486*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_VOL);
487*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_icsw,
488*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_CONTEXT_INV);
489*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nsig,
490*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SIGNALS);
491*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nswp,
492*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SWAPS);
493*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_nscl,
494*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_TASK_SYSCALLS);
495*7c478bd9Sstevel@tonic-gate 		break;
496*7c478bd9Sstevel@tonic-gate 	case AC_TASK_ANCTASKID:
497*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &tu->tu_anctaskid,
498*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_TASK_ANCTASKID);
499*7c478bd9Sstevel@tonic-gate 		break;
500*7c478bd9Sstevel@tonic-gate 	case AC_TASK_ZONENAME:
501*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, tk->tk_zone->zone_name,
502*7c478bd9Sstevel@tonic-gate 		    strlen(tk->tk_zone->zone_name) + 1,
503*7c478bd9Sstevel@tonic-gate 		    EXT_STRING | EXD_TASK_ZONENAME);
504*7c478bd9Sstevel@tonic-gate 		break;
505*7c478bd9Sstevel@tonic-gate 	default:
506*7c478bd9Sstevel@tonic-gate 		attached = 0;
507*7c478bd9Sstevel@tonic-gate 	}
508*7c478bd9Sstevel@tonic-gate 	return (attached);
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate static ea_object_t *
512*7c478bd9Sstevel@tonic-gate exacct_assemble_task_record(task_t *tk, task_usage_t *tu, ulong_t *mask,
513*7c478bd9Sstevel@tonic-gate     ea_catalog_t record_type)
514*7c478bd9Sstevel@tonic-gate {
515*7c478bd9Sstevel@tonic-gate 	int res, count;
516*7c478bd9Sstevel@tonic-gate 	ea_object_t *record;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	/*
519*7c478bd9Sstevel@tonic-gate 	 * Assemble usage values into group.
520*7c478bd9Sstevel@tonic-gate 	 */
521*7c478bd9Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
522*7c478bd9Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_TASK_MAX_RES; res++)
523*7c478bd9Sstevel@tonic-gate 		if (BT_TEST(mask, res))
524*7c478bd9Sstevel@tonic-gate 			count += exacct_attach_task_item(tk, tu, record, res);
525*7c478bd9Sstevel@tonic-gate 	if (count == 0) {
526*7c478bd9Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
527*7c478bd9Sstevel@tonic-gate 		record = NULL;
528*7c478bd9Sstevel@tonic-gate 	}
529*7c478bd9Sstevel@tonic-gate 	return (record);
530*7c478bd9Sstevel@tonic-gate }
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate /*
533*7c478bd9Sstevel@tonic-gate  * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *,
534*7c478bd9Sstevel@tonic-gate  *	size_t, size_t *), void *, size_t, size_t *, int)
535*7c478bd9Sstevel@tonic-gate  *
536*7c478bd9Sstevel@tonic-gate  * Overview
537*7c478bd9Sstevel@tonic-gate  *   exacct_assemble_task_usage() builds the packed exacct buffer for the
538*7c478bd9Sstevel@tonic-gate  *   indicated task, executes the given callback function, and free the packed
539*7c478bd9Sstevel@tonic-gate  *   buffer.
540*7c478bd9Sstevel@tonic-gate  *
541*7c478bd9Sstevel@tonic-gate  * Return values
542*7c478bd9Sstevel@tonic-gate  *   Returns 0 on success; otherwise the appropriate error code is returned.
543*7c478bd9Sstevel@tonic-gate  *
544*7c478bd9Sstevel@tonic-gate  * Caller's context
545*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
546*7c478bd9Sstevel@tonic-gate  */
547*7c478bd9Sstevel@tonic-gate int
548*7c478bd9Sstevel@tonic-gate exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk,
549*7c478bd9Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
550*7c478bd9Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual, int flag)
551*7c478bd9Sstevel@tonic-gate {
552*7c478bd9Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
553*7c478bd9Sstevel@tonic-gate 	ea_object_t *task_record;
554*7c478bd9Sstevel@tonic-gate 	ea_catalog_t record_type;
555*7c478bd9Sstevel@tonic-gate 	task_usage_t *tu;
556*7c478bd9Sstevel@tonic-gate 	void *buf;
557*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
558*7c478bd9Sstevel@tonic-gate 	int ret;
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL);
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ac_task->ac_lock);
563*7c478bd9Sstevel@tonic-gate 	if (ac_task->ac_state == AC_OFF) {
564*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_task->ac_lock);
565*7c478bd9Sstevel@tonic-gate 		return (ENOTACTIVE);
566*7c478bd9Sstevel@tonic-gate 	}
567*7c478bd9Sstevel@tonic-gate 	bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ);
568*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ac_task->ac_lock);
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	switch (flag) {
571*7c478bd9Sstevel@tonic-gate 	case EW_FINAL:
572*7c478bd9Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK;
573*7c478bd9Sstevel@tonic-gate 		break;
574*7c478bd9Sstevel@tonic-gate 	case EW_PARTIAL:
575*7c478bd9Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK_PARTIAL;
576*7c478bd9Sstevel@tonic-gate 		break;
577*7c478bd9Sstevel@tonic-gate 	case EW_INTERVAL:
578*7c478bd9Sstevel@tonic-gate 		record_type = EXD_GROUP_TASK_INTERVAL;
579*7c478bd9Sstevel@tonic-gate 		break;
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	/*
583*7c478bd9Sstevel@tonic-gate 	 * Calculate task usage and assemble it into the task record.
584*7c478bd9Sstevel@tonic-gate 	 */
585*7c478bd9Sstevel@tonic-gate 	tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
586*7c478bd9Sstevel@tonic-gate 	exacct_calculate_task_usage(tk, tu, flag);
587*7c478bd9Sstevel@tonic-gate 	task_record = exacct_assemble_task_record(tk, tu, mask, record_type);
588*7c478bd9Sstevel@tonic-gate 	if (task_record == NULL) {
589*7c478bd9Sstevel@tonic-gate 		/*
590*7c478bd9Sstevel@tonic-gate 		 * The current configuration of the accounting system has
591*7c478bd9Sstevel@tonic-gate 		 * resulted in records with no data; accordingly, we don't write
592*7c478bd9Sstevel@tonic-gate 		 * these, but we return success.
593*7c478bd9Sstevel@tonic-gate 		 */
594*7c478bd9Sstevel@tonic-gate 		kmem_free(tu, sizeof (task_usage_t));
595*7c478bd9Sstevel@tonic-gate 		return (0);
596*7c478bd9Sstevel@tonic-gate 	}
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	/*
599*7c478bd9Sstevel@tonic-gate 	 * Pack object into buffer and run callback on it.
600*7c478bd9Sstevel@tonic-gate 	 */
601*7c478bd9Sstevel@tonic-gate 	bufsize = ea_pack_object(task_record, NULL, 0);
602*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
603*7c478bd9Sstevel@tonic-gate 	(void) ea_pack_object(task_record, buf, bufsize);
604*7c478bd9Sstevel@tonic-gate 	ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual);
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	/*
607*7c478bd9Sstevel@tonic-gate 	 * Free all previously allocated structures.
608*7c478bd9Sstevel@tonic-gate 	 */
609*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, bufsize);
610*7c478bd9Sstevel@tonic-gate 	ea_free_object(task_record, EUP_ALLOC);
611*7c478bd9Sstevel@tonic-gate 	kmem_free(tu, sizeof (task_usage_t));
612*7c478bd9Sstevel@tonic-gate 	return (ret);
613*7c478bd9Sstevel@tonic-gate }
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate /*
616*7c478bd9Sstevel@tonic-gate  * void exacct_commit_task(void *)
617*7c478bd9Sstevel@tonic-gate  *
618*7c478bd9Sstevel@tonic-gate  * Overview
619*7c478bd9Sstevel@tonic-gate  *   exacct_commit_task() calculates the final usage for a task, updating the
620*7c478bd9Sstevel@tonic-gate  *   task usage if task accounting is active, and writing a task record if task
621*7c478bd9Sstevel@tonic-gate  *   accounting is active.  exacct_commit_task() is intended for being called
622*7c478bd9Sstevel@tonic-gate  *   from a task queue (taskq_t).
623*7c478bd9Sstevel@tonic-gate  *
624*7c478bd9Sstevel@tonic-gate  * Return values
625*7c478bd9Sstevel@tonic-gate  *   None.
626*7c478bd9Sstevel@tonic-gate  *
627*7c478bd9Sstevel@tonic-gate  * Caller's context
628*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
629*7c478bd9Sstevel@tonic-gate  */
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate void
632*7c478bd9Sstevel@tonic-gate exacct_commit_task(void *arg)
633*7c478bd9Sstevel@tonic-gate {
634*7c478bd9Sstevel@tonic-gate 	task_t *tk = (task_t *)arg;
635*7c478bd9Sstevel@tonic-gate 	size_t size;
636*7c478bd9Sstevel@tonic-gate 	zone_t *zone = tk->tk_zone;
637*7c478bd9Sstevel@tonic-gate 	struct exacct_globals *acg;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	ASSERT(tk != task0p);
640*7c478bd9Sstevel@tonic-gate 	ASSERT(tk->tk_memb_list == NULL);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	/*
643*7c478bd9Sstevel@tonic-gate 	 * Don't do any extra work if the acctctl module isn't loaded.
644*7c478bd9Sstevel@tonic-gate 	 */
645*7c478bd9Sstevel@tonic-gate 	if (exacct_zone_key != ZONE_KEY_UNINITIALIZED) {
646*7c478bd9Sstevel@tonic-gate 		acg = zone_getspecific(exacct_zone_key, zone);
647*7c478bd9Sstevel@tonic-gate 		(void) exacct_assemble_task_usage(&acg->ac_task, tk,
648*7c478bd9Sstevel@tonic-gate 		    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
649*7c478bd9Sstevel@tonic-gate 		if (tk->tk_zone != global_zone) {
650*7c478bd9Sstevel@tonic-gate 			acg = zone_getspecific(exacct_zone_key, global_zone);
651*7c478bd9Sstevel@tonic-gate 			(void) exacct_assemble_task_usage(&acg->ac_task, tk,
652*7c478bd9Sstevel@tonic-gate 			    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 	/*
656*7c478bd9Sstevel@tonic-gate 	 * Release associated project and finalize task.
657*7c478bd9Sstevel@tonic-gate 	 */
658*7c478bd9Sstevel@tonic-gate 	task_end(tk);
659*7c478bd9Sstevel@tonic-gate }
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate static int
662*7c478bd9Sstevel@tonic-gate exacct_attach_proc_item(proc_usage_t *pu, ea_object_t *record, int res)
663*7c478bd9Sstevel@tonic-gate {
664*7c478bd9Sstevel@tonic-gate 	int attached = 1;
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	switch (res) {
667*7c478bd9Sstevel@tonic-gate 	case AC_PROC_PID:
668*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_pid,
669*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PID);
670*7c478bd9Sstevel@tonic-gate 		break;
671*7c478bd9Sstevel@tonic-gate 	case AC_PROC_UID:
672*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ruid,
673*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_UID);
674*7c478bd9Sstevel@tonic-gate 		break;
675*7c478bd9Sstevel@tonic-gate 	case AC_PROC_FLAG:
676*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_acflag,
677*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ACCT_FLAGS);
678*7c478bd9Sstevel@tonic-gate 		break;
679*7c478bd9Sstevel@tonic-gate 	case AC_PROC_GID:
680*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_rgid,
681*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_GID);
682*7c478bd9Sstevel@tonic-gate 		break;
683*7c478bd9Sstevel@tonic-gate 	case AC_PROC_PROJID:
684*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_projid,
685*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_PROJID);
686*7c478bd9Sstevel@tonic-gate 		break;
687*7c478bd9Sstevel@tonic-gate 	case AC_PROC_TASKID:
688*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_taskid,
689*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TASKID);
690*7c478bd9Sstevel@tonic-gate 		break;
691*7c478bd9Sstevel@tonic-gate 	case AC_PROC_CPU:
692*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_utimesec,
693*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_SEC);
694*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_utimensec,
695*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_USER_NSEC);
696*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_stimesec,
697*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_SEC);
698*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_stimensec,
699*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CPU_SYS_NSEC);
700*7c478bd9Sstevel@tonic-gate 		break;
701*7c478bd9Sstevel@tonic-gate 	case AC_PROC_TIME:
702*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_startsec,
703*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_SEC);
704*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_startnsec,
705*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_START_NSEC);
706*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_finishsec,
707*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_SEC);
708*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_finishnsec,
709*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FINISH_NSEC);
710*7c478bd9Sstevel@tonic-gate 		break;
711*7c478bd9Sstevel@tonic-gate 	case AC_PROC_COMMAND:
712*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_command,
713*7c478bd9Sstevel@tonic-gate 		    strlen(pu->pu_command) + 1, EXT_STRING | EXD_PROC_COMMAND);
714*7c478bd9Sstevel@tonic-gate 		break;
715*7c478bd9Sstevel@tonic-gate 	case AC_PROC_HOSTNAME:
716*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_nodename,
717*7c478bd9Sstevel@tonic-gate 		    strlen(pu->pu_nodename) + 1,
718*7c478bd9Sstevel@tonic-gate 		    EXT_STRING | EXD_PROC_HOSTNAME);
719*7c478bd9Sstevel@tonic-gate 		break;
720*7c478bd9Sstevel@tonic-gate 	case AC_PROC_TTY:
721*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_major,
722*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MAJOR);
723*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_minor,
724*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_TTY_MINOR);
725*7c478bd9Sstevel@tonic-gate 		break;
726*7c478bd9Sstevel@tonic-gate 	case AC_PROC_MICROSTATE:
727*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_majflt,
728*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MAJOR);
729*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_minflt,
730*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_FAULTS_MINOR);
731*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_sndmsg,
732*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_SND);
733*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_rcvmsg,
734*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MESSAGES_RCV);
735*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_iblk,
736*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_IN);
737*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_oblk,
738*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_BLOCKS_OUT);
739*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ioch,
740*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CHARS_RDWR);
741*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_vcsw,
742*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_VOL);
743*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_icsw,
744*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_CONTEXT_INV);
745*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nsig,
746*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SIGNALS);
747*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nswp,
748*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SWAPS);
749*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_nscl,
750*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_SYSCALLS);
751*7c478bd9Sstevel@tonic-gate 		break;
752*7c478bd9Sstevel@tonic-gate 	case AC_PROC_ANCPID:
753*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_ancpid,
754*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_ANCPID);
755*7c478bd9Sstevel@tonic-gate 		break;
756*7c478bd9Sstevel@tonic-gate 	case AC_PROC_WAIT_STATUS:
757*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_wstat,
758*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), EXT_UINT32 | EXD_PROC_WAIT_STATUS);
759*7c478bd9Sstevel@tonic-gate 		break;
760*7c478bd9Sstevel@tonic-gate 	case AC_PROC_ZONENAME:
761*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, pu->pu_zonename,
762*7c478bd9Sstevel@tonic-gate 		    strlen(pu->pu_zonename) + 1,
763*7c478bd9Sstevel@tonic-gate 		    EXT_STRING | EXD_PROC_ZONENAME);
764*7c478bd9Sstevel@tonic-gate 		break;
765*7c478bd9Sstevel@tonic-gate 	case AC_PROC_MEM:
766*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_mem_rss_avg,
767*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_AVG_K);
768*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &pu->pu_mem_rss_max,
769*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_PROC_MEM_RSS_MAX_K);
770*7c478bd9Sstevel@tonic-gate 		break;
771*7c478bd9Sstevel@tonic-gate 	default:
772*7c478bd9Sstevel@tonic-gate 		attached = 0;
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 	return (attached);
775*7c478bd9Sstevel@tonic-gate }
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate static ea_object_t *
778*7c478bd9Sstevel@tonic-gate exacct_assemble_proc_record(proc_usage_t *pu, ulong_t *mask,
779*7c478bd9Sstevel@tonic-gate     ea_catalog_t record_type)
780*7c478bd9Sstevel@tonic-gate {
781*7c478bd9Sstevel@tonic-gate 	int res, count;
782*7c478bd9Sstevel@tonic-gate 	ea_object_t *record;
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	/*
785*7c478bd9Sstevel@tonic-gate 	 * Assemble usage values into group.
786*7c478bd9Sstevel@tonic-gate 	 */
787*7c478bd9Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
788*7c478bd9Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_PROC_MAX_RES; res++)
789*7c478bd9Sstevel@tonic-gate 		if (BT_TEST(mask, res))
790*7c478bd9Sstevel@tonic-gate 		    count += exacct_attach_proc_item(pu, record, res);
791*7c478bd9Sstevel@tonic-gate 	if (count == 0) {
792*7c478bd9Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
793*7c478bd9Sstevel@tonic-gate 		record = NULL;
794*7c478bd9Sstevel@tonic-gate 	}
795*7c478bd9Sstevel@tonic-gate 	return (record);
796*7c478bd9Sstevel@tonic-gate }
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate /*
799*7c478bd9Sstevel@tonic-gate  * The following two routines assume that process's p_lock is held or
800*7c478bd9Sstevel@tonic-gate  * exacct_commit_proc has been called from exit() when all lwps are stopped.
801*7c478bd9Sstevel@tonic-gate  */
802*7c478bd9Sstevel@tonic-gate static void
803*7c478bd9Sstevel@tonic-gate exacct_calculate_proc_mstate(proc_t *p, proc_usage_t *pu)
804*7c478bd9Sstevel@tonic-gate {
805*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
808*7c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) == NULL)
809*7c478bd9Sstevel@tonic-gate 		return;
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	do {
812*7c478bd9Sstevel@tonic-gate 		pu->pu_minflt	+= t->t_lwp->lwp_ru.minflt;
813*7c478bd9Sstevel@tonic-gate 		pu->pu_majflt	+= t->t_lwp->lwp_ru.majflt;
814*7c478bd9Sstevel@tonic-gate 		pu->pu_sndmsg	+= t->t_lwp->lwp_ru.msgsnd;
815*7c478bd9Sstevel@tonic-gate 		pu->pu_rcvmsg	+= t->t_lwp->lwp_ru.msgrcv;
816*7c478bd9Sstevel@tonic-gate 		pu->pu_ioch	+= t->t_lwp->lwp_ru.ioch;
817*7c478bd9Sstevel@tonic-gate 		pu->pu_iblk	+= t->t_lwp->lwp_ru.inblock;
818*7c478bd9Sstevel@tonic-gate 		pu->pu_oblk	+= t->t_lwp->lwp_ru.oublock;
819*7c478bd9Sstevel@tonic-gate 		pu->pu_vcsw	+= t->t_lwp->lwp_ru.nvcsw;
820*7c478bd9Sstevel@tonic-gate 		pu->pu_icsw	+= t->t_lwp->lwp_ru.nivcsw;
821*7c478bd9Sstevel@tonic-gate 		pu->pu_nsig	+= t->t_lwp->lwp_ru.nsignals;
822*7c478bd9Sstevel@tonic-gate 		pu->pu_nswp	+= t->t_lwp->lwp_ru.nswap;
823*7c478bd9Sstevel@tonic-gate 		pu->pu_nscl	+= t->t_lwp->lwp_ru.sysc;
824*7c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
825*7c478bd9Sstevel@tonic-gate }
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate static void
828*7c478bd9Sstevel@tonic-gate exacct_copy_proc_mstate(proc_t *p, proc_usage_t *pu)
829*7c478bd9Sstevel@tonic-gate {
830*7c478bd9Sstevel@tonic-gate 	pu->pu_minflt	= p->p_ru.minflt;
831*7c478bd9Sstevel@tonic-gate 	pu->pu_majflt	= p->p_ru.majflt;
832*7c478bd9Sstevel@tonic-gate 	pu->pu_sndmsg	= p->p_ru.msgsnd;
833*7c478bd9Sstevel@tonic-gate 	pu->pu_rcvmsg	= p->p_ru.msgrcv;
834*7c478bd9Sstevel@tonic-gate 	pu->pu_ioch	= p->p_ru.ioch;
835*7c478bd9Sstevel@tonic-gate 	pu->pu_iblk	= p->p_ru.inblock;
836*7c478bd9Sstevel@tonic-gate 	pu->pu_oblk	= p->p_ru.oublock;
837*7c478bd9Sstevel@tonic-gate 	pu->pu_vcsw	= p->p_ru.nvcsw;
838*7c478bd9Sstevel@tonic-gate 	pu->pu_icsw	= p->p_ru.nivcsw;
839*7c478bd9Sstevel@tonic-gate 	pu->pu_nsig	= p->p_ru.nsignals;
840*7c478bd9Sstevel@tonic-gate 	pu->pu_nswp	= p->p_ru.nswap;
841*7c478bd9Sstevel@tonic-gate 	pu->pu_nscl	= p->p_ru.sysc;
842*7c478bd9Sstevel@tonic-gate }
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate void
845*7c478bd9Sstevel@tonic-gate exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask,
846*7c478bd9Sstevel@tonic-gate     int flag, int wstat)
847*7c478bd9Sstevel@tonic-gate {
848*7c478bd9Sstevel@tonic-gate 	timestruc_t ts, ts_run;
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	/*
853*7c478bd9Sstevel@tonic-gate 	 * Convert CPU and execution times to sec/nsec format.
854*7c478bd9Sstevel@tonic-gate 	 */
855*7c478bd9Sstevel@tonic-gate 	if (BT_TEST(mask, AC_PROC_CPU)) {
856*7c478bd9Sstevel@tonic-gate 		hrt2ts(mstate_aggr_state(p, LMS_USER), &ts);
857*7c478bd9Sstevel@tonic-gate 		pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec;
858*7c478bd9Sstevel@tonic-gate 		pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec;
859*7c478bd9Sstevel@tonic-gate 		hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts);
860*7c478bd9Sstevel@tonic-gate 		pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec;
861*7c478bd9Sstevel@tonic-gate 		pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec;
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 	if (BT_TEST(mask, AC_PROC_TIME)) {
864*7c478bd9Sstevel@tonic-gate 		gethrestime(&ts);
865*7c478bd9Sstevel@tonic-gate 		pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
866*7c478bd9Sstevel@tonic-gate 		pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
867*7c478bd9Sstevel@tonic-gate 		hrt2ts(gethrtime() - p->p_mstart, &ts_run);
868*7c478bd9Sstevel@tonic-gate 		ts.tv_sec -= ts_run.tv_sec;
869*7c478bd9Sstevel@tonic-gate 		ts.tv_nsec -= ts_run.tv_nsec;
870*7c478bd9Sstevel@tonic-gate 		if (ts.tv_nsec < 0) {
871*7c478bd9Sstevel@tonic-gate 			ts.tv_sec--;
872*7c478bd9Sstevel@tonic-gate 			if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) {
873*7c478bd9Sstevel@tonic-gate 				ts.tv_sec++;
874*7c478bd9Sstevel@tonic-gate 				ts.tv_nsec -= NANOSEC;
875*7c478bd9Sstevel@tonic-gate 			}
876*7c478bd9Sstevel@tonic-gate 		}
877*7c478bd9Sstevel@tonic-gate 		pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec;
878*7c478bd9Sstevel@tonic-gate 		pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec;
879*7c478bd9Sstevel@tonic-gate 	}
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	pu->pu_pid = p->p_pidp->pid_id;
882*7c478bd9Sstevel@tonic-gate 	pu->pu_acflag = p->p_user.u_acflag;
883*7c478bd9Sstevel@tonic-gate 	pu->pu_projid = p->p_task->tk_proj->kpj_id;
884*7c478bd9Sstevel@tonic-gate 	pu->pu_taskid = p->p_task->tk_tkid;
885*7c478bd9Sstevel@tonic-gate 	pu->pu_major = getmajor(p->p_sessp->s_dev);
886*7c478bd9Sstevel@tonic-gate 	pu->pu_minor = getminor(p->p_sessp->s_dev);
887*7c478bd9Sstevel@tonic-gate 	pu->pu_ancpid = p->p_ancpid;
888*7c478bd9Sstevel@tonic-gate 	pu->pu_wstat = wstat;
889*7c478bd9Sstevel@tonic-gate 	/*
890*7c478bd9Sstevel@tonic-gate 	 * Compute average RSS in K.  The denominator is the number of
891*7c478bd9Sstevel@tonic-gate 	 * samples:  the number of clock ticks plus the initial value.
892*7c478bd9Sstevel@tonic-gate 	 */
893*7c478bd9Sstevel@tonic-gate 	pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) *
894*7c478bd9Sstevel@tonic-gate 	    (PAGESIZE / 1024);
895*7c478bd9Sstevel@tonic-gate 	pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024);
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
898*7c478bd9Sstevel@tonic-gate 	pu->pu_ruid = crgetruid(p->p_cred);
899*7c478bd9Sstevel@tonic-gate 	pu->pu_rgid = crgetrgid(p->p_cred);
900*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1);
903*7c478bd9Sstevel@tonic-gate 	bcopy(p->p_zone->zone_name, pu->pu_zonename,
904*7c478bd9Sstevel@tonic-gate 	    strlen(p->p_zone->zone_name) + 1);
905*7c478bd9Sstevel@tonic-gate 	bcopy(p->p_zone->zone_nodename, pu->pu_nodename,
906*7c478bd9Sstevel@tonic-gate 	    strlen(p->p_zone->zone_nodename) + 1);
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	/*
909*7c478bd9Sstevel@tonic-gate 	 * Calculate microstate accounting data for a process that is still
910*7c478bd9Sstevel@tonic-gate 	 * running.  Presently, we explicitly collect all of the LWP usage into
911*7c478bd9Sstevel@tonic-gate 	 * the proc usage structure here.
912*7c478bd9Sstevel@tonic-gate 	 */
913*7c478bd9Sstevel@tonic-gate 	if (flag & EW_PARTIAL)
914*7c478bd9Sstevel@tonic-gate 		exacct_calculate_proc_mstate(p, pu);
915*7c478bd9Sstevel@tonic-gate 	if (flag & EW_FINAL)
916*7c478bd9Sstevel@tonic-gate 		exacct_copy_proc_mstate(p, pu);
917*7c478bd9Sstevel@tonic-gate }
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate /*
920*7c478bd9Sstevel@tonic-gate  * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void
921*7c478bd9Sstevel@tonic-gate  *	*, size_t, size_t *), void *, size_t, size_t *)
922*7c478bd9Sstevel@tonic-gate  *
923*7c478bd9Sstevel@tonic-gate  * Overview
924*7c478bd9Sstevel@tonic-gate  *   Assemble record with miscellaneous accounting information about the process
925*7c478bd9Sstevel@tonic-gate  *   and execute the callback on it. It is the callback's job to set "actual" to
926*7c478bd9Sstevel@tonic-gate  *   the size of record.
927*7c478bd9Sstevel@tonic-gate  *
928*7c478bd9Sstevel@tonic-gate  * Return values
929*7c478bd9Sstevel@tonic-gate  *   The result of the callback function, unless the extended process accounting
930*7c478bd9Sstevel@tonic-gate  *   feature is not active, in which case ENOTACTIVE is returned.
931*7c478bd9Sstevel@tonic-gate  *
932*7c478bd9Sstevel@tonic-gate  * Caller's context
933*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
934*7c478bd9Sstevel@tonic-gate  */
935*7c478bd9Sstevel@tonic-gate int
936*7c478bd9Sstevel@tonic-gate exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu,
937*7c478bd9Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
938*7c478bd9Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual, int flag)
939*7c478bd9Sstevel@tonic-gate {
940*7c478bd9Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
941*7c478bd9Sstevel@tonic-gate 	ea_object_t *proc_record;
942*7c478bd9Sstevel@tonic-gate 	ea_catalog_t record_type;
943*7c478bd9Sstevel@tonic-gate 	void *buf;
944*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
945*7c478bd9Sstevel@tonic-gate 	int ret;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL);
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
950*7c478bd9Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_OFF) {
951*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
952*7c478bd9Sstevel@tonic-gate 		return (ENOTACTIVE);
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate 	bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
955*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ac_proc->ac_lock);
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	switch (flag) {
958*7c478bd9Sstevel@tonic-gate 	case EW_FINAL:
959*7c478bd9Sstevel@tonic-gate 		record_type = EXD_GROUP_PROC;
960*7c478bd9Sstevel@tonic-gate 		break;
961*7c478bd9Sstevel@tonic-gate 	case EW_PARTIAL:
962*7c478bd9Sstevel@tonic-gate 		record_type = EXD_GROUP_PROC_PARTIAL;
963*7c478bd9Sstevel@tonic-gate 		break;
964*7c478bd9Sstevel@tonic-gate 	}
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	proc_record = exacct_assemble_proc_record(pu, mask, record_type);
967*7c478bd9Sstevel@tonic-gate 	if (proc_record == NULL)
968*7c478bd9Sstevel@tonic-gate 		return (0);
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	/*
971*7c478bd9Sstevel@tonic-gate 	 * Pack object into buffer and pass to callback.
972*7c478bd9Sstevel@tonic-gate 	 */
973*7c478bd9Sstevel@tonic-gate 	bufsize = ea_pack_object(proc_record, NULL, 0);
974*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
975*7c478bd9Sstevel@tonic-gate 	(void) ea_pack_object(proc_record, buf, bufsize);
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual);
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	/*
980*7c478bd9Sstevel@tonic-gate 	 * Free all previously allocations.
981*7c478bd9Sstevel@tonic-gate 	 */
982*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, bufsize);
983*7c478bd9Sstevel@tonic-gate 	ea_free_object(proc_record, EUP_ALLOC);
984*7c478bd9Sstevel@tonic-gate 	return (ret);
985*7c478bd9Sstevel@tonic-gate }
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate /*
988*7c478bd9Sstevel@tonic-gate  * int exacct_commit_callback(ac_info_t *, void *, size_t, void *, size_t,
989*7c478bd9Sstevel@tonic-gate  * 	size_t *)
990*7c478bd9Sstevel@tonic-gate  *
991*7c478bd9Sstevel@tonic-gate  * Overview
992*7c478bd9Sstevel@tonic-gate  *   exacct_commit_callback() writes the indicated buffer to the indicated
993*7c478bd9Sstevel@tonic-gate  *   extended accounting file.
994*7c478bd9Sstevel@tonic-gate  *
995*7c478bd9Sstevel@tonic-gate  * Return values
996*7c478bd9Sstevel@tonic-gate  *   The result of the write operation is returned.  "actual" is updated to
997*7c478bd9Sstevel@tonic-gate  *   contain the number of bytes actually written.
998*7c478bd9Sstevel@tonic-gate  *
999*7c478bd9Sstevel@tonic-gate  * Caller's context
1000*7c478bd9Sstevel@tonic-gate  *   Suitable for a vn_rdwr() operation.
1001*7c478bd9Sstevel@tonic-gate  */
1002*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1003*7c478bd9Sstevel@tonic-gate int
1004*7c478bd9Sstevel@tonic-gate exacct_commit_callback(ac_info_t *info, void *ubuf, size_t ubufsize,
1005*7c478bd9Sstevel@tonic-gate     void *buf, size_t bufsize, size_t *actual)
1006*7c478bd9Sstevel@tonic-gate {
1007*7c478bd9Sstevel@tonic-gate 	int error = 0;
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	*actual = 0;
1010*7c478bd9Sstevel@tonic-gate 	if ((error = exacct_vn_write(info, buf, bufsize)) == 0)
1011*7c478bd9Sstevel@tonic-gate 		*actual = bufsize;
1012*7c478bd9Sstevel@tonic-gate 	return (error);
1013*7c478bd9Sstevel@tonic-gate }
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate static void
1016*7c478bd9Sstevel@tonic-gate exacct_do_commit_proc(ac_info_t *ac_proc, proc_t *p, int wstat)
1017*7c478bd9Sstevel@tonic-gate {
1018*7c478bd9Sstevel@tonic-gate 	size_t size;
1019*7c478bd9Sstevel@tonic-gate 	proc_usage_t *pu;
1020*7c478bd9Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
1023*7c478bd9Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_ON) {
1024*7c478bd9Sstevel@tonic-gate 		bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
1025*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
1026*7c478bd9Sstevel@tonic-gate 	} else {
1027*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
1028*7c478bd9Sstevel@tonic-gate 		return;
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
1032*7c478bd9Sstevel@tonic-gate 	size = strlen(p->p_user.u_comm) + 1;
1033*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	pu = kmem_alloc(sizeof (proc_usage_t), KM_SLEEP);
1036*7c478bd9Sstevel@tonic-gate 	pu->pu_command = kmem_alloc(size, KM_SLEEP);
1037*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
1038*7c478bd9Sstevel@tonic-gate 	exacct_calculate_proc_usage(p, pu, mask, EW_FINAL, wstat);
1039*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 	(void) exacct_assemble_proc_usage(ac_proc, pu,
1042*7c478bd9Sstevel@tonic-gate 	    exacct_commit_callback, NULL, 0, &size, EW_FINAL);
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	kmem_free(pu->pu_command, strlen(pu->pu_command) + 1);
1045*7c478bd9Sstevel@tonic-gate 	kmem_free(pu, sizeof (proc_usage_t));
1046*7c478bd9Sstevel@tonic-gate }
1047*7c478bd9Sstevel@tonic-gate /*
1048*7c478bd9Sstevel@tonic-gate  * void exacct_commit_proc(proc_t *, int)
1049*7c478bd9Sstevel@tonic-gate  *
1050*7c478bd9Sstevel@tonic-gate  * Overview
1051*7c478bd9Sstevel@tonic-gate  *   exacct_commit_proc() calculates the final usage for a process, updating the
1052*7c478bd9Sstevel@tonic-gate  *   task usage if task accounting is active, and writing a process record if
1053*7c478bd9Sstevel@tonic-gate  *   process accounting is active.  exacct_commit_proc() is intended for being
1054*7c478bd9Sstevel@tonic-gate  *   called from proc_exit().
1055*7c478bd9Sstevel@tonic-gate  *
1056*7c478bd9Sstevel@tonic-gate  * Return values
1057*7c478bd9Sstevel@tonic-gate  *   None.
1058*7c478bd9Sstevel@tonic-gate  *
1059*7c478bd9Sstevel@tonic-gate  * Caller's context
1060*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.  p_lock must not be held at entry.
1061*7c478bd9Sstevel@tonic-gate  */
1062*7c478bd9Sstevel@tonic-gate void
1063*7c478bd9Sstevel@tonic-gate exacct_commit_proc(proc_t *p, int wstat)
1064*7c478bd9Sstevel@tonic-gate {
1065*7c478bd9Sstevel@tonic-gate 	zone_t *zone = p->p_zone;
1066*7c478bd9Sstevel@tonic-gate 	struct exacct_globals *acg, *gacg = NULL;
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
1069*7c478bd9Sstevel@tonic-gate 		/*
1070*7c478bd9Sstevel@tonic-gate 		 * acctctl module not loaded.  Nothing to do.
1071*7c478bd9Sstevel@tonic-gate 		 */
1072*7c478bd9Sstevel@tonic-gate 		return;
1073*7c478bd9Sstevel@tonic-gate 	}
1074*7c478bd9Sstevel@tonic-gate 	acg = zone_getspecific(exacct_zone_key, zone);
1075*7c478bd9Sstevel@tonic-gate 	if (zone != global_zone)
1076*7c478bd9Sstevel@tonic-gate 		gacg = zone_getspecific(exacct_zone_key, global_zone);
1077*7c478bd9Sstevel@tonic-gate 	if (acg->ac_task.ac_state == AC_ON ||
1078*7c478bd9Sstevel@tonic-gate 	    (gacg != NULL && gacg->ac_task.ac_state == AC_ON)) {
1079*7c478bd9Sstevel@tonic-gate 		exacct_update_task_mstate(p);
1080*7c478bd9Sstevel@tonic-gate 	}
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 	exacct_do_commit_proc(&acg->ac_proc, p, wstat);
1083*7c478bd9Sstevel@tonic-gate 	if (p->p_zone != global_zone)
1084*7c478bd9Sstevel@tonic-gate 		exacct_do_commit_proc(&gacg->ac_proc, p, wstat);
1085*7c478bd9Sstevel@tonic-gate }
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate static int
1088*7c478bd9Sstevel@tonic-gate exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res)
1089*7c478bd9Sstevel@tonic-gate {
1090*7c478bd9Sstevel@tonic-gate 	int attached = 1;
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	switch (res) {
1093*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_SADDR:
1094*7c478bd9Sstevel@tonic-gate 		if (fu->fu_isv4) {
1095*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_saddr[3],
1096*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4SADDR);
1097*7c478bd9Sstevel@tonic-gate 		} else {
1098*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_saddr,
1099*7c478bd9Sstevel@tonic-gate 			    sizeof (fu->fu_saddr), EXT_RAW |
1100*7c478bd9Sstevel@tonic-gate 			    EXD_FLOW_V6SADDR);
1101*7c478bd9Sstevel@tonic-gate 		}
1102*7c478bd9Sstevel@tonic-gate 		break;
1103*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_DADDR:
1104*7c478bd9Sstevel@tonic-gate 		if (fu->fu_isv4) {
1105*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_daddr[3],
1106*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_V4DADDR);
1107*7c478bd9Sstevel@tonic-gate 		} else {
1108*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_daddr,
1109*7c478bd9Sstevel@tonic-gate 			    sizeof (fu->fu_daddr), EXT_RAW |
1110*7c478bd9Sstevel@tonic-gate 			    EXD_FLOW_V6DADDR);
1111*7c478bd9Sstevel@tonic-gate 		}
1112*7c478bd9Sstevel@tonic-gate 		break;
1113*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_SPORT:
1114*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_sport,
1115*7c478bd9Sstevel@tonic-gate 		    sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_SPORT);
1116*7c478bd9Sstevel@tonic-gate 		break;
1117*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_DPORT:
1118*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_dport,
1119*7c478bd9Sstevel@tonic-gate 		    sizeof (uint16_t), EXT_UINT16 | EXD_FLOW_DPORT);
1120*7c478bd9Sstevel@tonic-gate 		break;
1121*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_PROTOCOL:
1122*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_protocol,
1123*7c478bd9Sstevel@tonic-gate 		    sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_PROTOCOL);
1124*7c478bd9Sstevel@tonic-gate 		break;
1125*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_DSFIELD:
1126*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_dsfield,
1127*7c478bd9Sstevel@tonic-gate 		    sizeof (uint8_t), EXT_UINT8 | EXD_FLOW_DSFIELD);
1128*7c478bd9Sstevel@tonic-gate 		break;
1129*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_CTIME:
1130*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_ctime,
1131*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_CTIME);
1132*7c478bd9Sstevel@tonic-gate 		break;
1133*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_LSEEN:
1134*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_lseen,
1135*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT64 | EXD_FLOW_LSEEN);
1136*7c478bd9Sstevel@tonic-gate 		break;
1137*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_NBYTES:
1138*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_nbytes,
1139*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NBYTES);
1140*7c478bd9Sstevel@tonic-gate 		break;
1141*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_NPKTS:
1142*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, &fu->fu_npackets,
1143*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), EXT_UINT32 | EXD_FLOW_NPKTS);
1144*7c478bd9Sstevel@tonic-gate 		break;
1145*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_PROJID:
1146*7c478bd9Sstevel@tonic-gate 		if (fu->fu_projid >= 0) {
1147*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_projid,
1148*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_PROJID);
1149*7c478bd9Sstevel@tonic-gate 		}
1150*7c478bd9Sstevel@tonic-gate 		break;
1151*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_UID:
1152*7c478bd9Sstevel@tonic-gate 		if (fu->fu_userid >= 0) {
1153*7c478bd9Sstevel@tonic-gate 			(void) ea_attach_item(record, &fu->fu_userid,
1154*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID);
1155*7c478bd9Sstevel@tonic-gate 		}
1156*7c478bd9Sstevel@tonic-gate 		break;
1157*7c478bd9Sstevel@tonic-gate 	case AC_FLOW_ANAME:
1158*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_item(record, fu->fu_aname,
1159*7c478bd9Sstevel@tonic-gate 		    strlen(fu->fu_aname) + 1, EXT_STRING | EXD_FLOW_ANAME);
1160*7c478bd9Sstevel@tonic-gate 		break;
1161*7c478bd9Sstevel@tonic-gate 	default:
1162*7c478bd9Sstevel@tonic-gate 		attached = 0;
1163*7c478bd9Sstevel@tonic-gate 	}
1164*7c478bd9Sstevel@tonic-gate 	return (attached);
1165*7c478bd9Sstevel@tonic-gate }
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate static ea_object_t *
1168*7c478bd9Sstevel@tonic-gate exacct_assemble_flow_record(flow_usage_t *fu, ulong_t *mask,
1169*7c478bd9Sstevel@tonic-gate     ea_catalog_t record_type)
1170*7c478bd9Sstevel@tonic-gate {
1171*7c478bd9Sstevel@tonic-gate 	int res, count;
1172*7c478bd9Sstevel@tonic-gate 	ea_object_t *record;
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	/*
1175*7c478bd9Sstevel@tonic-gate 	 * Assemble usage values into group.
1176*7c478bd9Sstevel@tonic-gate 	 */
1177*7c478bd9Sstevel@tonic-gate 	record = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | record_type);
1178*7c478bd9Sstevel@tonic-gate 	for (res = 1, count = 0; res <= AC_FLOW_MAX_RES; res++)
1179*7c478bd9Sstevel@tonic-gate 		if (BT_TEST(mask, res))
1180*7c478bd9Sstevel@tonic-gate 			count += exacct_attach_flow_item(fu, record, res);
1181*7c478bd9Sstevel@tonic-gate 	if (count == 0) {
1182*7c478bd9Sstevel@tonic-gate 		ea_free_object(record, EUP_ALLOC);
1183*7c478bd9Sstevel@tonic-gate 		record = NULL;
1184*7c478bd9Sstevel@tonic-gate 	}
1185*7c478bd9Sstevel@tonic-gate 	return (record);
1186*7c478bd9Sstevel@tonic-gate }
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate int
1189*7c478bd9Sstevel@tonic-gate exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu,
1190*7c478bd9Sstevel@tonic-gate     int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
1191*7c478bd9Sstevel@tonic-gate     void *ubuf, size_t ubufsize, size_t *actual)
1192*7c478bd9Sstevel@tonic-gate {
1193*7c478bd9Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
1194*7c478bd9Sstevel@tonic-gate 	ea_object_t *flow_usage;
1195*7c478bd9Sstevel@tonic-gate 	ea_catalog_t record_type;
1196*7c478bd9Sstevel@tonic-gate 	void *buf;
1197*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
1198*7c478bd9Sstevel@tonic-gate 	int ret;
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ac_flow->ac_lock);
1201*7c478bd9Sstevel@tonic-gate 	if (ac_flow->ac_state == AC_OFF) {
1202*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_flow->ac_lock);
1203*7c478bd9Sstevel@tonic-gate 		return (ENOTACTIVE);
1204*7c478bd9Sstevel@tonic-gate 	}
1205*7c478bd9Sstevel@tonic-gate 	bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
1206*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ac_flow->ac_lock);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	record_type = EXD_GROUP_FLOW;
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	flow_usage = exacct_assemble_flow_record(fu, mask, record_type);
1211*7c478bd9Sstevel@tonic-gate 	if (flow_usage == NULL) {
1212*7c478bd9Sstevel@tonic-gate 		return (0);
1213*7c478bd9Sstevel@tonic-gate 	}
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	/*
1216*7c478bd9Sstevel@tonic-gate 	 * Pack object into buffer and pass to callback.
1217*7c478bd9Sstevel@tonic-gate 	 */
1218*7c478bd9Sstevel@tonic-gate 	bufsize = ea_pack_object(flow_usage, NULL, 0);
1219*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_NOSLEEP);
1220*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
1221*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1222*7c478bd9Sstevel@tonic-gate 	}
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	(void) ea_pack_object(flow_usage, buf, bufsize);
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual);
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	/*
1229*7c478bd9Sstevel@tonic-gate 	 * Free all previously allocations.
1230*7c478bd9Sstevel@tonic-gate 	 */
1231*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, bufsize);
1232*7c478bd9Sstevel@tonic-gate 	ea_free_object(flow_usage, EUP_ALLOC);
1233*7c478bd9Sstevel@tonic-gate 	return (ret);
1234*7c478bd9Sstevel@tonic-gate }
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate void
1237*7c478bd9Sstevel@tonic-gate exacct_commit_flow(void *arg)
1238*7c478bd9Sstevel@tonic-gate {
1239*7c478bd9Sstevel@tonic-gate 	flow_usage_t *f = (flow_usage_t *)arg;
1240*7c478bd9Sstevel@tonic-gate 	size_t size;
1241*7c478bd9Sstevel@tonic-gate 	ulong_t mask[AC_MASK_SZ];
1242*7c478bd9Sstevel@tonic-gate 	struct exacct_globals *acg;
1243*7c478bd9Sstevel@tonic-gate 	ac_info_t *ac_flow;
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate 	if (exacct_zone_key == ZONE_KEY_UNINITIALIZED) {
1246*7c478bd9Sstevel@tonic-gate 		/*
1247*7c478bd9Sstevel@tonic-gate 		 * acctctl module not loaded. Nothing to do.
1248*7c478bd9Sstevel@tonic-gate 		 */
1249*7c478bd9Sstevel@tonic-gate 		return;
1250*7c478bd9Sstevel@tonic-gate 	}
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	/*
1253*7c478bd9Sstevel@tonic-gate 	 * Even though each zone nominally has its own flow accounting settings
1254*7c478bd9Sstevel@tonic-gate 	 * (ac_flow), these are only maintained by and for the global zone.
1255*7c478bd9Sstevel@tonic-gate 	 *
1256*7c478bd9Sstevel@tonic-gate 	 * If this were to change in the future, this function should grow a
1257*7c478bd9Sstevel@tonic-gate 	 * second zoneid (or zone) argument, and use the corresponding zone's
1258*7c478bd9Sstevel@tonic-gate 	 * settings rather than always using those of the global zone.
1259*7c478bd9Sstevel@tonic-gate 	 */
1260*7c478bd9Sstevel@tonic-gate 	acg = zone_getspecific(exacct_zone_key, global_zone);
1261*7c478bd9Sstevel@tonic-gate 	ac_flow = &acg->ac_flow;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ac_flow->ac_lock);
1264*7c478bd9Sstevel@tonic-gate 	if (ac_flow->ac_state == AC_OFF) {
1265*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_flow->ac_lock);
1266*7c478bd9Sstevel@tonic-gate 		return;
1267*7c478bd9Sstevel@tonic-gate 	}
1268*7c478bd9Sstevel@tonic-gate 	bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
1269*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ac_flow->ac_lock);
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	(void) exacct_assemble_flow_usage(ac_flow, f, exacct_commit_callback,
1272*7c478bd9Sstevel@tonic-gate 	    NULL, 0, &size);
1273*7c478bd9Sstevel@tonic-gate }
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate /*
1276*7c478bd9Sstevel@tonic-gate  * int exacct_tag_task(task_t *, void *, size_t, int)
1277*7c478bd9Sstevel@tonic-gate  *
1278*7c478bd9Sstevel@tonic-gate  * Overview
1279*7c478bd9Sstevel@tonic-gate  *   exacct_tag_task() provides the exacct record construction and writing
1280*7c478bd9Sstevel@tonic-gate  *   support required by putacct(2) for task entities.
1281*7c478bd9Sstevel@tonic-gate  *
1282*7c478bd9Sstevel@tonic-gate  * Return values
1283*7c478bd9Sstevel@tonic-gate  *   The result of the write operation is returned, unless the extended
1284*7c478bd9Sstevel@tonic-gate  *   accounting facility is not active, in which case ENOTACTIVE is returned.
1285*7c478bd9Sstevel@tonic-gate  *
1286*7c478bd9Sstevel@tonic-gate  * Caller's context
1287*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
1288*7c478bd9Sstevel@tonic-gate  */
1289*7c478bd9Sstevel@tonic-gate int
1290*7c478bd9Sstevel@tonic-gate exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz,
1291*7c478bd9Sstevel@tonic-gate     int flags)
1292*7c478bd9Sstevel@tonic-gate {
1293*7c478bd9Sstevel@tonic-gate 	int error = 0;
1294*7c478bd9Sstevel@tonic-gate 	void *buf;
1295*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
1296*7c478bd9Sstevel@tonic-gate 	ea_catalog_t cat;
1297*7c478bd9Sstevel@tonic-gate 	ea_object_t *tag;
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ac_task->ac_lock);
1300*7c478bd9Sstevel@tonic-gate 	if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) {
1301*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_task->ac_lock);
1302*7c478bd9Sstevel@tonic-gate 		return (ENOTACTIVE);
1303*7c478bd9Sstevel@tonic-gate 	}
1304*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ac_task->ac_lock);
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate 	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG);
1307*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(tag, &tk->tk_tkid, 0,
1308*7c478bd9Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
1309*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0,
1310*7c478bd9Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
1311*7c478bd9Sstevel@tonic-gate 	if (flags == EP_RAW)
1312*7c478bd9Sstevel@tonic-gate 		cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG;
1313*7c478bd9Sstevel@tonic-gate 	else
1314*7c478bd9Sstevel@tonic-gate 		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG;
1315*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(tag, ubuf, ubufsz, cat);
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 	bufsize = ea_pack_object(tag, NULL, 0);
1318*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
1319*7c478bd9Sstevel@tonic-gate 	(void) ea_pack_object(tag, buf, bufsize);
1320*7c478bd9Sstevel@tonic-gate 	error = exacct_vn_write(ac_task, buf, bufsize);
1321*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, bufsize);
1322*7c478bd9Sstevel@tonic-gate 	ea_free_object(tag, EUP_ALLOC);
1323*7c478bd9Sstevel@tonic-gate 	return (error);
1324*7c478bd9Sstevel@tonic-gate }
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate /*
1327*7c478bd9Sstevel@tonic-gate  * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *)
1328*7c478bd9Sstevel@tonic-gate  *
1329*7c478bd9Sstevel@tonic-gate  * Overview
1330*7c478bd9Sstevel@tonic-gate  *   exacct_tag_proc() provides the exacct record construction and writing
1331*7c478bd9Sstevel@tonic-gate  *   support required by putacct(2) for processes.
1332*7c478bd9Sstevel@tonic-gate  *
1333*7c478bd9Sstevel@tonic-gate  * Return values
1334*7c478bd9Sstevel@tonic-gate  *   The result of the write operation is returned, unless the extended
1335*7c478bd9Sstevel@tonic-gate  *   accounting facility is not active, in which case ENOTACTIVE is returned.
1336*7c478bd9Sstevel@tonic-gate  *
1337*7c478bd9Sstevel@tonic-gate  * Caller's context
1338*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
1339*7c478bd9Sstevel@tonic-gate  */
1340*7c478bd9Sstevel@tonic-gate int
1341*7c478bd9Sstevel@tonic-gate exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf,
1342*7c478bd9Sstevel@tonic-gate     size_t ubufsz, int flags, const char *hostname)
1343*7c478bd9Sstevel@tonic-gate {
1344*7c478bd9Sstevel@tonic-gate 	int error = 0;
1345*7c478bd9Sstevel@tonic-gate 	void *buf;
1346*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
1347*7c478bd9Sstevel@tonic-gate 	ea_catalog_t cat;
1348*7c478bd9Sstevel@tonic-gate 	ea_object_t *tag;
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ac_proc->ac_lock);
1351*7c478bd9Sstevel@tonic-gate 	if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) {
1352*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ac_proc->ac_lock);
1353*7c478bd9Sstevel@tonic-gate 		return (ENOTACTIVE);
1354*7c478bd9Sstevel@tonic-gate 	}
1355*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ac_proc->ac_lock);
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG);
1358*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(tag, &pid, sizeof (uint32_t),
1359*7c478bd9Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID);
1360*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(tag, &tkid, 0,
1361*7c478bd9Sstevel@tonic-gate 	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
1362*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(tag, (void *)hostname, 0,
1363*7c478bd9Sstevel@tonic-gate 	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
1364*7c478bd9Sstevel@tonic-gate 	if (flags == EP_RAW)
1365*7c478bd9Sstevel@tonic-gate 		cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG;
1366*7c478bd9Sstevel@tonic-gate 	else
1367*7c478bd9Sstevel@tonic-gate 		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG;
1368*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_item(tag, ubuf, ubufsz, cat);
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	bufsize = ea_pack_object(tag, NULL, 0);
1371*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(bufsize, KM_SLEEP);
1372*7c478bd9Sstevel@tonic-gate 	(void) ea_pack_object(tag, buf, bufsize);
1373*7c478bd9Sstevel@tonic-gate 	error = exacct_vn_write(ac_proc, buf, bufsize);
1374*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, bufsize);
1375*7c478bd9Sstevel@tonic-gate 	ea_free_object(tag, EUP_ALLOC);
1376*7c478bd9Sstevel@tonic-gate 	return (error);
1377*7c478bd9Sstevel@tonic-gate }
1378*7c478bd9Sstevel@tonic-gate 
1379*7c478bd9Sstevel@tonic-gate /*
1380*7c478bd9Sstevel@tonic-gate  * void exacct_init(void)
1381*7c478bd9Sstevel@tonic-gate  *
1382*7c478bd9Sstevel@tonic-gate  * Overview
1383*7c478bd9Sstevel@tonic-gate  *   Initialized the extended accounting subsystem.
1384*7c478bd9Sstevel@tonic-gate  *
1385*7c478bd9Sstevel@tonic-gate  * Return values
1386*7c478bd9Sstevel@tonic-gate  *   None.
1387*7c478bd9Sstevel@tonic-gate  *
1388*7c478bd9Sstevel@tonic-gate  * Caller's context
1389*7c478bd9Sstevel@tonic-gate  *   Suitable for KM_SLEEP allocations.
1390*7c478bd9Sstevel@tonic-gate  */
1391*7c478bd9Sstevel@tonic-gate void
1392*7c478bd9Sstevel@tonic-gate exacct_init()
1393*7c478bd9Sstevel@tonic-gate {
1394*7c478bd9Sstevel@tonic-gate 	exacct_queue = system_taskq;
1395*7c478bd9Sstevel@tonic-gate 	exacct_object_cache = kmem_cache_create("exacct_object_cache",
1396*7c478bd9Sstevel@tonic-gate 	    sizeof (ea_object_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
1397*7c478bd9Sstevel@tonic-gate }
1398