68 #include <sys/modctl.h>
69 #include <sys/ddi.h>
70 #include <sys/pathname.h>
71 #include <sys/bootconf.h>
72 #include <sys/dumphdr.h>
73 #include <sys/dc_ki.h>
74 #include <sys/poll.h>
75 #include <sys/sunddi.h>
76 #include <sys/sysmacros.h>
77 #include <sys/zone.h>
78 #include <sys/policy.h>
79 #include <sys/ctfs.h>
80 #include <sys/objfs.h>
81 #include <sys/console.h>
82 #include <sys/reboot.h>
83 #include <sys/attr.h>
84 #include <sys/zio.h>
85 #include <sys/spa.h>
86 #include <sys/lofi.h>
87 #include <sys/bootprops.h>
88
89 #include <vm/page.h>
90
91 #include <fs/fs_subr.h>
92 /* Private interfaces to create vopstats-related data structures */
93 extern void initialize_vopstats(vopstats_t *);
94 extern vopstats_t *get_fstype_vopstats(struct vfs *, struct vfssw *);
95 extern vsk_anchor_t *get_vskstat_anchor(struct vfs *);
96
97 static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
98 static void vfs_setmntopt_nolock(mntopts_t *, const char *,
99 const char *, int, int);
100 static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
101 static void vfs_freemnttab(struct vfs *);
102 static void vfs_freeopt(mntopt_t *);
103 static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
104 static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
105 static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
106 static void vfs_createopttbl_extend(mntopts_t *, const char *,
107 const mntopts_t *);
120 static kmutex_t vfs_miplist_mutex;
121 static struct ipmnt *vfs_miplist = NULL;
122 static struct ipmnt *vfs_miplist_end = NULL;
123
124 static kmem_cache_t *vfs_cache; /* Pointer to VFS kmem cache */
125
126 /*
127 * VFS global data.
128 */
129 vnode_t *rootdir; /* pointer to root inode vnode. */
130 vnode_t *devicesdir; /* pointer to inode of devices root */
131 vnode_t *devdir; /* pointer to inode of dev root */
132
133 char *server_rootpath; /* root path for diskless clients */
134 char *server_hostname; /* hostname of diskless server */
135
136 static struct vfs root;
137 static struct vfs devices;
138 static struct vfs dev;
139 struct vfs *rootvfs = &root; /* pointer to root vfs; head of VFS list. */
140 rvfs_t *rvfs_list; /* array of vfs ptrs for vfs hash list */
141 int vfshsz = 512; /* # of heads/locks in vfs hash arrays */
142 /* must be power of 2! */
143 timespec_t vfs_mnttab_ctime; /* mnttab created time */
144 timespec_t vfs_mnttab_mtime; /* mnttab last modified time */
145 char *vfs_dummyfstype = "\0";
146 struct pollhead vfs_pollhd; /* for mnttab pollers */
147 struct vnode *vfs_mntdummyvp; /* to fake mnttab read/write for file events */
148 int mntfstype; /* will be set once mnt fs is mounted */
149
150 /*
151 * Table for generic options recognized in the VFS layer and acted
152 * on at this level before parsing file system specific options.
153 * The nosuid option is stronger than any of the devices and setuid
154 * options, so those are canceled when nosuid is seen.
155 *
156 * All options which are added here need to be added to the
157 * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
158 */
159 /*
591 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
592 if (ALLOCATED_VFSSW(vswp) && VFS_INSTALLED(vswp)) {
593 vfs_refvfssw(vswp);
594 RUNLOCK_VFSSW();
595 (void) (*vswp->vsw_vfsops.vfs_sync)(NULL, flag,
596 CRED());
597 vfs_unrefvfssw(vswp);
598 RLOCK_VFSSW();
599 }
600 }
601 RUNLOCK_VFSSW();
602 }
603
604 void
605 sync(void)
606 {
607 vfs_sync(0);
608 }
609
610 /*
611 * External routines.
612 */
613
614 krwlock_t vfssw_lock; /* lock accesses to vfssw */
615
616 /*
617 * Lock for accessing the vfs linked list. Initialized in vfs_mountroot(),
618 * but otherwise should be accessed only via vfs_list_lock() and
619 * vfs_list_unlock(). Also used to protect the timestamp for mods to the list.
620 */
621 static krwlock_t vfslist;
622
623 /*
624 * Mount devfs on /devices. This is done right after root is mounted
625 * to provide device access support for the system
626 */
627 static void
628 vfs_mountdevices(void)
629 {
630 struct vfssw *vsw;
801 VFS_RELE(vfsp);
802 VN_RELE(mvp);
803 }
804
805 /*
806 * vfs_mountroot is called by main() to mount the root filesystem.
807 */
808 void
809 vfs_mountroot(void)
810 {
811 struct vnode *rvp = NULL;
812 char *path;
813 size_t plen;
814 struct vfssw *vswp;
815 proc_t *p;
816
817 rw_init(&vfssw_lock, NULL, RW_DEFAULT, NULL);
818 rw_init(&vfslist, NULL, RW_DEFAULT, NULL);
819
820 /*
821 * Alloc the vfs hash bucket array and locks
822 */
823 rvfs_list = kmem_zalloc(vfshsz * sizeof (rvfs_t), KM_SLEEP);
824
825 /*
826 * Call machine-dependent routine "rootconf" to choose a root
827 * file system type.
828 */
829 if (rootconf())
830 panic("vfs_mountroot: cannot mount root");
831 /*
832 * Get vnode for '/'. Set up rootdir, u.u_rdir and u.u_cdir
833 * to point to it. These are used by lookuppn() so that it
834 * knows where to start from ('/' or '.').
835 */
836 vfs_setmntpoint(rootvfs, "/", 0);
837 if (VFS_ROOT(rootvfs, &rootdir))
838 panic("vfs_mountroot: no root vnode");
839
840 /*
3594 */
3595 if (zone->zone_vfslist == NULL) {
3596 ASSERT(zone != global_zone);
3597 zone->zone_vfslist = vfsp;
3598 } else {
3599 zone->zone_vfslist->vfs_zone_prev->vfs_zone_next = vfsp;
3600 vfsp->vfs_zone_prev = zone->zone_vfslist->vfs_zone_prev;
3601 zone->zone_vfslist->vfs_zone_prev = vfsp;
3602 vfsp->vfs_zone_next = zone->zone_vfslist;
3603 }
3604 }
3605
3606 /*
3607 * Link into the hash table, inserting it at the end, so that LOFS
3608 * with the same fsid as UFS (or other) file systems will not hide
3609 * the UFS.
3610 */
3611 vfs_hash_add(vfsp, 0);
3612
3613 /*
3614 * update the mnttab modification time
3615 */
3616 vfs_mnttab_modtimeupd();
3617 vfs_list_unlock();
3618 zone_rele(zone);
3619 }
3620
3621 void
3622 vfs_list_remove(struct vfs *vfsp)
3623 {
3624 zone_t *zone;
3625
3626 zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
3627 ASSERT(zone != NULL);
3628 /*
3629 * Callers are responsible for preventing attempts to unmount the
3630 * root.
3631 */
3632 ASSERT(vfsp != rootvfs);
3633
3634 vfs_list_lock();
3635
3636 /*
3637 * Remove from hash.
3638 */
3639 vfs_hash_remove(vfsp);
3640
3641 /*
3642 * Remove from vfs list.
3643 */
3644 vfsp->vfs_prev->vfs_next = vfsp->vfs_next;
3645 vfsp->vfs_next->vfs_prev = vfsp->vfs_prev;
3646 vfsp->vfs_next = vfsp->vfs_prev = NULL;
3647
3648 /*
3649 * Remove from zone-specific vfs list.
3650 */
3651 if (zone->zone_vfslist == vfsp)
3652 zone->zone_vfslist = vfsp->vfs_zone_next;
3653
3654 if (vfsp->vfs_zone_next == vfsp) {
3655 ASSERT(vfsp->vfs_zone_prev == vfsp);
3656 ASSERT(zone->zone_vfslist == vfsp);
3710 for (mipp = vfs_miplist; mipp != NULL; mipp = mipp->mip_next) {
3711 if (mipp->mip_dev == dev) {
3712 if (mipp->mip_vfsp != vfsp)
3713 retval = 1;
3714 break;
3715 }
3716 }
3717 mutex_exit(&vfs_miplist_mutex);
3718 return (retval);
3719 }
3720
3721 /*
3722 * Search the vfs list for a specified device. Returns 1, if entry is found
3723 * or 0 if no suitable entry is found.
3724 */
3725
3726 int
3727 vfs_devismounted(dev_t dev)
3728 {
3729 struct vfs *vfsp;
3730 int found;
3731
3732 vfs_list_read_lock();
3733 vfsp = rootvfs;
3734 found = 0;
3735 do {
3736 if (vfsp->vfs_dev == dev) {
3737 found = 1;
3738 break;
3739 }
3740 vfsp = vfsp->vfs_next;
3741 } while (vfsp != rootvfs);
3742
3743 vfs_list_unlock();
3744 return (found);
3745 }
3746
3747 /*
3748 * Search the vfs list for a specified device. Returns a pointer to it
3749 * or NULL if no suitable entry is found. The caller of this routine
3750 * is responsible for releasing the returned vfs pointer.
3751 */
3752 struct vfs *
3753 vfs_dev2vfsp(dev_t dev)
3754 {
3755 struct vfs *vfsp;
3756 int found;
3757
3758 vfs_list_read_lock();
3759 vfsp = rootvfs;
3760 found = 0;
3761 do {
3762 /*
3763 * The following could be made more efficient by making
3764 * the entire loop use vfs_zone_next if the call is from
3765 * a zone. The only callers, however, ustat(2) and
3766 * umount2(2), don't seem to justify the added
3767 * complexity at present.
3768 */
3769 if (vfsp->vfs_dev == dev &&
3770 ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
3771 curproc->p_zone)) {
3772 VFS_HOLD(vfsp);
3773 found = 1;
3774 break;
3775 }
3776 vfsp = vfsp->vfs_next;
3777 } while (vfsp != rootvfs);
3778 vfs_list_unlock();
3779 return (found ? vfsp: NULL);
3780 }
3781
3782 /*
3783 * Search the vfs list for a specified mntpoint. Returns a pointer to it
3784 * or NULL if no suitable entry is found. The caller of this routine
3785 * is responsible for releasing the returned vfs pointer.
3786 *
3787 * Note that if multiple mntpoints match, the last one matching is
3788 * returned in an attempt to return the "top" mount when overlay
3789 * mounts are covering the same mount point. This is accomplished by starting
3790 * at the end of the list and working our way backwards, stopping at the first
3791 * matching mount.
3792 */
3793 struct vfs *
3794 vfs_mntpoint2vfsp(const char *mp)
3795 {
3796 struct vfs *vfsp;
3797 struct vfs *retvfsp = NULL;
3798 zone_t *zone = curproc->p_zone;
3799 struct vfs *list;
3800
3801 vfs_list_read_lock();
3802 if (getzoneid() == GLOBAL_ZONEID) {
3803 /*
3804 * The global zone may see filesystems in any zone.
3805 */
3806 vfsp = rootvfs->vfs_prev;
3807 do {
3808 if (strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0) {
3809 retvfsp = vfsp;
3810 break;
3811 }
3812 vfsp = vfsp->vfs_prev;
3813 } while (vfsp != rootvfs->vfs_prev);
3814 } else if ((list = zone->zone_vfslist) != NULL) {
3815 const char *mntpt;
3816
3817 vfsp = list->vfs_zone_prev;
3818 do {
3819 mntpt = refstr_value(vfsp->vfs_mntpt);
3820 mntpt = ZONE_PATH_TRANSLATE(mntpt, zone);
3821 if (strcmp(mntpt, mp) == 0) {
3822 retvfsp = vfsp;
3823 break;
3824 }
3825 vfsp = vfsp->vfs_zone_prev;
3826 } while (vfsp != list->vfs_zone_prev);
3827 }
3828 if (retvfsp)
3829 VFS_HOLD(retvfsp);
3830 vfs_list_unlock();
3831 return (retvfsp);
3832 }
3833
|
68 #include <sys/modctl.h>
69 #include <sys/ddi.h>
70 #include <sys/pathname.h>
71 #include <sys/bootconf.h>
72 #include <sys/dumphdr.h>
73 #include <sys/dc_ki.h>
74 #include <sys/poll.h>
75 #include <sys/sunddi.h>
76 #include <sys/sysmacros.h>
77 #include <sys/zone.h>
78 #include <sys/policy.h>
79 #include <sys/ctfs.h>
80 #include <sys/objfs.h>
81 #include <sys/console.h>
82 #include <sys/reboot.h>
83 #include <sys/attr.h>
84 #include <sys/zio.h>
85 #include <sys/spa.h>
86 #include <sys/lofi.h>
87 #include <sys/bootprops.h>
88 #include <sys/avl.h>
89
90 #include <vm/page.h>
91
92 #include <fs/fs_subr.h>
93 /* Private interfaces to create vopstats-related data structures */
94 extern void initialize_vopstats(vopstats_t *);
95 extern vopstats_t *get_fstype_vopstats(struct vfs *, struct vfssw *);
96 extern vsk_anchor_t *get_vskstat_anchor(struct vfs *);
97
98 static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
99 static void vfs_setmntopt_nolock(mntopts_t *, const char *,
100 const char *, int, int);
101 static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
102 static void vfs_freemnttab(struct vfs *);
103 static void vfs_freeopt(mntopt_t *);
104 static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
105 static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
106 static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
107 static void vfs_createopttbl_extend(mntopts_t *, const char *,
108 const mntopts_t *);
121 static kmutex_t vfs_miplist_mutex;
122 static struct ipmnt *vfs_miplist = NULL;
123 static struct ipmnt *vfs_miplist_end = NULL;
124
125 static kmem_cache_t *vfs_cache; /* Pointer to VFS kmem cache */
126
127 /*
128 * VFS global data.
129 */
130 vnode_t *rootdir; /* pointer to root inode vnode. */
131 vnode_t *devicesdir; /* pointer to inode of devices root */
132 vnode_t *devdir; /* pointer to inode of dev root */
133
134 char *server_rootpath; /* root path for diskless clients */
135 char *server_hostname; /* hostname of diskless server */
136
137 static struct vfs root;
138 static struct vfs devices;
139 static struct vfs dev;
140 struct vfs *rootvfs = &root; /* pointer to root vfs; head of VFS list. */
141 avl_tree_t vfs_by_dev; /* avl tree to index mounted VFSs by dev */
142 avl_tree_t vfs_by_mntpnt; /* avl tree to index mounted VFSs by mntpnt */
143 uint64_t vfs_curr_mntix; /* counter to provide a unique mntix for
144 * entries in the above avl trees.
145 * protected by vfslist lock */
146 rvfs_t *rvfs_list; /* array of vfs ptrs for vfs hash list */
147 int vfshsz = 512; /* # of heads/locks in vfs hash arrays */
148 /* must be power of 2! */
149 timespec_t vfs_mnttab_ctime; /* mnttab created time */
150 timespec_t vfs_mnttab_mtime; /* mnttab last modified time */
151 char *vfs_dummyfstype = "\0";
152 struct pollhead vfs_pollhd; /* for mnttab pollers */
153 struct vnode *vfs_mntdummyvp; /* to fake mnttab read/write for file events */
154 int mntfstype; /* will be set once mnt fs is mounted */
155
156 /*
157 * Table for generic options recognized in the VFS layer and acted
158 * on at this level before parsing file system specific options.
159 * The nosuid option is stronger than any of the devices and setuid
160 * options, so those are canceled when nosuid is seen.
161 *
162 * All options which are added here need to be added to the
163 * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
164 */
165 /*
597 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
598 if (ALLOCATED_VFSSW(vswp) && VFS_INSTALLED(vswp)) {
599 vfs_refvfssw(vswp);
600 RUNLOCK_VFSSW();
601 (void) (*vswp->vsw_vfsops.vfs_sync)(NULL, flag,
602 CRED());
603 vfs_unrefvfssw(vswp);
604 RLOCK_VFSSW();
605 }
606 }
607 RUNLOCK_VFSSW();
608 }
609
610 void
611 sync(void)
612 {
613 vfs_sync(0);
614 }
615
616 /*
617 * compare function for vfs_by_dev avl tree. compare dev first, then mntix
618 */
619 static int
620 vfs_cmp_dev(const void *aa, const void *bb)
621 {
622 const vfs_t *a = aa;
623 const vfs_t *b = bb;
624
625 if (a->vfs_dev < b->vfs_dev)
626 return (-1);
627 if (a->vfs_dev > b->vfs_dev)
628 return (1);
629 if (a->vfs_mntix < b->vfs_mntix)
630 return (-1);
631 if (a->vfs_mntix > b->vfs_mntix)
632 return (1);
633 return (0);
634 }
635
636 /*
637 * compare function for vfs_by_mntpnt avl tree. compare mntpnt first, then mntix
638 */
639 static int
640 vfs_cmp_mntpnt(const void *aa, const void *bb)
641 {
642 const vfs_t *a = aa;
643 const vfs_t *b = bb;
644 int ret;
645
646 ret = strcmp(refstr_value(a->vfs_mntpt), refstr_value(b->vfs_mntpt));
647 if (ret < 0)
648 return (-1);
649 if (ret > 0)
650 return (1);
651 if (a->vfs_mntix < b->vfs_mntix)
652 return (-1);
653 if (a->vfs_mntix > b->vfs_mntix)
654 return (1);
655 return (0);
656 }
657
658 /*
659 * External routines.
660 */
661
662 krwlock_t vfssw_lock; /* lock accesses to vfssw */
663
664 /*
665 * Lock for accessing the vfs linked list. Initialized in vfs_mountroot(),
666 * but otherwise should be accessed only via vfs_list_lock() and
667 * vfs_list_unlock(). Also used to protect the timestamp for mods to the list.
668 */
669 static krwlock_t vfslist;
670
671 /*
672 * Mount devfs on /devices. This is done right after root is mounted
673 * to provide device access support for the system
674 */
675 static void
676 vfs_mountdevices(void)
677 {
678 struct vfssw *vsw;
849 VFS_RELE(vfsp);
850 VN_RELE(mvp);
851 }
852
853 /*
854 * vfs_mountroot is called by main() to mount the root filesystem.
855 */
856 void
857 vfs_mountroot(void)
858 {
859 struct vnode *rvp = NULL;
860 char *path;
861 size_t plen;
862 struct vfssw *vswp;
863 proc_t *p;
864
865 rw_init(&vfssw_lock, NULL, RW_DEFAULT, NULL);
866 rw_init(&vfslist, NULL, RW_DEFAULT, NULL);
867
868 /*
869 * Alloc the avl trees for quick indexing via dev and mountpoint
870 */
871 avl_create(&vfs_by_dev, vfs_cmp_dev, sizeof(vfs_t),
872 offsetof(vfs_t, vfs_avldev));
873 avl_create(&vfs_by_mntpnt, vfs_cmp_mntpnt, sizeof(vfs_t),
874 offsetof(vfs_t, vfs_avlmntpnt));
875
876 /*
877 * Alloc the vfs hash bucket array and locks
878 */
879 rvfs_list = kmem_zalloc(vfshsz * sizeof (rvfs_t), KM_SLEEP);
880
881 /*
882 * Call machine-dependent routine "rootconf" to choose a root
883 * file system type.
884 */
885 if (rootconf())
886 panic("vfs_mountroot: cannot mount root");
887 /*
888 * Get vnode for '/'. Set up rootdir, u.u_rdir and u.u_cdir
889 * to point to it. These are used by lookuppn() so that it
890 * knows where to start from ('/' or '.').
891 */
892 vfs_setmntpoint(rootvfs, "/", 0);
893 if (VFS_ROOT(rootvfs, &rootdir))
894 panic("vfs_mountroot: no root vnode");
895
896 /*
3650 */
3651 if (zone->zone_vfslist == NULL) {
3652 ASSERT(zone != global_zone);
3653 zone->zone_vfslist = vfsp;
3654 } else {
3655 zone->zone_vfslist->vfs_zone_prev->vfs_zone_next = vfsp;
3656 vfsp->vfs_zone_prev = zone->zone_vfslist->vfs_zone_prev;
3657 zone->zone_vfslist->vfs_zone_prev = vfsp;
3658 vfsp->vfs_zone_next = zone->zone_vfslist;
3659 }
3660 }
3661
3662 /*
3663 * Link into the hash table, inserting it at the end, so that LOFS
3664 * with the same fsid as UFS (or other) file systems will not hide
3665 * the UFS.
3666 */
3667 vfs_hash_add(vfsp, 0);
3668
3669 /*
3670 * Link into tree indexed by mntpoint, for vfs_mntpoint2vfsp
3671 * mntix discerns entries with the same key
3672 */
3673 vfsp->vfs_mntix = ++vfs_curr_mntix;
3674 avl_add(&vfs_by_dev, vfsp);
3675
3676 /*
3677 * Link into tree indexed by dev, for vfs_devismounted
3678 */
3679 avl_add(&vfs_by_mntpnt, vfsp);
3680
3681 /*
3682 * update the mnttab modification time
3683 */
3684 vfs_mnttab_modtimeupd();
3685 vfs_list_unlock();
3686 zone_rele(zone);
3687 }
3688
3689 void
3690 vfs_list_remove(struct vfs *vfsp)
3691 {
3692 zone_t *zone;
3693
3694 zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
3695 ASSERT(zone != NULL);
3696 /*
3697 * Callers are responsible for preventing attempts to unmount the
3698 * root.
3699 */
3700 ASSERT(vfsp != rootvfs);
3701
3702 vfs_list_lock();
3703
3704 /*
3705 * Remove from avl trees
3706 */
3707 avl_remove(&vfs_by_mntpnt, vfsp);
3708 avl_remove(&vfs_by_dev, vfsp);
3709
3710 /*
3711 * Remove from hash.
3712 */
3713 vfs_hash_remove(vfsp);
3714
3715 /*
3716 * Remove from vfs list.
3717 */
3718 vfsp->vfs_prev->vfs_next = vfsp->vfs_next;
3719 vfsp->vfs_next->vfs_prev = vfsp->vfs_prev;
3720 vfsp->vfs_next = vfsp->vfs_prev = NULL;
3721
3722 /*
3723 * Remove from zone-specific vfs list.
3724 */
3725 if (zone->zone_vfslist == vfsp)
3726 zone->zone_vfslist = vfsp->vfs_zone_next;
3727
3728 if (vfsp->vfs_zone_next == vfsp) {
3729 ASSERT(vfsp->vfs_zone_prev == vfsp);
3730 ASSERT(zone->zone_vfslist == vfsp);
3784 for (mipp = vfs_miplist; mipp != NULL; mipp = mipp->mip_next) {
3785 if (mipp->mip_dev == dev) {
3786 if (mipp->mip_vfsp != vfsp)
3787 retval = 1;
3788 break;
3789 }
3790 }
3791 mutex_exit(&vfs_miplist_mutex);
3792 return (retval);
3793 }
3794
3795 /*
3796 * Search the vfs list for a specified device. Returns 1, if entry is found
3797 * or 0 if no suitable entry is found.
3798 */
3799
3800 int
3801 vfs_devismounted(dev_t dev)
3802 {
3803 struct vfs *vfsp;
3804 int found = 0;
3805 struct vfs search;
3806 avl_index_t index;
3807
3808 search.vfs_dev = dev;
3809 search.vfs_mntix = 0;
3810
3811 vfs_list_read_lock();
3812
3813 /*
3814 * there might be several entries with the same dev in the tree,
3815 * only discerned by mntix. To find the first, we start with a mntix
3816 * of 0. The search will fail. The following avl_nearest will give
3817 * us the actual first entry.
3818 */
3819 VERIFY(avl_find(&vfs_by_dev, &search, &index) == NULL);
3820 vfsp = avl_nearest(&vfs_by_dev, index, AVL_AFTER);
3821
3822 if (vfsp != NULL && vfsp->vfs_dev == dev)
3823 found = 1;
3824
3825 vfs_list_unlock();
3826 return (found);
3827 }
3828
3829 /*
3830 * Search the vfs list for a specified device. Returns a pointer to it
3831 * or NULL if no suitable entry is found. The caller of this routine
3832 * is responsible for releasing the returned vfs pointer.
3833 */
3834 struct vfs *
3835 vfs_dev2vfsp(dev_t dev)
3836 {
3837 struct vfs *vfsp;
3838 int found;
3839 struct vfs search;
3840 avl_index_t index;
3841
3842 search.vfs_dev = dev;
3843 search.vfs_mntix = 0;
3844
3845 vfs_list_read_lock();
3846
3847 /*
3848 * there might be several entries with the same dev in the tree,
3849 * only discerned by mntix. To find the first, we start with a mntix
3850 * of 0. The search will fail. The following avl_nearest will give
3851 * us the actual first entry.
3852 */
3853 VERIFY(avl_find(&vfs_by_dev, &search, &index) == NULL);
3854 vfsp = avl_nearest(&vfs_by_dev, index, AVL_AFTER);
3855
3856 found = 0;
3857 while (vfsp != NULL && vfsp->vfs_dev == dev) {
3858 /*
3859 * The following could be made more efficient by making
3860 * the entire loop use vfs_zone_next if the call is from
3861 * a zone. The only callers, however, ustat(2) and
3862 * umount2(2), don't seem to justify the added
3863 * complexity at present.
3864 */
3865 if (ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
3866 curproc->p_zone)) {
3867 VFS_HOLD(vfsp);
3868 found = 1;
3869 break;
3870 }
3871 vfsp = AVL_NEXT(&vfs_by_dev, vfsp);
3872 }
3873 vfs_list_unlock();
3874 return (found ? vfsp : NULL);
3875 }
3876
3877 /*
3878 * Search the vfs list for a specified mntpoint. Returns a pointer to it
3879 * or NULL if no suitable entry is found. The caller of this routine
3880 * is responsible for releasing the returned vfs pointer.
3881 *
3882 * Note that if multiple mntpoints match, the last one matching is
3883 * returned in an attempt to return the "top" mount when overlay
3884 * mounts are covering the same mount point. This is accomplished by starting
3885 * at the end of the list and working our way backwards, stopping at the first
3886 * matching mount.
3887 */
3888 struct vfs *
3889 vfs_mntpoint2vfsp(const char *mp)
3890 {
3891 struct vfs *vfsp;
3892 struct vfs *retvfsp = NULL;
3893 zone_t *zone = curproc->p_zone;
3894 struct vfs *list;
3895
3896 vfs_list_read_lock();
3897 if (getzoneid() == GLOBAL_ZONEID) {
3898 /*
3899 * The global zone may see filesystems in any zone.
3900 */
3901 struct vfs search;
3902 search.vfs_mntpt = refstr_alloc(mp);
3903 search.vfs_mntix = UINT64_MAX;
3904 avl_index_t index;
3905
3906 /*
3907 * there might be several entries with the same mntpnt in the
3908 * tree, only discerned by mntix. To find the last, we start
3909 * with a mntix of UINT64_MAX. The search will fail. The
3910 * following avl_nearest will give us the actual last entry
3911 * matching the mntpnt.
3912 */
3913 VERIFY(avl_find(&vfs_by_mntpnt, &search, &index) == 0);
3914 vfsp = avl_nearest(&vfs_by_mntpnt, index, AVL_BEFORE);
3915
3916 refstr_rele(search.vfs_mntpt);
3917
3918 if (vfsp != NULL &&
3919 strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0)
3920 retvfsp = vfsp;
3921 } else if ((list = zone->zone_vfslist) != NULL) {
3922 const char *mntpt;
3923
3924 vfsp = list->vfs_zone_prev;
3925 do {
3926 mntpt = refstr_value(vfsp->vfs_mntpt);
3927 mntpt = ZONE_PATH_TRANSLATE(mntpt, zone);
3928 if (strcmp(mntpt, mp) == 0) {
3929 retvfsp = vfsp;
3930 break;
3931 }
3932 vfsp = vfsp->vfs_zone_prev;
3933 } while (vfsp != list->vfs_zone_prev);
3934 }
3935 if (retvfsp)
3936 VFS_HOLD(retvfsp);
3937 vfs_list_unlock();
3938 return (retvfsp);
3939 }
3940
|