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.
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.
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]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2016, Joyent Inc.
28 * This file implements /dev filesystem operations for non-global
29 * instances. Three major entry points:
30 * devname_profile_update()
31 * Update matching rules determining which names to export
33 * Return the list of exported names
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/sysmacros.h>
41 #include <sys/vnode.h>
43 #include <sys/dirent.h>
44 #include <sys/pathname.h>
45 #include <sys/fs/dv_node.h>
46 #include <sys/fs/sdev_impl.h>
47 #include <sys/sunndi.h>
48 #include <sys/modctl.h>
58 WALK_DIR_CONTINUE
= 0,
62 static const char *sdev_nvp_val_err
= "nvpair_value error %d, %s\n";
64 static void process_rule(struct sdev_node
*, struct sdev_node
*,
66 static void walk_dir(struct vnode
*, void *, int (*)(char *, void *));
69 prof_getattr(struct sdev_node
*dir
, char *name
, struct vnode
*gdv
,
70 struct vattr
*vap
, struct vnode
**avpp
, int *no_fs_perm
)
74 /* get attribute from shadow, if present; else get default */
75 advp
= dir
->sdev_attrvp
;
76 if (advp
&& fop_lookup(advp
, name
, avpp
, NULL
, 0, NULL
, kcred
,
77 NULL
, NULL
, NULL
) == 0) {
78 (void) fop_getattr(*avpp
, vap
, 0, kcred
, NULL
);
79 } else if (gdv
== NULL
|| gdv
->v_type
== VDIR
) {
80 /* always create shadow directory */
81 *vap
= sdev_vattr_dir
;
82 if (advp
&& fop_mkdir(advp
, name
, &sdev_vattr_dir
,
83 avpp
, kcred
, NULL
, 0, NULL
) != 0) {
85 sdcmn_err10(("prof_getattr: failed to create "
86 "shadow directory %s/%s\n", dir
->sdev_path
, name
));
90 * get default permission from devfs
91 * Before calling devfs_get_defattr, we need to get
92 * the realvp (the dv_node). If realvp is not a dv_node,
93 * devfs_get_defattr() will return a system-wide default
94 * attr for device nodes.
97 if (fop_realvp(gdv
, &rvp
, NULL
) != 0)
99 devfs_get_defattr(rvp
, vap
, no_fs_perm
);
103 /* ignore dev_t and vtype from backing store */
105 vap
->va_type
= gdv
->v_type
;
106 vap
->va_rdev
= gdv
->v_rdev
;
111 apply_glob_pattern(struct sdev_node
*pdir
, struct sdev_node
*cdir
)
114 nvpair_t
*nvp
= NULL
;
116 struct vnode
*vp
= SDEVTOV(cdir
);
119 if (vp
->v_type
!= VDIR
)
121 name
= cdir
->sdev_name
;
122 nvl
= pdir
->sdev_prof
.dev_glob_incdir
;
123 while (nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
125 char *expr
= nvpair_name(nvp
);
126 if (!gmatch(name
, expr
))
128 rv
= nvpair_value_string(nvp
, &pathleft
);
130 cmn_err(CE_WARN
, sdev_nvp_val_err
,
131 rv
, nvpair_name(nvp
));
134 process_rule(cdir
, cdir
->sdev_origin
,
135 pathleft
, NULL
, PROFILE_TYPE_INCLUDE
);
140 * Some commonality here with sdev_mknode(), could be simplified.
141 * NOTE: prof_mknode returns with *newdv held once, if success.
144 prof_mknode(struct sdev_node
*dir
, char *name
, struct sdev_node
**newdv
,
145 vattr_t
*vap
, vnode_t
*avp
, void *arg
, cred_t
*cred
)
147 struct sdev_node
*dv
;
150 ASSERT(RW_WRITE_HELD(&dir
->sdev_contents
));
152 /* check cache first */
153 if (dv
= sdev_cache_lookup(dir
, name
)) {
158 /* allocate node and insert into cache */
159 rv
= sdev_nodeinit(dir
, name
, &dv
, NULL
);
165 sdev_cache_update(dir
, &dv
, name
, SDEV_CACHE_ADD
);
168 /* put it in ready state */
169 rv
= sdev_nodeready(*newdv
, vap
, avp
, arg
, cred
);
171 /* handle glob pattern in the middle of a path */
173 if (SDEVTOV(*newdv
)->v_type
== VDIR
)
174 sdcmn_err10(("sdev_origin for %s set to 0x%p\n",
176 apply_glob_pattern(dir
, *newdv
);
178 sdev_cache_update(dir
, &dv
, name
, SDEV_CACHE_DELETE
);
185 * Create a directory node in a non-global dev instance.
186 * Always create shadow vnode. Set sdev_origin to the corresponding
187 * global directory sdev_node if it exists. This facilitates the
191 prof_make_dir(char *name
, struct sdev_node
**gdirp
, struct sdev_node
**dirp
)
193 struct sdev_node
*dir
= *dirp
;
194 struct sdev_node
*gdir
= *gdirp
;
195 struct sdev_node
*newdv
;
196 struct vnode
*avp
, *gnewdir
= NULL
;
200 /* see if name already exists */
201 rw_enter(&dir
->sdev_contents
, RW_READER
);
202 if (newdv
= sdev_cache_lookup(dir
, name
)) {
204 *gdirp
= newdv
->sdev_origin
;
205 rw_exit(&dir
->sdev_contents
);
209 rw_exit(&dir
->sdev_contents
);
211 /* find corresponding dir node in global dev */
213 error
= fop_lookup(SDEVTOV(gdir
), name
, &gnewdir
,
214 NULL
, 0, NULL
, kcred
, NULL
, NULL
, NULL
);
216 *gdirp
= VTOSDEV(gnewdir
);
217 } else { /* it's ok if there no global dir */
222 /* get attribute from shadow, also create shadow dir */
223 prof_getattr(dir
, name
, gnewdir
, &vattr
, &avp
, NULL
);
225 /* create dev directory vnode */
226 rw_enter(&dir
->sdev_contents
, RW_WRITER
);
227 error
= prof_mknode(dir
, name
, &newdv
, &vattr
, avp
, (void *)*gdirp
,
229 rw_exit(&dir
->sdev_contents
);
239 * Look up a logical name in the global zone.
240 * Provides the ability to map the global zone's device name
241 * to an alternate name within a zone. The primary example
242 * is the virtual console device /dev/zcons/[zonename]/zconsole
243 * mapped to /[zonename]/root/dev/zconsole.
246 prof_lookup_globaldev(struct sdev_node
*dir
, struct sdev_node
*gdir
,
247 char *name
, char *rename
)
250 struct vnode
*avp
, *gdv
, *gddv
;
251 struct sdev_node
*newdv
;
252 struct vattr vattr
= {0};
255 /* check if node already exists */
256 newdv
= sdev_cache_lookup(dir
, rename
);
258 ASSERT(newdv
->sdev_state
!= SDEV_ZOMBIE
);
259 SDEV_SIMPLE_RELE(newdv
);
263 /* sanity check arguments */
264 if (!gdir
|| pn_get(name
, UIO_SYSSPACE
, &pn
))
267 /* perform a relative lookup of the global /dev instance */
268 gddv
= SDEVTOV(gdir
);
270 error
= lookuppnvp(&pn
, NULL
, FOLLOW
, NULLVPP
, &gdv
,
271 rootdir
, gddv
, kcred
);
274 sdcmn_err10(("prof_lookup_globaldev: %s not found\n", name
));
277 ASSERT(gdv
&& gdv
->v_type
!= VLNK
);
280 * Found the entry in global /dev, figure out attributes
281 * by looking at backing store. Call into devfs for default.
282 * Note, mapped device is persisted under the new name
284 prof_getattr(dir
, rename
, gdv
, &vattr
, &avp
, NULL
);
286 if (gdv
->v_type
!= VDIR
) {
292 if (prof_mknode(dir
, rename
, &newdv
, &vattr
, avp
,
293 (void *)gdir
, kcred
) == 0) {
294 ASSERT(newdv
->sdev_state
!= SDEV_ZOMBIE
);
295 SDEV_SIMPLE_RELE(newdv
);
300 prof_make_sym(struct sdev_node
*dir
, char *lnm
, char *tgt
)
302 struct sdev_node
*newdv
;
304 if (prof_mknode(dir
, lnm
, &newdv
, &sdev_vattr_lnk
, NULL
,
305 (void *)tgt
, kcred
) == 0) {
306 ASSERT(newdv
->sdev_state
!= SDEV_ZOMBIE
);
307 SDEV_SIMPLE_RELE(newdv
);
312 * Create symlinks in the current directory based on profile
315 prof_make_symlinks(struct sdev_node
*dir
)
318 nvpair_t
*nvp
= NULL
;
319 nvlist_t
*nvl
= dir
->sdev_prof
.dev_symlink
;
322 ASSERT(RW_WRITE_HELD(&dir
->sdev_contents
));
327 while (nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
328 lnm
= nvpair_name(nvp
);
329 rv
= nvpair_value_string(nvp
, &tgt
);
331 cmn_err(CE_WARN
, sdev_nvp_val_err
,
332 rv
, nvpair_name(nvp
));
335 prof_make_sym(dir
, lnm
, tgt
);
340 prof_make_maps(struct sdev_node
*dir
)
342 nvpair_t
*nvp
= NULL
;
343 nvlist_t
*nvl
= dir
->sdev_prof
.dev_map
;
346 ASSERT(RW_WRITE_HELD(&dir
->sdev_contents
));
351 while (nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
353 char *rename
= nvpair_name(nvp
);
354 rv
= nvpair_value_string(nvp
, &name
);
356 cmn_err(CE_WARN
, sdev_nvp_val_err
,
357 rv
, nvpair_name(nvp
));
360 sdcmn_err10(("map %s -> %s\n", name
, rename
));
361 (void) prof_lookup_globaldev(dir
, sdev_origins
->sdev_root
,
372 match_name(char *name
, void *arg
)
374 struct match_arg
*margp
= (struct match_arg
*)arg
;
376 if (gmatch(name
, margp
->expr
)) {
378 return (WALK_DIR_TERMINATE
);
380 return (WALK_DIR_CONTINUE
);
384 is_nonempty_dir(char *name
, char *pathleft
, struct sdev_node
*dir
)
386 struct match_arg marg
;
389 struct sdev_node
*gdir
= dir
->sdev_origin
;
391 if (fop_lookup(SDEVTOV(gdir
), name
, &gvp
, NULL
, 0, NULL
, kcred
,
392 NULL
, NULL
, NULL
) != 0)
395 if (gvp
->v_type
!= VDIR
) {
400 if (pn_get(pathleft
, UIO_SYSSPACE
, &pn
) != 0) {
405 marg
.expr
= kmem_alloc(MAXNAMELEN
, KM_SLEEP
);
406 (void) pn_getcomponent(&pn
, marg
.expr
);
409 walk_dir(gvp
, &marg
, match_name
);
411 kmem_free(marg
.expr
, MAXNAMELEN
);
418 /* Check if name passes matching rules */
420 prof_name_matched(char *name
, struct sdev_node
*dir
)
425 nvpair_t
*nvp
= NULL
;
428 /* check against nvlist for leaf include/exclude */
429 nvl
= dir
->sdev_prof
.dev_name
;
430 while (nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
431 expr
= nvpair_name(nvp
);
432 rv
= nvpair_value_int32(nvp
, &type
);
434 cmn_err(CE_WARN
, sdev_nvp_val_err
,
435 rv
, nvpair_name(nvp
));
439 if (type
== PROFILE_TYPE_EXCLUDE
) {
440 if (gmatch(name
, expr
))
441 return (0); /* excluded */
443 match
= gmatch(name
, expr
);
447 sdcmn_err10(("prof_name_matched: %s\n", name
));
451 /* check for match against directory globbing pattern */
452 nvl
= dir
->sdev_prof
.dev_glob_incdir
;
453 while (nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
455 expr
= nvpair_name(nvp
);
456 if (gmatch(name
, expr
) == 0)
458 rv
= nvpair_value_string(nvp
, &pathleft
);
460 cmn_err(CE_WARN
, sdev_nvp_val_err
,
461 rv
, nvpair_name(nvp
));
464 if (is_nonempty_dir(name
, pathleft
, dir
)) {
465 sdcmn_err10(("prof_name_matched: dir %s\n", name
));
474 walk_dir(struct vnode
*dvp
, void *arg
, int (*callback
)(char *, void *))
482 size_t dbuflen
, dlen
;
487 dbuf
= kmem_zalloc(dlen
, KM_SLEEP
);
491 uio
.uio_segflg
= UIO_SYSSPACE
;
493 uio
.uio_extflg
= UIO_COPY_CACHED
;
495 uio
.uio_llimit
= MAXOFFSET_T
;
499 while (!error
&& !eof
) {
500 uio
.uio_resid
= dlen
;
501 iov
.iov_base
= (char *)dbuf
;
503 (void) fop_rwlock(dvp
, V_WRITELOCK_FALSE
, NULL
);
504 error
= fop_readdir(dvp
, &uio
, kcred
, &eof
, NULL
, 0);
505 fop_rwunlock(dvp
, V_WRITELOCK_FALSE
, NULL
);
507 dbuflen
= dlen
- uio
.uio_resid
;
508 if (error
|| dbuflen
== 0)
510 for (dp
= dbuf
; ((intptr_t)dp
<
511 (intptr_t)dbuf
+ dbuflen
);
512 dp
= (dirent64_t
*)((intptr_t)dp
+ dp
->d_reclen
)) {
515 if (strcmp(nm
, ".") == 0 ||
516 strcmp(nm
, "..") == 0)
519 if (callback(nm
, arg
) == WALK_DIR_TERMINATE
)
525 kmem_free(dbuf
, dlen
);
529 * Last chance for a zone to see a node. If our parent dir is
530 * SDEV_ZONED, then we look up the "zone" property for the node. If the
531 * property is found and matches the current zone name, we allow it.
532 * Note that this isn't quite correct for the global zone peeking inside
533 * a zone's /dev - for that to work, we'd have to have a per-dev-mount
534 * zone ref squirreled away.
537 prof_zone_matched(char *name
, struct sdev_node
*dir
)
539 vnode_t
*gvn
= SDEVTOV(dir
->sdev_origin
);
542 char zonename
[ZONENAME_MAX
];
543 int znlen
= ZONENAME_MAX
;
546 ASSERT((dir
->sdev_flags
& SDEV_ZONED
) != 0);
548 sdcmn_err10(("sdev_node %p is zoned, looking for %s\n",
551 if (pn_get(name
, UIO_SYSSPACE
, &pn
))
556 ret
= lookuppnvp(&pn
, NULL
, FOLLOW
, NULLVPP
, &vn
, rootdir
, gvn
, kcred
);
561 sdcmn_err10(("prof_zone_matched: %s not found\n", name
));
566 * VBLK doesn't matter, and the property name is in fact treated
569 ret
= e_ddi_getlongprop_buf(vn
->v_rdev
, VBLK
, (char *)"zone",
570 DDI_PROP_NOTPROM
| DDI_PROP_DONTPASS
, (caddr_t
)zonename
, &znlen
);
574 if (ret
== DDI_PROP_NOT_FOUND
) {
575 sdcmn_err10(("vnode %p: no zone prop\n", (void *)vn
));
577 } else if (ret
!= DDI_PROP_SUCCESS
) {
578 sdcmn_err10(("vnode %p: zone prop error: %d\n",
583 sdcmn_err10(("vnode %p zone prop: %s\n", (void *)vn
, zonename
));
584 return (strcmp(zonename
, curproc
->p_zone
->zone_name
) == 0);
588 prof_make_name_glob(char *nm
, void *arg
)
590 struct sdev_node
*ddv
= (struct sdev_node
*)arg
;
592 if (prof_name_matched(nm
, ddv
))
593 prof_lookup_globaldev(ddv
, ddv
->sdev_origin
, nm
, nm
);
595 return (WALK_DIR_CONTINUE
);
599 prof_make_name_zone(char *nm
, void *arg
)
601 struct sdev_node
*ddv
= (struct sdev_node
*)arg
;
603 if (prof_zone_matched(nm
, ddv
))
604 prof_lookup_globaldev(ddv
, ddv
->sdev_origin
, nm
, nm
);
606 return (WALK_DIR_CONTINUE
);
610 prof_make_names_walk(struct sdev_node
*ddv
, int (*cb
)(char *, void *))
612 struct sdev_node
*gdir
;
614 gdir
= ddv
->sdev_origin
;
617 walk_dir(SDEVTOV(gdir
), (void *)ddv
, cb
);
621 prof_make_names(struct sdev_node
*dir
)
624 nvpair_t
*nvp
= NULL
;
625 nvlist_t
*nvl
= dir
->sdev_prof
.dev_name
;
628 ASSERT(RW_WRITE_HELD(&dir
->sdev_contents
));
630 if ((dir
->sdev_flags
& SDEV_ZONED
) != 0)
631 prof_make_names_walk(dir
, prof_make_name_zone
);
636 if (dir
->sdev_prof
.has_glob
) {
637 prof_make_names_walk(dir
, prof_make_name_glob
);
641 /* Walk nvlist and lookup corresponding device in global inst */
642 while (nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
644 rv
= nvpair_value_int32(nvp
, &type
);
646 cmn_err(CE_WARN
, sdev_nvp_val_err
,
647 rv
, nvpair_name(nvp
));
650 if (type
== PROFILE_TYPE_EXCLUDE
)
652 name
= nvpair_name(nvp
);
653 (void) prof_lookup_globaldev(dir
, dir
->sdev_origin
,
659 * Return True if directory cache is out of date and should be updated.
662 prof_dev_needupdate(sdev_node_t
*ddv
)
664 sdev_node_t
*gdir
= ddv
->sdev_origin
;
667 * Caller can have either reader or writer lock
669 ASSERT(RW_LOCK_HELD(&ddv
->sdev_contents
));
672 * We need to rebuild the directory content if
673 * - ddv is not in a SDEV_ZOMBIE state
674 * - SDEV_BUILD is set OR
675 * - The device tree generation number has changed OR
676 * - The corresponding /dev namespace has been updated
678 return ((ddv
->sdev_state
!= SDEV_ZOMBIE
) &&
679 (((ddv
->sdev_flags
& SDEV_BUILD
) != 0) ||
680 (ddv
->sdev_devtree_gen
!= devtree_gen
) ||
682 (ddv
->sdev_ldir_gen
!= gdir
->sdev_gdir_gen
))));
686 * Build directory vnodes based on the profile and the global
690 prof_filldir(sdev_node_t
*ddv
)
694 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
696 if (!prof_dev_needupdate(ddv
)) {
697 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
701 * Upgrade to writer lock
703 if (rw_tryupgrade(&ddv
->sdev_contents
) == 0) {
705 * We need to drop the read lock and re-acquire it as a
706 * write lock. While we do this the condition may change so we
707 * need to re-check condition
709 rw_exit(&ddv
->sdev_contents
);
710 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
711 if (!prof_dev_needupdate(ddv
)) {
712 /* Downgrade back to the read lock before returning */
713 rw_downgrade(&ddv
->sdev_contents
);
717 /* At this point we should have a write lock */
718 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
720 sdcmn_err10(("devtree_gen (%s): %ld -> %ld\n",
721 ddv
->sdev_path
, ddv
->sdev_devtree_gen
, devtree_gen
));
723 gdir
= ddv
->sdev_origin
;
726 sdcmn_err10(("sdev_dir_gen (%s): %ld -> %ld\n",
727 ddv
->sdev_path
, ddv
->sdev_ldir_gen
,
728 gdir
->sdev_gdir_gen
));
730 /* update flags and generation number so next filldir is quick */
731 if ((ddv
->sdev_flags
& SDEV_BUILD
) == SDEV_BUILD
) {
732 ddv
->sdev_flags
&= ~SDEV_BUILD
;
734 ddv
->sdev_devtree_gen
= devtree_gen
;
736 ddv
->sdev_ldir_gen
= gdir
->sdev_gdir_gen
;
738 prof_make_symlinks(ddv
);
740 prof_make_names(ddv
);
741 rw_downgrade(&ddv
->sdev_contents
);
744 /* apply include/exclude pattern to existing directory content */
746 apply_dir_pattern(struct sdev_node
*dir
, char *expr
, char *pathleft
, int type
)
748 struct sdev_node
*dv
;
751 if (pathleft
== NULL
) {
752 if (type
== PROFILE_TYPE_INCLUDE
)
753 return; /* nothing to do for include */
754 (void) sdev_cleandir(dir
, expr
, SDEV_ENFORCE
);
758 /* directory pattern */
759 rw_enter(&dir
->sdev_contents
, RW_WRITER
);
761 for (dv
= SDEV_FIRST_ENTRY(dir
); dv
; dv
= SDEV_NEXT_ENTRY(dir
, dv
)) {
762 if (gmatch(dv
->sdev_name
, expr
) == 0 ||
763 SDEVTOV(dv
)->v_type
!= VDIR
)
765 process_rule(dv
, dv
->sdev_origin
,
766 pathleft
, NULL
, type
);
768 rw_exit(&dir
->sdev_contents
);
772 * Add a profile rule.
773 * tgt represents a device name matching expression,
774 * matching device names are to be either included or excluded.
777 prof_add_rule(char *name
, char *tgt
, struct sdev_node
*dir
, int type
)
780 nvlist_t
**nvlp
= NULL
;
783 ASSERT(SDEVTOV(dir
)->v_type
== VDIR
);
785 rw_enter(&dir
->sdev_contents
, RW_WRITER
);
788 case PROFILE_TYPE_INCLUDE
:
790 nvlp
= &(dir
->sdev_prof
.dev_glob_incdir
);
792 nvlp
= &(dir
->sdev_prof
.dev_name
);
794 case PROFILE_TYPE_EXCLUDE
:
796 nvlp
= &(dir
->sdev_prof
.dev_glob_excdir
);
798 nvlp
= &(dir
->sdev_prof
.dev_name
);
800 case PROFILE_TYPE_MAP
:
801 nvlp
= &(dir
->sdev_prof
.dev_map
);
803 case PROFILE_TYPE_SYMLINK
:
804 nvlp
= &(dir
->sdev_prof
.dev_symlink
);
808 /* initialize nvlist */
810 error
= nvlist_alloc(nvlp
, NV_UNIQUE_NAME
, KM_SLEEP
);
815 rv
= nvlist_add_string(*nvlp
, name
, tgt
);
817 rv
= nvlist_add_int32(*nvlp
, name
, type
);
820 /* rebuild directory content */
821 dir
->sdev_flags
|= SDEV_BUILD
;
823 if ((type
== PROFILE_TYPE_INCLUDE
) &&
824 (strpbrk(name
, "*?[]") != NULL
)) {
825 dir
->sdev_prof
.has_glob
= 1;
828 rw_exit(&dir
->sdev_contents
);
830 /* additional details for glob pattern and exclusion */
832 case PROFILE_TYPE_INCLUDE
:
833 case PROFILE_TYPE_EXCLUDE
:
834 apply_dir_pattern(dir
, name
, tgt
, type
);
840 * Parse path components and apply requested matching rule at
844 process_rule(struct sdev_node
*dir
, struct sdev_node
*gdir
,
845 char *path
, char *tgt
, int type
)
851 if ((strlen(path
) > 5) && (strncmp(path
, "/dev/", 5) == 0)) {
855 if (pn_get(path
, UIO_SYSSPACE
, &pn
) != 0)
858 name
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
859 (void) pn_getcomponent(&pn
, name
);
863 while (pn_pathleft(&pn
)) {
864 /* If this is pattern, just add the pattern */
865 if (strpbrk(name
, "*?[]") != NULL
&&
866 (type
== PROFILE_TYPE_INCLUDE
||
867 type
== PROFILE_TYPE_EXCLUDE
)) {
872 if ((rv
= prof_make_dir(name
, &gdir
, &dir
)) != 0) {
873 cmn_err(CE_CONT
, "process_rule: %s error %d\n",
877 (void) pn_getcomponent(&pn
, name
);
881 /* process the leaf component */
883 prof_add_rule(name
, tgt
, dir
, type
);
884 SDEV_SIMPLE_RELE(dir
);
887 kmem_free(name
, MAXPATHLEN
);
892 copyin_nvlist(char *packed_usr
, size_t packed_sz
, nvlist_t
**nvlp
)
896 nvlist_t
*profile
= NULL
;
898 /* simple sanity check */
899 if (packed_usr
== NULL
|| packed_sz
== 0)
902 /* copyin packed profile nvlist */
903 packed
= kmem_alloc(packed_sz
, KM_NOSLEEP
);
906 err
= copyin(packed_usr
, packed
, packed_sz
);
908 /* unpack packed profile nvlist */
910 cmn_err(CE_WARN
, "copyin_nvlist: copyin failed with "
912 else if (err
= nvlist_unpack(packed
, packed_sz
, &profile
, KM_NOSLEEP
))
913 cmn_err(CE_WARN
, "copyin_nvlist: nvlist_unpack "
914 "failed with err %d\n", err
);
916 kmem_free(packed
, packed_sz
);
923 * Process profile passed down from libdevinfo. There are four types
925 * include: export a name or names matching a pattern
926 * exclude: exclude a name or names matching a pattern
927 * symlink: create a local symlink
928 * map: export a device with a name different from the global zone
929 * Note: We may consider supporting fop_symlink in non-global instances,
930 * because it does not present any security risk. For now, the fs
931 * instance is read only.
934 sdev_process_profile(struct sdev_data
*sdev_data
, nvlist_t
*profile
)
937 char *nvname
, *dname
;
938 struct sdev_node
*dir
, *gdir
;
939 char **pair
; /* for symlinks and maps */
943 gdir
= sdev_origins
->sdev_root
; /* root of global /dev */
944 dir
= sdev_data
->sdev_root
; /* root of current instance */
948 /* process nvpairs in the list */
950 while (nvpair
= nvlist_next_nvpair(profile
, nvpair
)) {
951 nvname
= nvpair_name(nvpair
);
952 ASSERT(nvname
!= NULL
);
954 if (strcmp(nvname
, SDEV_NVNAME_INCLUDE
) == 0) {
955 rv
= nvpair_value_string(nvpair
, &dname
);
957 cmn_err(CE_WARN
, sdev_nvp_val_err
,
958 rv
, nvpair_name(nvpair
));
961 process_rule(dir
, gdir
, dname
, NULL
,
962 PROFILE_TYPE_INCLUDE
);
963 } else if (strcmp(nvname
, SDEV_NVNAME_EXCLUDE
) == 0) {
964 rv
= nvpair_value_string(nvpair
, &dname
);
966 cmn_err(CE_WARN
, sdev_nvp_val_err
,
967 rv
, nvpair_name(nvpair
));
970 process_rule(dir
, gdir
, dname
, NULL
,
971 PROFILE_TYPE_EXCLUDE
);
972 } else if (strcmp(nvname
, SDEV_NVNAME_SYMLINK
) == 0) {
973 rv
= nvpair_value_string_array(nvpair
, &pair
, &nelem
);
975 cmn_err(CE_WARN
, sdev_nvp_val_err
,
976 rv
, nvpair_name(nvpair
));
980 process_rule(dir
, gdir
, pair
[0], pair
[1],
981 PROFILE_TYPE_SYMLINK
);
982 } else if (strcmp(nvname
, SDEV_NVNAME_MAP
) == 0) {
983 rv
= nvpair_value_string_array(nvpair
, &pair
, &nelem
);
985 cmn_err(CE_WARN
, sdev_nvp_val_err
,
986 rv
, nvpair_name(nvpair
));
989 process_rule(dir
, gdir
, pair
[1], pair
[0],
991 } else if (strcmp(nvname
, SDEV_NVNAME_MOUNTPT
) != 0) {
992 cmn_err(CE_WARN
, "sdev_process_profile: invalid "
993 "nvpair %s\n", nvname
);
1000 prof_lookup(vnode_t
*dvp
, char *nm
, struct vnode
**vpp
, struct cred
*cred
)
1002 struct sdev_node
*ddv
= VTOSDEV(dvp
);
1003 struct sdev_node
*dv
;
1007 * Empty name or ., return node itself.
1010 if ((nmlen
== 0) || ((nmlen
== 1) && (nm
[0] == '.'))) {
1011 *vpp
= SDEVTOV(ddv
);
1017 * .., return the parent directory
1019 if ((nmlen
== 2) && (strcmp(nm
, "..") == 0)) {
1020 *vpp
= SDEVTOV(ddv
->sdev_dotdot
);
1025 rw_enter(&ddv
->sdev_contents
, RW_READER
);
1026 dv
= sdev_cache_lookup(ddv
, nm
);
1029 dv
= sdev_cache_lookup(ddv
, nm
);
1031 rw_exit(&ddv
->sdev_contents
);
1033 sdcmn_err10(("prof_lookup: %s not found\n", nm
));
1037 return (sdev_to_vp(dv
, vpp
));
1041 * This is invoked after a new filesystem is mounted to define the
1042 * name space. It is also invoked during normal system operation
1043 * to update the name space.
1045 * Applications call di_prof_commit() in libdevinfo, which invokes
1046 * modctl(). modctl calls this function. The input is a packed nvlist.
1049 devname_profile_update(char *packed
, size_t packed_sz
)
1054 struct sdev_data
*mntinfo
;
1059 if ((err
= copyin_nvlist(packed
, packed_sz
, &nvl
)) != 0)
1063 /* The first nvpair must be the mount point */
1064 nvp
= nvlist_next_nvpair(nvl
, NULL
);
1065 if (strcmp(nvpair_name(nvp
), SDEV_NVNAME_MOUNTPT
) != 0) {
1067 "devname_profile_update: mount point not specified");
1072 /* find the matching filesystem instance */
1073 rv
= nvpair_value_string(nvp
, &mntpt
);
1075 cmn_err(CE_WARN
, sdev_nvp_val_err
,
1076 rv
, nvpair_name(nvp
));
1078 mntinfo
= sdev_find_mntinfo(mntpt
);
1079 if (mntinfo
== NULL
) {
1080 cmn_err(CE_NOTE
, "devname_profile_update: "
1081 " mount point %s not found", mntpt
);
1086 /* now do the hardwork to process the profile */
1087 sdev_process_profile(mntinfo
, nvl
);
1089 sdev_mntinfo_rele(mntinfo
);