1*7688SAaron.Zang@Sun.COM /* 2*7688SAaron.Zang@Sun.COM * CDDL HEADER START 3*7688SAaron.Zang@Sun.COM * 4*7688SAaron.Zang@Sun.COM * The contents of this file are subject to the terms of the 5*7688SAaron.Zang@Sun.COM * Common Development and Distribution License (the "License"). 6*7688SAaron.Zang@Sun.COM * You may not use this file except in compliance with the License. 7*7688SAaron.Zang@Sun.COM * 8*7688SAaron.Zang@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7688SAaron.Zang@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*7688SAaron.Zang@Sun.COM * See the License for the specific language governing permissions 11*7688SAaron.Zang@Sun.COM * and limitations under the License. 12*7688SAaron.Zang@Sun.COM * 13*7688SAaron.Zang@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*7688SAaron.Zang@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7688SAaron.Zang@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*7688SAaron.Zang@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*7688SAaron.Zang@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*7688SAaron.Zang@Sun.COM * 19*7688SAaron.Zang@Sun.COM * CDDL HEADER END 20*7688SAaron.Zang@Sun.COM */ 21*7688SAaron.Zang@Sun.COM /* 22*7688SAaron.Zang@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*7688SAaron.Zang@Sun.COM * Use is subject to license terms. 24*7688SAaron.Zang@Sun.COM */ 25*7688SAaron.Zang@Sun.COM 26*7688SAaron.Zang@Sun.COM /* 27*7688SAaron.Zang@Sun.COM * vnode ops for the /dev/vt directory 28*7688SAaron.Zang@Sun.COM */ 29*7688SAaron.Zang@Sun.COM 30*7688SAaron.Zang@Sun.COM #include <sys/types.h> 31*7688SAaron.Zang@Sun.COM #include <sys/param.h> 32*7688SAaron.Zang@Sun.COM #include <sys/sysmacros.h> 33*7688SAaron.Zang@Sun.COM #include <sys/sunndi.h> 34*7688SAaron.Zang@Sun.COM #include <fs/fs_subr.h> 35*7688SAaron.Zang@Sun.COM #include <sys/fs/dv_node.h> 36*7688SAaron.Zang@Sun.COM #include <sys/fs/sdev_impl.h> 37*7688SAaron.Zang@Sun.COM #include <sys/policy.h> 38*7688SAaron.Zang@Sun.COM #include <sys/stat.h> 39*7688SAaron.Zang@Sun.COM #include <sys/vfs_opreg.h> 40*7688SAaron.Zang@Sun.COM #include <sys/tty.h> 41*7688SAaron.Zang@Sun.COM #include <sys/vt_impl.h> 42*7688SAaron.Zang@Sun.COM #include <sys/note.h> 43*7688SAaron.Zang@Sun.COM 44*7688SAaron.Zang@Sun.COM /* warlock in this file only cares about variables shared by vt and devfs */ 45*7688SAaron.Zang@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode)) 46*7688SAaron.Zang@Sun.COM 47*7688SAaron.Zang@Sun.COM #define DEVVT_UID_DEFAULT SDEV_UID_DEFAULT 48*7688SAaron.Zang@Sun.COM #define DEVVT_GID_DEFAULT (0) 49*7688SAaron.Zang@Sun.COM #define DEVVT_DEVMODE_DEFAULT (0600) 50*7688SAaron.Zang@Sun.COM #define DEVVT_ACTIVE_NAME "active" 51*7688SAaron.Zang@Sun.COM 52*7688SAaron.Zang@Sun.COM #define isdigit(ch) ((ch) >= '0' && (ch) <= '9') 53*7688SAaron.Zang@Sun.COM 54*7688SAaron.Zang@Sun.COM /* attributes for VT nodes */ 55*7688SAaron.Zang@Sun.COM static vattr_t devvt_vattr = { 56*7688SAaron.Zang@Sun.COM AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 57*7688SAaron.Zang@Sun.COM VCHR, /* va_type */ 58*7688SAaron.Zang@Sun.COM S_IFCHR | DEVVT_DEVMODE_DEFAULT, /* va_mode */ 59*7688SAaron.Zang@Sun.COM DEVVT_UID_DEFAULT, /* va_uid */ 60*7688SAaron.Zang@Sun.COM DEVVT_GID_DEFAULT, /* va_gid */ 61*7688SAaron.Zang@Sun.COM 0 /* 0 hereafter */ 62*7688SAaron.Zang@Sun.COM }; 63*7688SAaron.Zang@Sun.COM 64*7688SAaron.Zang@Sun.COM struct vnodeops *devvt_vnodeops; 65*7688SAaron.Zang@Sun.COM 66*7688SAaron.Zang@Sun.COM struct vnodeops * 67*7688SAaron.Zang@Sun.COM devvt_getvnodeops(void) 68*7688SAaron.Zang@Sun.COM { 69*7688SAaron.Zang@Sun.COM return (devvt_vnodeops); 70*7688SAaron.Zang@Sun.COM } 71*7688SAaron.Zang@Sun.COM 72*7688SAaron.Zang@Sun.COM static int 73*7688SAaron.Zang@Sun.COM devvt_str2minor(const char *nm, minor_t *mp) 74*7688SAaron.Zang@Sun.COM { 75*7688SAaron.Zang@Sun.COM long uminor = 0; 76*7688SAaron.Zang@Sun.COM char *endptr = NULL; 77*7688SAaron.Zang@Sun.COM 78*7688SAaron.Zang@Sun.COM if (nm == NULL || !isdigit(*nm)) 79*7688SAaron.Zang@Sun.COM return (EINVAL); 80*7688SAaron.Zang@Sun.COM 81*7688SAaron.Zang@Sun.COM *mp = 0; 82*7688SAaron.Zang@Sun.COM if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 || 83*7688SAaron.Zang@Sun.COM *endptr != '\0' || uminor < 0) { 84*7688SAaron.Zang@Sun.COM return (EINVAL); 85*7688SAaron.Zang@Sun.COM } 86*7688SAaron.Zang@Sun.COM 87*7688SAaron.Zang@Sun.COM *mp = (minor_t)uminor; 88*7688SAaron.Zang@Sun.COM return (0); 89*7688SAaron.Zang@Sun.COM } 90*7688SAaron.Zang@Sun.COM 91*7688SAaron.Zang@Sun.COM /*ARGSUSED*/ 92*7688SAaron.Zang@Sun.COM int 93*7688SAaron.Zang@Sun.COM devvt_validate(struct sdev_node *dv) 94*7688SAaron.Zang@Sun.COM { 95*7688SAaron.Zang@Sun.COM minor_t min; 96*7688SAaron.Zang@Sun.COM char *nm = dv->sdev_name; 97*7688SAaron.Zang@Sun.COM 98*7688SAaron.Zang@Sun.COM ASSERT(!(dv->sdev_flags & SDEV_STALE)); 99*7688SAaron.Zang@Sun.COM ASSERT(dv->sdev_state == SDEV_READY); 100*7688SAaron.Zang@Sun.COM 101*7688SAaron.Zang@Sun.COM /* validate only READY nodes */ 102*7688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) { 103*7688SAaron.Zang@Sun.COM sdcmn_err(("dev fs: skipping: node not ready %s(%p)", 104*7688SAaron.Zang@Sun.COM nm, (void *)dv)); 105*7688SAaron.Zang@Sun.COM return (SDEV_VTOR_SKIP); 106*7688SAaron.Zang@Sun.COM } 107*7688SAaron.Zang@Sun.COM 108*7688SAaron.Zang@Sun.COM if (vt_wc_attached() == (major_t)-1) 109*7688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 110*7688SAaron.Zang@Sun.COM 111*7688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) { 112*7688SAaron.Zang@Sun.COM char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 113*7688SAaron.Zang@Sun.COM 114*7688SAaron.Zang@Sun.COM (void) vt_getactive(link, MAXPATHLEN); 115*7688SAaron.Zang@Sun.COM if (strcmp(link, dv->sdev_symlink) != 0) { 116*7688SAaron.Zang@Sun.COM kmem_free(dv->sdev_symlink, 117*7688SAaron.Zang@Sun.COM strlen(dv->sdev_symlink) + 1); 118*7688SAaron.Zang@Sun.COM dv->sdev_symlink = i_ddi_strdup(link, KM_SLEEP); 119*7688SAaron.Zang@Sun.COM dv->sdev_attr->va_size = strlen(link); 120*7688SAaron.Zang@Sun.COM } 121*7688SAaron.Zang@Sun.COM kmem_free(link, MAXPATHLEN); 122*7688SAaron.Zang@Sun.COM return (SDEV_VTOR_VALID); 123*7688SAaron.Zang@Sun.COM } else if (devvt_str2minor(nm, &min) != 0) { 124*7688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 125*7688SAaron.Zang@Sun.COM } 126*7688SAaron.Zang@Sun.COM 127*7688SAaron.Zang@Sun.COM if (vt_minor_valid(min) == B_FALSE) 128*7688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 129*7688SAaron.Zang@Sun.COM 130*7688SAaron.Zang@Sun.COM return (SDEV_VTOR_VALID); 131*7688SAaron.Zang@Sun.COM } 132*7688SAaron.Zang@Sun.COM 133*7688SAaron.Zang@Sun.COM /* 134*7688SAaron.Zang@Sun.COM * This callback is invoked from devname_lookup_func() to create 135*7688SAaron.Zang@Sun.COM * a entry when the node is not found in the cache. 136*7688SAaron.Zang@Sun.COM */ 137*7688SAaron.Zang@Sun.COM /*ARGSUSED*/ 138*7688SAaron.Zang@Sun.COM static int 139*7688SAaron.Zang@Sun.COM devvt_create_rvp(struct sdev_node *ddv, char *nm, 140*7688SAaron.Zang@Sun.COM void **arg, cred_t *cred, void *whatever, char *whichever) 141*7688SAaron.Zang@Sun.COM { 142*7688SAaron.Zang@Sun.COM minor_t min; 143*7688SAaron.Zang@Sun.COM major_t maj; 144*7688SAaron.Zang@Sun.COM struct vattr *vap = (struct vattr *)arg; 145*7688SAaron.Zang@Sun.COM 146*7688SAaron.Zang@Sun.COM if ((maj = vt_wc_attached()) == (major_t)-1) 147*7688SAaron.Zang@Sun.COM return (SDEV_VTOR_INVALID); 148*7688SAaron.Zang@Sun.COM 149*7688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) { 150*7688SAaron.Zang@Sun.COM (void) vt_getactive((char *)*arg, MAXPATHLEN); 151*7688SAaron.Zang@Sun.COM return (0); 152*7688SAaron.Zang@Sun.COM } 153*7688SAaron.Zang@Sun.COM 154*7688SAaron.Zang@Sun.COM if (devvt_str2minor(nm, &min) != 0) 155*7688SAaron.Zang@Sun.COM return (-1); 156*7688SAaron.Zang@Sun.COM 157*7688SAaron.Zang@Sun.COM if (vt_minor_valid(min) == B_FALSE) 158*7688SAaron.Zang@Sun.COM return (-1); 159*7688SAaron.Zang@Sun.COM 160*7688SAaron.Zang@Sun.COM *vap = devvt_vattr; 161*7688SAaron.Zang@Sun.COM vap->va_rdev = makedevice(maj, min); 162*7688SAaron.Zang@Sun.COM 163*7688SAaron.Zang@Sun.COM return (0); 164*7688SAaron.Zang@Sun.COM } 165*7688SAaron.Zang@Sun.COM 166*7688SAaron.Zang@Sun.COM /*ARGSUSED3*/ 167*7688SAaron.Zang@Sun.COM static int 168*7688SAaron.Zang@Sun.COM devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp, 169*7688SAaron.Zang@Sun.COM struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred, 170*7688SAaron.Zang@Sun.COM caller_context_t *ct, int *direntflags, pathname_t *realpnp) 171*7688SAaron.Zang@Sun.COM { 172*7688SAaron.Zang@Sun.COM struct sdev_node *sdvp = VTOSDEV(dvp); 173*7688SAaron.Zang@Sun.COM struct sdev_node *dv; 174*7688SAaron.Zang@Sun.COM struct vnode *rvp = NULL; 175*7688SAaron.Zang@Sun.COM int type, error; 176*7688SAaron.Zang@Sun.COM 177*7688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) { 178*7688SAaron.Zang@Sun.COM type = SDEV_VLINK; 179*7688SAaron.Zang@Sun.COM } else { 180*7688SAaron.Zang@Sun.COM type = SDEV_VATTR; 181*7688SAaron.Zang@Sun.COM } 182*7688SAaron.Zang@Sun.COM 183*7688SAaron.Zang@Sun.COM /* Give warlock a more clear call graph */ 184*7688SAaron.Zang@Sun.COM #ifndef __lock_lint 185*7688SAaron.Zang@Sun.COM error = devname_lookup_func(sdvp, nm, vpp, cred, 186*7688SAaron.Zang@Sun.COM devvt_create_rvp, type); 187*7688SAaron.Zang@Sun.COM #else 188*7688SAaron.Zang@Sun.COM devvt_create_rvp(0, 0, 0, 0, 0, 0); 189*7688SAaron.Zang@Sun.COM #endif 190*7688SAaron.Zang@Sun.COM 191*7688SAaron.Zang@Sun.COM if (error == 0) { 192*7688SAaron.Zang@Sun.COM switch ((*vpp)->v_type) { 193*7688SAaron.Zang@Sun.COM case VCHR: 194*7688SAaron.Zang@Sun.COM dv = VTOSDEV(VTOS(*vpp)->s_realvp); 195*7688SAaron.Zang@Sun.COM ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS); 196*7688SAaron.Zang@Sun.COM break; 197*7688SAaron.Zang@Sun.COM case VDIR: 198*7688SAaron.Zang@Sun.COM case VLNK: 199*7688SAaron.Zang@Sun.COM dv = VTOSDEV(*vpp); 200*7688SAaron.Zang@Sun.COM break; 201*7688SAaron.Zang@Sun.COM default: 202*7688SAaron.Zang@Sun.COM cmn_err(CE_PANIC, "devvt_lookup: Unsupported node " 203*7688SAaron.Zang@Sun.COM "type: %p: %d", (void *)(*vpp), (*vpp)->v_type); 204*7688SAaron.Zang@Sun.COM break; 205*7688SAaron.Zang@Sun.COM } 206*7688SAaron.Zang@Sun.COM ASSERT(SDEV_HELD(dv)); 207*7688SAaron.Zang@Sun.COM } 208*7688SAaron.Zang@Sun.COM 209*7688SAaron.Zang@Sun.COM return (error); 210*7688SAaron.Zang@Sun.COM } 211*7688SAaron.Zang@Sun.COM 212*7688SAaron.Zang@Sun.COM static void 213*7688SAaron.Zang@Sun.COM devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type) 214*7688SAaron.Zang@Sun.COM { 215*7688SAaron.Zang@Sun.COM int error; 216*7688SAaron.Zang@Sun.COM struct sdev_node *sdv = NULL; 217*7688SAaron.Zang@Sun.COM struct vattr *vap = NULL; 218*7688SAaron.Zang@Sun.COM major_t maj; 219*7688SAaron.Zang@Sun.COM minor_t min; 220*7688SAaron.Zang@Sun.COM 221*7688SAaron.Zang@Sun.COM if ((maj = vt_wc_attached()) == (major_t)-1) 222*7688SAaron.Zang@Sun.COM return; 223*7688SAaron.Zang@Sun.COM 224*7688SAaron.Zang@Sun.COM if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 && 225*7688SAaron.Zang@Sun.COM devvt_str2minor(nm, &min) != 0) 226*7688SAaron.Zang@Sun.COM return; 227*7688SAaron.Zang@Sun.COM 228*7688SAaron.Zang@Sun.COM error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT); 229*7688SAaron.Zang@Sun.COM if (error || !sdv) { 230*7688SAaron.Zang@Sun.COM return; 231*7688SAaron.Zang@Sun.COM } 232*7688SAaron.Zang@Sun.COM 233*7688SAaron.Zang@Sun.COM mutex_enter(&sdv->sdev_lookup_lock); 234*7688SAaron.Zang@Sun.COM SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP); 235*7688SAaron.Zang@Sun.COM mutex_exit(&sdv->sdev_lookup_lock); 236*7688SAaron.Zang@Sun.COM 237*7688SAaron.Zang@Sun.COM if (type & SDEV_VATTR) { 238*7688SAaron.Zang@Sun.COM vap = &devvt_vattr; 239*7688SAaron.Zang@Sun.COM vap->va_rdev = makedevice(maj, min); 240*7688SAaron.Zang@Sun.COM error = sdev_mknode(ddv, nm, &sdv, vap, NULL, 241*7688SAaron.Zang@Sun.COM NULL, cred, SDEV_READY); 242*7688SAaron.Zang@Sun.COM } else if (type & SDEV_VLINK) { 243*7688SAaron.Zang@Sun.COM char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 244*7688SAaron.Zang@Sun.COM 245*7688SAaron.Zang@Sun.COM (void) vt_getactive(link, MAXPATHLEN); 246*7688SAaron.Zang@Sun.COM vap = &sdev_vattr_lnk; 247*7688SAaron.Zang@Sun.COM vap->va_size = strlen(link); 248*7688SAaron.Zang@Sun.COM error = sdev_mknode(ddv, nm, &sdv, vap, NULL, 249*7688SAaron.Zang@Sun.COM (void *)link, cred, SDEV_READY); 250*7688SAaron.Zang@Sun.COM 251*7688SAaron.Zang@Sun.COM kmem_free(link, MAXPATHLEN); 252*7688SAaron.Zang@Sun.COM } 253*7688SAaron.Zang@Sun.COM 254*7688SAaron.Zang@Sun.COM mutex_enter(&sdv->sdev_lookup_lock); 255*7688SAaron.Zang@Sun.COM SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP); 256*7688SAaron.Zang@Sun.COM mutex_exit(&sdv->sdev_lookup_lock); 257*7688SAaron.Zang@Sun.COM 258*7688SAaron.Zang@Sun.COM } 259*7688SAaron.Zang@Sun.COM 260*7688SAaron.Zang@Sun.COM static void 261*7688SAaron.Zang@Sun.COM devvt_prunedir(struct sdev_node *ddv) 262*7688SAaron.Zang@Sun.COM { 263*7688SAaron.Zang@Sun.COM struct vnode *vp; 264*7688SAaron.Zang@Sun.COM struct sdev_node *dv, *next = NULL; 265*7688SAaron.Zang@Sun.COM int (*vtor)(struct sdev_node *) = NULL; 266*7688SAaron.Zang@Sun.COM 267*7688SAaron.Zang@Sun.COM ASSERT(ddv->sdev_flags & SDEV_VTOR); 268*7688SAaron.Zang@Sun.COM 269*7688SAaron.Zang@Sun.COM vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv); 270*7688SAaron.Zang@Sun.COM ASSERT(vtor); 271*7688SAaron.Zang@Sun.COM 272*7688SAaron.Zang@Sun.COM for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) { 273*7688SAaron.Zang@Sun.COM next = SDEV_NEXT_ENTRY(ddv, dv); 274*7688SAaron.Zang@Sun.COM 275*7688SAaron.Zang@Sun.COM /* skip stale nodes */ 276*7688SAaron.Zang@Sun.COM if (dv->sdev_flags & SDEV_STALE) 277*7688SAaron.Zang@Sun.COM continue; 278*7688SAaron.Zang@Sun.COM 279*7688SAaron.Zang@Sun.COM /* validate and prune only ready nodes */ 280*7688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) 281*7688SAaron.Zang@Sun.COM continue; 282*7688SAaron.Zang@Sun.COM 283*7688SAaron.Zang@Sun.COM switch (vtor(dv)) { 284*7688SAaron.Zang@Sun.COM case SDEV_VTOR_VALID: 285*7688SAaron.Zang@Sun.COM case SDEV_VTOR_SKIP: 286*7688SAaron.Zang@Sun.COM continue; 287*7688SAaron.Zang@Sun.COM case SDEV_VTOR_INVALID: 288*7688SAaron.Zang@Sun.COM sdcmn_err7(("destroy invalid " 289*7688SAaron.Zang@Sun.COM "node: %s(%p)\n", dv->sdev_name, (void *)dv)); 290*7688SAaron.Zang@Sun.COM break; 291*7688SAaron.Zang@Sun.COM } 292*7688SAaron.Zang@Sun.COM vp = SDEVTOV(dv); 293*7688SAaron.Zang@Sun.COM if (vp->v_count > 0) 294*7688SAaron.Zang@Sun.COM continue; 295*7688SAaron.Zang@Sun.COM SDEV_HOLD(dv); 296*7688SAaron.Zang@Sun.COM /* remove the cache node */ 297*7688SAaron.Zang@Sun.COM (void) sdev_cache_update(ddv, &dv, dv->sdev_name, 298*7688SAaron.Zang@Sun.COM SDEV_CACHE_DELETE); 299*7688SAaron.Zang@Sun.COM } 300*7688SAaron.Zang@Sun.COM } 301*7688SAaron.Zang@Sun.COM 302*7688SAaron.Zang@Sun.COM static void 303*7688SAaron.Zang@Sun.COM devvt_cleandir(struct vnode *dvp, struct cred *cred) 304*7688SAaron.Zang@Sun.COM { 305*7688SAaron.Zang@Sun.COM struct sdev_node *sdvp = VTOSDEV(dvp); 306*7688SAaron.Zang@Sun.COM struct sdev_node *dv, *next = NULL; 307*7688SAaron.Zang@Sun.COM int min, cnt; 308*7688SAaron.Zang@Sun.COM int found = 0; 309*7688SAaron.Zang@Sun.COM 310*7688SAaron.Zang@Sun.COM mutex_enter(&vc_lock); 311*7688SAaron.Zang@Sun.COM cnt = VC_INSTANCES_COUNT; 312*7688SAaron.Zang@Sun.COM mutex_exit(&vc_lock); 313*7688SAaron.Zang@Sun.COM 314*7688SAaron.Zang@Sun.COM /* We have to fool warlock this way, otherwise it will complain */ 315*7688SAaron.Zang@Sun.COM #ifndef __lock_lint 316*7688SAaron.Zang@Sun.COM if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) { 317*7688SAaron.Zang@Sun.COM rw_exit(&sdvp->sdev_contents); 318*7688SAaron.Zang@Sun.COM rw_enter(&sdvp->sdev_contents, RW_WRITER); 319*7688SAaron.Zang@Sun.COM } 320*7688SAaron.Zang@Sun.COM #else 321*7688SAaron.Zang@Sun.COM rw_enter(&sdvp->sdev_contents, RW_WRITER); 322*7688SAaron.Zang@Sun.COM #endif 323*7688SAaron.Zang@Sun.COM 324*7688SAaron.Zang@Sun.COM /* 1. create missed nodes */ 325*7688SAaron.Zang@Sun.COM for (min = 0; min < cnt; min++) { 326*7688SAaron.Zang@Sun.COM char nm[16]; 327*7688SAaron.Zang@Sun.COM 328*7688SAaron.Zang@Sun.COM if (vt_minor_valid(min) == B_FALSE) 329*7688SAaron.Zang@Sun.COM continue; 330*7688SAaron.Zang@Sun.COM 331*7688SAaron.Zang@Sun.COM (void) snprintf(nm, sizeof (nm), "%d", min); 332*7688SAaron.Zang@Sun.COM found = 0; 333*7688SAaron.Zang@Sun.COM for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) { 334*7688SAaron.Zang@Sun.COM next = SDEV_NEXT_ENTRY(sdvp, dv); 335*7688SAaron.Zang@Sun.COM 336*7688SAaron.Zang@Sun.COM /* skip stale nodes */ 337*7688SAaron.Zang@Sun.COM if (dv->sdev_flags & SDEV_STALE) 338*7688SAaron.Zang@Sun.COM continue; 339*7688SAaron.Zang@Sun.COM /* validate and prune only ready nodes */ 340*7688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) 341*7688SAaron.Zang@Sun.COM continue; 342*7688SAaron.Zang@Sun.COM if (strcmp(nm, dv->sdev_name) == 0) { 343*7688SAaron.Zang@Sun.COM found = 1; 344*7688SAaron.Zang@Sun.COM break; 345*7688SAaron.Zang@Sun.COM } 346*7688SAaron.Zang@Sun.COM } 347*7688SAaron.Zang@Sun.COM if (!found) { 348*7688SAaron.Zang@Sun.COM devvt_create_snode(sdvp, nm, cred, SDEV_VATTR); 349*7688SAaron.Zang@Sun.COM } 350*7688SAaron.Zang@Sun.COM } 351*7688SAaron.Zang@Sun.COM 352*7688SAaron.Zang@Sun.COM /* 2. create active link node */ 353*7688SAaron.Zang@Sun.COM found = 0; 354*7688SAaron.Zang@Sun.COM for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) { 355*7688SAaron.Zang@Sun.COM next = SDEV_NEXT_ENTRY(sdvp, dv); 356*7688SAaron.Zang@Sun.COM 357*7688SAaron.Zang@Sun.COM /* skip stale nodes */ 358*7688SAaron.Zang@Sun.COM if (dv->sdev_flags & SDEV_STALE) 359*7688SAaron.Zang@Sun.COM continue; 360*7688SAaron.Zang@Sun.COM /* validate and prune only ready nodes */ 361*7688SAaron.Zang@Sun.COM if (dv->sdev_state != SDEV_READY) 362*7688SAaron.Zang@Sun.COM continue; 363*7688SAaron.Zang@Sun.COM if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL)) { 364*7688SAaron.Zang@Sun.COM found = 1; 365*7688SAaron.Zang@Sun.COM break; 366*7688SAaron.Zang@Sun.COM } 367*7688SAaron.Zang@Sun.COM } 368*7688SAaron.Zang@Sun.COM if (!found) 369*7688SAaron.Zang@Sun.COM devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK); 370*7688SAaron.Zang@Sun.COM 371*7688SAaron.Zang@Sun.COM /* 3. cleanup invalid nodes */ 372*7688SAaron.Zang@Sun.COM devvt_prunedir(sdvp); 373*7688SAaron.Zang@Sun.COM 374*7688SAaron.Zang@Sun.COM #ifndef __lock_lint 375*7688SAaron.Zang@Sun.COM rw_downgrade(&sdvp->sdev_contents); 376*7688SAaron.Zang@Sun.COM #else 377*7688SAaron.Zang@Sun.COM rw_exit(&sdvp->sdev_contents); 378*7688SAaron.Zang@Sun.COM #endif 379*7688SAaron.Zang@Sun.COM } 380*7688SAaron.Zang@Sun.COM 381*7688SAaron.Zang@Sun.COM /*ARGSUSED4*/ 382*7688SAaron.Zang@Sun.COM static int 383*7688SAaron.Zang@Sun.COM devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, 384*7688SAaron.Zang@Sun.COM int *eofp, caller_context_t *ct, int flags) 385*7688SAaron.Zang@Sun.COM { 386*7688SAaron.Zang@Sun.COM if (uiop->uio_offset == 0) { 387*7688SAaron.Zang@Sun.COM devvt_cleandir(dvp, cred); 388*7688SAaron.Zang@Sun.COM } 389*7688SAaron.Zang@Sun.COM 390*7688SAaron.Zang@Sun.COM return (devname_readdir_func(dvp, uiop, cred, eofp, 0)); 391*7688SAaron.Zang@Sun.COM } 392*7688SAaron.Zang@Sun.COM 393*7688SAaron.Zang@Sun.COM /* 394*7688SAaron.Zang@Sun.COM * We allow create to find existing nodes 395*7688SAaron.Zang@Sun.COM * - if the node doesn't exist - EROFS 396*7688SAaron.Zang@Sun.COM * - creating an existing dir read-only succeeds, otherwise EISDIR 397*7688SAaron.Zang@Sun.COM * - exclusive creates fail - EEXIST 398*7688SAaron.Zang@Sun.COM */ 399*7688SAaron.Zang@Sun.COM /*ARGSUSED2*/ 400*7688SAaron.Zang@Sun.COM static int 401*7688SAaron.Zang@Sun.COM devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl, 402*7688SAaron.Zang@Sun.COM int mode, struct vnode **vpp, struct cred *cred, int flag, 403*7688SAaron.Zang@Sun.COM caller_context_t *ct, vsecattr_t *vsecp) 404*7688SAaron.Zang@Sun.COM { 405*7688SAaron.Zang@Sun.COM int error; 406*7688SAaron.Zang@Sun.COM struct vnode *vp; 407*7688SAaron.Zang@Sun.COM 408*7688SAaron.Zang@Sun.COM *vpp = NULL; 409*7688SAaron.Zang@Sun.COM 410*7688SAaron.Zang@Sun.COM if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, 411*7688SAaron.Zang@Sun.COM NULL)) != 0) { 412*7688SAaron.Zang@Sun.COM if (error == ENOENT) 413*7688SAaron.Zang@Sun.COM error = EROFS; 414*7688SAaron.Zang@Sun.COM return (error); 415*7688SAaron.Zang@Sun.COM } 416*7688SAaron.Zang@Sun.COM 417*7688SAaron.Zang@Sun.COM if (excl == EXCL) 418*7688SAaron.Zang@Sun.COM error = EEXIST; 419*7688SAaron.Zang@Sun.COM else if (vp->v_type == VDIR && (mode & VWRITE)) 420*7688SAaron.Zang@Sun.COM error = EISDIR; 421*7688SAaron.Zang@Sun.COM else 422*7688SAaron.Zang@Sun.COM error = VOP_ACCESS(vp, mode, 0, cred, ct); 423*7688SAaron.Zang@Sun.COM 424*7688SAaron.Zang@Sun.COM if (error) { 425*7688SAaron.Zang@Sun.COM VN_RELE(vp); 426*7688SAaron.Zang@Sun.COM } else 427*7688SAaron.Zang@Sun.COM *vpp = vp; 428*7688SAaron.Zang@Sun.COM 429*7688SAaron.Zang@Sun.COM return (error); 430*7688SAaron.Zang@Sun.COM } 431*7688SAaron.Zang@Sun.COM 432*7688SAaron.Zang@Sun.COM const fs_operation_def_t devvt_vnodeops_tbl[] = { 433*7688SAaron.Zang@Sun.COM VOPNAME_READDIR, { .vop_readdir = devvt_readdir }, 434*7688SAaron.Zang@Sun.COM VOPNAME_LOOKUP, { .vop_lookup = devvt_lookup }, 435*7688SAaron.Zang@Sun.COM VOPNAME_CREATE, { .vop_create = devvt_create }, 436*7688SAaron.Zang@Sun.COM VOPNAME_REMOVE, { .error = fs_nosys }, 437*7688SAaron.Zang@Sun.COM VOPNAME_MKDIR, { .error = fs_nosys }, 438*7688SAaron.Zang@Sun.COM VOPNAME_RMDIR, { .error = fs_nosys }, 439*7688SAaron.Zang@Sun.COM VOPNAME_SYMLINK, { .error = fs_nosys }, 440*7688SAaron.Zang@Sun.COM VOPNAME_SETSECATTR, { .error = fs_nosys }, 441*7688SAaron.Zang@Sun.COM NULL, NULL 442*7688SAaron.Zang@Sun.COM }; 443