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 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * miscellaneous routines for the devfs 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/param.h> 357c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 367c478bd9Sstevel@tonic-gate #include <sys/systm.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/user.h> 397c478bd9Sstevel@tonic-gate #include <sys/time.h> 407c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 417c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 427c478bd9Sstevel@tonic-gate #include <sys/file.h> 437c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 447c478bd9Sstevel@tonic-gate #include <sys/flock.h> 457c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 467c478bd9Sstevel@tonic-gate #include <sys/uio.h> 477c478bd9Sstevel@tonic-gate #include <sys/errno.h> 487c478bd9Sstevel@tonic-gate #include <sys/stat.h> 497c478bd9Sstevel@tonic-gate #include <sys/cred.h> 507c478bd9Sstevel@tonic-gate #include <sys/dirent.h> 517c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 527c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 537c478bd9Sstevel@tonic-gate #include <sys/debug.h> 547c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 557c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 567c478bd9Sstevel@tonic-gate #include <sys/fs/dv_node.h> 577c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 587c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 597c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 607c478bd9Sstevel@tonic-gate #include <sys/conf.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #ifdef DEBUG 637c478bd9Sstevel@tonic-gate int devfs_debug = 0x0; 647c478bd9Sstevel@tonic-gate #endif 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate const char dvnm[] = "devfs"; 677c478bd9Sstevel@tonic-gate kmem_cache_t *dv_node_cache; /* dv_node cache */ 687c478bd9Sstevel@tonic-gate uint_t devfs_clean_key; 697c478bd9Sstevel@tonic-gate struct dv_node *dvroot; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* prototype memory vattrs */ 727c478bd9Sstevel@tonic-gate vattr_t dv_vattr_dir = { 737c478bd9Sstevel@tonic-gate AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 747c478bd9Sstevel@tonic-gate VDIR, /* va_type */ 757c478bd9Sstevel@tonic-gate DV_DIRMODE_DEFAULT, /* va_mode */ 767c478bd9Sstevel@tonic-gate DV_UID_DEFAULT, /* va_uid */ 777c478bd9Sstevel@tonic-gate DV_GID_DEFAULT, /* va_gid */ 787c478bd9Sstevel@tonic-gate 0, /* va_fsid; */ 797c478bd9Sstevel@tonic-gate 0, /* va_nodeid; */ 807c478bd9Sstevel@tonic-gate 0, /* va_nlink; */ 817c478bd9Sstevel@tonic-gate 0, /* va_size; */ 827c478bd9Sstevel@tonic-gate 0, /* va_atime; */ 837c478bd9Sstevel@tonic-gate 0, /* va_mtime; */ 847c478bd9Sstevel@tonic-gate 0, /* va_ctime; */ 857c478bd9Sstevel@tonic-gate 0, /* va_rdev; */ 867c478bd9Sstevel@tonic-gate 0, /* va_blksize; */ 877c478bd9Sstevel@tonic-gate 0, /* va_nblocks; */ 887c478bd9Sstevel@tonic-gate 0, /* va_seq; */ 897c478bd9Sstevel@tonic-gate }; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate vattr_t dv_vattr_file = { 927c478bd9Sstevel@tonic-gate AT_TYPE|AT_MODE|AT_SIZE|AT_UID|AT_GID|AT_RDEV, /* va_mask */ 937c478bd9Sstevel@tonic-gate 0, /* va_type */ 947c478bd9Sstevel@tonic-gate DV_DEVMODE_DEFAULT, /* va_mode */ 957c478bd9Sstevel@tonic-gate DV_UID_DEFAULT, /* va_uid */ 967c478bd9Sstevel@tonic-gate DV_GID_DEFAULT, /* va_gid */ 977c478bd9Sstevel@tonic-gate 0, /* va_fsid; */ 987c478bd9Sstevel@tonic-gate 0, /* va_nodeid; */ 997c478bd9Sstevel@tonic-gate 0, /* va_nlink; */ 1007c478bd9Sstevel@tonic-gate 0, /* va_size; */ 1017c478bd9Sstevel@tonic-gate 0, /* va_atime; */ 1027c478bd9Sstevel@tonic-gate 0, /* va_mtime; */ 1037c478bd9Sstevel@tonic-gate 0, /* va_ctime; */ 1047c478bd9Sstevel@tonic-gate 0, /* va_rdev; */ 1057c478bd9Sstevel@tonic-gate 0, /* va_blksize; */ 1067c478bd9Sstevel@tonic-gate 0, /* va_nblocks; */ 1077c478bd9Sstevel@tonic-gate 0, /* va_seq; */ 1087c478bd9Sstevel@tonic-gate }; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate vattr_t dv_vattr_priv = { 1117c478bd9Sstevel@tonic-gate AT_TYPE|AT_MODE|AT_SIZE|AT_UID|AT_GID|AT_RDEV, /* va_mask */ 1127c478bd9Sstevel@tonic-gate 0, /* va_type */ 1137c478bd9Sstevel@tonic-gate DV_DEVMODE_PRIV, /* va_mode */ 1147c478bd9Sstevel@tonic-gate DV_UID_DEFAULT, /* va_uid */ 1157c478bd9Sstevel@tonic-gate DV_GID_DEFAULT, /* va_gid */ 1167c478bd9Sstevel@tonic-gate 0, /* va_fsid; */ 1177c478bd9Sstevel@tonic-gate 0, /* va_nodeid; */ 1187c478bd9Sstevel@tonic-gate 0, /* va_nlink; */ 1197c478bd9Sstevel@tonic-gate 0, /* va_size; */ 1207c478bd9Sstevel@tonic-gate 0, /* va_atime; */ 1217c478bd9Sstevel@tonic-gate 0, /* va_mtime; */ 1227c478bd9Sstevel@tonic-gate 0, /* va_ctime; */ 1237c478bd9Sstevel@tonic-gate 0, /* va_rdev; */ 1247c478bd9Sstevel@tonic-gate 0, /* va_blksize; */ 1257c478bd9Sstevel@tonic-gate 0, /* va_nblocks; */ 1267c478bd9Sstevel@tonic-gate 0, /* va_seq; */ 1277c478bd9Sstevel@tonic-gate }; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate extern dev_info_t *clone_dip; 1307c478bd9Sstevel@tonic-gate extern major_t clone_major; 1317c478bd9Sstevel@tonic-gate extern struct dev_ops *ddi_hold_driver(major_t); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * dv_node cache constructor, destructor, can cache creation 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 1377c478bd9Sstevel@tonic-gate static int 1387c478bd9Sstevel@tonic-gate i_dv_node_ctor(void *buf, void *cfarg, int flag) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate struct dv_node *dv = (struct dv_node *)buf; 1417c478bd9Sstevel@tonic-gate struct vnode *vp; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate bzero(buf, sizeof (struct dv_node)); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* initialize persistent parts of dv_node */ 1467c478bd9Sstevel@tonic-gate rw_init(&dv->dv_contents, NULL, RW_DEFAULT, NULL); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* allocate vnode and initialize link back to dv_node */ 1497c478bd9Sstevel@tonic-gate dv->dv_vnode = vn_alloc(KM_SLEEP); 1507c478bd9Sstevel@tonic-gate vp = DVTOV(dv); 1517c478bd9Sstevel@tonic-gate vp->v_data = (caddr_t)dv; 1527c478bd9Sstevel@tonic-gate return (0); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* dev_info node destructor for kmem cache */ 1567c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 1577c478bd9Sstevel@tonic-gate static void 1587c478bd9Sstevel@tonic-gate i_dv_node_dtor(void *buf, void *arg) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate struct dv_node *dv = (struct dv_node *)buf; 1617c478bd9Sstevel@tonic-gate struct vnode *vp = DVTOV(dv); 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate rw_destroy(&dv->dv_contents); 1647c478bd9Sstevel@tonic-gate vn_invalid(vp); 1657c478bd9Sstevel@tonic-gate vn_free(vp); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* initialize dev_info node cache */ 1707c478bd9Sstevel@tonic-gate void 1717c478bd9Sstevel@tonic-gate dv_node_cache_init() 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate ASSERT(dv_node_cache == NULL); 1747c478bd9Sstevel@tonic-gate dv_node_cache = kmem_cache_create("dv_node_cache", 1757c478bd9Sstevel@tonic-gate sizeof (struct dv_node), 0, i_dv_node_ctor, i_dv_node_dtor, 1767c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 0); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate tsd_create(&devfs_clean_key, NULL); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* initialize dev_info node cache */ 1827c478bd9Sstevel@tonic-gate void 1837c478bd9Sstevel@tonic-gate dv_node_cache_fini() 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate ASSERT(dv_node_cache != NULL); 1867c478bd9Sstevel@tonic-gate kmem_cache_destroy(dv_node_cache); 1877c478bd9Sstevel@tonic-gate dv_node_cache = NULL; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate tsd_destroy(&devfs_clean_key); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * dv_mkino - Generate a unique inode number for devfs nodes. 1947c478bd9Sstevel@tonic-gate * 1957c478bd9Sstevel@tonic-gate * Although ino_t is 64 bits, the inode number is truncated to 32 bits for 32 1967c478bd9Sstevel@tonic-gate * bit non-LARGEFILE applications. This means that there is a requirement to 1977c478bd9Sstevel@tonic-gate * maintain the inode number as a 32 bit value or applications will have 1987c478bd9Sstevel@tonic-gate * stat(2) calls fail with EOVERFLOW. We form a 32 bit inode number from the 1997c478bd9Sstevel@tonic-gate * dev_t. but if the minor number is larger than L_MAXMIN32 we fold extra minor 2007c478bd9Sstevel@tonic-gate * 2017c478bd9Sstevel@tonic-gate * To generate inode numbers for directories, we assume that we will never use 2027c478bd9Sstevel@tonic-gate * more than half the major space - this allows for ~8190 drivers. We use this 2037c478bd9Sstevel@tonic-gate * upper major number space to allocate inode numbers for directories by 2047c478bd9Sstevel@tonic-gate * encoding the major and instance into this space. 2057c478bd9Sstevel@tonic-gate * 2067c478bd9Sstevel@tonic-gate * We also skew the result so that inode 2 is reserved for the root of the file 2077c478bd9Sstevel@tonic-gate * system. 2087c478bd9Sstevel@tonic-gate * 2097c478bd9Sstevel@tonic-gate * As part of the future support for 64-bit dev_t APIs, the upper minor bits 2107c478bd9Sstevel@tonic-gate * should be folded into the high inode bits by adding the following code 2117c478bd9Sstevel@tonic-gate * after "ino |= 1": 2127c478bd9Sstevel@tonic-gate * 2137c478bd9Sstevel@tonic-gate * #if (L_BITSMINOR32 != L_BITSMINOR) 2147c478bd9Sstevel@tonic-gate * |* fold overflow minor bits into high bits of inode number *| 2157c478bd9Sstevel@tonic-gate * ino |= ((ino_t)(minor >> L_BITSMINOR32)) << L_BITSMINOR; 2167c478bd9Sstevel@tonic-gate * #endif |* (L_BITSMINOR32 != L_BITSMINOR) *| 2177c478bd9Sstevel@tonic-gate * 2187c478bd9Sstevel@tonic-gate * This way only applications that use devices that overflow their minor 2197c478bd9Sstevel@tonic-gate * space will have an application level impact. 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate static ino_t 2227c478bd9Sstevel@tonic-gate dv_mkino(dev_info_t *devi, vtype_t typ, dev_t dev) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate major_t major; 2257c478bd9Sstevel@tonic-gate minor_t minor; 2267c478bd9Sstevel@tonic-gate ino_t ino; 2277c478bd9Sstevel@tonic-gate static int warn; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate if (typ == VDIR) { 2307c478bd9Sstevel@tonic-gate major = ((L_MAXMAJ32 + 1) >> 1) + DEVI(devi)->devi_major; 2317c478bd9Sstevel@tonic-gate minor = ddi_get_instance(devi); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* makedevice32 in high half of major number space */ 2347c478bd9Sstevel@tonic-gate ino = (ino_t)((major << L_BITSMINOR32) | (minor & L_MAXMIN32)); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate major = DEVI(devi)->devi_major; 2377c478bd9Sstevel@tonic-gate } else { 2387c478bd9Sstevel@tonic-gate major = getmajor(dev); 2397c478bd9Sstevel@tonic-gate minor = getminor(dev); 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* makedevice32 */ 2427c478bd9Sstevel@tonic-gate ino = (ino_t)((major << L_BITSMINOR32) | (minor & L_MAXMIN32)); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* make ino for VCHR different than VBLK */ 2457c478bd9Sstevel@tonic-gate ino <<= 1; 2467c478bd9Sstevel@tonic-gate if (typ == VCHR) 2477c478bd9Sstevel@tonic-gate ino |= 1; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate ino += DV_ROOTINO + 1; /* skew */ 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * diagnose things a little early because adding the skew to a large 2547c478bd9Sstevel@tonic-gate * minor number could roll over the major. 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate if ((major >= (L_MAXMAJ32 >> 1)) && (warn == 0)) { 2577c478bd9Sstevel@tonic-gate warn = 1; 2587c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: inode numbers are not unique", dvnm); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate return (ino); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * dv_mkroot 2667c478bd9Sstevel@tonic-gate * 2677c478bd9Sstevel@tonic-gate * Build the first VDIR dv_node. 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate struct dv_node * 2707c478bd9Sstevel@tonic-gate dv_mkroot(struct vfs *vfsp, dev_t devfsdev) 2717c478bd9Sstevel@tonic-gate { 2727c478bd9Sstevel@tonic-gate struct dv_node *dv; 2737c478bd9Sstevel@tonic-gate struct vnode *vp; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate ASSERT(ddi_root_node() != NULL); 2767c478bd9Sstevel@tonic-gate ASSERT(dv_node_cache != NULL); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate dcmn_err3(("dv_mkroot\n")); 2797c478bd9Sstevel@tonic-gate dv = kmem_cache_alloc(dv_node_cache, KM_SLEEP); 2807c478bd9Sstevel@tonic-gate vp = DVTOV(dv); 2817c478bd9Sstevel@tonic-gate vn_reinit(vp); 2827c478bd9Sstevel@tonic-gate vp->v_flag = VROOT; 2837c478bd9Sstevel@tonic-gate vp->v_vfsp = vfsp; 2847c478bd9Sstevel@tonic-gate vp->v_type = VDIR; 2857c478bd9Sstevel@tonic-gate vp->v_rdev = devfsdev; 2867c478bd9Sstevel@tonic-gate vn_setops(vp, dv_vnodeops); 2877c478bd9Sstevel@tonic-gate vn_exists(vp); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate dvroot = dv; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate dv->dv_name = NULL; /* not needed */ 2927c478bd9Sstevel@tonic-gate dv->dv_namelen = 0; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate dv->dv_devi = ddi_root_node(); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate dv->dv_ino = DV_ROOTINO; 2977c478bd9Sstevel@tonic-gate dv->dv_nlink = 2; /* name + . (no dv_insert) */ 2987c478bd9Sstevel@tonic-gate dv->dv_dotdot = dv; /* .. == self */ 2997c478bd9Sstevel@tonic-gate dv->dv_attrvp = NULLVP; 3007c478bd9Sstevel@tonic-gate dv->dv_attr = NULL; 3017c478bd9Sstevel@tonic-gate dv->dv_flags = DV_BUILD; 3027c478bd9Sstevel@tonic-gate dv->dv_priv = NULL; 3037c478bd9Sstevel@tonic-gate dv->dv_busy = 0; 3047c478bd9Sstevel@tonic-gate dv->dv_dflt_mode = 0; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate return (dv); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * dv_mkdir 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * Given an probed or attached nexus node, create a VDIR dv_node. 3137c478bd9Sstevel@tonic-gate * No dv_attrvp is created at this point. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate struct dv_node * 3167c478bd9Sstevel@tonic-gate dv_mkdir(struct dv_node *ddv, dev_info_t *devi, char *nm) 3177c478bd9Sstevel@tonic-gate { 3187c478bd9Sstevel@tonic-gate struct dv_node *dv; 3197c478bd9Sstevel@tonic-gate struct vnode *vp; 3207c478bd9Sstevel@tonic-gate size_t nmlen; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate ASSERT((devi)); 3237c478bd9Sstevel@tonic-gate dcmn_err4(("dv_mkdir: %s\n", nm)); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate dv = kmem_cache_alloc(dv_node_cache, KM_SLEEP); 3267c478bd9Sstevel@tonic-gate nmlen = strlen(nm) + 1; 3277c478bd9Sstevel@tonic-gate dv->dv_name = kmem_alloc(nmlen, KM_SLEEP); 3287c478bd9Sstevel@tonic-gate bcopy(nm, dv->dv_name, nmlen); 3297c478bd9Sstevel@tonic-gate dv->dv_namelen = nmlen - 1; /* '\0' not included */ 3307c478bd9Sstevel@tonic-gate vp = DVTOV(dv); 3317c478bd9Sstevel@tonic-gate vn_reinit(vp); 3327c478bd9Sstevel@tonic-gate vp->v_flag = 0; 3337c478bd9Sstevel@tonic-gate vp->v_vfsp = DVTOV(ddv)->v_vfsp; 3347c478bd9Sstevel@tonic-gate vp->v_type = VDIR; 3357c478bd9Sstevel@tonic-gate vp->v_rdev = DVTOV(ddv)->v_rdev; 3367c478bd9Sstevel@tonic-gate vn_setops(vp, vn_getops(DVTOV(ddv))); 3377c478bd9Sstevel@tonic-gate vn_exists(vp); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate dv->dv_devi = devi; 3407c478bd9Sstevel@tonic-gate ndi_hold_devi(devi); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate dv->dv_ino = dv_mkino(devi, VDIR, NODEV); 3437c478bd9Sstevel@tonic-gate dv->dv_nlink = 0; /* updated on insert */ 3447c478bd9Sstevel@tonic-gate dv->dv_dotdot = ddv; 3457c478bd9Sstevel@tonic-gate dv->dv_attrvp = NULLVP; 3467c478bd9Sstevel@tonic-gate dv->dv_attr = NULL; 3477c478bd9Sstevel@tonic-gate dv->dv_flags = DV_BUILD; 3487c478bd9Sstevel@tonic-gate dv->dv_priv = NULL; 3497c478bd9Sstevel@tonic-gate dv->dv_busy = 0; 3507c478bd9Sstevel@tonic-gate dv->dv_dflt_mode = 0; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate return (dv); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * dv_mknod 3577c478bd9Sstevel@tonic-gate * 3587c478bd9Sstevel@tonic-gate * Given a minor node, create a VCHR or VBLK dv_node. 3597c478bd9Sstevel@tonic-gate * No dv_attrvp is created at this point. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate static struct dv_node * 3627c478bd9Sstevel@tonic-gate dv_mknod(struct dv_node *ddv, dev_info_t *devi, char *nm, 3637c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmd) 3647c478bd9Sstevel@tonic-gate { 3657c478bd9Sstevel@tonic-gate struct dv_node *dv; 3667c478bd9Sstevel@tonic-gate struct vnode *vp; 3677c478bd9Sstevel@tonic-gate size_t nmlen; 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate dcmn_err4(("dv_mknod: %s\n", nm)); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate dv = kmem_cache_alloc(dv_node_cache, KM_SLEEP); 3727c478bd9Sstevel@tonic-gate nmlen = strlen(nm) + 1; 3737c478bd9Sstevel@tonic-gate dv->dv_name = kmem_alloc(nmlen, KM_SLEEP); 3747c478bd9Sstevel@tonic-gate bcopy(nm, dv->dv_name, nmlen); 3757c478bd9Sstevel@tonic-gate dv->dv_namelen = nmlen - 1; /* no '\0' */ 3767c478bd9Sstevel@tonic-gate vp = DVTOV(dv); 3777c478bd9Sstevel@tonic-gate vn_reinit(vp); 3787c478bd9Sstevel@tonic-gate vp->v_flag = 0; 3797c478bd9Sstevel@tonic-gate vp->v_vfsp = DVTOV(ddv)->v_vfsp; 3807c478bd9Sstevel@tonic-gate vp->v_type = dmd->ddm_spec_type == S_IFCHR ? VCHR : VBLK; 3817c478bd9Sstevel@tonic-gate vp->v_rdev = dmd->ddm_dev; 3827c478bd9Sstevel@tonic-gate vn_setops(vp, vn_getops(DVTOV(ddv))); 3837c478bd9Sstevel@tonic-gate vn_exists(vp); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&DEVI(devi)->devi_lock)); 3867c478bd9Sstevel@tonic-gate dv->dv_devi = devi; 3877c478bd9Sstevel@tonic-gate DEVI(devi)->devi_ref++; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate dv->dv_ino = dv_mkino(devi, vp->v_type, vp->v_rdev); 3907c478bd9Sstevel@tonic-gate dv->dv_nlink = 0; /* updated on insert */ 3917c478bd9Sstevel@tonic-gate dv->dv_dotdot = ddv; 3927c478bd9Sstevel@tonic-gate dv->dv_attrvp = NULLVP; 3937c478bd9Sstevel@tonic-gate dv->dv_attr = NULL; 3947c478bd9Sstevel@tonic-gate dv->dv_flags = 0; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (dmd->type == DDM_INTERNAL_PATH) 3977c478bd9Sstevel@tonic-gate dv->dv_flags |= DV_INTERNAL; 3987c478bd9Sstevel@tonic-gate if (dmd->ddm_flags & DM_NO_FSPERM) 3997c478bd9Sstevel@tonic-gate dv->dv_flags |= DV_NO_FSPERM; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate dv->dv_priv = dmd->ddm_node_priv; 4027c478bd9Sstevel@tonic-gate if (dv->dv_priv) 4037c478bd9Sstevel@tonic-gate dphold(dv->dv_priv); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * Minors created with ddi_create_priv_minor_node can specify 4077c478bd9Sstevel@tonic-gate * a default mode permission other than the devfs default. 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate if (dv->dv_priv || dv->dv_flags & DV_NO_FSPERM) { 4107c478bd9Sstevel@tonic-gate dcmn_err5(("%s: dv_mknod default priv mode 0%o\n", 4117c478bd9Sstevel@tonic-gate dv->dv_name, dmd->ddm_priv_mode)); 4127c478bd9Sstevel@tonic-gate dv->dv_flags |= DV_DFLT_MODE; 4137c478bd9Sstevel@tonic-gate dv->dv_dflt_mode = dmd->ddm_priv_mode & S_IAMB; 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate return (dv); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* 4207c478bd9Sstevel@tonic-gate * dv_destroy 4217c478bd9Sstevel@tonic-gate * 4227c478bd9Sstevel@tonic-gate * Destroy what we created in dv_mkdir or dv_mknod. 4237c478bd9Sstevel@tonic-gate * In the case of a *referenced* directory, do nothing. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 4267c478bd9Sstevel@tonic-gate void 4277c478bd9Sstevel@tonic-gate dv_destroy(struct dv_node *dv, uint_t flags) 4287c478bd9Sstevel@tonic-gate { 4297c478bd9Sstevel@tonic-gate vnode_t *vp = DVTOV(dv); 4307c478bd9Sstevel@tonic-gate ASSERT(dv->dv_nlink == 0); /* no references */ 4317c478bd9Sstevel@tonic-gate ASSERT(dv->dv_next == NULL); /* unlinked from directory */ 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate dcmn_err4(("dv_destroy: %s\n", dv->dv_name)); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * We may be asked to unlink referenced directories. 4377c478bd9Sstevel@tonic-gate * In this case, there is nothing to be done. 4387c478bd9Sstevel@tonic-gate * The eventual memory free will be done in 4397c478bd9Sstevel@tonic-gate * devfs_inactive. 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate if (vp->v_count != 0) { 4427c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VDIR); 4437c478bd9Sstevel@tonic-gate ASSERT(flags & DV_CLEAN_FORCE); 4447c478bd9Sstevel@tonic-gate ASSERT(DV_STALE(dv)); 4457c478bd9Sstevel@tonic-gate return; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate if (dv->dv_attrvp != NULLVP) 4497c478bd9Sstevel@tonic-gate VN_RELE(dv->dv_attrvp); 4507c478bd9Sstevel@tonic-gate if (dv->dv_attr != NULL) 4517c478bd9Sstevel@tonic-gate kmem_free(dv->dv_attr, sizeof (struct vattr)); 4527c478bd9Sstevel@tonic-gate if (dv->dv_name != NULL) 4537c478bd9Sstevel@tonic-gate kmem_free(dv->dv_name, dv->dv_namelen + 1); 4547c478bd9Sstevel@tonic-gate if (dv->dv_devi != NULL) { 4557c478bd9Sstevel@tonic-gate ndi_rele_devi(dv->dv_devi); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate if (dv->dv_priv != NULL) { 4587c478bd9Sstevel@tonic-gate dpfree(dv->dv_priv); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate kmem_cache_free(dv_node_cache, dv); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * Find and hold dv_node by name 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate struct dv_node * 4687c478bd9Sstevel@tonic-gate dv_findbyname(struct dv_node *ddv, char *nm) 4697c478bd9Sstevel@tonic-gate { 4707c478bd9Sstevel@tonic-gate struct dv_node *dv; 4717c478bd9Sstevel@tonic-gate size_t nmlen = strlen(nm); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&ddv->dv_contents)); 4747c478bd9Sstevel@tonic-gate dcmn_err3(("dv_findbyname: %s\n", nm)); 4757c478bd9Sstevel@tonic-gate for (dv = ddv->dv_dot; dv; dv = dv->dv_next) { 4767c478bd9Sstevel@tonic-gate if (dv->dv_namelen != nmlen) 4777c478bd9Sstevel@tonic-gate continue; 4787c478bd9Sstevel@tonic-gate if (strcmp(dv->dv_name, nm) == 0) { 4797c478bd9Sstevel@tonic-gate VN_HOLD(DVTOV(dv)); 4807c478bd9Sstevel@tonic-gate return (dv); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate return (NULL); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Inserts a new dv_node in a parent directory 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate void 4907c478bd9Sstevel@tonic-gate dv_insert(struct dv_node *ddv, struct dv_node *dv) 4917c478bd9Sstevel@tonic-gate { 4927c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&ddv->dv_contents)); 4937c478bd9Sstevel@tonic-gate ASSERT(DVTOV(ddv)->v_type == VDIR); 4947c478bd9Sstevel@tonic-gate ASSERT(ddv->dv_nlink >= 2); 4957c478bd9Sstevel@tonic-gate ASSERT(dv->dv_nlink == 0); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate dcmn_err3(("dv_insert: %s\n", dv->dv_name)); 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate dv->dv_dotdot = ddv; 5007c478bd9Sstevel@tonic-gate dv->dv_next = ddv->dv_dot; 5017c478bd9Sstevel@tonic-gate ddv->dv_dot = dv; 5027c478bd9Sstevel@tonic-gate if (DVTOV(dv)->v_type == VDIR) { 5037c478bd9Sstevel@tonic-gate ddv->dv_nlink++; /* .. to containing directory */ 5047c478bd9Sstevel@tonic-gate dv->dv_nlink = 2; /* name + . */ 5057c478bd9Sstevel@tonic-gate } else { 5067c478bd9Sstevel@tonic-gate dv->dv_nlink = 1; /* name */ 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 511*45a9d961Scth * Unlink a dv_node from a perent directory 512*45a9d961Scth */ 513*45a9d961Scth void 514*45a9d961Scth dv_unlink(struct dv_node *ddv, struct dv_node *dv, struct dv_node **dv_pprev) 515*45a9d961Scth { 516*45a9d961Scth /* verify linkage of arguments */ 517*45a9d961Scth ASSERT(ddv && dv && dv_pprev); 518*45a9d961Scth ASSERT(dv->dv_dotdot == ddv); 519*45a9d961Scth ASSERT(*dv_pprev == dv); 520*45a9d961Scth ASSERT(RW_WRITE_HELD(&ddv->dv_contents)); 521*45a9d961Scth ASSERT(DVTOV(ddv)->v_type == VDIR); 522*45a9d961Scth 523*45a9d961Scth dcmn_err3(("dv_unlink: %s\n", dv->dv_name)); 524*45a9d961Scth 525*45a9d961Scth if (DVTOV(dv)->v_type == VDIR) { 526*45a9d961Scth ddv->dv_nlink--; /* .. to containing directory */ 527*45a9d961Scth dv->dv_nlink -= 2; /* name + . */ 528*45a9d961Scth } else { 529*45a9d961Scth dv->dv_nlink -= 1; /* name */ 530*45a9d961Scth } 531*45a9d961Scth ASSERT(ddv->dv_nlink >= 2); 532*45a9d961Scth ASSERT(dv->dv_nlink == 0); 533*45a9d961Scth 534*45a9d961Scth /* update ddv->dv_dot/dv_next */ 535*45a9d961Scth *dv_pprev = dv->dv_next; 536*45a9d961Scth 537*45a9d961Scth dv->dv_dotdot = NULL; 538*45a9d961Scth dv->dv_next = NULL; 539*45a9d961Scth dv->dv_dot = NULL; 540*45a9d961Scth } 541*45a9d961Scth 542*45a9d961Scth /* 5437c478bd9Sstevel@tonic-gate * Merge devfs node specific information into an attribute structure. 5447c478bd9Sstevel@tonic-gate * 5457c478bd9Sstevel@tonic-gate * NOTE: specfs provides ATIME,MTIME,CTIME,SIZE,BLKSIZE,NBLOCKS on leaf node. 5467c478bd9Sstevel@tonic-gate */ 5477c478bd9Sstevel@tonic-gate void 5487c478bd9Sstevel@tonic-gate dv_vattr_merge(struct dv_node *dv, struct vattr *vap) 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate struct vnode *vp = DVTOV(dv); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate vap->va_nodeid = dv->dv_ino; 5537c478bd9Sstevel@tonic-gate vap->va_nlink = dv->dv_nlink; 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 5567c478bd9Sstevel@tonic-gate vap->va_rdev = 0; 5577c478bd9Sstevel@tonic-gate vap->va_fsid = vp->v_rdev; 5587c478bd9Sstevel@tonic-gate } else { 5597c478bd9Sstevel@tonic-gate vap->va_rdev = vp->v_rdev; 5607c478bd9Sstevel@tonic-gate vap->va_fsid = DVTOV(dv->dv_dotdot)->v_rdev; 5617c478bd9Sstevel@tonic-gate vap->va_type = vp->v_type; 5627c478bd9Sstevel@tonic-gate /* don't trust the shadow file type */ 5637c478bd9Sstevel@tonic-gate vap->va_mode &= ~S_IFMT; 5647c478bd9Sstevel@tonic-gate if (vap->va_type == VCHR) 5657c478bd9Sstevel@tonic-gate vap->va_mode |= S_IFCHR; 5667c478bd9Sstevel@tonic-gate else 5677c478bd9Sstevel@tonic-gate vap->va_mode |= S_IFBLK; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate /* 5727c478bd9Sstevel@tonic-gate * Free a vsecattr 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate static void 5757c478bd9Sstevel@tonic-gate dv_free_vsa(struct vsecattr *vsap) 5767c478bd9Sstevel@tonic-gate { 5777c478bd9Sstevel@tonic-gate if (vsap->vsa_aclcnt > 0 && vsap->vsa_aclentp) 5787c478bd9Sstevel@tonic-gate kmem_free(vsap->vsa_aclentp, 5797c478bd9Sstevel@tonic-gate vsap->vsa_aclcnt * sizeof (aclent_t)); 5807c478bd9Sstevel@tonic-gate if (vsap->vsa_dfaclcnt > 0 && vsap->vsa_dfaclentp) 5817c478bd9Sstevel@tonic-gate kmem_free(vsap->vsa_dfaclentp, 5827c478bd9Sstevel@tonic-gate vsap->vsa_dfaclcnt * sizeof (aclent_t)); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * dv_shadow_node 5877c478bd9Sstevel@tonic-gate * 5887c478bd9Sstevel@tonic-gate * Given a VDIR dv_node, find/create the associated VDIR 5897c478bd9Sstevel@tonic-gate * node in the shadow attribute filesystem. 5907c478bd9Sstevel@tonic-gate * 5917c478bd9Sstevel@tonic-gate * Given a VCHR/VBLK dv_node, find the associated VREG 5927c478bd9Sstevel@tonic-gate * node in the shadow attribute filesystem. These nodes 5937c478bd9Sstevel@tonic-gate * are only created to persist non-default attributes. 5947c478bd9Sstevel@tonic-gate * Lack of such a node implies the default permissions 5957c478bd9Sstevel@tonic-gate * are sufficient. 5967c478bd9Sstevel@tonic-gate * 5977c478bd9Sstevel@tonic-gate * Managing the attribute file entries is slightly tricky (mostly 5987c478bd9Sstevel@tonic-gate * because we can't intercept VN_HOLD and VN_RELE except on the last 5997c478bd9Sstevel@tonic-gate * release). 6007c478bd9Sstevel@tonic-gate * 6017c478bd9Sstevel@tonic-gate * We assert that if the dv_attrvp pointer is non-NULL, it points 6027c478bd9Sstevel@tonic-gate * to a singly-held (by us) vnode that represents the shadow entry 6037c478bd9Sstevel@tonic-gate * in the underlying filesystem. To avoid store-ordering issues, 6047c478bd9Sstevel@tonic-gate * we assert that the pointer can only be tested under the dv_contents 6057c478bd9Sstevel@tonic-gate * READERS lock. 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate void 6097c478bd9Sstevel@tonic-gate dv_shadow_node( 6107c478bd9Sstevel@tonic-gate struct vnode *dvp, /* devfs parent directory vnode */ 6117c478bd9Sstevel@tonic-gate char *nm, /* name component */ 6127c478bd9Sstevel@tonic-gate struct vnode *vp, /* devfs vnode */ 6137c478bd9Sstevel@tonic-gate struct pathname *pnp, /* the path .. */ 6147c478bd9Sstevel@tonic-gate struct vnode *rdir, /* the root .. */ 6157c478bd9Sstevel@tonic-gate struct cred *cred, /* who's asking? */ 6167c478bd9Sstevel@tonic-gate int flags) /* optionally create shadow node */ 6177c478bd9Sstevel@tonic-gate { 6187c478bd9Sstevel@tonic-gate struct dv_node *dv; /* dv_node of named directory */ 6197c478bd9Sstevel@tonic-gate struct vnode *rdvp; /* shadow parent directory vnode */ 6207c478bd9Sstevel@tonic-gate struct vnode *rvp; /* shadow vnode */ 6217c478bd9Sstevel@tonic-gate struct vnode *rrvp; /* realvp of shadow vnode */ 6227c478bd9Sstevel@tonic-gate struct vattr vattr; 6237c478bd9Sstevel@tonic-gate int create_tried; 6247c478bd9Sstevel@tonic-gate int error; 6257c478bd9Sstevel@tonic-gate mperm_t mp; 6267c478bd9Sstevel@tonic-gate struct vsecattr vsa; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VDIR || vp->v_type == VCHR || vp->v_type == VBLK); 6297c478bd9Sstevel@tonic-gate dv = VTODV(vp); 6307c478bd9Sstevel@tonic-gate dcmn_err3(("dv_shadow_node: name %s attr %p\n", 6317c478bd9Sstevel@tonic-gate nm, (void *)dv->dv_attrvp)); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate if ((flags & DV_SHADOW_WRITE_HELD) == 0) { 6347c478bd9Sstevel@tonic-gate ASSERT(RW_READ_HELD(&dv->dv_contents)); 6357c478bd9Sstevel@tonic-gate if (dv->dv_attrvp != NULLVP) 6367c478bd9Sstevel@tonic-gate return; 6377c478bd9Sstevel@tonic-gate if (!rw_tryupgrade(&dv->dv_contents)) { 6387c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 6397c478bd9Sstevel@tonic-gate rw_enter(&dv->dv_contents, RW_WRITER); 6407c478bd9Sstevel@tonic-gate if (dv->dv_attrvp != NULLVP) { 6417c478bd9Sstevel@tonic-gate rw_downgrade(&dv->dv_contents); 6427c478bd9Sstevel@tonic-gate return; 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate } else { 6467c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&dv->dv_contents)); 6477c478bd9Sstevel@tonic-gate if (dv->dv_attrvp != NULLVP) 6487c478bd9Sstevel@tonic-gate return; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&dv->dv_contents) && dv->dv_attrvp == NULL); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate rdvp = VTODV(dvp)->dv_attrvp; 6547c478bd9Sstevel@tonic-gate create_tried = 0; 6557c478bd9Sstevel@tonic-gate lookup: 6567c478bd9Sstevel@tonic-gate if (rdvp && (dv->dv_flags & DV_NO_FSPERM) == 0) { 6577c478bd9Sstevel@tonic-gate error = VOP_LOOKUP(rdvp, nm, &rvp, pnp, LOOKUP_DIR, rdir, cred); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* factor out the snode since we only want the attribute node */ 6607c478bd9Sstevel@tonic-gate if ((error == 0) && (VOP_REALVP(rvp, &rrvp) == 0)) { 6617c478bd9Sstevel@tonic-gate VN_HOLD(rrvp); 6627c478bd9Sstevel@tonic-gate VN_RELE(rvp); 6637c478bd9Sstevel@tonic-gate rvp = rrvp; 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate } else 6667c478bd9Sstevel@tonic-gate error = EROFS; /* no parent, no entry */ 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* 6697c478bd9Sstevel@tonic-gate * All we want is the permissions (and maybe ACLs and 6707c478bd9Sstevel@tonic-gate * extended attributes), and we want to perform lookups 6717c478bd9Sstevel@tonic-gate * by name. Drivers occasionally change their minor 6727c478bd9Sstevel@tonic-gate * number space. If something changes, there's no 6737c478bd9Sstevel@tonic-gate * much we can do about it here. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* The shadow node checks out. We are done */ 6777c478bd9Sstevel@tonic-gate if (error == 0) { 6787c478bd9Sstevel@tonic-gate dv->dv_attrvp = rvp; /* with one hold */ 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* 6817c478bd9Sstevel@tonic-gate * Determine if we have (non-trivial) ACLs on this node. 6827c478bd9Sstevel@tonic-gate * NB: This should be changed call fs_acl_nontrivial for 6837c478bd9Sstevel@tonic-gate * new ACE flavor ACLs. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate vsa.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT; 6867c478bd9Sstevel@tonic-gate error = VOP_GETSECATTR(rvp, &vsa, 0, cred); 6877c478bd9Sstevel@tonic-gate dv->dv_flags &= ~DV_ACL; 6887c478bd9Sstevel@tonic-gate if (error == 0) { 6897c478bd9Sstevel@tonic-gate if (vsa.vsa_aclcnt > MIN_ACL_ENTRIES) { 6907c478bd9Sstevel@tonic-gate dv->dv_flags |= DV_ACL; /* non-trivial ACL */ 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate dv_free_vsa(&vsa); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * If we have synced out the memory attributes, free 6977c478bd9Sstevel@tonic-gate * them and switch back to using the persistent store. 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate if (rvp && dv->dv_attr) { 7007c478bd9Sstevel@tonic-gate kmem_free(dv->dv_attr, sizeof (struct vattr)); 7017c478bd9Sstevel@tonic-gate dv->dv_attr = NULL; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate if ((flags & DV_SHADOW_WRITE_HELD) == 0) 7047c478bd9Sstevel@tonic-gate rw_downgrade(&dv->dv_contents); 7057c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&dv->dv_contents)); 7067c478bd9Sstevel@tonic-gate return; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * Failed to find attribute in persistent backing store, 7117c478bd9Sstevel@tonic-gate * get default permission bits. For minors not created by 7127c478bd9Sstevel@tonic-gate * ddi_create_priv_minor_node(), use devfs defaults. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 7157c478bd9Sstevel@tonic-gate vattr = dv_vattr_dir; 7167c478bd9Sstevel@tonic-gate } else if (dv->dv_flags & DV_NO_FSPERM) { 7177c478bd9Sstevel@tonic-gate vattr = dv_vattr_priv; 7187c478bd9Sstevel@tonic-gate } else { 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * look up perm bits from minor_perm 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate vattr = dv_vattr_file; 7237c478bd9Sstevel@tonic-gate if (dev_minorperm(dv->dv_devi, dv->dv_name, &mp) == 0) { 7247c478bd9Sstevel@tonic-gate VATTR_MP_MERGE(vattr, mp); 7257c478bd9Sstevel@tonic-gate dcmn_err5(("%s: minor perm mode 0%o\n", 7267c478bd9Sstevel@tonic-gate dv->dv_name, vattr.va_mode)); 7277c478bd9Sstevel@tonic-gate } else if (dv->dv_flags & DV_DFLT_MODE) { 7287c478bd9Sstevel@tonic-gate ASSERT((dv->dv_dflt_mode & ~S_IAMB) == 0); 7297c478bd9Sstevel@tonic-gate vattr.va_mode &= ~S_IAMB; 7307c478bd9Sstevel@tonic-gate vattr.va_mode |= dv->dv_dflt_mode; 7317c478bd9Sstevel@tonic-gate dcmn_err5(("%s: priv mode 0%o\n", 7327c478bd9Sstevel@tonic-gate dv->dv_name, vattr.va_mode)); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate dv_vattr_merge(dv, &vattr); 7377c478bd9Sstevel@tonic-gate gethrestime(&vattr.va_atime); 7387c478bd9Sstevel@tonic-gate vattr.va_mtime = vattr.va_atime; 7397c478bd9Sstevel@tonic-gate vattr.va_ctime = vattr.va_atime; 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * Try to create shadow dir. This is necessary in case 7437c478bd9Sstevel@tonic-gate * we need to create a shadow leaf node later, when user 7447c478bd9Sstevel@tonic-gate * executes chmod. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate if ((error == ENOENT) && !create_tried) { 7477c478bd9Sstevel@tonic-gate switch (vp->v_type) { 7487c478bd9Sstevel@tonic-gate case VDIR: 7497c478bd9Sstevel@tonic-gate error = VOP_MKDIR(rdvp, nm, &vattr, &rvp, kcred); 7507c478bd9Sstevel@tonic-gate dsysdebug(error, ("vop_mkdir %s %s %d\n", 7517c478bd9Sstevel@tonic-gate VTODV(dvp)->dv_name, nm, error)); 7527c478bd9Sstevel@tonic-gate create_tried = 1; 7537c478bd9Sstevel@tonic-gate break; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate case VCHR: 7567c478bd9Sstevel@tonic-gate case VBLK: 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * Shadow nodes are only created on demand 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate if (flags & DV_SHADOW_CREATE) { 7617c478bd9Sstevel@tonic-gate error = VOP_CREATE(rdvp, nm, &vattr, NONEXCL, 7627c478bd9Sstevel@tonic-gate VREAD|VWRITE, &rvp, kcred, 0); 7637c478bd9Sstevel@tonic-gate dsysdebug(error, ("vop_create %s %s %d\n", 7647c478bd9Sstevel@tonic-gate VTODV(dvp)->dv_name, nm, error)); 7657c478bd9Sstevel@tonic-gate create_tried = 1; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate break; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate default: 7707c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "devfs: %s: create", dvnm); 7717c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate if (create_tried && 7757c478bd9Sstevel@tonic-gate (error == 0) || (error == EEXIST)) { 7767c478bd9Sstevel@tonic-gate VN_RELE(rvp); 7777c478bd9Sstevel@tonic-gate goto lookup; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* Store attribute in memory */ 7827c478bd9Sstevel@tonic-gate if (dv->dv_attr == NULL) { 7837c478bd9Sstevel@tonic-gate dv->dv_attr = kmem_alloc(sizeof (struct vattr), KM_SLEEP); 7847c478bd9Sstevel@tonic-gate *(dv->dv_attr) = vattr; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate if ((flags & DV_SHADOW_WRITE_HELD) == 0) 7887c478bd9Sstevel@tonic-gate rw_downgrade(&dv->dv_contents); 7897c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&dv->dv_contents)); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* 7937c478bd9Sstevel@tonic-gate * Given a devinfo node, and a name, returns the appropriate 7947c478bd9Sstevel@tonic-gate * minor information for that named node, if it exists. 7957c478bd9Sstevel@tonic-gate */ 7967c478bd9Sstevel@tonic-gate static int 7977c478bd9Sstevel@tonic-gate dv_find_leafnode(dev_info_t *devi, char *minor_nm, struct ddi_minor_data *r_mi) 7987c478bd9Sstevel@tonic-gate { 7997c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmd; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate ASSERT(i_ddi_node_state(devi) >= DS_ATTACHED); 8027c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&DEVI(devi)->devi_lock)); 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate dcmn_err3(("dv_find_leafnode: %s\n", minor_nm)); 8057c478bd9Sstevel@tonic-gate for (dmd = DEVI(devi)->devi_minor; dmd; dmd = dmd->next) { 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate /* 8087c478bd9Sstevel@tonic-gate * Skip alias nodes and nodes without a name. 8097c478bd9Sstevel@tonic-gate */ 8107c478bd9Sstevel@tonic-gate if ((dmd->type == DDM_ALIAS) || (dmd->ddm_name == NULL)) 8117c478bd9Sstevel@tonic-gate continue; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate dcmn_err4(("dv_find_leafnode: (%s,%s)\n", 8147c478bd9Sstevel@tonic-gate minor_nm, dmd->ddm_name)); 8157c478bd9Sstevel@tonic-gate if (strcmp(minor_nm, dmd->ddm_name) == 0) { 8167c478bd9Sstevel@tonic-gate r_mi->ddm_dev = dmd->ddm_dev; 8177c478bd9Sstevel@tonic-gate r_mi->ddm_spec_type = dmd->ddm_spec_type; 8187c478bd9Sstevel@tonic-gate r_mi->type = dmd->type; 8197c478bd9Sstevel@tonic-gate r_mi->ddm_flags = dmd->ddm_flags; 8207c478bd9Sstevel@tonic-gate r_mi->ddm_node_priv = dmd->ddm_node_priv; 8217c478bd9Sstevel@tonic-gate r_mi->ddm_priv_mode = dmd->ddm_priv_mode; 8227c478bd9Sstevel@tonic-gate if (r_mi->ddm_node_priv) 8237c478bd9Sstevel@tonic-gate dphold(r_mi->ddm_node_priv); 8247c478bd9Sstevel@tonic-gate return (0); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate dcmn_err3(("dv_find_leafnode: %s: ENOENT\n", minor_nm)); 8297c478bd9Sstevel@tonic-gate return (ENOENT); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * Special handling for clone node: 8347c478bd9Sstevel@tonic-gate * Clone minor name is a driver name, the minor number will 8357c478bd9Sstevel@tonic-gate * be the major number of the driver. There is no minor 8367c478bd9Sstevel@tonic-gate * node under the clone driver, so we'll manufacture the 8377c478bd9Sstevel@tonic-gate * dev_t. 8387c478bd9Sstevel@tonic-gate */ 8397c478bd9Sstevel@tonic-gate static struct dv_node * 8407c478bd9Sstevel@tonic-gate dv_clone_mknod(struct dv_node *ddv, char *drvname) 8417c478bd9Sstevel@tonic-gate { 8427c478bd9Sstevel@tonic-gate major_t major; 8437c478bd9Sstevel@tonic-gate struct dv_node *dvp; 8447c478bd9Sstevel@tonic-gate char *devnm; 8457c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmd; 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate /* 8487c478bd9Sstevel@tonic-gate * Make sure drvname is a STREAMS driver. We load the driver, 8497c478bd9Sstevel@tonic-gate * but don't attach to any instances. This makes stat(2) 8507c478bd9Sstevel@tonic-gate * relatively cheap. 8517c478bd9Sstevel@tonic-gate */ 8527c478bd9Sstevel@tonic-gate major = ddi_name_to_major(drvname); 8537c478bd9Sstevel@tonic-gate if (major == (major_t)-1) 8547c478bd9Sstevel@tonic-gate return (NULL); 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate if (ddi_hold_driver(major) == NULL) 8577c478bd9Sstevel@tonic-gate return (NULL); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate if (STREAMSTAB(major) == NULL) { 8607c478bd9Sstevel@tonic-gate ddi_rele_driver(major); 8617c478bd9Sstevel@tonic-gate return (NULL); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate ddi_rele_driver(major); 8657c478bd9Sstevel@tonic-gate devnm = kmem_alloc(MAXNAMELEN, KM_SLEEP); 8667c478bd9Sstevel@tonic-gate (void) snprintf(devnm, MAXNAMELEN, "clone@0:%s", drvname); 8677c478bd9Sstevel@tonic-gate dmd = kmem_zalloc(sizeof (*dmd), KM_SLEEP); 8687c478bd9Sstevel@tonic-gate dmd->ddm_dev = makedevice(clone_major, (minor_t)major); 8697c478bd9Sstevel@tonic-gate dmd->ddm_spec_type = S_IFCHR; 8707c478bd9Sstevel@tonic-gate dvp = dv_mknod(ddv, clone_dip, devnm, dmd); 8717c478bd9Sstevel@tonic-gate kmem_free(dmd, sizeof (*dmd)); 8727c478bd9Sstevel@tonic-gate kmem_free(devnm, MAXNAMELEN); 8737c478bd9Sstevel@tonic-gate return (dvp); 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate /* 8777c478bd9Sstevel@tonic-gate * Given the parent directory node, and a name in it, returns the 8787c478bd9Sstevel@tonic-gate * named dv_node to the caller (as a vnode). 8797c478bd9Sstevel@tonic-gate * 8807c478bd9Sstevel@tonic-gate * (We need pnp and rdir for doing shadow lookups; they can be NULL) 8817c478bd9Sstevel@tonic-gate */ 8827c478bd9Sstevel@tonic-gate int 8837c478bd9Sstevel@tonic-gate dv_find(struct dv_node *ddv, char *nm, struct vnode **vpp, struct pathname *pnp, 8847c478bd9Sstevel@tonic-gate struct vnode *rdir, struct cred *cred, uint_t ndi_flags) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate extern int isminiroot; /* see modctl.c */ 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate int rv = 0, was_busy = 0, nmlen; 8897c478bd9Sstevel@tonic-gate struct vnode *vp; 8907c478bd9Sstevel@tonic-gate struct dv_node *dv, *dup; 8917c478bd9Sstevel@tonic-gate dev_info_t *pdevi, *devi = NULL; 8927c478bd9Sstevel@tonic-gate char *mnm; 8937c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmd; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate dcmn_err3(("dv_find %s\n", nm)); 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_READER); 8987c478bd9Sstevel@tonic-gate start: 8997c478bd9Sstevel@tonic-gate if (DV_STALE(ddv)) { 9007c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9017c478bd9Sstevel@tonic-gate return (ESTALE); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Empty name or ., return node itself. 9067c478bd9Sstevel@tonic-gate */ 9077c478bd9Sstevel@tonic-gate nmlen = strlen(nm); 9087c478bd9Sstevel@tonic-gate if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) { 9097c478bd9Sstevel@tonic-gate *vpp = DVTOV(ddv); 9107c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9117c478bd9Sstevel@tonic-gate VN_HOLD(*vpp); 9127c478bd9Sstevel@tonic-gate return (0); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* 9167c478bd9Sstevel@tonic-gate * .., return the parent directory 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate if ((nmlen == 2) && (strcmp(nm, "..") == 0)) { 9197c478bd9Sstevel@tonic-gate *vpp = DVTOV(ddv->dv_dotdot); 9207c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9217c478bd9Sstevel@tonic-gate VN_HOLD(*vpp); 9227c478bd9Sstevel@tonic-gate return (0); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * Fail anything without a valid device name component 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate if (nm[0] == '@' || nm[0] == ':') { 9297c478bd9Sstevel@tonic-gate dcmn_err3(("devfs: no driver '%s'\n", nm)); 9307c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9317c478bd9Sstevel@tonic-gate return (ENOENT); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /* 9357c478bd9Sstevel@tonic-gate * So, now we have to deal with the trickier stuff. 9367c478bd9Sstevel@tonic-gate * 9377c478bd9Sstevel@tonic-gate * (a) search the existing list of dv_nodes on this directory 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate if ((dv = dv_findbyname(ddv, nm)) != NULL) { 9407c478bd9Sstevel@tonic-gate founddv: 9417c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&ddv->dv_contents)); 9427c478bd9Sstevel@tonic-gate rw_enter(&dv->dv_contents, RW_READER); 9437c478bd9Sstevel@tonic-gate vp = DVTOV(dv); 9447c478bd9Sstevel@tonic-gate if ((dv->dv_attrvp != NULLVP) || 9457c478bd9Sstevel@tonic-gate (vp->v_type != VDIR && dv->dv_attr != NULL)) { 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * Common case - we already have attributes 9487c478bd9Sstevel@tonic-gate */ 9497c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 9507c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9517c478bd9Sstevel@tonic-gate goto found; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * No attribute vp, try and build one. 9567c478bd9Sstevel@tonic-gate */ 9577c478bd9Sstevel@tonic-gate dv_shadow_node(DVTOV(ddv), nm, vp, pnp, rdir, cred, 0); 9587c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 9597c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9607c478bd9Sstevel@tonic-gate goto found; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * (b) Search the child devinfo nodes of our parent directory, 9657c478bd9Sstevel@tonic-gate * looking for the named node. If we find it, build a new 9667c478bd9Sstevel@tonic-gate * node, then grab the writers lock, search the directory 9677c478bd9Sstevel@tonic-gate * if it's still not there, then insert it. 9687c478bd9Sstevel@tonic-gate * 9697c478bd9Sstevel@tonic-gate * We drop the devfs locks before accessing the device tree. 9707c478bd9Sstevel@tonic-gate * Take care to mark the node BUSY so that a forced devfs_clean 9717c478bd9Sstevel@tonic-gate * doesn't mark the directory node stale. 9727c478bd9Sstevel@tonic-gate * 9737c478bd9Sstevel@tonic-gate * Also, check if we are called as part of devfs_clean or 9747c478bd9Sstevel@tonic-gate * reset_perm. If so, simply return not found because there 9757c478bd9Sstevel@tonic-gate * is nothing to clean. 9767c478bd9Sstevel@tonic-gate */ 9777c478bd9Sstevel@tonic-gate if (tsd_get(devfs_clean_key)) { 9787c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9797c478bd9Sstevel@tonic-gate return (ENOENT); 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* 9837c478bd9Sstevel@tonic-gate * We could be either READ or WRITE locked at 9847c478bd9Sstevel@tonic-gate * this point. Upgrade if we are read locked. 9857c478bd9Sstevel@tonic-gate */ 9867c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&ddv->dv_contents)); 9877c478bd9Sstevel@tonic-gate if (rw_read_locked(&ddv->dv_contents) && 9887c478bd9Sstevel@tonic-gate !rw_tryupgrade(&ddv->dv_contents)) { 9897c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 9907c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_WRITER); 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * Things may have changed when we dropped 9937c478bd9Sstevel@tonic-gate * the contents lock, so start from top again 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate goto start; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate ddv->dv_busy++; /* mark busy before dropping lock */ 9987c478bd9Sstevel@tonic-gate was_busy++; 9997c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate pdevi = ddv->dv_devi; 10027c478bd9Sstevel@tonic-gate ASSERT(pdevi != NULL); 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate mnm = strchr(nm, ':'); 10057c478bd9Sstevel@tonic-gate if (mnm) 10067c478bd9Sstevel@tonic-gate *mnm = (char)0; 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate /* 10097c478bd9Sstevel@tonic-gate * Configure one nexus child, will call nexus's bus_ops 10107c478bd9Sstevel@tonic-gate * If successful, devi is held upon returning. 10117c478bd9Sstevel@tonic-gate * Note: devfs lookup should not be configuring grandchildren. 10127c478bd9Sstevel@tonic-gate */ 10137c478bd9Sstevel@tonic-gate ASSERT((ndi_flags & NDI_CONFIG) == 0); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate rv = ndi_devi_config_one(pdevi, nm, &devi, ndi_flags | NDI_NO_EVENT); 10167c478bd9Sstevel@tonic-gate if (mnm) 10177c478bd9Sstevel@tonic-gate *mnm = ':'; 10187c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 10197c478bd9Sstevel@tonic-gate rv = ENOENT; 10207c478bd9Sstevel@tonic-gate goto notfound; 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * Don't make vhci clients visible under phci, unless we 10257c478bd9Sstevel@tonic-gate * are in miniroot. 10267c478bd9Sstevel@tonic-gate */ 10277c478bd9Sstevel@tonic-gate if (isminiroot == 0 && ddi_get_parent(devi) != pdevi) { 10287c478bd9Sstevel@tonic-gate ndi_rele_devi(devi); 10297c478bd9Sstevel@tonic-gate rv = ENOENT; 10307c478bd9Sstevel@tonic-gate goto notfound; 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate ASSERT(devi && (i_ddi_node_state(devi) >= DS_ATTACHED)); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Invalidate cache to notice newly created minor nodes. 10377c478bd9Sstevel@tonic-gate */ 10387c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_WRITER); 10397c478bd9Sstevel@tonic-gate ddv->dv_flags |= DV_BUILD; 10407c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * mkdir for nexus drivers and leaf nodes as well. If we are racing 10447c478bd9Sstevel@tonic-gate * and create a duplicate, the duplicate will be destroyed below. 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate if (mnm == NULL) { 10477c478bd9Sstevel@tonic-gate dv = dv_mkdir(ddv, devi, nm); 10487c478bd9Sstevel@tonic-gate } else { 10497c478bd9Sstevel@tonic-gate /* 10507c478bd9Sstevel@tonic-gate * For clone minors, load the driver indicated by minor name. 10517c478bd9Sstevel@tonic-gate */ 10527c478bd9Sstevel@tonic-gate mutex_enter(&DEVI(devi)->devi_lock); 10537c478bd9Sstevel@tonic-gate if (devi == clone_dip) { 10547c478bd9Sstevel@tonic-gate dv = dv_clone_mknod(ddv, mnm + 1); 10557c478bd9Sstevel@tonic-gate } else { 10567c478bd9Sstevel@tonic-gate /* 10577c478bd9Sstevel@tonic-gate * Find minor node and make a dv_node 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate dmd = kmem_zalloc(sizeof (*dmd), KM_SLEEP); 10607c478bd9Sstevel@tonic-gate if (dv_find_leafnode(devi, mnm + 1, dmd) == 0) { 10617c478bd9Sstevel@tonic-gate dv = dv_mknod(ddv, devi, nm, dmd); 10627c478bd9Sstevel@tonic-gate if (dmd->ddm_node_priv) 10637c478bd9Sstevel@tonic-gate dpfree(dmd->ddm_node_priv); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate kmem_free(dmd, sizeof (*dmd)); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate mutex_exit(&DEVI(devi)->devi_lock); 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate /* 10707c478bd9Sstevel@tonic-gate * Release hold from ndi_devi_config_one() 10717c478bd9Sstevel@tonic-gate */ 10727c478bd9Sstevel@tonic-gate ndi_rele_devi(devi); 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if (dv == NULL) { 10757c478bd9Sstevel@tonic-gate rv = ENOENT; 10767c478bd9Sstevel@tonic-gate goto notfound; 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * We have released the dv_contents lock, need to check 10817c478bd9Sstevel@tonic-gate * if another thread already created a duplicate node 10827c478bd9Sstevel@tonic-gate */ 10837c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_WRITER); 10847c478bd9Sstevel@tonic-gate if ((dup = dv_findbyname(ddv, nm)) == NULL) { 10857c478bd9Sstevel@tonic-gate dv_insert(ddv, dv); 10867c478bd9Sstevel@tonic-gate } else { 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * Duplicate found, use the existing node 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate VN_RELE(DVTOV(dv)); 10917c478bd9Sstevel@tonic-gate dv_destroy(dv, 0); 10927c478bd9Sstevel@tonic-gate dv = dup; 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate goto founddv; 10957c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate found: 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * Skip non-kernel lookups of internal nodes. 11007c478bd9Sstevel@tonic-gate * This use of kcred to distinguish between user and 11017c478bd9Sstevel@tonic-gate * internal kernel lookups is unfortunate. The information 11027c478bd9Sstevel@tonic-gate * provided by the seg argument to lookupnameat should 11037c478bd9Sstevel@tonic-gate * evolve into a lookup flag for filesystems that need 11047c478bd9Sstevel@tonic-gate * this distinction. 11057c478bd9Sstevel@tonic-gate */ 11067c478bd9Sstevel@tonic-gate if ((dv->dv_flags & DV_INTERNAL) && (cred != kcred)) { 11077c478bd9Sstevel@tonic-gate VN_RELE(vp); 11087c478bd9Sstevel@tonic-gate rv = ENOENT; 11097c478bd9Sstevel@tonic-gate goto notfound; 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate dcmn_err2(("dv_find: returning vp for nm %s\n", nm)); 11137c478bd9Sstevel@tonic-gate if (vp->v_type == VCHR || vp->v_type == VBLK) { 11147c478bd9Sstevel@tonic-gate /* 11157c478bd9Sstevel@tonic-gate * If vnode is a device, return special vnode instead 11167c478bd9Sstevel@tonic-gate * (though it knows all about -us- via sp->s_realvp, 11177c478bd9Sstevel@tonic-gate * sp->s_devvp, and sp->s_dip) 11187c478bd9Sstevel@tonic-gate */ 11197c478bd9Sstevel@tonic-gate *vpp = specvp_devfs(vp, vp->v_rdev, vp->v_type, cred, 11207c478bd9Sstevel@tonic-gate dv->dv_devi); 11217c478bd9Sstevel@tonic-gate VN_RELE(vp); 11227c478bd9Sstevel@tonic-gate if (*vpp == NULLVP) 11237c478bd9Sstevel@tonic-gate rv = ENOSYS; 11247c478bd9Sstevel@tonic-gate } else 11257c478bd9Sstevel@tonic-gate *vpp = vp; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate notfound: 11287c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_WRITER); 11297c478bd9Sstevel@tonic-gate if (was_busy) 11307c478bd9Sstevel@tonic-gate ddv->dv_busy--; 11317c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 11327c478bd9Sstevel@tonic-gate return (rv); 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * The given directory node is out-of-date; that is, it has been 11377c478bd9Sstevel@tonic-gate * marked as needing to be rebuilt, possibly because some new devinfo 11387c478bd9Sstevel@tonic-gate * node has come into existence, or possibly because this is the first 11397c478bd9Sstevel@tonic-gate * time we've been here. 11407c478bd9Sstevel@tonic-gate */ 11417c478bd9Sstevel@tonic-gate void 11427c478bd9Sstevel@tonic-gate dv_filldir(struct dv_node *ddv) 11437c478bd9Sstevel@tonic-gate { 11447c478bd9Sstevel@tonic-gate struct dv_node *dv; 11457c478bd9Sstevel@tonic-gate dev_info_t *devi, *pdevi; 11467c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmd; 11477c478bd9Sstevel@tonic-gate char devnm[MAXNAMELEN]; 11487c478bd9Sstevel@tonic-gate int circ; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate ASSERT(DVTOV(ddv)->v_type == VDIR); 11517c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&ddv->dv_contents)); 11527c478bd9Sstevel@tonic-gate ASSERT(ddv->dv_flags & DV_BUILD); 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate dcmn_err3(("dv_filldir: %s\n", ddv->dv_name)); 11557c478bd9Sstevel@tonic-gate if (DV_STALE(ddv)) 11567c478bd9Sstevel@tonic-gate return; 11577c478bd9Sstevel@tonic-gate pdevi = ddv->dv_devi; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate if (ndi_devi_config(pdevi, NDI_NO_EVENT) != NDI_SUCCESS) { 11607c478bd9Sstevel@tonic-gate dcmn_err3(("dv_filldir: config error %s\n", 11617c478bd9Sstevel@tonic-gate ddv->dv_name)); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate ndi_devi_enter(pdevi, &circ); 11657c478bd9Sstevel@tonic-gate for (devi = ddi_get_child(pdevi); devi; 11667c478bd9Sstevel@tonic-gate devi = ddi_get_next_sibling(devi)) { 11677c478bd9Sstevel@tonic-gate if (i_ddi_node_state(devi) < DS_PROBED) 11687c478bd9Sstevel@tonic-gate continue; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate dcmn_err3(("dv_filldir: node %s\n", ddi_node_name(devi))); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate mutex_enter(&DEVI(devi)->devi_lock); 11737c478bd9Sstevel@tonic-gate for (dmd = DEVI(devi)->devi_minor; dmd; dmd = dmd->next) { 11747c478bd9Sstevel@tonic-gate char *addr; 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate /* 11777c478bd9Sstevel@tonic-gate * Skip alias nodes, internal nodes, and nodes 11787c478bd9Sstevel@tonic-gate * without a name. We allow DDM_DEFAULT nodes 11797c478bd9Sstevel@tonic-gate * to appear in readdir. 11807c478bd9Sstevel@tonic-gate */ 11817c478bd9Sstevel@tonic-gate if ((dmd->type == DDM_ALIAS) || 11827c478bd9Sstevel@tonic-gate (dmd->type == DDM_INTERNAL_PATH) || 11837c478bd9Sstevel@tonic-gate (dmd->ddm_name == NULL)) 11847c478bd9Sstevel@tonic-gate continue; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate addr = ddi_get_name_addr(devi); 11877c478bd9Sstevel@tonic-gate if (addr && *addr) 11887c478bd9Sstevel@tonic-gate (void) sprintf(devnm, "%s@%s:%s", 11897c478bd9Sstevel@tonic-gate ddi_node_name(devi), addr, dmd->ddm_name); 11907c478bd9Sstevel@tonic-gate else 11917c478bd9Sstevel@tonic-gate (void) sprintf(devnm, "%s:%s", 11927c478bd9Sstevel@tonic-gate ddi_node_name(devi), dmd->ddm_name); 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate if ((dv = dv_findbyname(ddv, devnm)) != NULL) { 11957c478bd9Sstevel@tonic-gate /* dv_node already exists */ 11967c478bd9Sstevel@tonic-gate VN_RELE(DVTOV(dv)); 11977c478bd9Sstevel@tonic-gate continue; 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate dv = dv_mknod(ddv, devi, devnm, dmd); 12017c478bd9Sstevel@tonic-gate dv_insert(ddv, dv); 12027c478bd9Sstevel@tonic-gate VN_RELE(DVTOV(dv)); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate mutex_exit(&DEVI(devi)->devi_lock); 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate (void) ddi_deviname(devi, devnm); 12077c478bd9Sstevel@tonic-gate if ((dv = dv_findbyname(ddv, devnm + 1)) == NULL) { 12087c478bd9Sstevel@tonic-gate /* directory doesn't exist */ 12097c478bd9Sstevel@tonic-gate dv = dv_mkdir(ddv, devi, devnm + 1); 12107c478bd9Sstevel@tonic-gate dv_insert(ddv, dv); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate VN_RELE(DVTOV(dv)); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate ndi_devi_exit(pdevi, circ); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate ddv->dv_flags &= ~DV_BUILD; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * Given a directory node, clean out all the nodes beneath. 12217c478bd9Sstevel@tonic-gate * 12227c478bd9Sstevel@tonic-gate * VDIR: Reinvoke to clean them, then delete the directory. 12237c478bd9Sstevel@tonic-gate * VCHR, VBLK: Just blow them away. 12247c478bd9Sstevel@tonic-gate * 12257c478bd9Sstevel@tonic-gate * Mark the directories touched as in need of a rebuild, in case 12267c478bd9Sstevel@tonic-gate * we fall over part way through. When DV_CLEAN_FORCE is specified, 12277c478bd9Sstevel@tonic-gate * we mark referenced empty directories as stale to facilitate DR. 12287c478bd9Sstevel@tonic-gate */ 12297c478bd9Sstevel@tonic-gate int 12307c478bd9Sstevel@tonic-gate dv_cleandir(struct dv_node *ddv, char *devnm, uint_t flags) 12317c478bd9Sstevel@tonic-gate { 1232*45a9d961Scth struct dv_node *dv; 1233*45a9d961Scth struct dv_node **pprev, **npprev; 12347c478bd9Sstevel@tonic-gate struct vnode *vp; 1235*45a9d961Scth int busy = 0; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate dcmn_err3(("dv_cleandir: %s\n", ddv->dv_name)); 12387c478bd9Sstevel@tonic-gate 1239*45a9d961Scth if (!(flags & DV_CLEANDIR_LCK)) 12407c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_WRITER); 1241*45a9d961Scth for (pprev = &ddv->dv_dot, dv = *pprev; dv; 1242*45a9d961Scth pprev = npprev, dv = *pprev) { 1243*45a9d961Scth npprev = &dv->dv_next; 12447c478bd9Sstevel@tonic-gate 1245*45a9d961Scth /* 1246*45a9d961Scth * If devnm is specified, the non-minor portion of the 1247*45a9d961Scth * name must match devnm. 1248*45a9d961Scth */ 1249*45a9d961Scth if (devnm && 1250*45a9d961Scth (strncmp(devnm, dv->dv_name, strlen(devnm)) || 12517c478bd9Sstevel@tonic-gate (dv->dv_name[strlen(devnm)] != ':' && 12527c478bd9Sstevel@tonic-gate dv->dv_name[strlen(devnm)] != '\0'))) 12537c478bd9Sstevel@tonic-gate continue; 12547c478bd9Sstevel@tonic-gate 1255*45a9d961Scth /* check type of what we are cleaning */ 12567c478bd9Sstevel@tonic-gate vp = DVTOV(dv); 12577c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 1258*45a9d961Scth /* recurse on directories */ 12597c478bd9Sstevel@tonic-gate rw_enter(&dv->dv_contents, RW_WRITER); 1260*45a9d961Scth if (dv_cleandir(dv, NULL, 1261*45a9d961Scth flags | DV_CLEANDIR_LCK) == EBUSY) { 12627c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 1263*45a9d961Scth goto set_busy; 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 1266*45a9d961Scth /* A clean directory is an empty directory... */ 1267*45a9d961Scth ASSERT(dv->dv_nlink == 2); 1268*45a9d961Scth mutex_enter(&vp->v_lock); 1269*45a9d961Scth if (vp->v_count > 0) { 1270*45a9d961Scth /* 1271*45a9d961Scth * ... but an empty directory can still have 1272*45a9d961Scth * references to it. If we have dv_busy or 1273*45a9d961Scth * DV_CLEAN_FORCE is *not* specified then a 1274*45a9d961Scth * referenced directory is considered busy. 1275*45a9d961Scth */ 1276*45a9d961Scth if (dv->dv_busy || !(flags & DV_CLEAN_FORCE)) { 1277*45a9d961Scth mutex_exit(&vp->v_lock); 1278*45a9d961Scth rw_exit(&dv->dv_contents); 1279*45a9d961Scth goto set_busy; 1280*45a9d961Scth } 1281*45a9d961Scth 1282*45a9d961Scth /* 1283*45a9d961Scth * Mark referenced directory stale so that DR 1284*45a9d961Scth * will succeed even if a shell has 1285*45a9d961Scth * /devices/xxx as current directory (causing 1286*45a9d961Scth * VN_HOLD reference to an empty directory). 1287*45a9d961Scth */ 1288*45a9d961Scth ASSERT(!DV_STALE(dv)); 1289*45a9d961Scth ndi_rele_devi(dv->dv_devi); 1290*45a9d961Scth dv->dv_devi = NULL; /* mark DV_STALE */ 1291*45a9d961Scth } 1292*45a9d961Scth } else { 1293*45a9d961Scth ASSERT((vp->v_type == VCHR) || (vp->v_type == VBLK)); 1294*45a9d961Scth ASSERT(dv->dv_nlink == 1); /* no hard links */ 1295*45a9d961Scth mutex_enter(&vp->v_lock); 1296*45a9d961Scth if (vp->v_count > 0) { 1297*45a9d961Scth mutex_exit(&vp->v_lock); 1298*45a9d961Scth goto set_busy; 1299*45a9d961Scth } 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* unlink from directory */ 1303*45a9d961Scth dv_unlink(ddv, dv, pprev); 13047c478bd9Sstevel@tonic-gate 1305*45a9d961Scth /* drop locks */ 1306*45a9d961Scth mutex_exit(&vp->v_lock); 1307*45a9d961Scth if (vp->v_type == VDIR) 1308*45a9d961Scth rw_exit(&dv->dv_contents); 1309*45a9d961Scth 1310*45a9d961Scth /* destroy vnode if ref count is zero */ 1311*45a9d961Scth if (vp->v_count == 0) 1312*45a9d961Scth dv_destroy(dv, flags); 1313*45a9d961Scth 1314*45a9d961Scth /* pointer to previous stays unchanged */ 1315*45a9d961Scth npprev = pprev; 1316*45a9d961Scth continue; 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate /* 1319*45a9d961Scth * If devnm is not NULL we return immediately on busy, 1320*45a9d961Scth * otherwise we continue destroying unused dv_node's. 13217c478bd9Sstevel@tonic-gate */ 1322*45a9d961Scth set_busy: busy++; 1323*45a9d961Scth if (devnm) 1324*45a9d961Scth break; 13257c478bd9Sstevel@tonic-gate } 1326*45a9d961Scth 13277c478bd9Sstevel@tonic-gate /* 13287c478bd9Sstevel@tonic-gate * This code may be invoked to inform devfs that a new node has 13297c478bd9Sstevel@tonic-gate * been created in the kernel device tree. So we always set 13307c478bd9Sstevel@tonic-gate * the DV_BUILD flag to allow the next dv_filldir() to pick 13317c478bd9Sstevel@tonic-gate * the new devinfo nodes. 13327c478bd9Sstevel@tonic-gate */ 13337c478bd9Sstevel@tonic-gate ddv->dv_flags |= DV_BUILD; 13347c478bd9Sstevel@tonic-gate 1335*45a9d961Scth if (!(flags & DV_CLEANDIR_LCK)) 13367c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 13377c478bd9Sstevel@tonic-gate 1338*45a9d961Scth return (busy ? EBUSY : 0); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * Walk through the devfs hierarchy, correcting the permissions of 13437c478bd9Sstevel@tonic-gate * devices with default permissions that do not match those specified 13447c478bd9Sstevel@tonic-gate * by minor perm. This can only be done for all drivers for now. 13457c478bd9Sstevel@tonic-gate */ 13467c478bd9Sstevel@tonic-gate static int 13477c478bd9Sstevel@tonic-gate dv_reset_perm_dir(struct dv_node *ddv, uint_t flags) 13487c478bd9Sstevel@tonic-gate { 13497c478bd9Sstevel@tonic-gate struct dv_node *dv, *next = NULL; 13507c478bd9Sstevel@tonic-gate struct vnode *vp; 13517c478bd9Sstevel@tonic-gate int retval = 0; 13527c478bd9Sstevel@tonic-gate struct vattr *attrp; 13537c478bd9Sstevel@tonic-gate mperm_t mp; 13547c478bd9Sstevel@tonic-gate char *nm; 13557c478bd9Sstevel@tonic-gate uid_t old_uid; 13567c478bd9Sstevel@tonic-gate gid_t old_gid; 13577c478bd9Sstevel@tonic-gate mode_t old_mode; 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_WRITER); 13607c478bd9Sstevel@tonic-gate for (dv = ddv->dv_dot; dv; dv = next) { 13617c478bd9Sstevel@tonic-gate int error = 0; 13627c478bd9Sstevel@tonic-gate next = dv->dv_next; 13637c478bd9Sstevel@tonic-gate nm = dv->dv_name; 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate rw_enter(&dv->dv_contents, RW_READER); 13667c478bd9Sstevel@tonic-gate vp = DVTOV(dv); 13677c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 13687c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 13697c478bd9Sstevel@tonic-gate if (dv_reset_perm_dir(dv, flags) != 0) { 13707c478bd9Sstevel@tonic-gate error = EBUSY; 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate } else { 13737c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VCHR || vp->v_type == VBLK); 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * Check for permissions from minor_perm 13777c478bd9Sstevel@tonic-gate * If there are none, we're done 13787c478bd9Sstevel@tonic-gate */ 13797c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 13807c478bd9Sstevel@tonic-gate if (dev_minorperm(dv->dv_devi, nm, &mp) != 0) 13817c478bd9Sstevel@tonic-gate continue; 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate rw_enter(&dv->dv_contents, RW_READER); 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * Allow a node's permissions to be altered 13877c478bd9Sstevel@tonic-gate * permanently from the defaults by chmod, 13887c478bd9Sstevel@tonic-gate * using the shadow node as backing store. 13897c478bd9Sstevel@tonic-gate * Otherwise, update node to minor_perm permissions. 13907c478bd9Sstevel@tonic-gate */ 13917c478bd9Sstevel@tonic-gate if (dv->dv_attrvp == NULLVP) { 13927c478bd9Sstevel@tonic-gate /* 13937c478bd9Sstevel@tonic-gate * No attribute vp, try to find one. 13947c478bd9Sstevel@tonic-gate */ 13957c478bd9Sstevel@tonic-gate dv_shadow_node(DVTOV(ddv), nm, vp, 13967c478bd9Sstevel@tonic-gate NULL, NULLVP, kcred, 0); 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate if (dv->dv_attrvp != NULLVP || dv->dv_attr == NULL) { 13997c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 14007c478bd9Sstevel@tonic-gate continue; 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate attrp = dv->dv_attr; 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate if (VATTRP_MP_CMP(attrp, mp) == 0) { 14067c478bd9Sstevel@tonic-gate dcmn_err5(("%s: no perm change: " 14077c478bd9Sstevel@tonic-gate "%d %d 0%o\n", nm, attrp->va_uid, 14087c478bd9Sstevel@tonic-gate attrp->va_gid, attrp->va_mode)); 14097c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 14107c478bd9Sstevel@tonic-gate continue; 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate old_uid = attrp->va_uid; 14147c478bd9Sstevel@tonic-gate old_gid = attrp->va_gid; 14157c478bd9Sstevel@tonic-gate old_mode = attrp->va_mode; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate VATTRP_MP_MERGE(attrp, mp); 14187c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock); 14197c478bd9Sstevel@tonic-gate if (vp->v_count > 0) { 14207c478bd9Sstevel@tonic-gate error = EBUSY; 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate dcmn_err5(("%s: perm %d/%d/0%o -> %d/%d/0%o (%d)\n", 14257c478bd9Sstevel@tonic-gate nm, old_uid, old_gid, old_mode, attrp->va_uid, 14267c478bd9Sstevel@tonic-gate attrp->va_gid, attrp->va_mode, error)); 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate rw_exit(&dv->dv_contents); 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate if (error != 0) { 14327c478bd9Sstevel@tonic-gate retval = error; 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate ddv->dv_flags |= DV_BUILD; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate return (retval); 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate int 14447c478bd9Sstevel@tonic-gate devfs_reset_perm(uint_t flags) 14457c478bd9Sstevel@tonic-gate { 14467c478bd9Sstevel@tonic-gate struct dv_node *dvp; 14477c478bd9Sstevel@tonic-gate int rval; 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate if ((dvp = devfs_dip_to_dvnode(ddi_root_node())) == NULL) 14507c478bd9Sstevel@tonic-gate return (0); 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate VN_HOLD(DVTOV(dvp)); 14537c478bd9Sstevel@tonic-gate rval = dv_reset_perm_dir(dvp, flags); 14547c478bd9Sstevel@tonic-gate VN_RELE(DVTOV(dvp)); 14557c478bd9Sstevel@tonic-gate return (rval); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate /* 14597c478bd9Sstevel@tonic-gate * Clean up dangling devfs shadow nodes for removed 14607c478bd9Sstevel@tonic-gate * drivers so that, in the event the driver is re-added 14617c478bd9Sstevel@tonic-gate * to the system, newly created nodes won't incorrectly 14627c478bd9Sstevel@tonic-gate * pick up these stale shadow node permissions. 14637c478bd9Sstevel@tonic-gate * 14647c478bd9Sstevel@tonic-gate * This is accomplished by walking down the pathname 14657c478bd9Sstevel@tonic-gate * to the directory, starting at the root's attribute 14667c478bd9Sstevel@tonic-gate * node, then removing all minors matching the specified 14677c478bd9Sstevel@tonic-gate * node name. Care must be taken to remove all entries 14687c478bd9Sstevel@tonic-gate * in a directory before the directory itself, so that 14697c478bd9Sstevel@tonic-gate * the clean-up associated with rem_drv'ing a nexus driver 14707c478bd9Sstevel@tonic-gate * does not inadvertently result in an inconsistent 14717c478bd9Sstevel@tonic-gate * filesystem underlying devfs. 14727c478bd9Sstevel@tonic-gate */ 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate static int 14757c478bd9Sstevel@tonic-gate devfs_remdrv_rmdir(vnode_t *dirvp, const char *dir, vnode_t *rootvp) 14767c478bd9Sstevel@tonic-gate { 14777c478bd9Sstevel@tonic-gate int error; 14787c478bd9Sstevel@tonic-gate vnode_t *vp; 14797c478bd9Sstevel@tonic-gate int eof; 14807c478bd9Sstevel@tonic-gate struct iovec iov; 14817c478bd9Sstevel@tonic-gate struct uio uio; 14827c478bd9Sstevel@tonic-gate struct dirent64 *dp; 14837c478bd9Sstevel@tonic-gate dirent64_t *dbuf; 14847c478bd9Sstevel@tonic-gate size_t dlen; 14857c478bd9Sstevel@tonic-gate size_t dbuflen; 14867c478bd9Sstevel@tonic-gate int ndirents = 64; 14877c478bd9Sstevel@tonic-gate char *nm; 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate VN_HOLD(dirvp); 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate dlen = ndirents * (sizeof (*dbuf)); 14927c478bd9Sstevel@tonic-gate dbuf = kmem_alloc(dlen, KM_SLEEP); 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 14957c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 14967c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 14977c478bd9Sstevel@tonic-gate uio.uio_fmode = 0; 14987c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 14997c478bd9Sstevel@tonic-gate uio.uio_loffset = 0; 15007c478bd9Sstevel@tonic-gate uio.uio_llimit = MAXOFFSET_T; 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate eof = 0; 15037c478bd9Sstevel@tonic-gate error = 0; 15047c478bd9Sstevel@tonic-gate while (!error && !eof) { 15057c478bd9Sstevel@tonic-gate uio.uio_resid = dlen; 15067c478bd9Sstevel@tonic-gate iov.iov_base = (char *)dbuf; 15077c478bd9Sstevel@tonic-gate iov.iov_len = dlen; 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 15107c478bd9Sstevel@tonic-gate error = VOP_READDIR(dirvp, &uio, kcred, &eof); 15117c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate dbuflen = dlen - uio.uio_resid; 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate if (error || dbuflen == 0) 15167c478bd9Sstevel@tonic-gate break; 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate for (dp = dbuf; ((intptr_t)dp < (intptr_t)dbuf + dbuflen); 15197c478bd9Sstevel@tonic-gate dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) { 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate nm = dp->d_name; 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0) 15247c478bd9Sstevel@tonic-gate continue; 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate error = VOP_LOOKUP(dirvp, 15277c478bd9Sstevel@tonic-gate nm, &vp, NULL, 0, NULL, kcred); 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate dsysdebug(error, 15307c478bd9Sstevel@tonic-gate ("rem_drv %s/%s lookup (%d)\n", 15317c478bd9Sstevel@tonic-gate dir, nm, error)); 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate if (error) 15347c478bd9Sstevel@tonic-gate continue; 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VDIR || 15377c478bd9Sstevel@tonic-gate vp->v_type == VCHR || vp->v_type == VBLK); 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 15407c478bd9Sstevel@tonic-gate error = devfs_remdrv_rmdir(vp, nm, rootvp); 15417c478bd9Sstevel@tonic-gate if (error == 0) { 15427c478bd9Sstevel@tonic-gate error = VOP_RMDIR(dirvp, 15437c478bd9Sstevel@tonic-gate (char *)nm, rootvp, kcred); 15447c478bd9Sstevel@tonic-gate dsysdebug(error, 15457c478bd9Sstevel@tonic-gate ("rem_drv %s/%s rmdir (%d)\n", 15467c478bd9Sstevel@tonic-gate dir, nm, error)); 15477c478bd9Sstevel@tonic-gate } 15487c478bd9Sstevel@tonic-gate } else { 15497c478bd9Sstevel@tonic-gate error = VOP_REMOVE(dirvp, (char *)nm, kcred); 15507c478bd9Sstevel@tonic-gate dsysdebug(error, 15517c478bd9Sstevel@tonic-gate ("rem_drv %s/%s remove (%d)\n", 15527c478bd9Sstevel@tonic-gate dir, nm, error)); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate VN_RELE(vp); 15567c478bd9Sstevel@tonic-gate if (error) { 15577c478bd9Sstevel@tonic-gate goto exit; 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate exit: 15637c478bd9Sstevel@tonic-gate VN_RELE(dirvp); 15647c478bd9Sstevel@tonic-gate kmem_free(dbuf, dlen); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate return (error); 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate int 15707c478bd9Sstevel@tonic-gate devfs_remdrv_cleanup(const char *dir, const char *nodename) 15717c478bd9Sstevel@tonic-gate { 15727c478bd9Sstevel@tonic-gate int error; 15737c478bd9Sstevel@tonic-gate vnode_t *vp; 15747c478bd9Sstevel@tonic-gate vnode_t *dirvp; 15757c478bd9Sstevel@tonic-gate int eof; 15767c478bd9Sstevel@tonic-gate struct iovec iov; 15777c478bd9Sstevel@tonic-gate struct uio uio; 15787c478bd9Sstevel@tonic-gate struct dirent64 *dp; 15797c478bd9Sstevel@tonic-gate dirent64_t *dbuf; 15807c478bd9Sstevel@tonic-gate size_t dlen; 15817c478bd9Sstevel@tonic-gate size_t dbuflen; 15827c478bd9Sstevel@tonic-gate int ndirents = 64; 15837c478bd9Sstevel@tonic-gate int nodenamelen = strlen(nodename); 15847c478bd9Sstevel@tonic-gate char *nm; 15857c478bd9Sstevel@tonic-gate struct pathname pn; 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate dcmn_err5(("devfs_remdrv_cleanup: %s %s\n", dir, nodename)); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate if (error = pn_get((char *)dir, UIO_SYSSPACE, &pn)) 15907c478bd9Sstevel@tonic-gate return (0); 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate rootvp = dvroot->dv_attrvp; 15937c478bd9Sstevel@tonic-gate ASSERT(rootvp != NULL); 15947c478bd9Sstevel@tonic-gate VN_HOLD(rootvp); 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate pn_skipslash(&pn); 15977c478bd9Sstevel@tonic-gate dirvp = rootvp; 15987c478bd9Sstevel@tonic-gate VN_HOLD(dirvp); 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate nm = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate while (pn_pathleft(&pn)) { 16037c478bd9Sstevel@tonic-gate ASSERT(dirvp->v_type == VDIR); 16047c478bd9Sstevel@tonic-gate (void) pn_getcomponent(&pn, nm); 16057c478bd9Sstevel@tonic-gate ASSERT((strcmp(nm, ".") != 0) && (strcmp(nm, "..") != 0)); 16067c478bd9Sstevel@tonic-gate error = VOP_LOOKUP(dirvp, nm, &vp, NULL, 0, rootvp, kcred); 16077c478bd9Sstevel@tonic-gate if (error) { 16087c478bd9Sstevel@tonic-gate dcmn_err5(("remdrv_cleanup %s lookup error %d\n", 16097c478bd9Sstevel@tonic-gate nm, error)); 16107c478bd9Sstevel@tonic-gate VN_RELE(dirvp); 16117c478bd9Sstevel@tonic-gate if (dirvp != rootvp) 16127c478bd9Sstevel@tonic-gate VN_RELE(rootvp); 16137c478bd9Sstevel@tonic-gate pn_free(&pn); 16147c478bd9Sstevel@tonic-gate kmem_free(nm, MAXNAMELEN); 16157c478bd9Sstevel@tonic-gate return (0); 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate VN_RELE(dirvp); 16187c478bd9Sstevel@tonic-gate dirvp = vp; 16197c478bd9Sstevel@tonic-gate pn_skipslash(&pn); 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate ASSERT(dirvp->v_type == VDIR); 16237c478bd9Sstevel@tonic-gate if (dirvp != rootvp) 16247c478bd9Sstevel@tonic-gate VN_RELE(rootvp); 16257c478bd9Sstevel@tonic-gate pn_free(&pn); 16267c478bd9Sstevel@tonic-gate kmem_free(nm, MAXNAMELEN); 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate dlen = ndirents * (sizeof (*dbuf)); 16297c478bd9Sstevel@tonic-gate dbuf = kmem_alloc(dlen, KM_SLEEP); 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 16327c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 16337c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 16347c478bd9Sstevel@tonic-gate uio.uio_fmode = 0; 16357c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 16367c478bd9Sstevel@tonic-gate uio.uio_loffset = 0; 16377c478bd9Sstevel@tonic-gate uio.uio_llimit = MAXOFFSET_T; 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate eof = 0; 16407c478bd9Sstevel@tonic-gate error = 0; 16417c478bd9Sstevel@tonic-gate while (!error && !eof) { 16427c478bd9Sstevel@tonic-gate uio.uio_resid = dlen; 16437c478bd9Sstevel@tonic-gate iov.iov_base = (char *)dbuf; 16447c478bd9Sstevel@tonic-gate iov.iov_len = dlen; 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 16477c478bd9Sstevel@tonic-gate error = VOP_READDIR(dirvp, &uio, kcred, &eof); 16487c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate dbuflen = dlen - uio.uio_resid; 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate if (error || dbuflen == 0) 16537c478bd9Sstevel@tonic-gate break; 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate for (dp = dbuf; ((intptr_t)dp < (intptr_t)dbuf + dbuflen); 16567c478bd9Sstevel@tonic-gate dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) { 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate nm = dp->d_name; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0) 16617c478bd9Sstevel@tonic-gate continue; 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate if (strncmp(nm, nodename, nodenamelen) != 0) 16647c478bd9Sstevel@tonic-gate continue; 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate error = VOP_LOOKUP(dirvp, nm, &vp, 16677c478bd9Sstevel@tonic-gate NULL, 0, NULL, kcred); 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate dsysdebug(error, 16707c478bd9Sstevel@tonic-gate ("rem_drv %s/%s lookup (%d)\n", 16717c478bd9Sstevel@tonic-gate dir, nm, error)); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate if (error) 16747c478bd9Sstevel@tonic-gate continue; 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VDIR || 16777c478bd9Sstevel@tonic-gate vp->v_type == VCHR || vp->v_type == VBLK); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 16807c478bd9Sstevel@tonic-gate error = devfs_remdrv_rmdir(vp, nm, rootvp); 16817c478bd9Sstevel@tonic-gate if (error == 0) { 16827c478bd9Sstevel@tonic-gate error = VOP_RMDIR(dirvp, 16837c478bd9Sstevel@tonic-gate (char *)nm, rootvp, kcred); 16847c478bd9Sstevel@tonic-gate dsysdebug(error, 16857c478bd9Sstevel@tonic-gate ("rem_drv %s/%s rmdir (%d)\n", 16867c478bd9Sstevel@tonic-gate dir, nm, error)); 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate } else { 16897c478bd9Sstevel@tonic-gate error = VOP_REMOVE(dirvp, (char *)nm, kcred); 16907c478bd9Sstevel@tonic-gate dsysdebug(error, 16917c478bd9Sstevel@tonic-gate ("rem_drv %s/%s remove (%d)\n", 16927c478bd9Sstevel@tonic-gate dir, nm, error)); 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate VN_RELE(vp); 16967c478bd9Sstevel@tonic-gate if (error) 16977c478bd9Sstevel@tonic-gate goto exit; 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate exit: 17027c478bd9Sstevel@tonic-gate VN_RELE(dirvp); 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate kmem_free(dbuf, dlen); 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate return (0); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate struct dv_list { 17107c478bd9Sstevel@tonic-gate struct dv_node *dv; 17117c478bd9Sstevel@tonic-gate struct dv_list *next; 17127c478bd9Sstevel@tonic-gate }; 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate void 17157c478bd9Sstevel@tonic-gate dv_walk( 17167c478bd9Sstevel@tonic-gate struct dv_node *ddv, 17177c478bd9Sstevel@tonic-gate char *devnm, 17187c478bd9Sstevel@tonic-gate void (*callback)(struct dv_node *, void *), 17197c478bd9Sstevel@tonic-gate void *arg) 17207c478bd9Sstevel@tonic-gate { 17217c478bd9Sstevel@tonic-gate struct vnode *dvp; 17227c478bd9Sstevel@tonic-gate struct dv_node *dv; 17237c478bd9Sstevel@tonic-gate struct dv_list *head, *tail, *next; 1724*45a9d961Scth int len; 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate dcmn_err3(("dv_walk: ddv = %s, devnm = %s\n", 17277c478bd9Sstevel@tonic-gate ddv->dv_name, devnm ? devnm : "<null>")); 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate dvp = DVTOV(ddv); 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate ASSERT(dvp->v_type == VDIR); 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate head = tail = next = NULL; 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate rw_enter(&ddv->dv_contents, RW_READER); 1736*45a9d961Scth mutex_enter(&dvp->v_lock); 17377c478bd9Sstevel@tonic-gate for (dv = ddv->dv_dot; dv; dv = dv->dv_next) { 17387c478bd9Sstevel@tonic-gate /* 17397c478bd9Sstevel@tonic-gate * If devnm is not NULL and is not the empty string, 17407c478bd9Sstevel@tonic-gate * select only dv_nodes with matching non-minor name 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate if (devnm && (len = strlen(devnm)) && 17437c478bd9Sstevel@tonic-gate (strncmp(devnm, dv->dv_name, len) || 17447c478bd9Sstevel@tonic-gate (dv->dv_name[len] != ':' && dv->dv_name[len] != '\0'))) 17457c478bd9Sstevel@tonic-gate continue; 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate callback(dv, arg); 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate if (DVTOV(dv)->v_type != VDIR) 17507c478bd9Sstevel@tonic-gate continue; 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate next = kmem_zalloc(sizeof (*next), KM_SLEEP); 17537c478bd9Sstevel@tonic-gate next->dv = dv; 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate if (tail) 17567c478bd9Sstevel@tonic-gate tail->next = next; 17577c478bd9Sstevel@tonic-gate else 17587c478bd9Sstevel@tonic-gate head = next; 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate tail = next; 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate while (head) { 17647c478bd9Sstevel@tonic-gate dv_walk(head->dv, NULL, callback, arg); 17657c478bd9Sstevel@tonic-gate next = head->next; 17667c478bd9Sstevel@tonic-gate kmem_free(head, sizeof (*head)); 17677c478bd9Sstevel@tonic-gate head = next; 17687c478bd9Sstevel@tonic-gate } 17697c478bd9Sstevel@tonic-gate rw_exit(&ddv->dv_contents); 17707c478bd9Sstevel@tonic-gate mutex_exit(&dvp->v_lock); 17717c478bd9Sstevel@tonic-gate } 1772