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 /* 24*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 25*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 26*7c478bd9Sstevel@tonic-gate */ 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/session.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/var.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/utssys.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/ustat.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/sunldi_impl.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/flock.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/share.h> 65*7c478bd9Sstevel@tonic-gate #include <vm/as.h> 66*7c478bd9Sstevel@tonic-gate #include <vm/seg.h> 67*7c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h> 68*7c478bd9Sstevel@tonic-gate #include <util/qsort.h> 69*7c478bd9Sstevel@tonic-gate #include <sys/zone.h> 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate /* 72*7c478bd9Sstevel@tonic-gate * utssys() 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate static int uts_fusers(char *, int, intptr_t); 75*7c478bd9Sstevel@tonic-gate static int _statvfs64_by_dev(dev_t, struct statvfs64 *); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate static int utssys_uname32(caddr_t, rval_t *); 80*7c478bd9Sstevel@tonic-gate static int utssys_ustat32(dev_t, struct ustat32 *); 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate int64_t 83*7c478bd9Sstevel@tonic-gate utssys32(void *buf, int arg, int type, void *outbp) 84*7c478bd9Sstevel@tonic-gate { 85*7c478bd9Sstevel@tonic-gate int error; 86*7c478bd9Sstevel@tonic-gate rval_t rv; 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate rv.r_vals = 0; 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate switch (type) { 91*7c478bd9Sstevel@tonic-gate case UTS_UNAME: 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * This is an obsolete way to get the utsname structure 94*7c478bd9Sstevel@tonic-gate * (it only gives you the first 8 characters of each field!) 95*7c478bd9Sstevel@tonic-gate * uname(2) is the preferred and better interface. 96*7c478bd9Sstevel@tonic-gate */ 97*7c478bd9Sstevel@tonic-gate error = utssys_uname32(buf, &rv); 98*7c478bd9Sstevel@tonic-gate break; 99*7c478bd9Sstevel@tonic-gate case UTS_USTAT: 100*7c478bd9Sstevel@tonic-gate error = utssys_ustat32(expldev((dev32_t)arg), buf); 101*7c478bd9Sstevel@tonic-gate break; 102*7c478bd9Sstevel@tonic-gate case UTS_FUSERS: 103*7c478bd9Sstevel@tonic-gate error = uts_fusers(buf, arg, (intptr_t)outbp); 104*7c478bd9Sstevel@tonic-gate break; 105*7c478bd9Sstevel@tonic-gate default: 106*7c478bd9Sstevel@tonic-gate error = EINVAL; 107*7c478bd9Sstevel@tonic-gate break; 108*7c478bd9Sstevel@tonic-gate } 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate return (error == 0 ? rv.r_vals : (int64_t)set_errno(error)); 111*7c478bd9Sstevel@tonic-gate } 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate static int 114*7c478bd9Sstevel@tonic-gate utssys_uname32(caddr_t buf, rval_t *rvp) 115*7c478bd9Sstevel@tonic-gate { 116*7c478bd9Sstevel@tonic-gate if (copyout(utsname.sysname, buf, 8)) 117*7c478bd9Sstevel@tonic-gate return (EFAULT); 118*7c478bd9Sstevel@tonic-gate buf += 8; 119*7c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 120*7c478bd9Sstevel@tonic-gate return (EFAULT); 121*7c478bd9Sstevel@tonic-gate buf++; 122*7c478bd9Sstevel@tonic-gate if (copyout(uts_nodename(), buf, 8)) 123*7c478bd9Sstevel@tonic-gate return (EFAULT); 124*7c478bd9Sstevel@tonic-gate buf += 8; 125*7c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 126*7c478bd9Sstevel@tonic-gate return (EFAULT); 127*7c478bd9Sstevel@tonic-gate buf++; 128*7c478bd9Sstevel@tonic-gate if (copyout(utsname.release, buf, 8)) 129*7c478bd9Sstevel@tonic-gate return (EFAULT); 130*7c478bd9Sstevel@tonic-gate buf += 8; 131*7c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 132*7c478bd9Sstevel@tonic-gate return (EFAULT); 133*7c478bd9Sstevel@tonic-gate buf++; 134*7c478bd9Sstevel@tonic-gate if (copyout(utsname.version, buf, 8)) 135*7c478bd9Sstevel@tonic-gate return (EFAULT); 136*7c478bd9Sstevel@tonic-gate buf += 8; 137*7c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 138*7c478bd9Sstevel@tonic-gate return (EFAULT); 139*7c478bd9Sstevel@tonic-gate buf++; 140*7c478bd9Sstevel@tonic-gate if (copyout(utsname.machine, buf, 8)) 141*7c478bd9Sstevel@tonic-gate return (EFAULT); 142*7c478bd9Sstevel@tonic-gate buf += 8; 143*7c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 144*7c478bd9Sstevel@tonic-gate return (EFAULT); 145*7c478bd9Sstevel@tonic-gate rvp->r_val1 = 1; 146*7c478bd9Sstevel@tonic-gate return (0); 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate static int 150*7c478bd9Sstevel@tonic-gate utssys_ustat32(dev_t dev, struct ustat32 *cbuf) 151*7c478bd9Sstevel@tonic-gate { 152*7c478bd9Sstevel@tonic-gate struct ustat32 ust32; 153*7c478bd9Sstevel@tonic-gate struct statvfs64 stvfs; 154*7c478bd9Sstevel@tonic-gate fsblkcnt64_t fsbc64; 155*7c478bd9Sstevel@tonic-gate char *cp, *cp2; 156*7c478bd9Sstevel@tonic-gate int i, error; 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0) 159*7c478bd9Sstevel@tonic-gate return (error); 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512); 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Check to see if the number of free blocks can be expressed 164*7c478bd9Sstevel@tonic-gate * in 31 bits or whether the number of free files is more than 165*7c478bd9Sstevel@tonic-gate * can be expressed in 32 bits and is not -1 (UINT64_MAX). NFS 166*7c478bd9Sstevel@tonic-gate * Version 2 does not support the number of free files and 167*7c478bd9Sstevel@tonic-gate * hence will return -1. -1, when translated from a 32 bit 168*7c478bd9Sstevel@tonic-gate * quantity to an unsigned 64 bit quantity, turns into UINT64_MAX. 169*7c478bd9Sstevel@tonic-gate */ 170*7c478bd9Sstevel@tonic-gate if (fsbc64 > INT32_MAX || 171*7c478bd9Sstevel@tonic-gate (stvfs.f_ffree > UINT32_MAX && stvfs.f_ffree != UINT64_MAX)) 172*7c478bd9Sstevel@tonic-gate return (EOVERFLOW); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate ust32.f_tfree = (daddr32_t)fsbc64; 175*7c478bd9Sstevel@tonic-gate ust32.f_tinode = (ino32_t)stvfs.f_ffree; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate cp = stvfs.f_fstr; 178*7c478bd9Sstevel@tonic-gate cp2 = ust32.f_fname; 179*7c478bd9Sstevel@tonic-gate i = 0; 180*7c478bd9Sstevel@tonic-gate while (i++ < sizeof (ust32.f_fname)) 181*7c478bd9Sstevel@tonic-gate if (*cp != '\0') 182*7c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 183*7c478bd9Sstevel@tonic-gate else 184*7c478bd9Sstevel@tonic-gate *cp2++ = '\0'; 185*7c478bd9Sstevel@tonic-gate while (*cp != '\0' && 186*7c478bd9Sstevel@tonic-gate (i++ < sizeof (stvfs.f_fstr) - sizeof (ust32.f_fpack))) 187*7c478bd9Sstevel@tonic-gate cp++; 188*7c478bd9Sstevel@tonic-gate (void) strncpy(ust32.f_fpack, cp + 1, sizeof (ust32.f_fpack)); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate if (copyout(&ust32, cbuf, sizeof (ust32))) 191*7c478bd9Sstevel@tonic-gate return (EFAULT); 192*7c478bd9Sstevel@tonic-gate return (0); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate #endif /* _ILP32 || _SYSCALL32_IMPL */ 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate #ifdef _LP64 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate static int uts_ustat64(dev_t, struct ustat *); 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate int64_t 202*7c478bd9Sstevel@tonic-gate utssys64(void *buf, long arg, int type, void *outbp) 203*7c478bd9Sstevel@tonic-gate { 204*7c478bd9Sstevel@tonic-gate int error; 205*7c478bd9Sstevel@tonic-gate rval_t rv; 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate rv.r_vals = 0; 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate switch (type) { 210*7c478bd9Sstevel@tonic-gate case UTS_USTAT: 211*7c478bd9Sstevel@tonic-gate error = uts_ustat64((dev_t)arg, buf); 212*7c478bd9Sstevel@tonic-gate break; 213*7c478bd9Sstevel@tonic-gate case UTS_FUSERS: 214*7c478bd9Sstevel@tonic-gate error = uts_fusers(buf, (int)arg, (intptr_t)outbp); 215*7c478bd9Sstevel@tonic-gate break; 216*7c478bd9Sstevel@tonic-gate default: 217*7c478bd9Sstevel@tonic-gate error = EINVAL; 218*7c478bd9Sstevel@tonic-gate break; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate return (error == 0 ? rv.r_vals : (int64_t)set_errno(error)); 222*7c478bd9Sstevel@tonic-gate } 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate static int 225*7c478bd9Sstevel@tonic-gate uts_ustat64(dev_t dev, struct ustat *cbuf) 226*7c478bd9Sstevel@tonic-gate { 227*7c478bd9Sstevel@tonic-gate struct ustat ust; 228*7c478bd9Sstevel@tonic-gate struct statvfs64 stvfs; 229*7c478bd9Sstevel@tonic-gate fsblkcnt64_t fsbc64; 230*7c478bd9Sstevel@tonic-gate char *cp, *cp2; 231*7c478bd9Sstevel@tonic-gate int i, error; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0) 234*7c478bd9Sstevel@tonic-gate return (error); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512); 237*7c478bd9Sstevel@tonic-gate ust.f_tfree = (daddr_t)fsbc64; 238*7c478bd9Sstevel@tonic-gate ust.f_tinode = (ino_t)stvfs.f_ffree; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate cp = stvfs.f_fstr; 241*7c478bd9Sstevel@tonic-gate cp2 = ust.f_fname; 242*7c478bd9Sstevel@tonic-gate i = 0; 243*7c478bd9Sstevel@tonic-gate while (i++ < sizeof (ust.f_fname)) 244*7c478bd9Sstevel@tonic-gate if (*cp != '\0') 245*7c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 246*7c478bd9Sstevel@tonic-gate else 247*7c478bd9Sstevel@tonic-gate *cp2++ = '\0'; 248*7c478bd9Sstevel@tonic-gate while (*cp != '\0' && 249*7c478bd9Sstevel@tonic-gate (i++ < sizeof (stvfs.f_fstr) - sizeof (ust.f_fpack))) 250*7c478bd9Sstevel@tonic-gate cp++; 251*7c478bd9Sstevel@tonic-gate (void) strncpy(ust.f_fpack, cp + 1, sizeof (ust.f_fpack)); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if (copyout(&ust, cbuf, sizeof (ust))) 254*7c478bd9Sstevel@tonic-gate return (EFAULT); 255*7c478bd9Sstevel@tonic-gate return (0); 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate /* 261*7c478bd9Sstevel@tonic-gate * Utility routine for the ustat implementations. 262*7c478bd9Sstevel@tonic-gate * (If it wasn't for the 'find-by-dev_t' semantic of ustat(2), we could push 263*7c478bd9Sstevel@tonic-gate * this all out into userland, sigh.) 264*7c478bd9Sstevel@tonic-gate */ 265*7c478bd9Sstevel@tonic-gate static int 266*7c478bd9Sstevel@tonic-gate _statvfs64_by_dev(dev_t dev, struct statvfs64 *svp) 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate vfs_t *vfsp; 269*7c478bd9Sstevel@tonic-gate int error; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if ((vfsp = vfs_dev2vfsp(dev)) == NULL) { 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * See if it's the root of our zone. 274*7c478bd9Sstevel@tonic-gate */ 275*7c478bd9Sstevel@tonic-gate vfsp = curproc->p_zone->zone_rootvp->v_vfsp; 276*7c478bd9Sstevel@tonic-gate if (vfsp->vfs_dev == dev) { 277*7c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); 278*7c478bd9Sstevel@tonic-gate } else { 279*7c478bd9Sstevel@tonic-gate vfsp = NULL; 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate if (vfsp == NULL) 283*7c478bd9Sstevel@tonic-gate return (EINVAL); 284*7c478bd9Sstevel@tonic-gate error = VFS_STATVFS(vfsp, svp); 285*7c478bd9Sstevel@tonic-gate VFS_RELE(vfsp); 286*7c478bd9Sstevel@tonic-gate return (error); 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate /* 290*7c478bd9Sstevel@tonic-gate * Check if this pid has an NBMAND lock or share reservation 291*7c478bd9Sstevel@tonic-gate * on this vp. llp is a snapshoted list of all NBMAND locks 292*7c478bd9Sstevel@tonic-gate * set by this pid. Return 1 if there is an NBMAND lock else 293*7c478bd9Sstevel@tonic-gate * return 0. 294*7c478bd9Sstevel@tonic-gate */ 295*7c478bd9Sstevel@tonic-gate static int 296*7c478bd9Sstevel@tonic-gate proc_has_nbmand_on_vp(vnode_t *vp, pid_t pid, locklist_t *llp) 297*7c478bd9Sstevel@tonic-gate { 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * Any NBMAND lock held by the process on this vp? 300*7c478bd9Sstevel@tonic-gate */ 301*7c478bd9Sstevel@tonic-gate while (llp) { 302*7c478bd9Sstevel@tonic-gate if (llp->ll_vp == vp) { 303*7c478bd9Sstevel@tonic-gate return (1); 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate llp = llp->ll_next; 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate /* 308*7c478bd9Sstevel@tonic-gate * Any NBMAND share reservation on the vp for this process? 309*7c478bd9Sstevel@tonic-gate */ 310*7c478bd9Sstevel@tonic-gate return (proc_has_nbmand_share_on_vp(vp, pid)); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate static fu_data_t * 314*7c478bd9Sstevel@tonic-gate dofusers(vnode_t *fvp, int flags) 315*7c478bd9Sstevel@tonic-gate { 316*7c478bd9Sstevel@tonic-gate fu_data_t *fu_data; 317*7c478bd9Sstevel@tonic-gate proc_t *prp; 318*7c478bd9Sstevel@tonic-gate vfs_t *cvfsp; 319*7c478bd9Sstevel@tonic-gate pid_t npids, pidx, *pidlist; 320*7c478bd9Sstevel@tonic-gate int v_proc = v.v_proc; /* max # of procs */ 321*7c478bd9Sstevel@tonic-gate int pcnt = 0; 322*7c478bd9Sstevel@tonic-gate int contained = (flags & F_CONTAINED); 323*7c478bd9Sstevel@tonic-gate int nbmandonly = (flags & F_NBMANDLIST); 324*7c478bd9Sstevel@tonic-gate int dip_usage = (flags & F_DEVINFO); 325*7c478bd9Sstevel@tonic-gate int fvp_isdev = vn_matchops(fvp, spec_getvnodeops()); 326*7c478bd9Sstevel@tonic-gate zone_t *zone = curproc->p_zone; 327*7c478bd9Sstevel@tonic-gate int inglobal = INGLOBALZONE(curproc); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* get a pointer to the file system containing this vnode */ 330*7c478bd9Sstevel@tonic-gate cvfsp = fvp->v_vfsp; 331*7c478bd9Sstevel@tonic-gate ASSERT(cvfsp); 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate /* allocate the data structure to return our results in */ 334*7c478bd9Sstevel@tonic-gate fu_data = kmem_alloc(fu_data_size(v_proc), KM_SLEEP); 335*7c478bd9Sstevel@tonic-gate fu_data->fud_user_max = v_proc; 336*7c478bd9Sstevel@tonic-gate fu_data->fud_user_count = 0; 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* get a snapshot of all the pids we're going to check out */ 339*7c478bd9Sstevel@tonic-gate pidlist = kmem_alloc(v_proc * sizeof (pid_t), KM_SLEEP); 340*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 341*7c478bd9Sstevel@tonic-gate for (npids = 0, prp = practive; prp != NULL; prp = prp->p_next) { 342*7c478bd9Sstevel@tonic-gate if (inglobal || prp->p_zone == zone) 343*7c478bd9Sstevel@tonic-gate pidlist[npids++] = prp->p_pid; 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate /* grab each process and check its file usage */ 348*7c478bd9Sstevel@tonic-gate for (pidx = 0; pidx < npids; pidx++) { 349*7c478bd9Sstevel@tonic-gate locklist_t *llp = NULL; 350*7c478bd9Sstevel@tonic-gate uf_info_t *fip; 351*7c478bd9Sstevel@tonic-gate vnode_t *vp; 352*7c478bd9Sstevel@tonic-gate user_t *up; 353*7c478bd9Sstevel@tonic-gate sess_t *sp; 354*7c478bd9Sstevel@tonic-gate uid_t uid; 355*7c478bd9Sstevel@tonic-gate pid_t pid = pidlist[pidx]; 356*7c478bd9Sstevel@tonic-gate int i, use_flag = 0; 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* 359*7c478bd9Sstevel@tonic-gate * grab prp->p_lock using sprlock() 360*7c478bd9Sstevel@tonic-gate * if sprlock() fails the process does not exists anymore 361*7c478bd9Sstevel@tonic-gate */ 362*7c478bd9Sstevel@tonic-gate prp = sprlock(pid); 363*7c478bd9Sstevel@tonic-gate if (prp == NULL) 364*7c478bd9Sstevel@tonic-gate continue; 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate /* get the processes credential info in case we need it */ 367*7c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_crlock); 368*7c478bd9Sstevel@tonic-gate uid = crgetruid(prp->p_cred); 369*7c478bd9Sstevel@tonic-gate mutex_exit(&prp->p_crlock); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * it's safe to drop p_lock here because we 373*7c478bd9Sstevel@tonic-gate * called sprlock() before and it set the SPRLOCK 374*7c478bd9Sstevel@tonic-gate * flag for the process so it won't go away. 375*7c478bd9Sstevel@tonic-gate */ 376*7c478bd9Sstevel@tonic-gate mutex_exit(&prp->p_lock); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* 379*7c478bd9Sstevel@tonic-gate * now we want to walk a processes open file descriptors 380*7c478bd9Sstevel@tonic-gate * to do this we need to grab the fip->fi_lock. (you 381*7c478bd9Sstevel@tonic-gate * can't hold p_lock when grabbing the fip->fi_lock.) 382*7c478bd9Sstevel@tonic-gate */ 383*7c478bd9Sstevel@tonic-gate fip = P_FINFO(prp); 384*7c478bd9Sstevel@tonic-gate mutex_enter(&fip->fi_lock); 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate /* 387*7c478bd9Sstevel@tonic-gate * Snapshot nbmand locks for pid 388*7c478bd9Sstevel@tonic-gate */ 389*7c478bd9Sstevel@tonic-gate llp = flk_active_nbmand_locks(prp->p_pid); 390*7c478bd9Sstevel@tonic-gate for (i = 0; i < fip->fi_nfiles; i++) { 391*7c478bd9Sstevel@tonic-gate uf_entry_t *ufp; 392*7c478bd9Sstevel@tonic-gate file_t *fp; 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate UF_ENTER(ufp, fip, i); 395*7c478bd9Sstevel@tonic-gate if (((fp = ufp->uf_file) == NULL) || 396*7c478bd9Sstevel@tonic-gate ((vp = fp->f_vnode) == NULL)) { 397*7c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 398*7c478bd9Sstevel@tonic-gate continue; 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device 403*7c478bd9Sstevel@tonic-gate * and corrosponds to the root of a filesystem 404*7c478bd9Sstevel@tonic-gate * (cvfsp), then check if it contains the file 405*7c478bd9Sstevel@tonic-gate * is use by this process (vp). 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate if (contained && (vp->v_vfsp == cvfsp)) 408*7c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate /* 411*7c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device, 412*7c478bd9Sstevel@tonic-gate * then check if it matches the file in use 413*7c478bd9Sstevel@tonic-gate * by this process (vp). 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate if (!fvp_isdev && VN_CMP(fvp, vp)) 416*7c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate /* 419*7c478bd9Sstevel@tonic-gate * if the target file (fvp) is a device, 420*7c478bd9Sstevel@tonic-gate * then check if the current file in use 421*7c478bd9Sstevel@tonic-gate * by this process (vp) maps to the same device 422*7c478bd9Sstevel@tonic-gate * minor node. 423*7c478bd9Sstevel@tonic-gate */ 424*7c478bd9Sstevel@tonic-gate if (fvp_isdev && 425*7c478bd9Sstevel@tonic-gate vn_matchops(vp, spec_getvnodeops()) && 426*7c478bd9Sstevel@tonic-gate (fvp->v_rdev == vp->v_rdev)) 427*7c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate /* 430*7c478bd9Sstevel@tonic-gate * if the target file (fvp) is a device, 431*7c478bd9Sstevel@tonic-gate * and we're checking for device instance 432*7c478bd9Sstevel@tonic-gate * usage, then check if the current file in use 433*7c478bd9Sstevel@tonic-gate * by this process (vp) maps to the same device 434*7c478bd9Sstevel@tonic-gate * instance. 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate if (dip_usage && 437*7c478bd9Sstevel@tonic-gate vn_matchops(vp, spec_getvnodeops()) && 438*7c478bd9Sstevel@tonic-gate (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) 439*7c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* 442*7c478bd9Sstevel@tonic-gate * if the current file in use by this process (vp) 443*7c478bd9Sstevel@tonic-gate * doesn't match what we're looking for, move on 444*7c478bd9Sstevel@tonic-gate * to the next file in the process. 445*7c478bd9Sstevel@tonic-gate */ 446*7c478bd9Sstevel@tonic-gate if ((use_flag & F_OPEN) == 0) { 447*7c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 448*7c478bd9Sstevel@tonic-gate continue; 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate if (proc_has_nbmand_on_vp(vp, prp->p_pid, llp)) { 452*7c478bd9Sstevel@tonic-gate /* A nbmand found so we're done. */ 453*7c478bd9Sstevel@tonic-gate use_flag |= F_NBM; 454*7c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 455*7c478bd9Sstevel@tonic-gate break; 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate if (llp) 460*7c478bd9Sstevel@tonic-gate flk_free_locklist(llp); 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate mutex_exit(&fip->fi_lock); 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /* 465*7c478bd9Sstevel@tonic-gate * If nbmand usage tracking is desired and no nbmand was 466*7c478bd9Sstevel@tonic-gate * found for this process, then no need to do further 467*7c478bd9Sstevel@tonic-gate * usage tracking for this process. 468*7c478bd9Sstevel@tonic-gate */ 469*7c478bd9Sstevel@tonic-gate if (nbmandonly && (!(use_flag & F_NBM))) { 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * grab the process lock again, clear the SPRLOCK 472*7c478bd9Sstevel@tonic-gate * flag, release the process, and continue. 473*7c478bd9Sstevel@tonic-gate */ 474*7c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_lock); 475*7c478bd9Sstevel@tonic-gate sprunlock(prp); 476*7c478bd9Sstevel@tonic-gate continue; 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * All other types of usage. 481*7c478bd9Sstevel@tonic-gate * For the next few checks we need to hold p_lock. 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_lock); 484*7c478bd9Sstevel@tonic-gate up = PTOU(prp); 485*7c478bd9Sstevel@tonic-gate if (fvp_isdev) { 486*7c478bd9Sstevel@tonic-gate /* 487*7c478bd9Sstevel@tonic-gate * if the target file (fvp) is a device 488*7c478bd9Sstevel@tonic-gate * then check if it matches the processes tty 489*7c478bd9Sstevel@tonic-gate * 490*7c478bd9Sstevel@tonic-gate * we grab s_lock to protect ourselves against 491*7c478bd9Sstevel@tonic-gate * freectty() freeing the vnode out from under us. 492*7c478bd9Sstevel@tonic-gate */ 493*7c478bd9Sstevel@tonic-gate sp = prp->p_sessp; 494*7c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 495*7c478bd9Sstevel@tonic-gate vp = prp->p_sessp->s_vp; 496*7c478bd9Sstevel@tonic-gate if (vp != NULL) { 497*7c478bd9Sstevel@tonic-gate if (fvp->v_rdev == vp->v_rdev) 498*7c478bd9Sstevel@tonic-gate use_flag |= F_TTY; 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate if (dip_usage && 501*7c478bd9Sstevel@tonic-gate (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) 502*7c478bd9Sstevel@tonic-gate use_flag |= F_TTY; 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 505*7c478bd9Sstevel@tonic-gate } else { 506*7c478bd9Sstevel@tonic-gate /* check the processes current working directory */ 507*7c478bd9Sstevel@tonic-gate if (up->u_cdir && 508*7c478bd9Sstevel@tonic-gate (VN_CMP(fvp, up->u_cdir) || 509*7c478bd9Sstevel@tonic-gate (contained && (up->u_cdir->v_vfsp == cvfsp)))) 510*7c478bd9Sstevel@tonic-gate use_flag |= F_CDIR; 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate /* check the processes root directory */ 513*7c478bd9Sstevel@tonic-gate if (up->u_rdir && 514*7c478bd9Sstevel@tonic-gate (VN_CMP(fvp, up->u_rdir) || 515*7c478bd9Sstevel@tonic-gate (contained && (up->u_rdir->v_vfsp == cvfsp)))) 516*7c478bd9Sstevel@tonic-gate use_flag |= F_RDIR; 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate /* check the program text vnode */ 519*7c478bd9Sstevel@tonic-gate if (prp->p_exec && 520*7c478bd9Sstevel@tonic-gate (VN_CMP(fvp, prp->p_exec) || 521*7c478bd9Sstevel@tonic-gate (contained && (prp->p_exec->v_vfsp == cvfsp)))) 522*7c478bd9Sstevel@tonic-gate use_flag |= F_TEXT; 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* Now we can drop p_lock again */ 526*7c478bd9Sstevel@tonic-gate mutex_exit(&prp->p_lock); 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * now we want to walk a processes memory mappings. 530*7c478bd9Sstevel@tonic-gate * to do this we need to grab the prp->p_as lock. (you 531*7c478bd9Sstevel@tonic-gate * can't hold p_lock when grabbing the prp->p_as lock.) 532*7c478bd9Sstevel@tonic-gate */ 533*7c478bd9Sstevel@tonic-gate if (prp->p_as != &kas) { 534*7c478bd9Sstevel@tonic-gate struct seg *seg; 535*7c478bd9Sstevel@tonic-gate struct as *as = prp->p_as; 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 538*7c478bd9Sstevel@tonic-gate for (seg = AS_SEGFIRST(as); seg; 539*7c478bd9Sstevel@tonic-gate seg = AS_SEGNEXT(as, seg)) { 540*7c478bd9Sstevel@tonic-gate /* 541*7c478bd9Sstevel@tonic-gate * if we can't get a backing vnode for this 542*7c478bd9Sstevel@tonic-gate * segment then skip it 543*7c478bd9Sstevel@tonic-gate */ 544*7c478bd9Sstevel@tonic-gate vp = NULL; 545*7c478bd9Sstevel@tonic-gate if ((SEGOP_GETVP(seg, seg->s_base, &vp)) || 546*7c478bd9Sstevel@tonic-gate (vp == NULL)) 547*7c478bd9Sstevel@tonic-gate continue; 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate /* 550*7c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device 551*7c478bd9Sstevel@tonic-gate * and corrosponds to the root of a filesystem 552*7c478bd9Sstevel@tonic-gate * (cvfsp), then check if it contains the 553*7c478bd9Sstevel@tonic-gate * vnode backing this segment (vp). 554*7c478bd9Sstevel@tonic-gate */ 555*7c478bd9Sstevel@tonic-gate if (contained && (vp->v_vfsp == cvfsp)) { 556*7c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 557*7c478bd9Sstevel@tonic-gate break; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device, 562*7c478bd9Sstevel@tonic-gate * check if it matches the the vnode backing 563*7c478bd9Sstevel@tonic-gate * this segment (vp). 564*7c478bd9Sstevel@tonic-gate */ 565*7c478bd9Sstevel@tonic-gate if (!fvp_isdev && VN_CMP(fvp, vp)) { 566*7c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 567*7c478bd9Sstevel@tonic-gate break; 568*7c478bd9Sstevel@tonic-gate } 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate /* 571*7c478bd9Sstevel@tonic-gate * if the target file (fvp) isn't a device, 572*7c478bd9Sstevel@tonic-gate * or the the vnode backing this segment (vp) 573*7c478bd9Sstevel@tonic-gate * isn't a device then continue. 574*7c478bd9Sstevel@tonic-gate */ 575*7c478bd9Sstevel@tonic-gate if (!fvp_isdev || 576*7c478bd9Sstevel@tonic-gate !vn_matchops(vp, spec_getvnodeops())) 577*7c478bd9Sstevel@tonic-gate continue; 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate /* 580*7c478bd9Sstevel@tonic-gate * check if the vnode backing this segment 581*7c478bd9Sstevel@tonic-gate * (vp) maps to the same device minor node 582*7c478bd9Sstevel@tonic-gate * as the target device (fvp) 583*7c478bd9Sstevel@tonic-gate */ 584*7c478bd9Sstevel@tonic-gate if (fvp->v_rdev == vp->v_rdev) { 585*7c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 586*7c478bd9Sstevel@tonic-gate break; 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /* 590*7c478bd9Sstevel@tonic-gate * if we're checking for device instance 591*7c478bd9Sstevel@tonic-gate * usage, then check if the vnode backing 592*7c478bd9Sstevel@tonic-gate * this segment (vp) maps to the same device 593*7c478bd9Sstevel@tonic-gate * instance as the target device (fvp). 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate if (dip_usage && 596*7c478bd9Sstevel@tonic-gate (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) { 597*7c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 598*7c478bd9Sstevel@tonic-gate break; 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 602*7c478bd9Sstevel@tonic-gate } 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate if (use_flag) { 605*7c478bd9Sstevel@tonic-gate ASSERT(pcnt < fu_data->fud_user_max); 606*7c478bd9Sstevel@tonic-gate fu_data->fud_user[pcnt].fu_flags = use_flag; 607*7c478bd9Sstevel@tonic-gate fu_data->fud_user[pcnt].fu_pid = pid; 608*7c478bd9Sstevel@tonic-gate fu_data->fud_user[pcnt].fu_uid = uid; 609*7c478bd9Sstevel@tonic-gate pcnt++; 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* 613*7c478bd9Sstevel@tonic-gate * grab the process lock again, clear the SPRLOCK 614*7c478bd9Sstevel@tonic-gate * flag, release the process, and continue. 615*7c478bd9Sstevel@tonic-gate */ 616*7c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_lock); 617*7c478bd9Sstevel@tonic-gate sprunlock(prp); 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate kmem_free(pidlist, v_proc * sizeof (pid_t)); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate fu_data->fud_user_count = pcnt; 623*7c478bd9Sstevel@tonic-gate return (fu_data); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate typedef struct dofkusers_arg { 627*7c478bd9Sstevel@tonic-gate vnode_t *fvp; 628*7c478bd9Sstevel@tonic-gate int flags; 629*7c478bd9Sstevel@tonic-gate int *error; 630*7c478bd9Sstevel@tonic-gate fu_data_t *fu_data; 631*7c478bd9Sstevel@tonic-gate } dofkusers_arg_t; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate static int 634*7c478bd9Sstevel@tonic-gate dofkusers_walker(const ldi_usage_t *ldi_usage, void *arg) 635*7c478bd9Sstevel@tonic-gate { 636*7c478bd9Sstevel@tonic-gate dofkusers_arg_t *dofkusers_arg = (dofkusers_arg_t *)arg; 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate vnode_t *fvp = dofkusers_arg->fvp; 639*7c478bd9Sstevel@tonic-gate int flags = dofkusers_arg->flags; 640*7c478bd9Sstevel@tonic-gate int *error = dofkusers_arg->error; 641*7c478bd9Sstevel@tonic-gate fu_data_t *fu_data = dofkusers_arg->fu_data; 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate modid_t modid; 644*7c478bd9Sstevel@tonic-gate minor_t minor; 645*7c478bd9Sstevel@tonic-gate int instance; 646*7c478bd9Sstevel@tonic-gate int dip_usage = (flags & F_DEVINFO); 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate ASSERT(*error == 0); 649*7c478bd9Sstevel@tonic-gate ASSERT(vn_matchops(fvp, spec_getvnodeops())); 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* 652*7c478bd9Sstevel@tonic-gate * check if the dev_t of the target device matches the dev_t 653*7c478bd9Sstevel@tonic-gate * of the device we're trying to find usage info for. 654*7c478bd9Sstevel@tonic-gate */ 655*7c478bd9Sstevel@tonic-gate if (fvp->v_rdev != ldi_usage->tgt_devt) { 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate /* 658*7c478bd9Sstevel@tonic-gate * if the dev_ts don't match and we're not trying 659*7c478bd9Sstevel@tonic-gate * to find usage information for device instances 660*7c478bd9Sstevel@tonic-gate * then return 661*7c478bd9Sstevel@tonic-gate */ 662*7c478bd9Sstevel@tonic-gate if (!dip_usage) 663*7c478bd9Sstevel@tonic-gate return (LDI_USAGE_CONTINUE); 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate 666*7c478bd9Sstevel@tonic-gate /* 667*7c478bd9Sstevel@tonic-gate * we're trying to find usage information for an 668*7c478bd9Sstevel@tonic-gate * device instance instead of just a minor node. 669*7c478bd9Sstevel@tonic-gate * 670*7c478bd9Sstevel@tonic-gate * check if the dip for the target device matches the 671*7c478bd9Sstevel@tonic-gate * dip of the device we're trying to find usage info for. 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate if (VTOCS(fvp)->s_dip != ldi_usage->tgt_dip) 674*7c478bd9Sstevel@tonic-gate return (LDI_USAGE_CONTINUE); 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate if (fu_data->fud_user_count >= fu_data->fud_user_max) { 678*7c478bd9Sstevel@tonic-gate *error = E2BIG; 679*7c478bd9Sstevel@tonic-gate return (LDI_USAGE_TERMINATE); 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* get the device vnode user information */ 683*7c478bd9Sstevel@tonic-gate modid = ldi_usage->src_modid; 684*7c478bd9Sstevel@tonic-gate ASSERT(modid != -1); 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate minor = instance = -1; 687*7c478bd9Sstevel@tonic-gate if (ldi_usage->src_dip != NULL) { 688*7c478bd9Sstevel@tonic-gate instance = DEVI(ldi_usage->src_dip)->devi_instance; 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate if (ldi_usage->src_devt != DDI_DEV_T_NONE) { 691*7c478bd9Sstevel@tonic-gate minor = getminor(ldi_usage->src_devt); 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* set the device vnode user information */ 695*7c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_flags = F_KERNEL; 696*7c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_modid = modid; 697*7c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_instance = instance; 698*7c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_minor = minor; 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate fu_data->fud_user_count++; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate return (LDI_USAGE_CONTINUE); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate int 706*7c478bd9Sstevel@tonic-gate f_user_cmp(const void *arg1, const void *arg2) 707*7c478bd9Sstevel@tonic-gate { 708*7c478bd9Sstevel@tonic-gate f_user_t *f_user1 = (f_user_t *)arg1; 709*7c478bd9Sstevel@tonic-gate f_user_t *f_user2 = (f_user_t *)arg2; 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate /* 712*7c478bd9Sstevel@tonic-gate * we should only be called for f_user_t entires that represent 713*7c478bd9Sstevel@tonic-gate * a kernel file consumer 714*7c478bd9Sstevel@tonic-gate */ 715*7c478bd9Sstevel@tonic-gate ASSERT(f_user1->fu_flags & F_KERNEL); 716*7c478bd9Sstevel@tonic-gate ASSERT(f_user2->fu_flags & F_KERNEL); 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate if (f_user1->fu_modid != f_user2->fu_modid) 719*7c478bd9Sstevel@tonic-gate return ((f_user1->fu_modid < f_user2->fu_modid) ? -1 : 1); 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate if (f_user1->fu_instance != f_user2->fu_instance) 722*7c478bd9Sstevel@tonic-gate return ((f_user1->fu_instance < f_user2->fu_instance) ? -1 : 1); 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate if (f_user1->fu_minor != f_user2->fu_minor) 725*7c478bd9Sstevel@tonic-gate return ((f_user1->fu_minor < f_user2->fu_minor) ? -1 : 1); 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate return (0); 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate static fu_data_t * 731*7c478bd9Sstevel@tonic-gate dofkusers(vnode_t *fvp, int flags, int *error) 732*7c478bd9Sstevel@tonic-gate { 733*7c478bd9Sstevel@tonic-gate dofkusers_arg_t dofkusers_arg; 734*7c478bd9Sstevel@tonic-gate fu_data_t *fu_data; 735*7c478bd9Sstevel@tonic-gate int user_max, i; 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate /* 738*7c478bd9Sstevel@tonic-gate * we only keep track of kernel device consumers, so if the 739*7c478bd9Sstevel@tonic-gate * target vnode isn't a device then there's nothing to do here 740*7c478bd9Sstevel@tonic-gate */ 741*7c478bd9Sstevel@tonic-gate if (!vn_matchops(fvp, spec_getvnodeops())) 742*7c478bd9Sstevel@tonic-gate return (NULL); 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate /* allocate the data structure to return our results in */ 745*7c478bd9Sstevel@tonic-gate user_max = ldi_usage_count(); 746*7c478bd9Sstevel@tonic-gate fu_data = kmem_alloc(fu_data_size(user_max), KM_SLEEP); 747*7c478bd9Sstevel@tonic-gate fu_data->fud_user_max = user_max; 748*7c478bd9Sstevel@tonic-gate fu_data->fud_user_count = 0; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate /* invoke the callback to collect device usage information */ 751*7c478bd9Sstevel@tonic-gate dofkusers_arg.fvp = fvp; 752*7c478bd9Sstevel@tonic-gate dofkusers_arg.flags = flags; 753*7c478bd9Sstevel@tonic-gate dofkusers_arg.error = error; 754*7c478bd9Sstevel@tonic-gate dofkusers_arg.fu_data = fu_data; 755*7c478bd9Sstevel@tonic-gate ldi_usage_walker(&dofkusers_arg, dofkusers_walker); 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate /* check for errors */ 758*7c478bd9Sstevel@tonic-gate if (*error != 0) 759*7c478bd9Sstevel@tonic-gate return (fu_data); 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* if there aren't any file consumers then return */ 762*7c478bd9Sstevel@tonic-gate if (fu_data->fud_user_count == 0) 763*7c478bd9Sstevel@tonic-gate return (fu_data); 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate /* 766*7c478bd9Sstevel@tonic-gate * since we ignore the spec_type of the target we're trying to 767*7c478bd9Sstevel@tonic-gate * access it's possible that we could have duplicates entries in 768*7c478bd9Sstevel@tonic-gate * the list of consumers. 769*7c478bd9Sstevel@tonic-gate * 770*7c478bd9Sstevel@tonic-gate * we don't want to check for duplicate in the callback because 771*7c478bd9Sstevel@tonic-gate * we're holding locks in the ldi when the callback is invoked. 772*7c478bd9Sstevel@tonic-gate * 773*7c478bd9Sstevel@tonic-gate * so here we need to go through the array of file consumers 774*7c478bd9Sstevel@tonic-gate * and remove duplicate entries. 775*7c478bd9Sstevel@tonic-gate */ 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate /* first sort the array of file consumers */ 778*7c478bd9Sstevel@tonic-gate qsort((caddr_t)fu_data->fud_user, fu_data->fud_user_count, 779*7c478bd9Sstevel@tonic-gate sizeof (f_user_t), f_user_cmp); 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate /* then remove any duplicate entires */ 782*7c478bd9Sstevel@tonic-gate i = 1; 783*7c478bd9Sstevel@tonic-gate while (i < fu_data->fud_user_count) { 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate if (f_user_cmp(&fu_data->fud_user[i], 786*7c478bd9Sstevel@tonic-gate &fu_data->fud_user[i - 1]) != 0) { 787*7c478bd9Sstevel@tonic-gate /* 788*7c478bd9Sstevel@tonic-gate * the current element is unique, move onto 789*7c478bd9Sstevel@tonic-gate * the next one 790*7c478bd9Sstevel@tonic-gate */ 791*7c478bd9Sstevel@tonic-gate i++; 792*7c478bd9Sstevel@tonic-gate continue; 793*7c478bd9Sstevel@tonic-gate } 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate /* 796*7c478bd9Sstevel@tonic-gate * this entry is a duplicate so if it's not the last 797*7c478bd9Sstevel@tonic-gate * entry in the array then remove it. 798*7c478bd9Sstevel@tonic-gate */ 799*7c478bd9Sstevel@tonic-gate fu_data->fud_user_count--; 800*7c478bd9Sstevel@tonic-gate if (i == fu_data->fud_user_count) 801*7c478bd9Sstevel@tonic-gate break; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate bcopy(&fu_data->fud_user[i + 1], &fu_data->fud_user[i], 804*7c478bd9Sstevel@tonic-gate sizeof (f_user_t) * (fu_data->fud_user_count - i)); 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate return (fu_data); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate /* 811*7c478bd9Sstevel@tonic-gate * Determine the ways in which processes and the kernel are using a named 812*7c478bd9Sstevel@tonic-gate * file or mounted file system (path). Normally return 0. In case of an 813*7c478bd9Sstevel@tonic-gate * error appropriate errno will be returned. 814*7c478bd9Sstevel@tonic-gate * 815*7c478bd9Sstevel@tonic-gate * Upon success, uts_fusers will also copyout the file usage information 816*7c478bd9Sstevel@tonic-gate * in the form of an array of f_user_t's that are contained within an 817*7c478bd9Sstevel@tonic-gate * fu_data_t pointed to by userbp. 818*7c478bd9Sstevel@tonic-gate */ 819*7c478bd9Sstevel@tonic-gate static int 820*7c478bd9Sstevel@tonic-gate uts_fusers(char *path, int flags, intptr_t userbp) 821*7c478bd9Sstevel@tonic-gate { 822*7c478bd9Sstevel@tonic-gate fu_data_t *fu_data = NULL, *fuk_data = NULL; 823*7c478bd9Sstevel@tonic-gate fu_data_t fu_header; 824*7c478bd9Sstevel@tonic-gate vnode_t *fvp = NULL; 825*7c478bd9Sstevel@tonic-gate size_t bcount; 826*7c478bd9Sstevel@tonic-gate int error = 0; 827*7c478bd9Sstevel@tonic-gate int total_max, total_out; 828*7c478bd9Sstevel@tonic-gate int contained = (flags & F_CONTAINED); 829*7c478bd9Sstevel@tonic-gate int dip_usage = (flags & F_DEVINFO); 830*7c478bd9Sstevel@tonic-gate int fvp_isdev; 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate /* figure out how man f_user_t's we can safetly copy out */ 834*7c478bd9Sstevel@tonic-gate if (copyin((const void *)userbp, &total_max, sizeof (total_max))) 835*7c478bd9Sstevel@tonic-gate return (EFAULT); 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate /* 838*7c478bd9Sstevel@tonic-gate * check if we only want a count of how many kernel device 839*7c478bd9Sstevel@tonic-gate * consumers exist 840*7c478bd9Sstevel@tonic-gate */ 841*7c478bd9Sstevel@tonic-gate if (flags & F_KINFO_COUNT) { 842*7c478bd9Sstevel@tonic-gate fu_header.fud_user_max = total_max; 843*7c478bd9Sstevel@tonic-gate fu_header.fud_user_count = ldi_usage_count(); 844*7c478bd9Sstevel@tonic-gate bcount = fu_data_size(0); 845*7c478bd9Sstevel@tonic-gate if (copyout(&fu_header, (void *)userbp, bcount)) 846*7c478bd9Sstevel@tonic-gate return (EFAULT); 847*7c478bd9Sstevel@tonic-gate return (0); 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate /* get the vnode for the file we want to look up usage for */ 851*7c478bd9Sstevel@tonic-gate error = lookupname(path, UIO_USERSPACE, FOLLOW, NULLVPP, &fvp); 852*7c478bd9Sstevel@tonic-gate if (error != 0) 853*7c478bd9Sstevel@tonic-gate return (error); 854*7c478bd9Sstevel@tonic-gate ASSERT(fvp); 855*7c478bd9Sstevel@tonic-gate fvp_isdev = vn_matchops(fvp, spec_getvnodeops()); 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate /* 858*7c478bd9Sstevel@tonic-gate * if we want to report usage for all files contained within a 859*7c478bd9Sstevel@tonic-gate * file system then the target file better correspond to the 860*7c478bd9Sstevel@tonic-gate * root node of a mounted file system, or the root of a zone. 861*7c478bd9Sstevel@tonic-gate */ 862*7c478bd9Sstevel@tonic-gate if (contained && !(fvp->v_flag & VROOT) && 863*7c478bd9Sstevel@tonic-gate fvp != curproc->p_zone->zone_rootvp) { 864*7c478bd9Sstevel@tonic-gate error = EINVAL; 865*7c478bd9Sstevel@tonic-gate goto out; 866*7c478bd9Sstevel@tonic-gate } 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate /* 869*7c478bd9Sstevel@tonic-gate * if we want to report usage for all files contained within a 870*7c478bd9Sstevel@tonic-gate * file system then the target file better not be a device. 871*7c478bd9Sstevel@tonic-gate */ 872*7c478bd9Sstevel@tonic-gate if (contained && fvp_isdev) { 873*7c478bd9Sstevel@tonic-gate error = EINVAL; 874*7c478bd9Sstevel@tonic-gate goto out; 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate /* 878*7c478bd9Sstevel@tonic-gate * if we want to report usage for a device instance then the 879*7c478bd9Sstevel@tonic-gate * target file better corrospond to a device 880*7c478bd9Sstevel@tonic-gate */ 881*7c478bd9Sstevel@tonic-gate if (dip_usage && !fvp_isdev) { 882*7c478bd9Sstevel@tonic-gate error = EINVAL; 883*7c478bd9Sstevel@tonic-gate goto out; 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate /* 887*7c478bd9Sstevel@tonic-gate * if the target vnode isn't a device and it has a reference count 888*7c478bd9Sstevel@tonic-gate * of one then no one else is going to have it open so we don't 889*7c478bd9Sstevel@tonic-gate * have any work to do. 890*7c478bd9Sstevel@tonic-gate */ 891*7c478bd9Sstevel@tonic-gate if (!fvp_isdev && (fvp->v_count == 1)) { 892*7c478bd9Sstevel@tonic-gate goto out; 893*7c478bd9Sstevel@tonic-gate } 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate /* look up usage information for this vnode */ 896*7c478bd9Sstevel@tonic-gate fu_data = dofusers(fvp, flags); 897*7c478bd9Sstevel@tonic-gate fuk_data = dofkusers(fvp, flags, &error); 898*7c478bd9Sstevel@tonic-gate if (error != 0) 899*7c478bd9Sstevel@tonic-gate goto out; 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /* get a count of the number of f_user_t's we need to copy out */ 902*7c478bd9Sstevel@tonic-gate total_out = 0; 903*7c478bd9Sstevel@tonic-gate if (fu_data) 904*7c478bd9Sstevel@tonic-gate total_out += fu_data->fud_user_count; 905*7c478bd9Sstevel@tonic-gate if (fuk_data) 906*7c478bd9Sstevel@tonic-gate total_out += fuk_data->fud_user_count; 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate /* check if there is enough space to copyout all results */ 909*7c478bd9Sstevel@tonic-gate if (total_out > total_max) { 910*7c478bd9Sstevel@tonic-gate error = E2BIG; 911*7c478bd9Sstevel@tonic-gate goto out; 912*7c478bd9Sstevel@tonic-gate } 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* copyout file usage info counts */ 915*7c478bd9Sstevel@tonic-gate fu_header.fud_user_max = total_max; 916*7c478bd9Sstevel@tonic-gate fu_header.fud_user_count = total_out; 917*7c478bd9Sstevel@tonic-gate bcount = fu_data_size(0); 918*7c478bd9Sstevel@tonic-gate if (copyout(&fu_header, (void *)userbp, bcount)) { 919*7c478bd9Sstevel@tonic-gate error = EFAULT; 920*7c478bd9Sstevel@tonic-gate goto out; 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate /* copyout userland process file usage info */ 924*7c478bd9Sstevel@tonic-gate if ((fu_data != NULL) && (fu_data->fud_user_count > 0)) { 925*7c478bd9Sstevel@tonic-gate userbp += bcount; 926*7c478bd9Sstevel@tonic-gate bcount = fu_data->fud_user_count * sizeof (f_user_t); 927*7c478bd9Sstevel@tonic-gate if (copyout(fu_data->fud_user, (void *)userbp, bcount)) { 928*7c478bd9Sstevel@tonic-gate error = EFAULT; 929*7c478bd9Sstevel@tonic-gate goto out; 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate } 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate /* copyout kernel file usage info */ 934*7c478bd9Sstevel@tonic-gate if ((fuk_data != NULL) && (fuk_data->fud_user_count > 0)) { 935*7c478bd9Sstevel@tonic-gate userbp += bcount; 936*7c478bd9Sstevel@tonic-gate bcount = fuk_data->fud_user_count * sizeof (f_user_t); 937*7c478bd9Sstevel@tonic-gate if (copyout(fuk_data->fud_user, (void *)userbp, bcount)) { 938*7c478bd9Sstevel@tonic-gate error = EFAULT; 939*7c478bd9Sstevel@tonic-gate goto out; 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate out: 944*7c478bd9Sstevel@tonic-gate /* release the vnode that we were looking up usage for */ 945*7c478bd9Sstevel@tonic-gate VN_RELE(fvp); 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate /* release any allocated memory */ 948*7c478bd9Sstevel@tonic-gate if (fu_data) 949*7c478bd9Sstevel@tonic-gate kmem_free(fu_data, fu_data_size(fu_data->fud_user_max)); 950*7c478bd9Sstevel@tonic-gate if (fuk_data) 951*7c478bd9Sstevel@tonic-gate kmem_free(fuk_data, fu_data_size(fuk_data->fud_user_max)); 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate return (error); 954*7c478bd9Sstevel@tonic-gate } 955