17688SAaron.Zang@Sun.COM /* 27688SAaron.Zang@Sun.COM * CDDL HEADER START 37688SAaron.Zang@Sun.COM * 47688SAaron.Zang@Sun.COM * The contents of this file are subject to the terms of the 57688SAaron.Zang@Sun.COM * Common Development and Distribution License (the "License"). 67688SAaron.Zang@Sun.COM * You may not use this file except in compliance with the License. 77688SAaron.Zang@Sun.COM * 87688SAaron.Zang@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97688SAaron.Zang@Sun.COM * or http://www.opensolaris.org/os/licensing. 107688SAaron.Zang@Sun.COM * See the License for the specific language governing permissions 117688SAaron.Zang@Sun.COM * and limitations under the License. 127688SAaron.Zang@Sun.COM * 137688SAaron.Zang@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147688SAaron.Zang@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157688SAaron.Zang@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167688SAaron.Zang@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177688SAaron.Zang@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187688SAaron.Zang@Sun.COM * 197688SAaron.Zang@Sun.COM * CDDL HEADER END 207688SAaron.Zang@Sun.COM */ 217688SAaron.Zang@Sun.COM /* 22*11279SJerry.Gilliam@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237688SAaron.Zang@Sun.COM * Use is subject to license terms. 247688SAaron.Zang@Sun.COM */ 257688SAaron.Zang@Sun.COM 267688SAaron.Zang@Sun.COM /* 277688SAaron.Zang@Sun.COM * vnode ops for the /dev/vt directory 287688SAaron.Zang@Sun.COM */ 297688SAaron.Zang@Sun.COM 307688SAaron.Zang@Sun.COM #include <sys/types.h> 317688SAaron.Zang@Sun.COM #include <sys/param.h> 327688SAaron.Zang@Sun.COM #include <sys/sysmacros.h> 337688SAaron.Zang@Sun.COM #include <sys/sunndi.h> 347688SAaron.Zang@Sun.COM #include <fs/fs_subr.h> 357688SAaron.Zang@Sun.COM #include <sys/fs/dv_node.h> 367688SAaron.Zang@Sun.COM #include <sys/fs/sdev_impl.h> 377688SAaron.Zang@Sun.COM #include <sys/policy.h> 387688SAaron.Zang@Sun.COM #include <sys/stat.h> 397688SAaron.Zang@Sun.COM #include <sys/vfs_opreg.h> 407688SAaron.Zang@Sun.COM #include <sys/tty.h> 417688SAaron.Zang@Sun.COM #include <sys/vt_impl.h> 427688SAaron.Zang@Sun.COM #include <sys/note.h> 437688SAaron.Zang@Sun.COM 447688SAaron.Zang@Sun.COM /* warlock in this file only cares about variables shared by vt and devfs */ 457688SAaron.Zang@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode)) 467688SAaron.Zang@Sun.COM 477688SAaron.Zang@Sun.COM #define DEVVT_UID_DEFAULT SDEV_UID_DEFAULT 487688SAaron.Zang@Sun.COM #define DEVVT_GID_DEFAULT (0) 497688SAaron.Zang@Sun.COM #define DEVVT_DEVMODE_DEFAULT (0600) 507688SAaron.Zang@Sun.COM #define DEVVT_ACTIVE_NAME "active" 517688SAaron.Zang@Sun.COM 527688SAaron.Zang@Sun.COM #define isdigit(ch) ((ch) >= '0' && (ch) <= '9') 537688SAaron.Zang@Sun.COM 547688SAaron.Zang@Sun.COM /* attributes for VT nodes */ 557688SAaron.Zang@Sun.COM static vattr_t devvt_vattr = { 567688SAaron.Zang@Sun.COM AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 577688SAaron.Zang@Sun.COM VCHR, /* va_type */ 587688SAaron.Zang@Sun.COM S_IFCHR | DEVVT_DEVMODE_DEFAULT, /* va_mode */ 597688SAaron.Zang@Sun.COM DEVVT_UID_DEFAULT, /* va_uid */ 607688SAaron.Zang@Sun.COM DEVVT_GID_DEFAULT, /* va_gid */ 617688SAaron.Zang@Sun.COM 0 /* 0 hereafter */ 627688SAaron.Zang@Sun.COM }; 637688SAaron.Zang@Sun.COM 647688SAaron.Zang@Sun.COM struct vnodeops *devvt_vnodeops; 657688SAaron.Zang@Sun.COM 667688SAaron.Zang@Sun.COM struct vnodeops * 677688SAaron.Zang@Sun.COM devvt_getvnodeops(void) 687688SAaron.Zang@Sun.COM { 697688SAaron.Zang@Sun.COM return (devvt_vnodeops); 707688SAaron.Zang@Sun.COM } 717688SAaron.Zang@Sun.COM 727688SAaron.Zang@Sun.COM static int 737688SAaron.Zang@Sun.COM devvt_str2minor(const char *nm, minor_t *mp) 747688SAaron.Zang@Sun.COM { 757688SAaron.Zang@Sun.COM long uminor = 0; 767688SAaron.Zang@Sun.COM char *endptr = NULL; 777688SAaron.Zang@Sun.COM 787688SAaron.Zang@Sun.COM if (nm == NULL || !isdigit(*nm)) 797688SAaron.Zang@Sun.COM return (EINVAL); 807688SAaron.Zang@Sun.COM 817688SAaron.Zang@Sun.COM *mp = 0; 827688SAaron.Zang@Sun.COM if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 || 837688SAaron.Zang@Sun.COM *endptr != '\0' || uminor < 0) { 847688SAaron.Zang@Sun.COM return (EINVAL); 857688SAaron.Zang@Sun.COM } 867688SAaron.Zang@Sun.COM 877688SAaron.Zang@Sun.COM *mp = (minor_t)uminor; 887688SAaron.Zang@Sun.COM return (0); 897688SAaron.Zang@Sun.COM } 907688SAaron.Zang@Sun.COM 917688SAaron.Zang@Sun.COM /*ARGSUSED*/ 927688SAaron.Zang@Sun.COM int 937688SAaron.Zang@Sun.COM devvt_validate(struct sdev_node *dv) 947688SAaron.Zang@Sun.COM { 957688SAaron.Zang@Sun.COM minor_t min; 967688SAaron.Zang@Sun.COM char *nm = dv->sdev_name; 977688SAaron.Zang@Sun.COM 987688SAaron.Zang@Sun.COM ASSERT(!(dv->sdev_flags & SDEV_STALE)); 997688SAaron.Zang@Sun.COM ASSERT(dv->sdev_state == SDEV_READY); 1007688SAaron.Zang@Sun.COM 1017688SAaron.Zang@Sun.COM /* validate only READY nodes */ 1027688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) { 1037688SAaron.Zang@Sun.COM sdcmn_err(("dev fs: skipping: node not ready %s(%p)", 1047688SAaron.Zang@Sun.COM nm, (void *)dv)); 1057688SAaron.Zang@Sun.COM return (SDEV_VTOR_SKIP); 1067688SAaron.Zang@Sun.COM } 1077688SAaron.Zang@Sun.COM 1087688SAaron.Zang@Sun.COM if (vt_wc_attached() == (major_t)-1) 1097688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 1107688SAaron.Zang@Sun.COM 1117688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) { 1127688SAaron.Zang@Sun.COM char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1137688SAaron.Zang@Sun.COM 1147688SAaron.Zang@Sun.COM (void) vt_getactive(link, MAXPATHLEN); 1157688SAaron.Zang@Sun.COM if (strcmp(link, dv->sdev_symlink) != 0) { 1167688SAaron.Zang@Sun.COM kmem_free(dv->sdev_symlink, 1177688SAaron.Zang@Sun.COM strlen(dv->sdev_symlink) + 1); 1187688SAaron.Zang@Sun.COM dv->sdev_symlink = i_ddi_strdup(link, KM_SLEEP); 1197688SAaron.Zang@Sun.COM dv->sdev_attr->va_size = strlen(link); 1207688SAaron.Zang@Sun.COM } 1217688SAaron.Zang@Sun.COM kmem_free(link, MAXPATHLEN); 1227688SAaron.Zang@Sun.COM return (SDEV_VTOR_VALID); 1237688SAaron.Zang@Sun.COM } else if (devvt_str2minor(nm, &min) != 0) { 1247688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 1257688SAaron.Zang@Sun.COM } 1267688SAaron.Zang@Sun.COM 1277688SAaron.Zang@Sun.COM if (vt_minor_valid(min) == B_FALSE) 1287688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 1297688SAaron.Zang@Sun.COM 1307688SAaron.Zang@Sun.COM return (SDEV_VTOR_VALID); 1317688SAaron.Zang@Sun.COM } 1327688SAaron.Zang@Sun.COM 1337688SAaron.Zang@Sun.COM /* 1347688SAaron.Zang@Sun.COM * This callback is invoked from devname_lookup_func() to create 1357688SAaron.Zang@Sun.COM * a entry when the node is not found in the cache. 1367688SAaron.Zang@Sun.COM */ 1377688SAaron.Zang@Sun.COM /*ARGSUSED*/ 1387688SAaron.Zang@Sun.COM static int 1397688SAaron.Zang@Sun.COM devvt_create_rvp(struct sdev_node *ddv, char *nm, 1407688SAaron.Zang@Sun.COM void **arg, cred_t *cred, void *whatever, char *whichever) 1417688SAaron.Zang@Sun.COM { 1427688SAaron.Zang@Sun.COM minor_t min; 1437688SAaron.Zang@Sun.COM major_t maj; 1447688SAaron.Zang@Sun.COM struct vattr *vap = (struct vattr *)arg; 1457688SAaron.Zang@Sun.COM 1467688SAaron.Zang@Sun.COM if ((maj = vt_wc_attached()) == (major_t)-1) 1477688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 1487688SAaron.Zang@Sun.COM 1497688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) { 1507688SAaron.Zang@Sun.COM (void) vt_getactive((char *)*arg, MAXPATHLEN); 1517688SAaron.Zang@Sun.COM return (0); 1527688SAaron.Zang@Sun.COM } 1537688SAaron.Zang@Sun.COM 1547688SAaron.Zang@Sun.COM if (devvt_str2minor(nm, &min) != 0) 1557688SAaron.Zang@Sun.COM return (-1); 1567688SAaron.Zang@Sun.COM 1577688SAaron.Zang@Sun.COM if (vt_minor_valid(min) == B_FALSE) 1587688SAaron.Zang@Sun.COM return (-1); 1597688SAaron.Zang@Sun.COM 1607688SAaron.Zang@Sun.COM *vap = devvt_vattr; 1617688SAaron.Zang@Sun.COM vap->va_rdev = makedevice(maj, min); 1627688SAaron.Zang@Sun.COM 1637688SAaron.Zang@Sun.COM return (0); 1647688SAaron.Zang@Sun.COM } 1657688SAaron.Zang@Sun.COM 1667688SAaron.Zang@Sun.COM /*ARGSUSED3*/ 1677688SAaron.Zang@Sun.COM static int 1687688SAaron.Zang@Sun.COM devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp, 1697688SAaron.Zang@Sun.COM struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred, 1707688SAaron.Zang@Sun.COM caller_context_t *ct, int *direntflags, pathname_t *realpnp) 1717688SAaron.Zang@Sun.COM { 1727688SAaron.Zang@Sun.COM struct sdev_node *sdvp = VTOSDEV(dvp); 1737688SAaron.Zang@Sun.COM struct sdev_node *dv; 1747688SAaron.Zang@Sun.COM struct vnode *rvp = NULL; 1757688SAaron.Zang@Sun.COM int type, error; 1767688SAaron.Zang@Sun.COM 1777688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) { 1787688SAaron.Zang@Sun.COM type = SDEV_VLINK; 1797688SAaron.Zang@Sun.COM } else { 1807688SAaron.Zang@Sun.COM type = SDEV_VATTR; 1817688SAaron.Zang@Sun.COM } 1827688SAaron.Zang@Sun.COM 1837688SAaron.Zang@Sun.COM /* Give warlock a more clear call graph */ 1847688SAaron.Zang@Sun.COM #ifndef __lock_lint 1857688SAaron.Zang@Sun.COM error = devname_lookup_func(sdvp, nm, vpp, cred, 1867688SAaron.Zang@Sun.COM devvt_create_rvp, type); 1877688SAaron.Zang@Sun.COM #else 1887688SAaron.Zang@Sun.COM devvt_create_rvp(0, 0, 0, 0, 0, 0); 1897688SAaron.Zang@Sun.COM #endif 1907688SAaron.Zang@Sun.COM 1917688SAaron.Zang@Sun.COM if (error == 0) { 1927688SAaron.Zang@Sun.COM switch ((*vpp)->v_type) { 1937688SAaron.Zang@Sun.COM case VCHR: 1947688SAaron.Zang@Sun.COM dv = VTOSDEV(VTOS(*vpp)->s_realvp); 1957688SAaron.Zang@Sun.COM ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS); 1967688SAaron.Zang@Sun.COM break; 1977688SAaron.Zang@Sun.COM case VDIR: 1987688SAaron.Zang@Sun.COM case VLNK: 1997688SAaron.Zang@Sun.COM dv = VTOSDEV(*vpp); 2007688SAaron.Zang@Sun.COM break; 2017688SAaron.Zang@Sun.COM default: 2027688SAaron.Zang@Sun.COM cmn_err(CE_PANIC, "devvt_lookup: Unsupported node " 2037688SAaron.Zang@Sun.COM "type: %p: %d", (void *)(*vpp), (*vpp)->v_type); 2047688SAaron.Zang@Sun.COM break; 2057688SAaron.Zang@Sun.COM } 2067688SAaron.Zang@Sun.COM ASSERT(SDEV_HELD(dv)); 2077688SAaron.Zang@Sun.COM } 2087688SAaron.Zang@Sun.COM 2097688SAaron.Zang@Sun.COM return (error); 2107688SAaron.Zang@Sun.COM } 2117688SAaron.Zang@Sun.COM 2127688SAaron.Zang@Sun.COM static void 2137688SAaron.Zang@Sun.COM devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type) 2147688SAaron.Zang@Sun.COM { 2157688SAaron.Zang@Sun.COM int error; 2167688SAaron.Zang@Sun.COM struct sdev_node *sdv = NULL; 217*11279SJerry.Gilliam@Sun.COM struct vattr vattr; 218*11279SJerry.Gilliam@Sun.COM struct vattr *vap = &vattr; 2197688SAaron.Zang@Sun.COM major_t maj; 2207688SAaron.Zang@Sun.COM minor_t min; 2217688SAaron.Zang@Sun.COM 2227688SAaron.Zang@Sun.COM if ((maj = vt_wc_attached()) == (major_t)-1) 2237688SAaron.Zang@Sun.COM return; 2247688SAaron.Zang@Sun.COM 2257688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 && 2267688SAaron.Zang@Sun.COM devvt_str2minor(nm, &min) != 0) 2277688SAaron.Zang@Sun.COM return; 2287688SAaron.Zang@Sun.COM 2297688SAaron.Zang@Sun.COM error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT); 2307688SAaron.Zang@Sun.COM if (error || !sdv) { 2317688SAaron.Zang@Sun.COM return; 2327688SAaron.Zang@Sun.COM } 2337688SAaron.Zang@Sun.COM 2347688SAaron.Zang@Sun.COM mutex_enter(&sdv->sdev_lookup_lock); 2357688SAaron.Zang@Sun.COM SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP); 2367688SAaron.Zang@Sun.COM mutex_exit(&sdv->sdev_lookup_lock); 2377688SAaron.Zang@Sun.COM 2387688SAaron.Zang@Sun.COM if (type & SDEV_VATTR) { 239*11279SJerry.Gilliam@Sun.COM *vap = devvt_vattr; 2407688SAaron.Zang@Sun.COM vap->va_rdev = makedevice(maj, min); 2417688SAaron.Zang@Sun.COM error = sdev_mknode(ddv, nm, &sdv, vap, NULL, 2427688SAaron.Zang@Sun.COM NULL, cred, SDEV_READY); 2437688SAaron.Zang@Sun.COM } else if (type & SDEV_VLINK) { 2447688SAaron.Zang@Sun.COM char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 2457688SAaron.Zang@Sun.COM 2467688SAaron.Zang@Sun.COM (void) vt_getactive(link, MAXPATHLEN); 247*11279SJerry.Gilliam@Sun.COM *vap = sdev_vattr_lnk; 2487688SAaron.Zang@Sun.COM vap->va_size = strlen(link); 2497688SAaron.Zang@Sun.COM error = sdev_mknode(ddv, nm, &sdv, vap, NULL, 2507688SAaron.Zang@Sun.COM (void *)link, cred, SDEV_READY); 2517688SAaron.Zang@Sun.COM 2527688SAaron.Zang@Sun.COM kmem_free(link, MAXPATHLEN); 2537688SAaron.Zang@Sun.COM } 2547688SAaron.Zang@Sun.COM 2557688SAaron.Zang@Sun.COM mutex_enter(&sdv->sdev_lookup_lock); 2567688SAaron.Zang@Sun.COM SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP); 2577688SAaron.Zang@Sun.COM mutex_exit(&sdv->sdev_lookup_lock); 2587688SAaron.Zang@Sun.COM 2597688SAaron.Zang@Sun.COM } 2607688SAaron.Zang@Sun.COM 2617688SAaron.Zang@Sun.COM static void 2627688SAaron.Zang@Sun.COM devvt_prunedir(struct sdev_node *ddv) 2637688SAaron.Zang@Sun.COM { 2647688SAaron.Zang@Sun.COM struct vnode *vp; 2657688SAaron.Zang@Sun.COM struct sdev_node *dv, *next = NULL; 2667688SAaron.Zang@Sun.COM int (*vtor)(struct sdev_node *) = NULL; 2677688SAaron.Zang@Sun.COM 2687688SAaron.Zang@Sun.COM ASSERT(ddv->sdev_flags & SDEV_VTOR); 2697688SAaron.Zang@Sun.COM 2707688SAaron.Zang@Sun.COM vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv); 2717688SAaron.Zang@Sun.COM ASSERT(vtor); 2727688SAaron.Zang@Sun.COM 2737688SAaron.Zang@Sun.COM for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) { 2747688SAaron.Zang@Sun.COM next = SDEV_NEXT_ENTRY(ddv, dv); 2757688SAaron.Zang@Sun.COM 2767688SAaron.Zang@Sun.COM /* skip stale nodes */ 2777688SAaron.Zang@Sun.COM if (dv->sdev_flags & SDEV_STALE) 2787688SAaron.Zang@Sun.COM continue; 2797688SAaron.Zang@Sun.COM 2807688SAaron.Zang@Sun.COM /* validate and prune only ready nodes */ 2817688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) 2827688SAaron.Zang@Sun.COM continue; 2837688SAaron.Zang@Sun.COM 2847688SAaron.Zang@Sun.COM switch (vtor(dv)) { 2857688SAaron.Zang@Sun.COM case SDEV_VTOR_VALID: 2867688SAaron.Zang@Sun.COM case SDEV_VTOR_SKIP: 2877688SAaron.Zang@Sun.COM continue; 2887688SAaron.Zang@Sun.COM case SDEV_VTOR_INVALID: 2898023SPhil.Kirk@Sun.COM case SDEV_VTOR_STALE: 2907688SAaron.Zang@Sun.COM sdcmn_err7(("destroy invalid " 2917688SAaron.Zang@Sun.COM "node: %s(%p)\n", dv->sdev_name, (void *)dv)); 2927688SAaron.Zang@Sun.COM break; 2937688SAaron.Zang@Sun.COM } 2947688SAaron.Zang@Sun.COM vp = SDEVTOV(dv); 2957688SAaron.Zang@Sun.COM if (vp->v_count > 0) 2967688SAaron.Zang@Sun.COM continue; 2977688SAaron.Zang@Sun.COM SDEV_HOLD(dv); 2987688SAaron.Zang@Sun.COM /* remove the cache node */ 2997688SAaron.Zang@Sun.COM (void) sdev_cache_update(ddv, &dv, dv->sdev_name, 3007688SAaron.Zang@Sun.COM SDEV_CACHE_DELETE); 3017688SAaron.Zang@Sun.COM } 3027688SAaron.Zang@Sun.COM } 3037688SAaron.Zang@Sun.COM 3047688SAaron.Zang@Sun.COM static void 3057688SAaron.Zang@Sun.COM devvt_cleandir(struct vnode *dvp, struct cred *cred) 3067688SAaron.Zang@Sun.COM { 3077688SAaron.Zang@Sun.COM struct sdev_node *sdvp = VTOSDEV(dvp); 3087688SAaron.Zang@Sun.COM struct sdev_node *dv, *next = NULL; 3097688SAaron.Zang@Sun.COM int min, cnt; 3107688SAaron.Zang@Sun.COM int found = 0; 3117688SAaron.Zang@Sun.COM 3127688SAaron.Zang@Sun.COM mutex_enter(&vc_lock); 3137688SAaron.Zang@Sun.COM cnt = VC_INSTANCES_COUNT; 3147688SAaron.Zang@Sun.COM mutex_exit(&vc_lock); 3157688SAaron.Zang@Sun.COM 3167688SAaron.Zang@Sun.COM /* We have to fool warlock this way, otherwise it will complain */ 3177688SAaron.Zang@Sun.COM #ifndef __lock_lint 3187688SAaron.Zang@Sun.COM if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) { 3197688SAaron.Zang@Sun.COM rw_exit(&sdvp->sdev_contents); 3207688SAaron.Zang@Sun.COM rw_enter(&sdvp->sdev_contents, RW_WRITER); 3217688SAaron.Zang@Sun.COM } 3227688SAaron.Zang@Sun.COM #else 3237688SAaron.Zang@Sun.COM rw_enter(&sdvp->sdev_contents, RW_WRITER); 3247688SAaron.Zang@Sun.COM #endif 3257688SAaron.Zang@Sun.COM 3267688SAaron.Zang@Sun.COM /* 1. create missed nodes */ 3277688SAaron.Zang@Sun.COM for (min = 0; min < cnt; min++) { 3287688SAaron.Zang@Sun.COM char nm[16]; 3297688SAaron.Zang@Sun.COM 3307688SAaron.Zang@Sun.COM if (vt_minor_valid(min) == B_FALSE) 3317688SAaron.Zang@Sun.COM continue; 3327688SAaron.Zang@Sun.COM 3337688SAaron.Zang@Sun.COM (void) snprintf(nm, sizeof (nm), "%d", min); 3347688SAaron.Zang@Sun.COM found = 0; 3357688SAaron.Zang@Sun.COM for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) { 3367688SAaron.Zang@Sun.COM next = SDEV_NEXT_ENTRY(sdvp, dv); 3377688SAaron.Zang@Sun.COM 3387688SAaron.Zang@Sun.COM /* skip stale nodes */ 3397688SAaron.Zang@Sun.COM if (dv->sdev_flags & SDEV_STALE) 3407688SAaron.Zang@Sun.COM continue; 3417688SAaron.Zang@Sun.COM /* validate and prune only ready nodes */ 3427688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) 3437688SAaron.Zang@Sun.COM continue; 3447688SAaron.Zang@Sun.COM if (strcmp(nm, dv->sdev_name) == 0) { 3457688SAaron.Zang@Sun.COM found = 1; 3467688SAaron.Zang@Sun.COM break; 3477688SAaron.Zang@Sun.COM } 3487688SAaron.Zang@Sun.COM } 3497688SAaron.Zang@Sun.COM if (!found) { 3507688SAaron.Zang@Sun.COM devvt_create_snode(sdvp, nm, cred, SDEV_VATTR); 3517688SAaron.Zang@Sun.COM } 3527688SAaron.Zang@Sun.COM } 3537688SAaron.Zang@Sun.COM 3547688SAaron.Zang@Sun.COM /* 2. create active link node */ 3557688SAaron.Zang@Sun.COM found = 0; 3567688SAaron.Zang@Sun.COM for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) { 3577688SAaron.Zang@Sun.COM next = SDEV_NEXT_ENTRY(sdvp, dv); 3587688SAaron.Zang@Sun.COM 3597688SAaron.Zang@Sun.COM /* skip stale nodes */ 3607688SAaron.Zang@Sun.COM if (dv->sdev_flags & SDEV_STALE) 3617688SAaron.Zang@Sun.COM continue; 3627688SAaron.Zang@Sun.COM /* validate and prune only ready nodes */ 3637688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) 3647688SAaron.Zang@Sun.COM continue; 3657688SAaron.Zang@Sun.COM if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL)) { 3667688SAaron.Zang@Sun.COM found = 1; 3677688SAaron.Zang@Sun.COM break; 3687688SAaron.Zang@Sun.COM } 3697688SAaron.Zang@Sun.COM } 3707688SAaron.Zang@Sun.COM if (!found) 3717688SAaron.Zang@Sun.COM devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK); 3727688SAaron.Zang@Sun.COM 3737688SAaron.Zang@Sun.COM /* 3. cleanup invalid nodes */ 3747688SAaron.Zang@Sun.COM devvt_prunedir(sdvp); 3757688SAaron.Zang@Sun.COM 3767688SAaron.Zang@Sun.COM #ifndef __lock_lint 3777688SAaron.Zang@Sun.COM rw_downgrade(&sdvp->sdev_contents); 3787688SAaron.Zang@Sun.COM #else 3797688SAaron.Zang@Sun.COM rw_exit(&sdvp->sdev_contents); 3807688SAaron.Zang@Sun.COM #endif 3817688SAaron.Zang@Sun.COM } 3827688SAaron.Zang@Sun.COM 3837688SAaron.Zang@Sun.COM /*ARGSUSED4*/ 3847688SAaron.Zang@Sun.COM static int 3857688SAaron.Zang@Sun.COM devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, 3867688SAaron.Zang@Sun.COM int *eofp, caller_context_t *ct, int flags) 3877688SAaron.Zang@Sun.COM { 3887688SAaron.Zang@Sun.COM if (uiop->uio_offset == 0) { 3897688SAaron.Zang@Sun.COM devvt_cleandir(dvp, cred); 3907688SAaron.Zang@Sun.COM } 3917688SAaron.Zang@Sun.COM 3927688SAaron.Zang@Sun.COM return (devname_readdir_func(dvp, uiop, cred, eofp, 0)); 3937688SAaron.Zang@Sun.COM } 3947688SAaron.Zang@Sun.COM 3957688SAaron.Zang@Sun.COM /* 3967688SAaron.Zang@Sun.COM * We allow create to find existing nodes 3977688SAaron.Zang@Sun.COM * - if the node doesn't exist - EROFS 3987688SAaron.Zang@Sun.COM * - creating an existing dir read-only succeeds, otherwise EISDIR 3997688SAaron.Zang@Sun.COM * - exclusive creates fail - EEXIST 4007688SAaron.Zang@Sun.COM */ 4017688SAaron.Zang@Sun.COM /*ARGSUSED2*/ 4027688SAaron.Zang@Sun.COM static int 4037688SAaron.Zang@Sun.COM devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl, 4047688SAaron.Zang@Sun.COM int mode, struct vnode **vpp, struct cred *cred, int flag, 4057688SAaron.Zang@Sun.COM caller_context_t *ct, vsecattr_t *vsecp) 4067688SAaron.Zang@Sun.COM { 4077688SAaron.Zang@Sun.COM int error; 4087688SAaron.Zang@Sun.COM struct vnode *vp; 4097688SAaron.Zang@Sun.COM 4107688SAaron.Zang@Sun.COM *vpp = NULL; 4117688SAaron.Zang@Sun.COM 4127688SAaron.Zang@Sun.COM if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, 4137688SAaron.Zang@Sun.COM NULL)) != 0) { 4147688SAaron.Zang@Sun.COM if (error == ENOENT) 4157688SAaron.Zang@Sun.COM error = EROFS; 4167688SAaron.Zang@Sun.COM return (error); 4177688SAaron.Zang@Sun.COM } 4187688SAaron.Zang@Sun.COM 4197688SAaron.Zang@Sun.COM if (excl == EXCL) 4207688SAaron.Zang@Sun.COM error = EEXIST; 4217688SAaron.Zang@Sun.COM else if (vp->v_type == VDIR && (mode & VWRITE)) 4227688SAaron.Zang@Sun.COM error = EISDIR; 4237688SAaron.Zang@Sun.COM else 4247688SAaron.Zang@Sun.COM error = VOP_ACCESS(vp, mode, 0, cred, ct); 4257688SAaron.Zang@Sun.COM 4267688SAaron.Zang@Sun.COM if (error) { 4277688SAaron.Zang@Sun.COM VN_RELE(vp); 4287688SAaron.Zang@Sun.COM } else 4297688SAaron.Zang@Sun.COM *vpp = vp; 4307688SAaron.Zang@Sun.COM 4317688SAaron.Zang@Sun.COM return (error); 4327688SAaron.Zang@Sun.COM } 4337688SAaron.Zang@Sun.COM 4347688SAaron.Zang@Sun.COM const fs_operation_def_t devvt_vnodeops_tbl[] = { 4357688SAaron.Zang@Sun.COM VOPNAME_READDIR, { .vop_readdir = devvt_readdir }, 4367688SAaron.Zang@Sun.COM VOPNAME_LOOKUP, { .vop_lookup = devvt_lookup }, 4377688SAaron.Zang@Sun.COM VOPNAME_CREATE, { .vop_create = devvt_create }, 4387688SAaron.Zang@Sun.COM VOPNAME_REMOVE, { .error = fs_nosys }, 4397688SAaron.Zang@Sun.COM VOPNAME_MKDIR, { .error = fs_nosys }, 4407688SAaron.Zang@Sun.COM VOPNAME_RMDIR, { .error = fs_nosys }, 4417688SAaron.Zang@Sun.COM VOPNAME_SYMLINK, { .error = fs_nosys }, 4427688SAaron.Zang@Sun.COM VOPNAME_SETSECATTR, { .error = fs_nosys }, 4437688SAaron.Zang@Sun.COM NULL, NULL 4447688SAaron.Zang@Sun.COM }; 445