17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate 237c478bd9Sstevel@tonic-gate /* 247c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 297c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 367c478bd9Sstevel@tonic-gate #include <sys/systm.h> 377c478bd9Sstevel@tonic-gate #include <sys/user.h> 387c478bd9Sstevel@tonic-gate #include <sys/errno.h> 397c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 407c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 417c478bd9Sstevel@tonic-gate #include <sys/file.h> 427c478bd9Sstevel@tonic-gate #include <sys/proc.h> 437c478bd9Sstevel@tonic-gate #include <sys/session.h> 447c478bd9Sstevel@tonic-gate #include <sys/var.h> 457c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 467c478bd9Sstevel@tonic-gate #include <sys/utssys.h> 477c478bd9Sstevel@tonic-gate #include <sys/ustat.h> 487c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 497c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 507c478bd9Sstevel@tonic-gate #include <sys/debug.h> 517c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 527c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 537c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 547c478bd9Sstevel@tonic-gate #include <sys/sunldi_impl.h> 557c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 567c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 587c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 597c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 607c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 617c478bd9Sstevel@tonic-gate #include <sys/flock.h> 627c478bd9Sstevel@tonic-gate #include <sys/share.h> 637c478bd9Sstevel@tonic-gate #include <vm/as.h> 647c478bd9Sstevel@tonic-gate #include <vm/seg.h> 657c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h> 667c478bd9Sstevel@tonic-gate #include <util/qsort.h> 677c478bd9Sstevel@tonic-gate #include <sys/zone.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * utssys() 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate static int uts_fusers(char *, int, intptr_t); 737c478bd9Sstevel@tonic-gate static int _statvfs64_by_dev(dev_t, struct statvfs64 *); 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate static int utssys_uname32(caddr_t, rval_t *); 787c478bd9Sstevel@tonic-gate static int utssys_ustat32(dev_t, struct ustat32 *); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate int64_t 817c478bd9Sstevel@tonic-gate utssys32(void *buf, int arg, int type, void *outbp) 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate int error; 847c478bd9Sstevel@tonic-gate rval_t rv; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate rv.r_vals = 0; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate switch (type) { 897c478bd9Sstevel@tonic-gate case UTS_UNAME: 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * This is an obsolete way to get the utsname structure 927c478bd9Sstevel@tonic-gate * (it only gives you the first 8 characters of each field!) 937c478bd9Sstevel@tonic-gate * uname(2) is the preferred and better interface. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate error = utssys_uname32(buf, &rv); 967c478bd9Sstevel@tonic-gate break; 977c478bd9Sstevel@tonic-gate case UTS_USTAT: 987c478bd9Sstevel@tonic-gate error = utssys_ustat32(expldev((dev32_t)arg), buf); 997c478bd9Sstevel@tonic-gate break; 1007c478bd9Sstevel@tonic-gate case UTS_FUSERS: 1017c478bd9Sstevel@tonic-gate error = uts_fusers(buf, arg, (intptr_t)outbp); 1027c478bd9Sstevel@tonic-gate break; 1037c478bd9Sstevel@tonic-gate default: 1047c478bd9Sstevel@tonic-gate error = EINVAL; 1057c478bd9Sstevel@tonic-gate break; 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate return (error == 0 ? rv.r_vals : (int64_t)set_errno(error)); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate static int 1127c478bd9Sstevel@tonic-gate utssys_uname32(caddr_t buf, rval_t *rvp) 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate if (copyout(utsname.sysname, buf, 8)) 1157c478bd9Sstevel@tonic-gate return (EFAULT); 1167c478bd9Sstevel@tonic-gate buf += 8; 1177c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 1187c478bd9Sstevel@tonic-gate return (EFAULT); 1197c478bd9Sstevel@tonic-gate buf++; 1207c478bd9Sstevel@tonic-gate if (copyout(uts_nodename(), buf, 8)) 1217c478bd9Sstevel@tonic-gate return (EFAULT); 1227c478bd9Sstevel@tonic-gate buf += 8; 1237c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 1247c478bd9Sstevel@tonic-gate return (EFAULT); 1257c478bd9Sstevel@tonic-gate buf++; 1267c478bd9Sstevel@tonic-gate if (copyout(utsname.release, buf, 8)) 1277c478bd9Sstevel@tonic-gate return (EFAULT); 1287c478bd9Sstevel@tonic-gate buf += 8; 1297c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 1307c478bd9Sstevel@tonic-gate return (EFAULT); 1317c478bd9Sstevel@tonic-gate buf++; 1327c478bd9Sstevel@tonic-gate if (copyout(utsname.version, buf, 8)) 1337c478bd9Sstevel@tonic-gate return (EFAULT); 1347c478bd9Sstevel@tonic-gate buf += 8; 1357c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 1367c478bd9Sstevel@tonic-gate return (EFAULT); 1377c478bd9Sstevel@tonic-gate buf++; 1387c478bd9Sstevel@tonic-gate if (copyout(utsname.machine, buf, 8)) 1397c478bd9Sstevel@tonic-gate return (EFAULT); 1407c478bd9Sstevel@tonic-gate buf += 8; 1417c478bd9Sstevel@tonic-gate if (subyte(buf, 0) < 0) 1427c478bd9Sstevel@tonic-gate return (EFAULT); 1437c478bd9Sstevel@tonic-gate rvp->r_val1 = 1; 1447c478bd9Sstevel@tonic-gate return (0); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate static int 1487c478bd9Sstevel@tonic-gate utssys_ustat32(dev_t dev, struct ustat32 *cbuf) 1497c478bd9Sstevel@tonic-gate { 1507c478bd9Sstevel@tonic-gate struct ustat32 ust32; 1517c478bd9Sstevel@tonic-gate struct statvfs64 stvfs; 1527c478bd9Sstevel@tonic-gate fsblkcnt64_t fsbc64; 1537c478bd9Sstevel@tonic-gate char *cp, *cp2; 1547c478bd9Sstevel@tonic-gate int i, error; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0) 1577c478bd9Sstevel@tonic-gate return (error); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512); 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * Check to see if the number of free blocks can be expressed 1627c478bd9Sstevel@tonic-gate * in 31 bits or whether the number of free files is more than 1637c478bd9Sstevel@tonic-gate * can be expressed in 32 bits and is not -1 (UINT64_MAX). NFS 1647c478bd9Sstevel@tonic-gate * Version 2 does not support the number of free files and 1657c478bd9Sstevel@tonic-gate * hence will return -1. -1, when translated from a 32 bit 1667c478bd9Sstevel@tonic-gate * quantity to an unsigned 64 bit quantity, turns into UINT64_MAX. 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate if (fsbc64 > INT32_MAX || 1697c478bd9Sstevel@tonic-gate (stvfs.f_ffree > UINT32_MAX && stvfs.f_ffree != UINT64_MAX)) 1707c478bd9Sstevel@tonic-gate return (EOVERFLOW); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate ust32.f_tfree = (daddr32_t)fsbc64; 1737c478bd9Sstevel@tonic-gate ust32.f_tinode = (ino32_t)stvfs.f_ffree; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate cp = stvfs.f_fstr; 1767c478bd9Sstevel@tonic-gate cp2 = ust32.f_fname; 1777c478bd9Sstevel@tonic-gate i = 0; 1787c478bd9Sstevel@tonic-gate while (i++ < sizeof (ust32.f_fname)) 1797c478bd9Sstevel@tonic-gate if (*cp != '\0') 1807c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 1817c478bd9Sstevel@tonic-gate else 1827c478bd9Sstevel@tonic-gate *cp2++ = '\0'; 1837c478bd9Sstevel@tonic-gate while (*cp != '\0' && 1847c478bd9Sstevel@tonic-gate (i++ < sizeof (stvfs.f_fstr) - sizeof (ust32.f_fpack))) 1857c478bd9Sstevel@tonic-gate cp++; 1867c478bd9Sstevel@tonic-gate (void) strncpy(ust32.f_fpack, cp + 1, sizeof (ust32.f_fpack)); 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (copyout(&ust32, cbuf, sizeof (ust32))) 1897c478bd9Sstevel@tonic-gate return (EFAULT); 1907c478bd9Sstevel@tonic-gate return (0); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate #endif /* _ILP32 || _SYSCALL32_IMPL */ 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate #ifdef _LP64 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate static int uts_ustat64(dev_t, struct ustat *); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate int64_t 2007c478bd9Sstevel@tonic-gate utssys64(void *buf, long arg, int type, void *outbp) 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate int error; 2037c478bd9Sstevel@tonic-gate rval_t rv; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate rv.r_vals = 0; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate switch (type) { 2087c478bd9Sstevel@tonic-gate case UTS_USTAT: 2097c478bd9Sstevel@tonic-gate error = uts_ustat64((dev_t)arg, buf); 2107c478bd9Sstevel@tonic-gate break; 2117c478bd9Sstevel@tonic-gate case UTS_FUSERS: 2127c478bd9Sstevel@tonic-gate error = uts_fusers(buf, (int)arg, (intptr_t)outbp); 2137c478bd9Sstevel@tonic-gate break; 2147c478bd9Sstevel@tonic-gate default: 2157c478bd9Sstevel@tonic-gate error = EINVAL; 2167c478bd9Sstevel@tonic-gate break; 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate return (error == 0 ? rv.r_vals : (int64_t)set_errno(error)); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate static int 2237c478bd9Sstevel@tonic-gate uts_ustat64(dev_t dev, struct ustat *cbuf) 2247c478bd9Sstevel@tonic-gate { 2257c478bd9Sstevel@tonic-gate struct ustat ust; 2267c478bd9Sstevel@tonic-gate struct statvfs64 stvfs; 2277c478bd9Sstevel@tonic-gate fsblkcnt64_t fsbc64; 2287c478bd9Sstevel@tonic-gate char *cp, *cp2; 2297c478bd9Sstevel@tonic-gate int i, error; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0) 2327c478bd9Sstevel@tonic-gate return (error); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512); 2357c478bd9Sstevel@tonic-gate ust.f_tfree = (daddr_t)fsbc64; 2367c478bd9Sstevel@tonic-gate ust.f_tinode = (ino_t)stvfs.f_ffree; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate cp = stvfs.f_fstr; 2397c478bd9Sstevel@tonic-gate cp2 = ust.f_fname; 2407c478bd9Sstevel@tonic-gate i = 0; 2417c478bd9Sstevel@tonic-gate while (i++ < sizeof (ust.f_fname)) 2427c478bd9Sstevel@tonic-gate if (*cp != '\0') 2437c478bd9Sstevel@tonic-gate *cp2++ = *cp++; 2447c478bd9Sstevel@tonic-gate else 2457c478bd9Sstevel@tonic-gate *cp2++ = '\0'; 2467c478bd9Sstevel@tonic-gate while (*cp != '\0' && 2477c478bd9Sstevel@tonic-gate (i++ < sizeof (stvfs.f_fstr) - sizeof (ust.f_fpack))) 2487c478bd9Sstevel@tonic-gate cp++; 2497c478bd9Sstevel@tonic-gate (void) strncpy(ust.f_fpack, cp + 1, sizeof (ust.f_fpack)); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (copyout(&ust, cbuf, sizeof (ust))) 2527c478bd9Sstevel@tonic-gate return (EFAULT); 2537c478bd9Sstevel@tonic-gate return (0); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * Utility routine for the ustat implementations. 2607c478bd9Sstevel@tonic-gate * (If it wasn't for the 'find-by-dev_t' semantic of ustat(2), we could push 2617c478bd9Sstevel@tonic-gate * this all out into userland, sigh.) 2627c478bd9Sstevel@tonic-gate */ 2637c478bd9Sstevel@tonic-gate static int 2647c478bd9Sstevel@tonic-gate _statvfs64_by_dev(dev_t dev, struct statvfs64 *svp) 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate vfs_t *vfsp; 2677c478bd9Sstevel@tonic-gate int error; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if ((vfsp = vfs_dev2vfsp(dev)) == NULL) { 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * See if it's the root of our zone. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate vfsp = curproc->p_zone->zone_rootvp->v_vfsp; 2747c478bd9Sstevel@tonic-gate if (vfsp->vfs_dev == dev) { 2757c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); 2767c478bd9Sstevel@tonic-gate } else { 2777c478bd9Sstevel@tonic-gate vfsp = NULL; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate if (vfsp == NULL) 2817c478bd9Sstevel@tonic-gate return (EINVAL); 2827c478bd9Sstevel@tonic-gate error = VFS_STATVFS(vfsp, svp); 2837c478bd9Sstevel@tonic-gate VFS_RELE(vfsp); 2847c478bd9Sstevel@tonic-gate return (error); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * Check if this pid has an NBMAND lock or share reservation 2897c478bd9Sstevel@tonic-gate * on this vp. llp is a snapshoted list of all NBMAND locks 2907c478bd9Sstevel@tonic-gate * set by this pid. Return 1 if there is an NBMAND lock else 2917c478bd9Sstevel@tonic-gate * return 0. 2927c478bd9Sstevel@tonic-gate */ 2937c478bd9Sstevel@tonic-gate static int 2947c478bd9Sstevel@tonic-gate proc_has_nbmand_on_vp(vnode_t *vp, pid_t pid, locklist_t *llp) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Any NBMAND lock held by the process on this vp? 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate while (llp) { 3007c478bd9Sstevel@tonic-gate if (llp->ll_vp == vp) { 3017c478bd9Sstevel@tonic-gate return (1); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate llp = llp->ll_next; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate /* 3067c478bd9Sstevel@tonic-gate * Any NBMAND share reservation on the vp for this process? 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate return (proc_has_nbmand_share_on_vp(vp, pid)); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate static fu_data_t * 3127c478bd9Sstevel@tonic-gate dofusers(vnode_t *fvp, int flags) 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate fu_data_t *fu_data; 3157c478bd9Sstevel@tonic-gate proc_t *prp; 3167c478bd9Sstevel@tonic-gate vfs_t *cvfsp; 3177c478bd9Sstevel@tonic-gate pid_t npids, pidx, *pidlist; 3187c478bd9Sstevel@tonic-gate int v_proc = v.v_proc; /* max # of procs */ 3197c478bd9Sstevel@tonic-gate int pcnt = 0; 3207c478bd9Sstevel@tonic-gate int contained = (flags & F_CONTAINED); 3217c478bd9Sstevel@tonic-gate int nbmandonly = (flags & F_NBMANDLIST); 3227c478bd9Sstevel@tonic-gate int dip_usage = (flags & F_DEVINFO); 3237c478bd9Sstevel@tonic-gate int fvp_isdev = vn_matchops(fvp, spec_getvnodeops()); 3247c478bd9Sstevel@tonic-gate zone_t *zone = curproc->p_zone; 3257c478bd9Sstevel@tonic-gate int inglobal = INGLOBALZONE(curproc); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* get a pointer to the file system containing this vnode */ 3287c478bd9Sstevel@tonic-gate cvfsp = fvp->v_vfsp; 3297c478bd9Sstevel@tonic-gate ASSERT(cvfsp); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* allocate the data structure to return our results in */ 3327c478bd9Sstevel@tonic-gate fu_data = kmem_alloc(fu_data_size(v_proc), KM_SLEEP); 3337c478bd9Sstevel@tonic-gate fu_data->fud_user_max = v_proc; 3347c478bd9Sstevel@tonic-gate fu_data->fud_user_count = 0; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* get a snapshot of all the pids we're going to check out */ 3377c478bd9Sstevel@tonic-gate pidlist = kmem_alloc(v_proc * sizeof (pid_t), KM_SLEEP); 3387c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 3397c478bd9Sstevel@tonic-gate for (npids = 0, prp = practive; prp != NULL; prp = prp->p_next) { 3407c478bd9Sstevel@tonic-gate if (inglobal || prp->p_zone == zone) 3417c478bd9Sstevel@tonic-gate pidlist[npids++] = prp->p_pid; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* grab each process and check its file usage */ 3467c478bd9Sstevel@tonic-gate for (pidx = 0; pidx < npids; pidx++) { 3477c478bd9Sstevel@tonic-gate locklist_t *llp = NULL; 3487c478bd9Sstevel@tonic-gate uf_info_t *fip; 3497c478bd9Sstevel@tonic-gate vnode_t *vp; 3507c478bd9Sstevel@tonic-gate user_t *up; 3517c478bd9Sstevel@tonic-gate sess_t *sp; 3527c478bd9Sstevel@tonic-gate uid_t uid; 3537c478bd9Sstevel@tonic-gate pid_t pid = pidlist[pidx]; 3547c478bd9Sstevel@tonic-gate int i, use_flag = 0; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * grab prp->p_lock using sprlock() 3587c478bd9Sstevel@tonic-gate * if sprlock() fails the process does not exists anymore 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate prp = sprlock(pid); 3617c478bd9Sstevel@tonic-gate if (prp == NULL) 3627c478bd9Sstevel@tonic-gate continue; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* get the processes credential info in case we need it */ 3657c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_crlock); 3667c478bd9Sstevel@tonic-gate uid = crgetruid(prp->p_cred); 3677c478bd9Sstevel@tonic-gate mutex_exit(&prp->p_crlock); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * it's safe to drop p_lock here because we 3717c478bd9Sstevel@tonic-gate * called sprlock() before and it set the SPRLOCK 3727c478bd9Sstevel@tonic-gate * flag for the process so it won't go away. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate mutex_exit(&prp->p_lock); 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * now we want to walk a processes open file descriptors 3787c478bd9Sstevel@tonic-gate * to do this we need to grab the fip->fi_lock. (you 3797c478bd9Sstevel@tonic-gate * can't hold p_lock when grabbing the fip->fi_lock.) 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate fip = P_FINFO(prp); 3827c478bd9Sstevel@tonic-gate mutex_enter(&fip->fi_lock); 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * Snapshot nbmand locks for pid 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate llp = flk_active_nbmand_locks(prp->p_pid); 3887c478bd9Sstevel@tonic-gate for (i = 0; i < fip->fi_nfiles; i++) { 3897c478bd9Sstevel@tonic-gate uf_entry_t *ufp; 3907c478bd9Sstevel@tonic-gate file_t *fp; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate UF_ENTER(ufp, fip, i); 3937c478bd9Sstevel@tonic-gate if (((fp = ufp->uf_file) == NULL) || 3947c478bd9Sstevel@tonic-gate ((vp = fp->f_vnode) == NULL)) { 3957c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 3967c478bd9Sstevel@tonic-gate continue; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device 4017c478bd9Sstevel@tonic-gate * and corrosponds to the root of a filesystem 4027c478bd9Sstevel@tonic-gate * (cvfsp), then check if it contains the file 4037c478bd9Sstevel@tonic-gate * is use by this process (vp). 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate if (contained && (vp->v_vfsp == cvfsp)) 4067c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* 4097c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device, 4107c478bd9Sstevel@tonic-gate * then check if it matches the file in use 4117c478bd9Sstevel@tonic-gate * by this process (vp). 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate if (!fvp_isdev && VN_CMP(fvp, vp)) 4147c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * if the target file (fvp) is a device, 4187c478bd9Sstevel@tonic-gate * then check if the current file in use 4197c478bd9Sstevel@tonic-gate * by this process (vp) maps to the same device 4207c478bd9Sstevel@tonic-gate * minor node. 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate if (fvp_isdev && 4237c478bd9Sstevel@tonic-gate vn_matchops(vp, spec_getvnodeops()) && 4247c478bd9Sstevel@tonic-gate (fvp->v_rdev == vp->v_rdev)) 4257c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * if the target file (fvp) is a device, 4297c478bd9Sstevel@tonic-gate * and we're checking for device instance 4307c478bd9Sstevel@tonic-gate * usage, then check if the current file in use 4317c478bd9Sstevel@tonic-gate * by this process (vp) maps to the same device 4327c478bd9Sstevel@tonic-gate * instance. 4337c478bd9Sstevel@tonic-gate */ 4347c478bd9Sstevel@tonic-gate if (dip_usage && 4357c478bd9Sstevel@tonic-gate vn_matchops(vp, spec_getvnodeops()) && 4367c478bd9Sstevel@tonic-gate (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) 4377c478bd9Sstevel@tonic-gate use_flag |= F_OPEN; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * if the current file in use by this process (vp) 4417c478bd9Sstevel@tonic-gate * doesn't match what we're looking for, move on 4427c478bd9Sstevel@tonic-gate * to the next file in the process. 4437c478bd9Sstevel@tonic-gate */ 4447c478bd9Sstevel@tonic-gate if ((use_flag & F_OPEN) == 0) { 4457c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 4467c478bd9Sstevel@tonic-gate continue; 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate if (proc_has_nbmand_on_vp(vp, prp->p_pid, llp)) { 4507c478bd9Sstevel@tonic-gate /* A nbmand found so we're done. */ 4517c478bd9Sstevel@tonic-gate use_flag |= F_NBM; 4527c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 4537c478bd9Sstevel@tonic-gate break; 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate UF_EXIT(ufp); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate if (llp) 4587c478bd9Sstevel@tonic-gate flk_free_locklist(llp); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate mutex_exit(&fip->fi_lock); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * If nbmand usage tracking is desired and no nbmand was 4647c478bd9Sstevel@tonic-gate * found for this process, then no need to do further 4657c478bd9Sstevel@tonic-gate * usage tracking for this process. 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate if (nbmandonly && (!(use_flag & F_NBM))) { 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * grab the process lock again, clear the SPRLOCK 4707c478bd9Sstevel@tonic-gate * flag, release the process, and continue. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_lock); 4737c478bd9Sstevel@tonic-gate sprunlock(prp); 4747c478bd9Sstevel@tonic-gate continue; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * All other types of usage. 4797c478bd9Sstevel@tonic-gate * For the next few checks we need to hold p_lock. 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_lock); 4827c478bd9Sstevel@tonic-gate up = PTOU(prp); 4837c478bd9Sstevel@tonic-gate if (fvp_isdev) { 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * if the target file (fvp) is a device 4867c478bd9Sstevel@tonic-gate * then check if it matches the processes tty 4877c478bd9Sstevel@tonic-gate * 4887c478bd9Sstevel@tonic-gate * we grab s_lock to protect ourselves against 4897c478bd9Sstevel@tonic-gate * freectty() freeing the vnode out from under us. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate sp = prp->p_sessp; 4927c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 4937c478bd9Sstevel@tonic-gate vp = prp->p_sessp->s_vp; 4947c478bd9Sstevel@tonic-gate if (vp != NULL) { 4957c478bd9Sstevel@tonic-gate if (fvp->v_rdev == vp->v_rdev) 4967c478bd9Sstevel@tonic-gate use_flag |= F_TTY; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate if (dip_usage && 4997c478bd9Sstevel@tonic-gate (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) 5007c478bd9Sstevel@tonic-gate use_flag |= F_TTY; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 5037c478bd9Sstevel@tonic-gate } else { 5047c478bd9Sstevel@tonic-gate /* check the processes current working directory */ 5057c478bd9Sstevel@tonic-gate if (up->u_cdir && 5067c478bd9Sstevel@tonic-gate (VN_CMP(fvp, up->u_cdir) || 5077c478bd9Sstevel@tonic-gate (contained && (up->u_cdir->v_vfsp == cvfsp)))) 5087c478bd9Sstevel@tonic-gate use_flag |= F_CDIR; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* check the processes root directory */ 5117c478bd9Sstevel@tonic-gate if (up->u_rdir && 5127c478bd9Sstevel@tonic-gate (VN_CMP(fvp, up->u_rdir) || 5137c478bd9Sstevel@tonic-gate (contained && (up->u_rdir->v_vfsp == cvfsp)))) 5147c478bd9Sstevel@tonic-gate use_flag |= F_RDIR; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* check the program text vnode */ 5177c478bd9Sstevel@tonic-gate if (prp->p_exec && 5187c478bd9Sstevel@tonic-gate (VN_CMP(fvp, prp->p_exec) || 5197c478bd9Sstevel@tonic-gate (contained && (prp->p_exec->v_vfsp == cvfsp)))) 5207c478bd9Sstevel@tonic-gate use_flag |= F_TEXT; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* Now we can drop p_lock again */ 5247c478bd9Sstevel@tonic-gate mutex_exit(&prp->p_lock); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * now we want to walk a processes memory mappings. 5287c478bd9Sstevel@tonic-gate * to do this we need to grab the prp->p_as lock. (you 5297c478bd9Sstevel@tonic-gate * can't hold p_lock when grabbing the prp->p_as lock.) 5307c478bd9Sstevel@tonic-gate */ 5317c478bd9Sstevel@tonic-gate if (prp->p_as != &kas) { 5327c478bd9Sstevel@tonic-gate struct seg *seg; 5337c478bd9Sstevel@tonic-gate struct as *as = prp->p_as; 5347c478bd9Sstevel@tonic-gate 535*dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_READER); 5367c478bd9Sstevel@tonic-gate for (seg = AS_SEGFIRST(as); seg; 5377c478bd9Sstevel@tonic-gate seg = AS_SEGNEXT(as, seg)) { 5387c478bd9Sstevel@tonic-gate /* 5397c478bd9Sstevel@tonic-gate * if we can't get a backing vnode for this 5407c478bd9Sstevel@tonic-gate * segment then skip it 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate vp = NULL; 5437c478bd9Sstevel@tonic-gate if ((SEGOP_GETVP(seg, seg->s_base, &vp)) || 5447c478bd9Sstevel@tonic-gate (vp == NULL)) 5457c478bd9Sstevel@tonic-gate continue; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* 5487c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device 5497c478bd9Sstevel@tonic-gate * and corrosponds to the root of a filesystem 5507c478bd9Sstevel@tonic-gate * (cvfsp), then check if it contains the 5517c478bd9Sstevel@tonic-gate * vnode backing this segment (vp). 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate if (contained && (vp->v_vfsp == cvfsp)) { 5547c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 5557c478bd9Sstevel@tonic-gate break; 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate /* 5597c478bd9Sstevel@tonic-gate * if the target file (fvp) is not a device, 5607c478bd9Sstevel@tonic-gate * check if it matches the the vnode backing 5617c478bd9Sstevel@tonic-gate * this segment (vp). 5627c478bd9Sstevel@tonic-gate */ 5637c478bd9Sstevel@tonic-gate if (!fvp_isdev && VN_CMP(fvp, vp)) { 5647c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 5657c478bd9Sstevel@tonic-gate break; 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * if the target file (fvp) isn't a device, 5707c478bd9Sstevel@tonic-gate * or the the vnode backing this segment (vp) 5717c478bd9Sstevel@tonic-gate * isn't a device then continue. 5727c478bd9Sstevel@tonic-gate */ 5737c478bd9Sstevel@tonic-gate if (!fvp_isdev || 5747c478bd9Sstevel@tonic-gate !vn_matchops(vp, spec_getvnodeops())) 5757c478bd9Sstevel@tonic-gate continue; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * check if the vnode backing this segment 5797c478bd9Sstevel@tonic-gate * (vp) maps to the same device minor node 5807c478bd9Sstevel@tonic-gate * as the target device (fvp) 5817c478bd9Sstevel@tonic-gate */ 5827c478bd9Sstevel@tonic-gate if (fvp->v_rdev == vp->v_rdev) { 5837c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 5847c478bd9Sstevel@tonic-gate break; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * if we're checking for device instance 5897c478bd9Sstevel@tonic-gate * usage, then check if the vnode backing 5907c478bd9Sstevel@tonic-gate * this segment (vp) maps to the same device 5917c478bd9Sstevel@tonic-gate * instance as the target device (fvp). 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate if (dip_usage && 5947c478bd9Sstevel@tonic-gate (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) { 5957c478bd9Sstevel@tonic-gate use_flag |= F_MAP; 5967c478bd9Sstevel@tonic-gate break; 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate } 599*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate if (use_flag) { 6037c478bd9Sstevel@tonic-gate ASSERT(pcnt < fu_data->fud_user_max); 6047c478bd9Sstevel@tonic-gate fu_data->fud_user[pcnt].fu_flags = use_flag; 6057c478bd9Sstevel@tonic-gate fu_data->fud_user[pcnt].fu_pid = pid; 6067c478bd9Sstevel@tonic-gate fu_data->fud_user[pcnt].fu_uid = uid; 6077c478bd9Sstevel@tonic-gate pcnt++; 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * grab the process lock again, clear the SPRLOCK 6127c478bd9Sstevel@tonic-gate * flag, release the process, and continue. 6137c478bd9Sstevel@tonic-gate */ 6147c478bd9Sstevel@tonic-gate mutex_enter(&prp->p_lock); 6157c478bd9Sstevel@tonic-gate sprunlock(prp); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate kmem_free(pidlist, v_proc * sizeof (pid_t)); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate fu_data->fud_user_count = pcnt; 6217c478bd9Sstevel@tonic-gate return (fu_data); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate typedef struct dofkusers_arg { 6257c478bd9Sstevel@tonic-gate vnode_t *fvp; 6267c478bd9Sstevel@tonic-gate int flags; 6277c478bd9Sstevel@tonic-gate int *error; 6287c478bd9Sstevel@tonic-gate fu_data_t *fu_data; 6297c478bd9Sstevel@tonic-gate } dofkusers_arg_t; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate static int 6327c478bd9Sstevel@tonic-gate dofkusers_walker(const ldi_usage_t *ldi_usage, void *arg) 6337c478bd9Sstevel@tonic-gate { 6347c478bd9Sstevel@tonic-gate dofkusers_arg_t *dofkusers_arg = (dofkusers_arg_t *)arg; 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate vnode_t *fvp = dofkusers_arg->fvp; 6377c478bd9Sstevel@tonic-gate int flags = dofkusers_arg->flags; 6387c478bd9Sstevel@tonic-gate int *error = dofkusers_arg->error; 6397c478bd9Sstevel@tonic-gate fu_data_t *fu_data = dofkusers_arg->fu_data; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate modid_t modid; 6427c478bd9Sstevel@tonic-gate minor_t minor; 6437c478bd9Sstevel@tonic-gate int instance; 6447c478bd9Sstevel@tonic-gate int dip_usage = (flags & F_DEVINFO); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate ASSERT(*error == 0); 6477c478bd9Sstevel@tonic-gate ASSERT(vn_matchops(fvp, spec_getvnodeops())); 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * check if the dev_t of the target device matches the dev_t 6517c478bd9Sstevel@tonic-gate * of the device we're trying to find usage info for. 6527c478bd9Sstevel@tonic-gate */ 6537c478bd9Sstevel@tonic-gate if (fvp->v_rdev != ldi_usage->tgt_devt) { 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * if the dev_ts don't match and we're not trying 6577c478bd9Sstevel@tonic-gate * to find usage information for device instances 6587c478bd9Sstevel@tonic-gate * then return 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate if (!dip_usage) 6617c478bd9Sstevel@tonic-gate return (LDI_USAGE_CONTINUE); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * we're trying to find usage information for an 6667c478bd9Sstevel@tonic-gate * device instance instead of just a minor node. 6677c478bd9Sstevel@tonic-gate * 6687c478bd9Sstevel@tonic-gate * check if the dip for the target device matches the 6697c478bd9Sstevel@tonic-gate * dip of the device we're trying to find usage info for. 6707c478bd9Sstevel@tonic-gate */ 6717c478bd9Sstevel@tonic-gate if (VTOCS(fvp)->s_dip != ldi_usage->tgt_dip) 6727c478bd9Sstevel@tonic-gate return (LDI_USAGE_CONTINUE); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate if (fu_data->fud_user_count >= fu_data->fud_user_max) { 6767c478bd9Sstevel@tonic-gate *error = E2BIG; 6777c478bd9Sstevel@tonic-gate return (LDI_USAGE_TERMINATE); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* get the device vnode user information */ 6817c478bd9Sstevel@tonic-gate modid = ldi_usage->src_modid; 6827c478bd9Sstevel@tonic-gate ASSERT(modid != -1); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate minor = instance = -1; 6857c478bd9Sstevel@tonic-gate if (ldi_usage->src_dip != NULL) { 6867c478bd9Sstevel@tonic-gate instance = DEVI(ldi_usage->src_dip)->devi_instance; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate if (ldi_usage->src_devt != DDI_DEV_T_NONE) { 6897c478bd9Sstevel@tonic-gate minor = getminor(ldi_usage->src_devt); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate /* set the device vnode user information */ 6937c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_flags = F_KERNEL; 6947c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_modid = modid; 6957c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_instance = instance; 6967c478bd9Sstevel@tonic-gate fu_data->fud_user[fu_data->fud_user_count].fu_minor = minor; 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate fu_data->fud_user_count++; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate return (LDI_USAGE_CONTINUE); 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate int 7047c478bd9Sstevel@tonic-gate f_user_cmp(const void *arg1, const void *arg2) 7057c478bd9Sstevel@tonic-gate { 7067c478bd9Sstevel@tonic-gate f_user_t *f_user1 = (f_user_t *)arg1; 7077c478bd9Sstevel@tonic-gate f_user_t *f_user2 = (f_user_t *)arg2; 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * we should only be called for f_user_t entires that represent 7117c478bd9Sstevel@tonic-gate * a kernel file consumer 7127c478bd9Sstevel@tonic-gate */ 7137c478bd9Sstevel@tonic-gate ASSERT(f_user1->fu_flags & F_KERNEL); 7147c478bd9Sstevel@tonic-gate ASSERT(f_user2->fu_flags & F_KERNEL); 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (f_user1->fu_modid != f_user2->fu_modid) 7177c478bd9Sstevel@tonic-gate return ((f_user1->fu_modid < f_user2->fu_modid) ? -1 : 1); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate if (f_user1->fu_instance != f_user2->fu_instance) 7207c478bd9Sstevel@tonic-gate return ((f_user1->fu_instance < f_user2->fu_instance) ? -1 : 1); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate if (f_user1->fu_minor != f_user2->fu_minor) 7237c478bd9Sstevel@tonic-gate return ((f_user1->fu_minor < f_user2->fu_minor) ? -1 : 1); 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate return (0); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate static fu_data_t * 7297c478bd9Sstevel@tonic-gate dofkusers(vnode_t *fvp, int flags, int *error) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate dofkusers_arg_t dofkusers_arg; 7327c478bd9Sstevel@tonic-gate fu_data_t *fu_data; 7337c478bd9Sstevel@tonic-gate int user_max, i; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * we only keep track of kernel device consumers, so if the 7377c478bd9Sstevel@tonic-gate * target vnode isn't a device then there's nothing to do here 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate if (!vn_matchops(fvp, spec_getvnodeops())) 7407c478bd9Sstevel@tonic-gate return (NULL); 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* allocate the data structure to return our results in */ 7437c478bd9Sstevel@tonic-gate user_max = ldi_usage_count(); 7447c478bd9Sstevel@tonic-gate fu_data = kmem_alloc(fu_data_size(user_max), KM_SLEEP); 7457c478bd9Sstevel@tonic-gate fu_data->fud_user_max = user_max; 7467c478bd9Sstevel@tonic-gate fu_data->fud_user_count = 0; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate /* invoke the callback to collect device usage information */ 7497c478bd9Sstevel@tonic-gate dofkusers_arg.fvp = fvp; 7507c478bd9Sstevel@tonic-gate dofkusers_arg.flags = flags; 7517c478bd9Sstevel@tonic-gate dofkusers_arg.error = error; 7527c478bd9Sstevel@tonic-gate dofkusers_arg.fu_data = fu_data; 7537c478bd9Sstevel@tonic-gate ldi_usage_walker(&dofkusers_arg, dofkusers_walker); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* check for errors */ 7567c478bd9Sstevel@tonic-gate if (*error != 0) 7577c478bd9Sstevel@tonic-gate return (fu_data); 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate /* if there aren't any file consumers then return */ 7607c478bd9Sstevel@tonic-gate if (fu_data->fud_user_count == 0) 7617c478bd9Sstevel@tonic-gate return (fu_data); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * since we ignore the spec_type of the target we're trying to 7657c478bd9Sstevel@tonic-gate * access it's possible that we could have duplicates entries in 7667c478bd9Sstevel@tonic-gate * the list of consumers. 7677c478bd9Sstevel@tonic-gate * 7687c478bd9Sstevel@tonic-gate * we don't want to check for duplicate in the callback because 7697c478bd9Sstevel@tonic-gate * we're holding locks in the ldi when the callback is invoked. 7707c478bd9Sstevel@tonic-gate * 7717c478bd9Sstevel@tonic-gate * so here we need to go through the array of file consumers 7727c478bd9Sstevel@tonic-gate * and remove duplicate entries. 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /* first sort the array of file consumers */ 7767c478bd9Sstevel@tonic-gate qsort((caddr_t)fu_data->fud_user, fu_data->fud_user_count, 7777c478bd9Sstevel@tonic-gate sizeof (f_user_t), f_user_cmp); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* then remove any duplicate entires */ 7807c478bd9Sstevel@tonic-gate i = 1; 7817c478bd9Sstevel@tonic-gate while (i < fu_data->fud_user_count) { 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate if (f_user_cmp(&fu_data->fud_user[i], 7847c478bd9Sstevel@tonic-gate &fu_data->fud_user[i - 1]) != 0) { 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * the current element is unique, move onto 7877c478bd9Sstevel@tonic-gate * the next one 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate i++; 7907c478bd9Sstevel@tonic-gate continue; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate /* 7947c478bd9Sstevel@tonic-gate * this entry is a duplicate so if it's not the last 7957c478bd9Sstevel@tonic-gate * entry in the array then remove it. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate fu_data->fud_user_count--; 7987c478bd9Sstevel@tonic-gate if (i == fu_data->fud_user_count) 7997c478bd9Sstevel@tonic-gate break; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate bcopy(&fu_data->fud_user[i + 1], &fu_data->fud_user[i], 8027c478bd9Sstevel@tonic-gate sizeof (f_user_t) * (fu_data->fud_user_count - i)); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate return (fu_data); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate /* 8097c478bd9Sstevel@tonic-gate * Determine the ways in which processes and the kernel are using a named 8107c478bd9Sstevel@tonic-gate * file or mounted file system (path). Normally return 0. In case of an 8117c478bd9Sstevel@tonic-gate * error appropriate errno will be returned. 8127c478bd9Sstevel@tonic-gate * 8137c478bd9Sstevel@tonic-gate * Upon success, uts_fusers will also copyout the file usage information 8147c478bd9Sstevel@tonic-gate * in the form of an array of f_user_t's that are contained within an 8157c478bd9Sstevel@tonic-gate * fu_data_t pointed to by userbp. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate static int 8187c478bd9Sstevel@tonic-gate uts_fusers(char *path, int flags, intptr_t userbp) 8197c478bd9Sstevel@tonic-gate { 8207c478bd9Sstevel@tonic-gate fu_data_t *fu_data = NULL, *fuk_data = NULL; 8217c478bd9Sstevel@tonic-gate fu_data_t fu_header; 8227c478bd9Sstevel@tonic-gate vnode_t *fvp = NULL; 8237c478bd9Sstevel@tonic-gate size_t bcount; 8247c478bd9Sstevel@tonic-gate int error = 0; 8257c478bd9Sstevel@tonic-gate int total_max, total_out; 8267c478bd9Sstevel@tonic-gate int contained = (flags & F_CONTAINED); 8277c478bd9Sstevel@tonic-gate int dip_usage = (flags & F_DEVINFO); 8287c478bd9Sstevel@tonic-gate int fvp_isdev; 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* figure out how man f_user_t's we can safetly copy out */ 8327c478bd9Sstevel@tonic-gate if (copyin((const void *)userbp, &total_max, sizeof (total_max))) 8337c478bd9Sstevel@tonic-gate return (EFAULT); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * check if we only want a count of how many kernel device 8377c478bd9Sstevel@tonic-gate * consumers exist 8387c478bd9Sstevel@tonic-gate */ 8397c478bd9Sstevel@tonic-gate if (flags & F_KINFO_COUNT) { 8407c478bd9Sstevel@tonic-gate fu_header.fud_user_max = total_max; 8417c478bd9Sstevel@tonic-gate fu_header.fud_user_count = ldi_usage_count(); 8427c478bd9Sstevel@tonic-gate bcount = fu_data_size(0); 8437c478bd9Sstevel@tonic-gate if (copyout(&fu_header, (void *)userbp, bcount)) 8447c478bd9Sstevel@tonic-gate return (EFAULT); 8457c478bd9Sstevel@tonic-gate return (0); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* get the vnode for the file we want to look up usage for */ 8497c478bd9Sstevel@tonic-gate error = lookupname(path, UIO_USERSPACE, FOLLOW, NULLVPP, &fvp); 8507c478bd9Sstevel@tonic-gate if (error != 0) 8517c478bd9Sstevel@tonic-gate return (error); 8527c478bd9Sstevel@tonic-gate ASSERT(fvp); 8537c478bd9Sstevel@tonic-gate fvp_isdev = vn_matchops(fvp, spec_getvnodeops()); 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* 8567c478bd9Sstevel@tonic-gate * if we want to report usage for all files contained within a 8577c478bd9Sstevel@tonic-gate * file system then the target file better correspond to the 8587c478bd9Sstevel@tonic-gate * root node of a mounted file system, or the root of a zone. 8597c478bd9Sstevel@tonic-gate */ 8607c478bd9Sstevel@tonic-gate if (contained && !(fvp->v_flag & VROOT) && 8617c478bd9Sstevel@tonic-gate fvp != curproc->p_zone->zone_rootvp) { 8627c478bd9Sstevel@tonic-gate error = EINVAL; 8637c478bd9Sstevel@tonic-gate goto out; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate /* 8677c478bd9Sstevel@tonic-gate * if we want to report usage for all files contained within a 8687c478bd9Sstevel@tonic-gate * file system then the target file better not be a device. 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate if (contained && fvp_isdev) { 8717c478bd9Sstevel@tonic-gate error = EINVAL; 8727c478bd9Sstevel@tonic-gate goto out; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * if we want to report usage for a device instance then the 8777c478bd9Sstevel@tonic-gate * target file better corrospond to a device 8787c478bd9Sstevel@tonic-gate */ 8797c478bd9Sstevel@tonic-gate if (dip_usage && !fvp_isdev) { 8807c478bd9Sstevel@tonic-gate error = EINVAL; 8817c478bd9Sstevel@tonic-gate goto out; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * if the target vnode isn't a device and it has a reference count 8867c478bd9Sstevel@tonic-gate * of one then no one else is going to have it open so we don't 8877c478bd9Sstevel@tonic-gate * have any work to do. 8887c478bd9Sstevel@tonic-gate */ 8897c478bd9Sstevel@tonic-gate if (!fvp_isdev && (fvp->v_count == 1)) { 8907c478bd9Sstevel@tonic-gate goto out; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* look up usage information for this vnode */ 8947c478bd9Sstevel@tonic-gate fu_data = dofusers(fvp, flags); 8957c478bd9Sstevel@tonic-gate fuk_data = dofkusers(fvp, flags, &error); 8967c478bd9Sstevel@tonic-gate if (error != 0) 8977c478bd9Sstevel@tonic-gate goto out; 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate /* get a count of the number of f_user_t's we need to copy out */ 9007c478bd9Sstevel@tonic-gate total_out = 0; 9017c478bd9Sstevel@tonic-gate if (fu_data) 9027c478bd9Sstevel@tonic-gate total_out += fu_data->fud_user_count; 9037c478bd9Sstevel@tonic-gate if (fuk_data) 9047c478bd9Sstevel@tonic-gate total_out += fuk_data->fud_user_count; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* check if there is enough space to copyout all results */ 9077c478bd9Sstevel@tonic-gate if (total_out > total_max) { 9087c478bd9Sstevel@tonic-gate error = E2BIG; 9097c478bd9Sstevel@tonic-gate goto out; 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate /* copyout file usage info counts */ 9137c478bd9Sstevel@tonic-gate fu_header.fud_user_max = total_max; 9147c478bd9Sstevel@tonic-gate fu_header.fud_user_count = total_out; 9157c478bd9Sstevel@tonic-gate bcount = fu_data_size(0); 9167c478bd9Sstevel@tonic-gate if (copyout(&fu_header, (void *)userbp, bcount)) { 9177c478bd9Sstevel@tonic-gate error = EFAULT; 9187c478bd9Sstevel@tonic-gate goto out; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate /* copyout userland process file usage info */ 9227c478bd9Sstevel@tonic-gate if ((fu_data != NULL) && (fu_data->fud_user_count > 0)) { 9237c478bd9Sstevel@tonic-gate userbp += bcount; 9247c478bd9Sstevel@tonic-gate bcount = fu_data->fud_user_count * sizeof (f_user_t); 9257c478bd9Sstevel@tonic-gate if (copyout(fu_data->fud_user, (void *)userbp, bcount)) { 9267c478bd9Sstevel@tonic-gate error = EFAULT; 9277c478bd9Sstevel@tonic-gate goto out; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate /* copyout kernel file usage info */ 9327c478bd9Sstevel@tonic-gate if ((fuk_data != NULL) && (fuk_data->fud_user_count > 0)) { 9337c478bd9Sstevel@tonic-gate userbp += bcount; 9347c478bd9Sstevel@tonic-gate bcount = fuk_data->fud_user_count * sizeof (f_user_t); 9357c478bd9Sstevel@tonic-gate if (copyout(fuk_data->fud_user, (void *)userbp, bcount)) { 9367c478bd9Sstevel@tonic-gate error = EFAULT; 9377c478bd9Sstevel@tonic-gate goto out; 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate out: 9427c478bd9Sstevel@tonic-gate /* release the vnode that we were looking up usage for */ 9437c478bd9Sstevel@tonic-gate VN_RELE(fvp); 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate /* release any allocated memory */ 9467c478bd9Sstevel@tonic-gate if (fu_data) 9477c478bd9Sstevel@tonic-gate kmem_free(fu_data, fu_data_size(fu_data->fud_user_max)); 9487c478bd9Sstevel@tonic-gate if (fuk_data) 9497c478bd9Sstevel@tonic-gate kmem_free(fuk_data, fu_data_size(fuk_data->fud_user_max)); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate return (error); 9527c478bd9Sstevel@tonic-gate } 953