1facf4a8dSllai /* 2facf4a8dSllai * CDDL HEADER START 3facf4a8dSllai * 4facf4a8dSllai * The contents of this file are subject to the terms of the 5facf4a8dSllai * Common Development and Distribution License (the "License"). 6facf4a8dSllai * You may not use this file except in compliance with the License. 7facf4a8dSllai * 8facf4a8dSllai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9facf4a8dSllai * or http://www.opensolaris.org/os/licensing. 10facf4a8dSllai * See the License for the specific language governing permissions 11facf4a8dSllai * and limitations under the License. 12facf4a8dSllai * 13facf4a8dSllai * When distributing Covered Code, include this CDDL HEADER in each 14facf4a8dSllai * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15facf4a8dSllai * If applicable, add the following below this CDDL HEADER, with the 16facf4a8dSllai * fields enclosed by brackets "[]" replaced with your own identifying 17facf4a8dSllai * information: Portions Copyright [yyyy] [name of copyright owner] 18facf4a8dSllai * 19facf4a8dSllai * CDDL HEADER END 20facf4a8dSllai */ 21facf4a8dSllai 22facf4a8dSllai /* 23facf4a8dSllai * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24facf4a8dSllai * Use is subject to license terms. 25facf4a8dSllai */ 26facf4a8dSllai 27facf4a8dSllai #pragma ident "%Z%%M% %I% %E% SMI" 28facf4a8dSllai 29facf4a8dSllai /* 30facf4a8dSllai * This file implements /dev filesystem operations for non-global 31facf4a8dSllai * instances. Three major entry points: 32facf4a8dSllai * devname_profile_update() 33facf4a8dSllai * Update matching rules determining which names to export 34facf4a8dSllai * prof_readdir() 35facf4a8dSllai * Return the list of exported names 36facf4a8dSllai * prof_lookup() 37facf4a8dSllai * Implements lookup 38facf4a8dSllai */ 39facf4a8dSllai 40facf4a8dSllai #include <sys/types.h> 41facf4a8dSllai #include <sys/param.h> 42facf4a8dSllai #include <sys/sysmacros.h> 43facf4a8dSllai #include <sys/vnode.h> 44facf4a8dSllai #include <sys/uio.h> 45facf4a8dSllai #include <sys/dirent.h> 46facf4a8dSllai #include <sys/pathname.h> 47facf4a8dSllai #include <sys/fs/dv_node.h> 48facf4a8dSllai #include <sys/fs/sdev_impl.h> 49facf4a8dSllai #include <sys/sunndi.h> 50facf4a8dSllai #include <sys/modctl.h> 51facf4a8dSllai 52facf4a8dSllai enum { 53facf4a8dSllai PROFILE_TYPE_INCLUDE, 54facf4a8dSllai PROFILE_TYPE_EXCLUDE, 55facf4a8dSllai PROFILE_TYPE_MAP, 56facf4a8dSllai PROFILE_TYPE_SYMLINK 57facf4a8dSllai }; 58facf4a8dSllai 59facf4a8dSllai enum { 60facf4a8dSllai WALK_DIR_CONTINUE = 0, 61facf4a8dSllai WALK_DIR_TERMINATE 62facf4a8dSllai }; 63facf4a8dSllai 64facf4a8dSllai static const char *sdev_nvp_val_err = "nvpair_value error %d, %s\n"; 65facf4a8dSllai 66facf4a8dSllai static void process_rule(struct sdev_node *, struct sdev_node *, 67facf4a8dSllai char *, char *, int); 68facf4a8dSllai static void walk_dir(struct vnode *, void *, int (*)(char *, void *)); 69facf4a8dSllai 70facf4a8dSllai static void 71facf4a8dSllai prof_getattr(struct sdev_node *dir, char *name, struct vnode *gdv, 72facf4a8dSllai struct vattr *vap, struct vnode **avpp, int *no_fs_perm) 73facf4a8dSllai { 74facf4a8dSllai struct vnode *advp; 75facf4a8dSllai 76facf4a8dSllai /* get attribute from shadow, if present; else get default */ 77facf4a8dSllai advp = dir->sdev_attrvp; 78facf4a8dSllai if (advp && VOP_LOOKUP(advp, name, avpp, NULL, 0, NULL, kcred) == 0) { 79facf4a8dSllai (void) VOP_GETATTR(*avpp, vap, 0, kcred); 80facf4a8dSllai } else if (gdv == NULL || gdv->v_type == VDIR) { 81facf4a8dSllai /* always create shadow directory */ 82facf4a8dSllai *vap = sdev_vattr_dir; 83facf4a8dSllai if (advp && VOP_MKDIR(advp, name, 84facf4a8dSllai &sdev_vattr_dir, avpp, kcred) != 0) { 85facf4a8dSllai *avpp = NULLVP; 86facf4a8dSllai sdcmn_err10(("prof_getattr: failed to create " 87facf4a8dSllai "shadow directory %s/%s\n", dir->sdev_path, name)); 88facf4a8dSllai } 89facf4a8dSllai } else { 90facf4a8dSllai /* 91facf4a8dSllai * get default permission from devfs 92facf4a8dSllai * Before calling devfs_get_defattr, we need to get 93facf4a8dSllai * the realvp (the dv_node). If realvp is not a dv_node, 94facf4a8dSllai * devfs_get_defattr() will return a system-wide default 95facf4a8dSllai * attr for device nodes. 96facf4a8dSllai */ 97facf4a8dSllai struct vnode *rvp; 98facf4a8dSllai if (VOP_REALVP(gdv, &rvp) != 0) 99facf4a8dSllai rvp = gdv; 100facf4a8dSllai devfs_get_defattr(rvp, vap, no_fs_perm); 101facf4a8dSllai *avpp = NULLVP; 102facf4a8dSllai } 103facf4a8dSllai 104facf4a8dSllai /* ignore dev_t and vtype from backing store */ 105facf4a8dSllai if (gdv) { 106facf4a8dSllai vap->va_type = gdv->v_type; 107facf4a8dSllai vap->va_rdev = gdv->v_rdev; 108facf4a8dSllai } 109facf4a8dSllai } 110facf4a8dSllai 111facf4a8dSllai static void 112facf4a8dSllai apply_glob_pattern(struct sdev_node *pdir, struct sdev_node *cdir) 113facf4a8dSllai { 114facf4a8dSllai char *name; 115facf4a8dSllai nvpair_t *nvp = NULL; 116facf4a8dSllai nvlist_t *nvl; 117facf4a8dSllai struct vnode *vp = SDEVTOV(cdir); 118facf4a8dSllai int rv = 0; 119facf4a8dSllai 120facf4a8dSllai if (vp->v_type != VDIR) 121facf4a8dSllai return; 122facf4a8dSllai name = cdir->sdev_name; 123facf4a8dSllai nvl = pdir->sdev_prof.dev_glob_incdir; 124facf4a8dSllai while (nvp = nvlist_next_nvpair(nvl, nvp)) { 125facf4a8dSllai char *pathleft; 126facf4a8dSllai char *expr = nvpair_name(nvp); 127facf4a8dSllai if (!gmatch(name, expr)) 128facf4a8dSllai continue; 129facf4a8dSllai rv = nvpair_value_string(nvp, &pathleft); 130facf4a8dSllai if (rv != 0) { 131facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 132facf4a8dSllai rv, nvpair_name(nvp)); 133facf4a8dSllai break; 134facf4a8dSllai } 135facf4a8dSllai process_rule(cdir, cdir->sdev_origin, 136facf4a8dSllai pathleft, NULL, PROFILE_TYPE_INCLUDE); 137facf4a8dSllai } 138facf4a8dSllai } 139facf4a8dSllai 140facf4a8dSllai /* 141facf4a8dSllai * Some commonality here with sdev_mknode(), could be simplified. 142facf4a8dSllai * NOTE: prof_mknode returns with *newdv held once, if success. 143facf4a8dSllai */ 144facf4a8dSllai static int 145facf4a8dSllai prof_mknode(struct sdev_node *dir, char *name, struct sdev_node **newdv, 146facf4a8dSllai vattr_t *vap, vnode_t *avp, void *arg, cred_t *cred) 147facf4a8dSllai { 148facf4a8dSllai struct sdev_node *dv; 149facf4a8dSllai int rv; 150facf4a8dSllai 151facf4a8dSllai ASSERT(RW_WRITE_HELD(&dir->sdev_contents)); 152facf4a8dSllai 153facf4a8dSllai /* check cache first */ 154facf4a8dSllai if (dv = sdev_cache_lookup(dir, name)) { 155facf4a8dSllai *newdv = dv; 156facf4a8dSllai return (0); 157facf4a8dSllai } 158facf4a8dSllai 159facf4a8dSllai /* allocate node and insert into cache */ 160facf4a8dSllai rv = sdev_nodeinit(dir, name, &dv, NULL); 161facf4a8dSllai if (rv != 0) { 162facf4a8dSllai *newdv = NULL; 163facf4a8dSllai return (rv); 164facf4a8dSllai } 165facf4a8dSllai 166facf4a8dSllai rv = sdev_cache_update(dir, &dv, name, SDEV_CACHE_ADD); 167facf4a8dSllai *newdv = dv; 168facf4a8dSllai 169facf4a8dSllai /* put it in ready state */ 170facf4a8dSllai rv = sdev_nodeready(*newdv, vap, avp, arg, cred); 171facf4a8dSllai 172facf4a8dSllai /* handle glob pattern in the middle of a path */ 173facf4a8dSllai if (rv == 0) { 174facf4a8dSllai if (SDEVTOV(*newdv)->v_type == VDIR) 175facf4a8dSllai sdcmn_err10(("sdev_origin for %s set to 0x%p\n", 176facf4a8dSllai name, arg)); 177facf4a8dSllai apply_glob_pattern(dir, *newdv); 178facf4a8dSllai } 179facf4a8dSllai return (rv); 180facf4a8dSllai } 181facf4a8dSllai 182facf4a8dSllai /* 183facf4a8dSllai * Create a directory node in a non-global dev instance. 184facf4a8dSllai * Always create shadow vnode. Set sdev_origin to the corresponding 185facf4a8dSllai * global directory sdev_node if it exists. This facilitates the 186facf4a8dSllai * lookup operation. 187facf4a8dSllai */ 188facf4a8dSllai static int 189facf4a8dSllai prof_make_dir(char *name, struct sdev_node **gdirp, struct sdev_node **dirp) 190facf4a8dSllai { 191facf4a8dSllai struct sdev_node *dir = *dirp; 192facf4a8dSllai struct sdev_node *gdir = *gdirp; 193facf4a8dSllai struct sdev_node *newdv; 194facf4a8dSllai struct vnode *avp, *gnewdir = NULL; 195facf4a8dSllai struct vattr vattr; 196facf4a8dSllai int error; 197facf4a8dSllai 198facf4a8dSllai /* see if name already exists */ 199facf4a8dSllai rw_enter(&dir->sdev_contents, RW_READER); 200facf4a8dSllai if (newdv = sdev_cache_lookup(dir, name)) { 201facf4a8dSllai *dirp = newdv; 202facf4a8dSllai *gdirp = newdv->sdev_origin; 203facf4a8dSllai SDEV_RELE(dir); 204facf4a8dSllai rw_exit(&dir->sdev_contents); 205facf4a8dSllai return (0); 206facf4a8dSllai } 207facf4a8dSllai rw_exit(&dir->sdev_contents); 208facf4a8dSllai 209facf4a8dSllai /* find corresponding dir node in global dev */ 210facf4a8dSllai if (gdir) { 211facf4a8dSllai error = VOP_LOOKUP(SDEVTOV(gdir), name, &gnewdir, 212facf4a8dSllai NULL, 0, NULL, kcred); 213facf4a8dSllai if (error == 0) { 214facf4a8dSllai *gdirp = VTOSDEV(gnewdir); 215facf4a8dSllai } else { /* it's ok if there no global dir */ 216facf4a8dSllai *gdirp = NULL; 217facf4a8dSllai } 218facf4a8dSllai } 219facf4a8dSllai 220facf4a8dSllai /* get attribute from shadow, also create shadow dir */ 221facf4a8dSllai prof_getattr(dir, name, gnewdir, &vattr, &avp, NULL); 222facf4a8dSllai 223facf4a8dSllai /* create dev directory vnode */ 224facf4a8dSllai rw_enter(&dir->sdev_contents, RW_WRITER); 225facf4a8dSllai error = prof_mknode(dir, name, &newdv, &vattr, avp, (void *)*gdirp, 226facf4a8dSllai kcred); 227facf4a8dSllai rw_exit(&dir->sdev_contents); 228facf4a8dSllai if (error == 0) { 229facf4a8dSllai ASSERT(newdv); 230facf4a8dSllai *dirp = newdv; 231facf4a8dSllai } 232facf4a8dSllai SDEV_RELE(dir); 233facf4a8dSllai return (error); 234facf4a8dSllai } 235facf4a8dSllai 236facf4a8dSllai /* 237facf4a8dSllai * Look up a logical name in the global zone. 238facf4a8dSllai * Provides the ability to map the global zone's device name 239facf4a8dSllai * to an alternate name within a zone. The primary example 240facf4a8dSllai * is the virtual console device /dev/zcons/[zonename]/zconsole 241facf4a8dSllai * mapped to /[zonename]/root/dev/zconsole. 242facf4a8dSllai */ 243facf4a8dSllai static void 244facf4a8dSllai prof_lookup_globaldev(struct sdev_node *dir, struct sdev_node *gdir, 245facf4a8dSllai char *name, char *rename) 246facf4a8dSllai { 247facf4a8dSllai /* global OS rootdir */ 248facf4a8dSllai extern vnode_t *rootdir; 249facf4a8dSllai 250facf4a8dSllai int error; 251facf4a8dSllai struct vnode *avp, *gdv, *gddv; 252facf4a8dSllai struct sdev_node *newdv; 253facf4a8dSllai struct vattr vattr = {0}; 254facf4a8dSllai struct pathname pn; 255facf4a8dSllai 256facf4a8dSllai /* check if node already exists */ 257facf4a8dSllai newdv = sdev_cache_lookup(dir, rename); 258facf4a8dSllai if (newdv) { 259facf4a8dSllai ASSERT(newdv->sdev_state != SDEV_ZOMBIE); 260facf4a8dSllai SDEV_SIMPLE_RELE(newdv); 261facf4a8dSllai return; 262facf4a8dSllai } 263facf4a8dSllai 264facf4a8dSllai /* sanity check arguments */ 265facf4a8dSllai if (!gdir || pn_get(name, UIO_SYSSPACE, &pn)) 266facf4a8dSllai return; 267facf4a8dSllai 268facf4a8dSllai /* perform a relative lookup of the global /dev instance */ 269facf4a8dSllai gddv = SDEVTOV(gdir); 270facf4a8dSllai VN_HOLD(gddv); 271facf4a8dSllai VN_HOLD(rootdir); 272facf4a8dSllai error = lookuppnvp(&pn, NULL, FOLLOW, NULLVPP, &gdv, 273facf4a8dSllai rootdir, gddv, kcred); 274facf4a8dSllai pn_free(&pn); 275facf4a8dSllai if (error) { 276facf4a8dSllai sdcmn_err10(("prof_lookup_globaldev: %s not found\n", name)); 277facf4a8dSllai return; 278facf4a8dSllai } 279facf4a8dSllai ASSERT(gdv && gdv->v_type != VLNK); 280facf4a8dSllai 281facf4a8dSllai /* 282facf4a8dSllai * Found the entry in global /dev, figure out attributes 283facf4a8dSllai * by looking at backing store. Call into devfs for default. 284*a83b1f2cSllai * Note, mapped device is persisted under the new name 285facf4a8dSllai */ 286*a83b1f2cSllai prof_getattr(dir, rename, gdv, &vattr, &avp, NULL); 287facf4a8dSllai 288facf4a8dSllai if (gdv->v_type != VDIR) { 289facf4a8dSllai VN_RELE(gdv); 290facf4a8dSllai gdir = NULL; 291facf4a8dSllai } else 292facf4a8dSllai gdir = VTOSDEV(gdv); 293facf4a8dSllai 294facf4a8dSllai if (prof_mknode(dir, rename, &newdv, &vattr, avp, 295facf4a8dSllai (void *)gdir, kcred) == 0) { 296facf4a8dSllai ASSERT(newdv->sdev_state != SDEV_ZOMBIE); 297facf4a8dSllai SDEV_SIMPLE_RELE(newdv); 298facf4a8dSllai } 299facf4a8dSllai } 300facf4a8dSllai 301facf4a8dSllai static void 302facf4a8dSllai prof_make_sym(struct sdev_node *dir, char *lnm, char *tgt) 303facf4a8dSllai { 304facf4a8dSllai struct sdev_node *newdv; 305facf4a8dSllai 306facf4a8dSllai if (prof_mknode(dir, lnm, &newdv, &sdev_vattr_lnk, NULL, 307facf4a8dSllai (void *)tgt, kcred) == 0) { 308facf4a8dSllai ASSERT(newdv->sdev_state != SDEV_ZOMBIE); 309facf4a8dSllai SDEV_SIMPLE_RELE(newdv); 310facf4a8dSllai } 311facf4a8dSllai } 312facf4a8dSllai 313facf4a8dSllai /* 314facf4a8dSllai * Create symlinks in the current directory based on profile 315facf4a8dSllai */ 316facf4a8dSllai static void 317facf4a8dSllai prof_make_symlinks(struct sdev_node *dir) 318facf4a8dSllai { 319facf4a8dSllai char *tgt, *lnm; 320facf4a8dSllai nvpair_t *nvp = NULL; 321facf4a8dSllai nvlist_t *nvl = dir->sdev_prof.dev_symlink; 322facf4a8dSllai int rv; 323facf4a8dSllai 324facf4a8dSllai ASSERT(RW_WRITE_HELD(&dir->sdev_contents)); 325facf4a8dSllai 326facf4a8dSllai if (nvl == NULL) 327facf4a8dSllai return; 328facf4a8dSllai 329facf4a8dSllai while (nvp = nvlist_next_nvpair(nvl, nvp)) { 330facf4a8dSllai lnm = nvpair_name(nvp); 331facf4a8dSllai rv = nvpair_value_string(nvp, &tgt); 332facf4a8dSllai if (rv != 0) { 333facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 334facf4a8dSllai rv, nvpair_name(nvp)); 335facf4a8dSllai break; 336facf4a8dSllai } 337facf4a8dSllai prof_make_sym(dir, lnm, tgt); 338facf4a8dSllai } 339facf4a8dSllai } 340facf4a8dSllai 341facf4a8dSllai static void 342facf4a8dSllai prof_make_maps(struct sdev_node *dir) 343facf4a8dSllai { 344facf4a8dSllai nvpair_t *nvp = NULL; 345facf4a8dSllai nvlist_t *nvl = dir->sdev_prof.dev_map; 346facf4a8dSllai int rv; 347facf4a8dSllai 348facf4a8dSllai ASSERT(RW_WRITE_HELD(&dir->sdev_contents)); 349facf4a8dSllai 350facf4a8dSllai if (nvl == NULL) 351facf4a8dSllai return; 352facf4a8dSllai 353facf4a8dSllai while (nvp = nvlist_next_nvpair(nvl, nvp)) { 354facf4a8dSllai char *name; 355facf4a8dSllai char *rename = nvpair_name(nvp); 356facf4a8dSllai rv = nvpair_value_string(nvp, &name); 357facf4a8dSllai if (rv != 0) { 358facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 359facf4a8dSllai rv, nvpair_name(nvp)); 360facf4a8dSllai break; 361facf4a8dSllai } 362facf4a8dSllai sdcmn_err10(("map %s -> %s\n", name, rename)); 363facf4a8dSllai (void) prof_lookup_globaldev(dir, sdev_origins->sdev_root, 364facf4a8dSllai name, rename); 365facf4a8dSllai } 366facf4a8dSllai } 367facf4a8dSllai 368facf4a8dSllai struct match_arg { 369facf4a8dSllai char *expr; 370facf4a8dSllai int match; 371facf4a8dSllai }; 372facf4a8dSllai 373facf4a8dSllai static int 374facf4a8dSllai match_name(char *name, void *arg) 375facf4a8dSllai { 376facf4a8dSllai struct match_arg *margp = (struct match_arg *)arg; 377facf4a8dSllai 378facf4a8dSllai if (gmatch(name, margp->expr)) { 379facf4a8dSllai margp->match = 1; 380facf4a8dSllai return (WALK_DIR_TERMINATE); 381facf4a8dSllai } 382facf4a8dSllai return (WALK_DIR_CONTINUE); 383facf4a8dSllai } 384facf4a8dSllai 385facf4a8dSllai static int 386facf4a8dSllai is_nonempty_dir(char *name, char *pathleft, struct sdev_node *dir) 387facf4a8dSllai { 388facf4a8dSllai struct match_arg marg; 389facf4a8dSllai struct pathname pn; 390facf4a8dSllai struct vnode *gvp; 391facf4a8dSllai struct sdev_node *gdir = dir->sdev_origin; 392facf4a8dSllai 393facf4a8dSllai if (VOP_LOOKUP(SDEVTOV(gdir), name, &gvp, NULL, 0, NULL, kcred) != 0) 394facf4a8dSllai return (0); 395facf4a8dSllai 396facf4a8dSllai if (gvp->v_type != VDIR) { 397facf4a8dSllai VN_RELE(gvp); 398facf4a8dSllai return (0); 399facf4a8dSllai } 400facf4a8dSllai 401facf4a8dSllai if (pn_get(pathleft, UIO_SYSSPACE, &pn) != 0) { 402facf4a8dSllai VN_RELE(gvp); 403facf4a8dSllai return (0); 404facf4a8dSllai } 405facf4a8dSllai 406facf4a8dSllai marg.expr = kmem_alloc(MAXNAMELEN, KM_SLEEP); 407facf4a8dSllai (void) pn_getcomponent(&pn, marg.expr); 408facf4a8dSllai marg.match = 0; 409facf4a8dSllai 410facf4a8dSllai walk_dir(gvp, &marg, match_name); 411facf4a8dSllai VN_RELE(gvp); 412facf4a8dSllai kmem_free(marg.expr, MAXNAMELEN); 413facf4a8dSllai pn_free(&pn); 414facf4a8dSllai 415facf4a8dSllai return (marg.match); 416facf4a8dSllai } 417facf4a8dSllai 418facf4a8dSllai 419facf4a8dSllai /* Check if name passes matching rules */ 420facf4a8dSllai static int 421facf4a8dSllai prof_name_matched(char *name, struct sdev_node *dir) 422facf4a8dSllai { 423facf4a8dSllai int type, match = 0; 424facf4a8dSllai char *expr; 425facf4a8dSllai nvlist_t *nvl; 426facf4a8dSllai nvpair_t *nvp = NULL; 427facf4a8dSllai int rv; 428facf4a8dSllai 429facf4a8dSllai /* check against nvlist for leaf include/exclude */ 430facf4a8dSllai nvl = dir->sdev_prof.dev_name; 431facf4a8dSllai while (nvp = nvlist_next_nvpair(nvl, nvp)) { 432facf4a8dSllai expr = nvpair_name(nvp); 433facf4a8dSllai rv = nvpair_value_int32(nvp, &type); 434facf4a8dSllai if (rv != 0) { 435facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 436facf4a8dSllai rv, nvpair_name(nvp)); 437facf4a8dSllai break; 438facf4a8dSllai } 439facf4a8dSllai 440facf4a8dSllai if (type == PROFILE_TYPE_EXCLUDE) { 441facf4a8dSllai if (gmatch(name, expr)) 442facf4a8dSllai return (0); /* excluded */ 443facf4a8dSllai } else if (!match) { 444facf4a8dSllai match = gmatch(name, expr); 445facf4a8dSllai } 446facf4a8dSllai } 447facf4a8dSllai if (match) { 448facf4a8dSllai sdcmn_err10(("prof_name_matched: %s\n", name)); 449facf4a8dSllai return (match); 450facf4a8dSllai } 451facf4a8dSllai 452facf4a8dSllai /* check for match against directory globbing pattern */ 453facf4a8dSllai nvl = dir->sdev_prof.dev_glob_incdir; 454facf4a8dSllai while (nvp = nvlist_next_nvpair(nvl, nvp)) { 455facf4a8dSllai char *pathleft; 456facf4a8dSllai expr = nvpair_name(nvp); 457facf4a8dSllai if (gmatch(name, expr) == 0) 458facf4a8dSllai continue; 459facf4a8dSllai rv = nvpair_value_string(nvp, &pathleft); 460facf4a8dSllai if (rv != 0) { 461facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 462facf4a8dSllai rv, nvpair_name(nvp)); 463facf4a8dSllai break; 464facf4a8dSllai } 465facf4a8dSllai if (is_nonempty_dir(name, pathleft, dir)) { 466facf4a8dSllai sdcmn_err10(("prof_name_matched: dir %s\n", name)); 467facf4a8dSllai return (1); 468facf4a8dSllai } 469facf4a8dSllai } 470facf4a8dSllai 471facf4a8dSllai return (0); 472facf4a8dSllai } 473facf4a8dSllai 474facf4a8dSllai static void 475facf4a8dSllai walk_dir(struct vnode *dvp, void *arg, int (*callback)(char *, void *)) 476facf4a8dSllai { 477facf4a8dSllai char *nm; 478facf4a8dSllai int eof, error; 479facf4a8dSllai struct iovec iov; 480facf4a8dSllai struct uio uio; 481facf4a8dSllai struct dirent64 *dp; 482facf4a8dSllai dirent64_t *dbuf; 483facf4a8dSllai size_t dbuflen, dlen; 484facf4a8dSllai 485facf4a8dSllai ASSERT(dvp); 486facf4a8dSllai 487facf4a8dSllai dlen = 4096; 488facf4a8dSllai dbuf = kmem_zalloc(dlen, KM_SLEEP); 489facf4a8dSllai 490facf4a8dSllai uio.uio_iov = &iov; 491facf4a8dSllai uio.uio_iovcnt = 1; 492facf4a8dSllai uio.uio_segflg = UIO_SYSSPACE; 493facf4a8dSllai uio.uio_fmode = 0; 494facf4a8dSllai uio.uio_extflg = UIO_COPY_CACHED; 495facf4a8dSllai uio.uio_loffset = 0; 496facf4a8dSllai uio.uio_llimit = MAXOFFSET_T; 497facf4a8dSllai 498facf4a8dSllai eof = 0; 499facf4a8dSllai error = 0; 500facf4a8dSllai while (!error && !eof) { 501facf4a8dSllai uio.uio_resid = dlen; 502facf4a8dSllai iov.iov_base = (char *)dbuf; 503facf4a8dSllai iov.iov_len = dlen; 504facf4a8dSllai (void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL); 505facf4a8dSllai error = VOP_READDIR(dvp, &uio, kcred, &eof); 506facf4a8dSllai VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL); 507facf4a8dSllai 508facf4a8dSllai dbuflen = dlen - uio.uio_resid; 509facf4a8dSllai if (error || dbuflen == 0) 510facf4a8dSllai break; 511facf4a8dSllai for (dp = dbuf; ((intptr_t)dp < 512facf4a8dSllai (intptr_t)dbuf + dbuflen); 513facf4a8dSllai dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) { 514facf4a8dSllai nm = dp->d_name; 515facf4a8dSllai 516facf4a8dSllai if (strcmp(nm, ".") == 0 || 517facf4a8dSllai strcmp(nm, "..") == 0) 518facf4a8dSllai continue; 519facf4a8dSllai 520facf4a8dSllai if (callback(nm, arg) == WALK_DIR_TERMINATE) 521facf4a8dSllai goto end; 522facf4a8dSllai } 523facf4a8dSllai } 524facf4a8dSllai 525facf4a8dSllai end: 526facf4a8dSllai kmem_free(dbuf, dlen); 527facf4a8dSllai } 528facf4a8dSllai 529facf4a8dSllai static int 530facf4a8dSllai prof_make_name(char *nm, void *arg) 531facf4a8dSllai { 532facf4a8dSllai struct sdev_node *ddv = (struct sdev_node *)arg; 533facf4a8dSllai 534facf4a8dSllai if (prof_name_matched(nm, ddv)) 535facf4a8dSllai prof_lookup_globaldev(ddv, ddv->sdev_origin, nm, nm); 536facf4a8dSllai return (WALK_DIR_CONTINUE); 537facf4a8dSllai } 538facf4a8dSllai 539facf4a8dSllai static void 540facf4a8dSllai prof_make_names_glob(struct sdev_node *ddv) 541facf4a8dSllai { 542facf4a8dSllai struct sdev_node *gdir; 543facf4a8dSllai 544facf4a8dSllai gdir = ddv->sdev_origin; 545facf4a8dSllai if (gdir == NULL) 546facf4a8dSllai return; 547facf4a8dSllai walk_dir(SDEVTOV(gdir), (void *)ddv, prof_make_name); 548facf4a8dSllai } 549facf4a8dSllai 550facf4a8dSllai static void 551facf4a8dSllai prof_make_names(struct sdev_node *dir) 552facf4a8dSllai { 553facf4a8dSllai char *name; 554facf4a8dSllai nvpair_t *nvp = NULL; 555facf4a8dSllai nvlist_t *nvl = dir->sdev_prof.dev_name; 556facf4a8dSllai int rv; 557facf4a8dSllai 558facf4a8dSllai ASSERT(RW_WRITE_HELD(&dir->sdev_contents)); 559facf4a8dSllai 560facf4a8dSllai if (nvl == NULL) 561facf4a8dSllai return; 562facf4a8dSllai 563facf4a8dSllai if (dir->sdev_prof.has_glob) { 564facf4a8dSllai prof_make_names_glob(dir); 565facf4a8dSllai return; 566facf4a8dSllai } 567facf4a8dSllai 568facf4a8dSllai /* Walk nvlist and lookup corresponding device in global inst */ 569facf4a8dSllai while (nvp = nvlist_next_nvpair(nvl, nvp)) { 570facf4a8dSllai int type; 571facf4a8dSllai rv = nvpair_value_int32(nvp, &type); 572facf4a8dSllai if (rv != 0) { 573facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 574facf4a8dSllai rv, nvpair_name(nvp)); 575facf4a8dSllai break; 576facf4a8dSllai } 577facf4a8dSllai if (type == PROFILE_TYPE_EXCLUDE) 578facf4a8dSllai continue; 579facf4a8dSllai name = nvpair_name(nvp); 580facf4a8dSllai (void) prof_lookup_globaldev(dir, dir->sdev_origin, 581facf4a8dSllai name, name); 582facf4a8dSllai } 583facf4a8dSllai } 584facf4a8dSllai 585facf4a8dSllai /* 586facf4a8dSllai * Build directory vnodes based on the profile and the global 587facf4a8dSllai * dev instance. 588facf4a8dSllai */ 589facf4a8dSllai void 590facf4a8dSllai prof_filldir(struct sdev_node *ddv) 591facf4a8dSllai { 592facf4a8dSllai int firsttime = 1; 593facf4a8dSllai struct sdev_node *gdir = ddv->sdev_origin; 594facf4a8dSllai 595facf4a8dSllai ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 596facf4a8dSllai 597facf4a8dSllai /* 598facf4a8dSllai * We need to rebuild the directory content if 599facf4a8dSllai * - SDEV_BUILD is set 600facf4a8dSllai * - The device tree generation number has changed 601facf4a8dSllai * - The corresponding /dev namespace has been updated 602facf4a8dSllai */ 603facf4a8dSllai check_build: 604facf4a8dSllai if ((ddv->sdev_flags & SDEV_BUILD) == 0 && 605facf4a8dSllai ddv->sdev_devtree_gen == devtree_gen && 606facf4a8dSllai (gdir == NULL || ddv->sdev_ldir_gen 607facf4a8dSllai == gdir->sdev_gdir_gen)) 608facf4a8dSllai return; /* already up to date */ 609facf4a8dSllai 610facf4a8dSllai if (firsttime && rw_tryupgrade(&ddv->sdev_contents) == 0) { 611facf4a8dSllai rw_exit(&ddv->sdev_contents); 612facf4a8dSllai firsttime = 0; 613facf4a8dSllai rw_enter(&ddv->sdev_contents, RW_WRITER); 614facf4a8dSllai goto check_build; 615facf4a8dSllai } 616facf4a8dSllai sdcmn_err10(("devtree_gen (%s): %ld -> %ld\n", 617facf4a8dSllai ddv->sdev_path, ddv->sdev_devtree_gen, devtree_gen)); 618facf4a8dSllai if (gdir) 619facf4a8dSllai sdcmn_err10(("sdev_dir_gen (%s): %ld -> %ld\n", 620facf4a8dSllai ddv->sdev_path, ddv->sdev_ldir_gen, 621facf4a8dSllai gdir->sdev_gdir_gen)); 622facf4a8dSllai 623facf4a8dSllai /* update flags and generation number so next filldir is quick */ 624facf4a8dSllai ddv->sdev_flags &= ~SDEV_BUILD; 625facf4a8dSllai ddv->sdev_devtree_gen = devtree_gen; 626facf4a8dSllai if (gdir) 627facf4a8dSllai ddv->sdev_ldir_gen = gdir->sdev_gdir_gen; 628facf4a8dSllai 629facf4a8dSllai prof_make_symlinks(ddv); 630facf4a8dSllai prof_make_maps(ddv); 631facf4a8dSllai prof_make_names(ddv); 632facf4a8dSllai rw_downgrade(&ddv->sdev_contents); 633facf4a8dSllai } 634facf4a8dSllai 635facf4a8dSllai /* apply include/exclude pattern to existing directory content */ 636facf4a8dSllai static void 637facf4a8dSllai apply_dir_pattern(struct sdev_node *dir, char *expr, char *pathleft, int type) 638facf4a8dSllai { 639facf4a8dSllai struct sdev_node *dv; 640facf4a8dSllai 641facf4a8dSllai /* leaf pattern */ 642facf4a8dSllai if (pathleft == NULL) { 643facf4a8dSllai if (type == PROFILE_TYPE_INCLUDE) 644facf4a8dSllai return; /* nothing to do for include */ 645facf4a8dSllai (void) sdev_cleandir(dir, expr, SDEV_ENFORCE); 646facf4a8dSllai return; 647facf4a8dSllai } 648facf4a8dSllai 649facf4a8dSllai /* directory pattern */ 650facf4a8dSllai rw_enter(&dir->sdev_contents, RW_WRITER); 651facf4a8dSllai for (dv = dir->sdev_dot; dv; dv = dv->sdev_next) { 652facf4a8dSllai if (gmatch(dv->sdev_name, expr) == 0 || 653facf4a8dSllai SDEVTOV(dv)->v_type != VDIR) 654facf4a8dSllai continue; 655facf4a8dSllai process_rule(dv, dv->sdev_origin, 656facf4a8dSllai pathleft, NULL, type); 657facf4a8dSllai } 658facf4a8dSllai rw_exit(&dir->sdev_contents); 659facf4a8dSllai } 660facf4a8dSllai 661facf4a8dSllai /* 662facf4a8dSllai * Add a profile rule. 663facf4a8dSllai * tgt represents a device name matching expression, 664facf4a8dSllai * matching device names are to be either included or excluded. 665facf4a8dSllai */ 666facf4a8dSllai static void 667facf4a8dSllai prof_add_rule(char *name, char *tgt, struct sdev_node *dir, int type) 668facf4a8dSllai { 669facf4a8dSllai int error; 670facf4a8dSllai nvlist_t **nvlp = NULL; 671facf4a8dSllai int rv; 672facf4a8dSllai 673facf4a8dSllai ASSERT(SDEVTOV(dir)->v_type == VDIR); 674facf4a8dSllai 675facf4a8dSllai rw_enter(&dir->sdev_contents, RW_WRITER); 676facf4a8dSllai 677facf4a8dSllai switch (type) { 678facf4a8dSllai case PROFILE_TYPE_INCLUDE: 679facf4a8dSllai if (tgt) 680facf4a8dSllai nvlp = &(dir->sdev_prof.dev_glob_incdir); 681facf4a8dSllai else 682facf4a8dSllai nvlp = &(dir->sdev_prof.dev_name); 683facf4a8dSllai break; 684facf4a8dSllai case PROFILE_TYPE_EXCLUDE: 685facf4a8dSllai if (tgt) 686facf4a8dSllai nvlp = &(dir->sdev_prof.dev_glob_excdir); 687facf4a8dSllai else 688facf4a8dSllai nvlp = &(dir->sdev_prof.dev_name); 689facf4a8dSllai break; 690facf4a8dSllai case PROFILE_TYPE_MAP: 691facf4a8dSllai nvlp = &(dir->sdev_prof.dev_map); 692facf4a8dSllai break; 693facf4a8dSllai case PROFILE_TYPE_SYMLINK: 694facf4a8dSllai nvlp = &(dir->sdev_prof.dev_symlink); 695facf4a8dSllai break; 696facf4a8dSllai }; 697facf4a8dSllai 698facf4a8dSllai /* initialize nvlist */ 699facf4a8dSllai if (*nvlp == NULL) { 700facf4a8dSllai error = nvlist_alloc(nvlp, NV_UNIQUE_NAME, KM_SLEEP); 701facf4a8dSllai ASSERT(error == 0); 702facf4a8dSllai } 703facf4a8dSllai 704facf4a8dSllai if (tgt) { 705facf4a8dSllai rv = nvlist_add_string(*nvlp, name, tgt); 706facf4a8dSllai } else { 707facf4a8dSllai rv = nvlist_add_int32(*nvlp, name, type); 708facf4a8dSllai } 709facf4a8dSllai ASSERT(rv == 0); 710facf4a8dSllai /* rebuild directory content */ 711facf4a8dSllai dir->sdev_flags |= SDEV_BUILD; 712facf4a8dSllai 713facf4a8dSllai if ((type == PROFILE_TYPE_INCLUDE) && 714facf4a8dSllai (strpbrk(name, "*?[]") != NULL)) { 715facf4a8dSllai dir->sdev_prof.has_glob = 1; 716facf4a8dSllai } 717facf4a8dSllai 718facf4a8dSllai rw_exit(&dir->sdev_contents); 719facf4a8dSllai 720facf4a8dSllai /* additional details for glob pattern and exclusion */ 721facf4a8dSllai switch (type) { 722facf4a8dSllai case PROFILE_TYPE_INCLUDE: 723facf4a8dSllai case PROFILE_TYPE_EXCLUDE: 724facf4a8dSllai apply_dir_pattern(dir, name, tgt, type); 725facf4a8dSllai break; 726facf4a8dSllai }; 727facf4a8dSllai } 728facf4a8dSllai 729facf4a8dSllai /* 730facf4a8dSllai * Parse path components and apply requested matching rule at 731facf4a8dSllai * directory level. 732facf4a8dSllai */ 733facf4a8dSllai static void 734facf4a8dSllai process_rule(struct sdev_node *dir, struct sdev_node *gdir, 735facf4a8dSllai char *path, char *tgt, int type) 736facf4a8dSllai { 737facf4a8dSllai char *name; 738facf4a8dSllai struct pathname pn; 739facf4a8dSllai int rv = 0; 740facf4a8dSllai 741facf4a8dSllai if ((strlen(path) > 5) && (strncmp(path, "/dev/", 5) == 0)) { 742facf4a8dSllai path += 5; 743facf4a8dSllai } 744facf4a8dSllai 745facf4a8dSllai if (pn_get(path, UIO_SYSSPACE, &pn) != 0) 746facf4a8dSllai return; 747facf4a8dSllai 748facf4a8dSllai name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 749facf4a8dSllai (void) pn_getcomponent(&pn, name); 750facf4a8dSllai pn_skipslash(&pn); 751facf4a8dSllai SDEV_HOLD(dir); 752facf4a8dSllai 753facf4a8dSllai while (pn_pathleft(&pn)) { 754facf4a8dSllai /* If this is pattern, just add the pattern */ 755facf4a8dSllai if (strpbrk(name, "*?[]") != NULL && 756facf4a8dSllai (type == PROFILE_TYPE_INCLUDE || 757facf4a8dSllai type == PROFILE_TYPE_EXCLUDE)) { 758facf4a8dSllai ASSERT(tgt == NULL); 759facf4a8dSllai tgt = pn.pn_path; 760facf4a8dSllai break; 761facf4a8dSllai } 762facf4a8dSllai if ((rv = prof_make_dir(name, &gdir, &dir)) != 0) { 763facf4a8dSllai cmn_err(CE_CONT, "process_rule: %s error %d\n", 764facf4a8dSllai path, rv); 765facf4a8dSllai break; 766facf4a8dSllai } 767facf4a8dSllai (void) pn_getcomponent(&pn, name); 768facf4a8dSllai pn_skipslash(&pn); 769facf4a8dSllai } 770facf4a8dSllai 771facf4a8dSllai /* process the leaf component */ 772facf4a8dSllai if (rv == 0) { 773facf4a8dSllai prof_add_rule(name, tgt, dir, type); 774facf4a8dSllai SDEV_SIMPLE_RELE(dir); 775facf4a8dSllai } 776facf4a8dSllai 777facf4a8dSllai kmem_free(name, MAXPATHLEN); 778facf4a8dSllai pn_free(&pn); 779facf4a8dSllai } 780facf4a8dSllai 781facf4a8dSllai static int 782facf4a8dSllai copyin_nvlist(char *packed_usr, size_t packed_sz, nvlist_t **nvlp) 783facf4a8dSllai { 784facf4a8dSllai int err = 0; 785facf4a8dSllai char *packed; 786facf4a8dSllai nvlist_t *profile = NULL; 787facf4a8dSllai 788facf4a8dSllai /* simple sanity check */ 789facf4a8dSllai if (packed_usr == NULL || packed_sz == 0) 790facf4a8dSllai return (NULL); 791facf4a8dSllai 792facf4a8dSllai /* copyin packed profile nvlist */ 793facf4a8dSllai packed = kmem_alloc(packed_sz, KM_NOSLEEP); 794facf4a8dSllai if (packed == NULL) 795facf4a8dSllai return (ENOMEM); 796facf4a8dSllai err = copyin(packed_usr, packed, packed_sz); 797facf4a8dSllai 798facf4a8dSllai /* unpack packed profile nvlist */ 799facf4a8dSllai if (err) 800facf4a8dSllai cmn_err(CE_WARN, "copyin_nvlist: copyin failed with " 801facf4a8dSllai "err %d\n", err); 802facf4a8dSllai else if (err = nvlist_unpack(packed, packed_sz, &profile, KM_NOSLEEP)) 803facf4a8dSllai cmn_err(CE_WARN, "copyin_nvlist: nvlist_unpack " 804facf4a8dSllai "failed with err %d\n", err); 805facf4a8dSllai 806facf4a8dSllai kmem_free(packed, packed_sz); 807facf4a8dSllai if (err == 0) 808facf4a8dSllai *nvlp = profile; 809facf4a8dSllai return (err); 810facf4a8dSllai } 811facf4a8dSllai 812facf4a8dSllai /* 813facf4a8dSllai * Process profile passed down from libdevinfo. There are four types 814facf4a8dSllai * of matching rules: 815facf4a8dSllai * include: export a name or names matching a pattern 816facf4a8dSllai * exclude: exclude a name or names matching a pattern 817facf4a8dSllai * symlink: create a local symlink 818facf4a8dSllai * map: export a device with a name different from the global zone 819facf4a8dSllai * Note: We may consider supporting VOP_SYMLINK in non-global instances, 820facf4a8dSllai * because it does not present any security risk. For now, the fs 821facf4a8dSllai * instance is read only. 822facf4a8dSllai */ 823facf4a8dSllai static void 824facf4a8dSllai sdev_process_profile(struct sdev_data *sdev_data, nvlist_t *profile) 825facf4a8dSllai { 826facf4a8dSllai nvpair_t *nvpair; 827facf4a8dSllai char *nvname, *dname; 828facf4a8dSllai struct sdev_node *dir, *gdir; 829facf4a8dSllai char **pair; /* for symlinks and maps */ 830facf4a8dSllai uint_t nelem; 831facf4a8dSllai int rv; 832facf4a8dSllai 833facf4a8dSllai gdir = sdev_origins->sdev_root; /* root of global /dev */ 834facf4a8dSllai dir = sdev_data->sdev_root; /* root of current instance */ 835facf4a8dSllai 836facf4a8dSllai ASSERT(profile); 837facf4a8dSllai 838facf4a8dSllai /* process nvpairs in the list */ 839facf4a8dSllai nvpair = NULL; 840facf4a8dSllai while (nvpair = nvlist_next_nvpair(profile, nvpair)) { 841facf4a8dSllai nvname = nvpair_name(nvpair); 842facf4a8dSllai ASSERT(nvname != NULL); 843facf4a8dSllai 844facf4a8dSllai if (strcmp(nvname, SDEV_NVNAME_INCLUDE) == 0) { 845facf4a8dSllai rv = nvpair_value_string(nvpair, &dname); 846facf4a8dSllai if (rv != 0) { 847facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 848facf4a8dSllai rv, nvpair_name(nvpair)); 849facf4a8dSllai break; 850facf4a8dSllai } 851facf4a8dSllai process_rule(dir, gdir, dname, NULL, 852facf4a8dSllai PROFILE_TYPE_INCLUDE); 853facf4a8dSllai } else if (strcmp(nvname, SDEV_NVNAME_EXCLUDE) == 0) { 854facf4a8dSllai rv = nvpair_value_string(nvpair, &dname); 855facf4a8dSllai if (rv != 0) { 856facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 857facf4a8dSllai rv, nvpair_name(nvpair)); 858facf4a8dSllai break; 859facf4a8dSllai } 860facf4a8dSllai process_rule(dir, gdir, dname, NULL, 861facf4a8dSllai PROFILE_TYPE_EXCLUDE); 862facf4a8dSllai } else if (strcmp(nvname, SDEV_NVNAME_SYMLINK) == 0) { 863facf4a8dSllai rv = nvpair_value_string_array(nvpair, &pair, &nelem); 864facf4a8dSllai if (rv != 0) { 865facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 866facf4a8dSllai rv, nvpair_name(nvpair)); 867facf4a8dSllai break; 868facf4a8dSllai } 869facf4a8dSllai ASSERT(nelem == 2); 870facf4a8dSllai process_rule(dir, gdir, pair[0], pair[1], 871facf4a8dSllai PROFILE_TYPE_SYMLINK); 872facf4a8dSllai } else if (strcmp(nvname, SDEV_NVNAME_MAP) == 0) { 873facf4a8dSllai rv = nvpair_value_string_array(nvpair, &pair, &nelem); 874facf4a8dSllai if (rv != 0) { 875facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 876facf4a8dSllai rv, nvpair_name(nvpair)); 877facf4a8dSllai break; 878facf4a8dSllai } 879facf4a8dSllai process_rule(dir, gdir, pair[1], pair[0], 880facf4a8dSllai PROFILE_TYPE_MAP); 881facf4a8dSllai } else if (strcmp(nvname, SDEV_NVNAME_MOUNTPT) != 0) { 882facf4a8dSllai cmn_err(CE_WARN, "sdev_process_profile: invalid " 883facf4a8dSllai "nvpair %s\n", nvname); 884facf4a8dSllai } 885facf4a8dSllai } 886facf4a8dSllai } 887facf4a8dSllai 888facf4a8dSllai /*ARGSUSED*/ 889facf4a8dSllai int 890facf4a8dSllai prof_lookup(vnode_t *dvp, char *nm, struct vnode **vpp, struct cred *cred) 891facf4a8dSllai { 892facf4a8dSllai struct sdev_node *ddv = VTOSDEV(dvp); 893facf4a8dSllai struct sdev_node *dv; 894facf4a8dSllai int nmlen; 895facf4a8dSllai 896facf4a8dSllai /* 897facf4a8dSllai * Empty name or ., return node itself. 898facf4a8dSllai */ 899facf4a8dSllai nmlen = strlen(nm); 900facf4a8dSllai if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) { 901facf4a8dSllai *vpp = SDEVTOV(ddv); 902facf4a8dSllai VN_HOLD(*vpp); 903facf4a8dSllai return (0); 904facf4a8dSllai } 905facf4a8dSllai 906facf4a8dSllai /* 907facf4a8dSllai * .., return the parent directory 908facf4a8dSllai */ 909facf4a8dSllai if ((nmlen == 2) && (strcmp(nm, "..") == 0)) { 910facf4a8dSllai *vpp = SDEVTOV(ddv->sdev_dotdot); 911facf4a8dSllai VN_HOLD(*vpp); 912facf4a8dSllai return (0); 913facf4a8dSllai } 914facf4a8dSllai 915facf4a8dSllai rw_enter(&ddv->sdev_contents, RW_READER); 916facf4a8dSllai dv = sdev_cache_lookup(ddv, nm); 917facf4a8dSllai if (dv == NULL) { 918facf4a8dSllai prof_filldir(ddv); 919facf4a8dSllai dv = sdev_cache_lookup(ddv, nm); 920facf4a8dSllai } 921facf4a8dSllai rw_exit(&ddv->sdev_contents); 922facf4a8dSllai if (dv == NULL) { 923facf4a8dSllai sdcmn_err10(("prof_lookup: %s not found\n", nm)); 924facf4a8dSllai return (ENOENT); 925facf4a8dSllai } 926facf4a8dSllai 927facf4a8dSllai return (sdev_to_vp(dv, vpp)); 928facf4a8dSllai } 929facf4a8dSllai 930facf4a8dSllai /* 931facf4a8dSllai * This is invoked after a new filesystem is mounted to define the 932facf4a8dSllai * name space. It is also invoked during normal system operation 933facf4a8dSllai * to update the name space. 934facf4a8dSllai * 935facf4a8dSllai * Applications call di_prof_commit() in libdevinfo, which invokes 936facf4a8dSllai * modctl(). modctl calls this function. The input is a packed nvlist. 937facf4a8dSllai */ 938facf4a8dSllai int 939facf4a8dSllai devname_profile_update(char *packed, size_t packed_sz) 940facf4a8dSllai { 941facf4a8dSllai char *mntpt; 942facf4a8dSllai nvlist_t *nvl; 943facf4a8dSllai nvpair_t *nvp; 944facf4a8dSllai struct sdev_data *mntinfo; 945facf4a8dSllai int err; 946facf4a8dSllai int rv; 947facf4a8dSllai 948facf4a8dSllai nvl = NULL; 949facf4a8dSllai if ((err = copyin_nvlist(packed, packed_sz, &nvl)) != 0) 950facf4a8dSllai return (err); 951facf4a8dSllai ASSERT(nvl); 952facf4a8dSllai 953facf4a8dSllai /* The first nvpair must be the mount point */ 954facf4a8dSllai nvp = nvlist_next_nvpair(nvl, NULL); 955facf4a8dSllai if (strcmp(nvpair_name(nvp), SDEV_NVNAME_MOUNTPT) != 0) { 956facf4a8dSllai cmn_err(CE_NOTE, 957facf4a8dSllai "devname_profile_update: mount point not specified"); 958facf4a8dSllai nvlist_free(nvl); 959facf4a8dSllai return (EINVAL); 960facf4a8dSllai } 961facf4a8dSllai 962facf4a8dSllai /* find the matching filesystem instance */ 963facf4a8dSllai rv = nvpair_value_string(nvp, &mntpt); 964facf4a8dSllai if (rv != 0) { 965facf4a8dSllai cmn_err(CE_WARN, sdev_nvp_val_err, 966facf4a8dSllai rv, nvpair_name(nvp)); 967facf4a8dSllai } else { 968facf4a8dSllai mntinfo = sdev_find_mntinfo(mntpt); 969facf4a8dSllai if (mntinfo == NULL) { 970facf4a8dSllai cmn_err(CE_NOTE, "devname_profile_update: " 971facf4a8dSllai " mount point %s not found", mntpt); 972facf4a8dSllai nvlist_free(nvl); 973facf4a8dSllai return (EINVAL); 974facf4a8dSllai } 975facf4a8dSllai 976facf4a8dSllai /* now do the hardwork to process the profile */ 977facf4a8dSllai sdev_process_profile(mntinfo, nvl); 978facf4a8dSllai 979facf4a8dSllai sdev_mntinfo_rele(mntinfo); 980facf4a8dSllai } 981facf4a8dSllai 982facf4a8dSllai nvlist_free(nvl); 983facf4a8dSllai return (0); 984facf4a8dSllai } 985