638 }
639
640 /* Walk nvlist and lookup corresponding device in global inst */
641 while (nvp = nvlist_next_nvpair(nvl, nvp)) {
642 int type;
643 rv = nvpair_value_int32(nvp, &type);
644 if (rv != 0) {
645 cmn_err(CE_WARN, sdev_nvp_val_err,
646 rv, nvpair_name(nvp));
647 break;
648 }
649 if (type == PROFILE_TYPE_EXCLUDE)
650 continue;
651 name = nvpair_name(nvp);
652 (void) prof_lookup_globaldev(dir, dir->sdev_origin,
653 name, name);
654 }
655 }
656
657 /*
658 * Build directory vnodes based on the profile and the global
659 * dev instance.
660 */
661 void
662 prof_filldir(struct sdev_node *ddv)
663 {
664 int firsttime = 1;
665 struct sdev_node *gdir = ddv->sdev_origin;
666
667 ASSERT(RW_READ_HELD(&ddv->sdev_contents));
668
669 /*
670 * We need to rebuild the directory content if
671 * - SDEV_BUILD is set
672 * - The device tree generation number has changed
673 * - The corresponding /dev namespace has been updated
674 */
675 check_build:
676 if ((ddv->sdev_flags & SDEV_BUILD) == 0 &&
677 ddv->sdev_devtree_gen == devtree_gen &&
678 (gdir == NULL || ddv->sdev_ldir_gen
679 == gdir->sdev_gdir_gen))
680 return; /* already up to date */
681
682 /* We may have become a zombie (across a try) */
683 if (ddv->sdev_state == SDEV_ZOMBIE)
684 return;
685
686 if (firsttime && rw_tryupgrade(&ddv->sdev_contents) == 0) {
687 rw_exit(&ddv->sdev_contents);
688 firsttime = 0;
689 rw_enter(&ddv->sdev_contents, RW_WRITER);
690 goto check_build;
691 }
692 sdcmn_err10(("devtree_gen (%s): %ld -> %ld\n",
693 ddv->sdev_path, ddv->sdev_devtree_gen, devtree_gen));
694 if (gdir)
695 sdcmn_err10(("sdev_dir_gen (%s): %ld -> %ld\n",
696 ddv->sdev_path, ddv->sdev_ldir_gen,
697 gdir->sdev_gdir_gen));
698
699 /* update flags and generation number so next filldir is quick */
700 ddv->sdev_flags &= ~SDEV_BUILD;
701 ddv->sdev_devtree_gen = devtree_gen;
702 if (gdir)
703 ddv->sdev_ldir_gen = gdir->sdev_gdir_gen;
704
705 prof_make_symlinks(ddv);
706 prof_make_maps(ddv);
707 prof_make_names(ddv);
708 rw_downgrade(&ddv->sdev_contents);
709 }
710
711 /* apply include/exclude pattern to existing directory content */
712 static void
713 apply_dir_pattern(struct sdev_node *dir, char *expr, char *pathleft, int type)
714 {
715 struct sdev_node *dv;
716
717 /* leaf pattern */
718 if (pathleft == NULL) {
719 if (type == PROFILE_TYPE_INCLUDE)
720 return; /* nothing to do for include */
721 (void) sdev_cleandir(dir, expr, SDEV_ENFORCE);
722 return;
|
638 }
639
640 /* Walk nvlist and lookup corresponding device in global inst */
641 while (nvp = nvlist_next_nvpair(nvl, nvp)) {
642 int type;
643 rv = nvpair_value_int32(nvp, &type);
644 if (rv != 0) {
645 cmn_err(CE_WARN, sdev_nvp_val_err,
646 rv, nvpair_name(nvp));
647 break;
648 }
649 if (type == PROFILE_TYPE_EXCLUDE)
650 continue;
651 name = nvpair_name(nvp);
652 (void) prof_lookup_globaldev(dir, dir->sdev_origin,
653 name, name);
654 }
655 }
656
657 /*
658 * Return True if directory cache is out of date and should be updated.
659 */
660 static boolean_t
661 prof_dev_needupdate(sdev_node_t *ddv)
662 {
663 sdev_node_t *gdir = ddv->sdev_origin;
664
665 /*
666 * Caller can have either reader or writer lock
667 */
668 ASSERT(RW_LOCK_HELD(&ddv->sdev_contents));
669
670 /*
671 * We need to rebuild the directory content if
672 * - ddv is not in a SDEV_ZOMBIE state
673 * - SDEV_BUILD is set OR
674 * - The device tree generation number has changed OR
675 * - The corresponding /dev namespace has been updated
676 */
677 return ((ddv->sdev_state != SDEV_ZOMBIE) &&
678 (((ddv->sdev_flags & SDEV_BUILD) != 0) ||
679 (ddv->sdev_devtree_gen != devtree_gen) ||
680 ((gdir != NULL) &&
681 (ddv->sdev_ldir_gen != gdir->sdev_gdir_gen))));
682 }
683
684 /*
685 * Build directory vnodes based on the profile and the global
686 * dev instance.
687 */
688 void
689 prof_filldir(sdev_node_t *ddv)
690 {
691 sdev_node_t *gdir;
692
693 ASSERT(RW_READ_HELD(&ddv->sdev_contents));
694
695 if (!prof_dev_needupdate(ddv)) {
696 ASSERT(RW_READ_HELD(&ddv->sdev_contents));
697 return;
698 }
699 /*
700 * Upgrade to writer lock
701 */
702 if (rw_tryupgrade(&ddv->sdev_contents) == 0) {
703 /*
704 * We need to drop the read lock and re-acquire it as a
705 * write lock. While we do this the condition may change so we
706 * need to re-check condition
707 */
708 rw_exit(&ddv->sdev_contents);
709 rw_enter(&ddv->sdev_contents, RW_WRITER);
710 if (!prof_dev_needupdate(ddv)) {
711 /* Downgrade back to the read lock before returning */
712 rw_downgrade(&ddv->sdev_contents);
713 return;
714 }
715 }
716 /* At this point we should have a write lock */
717 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
718
719 sdcmn_err10(("devtree_gen (%s): %ld -> %ld\n",
720 ddv->sdev_path, ddv->sdev_devtree_gen, devtree_gen));
721
722 gdir = ddv->sdev_origin;
723
724 if (gdir != NULL)
725 sdcmn_err10(("sdev_dir_gen (%s): %ld -> %ld\n",
726 ddv->sdev_path, ddv->sdev_ldir_gen,
727 gdir->sdev_gdir_gen));
728
729 /* update flags and generation number so next filldir is quick */
730 if ((ddv->sdev_flags & SDEV_BUILD) == SDEV_BUILD) {
731 ddv->sdev_flags &= ~SDEV_BUILD;
732 }
733 ddv->sdev_devtree_gen = devtree_gen;
734 if (gdir != NULL)
735 ddv->sdev_ldir_gen = gdir->sdev_gdir_gen;
736
737 prof_make_symlinks(ddv);
738 prof_make_maps(ddv);
739 prof_make_names(ddv);
740 rw_downgrade(&ddv->sdev_contents);
741 }
742
743 /* apply include/exclude pattern to existing directory content */
744 static void
745 apply_dir_pattern(struct sdev_node *dir, char *expr, char *pathleft, int type)
746 {
747 struct sdev_node *dv;
748
749 /* leaf pattern */
750 if (pathleft == NULL) {
751 if (type == PROFILE_TYPE_INCLUDE)
752 return; /* nothing to do for include */
753 (void) sdev_cleandir(dir, expr, SDEV_ENFORCE);
754 return;
|