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