1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * utility routines for the /dev fs 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/t_lock.h> 35 #include <sys/systm.h> 36 #include <sys/sysmacros.h> 37 #include <sys/user.h> 38 #include <sys/time.h> 39 #include <sys/vfs.h> 40 #include <sys/vnode.h> 41 #include <sys/file.h> 42 #include <sys/fcntl.h> 43 #include <sys/flock.h> 44 #include <sys/kmem.h> 45 #include <sys/uio.h> 46 #include <sys/errno.h> 47 #include <sys/stat.h> 48 #include <sys/cred.h> 49 #include <sys/dirent.h> 50 #include <sys/pathname.h> 51 #include <sys/cmn_err.h> 52 #include <sys/debug.h> 53 #include <sys/mode.h> 54 #include <sys/policy.h> 55 #include <fs/fs_subr.h> 56 #include <sys/mount.h> 57 #include <sys/fs/snode.h> 58 #include <sys/fs/dv_node.h> 59 #include <sys/fs/sdev_impl.h> 60 #include <sys/fs/sdev_node.h> 61 #include <sys/sunndi.h> 62 #include <sys/sunmdi.h> 63 #include <sys/conf.h> 64 #include <sys/proc.h> 65 #include <sys/user.h> 66 #include <sys/modctl.h> 67 68 #ifdef DEBUG 69 int sdev_debug = 0x00000001; 70 int sdev_debug_cache_flags = 0; 71 #endif 72 73 /* 74 * globals 75 */ 76 /* prototype memory vattrs */ 77 vattr_t sdev_vattr_dir = { 78 AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 79 VDIR, /* va_type */ 80 SDEV_DIRMODE_DEFAULT, /* va_mode */ 81 SDEV_UID_DEFAULT, /* va_uid */ 82 SDEV_GID_DEFAULT, /* va_gid */ 83 0, /* va_fsid */ 84 0, /* va_nodeid */ 85 0, /* va_nlink */ 86 0, /* va_size */ 87 0, /* va_atime */ 88 0, /* va_mtime */ 89 0, /* va_ctime */ 90 0, /* va_rdev */ 91 0, /* va_blksize */ 92 0, /* va_nblocks */ 93 0 /* va_vcode */ 94 }; 95 96 vattr_t sdev_vattr_lnk = { 97 AT_TYPE|AT_MODE, /* va_mask */ 98 VLNK, /* va_type */ 99 SDEV_LNKMODE_DEFAULT, /* va_mode */ 100 SDEV_UID_DEFAULT, /* va_uid */ 101 SDEV_GID_DEFAULT, /* va_gid */ 102 0, /* va_fsid */ 103 0, /* va_nodeid */ 104 0, /* va_nlink */ 105 0, /* va_size */ 106 0, /* va_atime */ 107 0, /* va_mtime */ 108 0, /* va_ctime */ 109 0, /* va_rdev */ 110 0, /* va_blksize */ 111 0, /* va_nblocks */ 112 0 /* va_vcode */ 113 }; 114 115 vattr_t sdev_vattr_blk = { 116 AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 117 VBLK, /* va_type */ 118 S_IFBLK | SDEV_DEVMODE_DEFAULT, /* va_mode */ 119 SDEV_UID_DEFAULT, /* va_uid */ 120 SDEV_GID_DEFAULT, /* va_gid */ 121 0, /* va_fsid */ 122 0, /* va_nodeid */ 123 0, /* va_nlink */ 124 0, /* va_size */ 125 0, /* va_atime */ 126 0, /* va_mtime */ 127 0, /* va_ctime */ 128 0, /* va_rdev */ 129 0, /* va_blksize */ 130 0, /* va_nblocks */ 131 0 /* va_vcode */ 132 }; 133 134 vattr_t sdev_vattr_chr = { 135 AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 136 VCHR, /* va_type */ 137 S_IFCHR | SDEV_DEVMODE_DEFAULT, /* va_mode */ 138 SDEV_UID_DEFAULT, /* va_uid */ 139 SDEV_GID_DEFAULT, /* va_gid */ 140 0, /* va_fsid */ 141 0, /* va_nodeid */ 142 0, /* va_nlink */ 143 0, /* va_size */ 144 0, /* va_atime */ 145 0, /* va_mtime */ 146 0, /* va_ctime */ 147 0, /* va_rdev */ 148 0, /* va_blksize */ 149 0, /* va_nblocks */ 150 0 /* va_vcode */ 151 }; 152 153 kmem_cache_t *sdev_node_cache; /* sdev_node cache */ 154 int devtype; /* fstype */ 155 156 struct devname_ops *devname_ns_ops; /* default name service directory ops */ 157 kmutex_t devname_nsmaps_lock; /* protect devname_nsmaps */ 158 159 /* static */ 160 static struct devname_nsmap *devname_nsmaps = NULL; 161 /* contents from /etc/dev/devname_master */ 162 static int devname_nsmaps_invalidated = 0; /* "devfsadm -m" has run */ 163 164 static struct vnodeops *sdev_get_vop(struct sdev_node *); 165 static void sdev_set_no_nocache(struct sdev_node *); 166 static int sdev_get_moduleops(struct sdev_node *); 167 static fs_operation_def_t *sdev_merge_vtab(const fs_operation_def_t []); 168 static void sdev_free_vtab(fs_operation_def_t *); 169 170 static void 171 sdev_prof_free(struct sdev_node *dv) 172 { 173 ASSERT(!SDEV_IS_GLOBAL(dv)); 174 if (dv->sdev_prof.dev_name) 175 nvlist_free(dv->sdev_prof.dev_name); 176 if (dv->sdev_prof.dev_map) 177 nvlist_free(dv->sdev_prof.dev_map); 178 if (dv->sdev_prof.dev_symlink) 179 nvlist_free(dv->sdev_prof.dev_symlink); 180 if (dv->sdev_prof.dev_glob_incdir) 181 nvlist_free(dv->sdev_prof.dev_glob_incdir); 182 if (dv->sdev_prof.dev_glob_excdir) 183 nvlist_free(dv->sdev_prof.dev_glob_excdir); 184 bzero(&dv->sdev_prof, sizeof (dv->sdev_prof)); 185 } 186 187 /* 188 * sdev_node cache constructor 189 */ 190 /*ARGSUSED1*/ 191 static int 192 i_sdev_node_ctor(void *buf, void *cfarg, int flag) 193 { 194 struct sdev_node *dv = (struct sdev_node *)buf; 195 struct vnode *vp; 196 197 ASSERT(flag == KM_SLEEP); 198 199 bzero(buf, sizeof (struct sdev_node)); 200 rw_init(&dv->sdev_contents, NULL, RW_DEFAULT, NULL); 201 dv->sdev_vnode = vn_alloc(KM_SLEEP); 202 vp = SDEVTOV(dv); 203 vp->v_data = (caddr_t)dv; 204 return (0); 205 } 206 207 /* sdev_node destructor for kmem cache */ 208 /*ARGSUSED1*/ 209 static void 210 i_sdev_node_dtor(void *buf, void *arg) 211 { 212 struct sdev_node *dv = (struct sdev_node *)buf; 213 struct vnode *vp = SDEVTOV(dv); 214 215 rw_destroy(&dv->sdev_contents); 216 vn_free(vp); 217 } 218 219 /* initialize sdev_node cache */ 220 void 221 sdev_node_cache_init() 222 { 223 int flags = 0; 224 225 #ifdef DEBUG 226 flags = sdev_debug_cache_flags; 227 if (flags) 228 sdcmn_err(("cache debug flags 0x%x\n", flags)); 229 #endif /* DEBUG */ 230 231 ASSERT(sdev_node_cache == NULL); 232 sdev_node_cache = kmem_cache_create("sdev_node_cache", 233 sizeof (struct sdev_node), 0, i_sdev_node_ctor, i_sdev_node_dtor, 234 NULL, NULL, NULL, flags); 235 } 236 237 /* destroy sdev_node cache */ 238 void 239 sdev_node_cache_fini() 240 { 241 ASSERT(sdev_node_cache != NULL); 242 kmem_cache_destroy(sdev_node_cache); 243 sdev_node_cache = NULL; 244 } 245 246 /* 247 * Compare two nodes lexographically to balance avl tree 248 */ 249 static int 250 sdev_compare_nodes(const struct sdev_node *dv1, const struct sdev_node *dv2) 251 { 252 int rv; 253 if ((rv = strcmp(dv1->sdev_name, dv2->sdev_name)) == 0) 254 return (0); 255 return ((rv < 0) ? -1 : 1); 256 } 257 258 void 259 sdev_set_nodestate(struct sdev_node *dv, sdev_node_state_t state) 260 { 261 ASSERT(dv); 262 ASSERT(RW_WRITE_HELD(&dv->sdev_contents)); 263 dv->sdev_state = state; 264 } 265 266 static void 267 sdev_attrinit(struct sdev_node *dv, vattr_t *vap) 268 { 269 timestruc_t now; 270 271 ASSERT(vap); 272 273 dv->sdev_attr = kmem_zalloc(sizeof (struct vattr), KM_SLEEP); 274 *dv->sdev_attr = *vap; 275 276 dv->sdev_attr->va_mode = MAKEIMODE(vap->va_type, vap->va_mode); 277 278 gethrestime(&now); 279 dv->sdev_attr->va_atime = now; 280 dv->sdev_attr->va_mtime = now; 281 dv->sdev_attr->va_ctime = now; 282 } 283 284 /* alloc and initialize a sdev_node */ 285 int 286 sdev_nodeinit(struct sdev_node *ddv, char *nm, struct sdev_node **newdv, 287 vattr_t *vap) 288 { 289 struct sdev_node *dv = NULL; 290 struct vnode *vp; 291 size_t nmlen, len; 292 devname_handle_t *dhl; 293 294 nmlen = strlen(nm) + 1; 295 if (nmlen > MAXNAMELEN) { 296 sdcmn_err9(("sdev_nodeinit: node name %s" 297 " too long\n", nm)); 298 *newdv = NULL; 299 return (ENAMETOOLONG); 300 } 301 302 dv = kmem_cache_alloc(sdev_node_cache, KM_SLEEP); 303 304 dv->sdev_name = kmem_alloc(nmlen, KM_SLEEP); 305 bcopy(nm, dv->sdev_name, nmlen); 306 dv->sdev_namelen = nmlen - 1; /* '\0' not included */ 307 len = strlen(ddv->sdev_path) + strlen(nm) + 2; 308 dv->sdev_path = kmem_alloc(len, KM_SLEEP); 309 (void) snprintf(dv->sdev_path, len, "%s/%s", ddv->sdev_path, nm); 310 /* overwritten for VLNK nodes */ 311 dv->sdev_symlink = NULL; 312 313 vp = SDEVTOV(dv); 314 vn_reinit(vp); 315 vp->v_vfsp = SDEVTOV(ddv)->v_vfsp; 316 if (vap) 317 vp->v_type = vap->va_type; 318 319 /* 320 * initialized to the parent's vnodeops. 321 * maybe overwriten for a VDIR 322 */ 323 vn_setops(vp, vn_getops(SDEVTOV(ddv))); 324 vn_exists(vp); 325 326 dv->sdev_dotdot = NULL; 327 dv->sdev_attrvp = NULL; 328 if (vap) { 329 sdev_attrinit(dv, vap); 330 } else { 331 dv->sdev_attr = NULL; 332 } 333 334 dv->sdev_ino = sdev_mkino(dv); 335 dv->sdev_nlink = 0; /* updated on insert */ 336 dv->sdev_flags = ddv->sdev_flags; /* inherit from the parent first */ 337 dv->sdev_flags |= SDEV_BUILD; 338 mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL); 339 cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL); 340 if (SDEV_IS_GLOBAL(ddv)) { 341 dv->sdev_flags |= SDEV_GLOBAL; 342 dv->sdev_mapinfo = NULL; 343 dhl = &(dv->sdev_handle); 344 dhl->dh_data = dv; 345 dhl->dh_spec = DEVNAME_NS_NONE; 346 dhl->dh_args = NULL; 347 sdev_set_no_nocache(dv); 348 dv->sdev_gdir_gen = 0; 349 } else { 350 dv->sdev_flags &= ~SDEV_GLOBAL; 351 dv->sdev_origin = NULL; /* set later */ 352 bzero(&dv->sdev_prof, sizeof (dv->sdev_prof)); 353 dv->sdev_ldir_gen = 0; 354 dv->sdev_devtree_gen = 0; 355 } 356 357 rw_enter(&dv->sdev_contents, RW_WRITER); 358 sdev_set_nodestate(dv, SDEV_INIT); 359 rw_exit(&dv->sdev_contents); 360 *newdv = dv; 361 362 return (0); 363 } 364 365 /* 366 * transition a sdev_node into SDEV_READY state 367 */ 368 int 369 sdev_nodeready(struct sdev_node *dv, struct vattr *vap, struct vnode *avp, 370 void *args, struct cred *cred) 371 { 372 int error = 0; 373 struct vnode *vp = SDEVTOV(dv); 374 vtype_t type; 375 376 ASSERT(dv && (dv->sdev_state != SDEV_READY) && vap); 377 378 type = vap->va_type; 379 vp->v_type = type; 380 vp->v_rdev = vap->va_rdev; 381 rw_enter(&dv->sdev_contents, RW_WRITER); 382 if (type == VDIR) { 383 dv->sdev_nlink = 2; 384 dv->sdev_flags &= ~SDEV_PERSIST; 385 dv->sdev_flags &= ~SDEV_DYNAMIC; 386 vn_setops(vp, sdev_get_vop(dv)); /* from internal vtab */ 387 error = sdev_get_moduleops(dv); /* from plug-in module */ 388 ASSERT(dv->sdev_dotdot); 389 ASSERT(SDEVTOV(dv->sdev_dotdot)->v_type == VDIR); 390 vp->v_rdev = SDEVTOV(dv->sdev_dotdot)->v_rdev; 391 avl_create(&dv->sdev_entries, 392 (int (*)(const void *, const void *))sdev_compare_nodes, 393 sizeof (struct sdev_node), 394 offsetof(struct sdev_node, sdev_avllink)); 395 } else if (type == VLNK) { 396 ASSERT(args); 397 dv->sdev_nlink = 1; 398 dv->sdev_symlink = i_ddi_strdup((char *)args, KM_SLEEP); 399 } else { 400 dv->sdev_nlink = 1; 401 } 402 403 if (!(SDEV_IS_GLOBAL(dv))) { 404 dv->sdev_origin = (struct sdev_node *)args; 405 dv->sdev_flags &= ~SDEV_PERSIST; 406 } 407 408 /* 409 * shadow node is created here OR 410 * if failed (indicated by dv->sdev_attrvp == NULL), 411 * created later in sdev_setattr 412 */ 413 if (avp) { 414 dv->sdev_attrvp = avp; 415 } else { 416 if (dv->sdev_attr == NULL) 417 sdev_attrinit(dv, vap); 418 else 419 *dv->sdev_attr = *vap; 420 421 if ((SDEV_IS_PERSIST(dv) && (dv->sdev_attrvp == NULL)) || 422 ((SDEVTOV(dv)->v_type == VDIR) && 423 (dv->sdev_attrvp == NULL))) { 424 error = sdev_shadow_node(dv, cred); 425 } 426 } 427 428 if (error == 0) { 429 /* transition to READY state */ 430 sdev_set_nodestate(dv, SDEV_READY); 431 sdev_nc_node_exists(dv); 432 } else { 433 sdev_set_nodestate(dv, SDEV_ZOMBIE); 434 } 435 rw_exit(&dv->sdev_contents); 436 return (error); 437 } 438 439 /* 440 * setting ZOMBIE state 441 */ 442 static int 443 sdev_nodezombied(struct sdev_node *dv) 444 { 445 rw_enter(&dv->sdev_contents, RW_WRITER); 446 sdev_set_nodestate(dv, SDEV_ZOMBIE); 447 rw_exit(&dv->sdev_contents); 448 return (0); 449 } 450 451 /* 452 * Build the VROOT sdev_node. 453 */ 454 /*ARGSUSED*/ 455 struct sdev_node * 456 sdev_mkroot(struct vfs *vfsp, dev_t devdev, struct vnode *mvp, 457 struct vnode *avp, struct cred *cred) 458 { 459 struct sdev_node *dv; 460 struct vnode *vp; 461 char devdir[] = "/dev"; 462 463 ASSERT(sdev_node_cache != NULL); 464 ASSERT(avp); 465 dv = kmem_cache_alloc(sdev_node_cache, KM_SLEEP); 466 vp = SDEVTOV(dv); 467 vn_reinit(vp); 468 vp->v_flag |= VROOT; 469 vp->v_vfsp = vfsp; 470 vp->v_type = VDIR; 471 vp->v_rdev = devdev; 472 vn_setops(vp, sdev_vnodeops); /* apply the default vnodeops at /dev */ 473 vn_exists(vp); 474 475 if (vfsp->vfs_mntpt) 476 dv->sdev_name = i_ddi_strdup( 477 (char *)refstr_value(vfsp->vfs_mntpt), KM_SLEEP); 478 else 479 /* vfs_mountdev1 set mount point later */ 480 dv->sdev_name = i_ddi_strdup("/dev", KM_SLEEP); 481 dv->sdev_namelen = strlen(dv->sdev_name); /* '\0' not included */ 482 dv->sdev_path = i_ddi_strdup(devdir, KM_SLEEP); 483 dv->sdev_ino = SDEV_ROOTINO; 484 dv->sdev_nlink = 2; /* name + . (no sdev_insert) */ 485 dv->sdev_dotdot = dv; /* .. == self */ 486 dv->sdev_attrvp = avp; 487 dv->sdev_attr = NULL; 488 mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL); 489 cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL); 490 if (strcmp(dv->sdev_name, "/dev") == 0) { 491 mutex_init(&devname_nsmaps_lock, NULL, MUTEX_DEFAULT, NULL); 492 dv->sdev_mapinfo = NULL; 493 dv->sdev_flags = SDEV_BUILD|SDEV_GLOBAL|SDEV_PERSIST; 494 bzero(&dv->sdev_handle, sizeof (dv->sdev_handle)); 495 dv->sdev_gdir_gen = 0; 496 } else { 497 dv->sdev_flags = SDEV_BUILD; 498 dv->sdev_flags &= ~SDEV_PERSIST; 499 bzero(&dv->sdev_prof, sizeof (dv->sdev_prof)); 500 dv->sdev_ldir_gen = 0; 501 dv->sdev_devtree_gen = 0; 502 } 503 504 avl_create(&dv->sdev_entries, 505 (int (*)(const void *, const void *))sdev_compare_nodes, 506 sizeof (struct sdev_node), 507 offsetof(struct sdev_node, sdev_avllink)); 508 509 rw_enter(&dv->sdev_contents, RW_WRITER); 510 sdev_set_nodestate(dv, SDEV_READY); 511 rw_exit(&dv->sdev_contents); 512 sdev_nc_node_exists(dv); 513 return (dv); 514 } 515 516 /* 517 * 1. load the module 518 * 2. modload invokes sdev_module_register, which in turn sets 519 * the dv->sdev_mapinfo->dir_ops 520 * 521 * note: locking order: 522 * dv->sdev_contents -> map->dir_lock 523 */ 524 static int 525 sdev_get_moduleops(struct sdev_node *dv) 526 { 527 int error = 0; 528 struct devname_nsmap *map = NULL; 529 char *module; 530 char *path; 531 int load = 1; 532 533 ASSERT(SDEVTOV(dv)->v_type == VDIR); 534 535 if (devname_nsmaps == NULL) 536 return (0); 537 538 if (!sdev_nsmaps_loaded() && !sdev_nsmaps_reloaded()) 539 return (0); 540 541 542 path = dv->sdev_path; 543 if ((map = sdev_get_nsmap_by_dir(path, 0))) { 544 rw_enter(&map->dir_lock, RW_READER); 545 if (map->dir_invalid) { 546 if (map->dir_module && map->dir_newmodule && 547 (strcmp(map->dir_module, 548 map->dir_newmodule) == 0)) { 549 load = 0; 550 } 551 sdev_replace_nsmap(map, map->dir_newmodule, 552 map->dir_newmap); 553 } 554 555 module = map->dir_module; 556 if (module && load) { 557 sdcmn_err6(("sdev_get_moduleops: " 558 "load module %s", module)); 559 rw_exit(&map->dir_lock); 560 error = modload("devname", module); 561 sdcmn_err6(("sdev_get_moduleops: error %d\n", error)); 562 if (error < 0) { 563 return (-1); 564 } 565 } else if (module == NULL) { 566 /* 567 * loading the module ops for name services 568 */ 569 if (devname_ns_ops == NULL) { 570 sdcmn_err6(( 571 "sdev_get_moduleops: modload default\n")); 572 error = modload("devname", DEVNAME_NSCONFIG); 573 sdcmn_err6(( 574 "sdev_get_moduleops: error %d\n", error)); 575 if (error < 0) { 576 return (-1); 577 } 578 } 579 580 if (!rw_tryupgrade(&map->dir_lock)) { 581 rw_exit(&map->dir_lock); 582 rw_enter(&map->dir_lock, RW_WRITER); 583 } 584 ASSERT(devname_ns_ops); 585 map->dir_ops = devname_ns_ops; 586 rw_exit(&map->dir_lock); 587 } 588 } 589 590 dv->sdev_mapinfo = map; 591 return (0); 592 } 593 594 /* directory dependent vop table */ 595 struct sdev_vop_table { 596 char *vt_name; /* subdirectory name */ 597 const fs_operation_def_t *vt_service; /* vnodeops table */ 598 struct vnodeops *vt_vops; /* constructed vop */ 599 struct vnodeops **vt_global_vops; /* global container for vop */ 600 int (*vt_vtor)(struct sdev_node *); /* validate sdev_node */ 601 int vt_flags; 602 }; 603 604 /* 605 * A nice improvement would be to provide a plug-in mechanism 606 * for this table instead of a const table. 607 */ 608 static struct sdev_vop_table vtab[] = 609 { 610 { "pts", devpts_vnodeops_tbl, NULL, &devpts_vnodeops, devpts_validate, 611 SDEV_DYNAMIC | SDEV_VTOR }, 612 613 { "zcons", NULL, NULL, NULL, NULL, SDEV_NO_NCACHE }, 614 615 { "net", devnet_vnodeops_tbl, NULL, &devnet_vnodeops, devnet_validate, 616 SDEV_DYNAMIC | SDEV_VTOR }, 617 618 { NULL, NULL, NULL, NULL, NULL, 0} 619 }; 620 621 622 /* 623 * sets a directory's vnodeops if the directory is in the vtab; 624 */ 625 static struct vnodeops * 626 sdev_get_vop(struct sdev_node *dv) 627 { 628 int i; 629 char *path; 630 631 path = dv->sdev_path; 632 ASSERT(path); 633 634 /* gets the relative path to /dev/ */ 635 path += 5; 636 637 /* gets the vtab entry if matches */ 638 for (i = 0; vtab[i].vt_name; i++) { 639 if (strcmp(vtab[i].vt_name, path) != 0) 640 continue; 641 dv->sdev_flags |= vtab[i].vt_flags; 642 643 if (vtab[i].vt_vops) { 644 if (vtab[i].vt_global_vops) 645 *(vtab[i].vt_global_vops) = vtab[i].vt_vops; 646 return (vtab[i].vt_vops); 647 } 648 649 if (vtab[i].vt_service) { 650 fs_operation_def_t *templ; 651 templ = sdev_merge_vtab(vtab[i].vt_service); 652 if (vn_make_ops(vtab[i].vt_name, 653 (const fs_operation_def_t *)templ, 654 &vtab[i].vt_vops) != 0) { 655 cmn_err(CE_PANIC, "%s: malformed vnode ops\n", 656 vtab[i].vt_name); 657 /*NOTREACHED*/ 658 } 659 if (vtab[i].vt_global_vops) { 660 *(vtab[i].vt_global_vops) = vtab[i].vt_vops; 661 } 662 sdev_free_vtab(templ); 663 return (vtab[i].vt_vops); 664 } 665 return (sdev_vnodeops); 666 } 667 668 /* child inherits the persistence of the parent */ 669 if (SDEV_IS_PERSIST(dv->sdev_dotdot)) 670 dv->sdev_flags |= SDEV_PERSIST; 671 672 return (sdev_vnodeops); 673 } 674 675 static void 676 sdev_set_no_nocache(struct sdev_node *dv) 677 { 678 int i; 679 char *path; 680 681 ASSERT(dv->sdev_path); 682 path = dv->sdev_path + strlen("/dev/"); 683 684 for (i = 0; vtab[i].vt_name; i++) { 685 if (strcmp(vtab[i].vt_name, path) == 0) { 686 if (vtab[i].vt_flags & SDEV_NO_NCACHE) 687 dv->sdev_flags |= SDEV_NO_NCACHE; 688 break; 689 } 690 } 691 } 692 693 void * 694 sdev_get_vtor(struct sdev_node *dv) 695 { 696 int i; 697 698 for (i = 0; vtab[i].vt_name; i++) { 699 if (strcmp(vtab[i].vt_name, dv->sdev_name) != 0) 700 continue; 701 return ((void *)vtab[i].vt_vtor); 702 } 703 return (NULL); 704 } 705 706 /* 707 * Build the base root inode 708 */ 709 ino_t 710 sdev_mkino(struct sdev_node *dv) 711 { 712 ino_t ino; 713 714 /* 715 * for now, follow the lead of tmpfs here 716 * need to someday understand the requirements here 717 */ 718 ino = (ino_t)(uint32_t)((uintptr_t)dv >> 3); 719 ino += SDEV_ROOTINO + 1; 720 721 return (ino); 722 } 723 724 static int 725 sdev_getlink(struct vnode *linkvp, char **link) 726 { 727 int err; 728 char *buf; 729 struct uio uio = {0}; 730 struct iovec iov = {0}; 731 732 if (linkvp == NULL) 733 return (ENOENT); 734 ASSERT(linkvp->v_type == VLNK); 735 736 buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 737 iov.iov_base = buf; 738 iov.iov_len = MAXPATHLEN; 739 uio.uio_iov = &iov; 740 uio.uio_iovcnt = 1; 741 uio.uio_resid = MAXPATHLEN; 742 uio.uio_segflg = UIO_SYSSPACE; 743 uio.uio_llimit = MAXOFFSET_T; 744 745 err = VOP_READLINK(linkvp, &uio, kcred, NULL); 746 if (err) { 747 cmn_err(CE_WARN, "readlink %s failed in dev\n", buf); 748 kmem_free(buf, MAXPATHLEN); 749 return (ENOENT); 750 } 751 752 /* mission complete */ 753 *link = i_ddi_strdup(buf, KM_SLEEP); 754 kmem_free(buf, MAXPATHLEN); 755 return (0); 756 } 757 758 /* 759 * A convenient wrapper to get the devfs node vnode for a device 760 * minor functionality: readlink() of a /dev symlink 761 * Place the link into dv->sdev_symlink 762 */ 763 static int 764 sdev_follow_link(struct sdev_node *dv) 765 { 766 int err; 767 struct vnode *linkvp; 768 char *link = NULL; 769 770 linkvp = SDEVTOV(dv); 771 if (linkvp == NULL) 772 return (ENOENT); 773 ASSERT(linkvp->v_type == VLNK); 774 err = sdev_getlink(linkvp, &link); 775 if (err) { 776 (void) sdev_nodezombied(dv); 777 dv->sdev_symlink = NULL; 778 return (ENOENT); 779 } 780 781 ASSERT(link != NULL); 782 dv->sdev_symlink = link; 783 return (0); 784 } 785 786 static int 787 sdev_node_check(struct sdev_node *dv, struct vattr *nvap, void *nargs) 788 { 789 vtype_t otype = SDEVTOV(dv)->v_type; 790 791 /* 792 * existing sdev_node has a different type. 793 */ 794 if (otype != nvap->va_type) { 795 sdcmn_err9(("sdev_node_check: existing node " 796 " %s type %d does not match new node type %d\n", 797 dv->sdev_name, otype, nvap->va_type)); 798 return (EEXIST); 799 } 800 801 /* 802 * For a symlink, the target should be the same. 803 */ 804 if (otype == VLNK) { 805 ASSERT(nargs != NULL); 806 ASSERT(dv->sdev_symlink != NULL); 807 if (strcmp(dv->sdev_symlink, (char *)nargs) != 0) { 808 sdcmn_err9(("sdev_node_check: existing node " 809 " %s has different symlink %s as new node " 810 " %s\n", dv->sdev_name, dv->sdev_symlink, 811 (char *)nargs)); 812 return (EEXIST); 813 } 814 } 815 816 return (0); 817 } 818 819 /* 820 * sdev_mknode - a wrapper for sdev_nodeinit(), sdev_nodeready() 821 * 822 * arguments: 823 * - ddv (parent) 824 * - nm (child name) 825 * - newdv (sdev_node for nm is returned here) 826 * - vap (vattr for the node to be created, va_type should be set. 827 * - avp (attribute vnode) 828 * the defaults should be used if unknown) 829 * - cred 830 * - args 831 * . tnm (for VLNK) 832 * . global sdev_node (for !SDEV_GLOBAL) 833 * - state: SDEV_INIT, SDEV_READY 834 * 835 * only ddv, nm, newddv, vap, cred are required for sdev_mknode(SDEV_INIT) 836 * 837 * NOTE: directory contents writers lock needs to be held before 838 * calling this routine. 839 */ 840 int 841 sdev_mknode(struct sdev_node *ddv, char *nm, struct sdev_node **newdv, 842 struct vattr *vap, struct vnode *avp, void *args, struct cred *cred, 843 sdev_node_state_t state) 844 { 845 int error = 0; 846 sdev_node_state_t node_state; 847 struct sdev_node *dv = NULL; 848 849 ASSERT(state != SDEV_ZOMBIE); 850 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 851 852 if (*newdv) { 853 dv = *newdv; 854 } else { 855 /* allocate and initialize a sdev_node */ 856 if (ddv->sdev_state == SDEV_ZOMBIE) { 857 sdcmn_err9(("sdev_mknode: parent %s ZOMBIEd\n", 858 ddv->sdev_path)); 859 return (ENOENT); 860 } 861 862 error = sdev_nodeinit(ddv, nm, &dv, vap); 863 if (error != 0) { 864 sdcmn_err9(("sdev_mknode: error %d," 865 " name %s can not be initialized\n", 866 error, nm)); 867 return (error); 868 } 869 ASSERT(dv); 870 871 /* insert into the directory cache */ 872 error = sdev_cache_update(ddv, &dv, nm, SDEV_CACHE_ADD); 873 if (error) { 874 sdcmn_err9(("sdev_mknode: node %s can not" 875 " be added into directory cache\n", nm)); 876 return (ENOENT); 877 } 878 } 879 880 ASSERT(dv); 881 node_state = dv->sdev_state; 882 ASSERT(node_state != SDEV_ZOMBIE); 883 884 if (state == SDEV_READY) { 885 switch (node_state) { 886 case SDEV_INIT: 887 error = sdev_nodeready(dv, vap, avp, args, cred); 888 if (error) { 889 sdcmn_err9(("sdev_mknode: node %s can NOT" 890 " be transitioned into READY state, " 891 "error %d\n", nm, error)); 892 } 893 break; 894 case SDEV_READY: 895 /* 896 * Do some sanity checking to make sure 897 * the existing sdev_node is what has been 898 * asked for. 899 */ 900 error = sdev_node_check(dv, vap, args); 901 break; 902 default: 903 break; 904 } 905 } 906 907 if (!error) { 908 *newdv = dv; 909 ASSERT((*newdv)->sdev_state != SDEV_ZOMBIE); 910 } else { 911 SDEV_SIMPLE_RELE(dv); 912 *newdv = NULL; 913 } 914 915 return (error); 916 } 917 918 /* 919 * convenient wrapper to change vp's ATIME, CTIME and MTIME 920 */ 921 void 922 sdev_update_timestamps(struct vnode *vp, cred_t *cred, uint_t mask) 923 { 924 struct vattr attr; 925 timestruc_t now; 926 int err; 927 928 ASSERT(vp); 929 gethrestime(&now); 930 if (mask & AT_CTIME) 931 attr.va_ctime = now; 932 if (mask & AT_MTIME) 933 attr.va_mtime = now; 934 if (mask & AT_ATIME) 935 attr.va_atime = now; 936 937 attr.va_mask = (mask & AT_TIMES); 938 err = VOP_SETATTR(vp, &attr, 0, cred, NULL); 939 if (err && (err != EROFS)) { 940 sdcmn_err(("update timestamps error %d\n", err)); 941 } 942 } 943 944 /* 945 * the backing store vnode is released here 946 */ 947 /*ARGSUSED1*/ 948 void 949 sdev_nodedestroy(struct sdev_node *dv, uint_t flags) 950 { 951 /* no references */ 952 ASSERT(dv->sdev_nlink == 0); 953 954 if (dv->sdev_attrvp != NULLVP) { 955 VN_RELE(dv->sdev_attrvp); 956 /* 957 * reset the attrvp so that no more 958 * references can be made on this already 959 * vn_rele() vnode 960 */ 961 dv->sdev_attrvp = NULLVP; 962 } 963 964 if (dv->sdev_attr != NULL) { 965 kmem_free(dv->sdev_attr, sizeof (struct vattr)); 966 dv->sdev_attr = NULL; 967 } 968 969 if (dv->sdev_name != NULL) { 970 kmem_free(dv->sdev_name, dv->sdev_namelen + 1); 971 dv->sdev_name = NULL; 972 } 973 974 if (dv->sdev_symlink != NULL) { 975 kmem_free(dv->sdev_symlink, strlen(dv->sdev_symlink) + 1); 976 dv->sdev_symlink = NULL; 977 } 978 979 if (dv->sdev_path) { 980 kmem_free(dv->sdev_path, strlen(dv->sdev_path) + 1); 981 dv->sdev_path = NULL; 982 } 983 984 if (!SDEV_IS_GLOBAL(dv)) 985 sdev_prof_free(dv); 986 987 if (SDEVTOV(dv)->v_type == VDIR) { 988 ASSERT(SDEV_FIRST_ENTRY(dv) == NULL); 989 avl_destroy(&dv->sdev_entries); 990 } 991 992 mutex_destroy(&dv->sdev_lookup_lock); 993 cv_destroy(&dv->sdev_lookup_cv); 994 995 /* return node to initial state as per constructor */ 996 (void) memset((void *)&dv->sdev_instance_data, 0, 997 sizeof (dv->sdev_instance_data)); 998 vn_invalid(SDEVTOV(dv)); 999 kmem_cache_free(sdev_node_cache, dv); 1000 } 1001 1002 /* 1003 * DIRECTORY CACHE lookup 1004 */ 1005 struct sdev_node * 1006 sdev_findbyname(struct sdev_node *ddv, char *nm) 1007 { 1008 struct sdev_node *dv; 1009 struct sdev_node dvtmp; 1010 avl_index_t where; 1011 1012 ASSERT(RW_LOCK_HELD(&ddv->sdev_contents)); 1013 1014 dvtmp.sdev_name = nm; 1015 dv = avl_find(&ddv->sdev_entries, &dvtmp, &where); 1016 if (dv) { 1017 ASSERT(dv->sdev_dotdot == ddv); 1018 ASSERT(strcmp(dv->sdev_name, nm) == 0); 1019 SDEV_HOLD(dv); 1020 return (dv); 1021 } 1022 return (NULL); 1023 } 1024 1025 /* 1026 * Inserts a new sdev_node in a parent directory 1027 */ 1028 void 1029 sdev_direnter(struct sdev_node *ddv, struct sdev_node *dv) 1030 { 1031 avl_index_t where; 1032 1033 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1034 ASSERT(SDEVTOV(ddv)->v_type == VDIR); 1035 ASSERT(ddv->sdev_nlink >= 2); 1036 ASSERT(dv->sdev_nlink == 0); 1037 1038 dv->sdev_dotdot = ddv; 1039 VERIFY(avl_find(&ddv->sdev_entries, dv, &where) == NULL); 1040 avl_insert(&ddv->sdev_entries, dv, where); 1041 ddv->sdev_nlink++; 1042 } 1043 1044 /* 1045 * The following check is needed because while sdev_nodes are linked 1046 * in SDEV_INIT state, they have their link counts incremented only 1047 * in SDEV_READY state. 1048 */ 1049 static void 1050 decr_link(struct sdev_node *dv) 1051 { 1052 if (dv->sdev_state != SDEV_INIT) 1053 dv->sdev_nlink--; 1054 else 1055 ASSERT(dv->sdev_nlink == 0); 1056 } 1057 1058 /* 1059 * Delete an existing dv from directory cache 1060 * 1061 * In the case of a node is still held by non-zero reference count, 1062 * the node is put into ZOMBIE state. Once the reference count 1063 * reaches "0", the node is unlinked and destroyed, 1064 * in sdev_inactive(). 1065 */ 1066 static int 1067 sdev_dirdelete(struct sdev_node *ddv, struct sdev_node *dv) 1068 { 1069 struct vnode *vp; 1070 1071 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1072 1073 vp = SDEVTOV(dv); 1074 mutex_enter(&vp->v_lock); 1075 1076 /* dv is held still */ 1077 if (vp->v_count > 1) { 1078 rw_enter(&dv->sdev_contents, RW_WRITER); 1079 if (dv->sdev_state == SDEV_READY) { 1080 sdcmn_err9(( 1081 "sdev_delete: node %s busy with count %d\n", 1082 dv->sdev_name, vp->v_count)); 1083 dv->sdev_state = SDEV_ZOMBIE; 1084 } 1085 rw_exit(&dv->sdev_contents); 1086 --vp->v_count; 1087 mutex_exit(&vp->v_lock); 1088 return (EBUSY); 1089 } 1090 ASSERT(vp->v_count == 1); 1091 1092 /* unlink from the memory cache */ 1093 ddv->sdev_nlink--; /* .. to above */ 1094 if (vp->v_type == VDIR) { 1095 decr_link(dv); /* . to self */ 1096 } 1097 1098 avl_remove(&ddv->sdev_entries, dv); 1099 decr_link(dv); /* name, back to zero */ 1100 vp->v_count--; 1101 mutex_exit(&vp->v_lock); 1102 1103 /* destroy the node */ 1104 sdev_nodedestroy(dv, 0); 1105 return (0); 1106 } 1107 1108 /* 1109 * check if the source is in the path of the target 1110 * 1111 * source and target are different 1112 */ 1113 /*ARGSUSED2*/ 1114 static int 1115 sdev_checkpath(struct sdev_node *sdv, struct sdev_node *tdv, struct cred *cred) 1116 { 1117 int error = 0; 1118 struct sdev_node *dotdot, *dir; 1119 1120 dotdot = tdv->sdev_dotdot; 1121 ASSERT(dotdot); 1122 1123 /* fs root */ 1124 if (dotdot == tdv) { 1125 return (0); 1126 } 1127 1128 for (;;) { 1129 /* 1130 * avoid error cases like 1131 * mv a a/b 1132 * mv a a/b/c 1133 * etc. 1134 */ 1135 if (dotdot == sdv) { 1136 error = EINVAL; 1137 break; 1138 } 1139 1140 dir = dotdot; 1141 dotdot = dir->sdev_dotdot; 1142 1143 /* done checking because root is reached */ 1144 if (dir == dotdot) { 1145 break; 1146 } 1147 } 1148 return (error); 1149 } 1150 1151 int 1152 sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv, 1153 struct sdev_node *nddv, struct sdev_node **ndvp, char *nnm, 1154 struct cred *cred) 1155 { 1156 int error = 0; 1157 struct vnode *ovp = SDEVTOV(odv); 1158 struct vnode *nvp; 1159 struct vattr vattr; 1160 int doingdir = (ovp->v_type == VDIR); 1161 char *link = NULL; 1162 int samedir = (oddv == nddv) ? 1 : 0; 1163 int bkstore = 0; 1164 struct sdev_node *idv = NULL; 1165 struct sdev_node *ndv = NULL; 1166 timestruc_t now; 1167 1168 vattr.va_mask = AT_MODE|AT_UID|AT_GID; 1169 error = VOP_GETATTR(ovp, &vattr, 0, cred, NULL); 1170 if (error) 1171 return (error); 1172 1173 if (!samedir) 1174 rw_enter(&oddv->sdev_contents, RW_WRITER); 1175 rw_enter(&nddv->sdev_contents, RW_WRITER); 1176 1177 /* 1178 * the source may have been deleted by another thread before 1179 * we gets here. 1180 */ 1181 if (odv->sdev_state != SDEV_READY) { 1182 error = ENOENT; 1183 goto err_out; 1184 } 1185 1186 if (doingdir && (odv == nddv)) { 1187 error = EINVAL; 1188 goto err_out; 1189 } 1190 1191 /* 1192 * If renaming a directory, and the parents are different (".." must be 1193 * changed) then the source dir must not be in the dir hierarchy above 1194 * the target since it would orphan everything below the source dir. 1195 */ 1196 if (doingdir && (oddv != nddv)) { 1197 error = sdev_checkpath(odv, nddv, cred); 1198 if (error) 1199 goto err_out; 1200 } 1201 1202 /* destination existing */ 1203 if (*ndvp) { 1204 nvp = SDEVTOV(*ndvp); 1205 ASSERT(nvp); 1206 1207 /* handling renaming to itself */ 1208 if (odv == *ndvp) { 1209 error = 0; 1210 goto err_out; 1211 } 1212 1213 if (nvp->v_type == VDIR) { 1214 if (!doingdir) { 1215 error = EISDIR; 1216 goto err_out; 1217 } 1218 1219 if (vn_vfswlock(nvp)) { 1220 error = EBUSY; 1221 goto err_out; 1222 } 1223 1224 if (vn_mountedvfs(nvp) != NULL) { 1225 vn_vfsunlock(nvp); 1226 error = EBUSY; 1227 goto err_out; 1228 } 1229 1230 /* in case dir1 exists in dir2 and "mv dir1 dir2" */ 1231 if ((*ndvp)->sdev_nlink > 2) { 1232 vn_vfsunlock(nvp); 1233 error = EEXIST; 1234 goto err_out; 1235 } 1236 vn_vfsunlock(nvp); 1237 1238 (void) sdev_dirdelete(nddv, *ndvp); 1239 *ndvp = NULL; 1240 ASSERT(nddv->sdev_attrvp); 1241 error = VOP_RMDIR(nddv->sdev_attrvp, nnm, 1242 nddv->sdev_attrvp, cred, NULL, 0); 1243 if (error) 1244 goto err_out; 1245 } else { 1246 if (doingdir) { 1247 error = ENOTDIR; 1248 goto err_out; 1249 } 1250 1251 if (SDEV_IS_PERSIST((*ndvp))) { 1252 bkstore = 1; 1253 } 1254 1255 /* 1256 * get rid of the node from the directory cache 1257 * note, in case EBUSY is returned, the ZOMBIE 1258 * node is taken care in sdev_mknode. 1259 */ 1260 (void) sdev_dirdelete(nddv, *ndvp); 1261 *ndvp = NULL; 1262 if (bkstore) { 1263 ASSERT(nddv->sdev_attrvp); 1264 error = VOP_REMOVE(nddv->sdev_attrvp, 1265 nnm, cred, NULL, 0); 1266 if (error) 1267 goto err_out; 1268 } 1269 } 1270 } 1271 1272 /* fix the source for a symlink */ 1273 if (vattr.va_type == VLNK) { 1274 if (odv->sdev_symlink == NULL) { 1275 error = sdev_follow_link(odv); 1276 if (error) { 1277 error = ENOENT; 1278 goto err_out; 1279 } 1280 } 1281 ASSERT(odv->sdev_symlink); 1282 link = i_ddi_strdup(odv->sdev_symlink, KM_SLEEP); 1283 } 1284 1285 /* 1286 * make a fresh node from the source attrs 1287 */ 1288 ASSERT(RW_WRITE_HELD(&nddv->sdev_contents)); 1289 error = sdev_mknode(nddv, nnm, ndvp, &vattr, 1290 NULL, (void *)link, cred, SDEV_READY); 1291 1292 if (link) 1293 kmem_free(link, strlen(link) + 1); 1294 1295 if (error) 1296 goto err_out; 1297 ASSERT(*ndvp); 1298 ASSERT((*ndvp)->sdev_state == SDEV_READY); 1299 1300 /* move dir contents */ 1301 if (doingdir) { 1302 for (idv = SDEV_FIRST_ENTRY(odv); idv; 1303 idv = SDEV_NEXT_ENTRY(odv, idv)) { 1304 error = sdev_rnmnode(odv, idv, 1305 (struct sdev_node *)(*ndvp), &ndv, 1306 idv->sdev_name, cred); 1307 if (error) 1308 goto err_out; 1309 ndv = NULL; 1310 } 1311 } 1312 1313 if ((*ndvp)->sdev_attrvp) { 1314 sdev_update_timestamps((*ndvp)->sdev_attrvp, kcred, 1315 AT_CTIME|AT_ATIME); 1316 } else { 1317 ASSERT((*ndvp)->sdev_attr); 1318 gethrestime(&now); 1319 (*ndvp)->sdev_attr->va_ctime = now; 1320 (*ndvp)->sdev_attr->va_atime = now; 1321 } 1322 1323 if (nddv->sdev_attrvp) { 1324 sdev_update_timestamps(nddv->sdev_attrvp, kcred, 1325 AT_MTIME|AT_ATIME); 1326 } else { 1327 ASSERT(nddv->sdev_attr); 1328 gethrestime(&now); 1329 nddv->sdev_attr->va_mtime = now; 1330 nddv->sdev_attr->va_atime = now; 1331 } 1332 rw_exit(&nddv->sdev_contents); 1333 if (!samedir) 1334 rw_exit(&oddv->sdev_contents); 1335 1336 SDEV_RELE(*ndvp); 1337 return (error); 1338 1339 err_out: 1340 rw_exit(&nddv->sdev_contents); 1341 if (!samedir) 1342 rw_exit(&oddv->sdev_contents); 1343 return (error); 1344 } 1345 1346 /* 1347 * Merge sdev_node specific information into an attribute structure. 1348 * 1349 * note: sdev_node is not locked here 1350 */ 1351 void 1352 sdev_vattr_merge(struct sdev_node *dv, struct vattr *vap) 1353 { 1354 struct vnode *vp = SDEVTOV(dv); 1355 1356 vap->va_nlink = dv->sdev_nlink; 1357 vap->va_nodeid = dv->sdev_ino; 1358 vap->va_fsid = SDEVTOV(dv->sdev_dotdot)->v_rdev; 1359 vap->va_type = vp->v_type; 1360 1361 if (vp->v_type == VDIR) { 1362 vap->va_rdev = 0; 1363 vap->va_fsid = vp->v_rdev; 1364 } else if (vp->v_type == VLNK) { 1365 vap->va_rdev = 0; 1366 vap->va_mode &= ~S_IFMT; 1367 vap->va_mode |= S_IFLNK; 1368 } else if ((vp->v_type == VCHR) || (vp->v_type == VBLK)) { 1369 vap->va_rdev = vp->v_rdev; 1370 vap->va_mode &= ~S_IFMT; 1371 if (vap->va_type == VCHR) 1372 vap->va_mode |= S_IFCHR; 1373 else 1374 vap->va_mode |= S_IFBLK; 1375 } else { 1376 vap->va_rdev = 0; 1377 } 1378 } 1379 1380 static struct vattr * 1381 sdev_getdefault_attr(enum vtype type) 1382 { 1383 if (type == VDIR) 1384 return (&sdev_vattr_dir); 1385 else if (type == VCHR) 1386 return (&sdev_vattr_chr); 1387 else if (type == VBLK) 1388 return (&sdev_vattr_blk); 1389 else if (type == VLNK) 1390 return (&sdev_vattr_lnk); 1391 else 1392 return (NULL); 1393 } 1394 int 1395 sdev_to_vp(struct sdev_node *dv, struct vnode **vpp) 1396 { 1397 int rv = 0; 1398 struct vnode *vp = SDEVTOV(dv); 1399 1400 switch (vp->v_type) { 1401 case VCHR: 1402 case VBLK: 1403 /* 1404 * If vnode is a device, return special vnode instead 1405 * (though it knows all about -us- via sp->s_realvp) 1406 */ 1407 *vpp = specvp(vp, vp->v_rdev, vp->v_type, kcred); 1408 VN_RELE(vp); 1409 if (*vpp == NULLVP) 1410 rv = ENOSYS; 1411 break; 1412 default: /* most types are returned as is */ 1413 *vpp = vp; 1414 break; 1415 } 1416 return (rv); 1417 } 1418 1419 /* 1420 * loopback into sdev_lookup() 1421 */ 1422 static struct vnode * 1423 devname_find_by_devpath(char *devpath, struct vattr *vattr) 1424 { 1425 int error = 0; 1426 struct vnode *vp; 1427 1428 error = lookupname(devpath, UIO_SYSSPACE, NO_FOLLOW, NULLVPP, &vp); 1429 if (error) { 1430 return (NULL); 1431 } 1432 1433 if (vattr) 1434 (void) VOP_GETATTR(vp, vattr, 0, kcred, NULL); 1435 return (vp); 1436 } 1437 1438 /* 1439 * the junction between devname and devfs 1440 */ 1441 static struct vnode * 1442 devname_configure_by_path(char *physpath, struct vattr *vattr) 1443 { 1444 int error = 0; 1445 struct vnode *vp; 1446 1447 ASSERT(strncmp(physpath, "/devices/", sizeof ("/devices/") - 1) 1448 == 0); 1449 1450 error = devfs_lookupname(physpath + sizeof ("/devices/") - 1, 1451 NULLVPP, &vp); 1452 if (error != 0) { 1453 if (error == ENODEV) { 1454 cmn_err(CE_CONT, "%s: not found (line %d)\n", 1455 physpath, __LINE__); 1456 } 1457 1458 return (NULL); 1459 } 1460 1461 if (vattr) 1462 (void) VOP_GETATTR(vp, vattr, 0, kcred, NULL); 1463 return (vp); 1464 } 1465 1466 /* 1467 * junction between devname and root file system, e.g. ufs 1468 */ 1469 int 1470 devname_backstore_lookup(struct sdev_node *ddv, char *nm, struct vnode **rvp) 1471 { 1472 struct vnode *rdvp = ddv->sdev_attrvp; 1473 int rval = 0; 1474 1475 ASSERT(rdvp); 1476 1477 rval = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, kcred, NULL, NULL, 1478 NULL); 1479 return (rval); 1480 } 1481 1482 static int 1483 sdev_filldir_from_store(struct sdev_node *ddv, int dlen, struct cred *cred) 1484 { 1485 struct sdev_node *dv = NULL; 1486 char *nm; 1487 struct vnode *dirvp; 1488 int error; 1489 vnode_t *vp; 1490 int eof; 1491 struct iovec iov; 1492 struct uio uio; 1493 struct dirent64 *dp; 1494 dirent64_t *dbuf; 1495 size_t dbuflen; 1496 struct vattr vattr; 1497 char *link = NULL; 1498 1499 if (ddv->sdev_attrvp == NULL) 1500 return (0); 1501 if (!(ddv->sdev_flags & SDEV_BUILD)) 1502 return (0); 1503 1504 dirvp = ddv->sdev_attrvp; 1505 VN_HOLD(dirvp); 1506 dbuf = kmem_zalloc(dlen, KM_SLEEP); 1507 1508 uio.uio_iov = &iov; 1509 uio.uio_iovcnt = 1; 1510 uio.uio_segflg = UIO_SYSSPACE; 1511 uio.uio_fmode = 0; 1512 uio.uio_extflg = UIO_COPY_CACHED; 1513 uio.uio_loffset = 0; 1514 uio.uio_llimit = MAXOFFSET_T; 1515 1516 eof = 0; 1517 error = 0; 1518 while (!error && !eof) { 1519 uio.uio_resid = dlen; 1520 iov.iov_base = (char *)dbuf; 1521 iov.iov_len = dlen; 1522 (void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 1523 error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0); 1524 VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 1525 1526 dbuflen = dlen - uio.uio_resid; 1527 if (error || dbuflen == 0) 1528 break; 1529 1530 if (!(ddv->sdev_flags & SDEV_BUILD)) { 1531 error = 0; 1532 break; 1533 } 1534 1535 for (dp = dbuf; ((intptr_t)dp < 1536 (intptr_t)dbuf + dbuflen); 1537 dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) { 1538 nm = dp->d_name; 1539 1540 if (strcmp(nm, ".") == 0 || 1541 strcmp(nm, "..") == 0) 1542 continue; 1543 1544 vp = NULLVP; 1545 dv = sdev_cache_lookup(ddv, nm); 1546 if (dv) { 1547 if (dv->sdev_state != SDEV_ZOMBIE) { 1548 SDEV_SIMPLE_RELE(dv); 1549 } else { 1550 /* 1551 * A ZOMBIE node may not have been 1552 * cleaned up from the backing store, 1553 * bypass this entry in this case, 1554 * and clean it up from the directory 1555 * cache if this is the last call. 1556 */ 1557 (void) sdev_dirdelete(ddv, dv); 1558 } 1559 continue; 1560 } 1561 1562 /* refill the cache if not already */ 1563 error = devname_backstore_lookup(ddv, nm, &vp); 1564 if (error) 1565 continue; 1566 1567 vattr.va_mask = AT_MODE|AT_UID|AT_GID; 1568 error = VOP_GETATTR(vp, &vattr, 0, cred, NULL); 1569 if (error) 1570 continue; 1571 1572 if (vattr.va_type == VLNK) { 1573 error = sdev_getlink(vp, &link); 1574 if (error) { 1575 continue; 1576 } 1577 ASSERT(link != NULL); 1578 } 1579 1580 if (!rw_tryupgrade(&ddv->sdev_contents)) { 1581 rw_exit(&ddv->sdev_contents); 1582 rw_enter(&ddv->sdev_contents, RW_WRITER); 1583 } 1584 error = sdev_mknode(ddv, nm, &dv, &vattr, vp, link, 1585 cred, SDEV_READY); 1586 rw_downgrade(&ddv->sdev_contents); 1587 1588 if (link != NULL) { 1589 kmem_free(link, strlen(link) + 1); 1590 link = NULL; 1591 } 1592 1593 if (!error) { 1594 ASSERT(dv); 1595 ASSERT(dv->sdev_state != SDEV_ZOMBIE); 1596 SDEV_SIMPLE_RELE(dv); 1597 } 1598 vp = NULL; 1599 dv = NULL; 1600 } 1601 } 1602 1603 done: 1604 VN_RELE(dirvp); 1605 kmem_free(dbuf, dlen); 1606 1607 return (error); 1608 } 1609 1610 void 1611 sdev_filldir_dynamic(struct sdev_node *ddv) 1612 { 1613 int error; 1614 int i; 1615 struct vattr *vap; 1616 char *nm = NULL; 1617 struct sdev_node *dv = NULL; 1618 1619 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1620 ASSERT((ddv->sdev_flags & SDEV_BUILD)); 1621 1622 vap = sdev_getdefault_attr(VDIR); 1623 for (i = 0; vtab[i].vt_name != NULL; i++) { 1624 nm = vtab[i].vt_name; 1625 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1626 dv = NULL; 1627 error = sdev_mknode(ddv, nm, &dv, vap, NULL, 1628 NULL, kcred, SDEV_READY); 1629 if (error) { 1630 cmn_err(CE_WARN, "%s/%s: error %d\n", 1631 ddv->sdev_name, nm, error); 1632 } else { 1633 ASSERT(dv); 1634 ASSERT(dv->sdev_state != SDEV_ZOMBIE); 1635 SDEV_SIMPLE_RELE(dv); 1636 } 1637 } 1638 } 1639 1640 /* 1641 * Creating a backing store entry based on sdev_attr. 1642 * This is called either as part of node creation in a persistent directory 1643 * or from setattr/setsecattr to persist access attributes across reboot. 1644 */ 1645 int 1646 sdev_shadow_node(struct sdev_node *dv, struct cred *cred) 1647 { 1648 int error = 0; 1649 struct vnode *dvp = SDEVTOV(dv->sdev_dotdot); 1650 struct vnode *rdvp = VTOSDEV(dvp)->sdev_attrvp; 1651 struct vattr *vap = dv->sdev_attr; 1652 char *nm = dv->sdev_name; 1653 struct vnode *tmpvp, **rvp = &tmpvp, *rrvp = NULL; 1654 1655 ASSERT(dv && dv->sdev_name && rdvp); 1656 ASSERT(RW_WRITE_HELD(&dv->sdev_contents) && dv->sdev_attrvp == NULL); 1657 1658 lookup: 1659 /* try to find it in the backing store */ 1660 error = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, cred, NULL, NULL, 1661 NULL); 1662 if (error == 0) { 1663 if (VOP_REALVP(*rvp, &rrvp, NULL) == 0) { 1664 VN_HOLD(rrvp); 1665 VN_RELE(*rvp); 1666 *rvp = rrvp; 1667 } 1668 1669 kmem_free(dv->sdev_attr, sizeof (vattr_t)); 1670 dv->sdev_attr = NULL; 1671 dv->sdev_attrvp = *rvp; 1672 return (0); 1673 } 1674 1675 /* let's try to persist the node */ 1676 gethrestime(&vap->va_atime); 1677 vap->va_mtime = vap->va_atime; 1678 vap->va_ctime = vap->va_atime; 1679 vap->va_mask |= AT_TYPE|AT_MODE; 1680 switch (vap->va_type) { 1681 case VDIR: 1682 error = VOP_MKDIR(rdvp, nm, vap, rvp, cred, NULL, 0, NULL); 1683 sdcmn_err9(("sdev_shadow_node: mkdir vp %p error %d\n", 1684 (void *)(*rvp), error)); 1685 break; 1686 case VCHR: 1687 case VBLK: 1688 case VREG: 1689 case VDOOR: 1690 error = VOP_CREATE(rdvp, nm, vap, NONEXCL, VREAD|VWRITE, 1691 rvp, cred, 0, NULL, NULL); 1692 sdcmn_err9(("sdev_shadow_node: create vp %p, error %d\n", 1693 (void *)(*rvp), error)); 1694 if (!error) 1695 VN_RELE(*rvp); 1696 break; 1697 case VLNK: 1698 ASSERT(dv->sdev_symlink); 1699 error = VOP_SYMLINK(rdvp, nm, vap, dv->sdev_symlink, cred, 1700 NULL, 0); 1701 sdcmn_err9(("sdev_shadow_node: create symlink error %d\n", 1702 error)); 1703 break; 1704 default: 1705 cmn_err(CE_PANIC, "dev: %s: sdev_shadow_node " 1706 "create\n", nm); 1707 /*NOTREACHED*/ 1708 } 1709 1710 /* go back to lookup to factor out spec node and set attrvp */ 1711 if (error == 0) 1712 goto lookup; 1713 1714 sdcmn_err(("cannot persist %s - error %d\n", dv->sdev_path, error)); 1715 return (error); 1716 } 1717 1718 static int 1719 sdev_cache_add(struct sdev_node *ddv, struct sdev_node **dv, char *nm) 1720 { 1721 int error = 0; 1722 struct sdev_node *dup = NULL; 1723 1724 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1725 if ((dup = sdev_findbyname(ddv, nm)) == NULL) { 1726 sdev_direnter(ddv, *dv); 1727 } else { 1728 if (dup->sdev_state == SDEV_ZOMBIE) { 1729 error = sdev_dirdelete(ddv, dup); 1730 /* 1731 * The ZOMBIE node is still hanging 1732 * around with more than one reference counts. 1733 * Fail the new node creation so that 1734 * the directory cache won't have 1735 * duplicate entries for the same named node 1736 */ 1737 if (error == EBUSY) { 1738 SDEV_SIMPLE_RELE(*dv); 1739 sdev_nodedestroy(*dv, 0); 1740 *dv = NULL; 1741 return (error); 1742 } 1743 sdev_direnter(ddv, *dv); 1744 } else { 1745 ASSERT((*dv)->sdev_state != SDEV_ZOMBIE); 1746 SDEV_SIMPLE_RELE(*dv); 1747 sdev_nodedestroy(*dv, 0); 1748 *dv = dup; 1749 } 1750 } 1751 1752 return (0); 1753 } 1754 1755 static int 1756 sdev_cache_delete(struct sdev_node *ddv, struct sdev_node **dv) 1757 { 1758 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1759 return (sdev_dirdelete(ddv, *dv)); 1760 } 1761 1762 /* 1763 * update the in-core directory cache 1764 */ 1765 int 1766 sdev_cache_update(struct sdev_node *ddv, struct sdev_node **dv, char *nm, 1767 sdev_cache_ops_t ops) 1768 { 1769 int error = 0; 1770 1771 ASSERT((SDEV_HELD(*dv))); 1772 1773 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1774 switch (ops) { 1775 case SDEV_CACHE_ADD: 1776 error = sdev_cache_add(ddv, dv, nm); 1777 break; 1778 case SDEV_CACHE_DELETE: 1779 error = sdev_cache_delete(ddv, dv); 1780 break; 1781 default: 1782 break; 1783 } 1784 1785 return (error); 1786 } 1787 1788 /* 1789 * retrieve the named entry from the directory cache 1790 */ 1791 struct sdev_node * 1792 sdev_cache_lookup(struct sdev_node *ddv, char *nm) 1793 { 1794 struct sdev_node *dv = NULL; 1795 1796 ASSERT(RW_LOCK_HELD(&ddv->sdev_contents)); 1797 dv = sdev_findbyname(ddv, nm); 1798 1799 return (dv); 1800 } 1801 1802 /* 1803 * Implicit reconfig for nodes constructed by a link generator 1804 * Start devfsadm if needed, or if devfsadm is in progress, 1805 * prepare to block on devfsadm either completing or 1806 * constructing the desired node. As devfsadmd is global 1807 * in scope, constructing all necessary nodes, we only 1808 * need to initiate it once. 1809 */ 1810 static int 1811 sdev_call_devfsadmd(struct sdev_node *ddv, struct sdev_node *dv, char *nm) 1812 { 1813 int error = 0; 1814 1815 if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state)) { 1816 sdcmn_err6(("lookup: waiting for %s/%s, 0x%x\n", 1817 ddv->sdev_name, nm, devfsadm_state)); 1818 mutex_enter(&dv->sdev_lookup_lock); 1819 SDEV_BLOCK_OTHERS(dv, (SDEV_LOOKUP | SDEV_LGWAITING)); 1820 mutex_exit(&dv->sdev_lookup_lock); 1821 error = 0; 1822 } else if (!DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state)) { 1823 sdcmn_err6(("lookup %s/%s starting devfsadm, 0x%x\n", 1824 ddv->sdev_name, nm, devfsadm_state)); 1825 1826 sdev_devfsadmd_thread(ddv, dv, kcred); 1827 mutex_enter(&dv->sdev_lookup_lock); 1828 SDEV_BLOCK_OTHERS(dv, 1829 (SDEV_LOOKUP | SDEV_LGWAITING)); 1830 mutex_exit(&dv->sdev_lookup_lock); 1831 error = 0; 1832 } else { 1833 error = -1; 1834 } 1835 1836 return (error); 1837 } 1838 1839 static int 1840 sdev_call_modulelookup(struct sdev_node *ddv, struct sdev_node **dvp, char *nm, 1841 int (*fn)(char *, devname_handle_t *, struct cred *), struct cred *cred) 1842 { 1843 struct vnode *rvp = NULL; 1844 int error = 0; 1845 struct vattr *vap; 1846 devname_spec_t spec; 1847 devname_handle_t *hdl; 1848 void *args = NULL; 1849 struct sdev_node *dv = *dvp; 1850 1851 ASSERT(dv && ddv); 1852 hdl = &(dv->sdev_handle); 1853 ASSERT(hdl->dh_data == dv); 1854 mutex_enter(&dv->sdev_lookup_lock); 1855 SDEV_BLOCK_OTHERS(dv, SDEV_LOOKUP); 1856 mutex_exit(&dv->sdev_lookup_lock); 1857 error = (*fn)(nm, hdl, cred); 1858 if (error) { 1859 return (error); 1860 } 1861 1862 spec = hdl->dh_spec; 1863 args = hdl->dh_args; 1864 ASSERT(args); 1865 1866 switch (spec) { 1867 case DEVNAME_NS_PATH: 1868 /* 1869 * symlink of: 1870 * /dev/dir/nm -> /device/... 1871 */ 1872 rvp = devname_configure_by_path((char *)args, NULL); 1873 break; 1874 case DEVNAME_NS_DEV: 1875 /* 1876 * symlink of: 1877 * /dev/dir/nm -> /dev/... 1878 */ 1879 rvp = devname_find_by_devpath((char *)args, NULL); 1880 break; 1881 default: 1882 if (args) 1883 kmem_free((char *)args, strlen(args) + 1); 1884 return (ENOENT); 1885 1886 } 1887 1888 if (rvp == NULL) { 1889 if (args) 1890 kmem_free((char *)args, strlen(args) + 1); 1891 return (ENOENT); 1892 } else { 1893 vap = sdev_getdefault_attr(VLNK); 1894 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 1895 /* 1896 * Could sdev_mknode return a different dv_node 1897 * once the lock is dropped? 1898 */ 1899 if (!rw_tryupgrade(&ddv->sdev_contents)) { 1900 rw_exit(&ddv->sdev_contents); 1901 rw_enter(&ddv->sdev_contents, RW_WRITER); 1902 } 1903 error = sdev_mknode(ddv, nm, &dv, vap, NULL, args, cred, 1904 SDEV_READY); 1905 rw_downgrade(&ddv->sdev_contents); 1906 if (error) { 1907 if (args) 1908 kmem_free((char *)args, strlen(args) + 1); 1909 return (error); 1910 } else { 1911 mutex_enter(&dv->sdev_lookup_lock); 1912 SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP); 1913 mutex_exit(&dv->sdev_lookup_lock); 1914 error = 0; 1915 } 1916 } 1917 1918 if (args) 1919 kmem_free((char *)args, strlen(args) + 1); 1920 1921 *dvp = dv; 1922 return (0); 1923 } 1924 1925 /* 1926 * Support for specialized device naming construction mechanisms 1927 */ 1928 static int 1929 sdev_call_dircallback(struct sdev_node *ddv, struct sdev_node **dvp, char *nm, 1930 int (*callback)(struct sdev_node *, char *, void **, struct cred *, 1931 void *, char *), int flags, struct cred *cred) 1932 { 1933 int rv = 0; 1934 char *physpath = NULL; 1935 struct vnode *rvp = NULL; 1936 struct vattr vattr; 1937 struct vattr *vap; 1938 struct sdev_node *dv = *dvp; 1939 1940 mutex_enter(&dv->sdev_lookup_lock); 1941 SDEV_BLOCK_OTHERS(dv, SDEV_LOOKUP); 1942 mutex_exit(&dv->sdev_lookup_lock); 1943 1944 /* for non-devfsadm devices */ 1945 if (flags & SDEV_PATH) { 1946 physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1947 rv = callback(ddv, nm, (void *)&physpath, kcred, NULL, 1948 NULL); 1949 if (rv) { 1950 kmem_free(physpath, MAXPATHLEN); 1951 return (-1); 1952 } 1953 1954 ASSERT(physpath); 1955 rvp = devname_configure_by_path(physpath, NULL); 1956 if (rvp == NULL) { 1957 sdcmn_err3(("devname_configure_by_path: " 1958 "failed for /dev/%s/%s\n", 1959 ddv->sdev_name, nm)); 1960 kmem_free(physpath, MAXPATHLEN); 1961 rv = -1; 1962 } else { 1963 vap = sdev_getdefault_attr(VLNK); 1964 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 1965 1966 /* 1967 * Sdev_mknode may return back a different sdev_node 1968 * that was created by another thread that 1969 * raced to the directroy cache before this thread. 1970 * 1971 * With current directory cache mechanism 1972 * (linked list with the sdev_node name as 1973 * the entity key), this is a way to make sure 1974 * only one entry exists for the same name 1975 * in the same directory. The outcome is 1976 * the winner wins. 1977 */ 1978 if (!rw_tryupgrade(&ddv->sdev_contents)) { 1979 rw_exit(&ddv->sdev_contents); 1980 rw_enter(&ddv->sdev_contents, RW_WRITER); 1981 } 1982 rv = sdev_mknode(ddv, nm, &dv, vap, NULL, 1983 (void *)physpath, cred, SDEV_READY); 1984 rw_downgrade(&ddv->sdev_contents); 1985 kmem_free(physpath, MAXPATHLEN); 1986 if (rv) { 1987 return (rv); 1988 } else { 1989 mutex_enter(&dv->sdev_lookup_lock); 1990 SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP); 1991 mutex_exit(&dv->sdev_lookup_lock); 1992 return (0); 1993 } 1994 } 1995 } else if (flags & SDEV_VNODE) { 1996 /* 1997 * DBNR has its own way to create the device 1998 * and return a backing store vnode in rvp 1999 */ 2000 ASSERT(callback); 2001 rv = callback(ddv, nm, (void *)&rvp, kcred, NULL, NULL); 2002 if (rv || (rvp == NULL)) { 2003 sdcmn_err3(("devname_lookup_func: SDEV_VNODE " 2004 "callback failed \n")); 2005 return (-1); 2006 } 2007 vap = sdev_getdefault_attr(rvp->v_type); 2008 if (vap == NULL) 2009 return (-1); 2010 2011 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2012 if (!rw_tryupgrade(&ddv->sdev_contents)) { 2013 rw_exit(&ddv->sdev_contents); 2014 rw_enter(&ddv->sdev_contents, RW_WRITER); 2015 } 2016 rv = sdev_mknode(ddv, nm, &dv, vap, rvp, NULL, 2017 cred, SDEV_READY); 2018 rw_downgrade(&ddv->sdev_contents); 2019 if (rv) 2020 return (rv); 2021 2022 mutex_enter(&dv->sdev_lookup_lock); 2023 SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP); 2024 mutex_exit(&dv->sdev_lookup_lock); 2025 return (0); 2026 } else if (flags & SDEV_VATTR) { 2027 /* 2028 * /dev/pts 2029 * 2030 * DBNR has its own way to create the device 2031 * "0" is returned upon success. 2032 * 2033 * callback is responsible to set the basic attributes, 2034 * e.g. va_type/va_uid/va_gid/ 2035 * dev_t if VCHR or VBLK/ 2036 */ 2037 ASSERT(callback); 2038 rv = callback(ddv, nm, (void *)&vattr, kcred, NULL, NULL); 2039 if (rv) { 2040 sdcmn_err3(("devname_lookup_func: SDEV_NONE " 2041 "callback failed \n")); 2042 return (-1); 2043 } 2044 2045 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2046 if (!rw_tryupgrade(&ddv->sdev_contents)) { 2047 rw_exit(&ddv->sdev_contents); 2048 rw_enter(&ddv->sdev_contents, RW_WRITER); 2049 } 2050 rv = sdev_mknode(ddv, nm, &dv, &vattr, NULL, NULL, 2051 cred, SDEV_READY); 2052 rw_downgrade(&ddv->sdev_contents); 2053 2054 if (rv) 2055 return (rv); 2056 2057 mutex_enter(&dv->sdev_lookup_lock); 2058 SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP); 2059 mutex_exit(&dv->sdev_lookup_lock); 2060 return (0); 2061 } else { 2062 impossible(("lookup: %s/%s by %s not supported (%d)\n", 2063 SDEVTOV(ddv)->v_path, nm, curproc->p_user.u_comm, 2064 __LINE__)); 2065 rv = -1; 2066 } 2067 2068 *dvp = dv; 2069 return (rv); 2070 } 2071 2072 static int 2073 is_devfsadm_thread(char *exec_name) 2074 { 2075 /* 2076 * note: because devfsadmd -> /usr/sbin/devfsadm 2077 * it is safe to use "devfsadm" to capture the lookups 2078 * from devfsadm and its daemon version. 2079 */ 2080 if (strcmp(exec_name, "devfsadm") == 0) 2081 return (1); 2082 return (0); 2083 } 2084 2085 2086 /* 2087 * Lookup Order: 2088 * sdev_node cache; 2089 * backing store (SDEV_PERSIST); 2090 * DBNR: a. dir_ops implemented in the loadable modules; 2091 * b. vnode ops in vtab. 2092 */ 2093 int 2094 devname_lookup_func(struct sdev_node *ddv, char *nm, struct vnode **vpp, 2095 struct cred *cred, int (*callback)(struct sdev_node *, char *, void **, 2096 struct cred *, void *, char *), int flags) 2097 { 2098 int rv = 0, nmlen; 2099 struct vnode *rvp = NULL; 2100 struct sdev_node *dv = NULL; 2101 int retried = 0; 2102 int error = 0; 2103 struct devname_nsmap *map = NULL; 2104 struct devname_ops *dirops = NULL; 2105 int (*fn)(char *, devname_handle_t *, struct cred *) = NULL; 2106 struct vattr vattr; 2107 char *lookup_thread = curproc->p_user.u_comm; 2108 int failed_flags = 0; 2109 int (*vtor)(struct sdev_node *) = NULL; 2110 int state; 2111 int parent_state; 2112 char *link = NULL; 2113 2114 if (SDEVTOV(ddv)->v_type != VDIR) 2115 return (ENOTDIR); 2116 2117 /* 2118 * Empty name or ., return node itself. 2119 */ 2120 nmlen = strlen(nm); 2121 if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) { 2122 *vpp = SDEVTOV(ddv); 2123 VN_HOLD(*vpp); 2124 return (0); 2125 } 2126 2127 /* 2128 * .., return the parent directory 2129 */ 2130 if ((nmlen == 2) && (strcmp(nm, "..") == 0)) { 2131 *vpp = SDEVTOV(ddv->sdev_dotdot); 2132 VN_HOLD(*vpp); 2133 return (0); 2134 } 2135 2136 rw_enter(&ddv->sdev_contents, RW_READER); 2137 if (ddv->sdev_flags & SDEV_VTOR) { 2138 vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv); 2139 ASSERT(vtor); 2140 } 2141 2142 tryagain: 2143 /* 2144 * (a) directory cache lookup: 2145 */ 2146 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2147 parent_state = ddv->sdev_state; 2148 dv = sdev_cache_lookup(ddv, nm); 2149 if (dv) { 2150 state = dv->sdev_state; 2151 switch (state) { 2152 case SDEV_INIT: 2153 if (is_devfsadm_thread(lookup_thread)) 2154 break; 2155 2156 /* ZOMBIED parent won't allow node creation */ 2157 if (parent_state == SDEV_ZOMBIE) { 2158 SD_TRACE_FAILED_LOOKUP(ddv, nm, 2159 retried); 2160 goto nolock_notfound; 2161 } 2162 2163 mutex_enter(&dv->sdev_lookup_lock); 2164 /* compensate the threads started after devfsadm */ 2165 if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) && 2166 !(SDEV_IS_LOOKUP(dv))) 2167 SDEV_BLOCK_OTHERS(dv, 2168 (SDEV_LOOKUP | SDEV_LGWAITING)); 2169 2170 if (SDEV_IS_LOOKUP(dv)) { 2171 failed_flags |= SLF_REBUILT; 2172 rw_exit(&ddv->sdev_contents); 2173 error = sdev_wait4lookup(dv, SDEV_LOOKUP); 2174 mutex_exit(&dv->sdev_lookup_lock); 2175 rw_enter(&ddv->sdev_contents, RW_READER); 2176 2177 if (error != 0) { 2178 SD_TRACE_FAILED_LOOKUP(ddv, nm, 2179 retried); 2180 goto nolock_notfound; 2181 } 2182 2183 state = dv->sdev_state; 2184 if (state == SDEV_INIT) { 2185 SD_TRACE_FAILED_LOOKUP(ddv, nm, 2186 retried); 2187 goto nolock_notfound; 2188 } else if (state == SDEV_READY) { 2189 goto found; 2190 } else if (state == SDEV_ZOMBIE) { 2191 rw_exit(&ddv->sdev_contents); 2192 SD_TRACE_FAILED_LOOKUP(ddv, nm, 2193 retried); 2194 SDEV_RELE(dv); 2195 goto lookup_failed; 2196 } 2197 } else { 2198 mutex_exit(&dv->sdev_lookup_lock); 2199 } 2200 break; 2201 case SDEV_READY: 2202 goto found; 2203 case SDEV_ZOMBIE: 2204 rw_exit(&ddv->sdev_contents); 2205 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2206 SDEV_RELE(dv); 2207 goto lookup_failed; 2208 default: 2209 rw_exit(&ddv->sdev_contents); 2210 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2211 sdev_lookup_failed(ddv, nm, failed_flags); 2212 *vpp = NULLVP; 2213 return (ENOENT); 2214 } 2215 } 2216 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2217 2218 /* 2219 * ZOMBIED parent does not allow new node creation. 2220 * bail out early 2221 */ 2222 if (parent_state == SDEV_ZOMBIE) { 2223 rw_exit(&ddv->sdev_contents); 2224 *vpp = NULL; 2225 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2226 return (ENOENT); 2227 } 2228 2229 /* 2230 * (b0): backing store lookup 2231 * SDEV_PERSIST is default except: 2232 * 1) pts nodes 2233 * 2) non-chmod'ed local nodes 2234 */ 2235 if (SDEV_IS_PERSIST(ddv)) { 2236 error = devname_backstore_lookup(ddv, nm, &rvp); 2237 2238 if (!error) { 2239 sdcmn_err3(("devname_backstore_lookup: " 2240 "found attrvp %p for %s\n", (void *)rvp, nm)); 2241 2242 vattr.va_mask = AT_MODE|AT_UID|AT_GID; 2243 error = VOP_GETATTR(rvp, &vattr, 0, cred, NULL); 2244 if (error) { 2245 rw_exit(&ddv->sdev_contents); 2246 if (dv) 2247 SDEV_RELE(dv); 2248 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2249 sdev_lookup_failed(ddv, nm, failed_flags); 2250 *vpp = NULLVP; 2251 return (ENOENT); 2252 } 2253 2254 if (vattr.va_type == VLNK) { 2255 error = sdev_getlink(rvp, &link); 2256 if (error) { 2257 rw_exit(&ddv->sdev_contents); 2258 if (dv) 2259 SDEV_RELE(dv); 2260 SD_TRACE_FAILED_LOOKUP(ddv, nm, 2261 retried); 2262 sdev_lookup_failed(ddv, nm, 2263 failed_flags); 2264 *vpp = NULLVP; 2265 return (ENOENT); 2266 } 2267 ASSERT(link != NULL); 2268 } 2269 2270 if (!rw_tryupgrade(&ddv->sdev_contents)) { 2271 rw_exit(&ddv->sdev_contents); 2272 rw_enter(&ddv->sdev_contents, RW_WRITER); 2273 } 2274 error = sdev_mknode(ddv, nm, &dv, &vattr, 2275 rvp, link, cred, SDEV_READY); 2276 rw_downgrade(&ddv->sdev_contents); 2277 2278 if (link != NULL) { 2279 kmem_free(link, strlen(link) + 1); 2280 link = NULL; 2281 } 2282 2283 if (error) { 2284 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2285 rw_exit(&ddv->sdev_contents); 2286 if (dv) 2287 SDEV_RELE(dv); 2288 goto lookup_failed; 2289 } else { 2290 goto found; 2291 } 2292 } else if (retried) { 2293 rw_exit(&ddv->sdev_contents); 2294 sdcmn_err3(("retry of lookup of %s/%s: failed\n", 2295 ddv->sdev_name, nm)); 2296 if (dv) 2297 SDEV_RELE(dv); 2298 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2299 sdev_lookup_failed(ddv, nm, failed_flags); 2300 *vpp = NULLVP; 2301 return (ENOENT); 2302 } 2303 } 2304 2305 2306 /* first thread that is doing the lookup on this node */ 2307 if (!dv) { 2308 if (!rw_tryupgrade(&ddv->sdev_contents)) { 2309 rw_exit(&ddv->sdev_contents); 2310 rw_enter(&ddv->sdev_contents, RW_WRITER); 2311 } 2312 error = sdev_mknode(ddv, nm, &dv, NULL, NULL, NULL, 2313 cred, SDEV_INIT); 2314 if (!dv) { 2315 rw_exit(&ddv->sdev_contents); 2316 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2317 sdev_lookup_failed(ddv, nm, failed_flags); 2318 *vpp = NULLVP; 2319 return (ENOENT); 2320 } 2321 rw_downgrade(&ddv->sdev_contents); 2322 } 2323 ASSERT(dv); 2324 ASSERT(SDEV_HELD(dv)); 2325 2326 if (SDEV_IS_NO_NCACHE(dv)) { 2327 failed_flags |= SLF_NO_NCACHE; 2328 } 2329 2330 if (SDEV_IS_GLOBAL(ddv)) { 2331 map = sdev_get_map(ddv, 1); 2332 dirops = map ? map->dir_ops : NULL; 2333 fn = dirops ? dirops->devnops_lookup : NULL; 2334 } 2335 2336 /* 2337 * (b1) invoking devfsadm once per life time for devfsadm nodes 2338 */ 2339 if ((fn == NULL) && !callback) { 2340 2341 if (sdev_reconfig_boot || !i_ddi_io_initialized() || 2342 SDEV_IS_DYNAMIC(ddv) || SDEV_IS_NO_NCACHE(dv) || 2343 ((moddebug & MODDEBUG_FINI_EBUSY) != 0)) { 2344 ASSERT(SDEV_HELD(dv)); 2345 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2346 goto nolock_notfound; 2347 } 2348 2349 /* 2350 * filter out known non-existent devices recorded 2351 * during initial reconfiguration boot for which 2352 * reconfig should not be done and lookup may 2353 * be short-circuited now. 2354 */ 2355 if (sdev_lookup_filter(ddv, nm)) { 2356 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2357 goto nolock_notfound; 2358 } 2359 2360 /* bypassing devfsadm internal nodes */ 2361 if (is_devfsadm_thread(lookup_thread)) { 2362 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2363 goto nolock_notfound; 2364 } 2365 2366 if (sdev_reconfig_disable) { 2367 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2368 goto nolock_notfound; 2369 } 2370 2371 error = sdev_call_devfsadmd(ddv, dv, nm); 2372 if (error == 0) { 2373 sdcmn_err8(("lookup of %s/%s by %s: reconfig\n", 2374 ddv->sdev_name, nm, curproc->p_user.u_comm)); 2375 if (sdev_reconfig_verbose) { 2376 cmn_err(CE_CONT, 2377 "?lookup of %s/%s by %s: reconfig\n", 2378 ddv->sdev_name, nm, curproc->p_user.u_comm); 2379 } 2380 retried = 1; 2381 failed_flags |= SLF_REBUILT; 2382 ASSERT(dv->sdev_state != SDEV_ZOMBIE); 2383 SDEV_SIMPLE_RELE(dv); 2384 goto tryagain; 2385 } else { 2386 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2387 goto nolock_notfound; 2388 } 2389 } 2390 2391 /* 2392 * (b2) Directory Based Name Resolution (DBNR): 2393 * ddv - parent 2394 * nm - /dev/(ddv->sdev_name)/nm 2395 * 2396 * note: module vnode ops take precedence than the build-in ones 2397 */ 2398 if (fn) { 2399 error = sdev_call_modulelookup(ddv, &dv, nm, fn, cred); 2400 if (error) { 2401 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2402 goto notfound; 2403 } else { 2404 goto found; 2405 } 2406 } else if (callback) { 2407 error = sdev_call_dircallback(ddv, &dv, nm, callback, 2408 flags, cred); 2409 if (error == 0) { 2410 goto found; 2411 } else { 2412 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2413 goto notfound; 2414 } 2415 } 2416 ASSERT(rvp); 2417 2418 found: 2419 ASSERT(!(dv->sdev_flags & SDEV_STALE)); 2420 ASSERT(dv->sdev_state == SDEV_READY); 2421 if (vtor) { 2422 /* 2423 * Check validity of returned node 2424 */ 2425 switch (vtor(dv)) { 2426 case SDEV_VTOR_VALID: 2427 break; 2428 case SDEV_VTOR_INVALID: 2429 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2430 sdcmn_err7(("lookup: destroy invalid " 2431 "node: %s(%p)\n", dv->sdev_name, (void *)dv)); 2432 goto nolock_notfound; 2433 case SDEV_VTOR_SKIP: 2434 sdcmn_err7(("lookup: node not applicable - " 2435 "skipping: %s(%p)\n", dv->sdev_name, (void *)dv)); 2436 rw_exit(&ddv->sdev_contents); 2437 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2438 SDEV_RELE(dv); 2439 goto lookup_failed; 2440 default: 2441 cmn_err(CE_PANIC, 2442 "dev fs: validator failed: %s(%p)\n", 2443 dv->sdev_name, (void *)dv); 2444 break; 2445 /*NOTREACHED*/ 2446 } 2447 } 2448 2449 if ((SDEVTOV(dv)->v_type == VDIR) && SDEV_IS_GLOBAL(dv)) { 2450 rw_enter(&dv->sdev_contents, RW_READER); 2451 (void) sdev_get_map(dv, 1); 2452 rw_exit(&dv->sdev_contents); 2453 } 2454 rw_exit(&ddv->sdev_contents); 2455 rv = sdev_to_vp(dv, vpp); 2456 sdcmn_err3(("devname_lookup_func: returning vp %p v_count %d state %d " 2457 "for nm %s, error %d\n", (void *)*vpp, (*vpp)->v_count, 2458 dv->sdev_state, nm, rv)); 2459 return (rv); 2460 2461 notfound: 2462 mutex_enter(&dv->sdev_lookup_lock); 2463 SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP); 2464 mutex_exit(&dv->sdev_lookup_lock); 2465 nolock_notfound: 2466 /* 2467 * Destroy the node that is created for synchronization purposes. 2468 */ 2469 sdcmn_err3(("devname_lookup_func: %s with state %d\n", 2470 nm, dv->sdev_state)); 2471 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2472 if (dv->sdev_state == SDEV_INIT) { 2473 if (!rw_tryupgrade(&ddv->sdev_contents)) { 2474 rw_exit(&ddv->sdev_contents); 2475 rw_enter(&ddv->sdev_contents, RW_WRITER); 2476 } 2477 2478 /* 2479 * Node state may have changed during the lock 2480 * changes. Re-check. 2481 */ 2482 if (dv->sdev_state == SDEV_INIT) { 2483 (void) sdev_dirdelete(ddv, dv); 2484 rw_exit(&ddv->sdev_contents); 2485 sdev_lookup_failed(ddv, nm, failed_flags); 2486 *vpp = NULL; 2487 return (ENOENT); 2488 } 2489 } 2490 2491 rw_exit(&ddv->sdev_contents); 2492 SDEV_RELE(dv); 2493 2494 lookup_failed: 2495 sdev_lookup_failed(ddv, nm, failed_flags); 2496 *vpp = NULL; 2497 return (ENOENT); 2498 } 2499 2500 /* 2501 * Given a directory node, mark all nodes beneath as 2502 * STALE, i.e. nodes that don't exist as far as new 2503 * consumers are concerned. Remove them from the 2504 * list of directory entries so that no lookup or 2505 * directory traversal will find them. The node 2506 * not deallocated so existing holds are not affected. 2507 */ 2508 void 2509 sdev_stale(struct sdev_node *ddv) 2510 { 2511 struct sdev_node *dv; 2512 struct vnode *vp; 2513 2514 ASSERT(SDEVTOV(ddv)->v_type == VDIR); 2515 2516 rw_enter(&ddv->sdev_contents, RW_WRITER); 2517 for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = SDEV_NEXT_ENTRY(ddv, dv)) { 2518 vp = SDEVTOV(dv); 2519 if (vp->v_type == VDIR) 2520 sdev_stale(dv); 2521 2522 sdcmn_err9(("sdev_stale: setting stale %s\n", 2523 dv->sdev_path)); 2524 dv->sdev_flags |= SDEV_STALE; 2525 avl_remove(&ddv->sdev_entries, dv); 2526 } 2527 ddv->sdev_flags |= SDEV_BUILD; 2528 rw_exit(&ddv->sdev_contents); 2529 } 2530 2531 /* 2532 * Given a directory node, clean out all the nodes beneath. 2533 * If expr is specified, clean node with names matching expr. 2534 * If SDEV_ENFORCE is specified in flags, busy nodes are made stale, 2535 * so they are excluded from future lookups. 2536 */ 2537 int 2538 sdev_cleandir(struct sdev_node *ddv, char *expr, uint_t flags) 2539 { 2540 int error = 0; 2541 int busy = 0; 2542 struct vnode *vp; 2543 struct sdev_node *dv, *next = NULL; 2544 int bkstore = 0; 2545 int len = 0; 2546 char *bks_name = NULL; 2547 2548 ASSERT(SDEVTOV(ddv)->v_type == VDIR); 2549 2550 /* 2551 * We try our best to destroy all unused sdev_node's 2552 */ 2553 rw_enter(&ddv->sdev_contents, RW_WRITER); 2554 for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) { 2555 next = SDEV_NEXT_ENTRY(ddv, dv); 2556 vp = SDEVTOV(dv); 2557 2558 if (expr && gmatch(dv->sdev_name, expr) == 0) 2559 continue; 2560 2561 if (vp->v_type == VDIR && 2562 sdev_cleandir(dv, NULL, flags) != 0) { 2563 sdcmn_err9(("sdev_cleandir: dir %s busy\n", 2564 dv->sdev_name)); 2565 busy++; 2566 continue; 2567 } 2568 2569 if (vp->v_count > 0 && (flags & SDEV_ENFORCE) == 0) { 2570 sdcmn_err9(("sdev_cleandir: dir %s busy\n", 2571 dv->sdev_name)); 2572 busy++; 2573 continue; 2574 } 2575 2576 /* 2577 * at this point, either dv is not held or SDEV_ENFORCE 2578 * is specified. In either case, dv needs to be deleted 2579 */ 2580 SDEV_HOLD(dv); 2581 2582 bkstore = SDEV_IS_PERSIST(dv) ? 1 : 0; 2583 if (bkstore && (vp->v_type == VDIR)) 2584 bkstore += 1; 2585 2586 if (bkstore) { 2587 len = strlen(dv->sdev_name) + 1; 2588 bks_name = kmem_alloc(len, KM_SLEEP); 2589 bcopy(dv->sdev_name, bks_name, len); 2590 } 2591 2592 error = sdev_dirdelete(ddv, dv); 2593 2594 if (error == EBUSY) { 2595 sdcmn_err9(("sdev_cleandir: dir busy\n")); 2596 busy++; 2597 } 2598 2599 /* take care the backing store clean up */ 2600 if (bkstore && (error == 0)) { 2601 ASSERT(bks_name); 2602 ASSERT(ddv->sdev_attrvp); 2603 2604 if (bkstore == 1) { 2605 error = VOP_REMOVE(ddv->sdev_attrvp, 2606 bks_name, kcred, NULL, 0); 2607 } else if (bkstore == 2) { 2608 error = VOP_RMDIR(ddv->sdev_attrvp, 2609 bks_name, ddv->sdev_attrvp, kcred, NULL, 0); 2610 } 2611 2612 /* do not propagate the backing store errors */ 2613 if (error) { 2614 sdcmn_err9(("sdev_cleandir: backing store" 2615 "not cleaned\n")); 2616 error = 0; 2617 } 2618 2619 bkstore = 0; 2620 kmem_free(bks_name, len); 2621 bks_name = NULL; 2622 len = 0; 2623 } 2624 } 2625 2626 ddv->sdev_flags |= SDEV_BUILD; 2627 rw_exit(&ddv->sdev_contents); 2628 2629 if (busy) { 2630 error = EBUSY; 2631 } 2632 2633 return (error); 2634 } 2635 2636 /* 2637 * a convenient wrapper for readdir() funcs 2638 */ 2639 size_t 2640 add_dir_entry(dirent64_t *de, char *nm, size_t size, ino_t ino, offset_t off) 2641 { 2642 size_t reclen = DIRENT64_RECLEN(strlen(nm)); 2643 if (reclen > size) 2644 return (0); 2645 2646 de->d_ino = (ino64_t)ino; 2647 de->d_off = (off64_t)off + 1; 2648 de->d_reclen = (ushort_t)reclen; 2649 (void) strncpy(de->d_name, nm, DIRENT64_NAMELEN(reclen)); 2650 return (reclen); 2651 } 2652 2653 /* 2654 * sdev_mount service routines 2655 */ 2656 int 2657 sdev_copyin_mountargs(struct mounta *uap, struct sdev_mountargs *args) 2658 { 2659 int error; 2660 2661 if (uap->datalen != sizeof (*args)) 2662 return (EINVAL); 2663 2664 if (error = copyin(uap->dataptr, args, sizeof (*args))) { 2665 cmn_err(CE_WARN, "sdev_copyin_mountargs: can not" 2666 "get user data. error %d\n", error); 2667 return (EFAULT); 2668 } 2669 2670 return (0); 2671 } 2672 2673 #ifdef nextdp 2674 #undef nextdp 2675 #endif 2676 #define nextdp(dp) ((struct dirent64 *) \ 2677 (intptr_t)((char *)(dp) + (dp)->d_reclen)) 2678 2679 /* 2680 * readdir helper func 2681 */ 2682 int 2683 devname_readdir_func(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp, 2684 int flags) 2685 { 2686 struct sdev_node *ddv = VTOSDEV(vp); 2687 struct sdev_node *dv; 2688 dirent64_t *dp; 2689 ulong_t outcount = 0; 2690 size_t namelen; 2691 ulong_t alloc_count; 2692 void *outbuf; 2693 struct iovec *iovp; 2694 int error = 0; 2695 size_t reclen; 2696 offset_t diroff; 2697 offset_t soff; 2698 int this_reclen; 2699 struct devname_nsmap *map = NULL; 2700 struct devname_ops *dirops = NULL; 2701 int (*fn)(devname_handle_t *, struct cred *) = NULL; 2702 int (*vtor)(struct sdev_node *) = NULL; 2703 struct vattr attr; 2704 timestruc_t now; 2705 2706 ASSERT(ddv->sdev_attr || ddv->sdev_attrvp); 2707 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2708 2709 if (uiop->uio_loffset >= MAXOFF_T) { 2710 if (eofp) 2711 *eofp = 1; 2712 return (0); 2713 } 2714 2715 if (uiop->uio_iovcnt != 1) 2716 return (EINVAL); 2717 2718 if (vp->v_type != VDIR) 2719 return (ENOTDIR); 2720 2721 if (ddv->sdev_flags & SDEV_VTOR) { 2722 vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv); 2723 ASSERT(vtor); 2724 } 2725 2726 if (eofp != NULL) 2727 *eofp = 0; 2728 2729 soff = uiop->uio_loffset; 2730 iovp = uiop->uio_iov; 2731 alloc_count = iovp->iov_len; 2732 dp = outbuf = kmem_alloc(alloc_count, KM_SLEEP); 2733 outcount = 0; 2734 2735 if (ddv->sdev_state == SDEV_ZOMBIE) 2736 goto get_cache; 2737 2738 if (SDEV_IS_GLOBAL(ddv)) { 2739 map = sdev_get_map(ddv, 0); 2740 dirops = map ? map->dir_ops : NULL; 2741 fn = dirops ? dirops->devnops_readdir : NULL; 2742 2743 if (map && map->dir_map) { 2744 /* 2745 * load the name mapping rule database 2746 * through invoking devfsadm and symlink 2747 * all the entries in the map 2748 */ 2749 devname_rdr_result_t rdr_result; 2750 int do_thread = 0; 2751 2752 rw_enter(&map->dir_lock, RW_READER); 2753 do_thread = map->dir_maploaded ? 0 : 1; 2754 rw_exit(&map->dir_lock); 2755 2756 if (do_thread) { 2757 mutex_enter(&ddv->sdev_lookup_lock); 2758 SDEV_BLOCK_OTHERS(ddv, SDEV_READDIR); 2759 mutex_exit(&ddv->sdev_lookup_lock); 2760 2761 sdev_dispatch_to_nsrdr_thread(ddv, 2762 map->dir_map, &rdr_result); 2763 } 2764 } else if ((sdev_boot_state == SDEV_BOOT_STATE_COMPLETE) && 2765 !sdev_reconfig_boot && (flags & SDEV_BROWSE) && 2766 !SDEV_IS_DYNAMIC(ddv) && !SDEV_IS_NO_NCACHE(ddv) && 2767 ((moddebug & MODDEBUG_FINI_EBUSY) == 0) && 2768 !DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state) && 2769 !DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) && 2770 !sdev_reconfig_disable) { 2771 /* 2772 * invoking "devfsadm" to do system device reconfig 2773 */ 2774 mutex_enter(&ddv->sdev_lookup_lock); 2775 SDEV_BLOCK_OTHERS(ddv, 2776 (SDEV_READDIR|SDEV_LGWAITING)); 2777 mutex_exit(&ddv->sdev_lookup_lock); 2778 2779 sdcmn_err8(("readdir of %s by %s: reconfig\n", 2780 ddv->sdev_path, curproc->p_user.u_comm)); 2781 if (sdev_reconfig_verbose) { 2782 cmn_err(CE_CONT, 2783 "?readdir of %s by %s: reconfig\n", 2784 ddv->sdev_path, curproc->p_user.u_comm); 2785 } 2786 2787 sdev_devfsadmd_thread(ddv, NULL, kcred); 2788 } else if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state)) { 2789 /* 2790 * compensate the "ls" started later than "devfsadm" 2791 */ 2792 mutex_enter(&ddv->sdev_lookup_lock); 2793 SDEV_BLOCK_OTHERS(ddv, (SDEV_READDIR|SDEV_LGWAITING)); 2794 mutex_exit(&ddv->sdev_lookup_lock); 2795 } 2796 2797 /* 2798 * release the contents lock so that 2799 * the cache may be updated by devfsadmd 2800 */ 2801 rw_exit(&ddv->sdev_contents); 2802 mutex_enter(&ddv->sdev_lookup_lock); 2803 if (SDEV_IS_READDIR(ddv)) 2804 (void) sdev_wait4lookup(ddv, SDEV_READDIR); 2805 mutex_exit(&ddv->sdev_lookup_lock); 2806 rw_enter(&ddv->sdev_contents, RW_READER); 2807 2808 sdcmn_err4(("readdir of directory %s by %s\n", 2809 ddv->sdev_name, curproc->p_user.u_comm)); 2810 if (ddv->sdev_flags & SDEV_BUILD) { 2811 if (SDEV_IS_PERSIST(ddv)) { 2812 error = sdev_filldir_from_store(ddv, 2813 alloc_count, cred); 2814 } 2815 ddv->sdev_flags &= ~SDEV_BUILD; 2816 } 2817 } 2818 2819 get_cache: 2820 /* handle "." and ".." */ 2821 diroff = 0; 2822 if (soff == 0) { 2823 /* first time */ 2824 this_reclen = DIRENT64_RECLEN(1); 2825 if (alloc_count < this_reclen) { 2826 error = EINVAL; 2827 goto done; 2828 } 2829 2830 dp->d_ino = (ino64_t)ddv->sdev_ino; 2831 dp->d_off = (off64_t)1; 2832 dp->d_reclen = (ushort_t)this_reclen; 2833 2834 (void) strncpy(dp->d_name, ".", 2835 DIRENT64_NAMELEN(this_reclen)); 2836 outcount += dp->d_reclen; 2837 dp = nextdp(dp); 2838 } 2839 2840 diroff++; 2841 if (soff <= 1) { 2842 this_reclen = DIRENT64_RECLEN(2); 2843 if (alloc_count < outcount + this_reclen) { 2844 error = EINVAL; 2845 goto done; 2846 } 2847 2848 dp->d_reclen = (ushort_t)this_reclen; 2849 dp->d_ino = (ino64_t)ddv->sdev_dotdot->sdev_ino; 2850 dp->d_off = (off64_t)2; 2851 2852 (void) strncpy(dp->d_name, "..", 2853 DIRENT64_NAMELEN(this_reclen)); 2854 outcount += dp->d_reclen; 2855 2856 dp = nextdp(dp); 2857 } 2858 2859 2860 /* gets the cache */ 2861 diroff++; 2862 for (dv = SDEV_FIRST_ENTRY(ddv); dv; 2863 dv = SDEV_NEXT_ENTRY(ddv, dv), diroff++) { 2864 sdcmn_err3(("sdev_readdir: diroff %lld soff %lld for '%s' \n", 2865 diroff, soff, dv->sdev_name)); 2866 2867 /* bypassing pre-matured nodes */ 2868 if (diroff < soff || (dv->sdev_state != SDEV_READY)) { 2869 sdcmn_err3(("sdev_readdir: pre-mature node " 2870 "%s\n", dv->sdev_name)); 2871 continue; 2872 } 2873 2874 /* 2875 * Check validity of node 2876 */ 2877 if (vtor) { 2878 switch (vtor(dv)) { 2879 case SDEV_VTOR_VALID: 2880 break; 2881 case SDEV_VTOR_INVALID: 2882 case SDEV_VTOR_SKIP: 2883 continue; 2884 default: 2885 cmn_err(CE_PANIC, 2886 "dev fs: validator failed: %s(%p)\n", 2887 dv->sdev_name, (void *)dv); 2888 break; 2889 /*NOTREACHED*/ 2890 } 2891 } 2892 2893 /* 2894 * call back into the module for the validity/bookkeeping 2895 * of this entry 2896 */ 2897 if (fn) { 2898 error = (*fn)(&(dv->sdev_handle), cred); 2899 if (error) { 2900 sdcmn_err4(("sdev_readdir: module did not " 2901 "validate %s\n", dv->sdev_name)); 2902 continue; 2903 } 2904 } 2905 2906 namelen = strlen(dv->sdev_name); 2907 reclen = DIRENT64_RECLEN(namelen); 2908 if (outcount + reclen > alloc_count) { 2909 goto full; 2910 } 2911 dp->d_reclen = (ushort_t)reclen; 2912 dp->d_ino = (ino64_t)dv->sdev_ino; 2913 dp->d_off = (off64_t)diroff + 1; 2914 (void) strncpy(dp->d_name, dv->sdev_name, 2915 DIRENT64_NAMELEN(reclen)); 2916 outcount += reclen; 2917 dp = nextdp(dp); 2918 } 2919 2920 full: 2921 sdcmn_err4(("sdev_readdir: moving %lu bytes: " 2922 "diroff %lld, soff %lld, dv %p\n", outcount, diroff, soff, 2923 (void *)dv)); 2924 2925 if (outcount) 2926 error = uiomove(outbuf, outcount, UIO_READ, uiop); 2927 2928 if (!error) { 2929 uiop->uio_loffset = diroff; 2930 if (eofp) 2931 *eofp = dv ? 0 : 1; 2932 } 2933 2934 2935 if (ddv->sdev_attrvp) { 2936 gethrestime(&now); 2937 attr.va_ctime = now; 2938 attr.va_atime = now; 2939 attr.va_mask = AT_CTIME|AT_ATIME; 2940 2941 (void) VOP_SETATTR(ddv->sdev_attrvp, &attr, 0, kcred, NULL); 2942 } 2943 done: 2944 kmem_free(outbuf, alloc_count); 2945 return (error); 2946 } 2947 2948 2949 static int 2950 sdev_modctl_lookup(const char *path, vnode_t **r_vp) 2951 { 2952 vnode_t *vp; 2953 vnode_t *cvp; 2954 struct sdev_node *svp; 2955 char *nm; 2956 struct pathname pn; 2957 int error; 2958 int persisted = 0; 2959 2960 if (error = pn_get((char *)path, UIO_SYSSPACE, &pn)) 2961 return (error); 2962 nm = kmem_alloc(MAXNAMELEN, KM_SLEEP); 2963 2964 vp = rootdir; 2965 VN_HOLD(vp); 2966 2967 while (pn_pathleft(&pn)) { 2968 ASSERT(vp->v_type == VDIR); 2969 (void) pn_getcomponent(&pn, nm); 2970 error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred, NULL, 2971 NULL, NULL); 2972 VN_RELE(vp); 2973 2974 if (error) 2975 break; 2976 2977 /* traverse mount points encountered on our journey */ 2978 if (vn_ismntpt(cvp) && (error = traverse(&cvp)) != 0) { 2979 VN_RELE(cvp); 2980 break; 2981 } 2982 2983 /* 2984 * Direct the operation to the persisting filesystem 2985 * underlying /dev. Bail if we encounter a 2986 * non-persistent dev entity here. 2987 */ 2988 if (cvp->v_vfsp->vfs_fstype == devtype) { 2989 2990 if ((VTOSDEV(cvp)->sdev_flags & SDEV_PERSIST) == 0) { 2991 error = ENOENT; 2992 VN_RELE(cvp); 2993 break; 2994 } 2995 2996 if (VTOSDEV(cvp) == NULL) { 2997 error = ENOENT; 2998 VN_RELE(cvp); 2999 break; 3000 } 3001 svp = VTOSDEV(cvp); 3002 if ((vp = svp->sdev_attrvp) == NULL) { 3003 error = ENOENT; 3004 VN_RELE(cvp); 3005 break; 3006 } 3007 persisted = 1; 3008 VN_HOLD(vp); 3009 VN_RELE(cvp); 3010 cvp = vp; 3011 } 3012 3013 vp = cvp; 3014 pn_skipslash(&pn); 3015 } 3016 3017 kmem_free(nm, MAXNAMELEN); 3018 pn_free(&pn); 3019 3020 if (error) 3021 return (error); 3022 3023 /* 3024 * Only return persisted nodes in the filesystem underlying /dev. 3025 */ 3026 if (!persisted) { 3027 VN_RELE(vp); 3028 return (ENOENT); 3029 } 3030 3031 *r_vp = vp; 3032 return (0); 3033 } 3034 3035 int 3036 sdev_modctl_readdir(const char *dir, char ***dirlistp, 3037 int *npathsp, int *npathsp_alloc, int checking_empty) 3038 { 3039 char **pathlist = NULL; 3040 char **newlist = NULL; 3041 int npaths = 0; 3042 int npaths_alloc = 0; 3043 dirent64_t *dbuf = NULL; 3044 int n; 3045 char *s; 3046 int error; 3047 vnode_t *vp; 3048 int eof; 3049 struct iovec iov; 3050 struct uio uio; 3051 struct dirent64 *dp; 3052 size_t dlen; 3053 size_t dbuflen; 3054 int ndirents = 64; 3055 char *nm; 3056 3057 error = sdev_modctl_lookup(dir, &vp); 3058 sdcmn_err11(("modctl readdir: %s by %s: %s\n", 3059 dir, curproc->p_user.u_comm, 3060 (error == 0) ? "ok" : "failed")); 3061 if (error) 3062 return (error); 3063 3064 dlen = ndirents * (sizeof (*dbuf)); 3065 dbuf = kmem_alloc(dlen, KM_SLEEP); 3066 3067 uio.uio_iov = &iov; 3068 uio.uio_iovcnt = 1; 3069 uio.uio_segflg = UIO_SYSSPACE; 3070 uio.uio_fmode = 0; 3071 uio.uio_extflg = UIO_COPY_CACHED; 3072 uio.uio_loffset = 0; 3073 uio.uio_llimit = MAXOFFSET_T; 3074 3075 eof = 0; 3076 error = 0; 3077 while (!error && !eof) { 3078 uio.uio_resid = dlen; 3079 iov.iov_base = (char *)dbuf; 3080 iov.iov_len = dlen; 3081 3082 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 3083 error = VOP_READDIR(vp, &uio, kcred, &eof, NULL, 0); 3084 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3085 3086 dbuflen = dlen - uio.uio_resid; 3087 3088 if (error || dbuflen == 0) 3089 break; 3090 3091 for (dp = dbuf; ((intptr_t)dp < (intptr_t)dbuf + dbuflen); 3092 dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) { 3093 3094 nm = dp->d_name; 3095 3096 if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0) 3097 continue; 3098 if (npaths == npaths_alloc) { 3099 npaths_alloc += 64; 3100 newlist = (char **) 3101 kmem_zalloc((npaths_alloc + 1) * 3102 sizeof (char *), KM_SLEEP); 3103 if (pathlist) { 3104 bcopy(pathlist, newlist, 3105 npaths * sizeof (char *)); 3106 kmem_free(pathlist, 3107 (npaths + 1) * sizeof (char *)); 3108 } 3109 pathlist = newlist; 3110 } 3111 n = strlen(nm) + 1; 3112 s = kmem_alloc(n, KM_SLEEP); 3113 bcopy(nm, s, n); 3114 pathlist[npaths++] = s; 3115 sdcmn_err11((" %s/%s\n", dir, s)); 3116 3117 /* if checking empty, one entry is as good as many */ 3118 if (checking_empty) { 3119 eof = 1; 3120 break; 3121 } 3122 } 3123 } 3124 3125 exit: 3126 VN_RELE(vp); 3127 3128 if (dbuf) 3129 kmem_free(dbuf, dlen); 3130 3131 if (error) 3132 return (error); 3133 3134 *dirlistp = pathlist; 3135 *npathsp = npaths; 3136 *npathsp_alloc = npaths_alloc; 3137 3138 return (0); 3139 } 3140 3141 void 3142 sdev_modctl_readdir_free(char **pathlist, int npaths, int npaths_alloc) 3143 { 3144 int i, n; 3145 3146 for (i = 0; i < npaths; i++) { 3147 n = strlen(pathlist[i]) + 1; 3148 kmem_free(pathlist[i], n); 3149 } 3150 3151 kmem_free(pathlist, (npaths_alloc + 1) * sizeof (char *)); 3152 } 3153 3154 int 3155 sdev_modctl_devexists(const char *path) 3156 { 3157 vnode_t *vp; 3158 int error; 3159 3160 error = sdev_modctl_lookup(path, &vp); 3161 sdcmn_err11(("modctl dev exists: %s by %s: %s\n", 3162 path, curproc->p_user.u_comm, 3163 (error == 0) ? "ok" : "failed")); 3164 if (error == 0) 3165 VN_RELE(vp); 3166 3167 return (error); 3168 } 3169 3170 void 3171 sdev_update_newnsmap(struct devname_nsmap *map, char *module, char *mapname) 3172 { 3173 rw_enter(&map->dir_lock, RW_WRITER); 3174 if (module) { 3175 ASSERT(map->dir_newmodule == NULL); 3176 map->dir_newmodule = i_ddi_strdup(module, KM_SLEEP); 3177 } 3178 if (mapname) { 3179 ASSERT(map->dir_newmap == NULL); 3180 map->dir_newmap = i_ddi_strdup(mapname, KM_SLEEP); 3181 } 3182 3183 map->dir_invalid = 1; 3184 rw_exit(&map->dir_lock); 3185 } 3186 3187 void 3188 sdev_replace_nsmap(struct devname_nsmap *map, char *module, char *mapname) 3189 { 3190 char *old_module = NULL; 3191 char *old_map = NULL; 3192 3193 ASSERT(RW_LOCK_HELD(&map->dir_lock)); 3194 if (!rw_tryupgrade(&map->dir_lock)) { 3195 rw_exit(&map->dir_lock); 3196 rw_enter(&map->dir_lock, RW_WRITER); 3197 } 3198 3199 old_module = map->dir_module; 3200 if (module) { 3201 if (old_module && strcmp(old_module, module) != 0) { 3202 kmem_free(old_module, strlen(old_module) + 1); 3203 } 3204 map->dir_module = module; 3205 map->dir_newmodule = NULL; 3206 } 3207 3208 old_map = map->dir_map; 3209 if (mapname) { 3210 if (old_map && strcmp(old_map, mapname) != 0) { 3211 kmem_free(old_map, strlen(old_map) + 1); 3212 } 3213 3214 map->dir_map = mapname; 3215 map->dir_newmap = NULL; 3216 } 3217 map->dir_maploaded = 0; 3218 map->dir_invalid = 0; 3219 rw_downgrade(&map->dir_lock); 3220 } 3221 3222 /* 3223 * dir_name should have at least one attribute, 3224 * dir_module 3225 * or dir_map 3226 * or both 3227 * caller holds the devname_nsmaps_lock 3228 */ 3229 void 3230 sdev_insert_nsmap(char *dir_name, char *dir_module, char *dir_map) 3231 { 3232 struct devname_nsmap *map; 3233 int len = 0; 3234 3235 ASSERT(dir_name); 3236 ASSERT(dir_module || dir_map); 3237 ASSERT(MUTEX_HELD(&devname_nsmaps_lock)); 3238 3239 if (map = sdev_get_nsmap_by_dir(dir_name, 1)) { 3240 sdev_update_newnsmap(map, dir_module, dir_map); 3241 return; 3242 } 3243 3244 map = (struct devname_nsmap *)kmem_zalloc(sizeof (*map), KM_SLEEP); 3245 map->dir_name = i_ddi_strdup(dir_name, KM_SLEEP); 3246 if (dir_module) { 3247 map->dir_module = i_ddi_strdup(dir_module, KM_SLEEP); 3248 } 3249 3250 if (dir_map) { 3251 if (dir_map[0] != '/') { 3252 len = strlen(ETC_DEV_DIR) + strlen(dir_map) + 2; 3253 map->dir_map = kmem_zalloc(len, KM_SLEEP); 3254 (void) snprintf(map->dir_map, len, "%s/%s", ETC_DEV_DIR, 3255 dir_map); 3256 } else { 3257 map->dir_map = i_ddi_strdup(dir_map, KM_SLEEP); 3258 } 3259 } 3260 3261 map->dir_ops = NULL; 3262 map->dir_maploaded = 0; 3263 map->dir_invalid = 0; 3264 rw_init(&map->dir_lock, NULL, RW_DEFAULT, NULL); 3265 3266 map->next = devname_nsmaps; 3267 map->prev = NULL; 3268 if (devname_nsmaps) { 3269 devname_nsmaps->prev = map; 3270 } 3271 devname_nsmaps = map; 3272 } 3273 3274 struct devname_nsmap * 3275 sdev_get_nsmap_by_dir(char *dir_path, int locked) 3276 { 3277 struct devname_nsmap *map = NULL; 3278 3279 if (!locked) 3280 mutex_enter(&devname_nsmaps_lock); 3281 for (map = devname_nsmaps; map; map = map->next) { 3282 sdcmn_err6(("sdev_get_nsmap_by_dir: dir %s\n", map->dir_name)); 3283 if (strcmp(map->dir_name, dir_path) == 0) { 3284 if (!locked) 3285 mutex_exit(&devname_nsmaps_lock); 3286 return (map); 3287 } 3288 } 3289 if (!locked) 3290 mutex_exit(&devname_nsmaps_lock); 3291 return (NULL); 3292 } 3293 3294 struct devname_nsmap * 3295 sdev_get_nsmap_by_module(char *mod_name) 3296 { 3297 struct devname_nsmap *map = NULL; 3298 3299 mutex_enter(&devname_nsmaps_lock); 3300 for (map = devname_nsmaps; map; map = map->next) { 3301 sdcmn_err7(("sdev_get_nsmap_by_module: module %s\n", 3302 map->dir_module)); 3303 if (map->dir_module && strcmp(map->dir_module, mod_name) == 0) { 3304 mutex_exit(&devname_nsmaps_lock); 3305 return (map); 3306 } 3307 } 3308 mutex_exit(&devname_nsmaps_lock); 3309 return (NULL); 3310 } 3311 3312 void 3313 sdev_invalidate_nsmaps() 3314 { 3315 struct devname_nsmap *map = NULL; 3316 3317 ASSERT(MUTEX_HELD(&devname_nsmaps_lock)); 3318 3319 if (devname_nsmaps == NULL) 3320 return; 3321 3322 for (map = devname_nsmaps; map; map = map->next) { 3323 rw_enter(&map->dir_lock, RW_WRITER); 3324 map->dir_invalid = 1; 3325 rw_exit(&map->dir_lock); 3326 } 3327 devname_nsmaps_invalidated = 1; 3328 } 3329 3330 3331 int 3332 sdev_nsmaps_loaded() 3333 { 3334 int ret = 0; 3335 3336 mutex_enter(&devname_nsmaps_lock); 3337 if (devname_nsmaps_loaded) 3338 ret = 1; 3339 3340 mutex_exit(&devname_nsmaps_lock); 3341 return (ret); 3342 } 3343 3344 int 3345 sdev_nsmaps_reloaded() 3346 { 3347 int ret = 0; 3348 3349 mutex_enter(&devname_nsmaps_lock); 3350 if (devname_nsmaps_invalidated) 3351 ret = 1; 3352 3353 mutex_exit(&devname_nsmaps_lock); 3354 return (ret); 3355 } 3356 3357 static void 3358 sdev_free_nsmap(struct devname_nsmap *map) 3359 { 3360 ASSERT(map); 3361 if (map->dir_name) 3362 kmem_free(map->dir_name, strlen(map->dir_name) + 1); 3363 if (map->dir_module) 3364 kmem_free(map->dir_module, strlen(map->dir_module) + 1); 3365 if (map->dir_map) 3366 kmem_free(map->dir_map, strlen(map->dir_map) + 1); 3367 rw_destroy(&map->dir_lock); 3368 kmem_free(map, sizeof (*map)); 3369 } 3370 3371 void 3372 sdev_validate_nsmaps() 3373 { 3374 struct devname_nsmap *map = NULL; 3375 struct devname_nsmap *oldmap = NULL; 3376 3377 ASSERT(MUTEX_HELD(&devname_nsmaps_lock)); 3378 map = devname_nsmaps; 3379 while (map) { 3380 rw_enter(&map->dir_lock, RW_READER); 3381 if ((map->dir_invalid == 1) && (map->dir_newmodule == NULL) && 3382 (map->dir_newmap == NULL)) { 3383 oldmap = map; 3384 rw_exit(&map->dir_lock); 3385 if (map->prev) 3386 map->prev->next = oldmap->next; 3387 if (map == devname_nsmaps) 3388 devname_nsmaps = oldmap->next; 3389 3390 map = oldmap->next; 3391 if (map) 3392 map->prev = oldmap->prev; 3393 sdev_free_nsmap(oldmap); 3394 oldmap = NULL; 3395 } else { 3396 rw_exit(&map->dir_lock); 3397 map = map->next; 3398 } 3399 } 3400 devname_nsmaps_invalidated = 0; 3401 } 3402 3403 static int 3404 sdev_map_is_invalid(struct devname_nsmap *map) 3405 { 3406 int ret = 0; 3407 3408 ASSERT(map); 3409 rw_enter(&map->dir_lock, RW_READER); 3410 if (map->dir_invalid) 3411 ret = 1; 3412 rw_exit(&map->dir_lock); 3413 return (ret); 3414 } 3415 3416 static int 3417 sdev_check_map(struct devname_nsmap *map) 3418 { 3419 struct devname_nsmap *mapp; 3420 3421 mutex_enter(&devname_nsmaps_lock); 3422 if (devname_nsmaps == NULL) { 3423 mutex_exit(&devname_nsmaps_lock); 3424 return (1); 3425 } 3426 3427 for (mapp = devname_nsmaps; mapp; mapp = mapp->next) { 3428 if (mapp == map) { 3429 mutex_exit(&devname_nsmaps_lock); 3430 return (0); 3431 } 3432 } 3433 3434 mutex_exit(&devname_nsmaps_lock); 3435 return (1); 3436 3437 } 3438 3439 struct devname_nsmap * 3440 sdev_get_map(struct sdev_node *dv, int validate) 3441 { 3442 struct devname_nsmap *map; 3443 int error; 3444 3445 ASSERT(RW_READ_HELD(&dv->sdev_contents)); 3446 map = dv->sdev_mapinfo; 3447 if (map && sdev_check_map(map)) { 3448 if (!rw_tryupgrade(&dv->sdev_contents)) { 3449 rw_exit(&dv->sdev_contents); 3450 rw_enter(&dv->sdev_contents, RW_WRITER); 3451 } 3452 dv->sdev_mapinfo = NULL; 3453 rw_downgrade(&dv->sdev_contents); 3454 return (NULL); 3455 } 3456 3457 if (validate && (!map || (map && sdev_map_is_invalid(map)))) { 3458 if (!rw_tryupgrade(&dv->sdev_contents)) { 3459 rw_exit(&dv->sdev_contents); 3460 rw_enter(&dv->sdev_contents, RW_WRITER); 3461 } 3462 error = sdev_get_moduleops(dv); 3463 if (!error) 3464 map = dv->sdev_mapinfo; 3465 rw_downgrade(&dv->sdev_contents); 3466 } 3467 return (map); 3468 } 3469 3470 extern int sdev_vnodeops_tbl_size; 3471 3472 /* 3473 * construct a new template with overrides from vtab 3474 */ 3475 static fs_operation_def_t * 3476 sdev_merge_vtab(const fs_operation_def_t tab[]) 3477 { 3478 fs_operation_def_t *new; 3479 const fs_operation_def_t *tab_entry; 3480 3481 /* make a copy of standard vnode ops table */ 3482 new = kmem_alloc(sdev_vnodeops_tbl_size, KM_SLEEP); 3483 bcopy((void *)sdev_vnodeops_tbl, new, sdev_vnodeops_tbl_size); 3484 3485 /* replace the overrides from tab */ 3486 for (tab_entry = tab; tab_entry->name != NULL; tab_entry++) { 3487 fs_operation_def_t *std_entry = new; 3488 while (std_entry->name) { 3489 if (strcmp(tab_entry->name, std_entry->name) == 0) { 3490 std_entry->func = tab_entry->func; 3491 break; 3492 } 3493 std_entry++; 3494 } 3495 if (std_entry->name == NULL) 3496 cmn_err(CE_NOTE, "sdev_merge_vtab: entry %s unused.", 3497 tab_entry->name); 3498 } 3499 3500 return (new); 3501 } 3502 3503 /* free memory allocated by sdev_merge_vtab */ 3504 static void 3505 sdev_free_vtab(fs_operation_def_t *new) 3506 { 3507 kmem_free(new, sdev_vnodeops_tbl_size); 3508 } 3509 3510 void 3511 devname_get_vnode(devname_handle_t *hdl, vnode_t **vpp) 3512 { 3513 struct sdev_node *dv = hdl->dh_data; 3514 3515 ASSERT(dv); 3516 3517 rw_enter(&dv->sdev_contents, RW_READER); 3518 *vpp = SDEVTOV(dv); 3519 rw_exit(&dv->sdev_contents); 3520 } 3521 3522 int 3523 devname_get_path(devname_handle_t *hdl, char **path) 3524 { 3525 struct sdev_node *dv = hdl->dh_data; 3526 3527 ASSERT(dv); 3528 3529 rw_enter(&dv->sdev_contents, RW_READER); 3530 *path = dv->sdev_path; 3531 rw_exit(&dv->sdev_contents); 3532 return (0); 3533 } 3534 3535 int 3536 devname_get_name(devname_handle_t *hdl, char **entry) 3537 { 3538 struct sdev_node *dv = hdl->dh_data; 3539 3540 ASSERT(dv); 3541 rw_enter(&dv->sdev_contents, RW_READER); 3542 *entry = dv->sdev_name; 3543 rw_exit(&dv->sdev_contents); 3544 return (0); 3545 } 3546 3547 void 3548 devname_get_dir_vnode(devname_handle_t *hdl, vnode_t **vpp) 3549 { 3550 struct sdev_node *dv = hdl->dh_data->sdev_dotdot; 3551 3552 ASSERT(dv); 3553 3554 rw_enter(&dv->sdev_contents, RW_READER); 3555 *vpp = SDEVTOV(dv); 3556 rw_exit(&dv->sdev_contents); 3557 } 3558 3559 int 3560 devname_get_dir_path(devname_handle_t *hdl, char **path) 3561 { 3562 struct sdev_node *dv = hdl->dh_data->sdev_dotdot; 3563 3564 ASSERT(dv); 3565 rw_enter(&dv->sdev_contents, RW_READER); 3566 *path = dv->sdev_path; 3567 rw_exit(&dv->sdev_contents); 3568 return (0); 3569 } 3570 3571 int 3572 devname_get_dir_name(devname_handle_t *hdl, char **entry) 3573 { 3574 struct sdev_node *dv = hdl->dh_data->sdev_dotdot; 3575 3576 ASSERT(dv); 3577 rw_enter(&dv->sdev_contents, RW_READER); 3578 *entry = dv->sdev_name; 3579 rw_exit(&dv->sdev_contents); 3580 return (0); 3581 } 3582 3583 int 3584 devname_get_dir_nsmap(devname_handle_t *hdl, struct devname_nsmap **map) 3585 { 3586 struct sdev_node *dv = hdl->dh_data->sdev_dotdot; 3587 3588 ASSERT(dv); 3589 rw_enter(&dv->sdev_contents, RW_READER); 3590 *map = dv->sdev_mapinfo; 3591 rw_exit(&dv->sdev_contents); 3592 return (0); 3593 } 3594 3595 int 3596 devname_get_dir_handle(devname_handle_t *hdl, devname_handle_t **dir_hdl) 3597 { 3598 struct sdev_node *dv = hdl->dh_data->sdev_dotdot; 3599 3600 ASSERT(dv); 3601 rw_enter(&dv->sdev_contents, RW_READER); 3602 *dir_hdl = &(dv->sdev_handle); 3603 rw_exit(&dv->sdev_contents); 3604 return (0); 3605 } 3606 3607 void 3608 devname_set_nodetype(devname_handle_t *hdl, void *args, int spec) 3609 { 3610 struct sdev_node *dv = hdl->dh_data; 3611 3612 ASSERT(dv); 3613 rw_enter(&dv->sdev_contents, RW_WRITER); 3614 hdl->dh_spec = (devname_spec_t)spec; 3615 hdl->dh_args = (void *)i_ddi_strdup((char *)args, KM_SLEEP); 3616 rw_exit(&dv->sdev_contents); 3617 } 3618 3619 /* 3620 * a generic setattr() function 3621 * 3622 * note: flags only supports AT_UID and AT_GID. 3623 * Future enhancements can be done for other types, e.g. AT_MODE 3624 */ 3625 int 3626 devname_setattr_func(struct vnode *vp, struct vattr *vap, int flags, 3627 struct cred *cred, int (*callback)(struct sdev_node *, struct vattr *, 3628 int), int protocol) 3629 { 3630 struct sdev_node *dv = VTOSDEV(vp); 3631 struct sdev_node *parent = dv->sdev_dotdot; 3632 struct vattr *get; 3633 uint_t mask = vap->va_mask; 3634 int error; 3635 3636 /* some sanity checks */ 3637 if (vap->va_mask & AT_NOSET) 3638 return (EINVAL); 3639 3640 if (vap->va_mask & AT_SIZE) { 3641 if (vp->v_type == VDIR) { 3642 return (EISDIR); 3643 } 3644 } 3645 3646 /* no need to set attribute, but do not fail either */ 3647 ASSERT(parent); 3648 rw_enter(&parent->sdev_contents, RW_READER); 3649 if (dv->sdev_state == SDEV_ZOMBIE) { 3650 rw_exit(&parent->sdev_contents); 3651 return (0); 3652 } 3653 3654 /* If backing store exists, just set it. */ 3655 if (dv->sdev_attrvp) { 3656 rw_exit(&parent->sdev_contents); 3657 return (VOP_SETATTR(dv->sdev_attrvp, vap, flags, cred, NULL)); 3658 } 3659 3660 /* 3661 * Otherwise, for nodes with the persistence attribute, create it. 3662 */ 3663 ASSERT(dv->sdev_attr); 3664 if (SDEV_IS_PERSIST(dv) || 3665 ((vap->va_mask & ~AT_TIMES) != 0 && !SDEV_IS_DYNAMIC(dv))) { 3666 sdev_vattr_merge(dv, vap); 3667 rw_enter(&dv->sdev_contents, RW_WRITER); 3668 error = sdev_shadow_node(dv, cred); 3669 rw_exit(&dv->sdev_contents); 3670 rw_exit(&parent->sdev_contents); 3671 3672 if (error) 3673 return (error); 3674 return (VOP_SETATTR(dv->sdev_attrvp, vap, flags, cred, NULL)); 3675 } 3676 3677 3678 /* 3679 * sdev_attr was allocated in sdev_mknode 3680 */ 3681 rw_enter(&dv->sdev_contents, RW_WRITER); 3682 error = secpolicy_vnode_setattr(cred, vp, vap, 3683 dv->sdev_attr, flags, sdev_unlocked_access, dv); 3684 if (error) { 3685 rw_exit(&dv->sdev_contents); 3686 rw_exit(&parent->sdev_contents); 3687 return (error); 3688 } 3689 3690 get = dv->sdev_attr; 3691 if (mask & AT_MODE) { 3692 get->va_mode &= S_IFMT; 3693 get->va_mode |= vap->va_mode & ~S_IFMT; 3694 } 3695 3696 if ((mask & AT_UID) || (mask & AT_GID)) { 3697 if (mask & AT_UID) 3698 get->va_uid = vap->va_uid; 3699 if (mask & AT_GID) 3700 get->va_gid = vap->va_gid; 3701 /* 3702 * a callback must be provided if the protocol is set 3703 */ 3704 if ((protocol & AT_UID) || (protocol & AT_GID)) { 3705 ASSERT(callback); 3706 error = callback(dv, get, protocol); 3707 if (error) { 3708 rw_exit(&dv->sdev_contents); 3709 rw_exit(&parent->sdev_contents); 3710 return (error); 3711 } 3712 } 3713 } 3714 3715 if (mask & AT_ATIME) 3716 get->va_atime = vap->va_atime; 3717 if (mask & AT_MTIME) 3718 get->va_mtime = vap->va_mtime; 3719 if (mask & (AT_MODE | AT_UID | AT_GID | AT_CTIME)) { 3720 gethrestime(&get->va_ctime); 3721 } 3722 3723 sdev_vattr_merge(dv, get); 3724 rw_exit(&dv->sdev_contents); 3725 rw_exit(&parent->sdev_contents); 3726 return (0); 3727 } 3728 3729 /* 3730 * a generic inactive() function 3731 */ 3732 void 3733 devname_inactive_func(struct vnode *vp, struct cred *cred, 3734 void (*callback)(struct vnode *)) 3735 { 3736 int clean; 3737 struct sdev_node *dv = VTOSDEV(vp); 3738 struct sdev_node *ddv = dv->sdev_dotdot; 3739 int state; 3740 struct devname_nsmap *map = NULL; 3741 struct devname_ops *dirops = NULL; 3742 void (*fn)(devname_handle_t *, struct cred *) = NULL; 3743 3744 rw_enter(&ddv->sdev_contents, RW_WRITER); 3745 state = dv->sdev_state; 3746 3747 mutex_enter(&vp->v_lock); 3748 ASSERT(vp->v_count >= 1); 3749 3750 if (vp->v_count == 1 && callback != NULL) 3751 callback(vp); 3752 3753 clean = (vp->v_count == 1) && (state == SDEV_ZOMBIE); 3754 3755 /* 3756 * last ref count on the ZOMBIE node is released. 3757 * clean up the sdev_node, and 3758 * release the hold on the backing store node so that 3759 * the ZOMBIE backing stores also cleaned out. 3760 */ 3761 if (clean) { 3762 ASSERT(ddv); 3763 if (SDEV_IS_GLOBAL(dv)) { 3764 map = ddv->sdev_mapinfo; 3765 dirops = map ? map->dir_ops : NULL; 3766 if (dirops && (fn = dirops->devnops_inactive)) 3767 (*fn)(&(dv->sdev_handle), cred); 3768 } 3769 3770 ddv->sdev_nlink--; 3771 if (vp->v_type == VDIR) { 3772 dv->sdev_nlink--; 3773 } 3774 if ((dv->sdev_flags & SDEV_STALE) == 0) 3775 avl_remove(&ddv->sdev_entries, dv); 3776 dv->sdev_nlink--; 3777 --vp->v_count; 3778 mutex_exit(&vp->v_lock); 3779 sdev_nodedestroy(dv, 0); 3780 } else { 3781 --vp->v_count; 3782 mutex_exit(&vp->v_lock); 3783 } 3784 rw_exit(&ddv->sdev_contents); 3785 } 3786