10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*1235Ssp92102 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/sysmacros.h> 350Sstevel@tonic-gate #include <sys/param.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/acct.h> 380Sstevel@tonic-gate #include <sys/cred.h> 390Sstevel@tonic-gate #include <sys/user.h> 400Sstevel@tonic-gate #include <sys/errno.h> 410Sstevel@tonic-gate #include <sys/file.h> 420Sstevel@tonic-gate #include <sys/vnode.h> 430Sstevel@tonic-gate #include <sys/debug.h> 440Sstevel@tonic-gate #include <sys/proc.h> 450Sstevel@tonic-gate #include <sys/resource.h> 460Sstevel@tonic-gate #include <sys/session.h> 470Sstevel@tonic-gate #include <sys/modctl.h> 480Sstevel@tonic-gate #include <sys/syscall.h> 490Sstevel@tonic-gate #include <sys/policy.h> 500Sstevel@tonic-gate #include <sys/list.h> 510Sstevel@tonic-gate #include <sys/time.h> 520Sstevel@tonic-gate #include <sys/msacct.h> 530Sstevel@tonic-gate #include <sys/zone.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * Each zone has its own accounting settings (on or off) and associated 570Sstevel@tonic-gate * file. The global zone is not special in this aspect; it will only 580Sstevel@tonic-gate * generate records for processes that ran in the global zone. We could 590Sstevel@tonic-gate * allow the global zone to record all activity on the system, but there 600Sstevel@tonic-gate * would be no way of knowing the zone in which the processes executed. 610Sstevel@tonic-gate * sysacct() is thus virtualized to only act on the caller's zone. 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate struct acct_globals { 640Sstevel@tonic-gate struct acct acctbuf; 650Sstevel@tonic-gate kmutex_t aclock; 660Sstevel@tonic-gate struct vnode *acctvp; 670Sstevel@tonic-gate list_node_t aclink; 680Sstevel@tonic-gate }; 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* 710Sstevel@tonic-gate * We need a list of all accounting settings for all zones, so we can 720Sstevel@tonic-gate * accurately determine if a file is in use for accounting (possibly by 730Sstevel@tonic-gate * another zone). 740Sstevel@tonic-gate */ 750Sstevel@tonic-gate static zone_key_t acct_zone_key; 760Sstevel@tonic-gate static list_t acct_list; 770Sstevel@tonic-gate kmutex_t acct_list_lock; 780Sstevel@tonic-gate 790Sstevel@tonic-gate static struct sysent acctsysent = { 800Sstevel@tonic-gate 1, 810Sstevel@tonic-gate SE_NOUNLOAD | SE_ARGC | SE_32RVAL1, 820Sstevel@tonic-gate sysacct 830Sstevel@tonic-gate }; 840Sstevel@tonic-gate 850Sstevel@tonic-gate static struct modlsys modlsys = { 860Sstevel@tonic-gate &mod_syscallops, "acct(2) syscall", &acctsysent 870Sstevel@tonic-gate }; 880Sstevel@tonic-gate 890Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 900Sstevel@tonic-gate static struct modlsys modlsys32 = { 910Sstevel@tonic-gate &mod_syscallops32, "32-bit acct(2) syscall", &acctsysent 920Sstevel@tonic-gate }; 930Sstevel@tonic-gate #endif 940Sstevel@tonic-gate 950Sstevel@tonic-gate static struct modlinkage modlinkage = { 960Sstevel@tonic-gate MODREV_1, 970Sstevel@tonic-gate &modlsys, 980Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 990Sstevel@tonic-gate &modlsys32, 1000Sstevel@tonic-gate #endif 1010Sstevel@tonic-gate NULL 1020Sstevel@tonic-gate }; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /*ARGSUSED*/ 1050Sstevel@tonic-gate static void * 1060Sstevel@tonic-gate acct_init(zoneid_t zoneid) 1070Sstevel@tonic-gate { 1080Sstevel@tonic-gate struct acct_globals *ag; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate ag = kmem_alloc(sizeof (*ag), KM_SLEEP); 1110Sstevel@tonic-gate bzero(&ag->acctbuf, sizeof (ag->acctbuf)); 1120Sstevel@tonic-gate mutex_init(&ag->aclock, NULL, MUTEX_DEFAULT, NULL); 1130Sstevel@tonic-gate ag->acctvp = NULL; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate mutex_enter(&acct_list_lock); 1160Sstevel@tonic-gate list_insert_tail(&acct_list, ag); 1170Sstevel@tonic-gate mutex_exit(&acct_list_lock); 1180Sstevel@tonic-gate return (ag); 1190Sstevel@tonic-gate } 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* ARGSUSED */ 1220Sstevel@tonic-gate static void 1230Sstevel@tonic-gate acct_shutdown(zoneid_t zoneid, void *arg) 1240Sstevel@tonic-gate { 1250Sstevel@tonic-gate struct acct_globals *ag = arg; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate mutex_enter(&ag->aclock); 1280Sstevel@tonic-gate if (ag->acctvp) { 1290Sstevel@tonic-gate /* 1300Sstevel@tonic-gate * This needs to be done as a shutdown callback, otherwise this 1310Sstevel@tonic-gate * held vnode may cause filesystems to be busy, and the zone 1320Sstevel@tonic-gate * shutdown operation to fail. 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate (void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred); 1350Sstevel@tonic-gate VN_RELE(ag->acctvp); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate ag->acctvp = NULL; 1380Sstevel@tonic-gate mutex_exit(&ag->aclock); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /*ARGSUSED*/ 1420Sstevel@tonic-gate static void 1430Sstevel@tonic-gate acct_fini(zoneid_t zoneid, void *arg) 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate struct acct_globals *ag = arg; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate mutex_enter(&acct_list_lock); 1480Sstevel@tonic-gate list_remove(&acct_list, ag); 1490Sstevel@tonic-gate mutex_exit(&acct_list_lock); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate mutex_destroy(&ag->aclock); 1520Sstevel@tonic-gate kmem_free(ag, sizeof (*ag)); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate int 1560Sstevel@tonic-gate _init(void) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate int error; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate mutex_init(&acct_list_lock, NULL, MUTEX_DEFAULT, NULL); 1610Sstevel@tonic-gate list_create(&acct_list, sizeof (struct acct_globals), 1620Sstevel@tonic-gate offsetof(struct acct_globals, aclink)); 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Using an initializer here wastes a bit of memory for zones that 1650Sstevel@tonic-gate * don't use accounting, but vastly simplifies the locking. 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate zone_key_create(&acct_zone_key, acct_init, acct_shutdown, acct_fini); 1680Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) { 1690Sstevel@tonic-gate (void) zone_key_delete(acct_zone_key); 1700Sstevel@tonic-gate list_destroy(&acct_list); 1710Sstevel@tonic-gate mutex_destroy(&acct_list_lock); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate return (error); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate int 1770Sstevel@tonic-gate _info(struct modinfo *modinfop) 1780Sstevel@tonic-gate { 1790Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 1830Sstevel@tonic-gate * acct() is a "weak stub" routine called from exit(). 1840Sstevel@tonic-gate * Once this module has been loaded, we refuse to allow 1850Sstevel@tonic-gate * it to unload - otherwise accounting would quietly 1860Sstevel@tonic-gate * cease. See 1211661. It's possible to make this module 1870Sstevel@tonic-gate * unloadable but it's substantially safer not to bother. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate int 1900Sstevel@tonic-gate _fini(void) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate return (EBUSY); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate /* 1960Sstevel@tonic-gate * See if vp is in use by the accounting system on any zone. This does a deep 1970Sstevel@tonic-gate * comparison of vnodes such that a file and a lofs "shadow" node of it will 1980Sstevel@tonic-gate * appear to be the same. 1990Sstevel@tonic-gate * 2000Sstevel@tonic-gate * If 'compare_vfs' is true, the function will do a comparison of vfs_t's 2010Sstevel@tonic-gate * instead (ie, is the vfs_t on which the vnode resides in use by the 2020Sstevel@tonic-gate * accounting system in any zone). 2030Sstevel@tonic-gate * 2040Sstevel@tonic-gate * Returns 1 if found (in use), 0 otherwise. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate static int 2070Sstevel@tonic-gate acct_find(vnode_t *vp, boolean_t compare_vfs) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate struct acct_globals *ag; 2100Sstevel@tonic-gate vnode_t *realvp; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate ASSERT(MUTEX_HELD(&acct_list_lock)); 2130Sstevel@tonic-gate ASSERT(vp != NULL); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate if (VOP_REALVP(vp, &realvp)) 2160Sstevel@tonic-gate realvp = vp; 2170Sstevel@tonic-gate for (ag = list_head(&acct_list); ag != NULL; 2180Sstevel@tonic-gate ag = list_next(&acct_list, ag)) { 2190Sstevel@tonic-gate vnode_t *racctvp; 2200Sstevel@tonic-gate boolean_t found = B_FALSE; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate mutex_enter(&ag->aclock); 2230Sstevel@tonic-gate if (ag->acctvp == NULL) { 2240Sstevel@tonic-gate mutex_exit(&ag->aclock); 2250Sstevel@tonic-gate continue; 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate if (VOP_REALVP(ag->acctvp, &racctvp)) 2280Sstevel@tonic-gate racctvp = ag->acctvp; 2290Sstevel@tonic-gate if (compare_vfs) { 2300Sstevel@tonic-gate if (racctvp->v_vfsp == realvp->v_vfsp) 2310Sstevel@tonic-gate found = B_TRUE; 2320Sstevel@tonic-gate } else { 2330Sstevel@tonic-gate if (VN_CMP(realvp, racctvp)) 2340Sstevel@tonic-gate found = B_TRUE; 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate mutex_exit(&ag->aclock); 2370Sstevel@tonic-gate if (found) 2380Sstevel@tonic-gate return (1); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate return (0); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * Returns 1 if the vfs that vnode resides on is in use for the accounting 2450Sstevel@tonic-gate * subsystem, 0 otherwise. 2460Sstevel@tonic-gate */ 2470Sstevel@tonic-gate int 2480Sstevel@tonic-gate acct_fs_in_use(vnode_t *vp) 2490Sstevel@tonic-gate { 2500Sstevel@tonic-gate int found; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate if (vp == NULL) 2530Sstevel@tonic-gate return (0); 2540Sstevel@tonic-gate mutex_enter(&acct_list_lock); 2550Sstevel@tonic-gate found = acct_find(vp, B_TRUE); 2560Sstevel@tonic-gate mutex_exit(&acct_list_lock); 2570Sstevel@tonic-gate return (found); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * Perform process accounting functions. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate int 2640Sstevel@tonic-gate sysacct(char *fname) 2650Sstevel@tonic-gate { 2660Sstevel@tonic-gate struct acct_globals *ag; 2670Sstevel@tonic-gate struct vnode *vp; 2680Sstevel@tonic-gate int error = 0; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate if (secpolicy_acct(CRED()) != 0) 2710Sstevel@tonic-gate return (set_errno(EPERM)); 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate ag = zone_getspecific(acct_zone_key, curproc->p_zone); 2740Sstevel@tonic-gate ASSERT(ag != NULL); 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate if (fname == NULL) { 2770Sstevel@tonic-gate /* 2780Sstevel@tonic-gate * Close the file and stop accounting. 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate mutex_enter(&ag->aclock); 2810Sstevel@tonic-gate vp = ag->acctvp; 2820Sstevel@tonic-gate ag->acctvp = NULL; 2830Sstevel@tonic-gate mutex_exit(&ag->aclock); 2840Sstevel@tonic-gate if (vp) { 2850Sstevel@tonic-gate error = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED()); 2860Sstevel@tonic-gate VN_RELE(vp); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate return (error == 0 ? 0 : set_errno(error)); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * Either (a) open a new file and begin accounting -or- (b) 2930Sstevel@tonic-gate * switch accounting from an old to a new file. 2940Sstevel@tonic-gate * 2950Sstevel@tonic-gate * (Open the file without holding aclock in case it 2960Sstevel@tonic-gate * sleeps (holding the lock prevents process exit).) 2970Sstevel@tonic-gate */ 2980Sstevel@tonic-gate if ((error = vn_open(fname, UIO_USERSPACE, FWRITE, 2990Sstevel@tonic-gate 0, &vp, (enum create)0, 0)) != 0) { 3000Sstevel@tonic-gate /* SVID compliance */ 3010Sstevel@tonic-gate if (error == EISDIR) 3020Sstevel@tonic-gate error = EACCES; 3030Sstevel@tonic-gate return (set_errno(error)); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if (vp->v_type != VREG) { 3070Sstevel@tonic-gate error = EACCES; 3080Sstevel@tonic-gate } else { 3090Sstevel@tonic-gate mutex_enter(&acct_list_lock); 3100Sstevel@tonic-gate if (acct_find(vp, B_FALSE)) { 3110Sstevel@tonic-gate error = EBUSY; 3120Sstevel@tonic-gate } else { 3130Sstevel@tonic-gate mutex_enter(&ag->aclock); 3140Sstevel@tonic-gate if (ag->acctvp) { 3150Sstevel@tonic-gate vnode_t *oldvp; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * close old acctvp, and point acct() 3190Sstevel@tonic-gate * at new file by swapping vp and acctvp 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate oldvp = ag->acctvp; 3220Sstevel@tonic-gate ag->acctvp = vp; 3230Sstevel@tonic-gate vp = oldvp; 3240Sstevel@tonic-gate } else { 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * no existing file, start accounting .. 3270Sstevel@tonic-gate */ 3280Sstevel@tonic-gate ag->acctvp = vp; 3290Sstevel@tonic-gate vp = NULL; 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate mutex_exit(&ag->aclock); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate mutex_exit(&acct_list_lock); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate if (vp) { 3370Sstevel@tonic-gate (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED()); 3380Sstevel@tonic-gate VN_RELE(vp); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate return (error == 0 ? 0 : set_errno(error)); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * Produce a pseudo-floating point representation 3450Sstevel@tonic-gate * with 3 bits base-8 exponent, 13 bits fraction. 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate static comp_t 3480Sstevel@tonic-gate acct_compress(ulong_t t) 3490Sstevel@tonic-gate { 3500Sstevel@tonic-gate int exp = 0, round = 0; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate while (t >= 8192) { 3530Sstevel@tonic-gate exp++; 3540Sstevel@tonic-gate round = t & 04; 3550Sstevel@tonic-gate t >>= 3; 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate if (round) { 3580Sstevel@tonic-gate t++; 3590Sstevel@tonic-gate if (t >= 8192) { 3600Sstevel@tonic-gate t >>= 3; 3610Sstevel@tonic-gate exp++; 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate #ifdef _LP64 3650Sstevel@tonic-gate if (exp > 7) { 3660Sstevel@tonic-gate /* prevent wraparound */ 3670Sstevel@tonic-gate t = 8191; 3680Sstevel@tonic-gate exp = 7; 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate #endif 3710Sstevel@tonic-gate return ((exp << 13) + t); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* 3750Sstevel@tonic-gate * On exit, write a record on the accounting file. 3760Sstevel@tonic-gate */ 3770Sstevel@tonic-gate void 3780Sstevel@tonic-gate acct(char st) 3790Sstevel@tonic-gate { 3800Sstevel@tonic-gate struct vnode *vp; 3810Sstevel@tonic-gate struct cred *cr; 3820Sstevel@tonic-gate struct proc *p; 3830Sstevel@tonic-gate struct vattr va; 3840Sstevel@tonic-gate ssize_t resid = 0; 3850Sstevel@tonic-gate int error; 3860Sstevel@tonic-gate struct acct_globals *ag; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate ag = zone_getspecific(acct_zone_key, curproc->p_zone); 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate mutex_enter(&ag->aclock); 3910Sstevel@tonic-gate if ((vp = ag->acctvp) == NULL) { 3920Sstevel@tonic-gate mutex_exit(&ag->aclock); 3930Sstevel@tonic-gate return; 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * This only gets called from exit after all lwp's have exited so no 3980Sstevel@tonic-gate * cred locking is needed. 3990Sstevel@tonic-gate */ 4000Sstevel@tonic-gate p = curproc; 4010Sstevel@tonic-gate bcopy(u.u_comm, ag->acctbuf.ac_comm, sizeof (ag->acctbuf.ac_comm)); 4020Sstevel@tonic-gate ag->acctbuf.ac_btime = u.u_start.tv_sec; 403*1235Ssp92102 ag->acctbuf.ac_utime = acct_compress(NSEC_TO_TICK(p->p_acct[LMS_USER])); 4040Sstevel@tonic-gate ag->acctbuf.ac_stime = acct_compress( 405*1235Ssp92102 NSEC_TO_TICK(p->p_acct[LMS_SYSTEM] + p->p_acct[LMS_TRAP])); 4060Sstevel@tonic-gate ag->acctbuf.ac_etime = acct_compress(lbolt - u.u_ticks); 4070Sstevel@tonic-gate ag->acctbuf.ac_mem = acct_compress((ulong_t)u.u_mem); 4080Sstevel@tonic-gate ag->acctbuf.ac_io = acct_compress((ulong_t)p->p_ru.ioch); 4090Sstevel@tonic-gate ag->acctbuf.ac_rw = acct_compress((ulong_t)(p->p_ru.inblock + 4100Sstevel@tonic-gate p->p_ru.oublock)); 4110Sstevel@tonic-gate cr = CRED(); 4120Sstevel@tonic-gate ag->acctbuf.ac_uid = crgetruid(cr); 4130Sstevel@tonic-gate ag->acctbuf.ac_gid = crgetrgid(cr); 4140Sstevel@tonic-gate (void) cmpldev(&ag->acctbuf.ac_tty, cttydev(p)); 4150Sstevel@tonic-gate ag->acctbuf.ac_stat = st; 4160Sstevel@tonic-gate ag->acctbuf.ac_flag = (u.u_acflag | AEXPND); 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate /* 4190Sstevel@tonic-gate * Save the size. If the write fails, reset the size to avoid 4200Sstevel@tonic-gate * corrupted acct files. 4210Sstevel@tonic-gate * 4220Sstevel@tonic-gate * Large Files: We deliberately prevent accounting files from 4230Sstevel@tonic-gate * exceeding the 2GB limit as none of the accounting commands are 4240Sstevel@tonic-gate * currently large file aware. 4250Sstevel@tonic-gate */ 4260Sstevel@tonic-gate va.va_mask = AT_SIZE; 4270Sstevel@tonic-gate if (VOP_GETATTR(vp, &va, 0, kcred) == 0) { 4280Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&ag->acctbuf, 4290Sstevel@tonic-gate sizeof (ag->acctbuf), 0LL, UIO_SYSSPACE, FAPPEND, 4300Sstevel@tonic-gate (rlim64_t)MAXOFF32_T, kcred, &resid); 4310Sstevel@tonic-gate if (error || resid) 4320Sstevel@tonic-gate (void) VOP_SETATTR(vp, &va, 0, kcred, NULL); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate mutex_exit(&ag->aclock); 4350Sstevel@tonic-gate } 436