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