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]
22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
26 * utility routines for the /dev fs
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/t_lock.h>
32 #include <sys/systm.h>
33 #include <sys/sysmacros.h>
37 #include <sys/vnode.h>
39 #include <sys/fcntl.h>
40 #include <sys/flock.h>
43 #include <sys/errno.h>
46 #include <sys/dirent.h>
47 #include <sys/pathname.h>
48 #include <sys/cmn_err.h>
49 #include <sys/debug.h>
51 #include <sys/policy.h>
52 #include <fs/fs_subr.h>
53 #include <sys/mount.h>
54 #include <sys/fs/snode.h>
55 #include <sys/fs/dv_node.h>
56 #include <sys/fs/sdev_impl.h>
57 #include <sys/sunndi.h>
58 #include <sys/sunmdi.h>
62 #include <sys/modctl.h>
65 int sdev_debug
= 0x00000001;
66 int sdev_debug_cache_flags
= 0;
72 /* prototype memory vattrs */
73 vattr_t sdev_vattr_dir
= {
74 AT_TYPE
|AT_MODE
|AT_UID
|AT_GID
, /* va_mask */
76 SDEV_DIRMODE_DEFAULT
, /* va_mode */
77 SDEV_UID_DEFAULT
, /* va_uid */
78 SDEV_GID_DEFAULT
, /* va_gid */
92 vattr_t sdev_vattr_lnk
= {
93 AT_TYPE
|AT_MODE
, /* va_mask */
95 SDEV_LNKMODE_DEFAULT
, /* va_mode */
96 SDEV_UID_DEFAULT
, /* va_uid */
97 SDEV_GID_DEFAULT
, /* va_gid */
111 vattr_t sdev_vattr_blk
= {
112 AT_TYPE
|AT_MODE
|AT_UID
|AT_GID
, /* va_mask */
114 S_IFBLK
| SDEV_DEVMODE_DEFAULT
, /* va_mode */
115 SDEV_UID_DEFAULT
, /* va_uid */
116 SDEV_GID_DEFAULT
, /* va_gid */
130 vattr_t sdev_vattr_chr
= {
131 AT_TYPE
|AT_MODE
|AT_UID
|AT_GID
, /* va_mask */
133 S_IFCHR
| SDEV_DEVMODE_DEFAULT
, /* va_mode */
134 SDEV_UID_DEFAULT
, /* va_uid */
135 SDEV_GID_DEFAULT
, /* va_gid */
149 kmem_cache_t
*sdev_node_cache
; /* sdev_node cache */
150 int devtype
; /* fstype */
153 static struct vnodeops
*sdev_get_vop(struct sdev_node
*);
154 static void sdev_set_no_negcache(struct sdev_node
*);
155 static fs_operation_def_t
*sdev_merge_vtab(const fs_operation_def_t
[]);
156 static void sdev_free_vtab(fs_operation_def_t
*);
159 sdev_prof_free(struct sdev_node
*dv
)
161 ASSERT(!SDEV_IS_GLOBAL(dv
));
162 if (dv
->sdev_prof
.dev_name
)
163 nvlist_free(dv
->sdev_prof
.dev_name
);
164 if (dv
->sdev_prof
.dev_map
)
165 nvlist_free(dv
->sdev_prof
.dev_map
);
166 if (dv
->sdev_prof
.dev_symlink
)
167 nvlist_free(dv
->sdev_prof
.dev_symlink
);
168 if (dv
->sdev_prof
.dev_glob_incdir
)
169 nvlist_free(dv
->sdev_prof
.dev_glob_incdir
);
170 if (dv
->sdev_prof
.dev_glob_excdir
)
171 nvlist_free(dv
->sdev_prof
.dev_glob_excdir
);
172 bzero(&dv
->sdev_prof
, sizeof (dv
->sdev_prof
));
175 /* sdev_node cache constructor */
178 i_sdev_node_ctor(void *buf
, void *cfarg
, int flag
)
180 struct sdev_node
*dv
= (struct sdev_node
*)buf
;
183 bzero(buf
, sizeof (struct sdev_node
));
184 vp
= dv
->sdev_vnode
= vn_alloc(flag
);
189 rw_init(&dv
->sdev_contents
, NULL
, RW_DEFAULT
, NULL
);
193 /* sdev_node cache destructor */
196 i_sdev_node_dtor(void *buf
, void *arg
)
198 struct sdev_node
*dv
= (struct sdev_node
*)buf
;
199 struct vnode
*vp
= SDEVTOV(dv
);
201 rw_destroy(&dv
->sdev_contents
);
205 /* initialize sdev_node cache */
207 sdev_node_cache_init()
212 flags
= sdev_debug_cache_flags
;
214 sdcmn_err(("cache debug flags 0x%x\n", flags
));
217 ASSERT(sdev_node_cache
== NULL
);
218 sdev_node_cache
= kmem_cache_create("sdev_node_cache",
219 sizeof (struct sdev_node
), 0, i_sdev_node_ctor
, i_sdev_node_dtor
,
220 NULL
, NULL
, NULL
, flags
);
223 /* destroy sdev_node cache */
225 sdev_node_cache_fini()
227 ASSERT(sdev_node_cache
!= NULL
);
228 kmem_cache_destroy(sdev_node_cache
);
229 sdev_node_cache
= NULL
;
233 * Compare two nodes lexographically to balance avl tree
236 sdev_compare_nodes(const struct sdev_node
*dv1
, const struct sdev_node
*dv2
)
239 if ((rv
= strcmp(dv1
->sdev_name
, dv2
->sdev_name
)) == 0)
241 return ((rv
< 0) ? -1 : 1);
245 sdev_set_nodestate(struct sdev_node
*dv
, sdev_node_state_t state
)
248 ASSERT(RW_WRITE_HELD(&dv
->sdev_contents
));
249 dv
->sdev_state
= state
;
253 sdev_attr_update(struct sdev_node
*dv
, vattr_t
*vap
)
259 ASSERT(dv
->sdev_attr
);
262 attrp
= dv
->sdev_attr
;
265 attrp
->va_type
= vap
->va_type
;
267 attrp
->va_mode
= vap
->va_mode
;
269 attrp
->va_uid
= vap
->va_uid
;
271 attrp
->va_gid
= vap
->va_gid
;
273 attrp
->va_rdev
= vap
->va_rdev
;
276 attrp
->va_atime
= (mask
& AT_ATIME
) ? vap
->va_atime
: now
;
277 attrp
->va_mtime
= (mask
& AT_MTIME
) ? vap
->va_mtime
: now
;
278 attrp
->va_ctime
= (mask
& AT_CTIME
) ? vap
->va_ctime
: now
;
282 sdev_attr_alloc(struct sdev_node
*dv
, vattr_t
*vap
)
284 ASSERT(dv
->sdev_attr
== NULL
);
285 ASSERT(vap
->va_mask
& AT_TYPE
);
286 ASSERT(vap
->va_mask
& AT_MODE
);
288 dv
->sdev_attr
= kmem_zalloc(sizeof (struct vattr
), KM_SLEEP
);
289 sdev_attr_update(dv
, vap
);
292 /* alloc and initialize a sdev_node */
294 sdev_nodeinit(struct sdev_node
*ddv
, char *nm
, struct sdev_node
**newdv
,
297 struct sdev_node
*dv
= NULL
;
300 devname_handle_t
*dhl
;
302 nmlen
= strlen(nm
) + 1;
303 if (nmlen
> MAXNAMELEN
) {
304 sdcmn_err9(("sdev_nodeinit: node name %s"
307 return (ENAMETOOLONG
);
310 dv
= kmem_cache_alloc(sdev_node_cache
, KM_SLEEP
);
312 dv
->sdev_name
= kmem_alloc(nmlen
, KM_SLEEP
);
313 bcopy(nm
, dv
->sdev_name
, nmlen
);
314 dv
->sdev_namelen
= nmlen
- 1; /* '\0' not included */
315 len
= strlen(ddv
->sdev_path
) + strlen(nm
) + 2;
316 dv
->sdev_path
= kmem_alloc(len
, KM_SLEEP
);
317 (void) snprintf(dv
->sdev_path
, len
, "%s/%s", ddv
->sdev_path
, nm
);
318 /* overwritten for VLNK nodes */
319 dv
->sdev_symlink
= NULL
;
323 vp
->v_vfsp
= SDEVTOV(ddv
)->v_vfsp
;
325 vp
->v_type
= vap
->va_type
;
328 * initialized to the parent's vnodeops.
329 * maybe overwriten for a VDIR
331 vn_setops(vp
, vn_getops(SDEVTOV(ddv
)));
334 dv
->sdev_dotdot
= NULL
;
335 dv
->sdev_attrvp
= NULL
;
337 sdev_attr_alloc(dv
, vap
);
339 dv
->sdev_attr
= NULL
;
342 dv
->sdev_ino
= sdev_mkino(dv
);
343 dv
->sdev_nlink
= 0; /* updated on insert */
344 dv
->sdev_flags
= ddv
->sdev_flags
; /* inherit from the parent first */
345 dv
->sdev_flags
|= SDEV_BUILD
;
346 mutex_init(&dv
->sdev_lookup_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
347 cv_init(&dv
->sdev_lookup_cv
, NULL
, CV_DEFAULT
, NULL
);
348 if (SDEV_IS_GLOBAL(ddv
)) {
349 dv
->sdev_flags
|= SDEV_GLOBAL
;
350 dhl
= &(dv
->sdev_handle
);
353 sdev_set_no_negcache(dv
);
354 dv
->sdev_gdir_gen
= 0;
356 dv
->sdev_flags
&= ~SDEV_GLOBAL
;
357 dv
->sdev_origin
= NULL
; /* set later */
358 bzero(&dv
->sdev_prof
, sizeof (dv
->sdev_prof
));
359 dv
->sdev_ldir_gen
= 0;
360 dv
->sdev_devtree_gen
= 0;
363 rw_enter(&dv
->sdev_contents
, RW_WRITER
);
364 sdev_set_nodestate(dv
, SDEV_INIT
);
365 rw_exit(&dv
->sdev_contents
);
372 * transition a sdev_node into SDEV_READY state
375 sdev_nodeready(struct sdev_node
*dv
, struct vattr
*vap
, struct vnode
*avp
,
376 void *args
, struct cred
*cred
)
379 struct vnode
*vp
= SDEVTOV(dv
);
382 ASSERT(dv
&& (dv
->sdev_state
!= SDEV_READY
) && vap
);
386 vp
->v_rdev
= vap
->va_rdev
;
387 rw_enter(&dv
->sdev_contents
, RW_WRITER
);
390 dv
->sdev_flags
&= ~SDEV_PERSIST
;
391 dv
->sdev_flags
&= ~SDEV_DYNAMIC
;
392 vn_setops(vp
, sdev_get_vop(dv
)); /* from internal vtab */
393 ASSERT(dv
->sdev_dotdot
);
394 ASSERT(SDEVTOV(dv
->sdev_dotdot
)->v_type
== VDIR
);
395 vp
->v_rdev
= SDEVTOV(dv
->sdev_dotdot
)->v_rdev
;
396 avl_create(&dv
->sdev_entries
,
397 (int (*)(const void *, const void *))sdev_compare_nodes
,
398 sizeof (struct sdev_node
),
399 offsetof(struct sdev_node
, sdev_avllink
));
400 } else if (type
== VLNK
) {
403 dv
->sdev_symlink
= i_ddi_strdup((char *)args
, KM_SLEEP
);
408 if (!(SDEV_IS_GLOBAL(dv
))) {
409 dv
->sdev_origin
= (struct sdev_node
*)args
;
410 dv
->sdev_flags
&= ~SDEV_PERSIST
;
414 * shadow node is created here OR
415 * if failed (indicated by dv->sdev_attrvp == NULL),
416 * created later in sdev_setattr
419 dv
->sdev_attrvp
= avp
;
421 if (dv
->sdev_attr
== NULL
) {
422 sdev_attr_alloc(dv
, vap
);
424 sdev_attr_update(dv
, vap
);
427 if ((dv
->sdev_attrvp
== NULL
) && SDEV_IS_PERSIST(dv
))
428 error
= sdev_shadow_node(dv
, cred
);
432 /* transition to READY state */
433 sdev_set_nodestate(dv
, SDEV_READY
);
434 sdev_nc_node_exists(dv
);
436 sdev_set_nodestate(dv
, SDEV_ZOMBIE
);
438 rw_exit(&dv
->sdev_contents
);
443 * setting ZOMBIE state
446 sdev_nodezombied(struct sdev_node
*dv
)
448 rw_enter(&dv
->sdev_contents
, RW_WRITER
);
449 sdev_set_nodestate(dv
, SDEV_ZOMBIE
);
450 rw_exit(&dv
->sdev_contents
);
455 * Build the VROOT sdev_node.
459 sdev_mkroot(struct vfs
*vfsp
, dev_t devdev
, struct vnode
*mvp
,
460 struct vnode
*avp
, struct cred
*cred
)
462 struct sdev_node
*dv
;
464 char devdir
[] = "/dev";
466 ASSERT(sdev_node_cache
!= NULL
);
468 dv
= kmem_cache_alloc(sdev_node_cache
, KM_SLEEP
);
475 vn_setops(vp
, sdev_vnodeops
); /* apply the default vnodeops at /dev */
479 dv
->sdev_name
= i_ddi_strdup(
480 (char *)refstr_value(vfsp
->vfs_mntpt
), KM_SLEEP
);
482 /* vfs_mountdev1 set mount point later */
483 dv
->sdev_name
= i_ddi_strdup("/dev", KM_SLEEP
);
484 dv
->sdev_namelen
= strlen(dv
->sdev_name
); /* '\0' not included */
485 dv
->sdev_path
= i_ddi_strdup(devdir
, KM_SLEEP
);
486 dv
->sdev_ino
= SDEV_ROOTINO
;
487 dv
->sdev_nlink
= 2; /* name + . (no sdev_insert) */
488 dv
->sdev_dotdot
= dv
; /* .. == self */
489 dv
->sdev_attrvp
= avp
;
490 dv
->sdev_attr
= NULL
;
491 mutex_init(&dv
->sdev_lookup_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
492 cv_init(&dv
->sdev_lookup_cv
, NULL
, CV_DEFAULT
, NULL
);
493 if (strcmp(dv
->sdev_name
, "/dev") == 0) {
494 dv
->sdev_flags
= SDEV_BUILD
|SDEV_GLOBAL
|SDEV_PERSIST
;
495 bzero(&dv
->sdev_handle
, sizeof (dv
->sdev_handle
));
496 dv
->sdev_gdir_gen
= 0;
498 dv
->sdev_flags
= SDEV_BUILD
;
499 dv
->sdev_flags
&= ~SDEV_PERSIST
;
500 bzero(&dv
->sdev_prof
, sizeof (dv
->sdev_prof
));
501 dv
->sdev_ldir_gen
= 0;
502 dv
->sdev_devtree_gen
= 0;
505 avl_create(&dv
->sdev_entries
,
506 (int (*)(const void *, const void *))sdev_compare_nodes
,
507 sizeof (struct sdev_node
),
508 offsetof(struct sdev_node
, sdev_avllink
));
510 rw_enter(&dv
->sdev_contents
, RW_WRITER
);
511 sdev_set_nodestate(dv
, SDEV_READY
);
512 rw_exit(&dv
->sdev_contents
);
513 sdev_nc_node_exists(dv
);
517 /* directory dependent vop table */
518 struct sdev_vop_table
{
519 char *vt_name
; /* subdirectory name */
520 const fs_operation_def_t
*vt_service
; /* vnodeops table */
521 struct vnodeops
*vt_vops
; /* constructed vop */
522 struct vnodeops
**vt_global_vops
; /* global container for vop */
523 int (*vt_vtor
)(struct sdev_node
*); /* validate sdev_node */
528 * A nice improvement would be to provide a plug-in mechanism
529 * for this table instead of a const table.
531 static struct sdev_vop_table vtab
[] =
533 { "pts", devpts_vnodeops_tbl
, NULL
, &devpts_vnodeops
, devpts_validate
,
534 SDEV_DYNAMIC
| SDEV_VTOR
},
536 { "vt", devvt_vnodeops_tbl
, NULL
, &devvt_vnodeops
, devvt_validate
,
537 SDEV_DYNAMIC
| SDEV_VTOR
},
539 { "zvol", devzvol_vnodeops_tbl
, NULL
, &devzvol_vnodeops
,
540 devzvol_validate
, SDEV_DYNAMIC
| SDEV_VTOR
| SDEV_SUBDIR
},
542 { "zcons", NULL
, NULL
, NULL
, NULL
, SDEV_NO_NCACHE
},
544 { "net", devnet_vnodeops_tbl
, NULL
, &devnet_vnodeops
, devnet_validate
,
545 SDEV_DYNAMIC
| SDEV_VTOR
},
547 { "ipnet", devipnet_vnodeops_tbl
, NULL
, &devipnet_vnodeops
,
548 devipnet_validate
, SDEV_DYNAMIC
| SDEV_VTOR
| SDEV_NO_NCACHE
},
550 { "lofi", NULL
, NULL
, NULL
, NULL
, SDEV_ZONED
},
551 { "rlofi", NULL
, NULL
, NULL
, NULL
, SDEV_ZONED
},
553 { NULL
, NULL
, NULL
, NULL
, NULL
, 0}
556 struct sdev_vop_table
*
557 sdev_match(struct sdev_node
*dv
)
562 for (i
= 0; vtab
[i
].vt_name
; i
++) {
563 if (strcmp(vtab
[i
].vt_name
, dv
->sdev_name
) == 0)
565 if (vtab
[i
].vt_flags
& SDEV_SUBDIR
) {
568 ASSERT(strlen(dv
->sdev_path
) > 5);
569 ptr
= dv
->sdev_path
+ 5;
570 vlen
= strlen(vtab
[i
].vt_name
);
571 if ((strncmp(vtab
[i
].vt_name
, ptr
,
572 vlen
- 1) == 0) && ptr
[vlen
] == '/')
581 * sets a directory's vnodeops if the directory is in the vtab;
583 static struct vnodeops
*
584 sdev_get_vop(struct sdev_node
*dv
)
586 struct sdev_vop_table
*vtp
;
589 path
= dv
->sdev_path
;
592 /* gets the relative path to /dev/ */
595 /* gets the vtab entry it matches */
596 if ((vtp
= sdev_match(dv
)) != NULL
) {
597 dv
->sdev_flags
|= vtp
->vt_flags
;
600 if (vtp
->vt_global_vops
)
601 *(vtp
->vt_global_vops
) = vtp
->vt_vops
;
602 return (vtp
->vt_vops
);
605 if (vtp
->vt_service
) {
606 fs_operation_def_t
*templ
;
607 templ
= sdev_merge_vtab(vtp
->vt_service
);
608 if (vn_make_ops(vtp
->vt_name
,
609 (const fs_operation_def_t
*)templ
,
610 &vtp
->vt_vops
) != 0) {
611 cmn_err(CE_PANIC
, "%s: malformed vnode ops\n",
615 if (vtp
->vt_global_vops
) {
616 *(vtp
->vt_global_vops
) = vtp
->vt_vops
;
618 sdev_free_vtab(templ
);
619 return (vtp
->vt_vops
);
621 return (sdev_vnodeops
);
624 /* child inherits the persistence of the parent */
625 if (SDEV_IS_PERSIST(dv
->sdev_dotdot
))
626 dv
->sdev_flags
|= SDEV_PERSIST
;
628 return (sdev_vnodeops
);
632 sdev_set_no_negcache(struct sdev_node
*dv
)
637 ASSERT(dv
->sdev_path
);
638 path
= dv
->sdev_path
+ strlen("/dev/");
640 for (i
= 0; vtab
[i
].vt_name
; i
++) {
641 if (strcmp(vtab
[i
].vt_name
, path
) == 0) {
642 if (vtab
[i
].vt_flags
& SDEV_NO_NCACHE
)
643 dv
->sdev_flags
|= SDEV_NO_NCACHE
;
650 sdev_get_vtor(struct sdev_node
*dv
)
652 struct sdev_vop_table
*vtp
;
654 vtp
= sdev_match(dv
);
656 return ((void *)vtp
->vt_vtor
);
662 * Build the base root inode
665 sdev_mkino(struct sdev_node
*dv
)
670 * for now, follow the lead of tmpfs here
671 * need to someday understand the requirements here
673 ino
= (ino_t
)(uint32_t)((uintptr_t)dv
>> 3);
674 ino
+= SDEV_ROOTINO
+ 1;
680 sdev_getlink(struct vnode
*linkvp
, char **link
)
684 struct uio uio
= {0};
685 struct iovec iov
= {0};
689 ASSERT(linkvp
->v_type
== VLNK
);
691 buf
= kmem_zalloc(MAXPATHLEN
, KM_SLEEP
);
693 iov
.iov_len
= MAXPATHLEN
;
696 uio
.uio_resid
= MAXPATHLEN
;
697 uio
.uio_segflg
= UIO_SYSSPACE
;
698 uio
.uio_llimit
= MAXOFFSET_T
;
700 err
= VOP_READLINK(linkvp
, &uio
, kcred
, NULL
);
702 cmn_err(CE_WARN
, "readlink %s failed in dev\n", buf
);
703 kmem_free(buf
, MAXPATHLEN
);
707 /* mission complete */
708 *link
= i_ddi_strdup(buf
, KM_SLEEP
);
709 kmem_free(buf
, MAXPATHLEN
);
714 * A convenient wrapper to get the devfs node vnode for a device
715 * minor functionality: readlink() of a /dev symlink
716 * Place the link into dv->sdev_symlink
719 sdev_follow_link(struct sdev_node
*dv
)
722 struct vnode
*linkvp
;
725 linkvp
= SDEVTOV(dv
);
728 ASSERT(linkvp
->v_type
== VLNK
);
729 err
= sdev_getlink(linkvp
, &link
);
731 (void) sdev_nodezombied(dv
);
732 dv
->sdev_symlink
= NULL
;
736 ASSERT(link
!= NULL
);
737 dv
->sdev_symlink
= link
;
742 sdev_node_check(struct sdev_node
*dv
, struct vattr
*nvap
, void *nargs
)
744 vtype_t otype
= SDEVTOV(dv
)->v_type
;
747 * existing sdev_node has a different type.
749 if (otype
!= nvap
->va_type
) {
750 sdcmn_err9(("sdev_node_check: existing node "
751 " %s type %d does not match new node type %d\n",
752 dv
->sdev_name
, otype
, nvap
->va_type
));
757 * For a symlink, the target should be the same.
760 ASSERT(nargs
!= NULL
);
761 ASSERT(dv
->sdev_symlink
!= NULL
);
762 if (strcmp(dv
->sdev_symlink
, (char *)nargs
) != 0) {
763 sdcmn_err9(("sdev_node_check: existing node "
764 " %s has different symlink %s as new node "
765 " %s\n", dv
->sdev_name
, dv
->sdev_symlink
,
775 * sdev_mknode - a wrapper for sdev_nodeinit(), sdev_nodeready()
780 * - newdv (sdev_node for nm is returned here)
781 * - vap (vattr for the node to be created, va_type should be set.
782 * - avp (attribute vnode)
783 * the defaults should be used if unknown)
787 * . global sdev_node (for !SDEV_GLOBAL)
788 * - state: SDEV_INIT, SDEV_READY
790 * only ddv, nm, newddv, vap, cred are required for sdev_mknode(SDEV_INIT)
792 * NOTE: directory contents writers lock needs to be held before
793 * calling this routine.
796 sdev_mknode(struct sdev_node
*ddv
, char *nm
, struct sdev_node
**newdv
,
797 struct vattr
*vap
, struct vnode
*avp
, void *args
, struct cred
*cred
,
798 sdev_node_state_t state
)
801 sdev_node_state_t node_state
;
802 struct sdev_node
*dv
= NULL
;
804 ASSERT(state
!= SDEV_ZOMBIE
);
805 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
810 /* allocate and initialize a sdev_node */
811 if (ddv
->sdev_state
== SDEV_ZOMBIE
) {
812 sdcmn_err9(("sdev_mknode: parent %s ZOMBIEd\n",
817 error
= sdev_nodeinit(ddv
, nm
, &dv
, vap
);
819 sdcmn_err9(("sdev_mknode: error %d,"
820 " name %s can not be initialized\n",
826 /* insert into the directory cache */
827 error
= sdev_cache_update(ddv
, &dv
, nm
, SDEV_CACHE_ADD
);
829 sdcmn_err9(("sdev_mknode: node %s can not"
830 " be added into directory cache\n", nm
));
836 node_state
= dv
->sdev_state
;
837 ASSERT(node_state
!= SDEV_ZOMBIE
);
839 if (state
== SDEV_READY
) {
840 switch (node_state
) {
842 error
= sdev_nodeready(dv
, vap
, avp
, args
, cred
);
844 sdcmn_err9(("sdev_mknode: node %s can NOT"
845 " be transitioned into READY state, "
846 "error %d\n", nm
, error
));
851 * Do some sanity checking to make sure
852 * the existing sdev_node is what has been
855 error
= sdev_node_check(dv
, vap
, args
);
864 ASSERT((*newdv
)->sdev_state
!= SDEV_ZOMBIE
);
866 SDEV_SIMPLE_RELE(dv
);
874 * convenient wrapper to change vp's ATIME, CTIME and MTIME
877 sdev_update_timestamps(struct vnode
*vp
, cred_t
*cred
, uint_t mask
)
892 attr
.va_mask
= (mask
& AT_TIMES
);
893 err
= VOP_SETATTR(vp
, &attr
, 0, cred
, NULL
);
894 if (err
&& (err
!= EROFS
)) {
895 sdcmn_err(("update timestamps error %d\n", err
));
900 * the backing store vnode is released here
904 sdev_nodedestroy(struct sdev_node
*dv
, uint_t flags
)
907 ASSERT(dv
->sdev_nlink
== 0);
909 if (dv
->sdev_attrvp
!= NULLVP
) {
910 VN_RELE(dv
->sdev_attrvp
);
912 * reset the attrvp so that no more
913 * references can be made on this already
916 dv
->sdev_attrvp
= NULLVP
;
919 if (dv
->sdev_attr
!= NULL
) {
920 kmem_free(dv
->sdev_attr
, sizeof (struct vattr
));
921 dv
->sdev_attr
= NULL
;
924 if (dv
->sdev_name
!= NULL
) {
925 kmem_free(dv
->sdev_name
, dv
->sdev_namelen
+ 1);
926 dv
->sdev_name
= NULL
;
929 if (dv
->sdev_symlink
!= NULL
) {
930 kmem_free(dv
->sdev_symlink
, strlen(dv
->sdev_symlink
) + 1);
931 dv
->sdev_symlink
= NULL
;
935 kmem_free(dv
->sdev_path
, strlen(dv
->sdev_path
) + 1);
936 dv
->sdev_path
= NULL
;
939 if (!SDEV_IS_GLOBAL(dv
))
942 if (SDEVTOV(dv
)->v_type
== VDIR
) {
943 ASSERT(SDEV_FIRST_ENTRY(dv
) == NULL
);
944 avl_destroy(&dv
->sdev_entries
);
947 mutex_destroy(&dv
->sdev_lookup_lock
);
948 cv_destroy(&dv
->sdev_lookup_cv
);
950 /* return node to initial state as per constructor */
951 (void) memset((void *)&dv
->sdev_instance_data
, 0,
952 sizeof (dv
->sdev_instance_data
));
953 vn_invalid(SDEVTOV(dv
));
954 kmem_cache_free(sdev_node_cache
, dv
);
958 * DIRECTORY CACHE lookup
961 sdev_findbyname(struct sdev_node
*ddv
, char *nm
)
963 struct sdev_node
*dv
;
964 struct sdev_node dvtmp
;
967 ASSERT(RW_LOCK_HELD(&ddv
->sdev_contents
));
969 dvtmp
.sdev_name
= nm
;
970 dv
= avl_find(&ddv
->sdev_entries
, &dvtmp
, &where
);
972 ASSERT(dv
->sdev_dotdot
== ddv
);
973 ASSERT(strcmp(dv
->sdev_name
, nm
) == 0);
981 * Inserts a new sdev_node in a parent directory
984 sdev_direnter(struct sdev_node
*ddv
, struct sdev_node
*dv
)
988 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
989 ASSERT(SDEVTOV(ddv
)->v_type
== VDIR
);
990 ASSERT(ddv
->sdev_nlink
>= 2);
991 ASSERT(dv
->sdev_nlink
== 0);
993 dv
->sdev_dotdot
= ddv
;
994 VERIFY(avl_find(&ddv
->sdev_entries
, dv
, &where
) == NULL
);
995 avl_insert(&ddv
->sdev_entries
, dv
, where
);
1000 * The following check is needed because while sdev_nodes are linked
1001 * in SDEV_INIT state, they have their link counts incremented only
1002 * in SDEV_READY state.
1005 decr_link(struct sdev_node
*dv
)
1007 if (dv
->sdev_state
!= SDEV_INIT
)
1010 ASSERT(dv
->sdev_nlink
== 0);
1014 * Delete an existing dv from directory cache
1016 * In the case of a node is still held by non-zero reference count,
1017 * the node is put into ZOMBIE state. Once the reference count
1018 * reaches "0", the node is unlinked and destroyed,
1019 * in sdev_inactive().
1022 sdev_dirdelete(struct sdev_node
*ddv
, struct sdev_node
*dv
)
1026 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
1029 mutex_enter(&vp
->v_lock
);
1031 /* dv is held still */
1032 if (vp
->v_count
> 1) {
1033 rw_enter(&dv
->sdev_contents
, RW_WRITER
);
1034 if (dv
->sdev_state
== SDEV_READY
) {
1036 "sdev_dirdelete: node %s busy with count %d\n",
1037 dv
->sdev_name
, vp
->v_count
));
1038 dv
->sdev_state
= SDEV_ZOMBIE
;
1040 rw_exit(&dv
->sdev_contents
);
1042 mutex_exit(&vp
->v_lock
);
1045 ASSERT(vp
->v_count
== 1);
1047 /* unlink from the memory cache */
1048 ddv
->sdev_nlink
--; /* .. to above */
1049 if (vp
->v_type
== VDIR
) {
1050 decr_link(dv
); /* . to self */
1053 avl_remove(&ddv
->sdev_entries
, dv
);
1054 decr_link(dv
); /* name, back to zero */
1056 mutex_exit(&vp
->v_lock
);
1058 /* destroy the node */
1059 sdev_nodedestroy(dv
, 0);
1064 * check if the source is in the path of the target
1066 * source and target are different
1070 sdev_checkpath(struct sdev_node
*sdv
, struct sdev_node
*tdv
, struct cred
*cred
)
1073 struct sdev_node
*dotdot
, *dir
;
1075 dotdot
= tdv
->sdev_dotdot
;
1079 if (dotdot
== tdv
) {
1085 * avoid error cases like
1090 if (dotdot
== sdv
) {
1096 dotdot
= dir
->sdev_dotdot
;
1098 /* done checking because root is reached */
1099 if (dir
== dotdot
) {
1107 sdev_rnmnode(struct sdev_node
*oddv
, struct sdev_node
*odv
,
1108 struct sdev_node
*nddv
, struct sdev_node
**ndvp
, char *nnm
,
1112 struct vnode
*ovp
= SDEVTOV(odv
);
1115 int doingdir
= (ovp
->v_type
== VDIR
);
1117 int samedir
= (oddv
== nddv
) ? 1 : 0;
1119 struct sdev_node
*idv
= NULL
;
1120 struct sdev_node
*ndv
= NULL
;
1123 vattr
.va_mask
= AT_TYPE
|AT_MODE
|AT_UID
|AT_GID
;
1124 error
= VOP_GETATTR(ovp
, &vattr
, 0, cred
, NULL
);
1129 rw_enter(&oddv
->sdev_contents
, RW_WRITER
);
1130 rw_enter(&nddv
->sdev_contents
, RW_WRITER
);
1133 * the source may have been deleted by another thread before
1136 if (odv
->sdev_state
!= SDEV_READY
) {
1141 if (doingdir
&& (odv
== nddv
)) {
1147 * If renaming a directory, and the parents are different (".." must be
1148 * changed) then the source dir must not be in the dir hierarchy above
1149 * the target since it would orphan everything below the source dir.
1151 if (doingdir
&& (oddv
!= nddv
)) {
1152 error
= sdev_checkpath(odv
, nddv
, cred
);
1157 /* destination existing */
1159 nvp
= SDEVTOV(*ndvp
);
1162 /* handling renaming to itself */
1168 if (nvp
->v_type
== VDIR
) {
1174 if (vn_vfswlock(nvp
)) {
1179 if (vn_mountedvfs(nvp
) != NULL
) {
1185 /* in case dir1 exists in dir2 and "mv dir1 dir2" */
1186 if ((*ndvp
)->sdev_nlink
> 2) {
1193 (void) sdev_dirdelete(nddv
, *ndvp
);
1195 ASSERT(nddv
->sdev_attrvp
);
1196 error
= VOP_RMDIR(nddv
->sdev_attrvp
, nnm
,
1197 nddv
->sdev_attrvp
, cred
, NULL
, 0);
1206 if (SDEV_IS_PERSIST((*ndvp
))) {
1211 * get rid of the node from the directory cache
1212 * note, in case EBUSY is returned, the ZOMBIE
1213 * node is taken care in sdev_mknode.
1215 (void) sdev_dirdelete(nddv
, *ndvp
);
1218 ASSERT(nddv
->sdev_attrvp
);
1219 error
= VOP_REMOVE(nddv
->sdev_attrvp
,
1220 nnm
, cred
, NULL
, 0);
1227 /* fix the source for a symlink */
1228 if (vattr
.va_type
== VLNK
) {
1229 if (odv
->sdev_symlink
== NULL
) {
1230 error
= sdev_follow_link(odv
);
1236 ASSERT(odv
->sdev_symlink
);
1237 link
= i_ddi_strdup(odv
->sdev_symlink
, KM_SLEEP
);
1241 * make a fresh node from the source attrs
1243 ASSERT(RW_WRITE_HELD(&nddv
->sdev_contents
));
1244 error
= sdev_mknode(nddv
, nnm
, ndvp
, &vattr
,
1245 NULL
, (void *)link
, cred
, SDEV_READY
);
1248 kmem_free(link
, strlen(link
) + 1);
1253 ASSERT((*ndvp
)->sdev_state
== SDEV_READY
);
1255 /* move dir contents */
1257 for (idv
= SDEV_FIRST_ENTRY(odv
); idv
;
1258 idv
= SDEV_NEXT_ENTRY(odv
, idv
)) {
1259 error
= sdev_rnmnode(odv
, idv
,
1260 (struct sdev_node
*)(*ndvp
), &ndv
,
1261 idv
->sdev_name
, cred
);
1268 if ((*ndvp
)->sdev_attrvp
) {
1269 sdev_update_timestamps((*ndvp
)->sdev_attrvp
, kcred
,
1272 ASSERT((*ndvp
)->sdev_attr
);
1274 (*ndvp
)->sdev_attr
->va_ctime
= now
;
1275 (*ndvp
)->sdev_attr
->va_atime
= now
;
1278 if (nddv
->sdev_attrvp
) {
1279 sdev_update_timestamps(nddv
->sdev_attrvp
, kcred
,
1282 ASSERT(nddv
->sdev_attr
);
1284 nddv
->sdev_attr
->va_mtime
= now
;
1285 nddv
->sdev_attr
->va_atime
= now
;
1287 rw_exit(&nddv
->sdev_contents
);
1289 rw_exit(&oddv
->sdev_contents
);
1295 rw_exit(&nddv
->sdev_contents
);
1297 rw_exit(&oddv
->sdev_contents
);
1302 * Merge sdev_node specific information into an attribute structure.
1304 * note: sdev_node is not locked here
1307 sdev_vattr_merge(struct sdev_node
*dv
, struct vattr
*vap
)
1309 struct vnode
*vp
= SDEVTOV(dv
);
1311 vap
->va_nlink
= dv
->sdev_nlink
;
1312 vap
->va_nodeid
= dv
->sdev_ino
;
1313 vap
->va_fsid
= SDEVTOV(dv
->sdev_dotdot
)->v_rdev
;
1314 vap
->va_type
= vp
->v_type
;
1316 if (vp
->v_type
== VDIR
) {
1318 vap
->va_fsid
= vp
->v_rdev
;
1319 } else if (vp
->v_type
== VLNK
) {
1321 vap
->va_mode
&= ~S_IFMT
;
1322 vap
->va_mode
|= S_IFLNK
;
1323 } else if ((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) {
1324 vap
->va_rdev
= vp
->v_rdev
;
1325 vap
->va_mode
&= ~S_IFMT
;
1326 if (vap
->va_type
== VCHR
)
1327 vap
->va_mode
|= S_IFCHR
;
1329 vap
->va_mode
|= S_IFBLK
;
1336 sdev_getdefault_attr(enum vtype type
)
1339 return (&sdev_vattr_dir
);
1340 else if (type
== VCHR
)
1341 return (&sdev_vattr_chr
);
1342 else if (type
== VBLK
)
1343 return (&sdev_vattr_blk
);
1344 else if (type
== VLNK
)
1345 return (&sdev_vattr_lnk
);
1350 sdev_to_vp(struct sdev_node
*dv
, struct vnode
**vpp
)
1353 struct vnode
*vp
= SDEVTOV(dv
);
1355 switch (vp
->v_type
) {
1359 * If vnode is a device, return special vnode instead
1360 * (though it knows all about -us- via sp->s_realvp)
1362 *vpp
= specvp(vp
, vp
->v_rdev
, vp
->v_type
, kcred
);
1367 default: /* most types are returned as is */
1375 * junction between devname and root file system, e.g. ufs
1378 devname_backstore_lookup(struct sdev_node
*ddv
, char *nm
, struct vnode
**rvp
)
1380 struct vnode
*rdvp
= ddv
->sdev_attrvp
;
1385 rval
= VOP_LOOKUP(rdvp
, nm
, rvp
, NULL
, 0, NULL
, kcred
, NULL
, NULL
,
1391 sdev_filldir_from_store(struct sdev_node
*ddv
, int dlen
, struct cred
*cred
)
1393 struct sdev_node
*dv
= NULL
;
1395 struct vnode
*dirvp
;
1401 struct dirent64
*dp
;
1407 if (ddv
->sdev_attrvp
== NULL
)
1409 if (!(ddv
->sdev_flags
& SDEV_BUILD
))
1412 dirvp
= ddv
->sdev_attrvp
;
1414 dbuf
= kmem_zalloc(dlen
, KM_SLEEP
);
1418 uio
.uio_segflg
= UIO_SYSSPACE
;
1420 uio
.uio_extflg
= UIO_COPY_CACHED
;
1421 uio
.uio_loffset
= 0;
1422 uio
.uio_llimit
= MAXOFFSET_T
;
1426 while (!error
&& !eof
) {
1427 uio
.uio_resid
= dlen
;
1428 iov
.iov_base
= (char *)dbuf
;
1430 (void) VOP_RWLOCK(dirvp
, V_WRITELOCK_FALSE
, NULL
);
1431 error
= VOP_READDIR(dirvp
, &uio
, kcred
, &eof
, NULL
, 0);
1432 VOP_RWUNLOCK(dirvp
, V_WRITELOCK_FALSE
, NULL
);
1434 dbuflen
= dlen
- uio
.uio_resid
;
1435 if (error
|| dbuflen
== 0)
1438 if (!(ddv
->sdev_flags
& SDEV_BUILD
))
1441 for (dp
= dbuf
; ((intptr_t)dp
<
1442 (intptr_t)dbuf
+ dbuflen
);
1443 dp
= (dirent64_t
*)((intptr_t)dp
+ dp
->d_reclen
)) {
1446 if (strcmp(nm
, ".") == 0 ||
1447 strcmp(nm
, "..") == 0)
1451 dv
= sdev_cache_lookup(ddv
, nm
);
1453 if (dv
->sdev_state
!= SDEV_ZOMBIE
) {
1454 SDEV_SIMPLE_RELE(dv
);
1457 * A ZOMBIE node may not have been
1458 * cleaned up from the backing store,
1459 * bypass this entry in this case,
1460 * and clean it up from the directory
1461 * cache if this is the last call.
1463 (void) sdev_dirdelete(ddv
, dv
);
1468 /* refill the cache if not already */
1469 error
= devname_backstore_lookup(ddv
, nm
, &vp
);
1473 vattr
.va_mask
= AT_TYPE
|AT_MODE
|AT_UID
|AT_GID
;
1474 error
= VOP_GETATTR(vp
, &vattr
, 0, cred
, NULL
);
1478 if (vattr
.va_type
== VLNK
) {
1479 error
= sdev_getlink(vp
, &link
);
1483 ASSERT(link
!= NULL
);
1486 if (!rw_tryupgrade(&ddv
->sdev_contents
)) {
1487 rw_exit(&ddv
->sdev_contents
);
1488 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
1490 error
= sdev_mknode(ddv
, nm
, &dv
, &vattr
, vp
, link
,
1492 rw_downgrade(&ddv
->sdev_contents
);
1495 kmem_free(link
, strlen(link
) + 1);
1501 ASSERT(dv
->sdev_state
!= SDEV_ZOMBIE
);
1502 SDEV_SIMPLE_RELE(dv
);
1511 kmem_free(dbuf
, dlen
);
1517 sdev_filldir_dynamic(struct sdev_node
*ddv
)
1522 struct vattr
*vap
= &vattr
;
1524 struct sdev_node
*dv
= NULL
;
1526 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
1527 ASSERT((ddv
->sdev_flags
& SDEV_BUILD
));
1529 *vap
= *sdev_getdefault_attr(VDIR
); /* note structure copy here */
1530 gethrestime(&vap
->va_atime
);
1531 vap
->va_mtime
= vap
->va_atime
;
1532 vap
->va_ctime
= vap
->va_atime
;
1533 for (i
= 0; vtab
[i
].vt_name
!= NULL
; i
++) {
1534 nm
= vtab
[i
].vt_name
;
1535 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
1537 error
= sdev_mknode(ddv
, nm
, &dv
, vap
, NULL
,
1538 NULL
, kcred
, SDEV_READY
);
1540 cmn_err(CE_WARN
, "%s/%s: error %d\n",
1541 ddv
->sdev_name
, nm
, error
);
1544 ASSERT(dv
->sdev_state
!= SDEV_ZOMBIE
);
1545 SDEV_SIMPLE_RELE(dv
);
1551 * Creating a backing store entry based on sdev_attr.
1552 * This is called either as part of node creation in a persistent directory
1553 * or from setattr/setsecattr to persist access attributes across reboot.
1556 sdev_shadow_node(struct sdev_node
*dv
, struct cred
*cred
)
1559 struct vnode
*dvp
= SDEVTOV(dv
->sdev_dotdot
);
1560 struct vnode
*rdvp
= VTOSDEV(dvp
)->sdev_attrvp
;
1561 struct vattr
*vap
= dv
->sdev_attr
;
1562 char *nm
= dv
->sdev_name
;
1563 struct vnode
*tmpvp
, **rvp
= &tmpvp
, *rrvp
= NULL
;
1565 ASSERT(dv
&& dv
->sdev_name
&& rdvp
);
1566 ASSERT(RW_WRITE_HELD(&dv
->sdev_contents
) && dv
->sdev_attrvp
== NULL
);
1569 /* try to find it in the backing store */
1570 error
= VOP_LOOKUP(rdvp
, nm
, rvp
, NULL
, 0, NULL
, cred
, NULL
, NULL
,
1573 if (VOP_REALVP(*rvp
, &rrvp
, NULL
) == 0) {
1579 kmem_free(dv
->sdev_attr
, sizeof (vattr_t
));
1580 dv
->sdev_attr
= NULL
;
1581 dv
->sdev_attrvp
= *rvp
;
1585 /* let's try to persist the node */
1586 gethrestime(&vap
->va_atime
);
1587 vap
->va_mtime
= vap
->va_atime
;
1588 vap
->va_ctime
= vap
->va_atime
;
1589 vap
->va_mask
|= AT_TYPE
|AT_MODE
;
1590 switch (vap
->va_type
) {
1592 error
= VOP_MKDIR(rdvp
, nm
, vap
, rvp
, cred
, NULL
, 0, NULL
);
1593 sdcmn_err9(("sdev_shadow_node: mkdir vp %p error %d\n",
1594 (void *)(*rvp
), error
));
1600 error
= VOP_CREATE(rdvp
, nm
, vap
, NONEXCL
, VREAD
|VWRITE
,
1601 rvp
, cred
, 0, NULL
, NULL
);
1602 sdcmn_err9(("sdev_shadow_node: create vp %p, error %d\n",
1603 (void *)(*rvp
), error
));
1608 ASSERT(dv
->sdev_symlink
);
1609 error
= VOP_SYMLINK(rdvp
, nm
, vap
, dv
->sdev_symlink
, cred
,
1611 sdcmn_err9(("sdev_shadow_node: create symlink error %d\n",
1615 cmn_err(CE_PANIC
, "dev: %s: sdev_shadow_node "
1620 /* go back to lookup to factor out spec node and set attrvp */
1624 sdcmn_err(("cannot persist %s - error %d\n", dv
->sdev_path
, error
));
1629 sdev_cache_add(struct sdev_node
*ddv
, struct sdev_node
**dv
, char *nm
)
1632 struct sdev_node
*dup
= NULL
;
1634 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
1635 if ((dup
= sdev_findbyname(ddv
, nm
)) == NULL
) {
1636 sdev_direnter(ddv
, *dv
);
1638 if (dup
->sdev_state
== SDEV_ZOMBIE
) {
1639 error
= sdev_dirdelete(ddv
, dup
);
1641 * The ZOMBIE node is still hanging
1642 * around with more than one reference counts.
1643 * Fail the new node creation so that
1644 * the directory cache won't have
1645 * duplicate entries for the same named node
1647 if (error
== EBUSY
) {
1648 SDEV_SIMPLE_RELE(*dv
);
1649 sdev_nodedestroy(*dv
, 0);
1653 sdev_direnter(ddv
, *dv
);
1655 ASSERT((*dv
)->sdev_state
!= SDEV_ZOMBIE
);
1656 SDEV_SIMPLE_RELE(*dv
);
1657 sdev_nodedestroy(*dv
, 0);
1666 sdev_cache_delete(struct sdev_node
*ddv
, struct sdev_node
**dv
)
1668 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
1669 return (sdev_dirdelete(ddv
, *dv
));
1673 * update the in-core directory cache
1676 sdev_cache_update(struct sdev_node
*ddv
, struct sdev_node
**dv
, char *nm
,
1677 sdev_cache_ops_t ops
)
1681 ASSERT((SDEV_HELD(*dv
)));
1683 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
1685 case SDEV_CACHE_ADD
:
1686 error
= sdev_cache_add(ddv
, dv
, nm
);
1688 case SDEV_CACHE_DELETE
:
1689 error
= sdev_cache_delete(ddv
, dv
);
1699 * retrieve the named entry from the directory cache
1702 sdev_cache_lookup(struct sdev_node
*ddv
, char *nm
)
1704 struct sdev_node
*dv
= NULL
;
1706 ASSERT(RW_LOCK_HELD(&ddv
->sdev_contents
));
1707 dv
= sdev_findbyname(ddv
, nm
);
1713 * Implicit reconfig for nodes constructed by a link generator
1714 * Start devfsadm if needed, or if devfsadm is in progress,
1715 * prepare to block on devfsadm either completing or
1716 * constructing the desired node. As devfsadmd is global
1717 * in scope, constructing all necessary nodes, we only
1718 * need to initiate it once.
1721 sdev_call_devfsadmd(struct sdev_node
*ddv
, struct sdev_node
*dv
, char *nm
)
1725 if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state
)) {
1726 sdcmn_err6(("lookup: waiting for %s/%s, 0x%x\n",
1727 ddv
->sdev_name
, nm
, devfsadm_state
));
1728 mutex_enter(&dv
->sdev_lookup_lock
);
1729 SDEV_BLOCK_OTHERS(dv
, (SDEV_LOOKUP
| SDEV_LGWAITING
));
1730 mutex_exit(&dv
->sdev_lookup_lock
);
1732 } else if (!DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state
)) {
1733 sdcmn_err6(("lookup %s/%s starting devfsadm, 0x%x\n",
1734 ddv
->sdev_name
, nm
, devfsadm_state
));
1736 sdev_devfsadmd_thread(ddv
, dv
, kcred
);
1737 mutex_enter(&dv
->sdev_lookup_lock
);
1738 SDEV_BLOCK_OTHERS(dv
,
1739 (SDEV_LOOKUP
| SDEV_LGWAITING
));
1740 mutex_exit(&dv
->sdev_lookup_lock
);
1750 * Support for specialized device naming construction mechanisms
1753 sdev_call_dircallback(struct sdev_node
*ddv
, struct sdev_node
**dvp
, char *nm
,
1754 int (*callback
)(struct sdev_node
*, char *, void **, struct cred
*,
1755 void *, char *), int flags
, struct cred
*cred
)
1758 char *physpath
= NULL
;
1760 struct vattr
*vap
= &vattr
;
1761 struct sdev_node
*dv
= NULL
;
1763 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
1764 if (flags
& SDEV_VLINK
) {
1765 physpath
= kmem_zalloc(MAXPATHLEN
, KM_SLEEP
);
1766 rv
= callback(ddv
, nm
, (void *)&physpath
, kcred
, NULL
,
1769 kmem_free(physpath
, MAXPATHLEN
);
1773 *vap
= *sdev_getdefault_attr(VLNK
); /* structure copy */
1774 vap
->va_size
= strlen(physpath
);
1775 gethrestime(&vap
->va_atime
);
1776 vap
->va_mtime
= vap
->va_atime
;
1777 vap
->va_ctime
= vap
->va_atime
;
1779 rv
= sdev_mknode(ddv
, nm
, &dv
, vap
, NULL
,
1780 (void *)physpath
, cred
, SDEV_READY
);
1781 kmem_free(physpath
, MAXPATHLEN
);
1784 } else if (flags
& SDEV_VATTR
) {
1788 * callback is responsible to set the basic attributes,
1789 * e.g. va_type/va_uid/va_gid/
1790 * dev_t if VCHR or VBLK/
1793 rv
= callback(ddv
, nm
, (void *)&vattr
, kcred
, NULL
, NULL
);
1795 sdcmn_err3(("devname_lookup_func: SDEV_NONE "
1796 "callback failed \n"));
1800 rv
= sdev_mknode(ddv
, nm
, &dv
, &vattr
, NULL
, NULL
,
1807 impossible(("lookup: %s/%s by %s not supported (%d)\n",
1808 SDEVTOV(ddv
)->v_path
, nm
, curproc
->p_user
.u_comm
,
1818 is_devfsadm_thread(char *exec_name
)
1821 * note: because devfsadmd -> /usr/sbin/devfsadm
1822 * it is safe to use "devfsadm" to capture the lookups
1823 * from devfsadm and its daemon version.
1825 if (strcmp(exec_name
, "devfsadm") == 0)
1833 * backing store (SDEV_PERSIST);
1834 * DBNR: a. dir_ops implemented in the loadable modules;
1835 * b. vnode ops in vtab.
1838 devname_lookup_func(struct sdev_node
*ddv
, char *nm
, struct vnode
**vpp
,
1839 struct cred
*cred
, int (*callback
)(struct sdev_node
*, char *, void **,
1840 struct cred
*, void *, char *), int flags
)
1843 struct vnode
*rvp
= NULL
;
1844 struct sdev_node
*dv
= NULL
;
1848 char *lookup_thread
= curproc
->p_user
.u_comm
;
1849 int failed_flags
= 0;
1850 int (*vtor
)(struct sdev_node
*) = NULL
;
1855 if (SDEVTOV(ddv
)->v_type
!= VDIR
)
1859 * Empty name or ., return node itself.
1862 if ((nmlen
== 0) || ((nmlen
== 1) && (nm
[0] == '.'))) {
1863 *vpp
= SDEVTOV(ddv
);
1869 * .., return the parent directory
1871 if ((nmlen
== 2) && (strcmp(nm
, "..") == 0)) {
1872 *vpp
= SDEVTOV(ddv
->sdev_dotdot
);
1877 rw_enter(&ddv
->sdev_contents
, RW_READER
);
1878 if (ddv
->sdev_flags
& SDEV_VTOR
) {
1879 vtor
= (int (*)(struct sdev_node
*))sdev_get_vtor(ddv
);
1885 * (a) directory cache lookup:
1887 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
1888 parent_state
= ddv
->sdev_state
;
1889 dv
= sdev_cache_lookup(ddv
, nm
);
1891 state
= dv
->sdev_state
;
1894 if (is_devfsadm_thread(lookup_thread
))
1897 /* ZOMBIED parent won't allow node creation */
1898 if (parent_state
== SDEV_ZOMBIE
) {
1899 SD_TRACE_FAILED_LOOKUP(ddv
, nm
,
1901 goto nolock_notfound
;
1904 mutex_enter(&dv
->sdev_lookup_lock
);
1905 /* compensate the threads started after devfsadm */
1906 if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state
) &&
1907 !(SDEV_IS_LOOKUP(dv
)))
1908 SDEV_BLOCK_OTHERS(dv
,
1909 (SDEV_LOOKUP
| SDEV_LGWAITING
));
1911 if (SDEV_IS_LOOKUP(dv
)) {
1912 failed_flags
|= SLF_REBUILT
;
1913 rw_exit(&ddv
->sdev_contents
);
1914 error
= sdev_wait4lookup(dv
, SDEV_LOOKUP
);
1915 mutex_exit(&dv
->sdev_lookup_lock
);
1916 rw_enter(&ddv
->sdev_contents
, RW_READER
);
1919 SD_TRACE_FAILED_LOOKUP(ddv
, nm
,
1921 goto nolock_notfound
;
1924 state
= dv
->sdev_state
;
1925 if (state
== SDEV_INIT
) {
1926 SD_TRACE_FAILED_LOOKUP(ddv
, nm
,
1928 goto nolock_notfound
;
1929 } else if (state
== SDEV_READY
) {
1931 } else if (state
== SDEV_ZOMBIE
) {
1932 rw_exit(&ddv
->sdev_contents
);
1933 SD_TRACE_FAILED_LOOKUP(ddv
, nm
,
1939 mutex_exit(&dv
->sdev_lookup_lock
);
1945 rw_exit(&ddv
->sdev_contents
);
1946 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
1950 rw_exit(&ddv
->sdev_contents
);
1951 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
1952 sdev_lookup_failed(ddv
, nm
, failed_flags
);
1957 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
1960 * ZOMBIED parent does not allow new node creation.
1963 if (parent_state
== SDEV_ZOMBIE
) {
1964 rw_exit(&ddv
->sdev_contents
);
1966 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
1971 * (b0): backing store lookup
1972 * SDEV_PERSIST is default except:
1974 * 2) non-chmod'ed local nodes
1977 if (SDEV_IS_PERSIST(ddv
)) {
1978 error
= devname_backstore_lookup(ddv
, nm
, &rvp
);
1982 vattr
.va_mask
= AT_TYPE
|AT_MODE
|AT_UID
|AT_GID
;
1983 error
= VOP_GETATTR(rvp
, &vattr
, 0, cred
, NULL
);
1985 rw_exit(&ddv
->sdev_contents
);
1988 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
1989 sdev_lookup_failed(ddv
, nm
, failed_flags
);
1994 if (vattr
.va_type
== VLNK
) {
1995 error
= sdev_getlink(rvp
, &link
);
1997 rw_exit(&ddv
->sdev_contents
);
2000 SD_TRACE_FAILED_LOOKUP(ddv
, nm
,
2002 sdev_lookup_failed(ddv
, nm
,
2007 ASSERT(link
!= NULL
);
2010 if (!rw_tryupgrade(&ddv
->sdev_contents
)) {
2011 rw_exit(&ddv
->sdev_contents
);
2012 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
2014 error
= sdev_mknode(ddv
, nm
, &dv
, &vattr
,
2015 rvp
, link
, cred
, SDEV_READY
);
2016 rw_downgrade(&ddv
->sdev_contents
);
2019 kmem_free(link
, strlen(link
) + 1);
2024 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2025 rw_exit(&ddv
->sdev_contents
);
2032 } else if (retried
) {
2033 rw_exit(&ddv
->sdev_contents
);
2034 sdcmn_err3(("retry of lookup of %s/%s: failed\n",
2035 ddv
->sdev_name
, nm
));
2038 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2039 sdev_lookup_failed(ddv
, nm
, failed_flags
);
2046 /* first thread that is doing the lookup on this node */
2049 if (!rw_tryupgrade(&ddv
->sdev_contents
)) {
2050 rw_exit(&ddv
->sdev_contents
);
2051 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
2053 error
= sdev_call_dircallback(ddv
, &dv
, nm
, callback
,
2055 rw_downgrade(&ddv
->sdev_contents
);
2059 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2060 rw_exit(&ddv
->sdev_contents
);
2065 if (!rw_tryupgrade(&ddv
->sdev_contents
)) {
2066 rw_exit(&ddv
->sdev_contents
);
2067 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
2069 error
= sdev_mknode(ddv
, nm
, &dv
, NULL
, NULL
, NULL
,
2072 rw_exit(&ddv
->sdev_contents
);
2073 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2074 sdev_lookup_failed(ddv
, nm
, failed_flags
);
2078 rw_downgrade(&ddv
->sdev_contents
);
2082 * (b1) invoking devfsadm once per life time for devfsadm nodes
2084 ASSERT(SDEV_HELD(dv
));
2086 if (SDEV_IS_NO_NCACHE(dv
))
2087 failed_flags
|= SLF_NO_NCACHE
;
2088 if (sdev_reconfig_boot
|| !i_ddi_io_initialized() ||
2089 SDEV_IS_DYNAMIC(ddv
) || SDEV_IS_NO_NCACHE(dv
) ||
2090 ((moddebug
& MODDEBUG_FINI_EBUSY
) != 0)) {
2091 ASSERT(SDEV_HELD(dv
));
2092 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2093 goto nolock_notfound
;
2097 * filter out known non-existent devices recorded
2098 * during initial reconfiguration boot for which
2099 * reconfig should not be done and lookup may
2100 * be short-circuited now.
2102 if (sdev_lookup_filter(ddv
, nm
)) {
2103 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2104 goto nolock_notfound
;
2107 /* bypassing devfsadm internal nodes */
2108 if (is_devfsadm_thread(lookup_thread
)) {
2109 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2110 goto nolock_notfound
;
2113 if (sdev_reconfig_disable
) {
2114 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2115 goto nolock_notfound
;
2118 error
= sdev_call_devfsadmd(ddv
, dv
, nm
);
2120 sdcmn_err8(("lookup of %s/%s by %s: reconfig\n",
2121 ddv
->sdev_name
, nm
, curproc
->p_user
.u_comm
));
2122 if (sdev_reconfig_verbose
) {
2124 "?lookup of %s/%s by %s: reconfig\n",
2125 ddv
->sdev_name
, nm
, curproc
->p_user
.u_comm
);
2128 failed_flags
|= SLF_REBUILT
;
2129 ASSERT(dv
->sdev_state
!= SDEV_ZOMBIE
);
2130 SDEV_SIMPLE_RELE(dv
);
2133 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2134 goto nolock_notfound
;
2138 ASSERT(!(dv
->sdev_flags
& SDEV_STALE
));
2139 ASSERT(dv
->sdev_state
== SDEV_READY
);
2142 * Check validity of returned node
2145 case SDEV_VTOR_VALID
:
2147 case SDEV_VTOR_STALE
:
2149 * The name exists, but the cache entry is
2150 * stale and needs to be re-created.
2152 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
2153 if (rw_tryupgrade(&ddv
->sdev_contents
) == 0) {
2154 rw_exit(&ddv
->sdev_contents
);
2155 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
2157 error
= sdev_cache_update(ddv
, &dv
, nm
,
2159 rw_downgrade(&ddv
->sdev_contents
);
2162 goto lookup_create_node
;
2165 case SDEV_VTOR_INVALID
:
2166 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2167 sdcmn_err7(("lookup: destroy invalid "
2168 "node: %s(%p)\n", dv
->sdev_name
, (void *)dv
));
2169 goto nolock_notfound
;
2170 case SDEV_VTOR_SKIP
:
2171 sdcmn_err7(("lookup: node not applicable - "
2172 "skipping: %s(%p)\n", dv
->sdev_name
, (void *)dv
));
2173 rw_exit(&ddv
->sdev_contents
);
2174 SD_TRACE_FAILED_LOOKUP(ddv
, nm
, retried
);
2179 "dev fs: validator failed: %s(%p)\n",
2180 dv
->sdev_name
, (void *)dv
);
2185 rw_exit(&ddv
->sdev_contents
);
2186 rv
= sdev_to_vp(dv
, vpp
);
2187 sdcmn_err3(("devname_lookup_func: returning vp %p v_count %d state %d "
2188 "for nm %s, error %d\n", (void *)*vpp
, (*vpp
)->v_count
,
2189 dv
->sdev_state
, nm
, rv
));
2194 * Destroy the node that is created for synchronization purposes.
2196 sdcmn_err3(("devname_lookup_func: %s with state %d\n",
2197 nm
, dv
->sdev_state
));
2198 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
2199 if (dv
->sdev_state
== SDEV_INIT
) {
2200 if (!rw_tryupgrade(&ddv
->sdev_contents
)) {
2201 rw_exit(&ddv
->sdev_contents
);
2202 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
2206 * Node state may have changed during the lock
2207 * changes. Re-check.
2209 if (dv
->sdev_state
== SDEV_INIT
) {
2210 (void) sdev_dirdelete(ddv
, dv
);
2211 rw_exit(&ddv
->sdev_contents
);
2212 sdev_lookup_failed(ddv
, nm
, failed_flags
);
2218 rw_exit(&ddv
->sdev_contents
);
2222 sdev_lookup_failed(ddv
, nm
, failed_flags
);
2228 * Given a directory node, mark all nodes beneath as
2229 * STALE, i.e. nodes that don't exist as far as new
2230 * consumers are concerned. Remove them from the
2231 * list of directory entries so that no lookup or
2232 * directory traversal will find them. The node
2233 * not deallocated so existing holds are not affected.
2236 sdev_stale(struct sdev_node
*ddv
)
2238 struct sdev_node
*dv
;
2241 ASSERT(SDEVTOV(ddv
)->v_type
== VDIR
);
2243 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
2244 for (dv
= SDEV_FIRST_ENTRY(ddv
); dv
; dv
= SDEV_NEXT_ENTRY(ddv
, dv
)) {
2246 if (vp
->v_type
== VDIR
)
2249 sdcmn_err9(("sdev_stale: setting stale %s\n",
2251 dv
->sdev_flags
|= SDEV_STALE
;
2252 avl_remove(&ddv
->sdev_entries
, dv
);
2254 ddv
->sdev_flags
|= SDEV_BUILD
;
2255 rw_exit(&ddv
->sdev_contents
);
2259 * Given a directory node, clean out all the nodes beneath.
2260 * If expr is specified, clean node with names matching expr.
2261 * If SDEV_ENFORCE is specified in flags, busy nodes are made stale,
2262 * so they are excluded from future lookups.
2265 sdev_cleandir(struct sdev_node
*ddv
, char *expr
, uint_t flags
)
2270 struct sdev_node
*dv
, *next
= NULL
;
2273 char *bks_name
= NULL
;
2275 ASSERT(SDEVTOV(ddv
)->v_type
== VDIR
);
2278 * We try our best to destroy all unused sdev_node's
2280 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
2281 for (dv
= SDEV_FIRST_ENTRY(ddv
); dv
; dv
= next
) {
2282 next
= SDEV_NEXT_ENTRY(ddv
, dv
);
2285 if (expr
&& gmatch(dv
->sdev_name
, expr
) == 0)
2288 if (vp
->v_type
== VDIR
&&
2289 sdev_cleandir(dv
, NULL
, flags
) != 0) {
2290 sdcmn_err9(("sdev_cleandir: dir %s busy\n",
2296 if (vp
->v_count
> 0 && (flags
& SDEV_ENFORCE
) == 0) {
2297 sdcmn_err9(("sdev_cleandir: dir %s busy\n",
2304 * at this point, either dv is not held or SDEV_ENFORCE
2305 * is specified. In either case, dv needs to be deleted
2309 bkstore
= SDEV_IS_PERSIST(dv
) ? 1 : 0;
2310 if (bkstore
&& (vp
->v_type
== VDIR
))
2314 len
= strlen(dv
->sdev_name
) + 1;
2315 bks_name
= kmem_alloc(len
, KM_SLEEP
);
2316 bcopy(dv
->sdev_name
, bks_name
, len
);
2319 error
= sdev_dirdelete(ddv
, dv
);
2321 if (error
== EBUSY
) {
2322 sdcmn_err9(("sdev_cleandir: dir busy\n"));
2326 /* take care the backing store clean up */
2327 if (bkstore
&& (error
== 0)) {
2329 ASSERT(ddv
->sdev_attrvp
);
2332 error
= VOP_REMOVE(ddv
->sdev_attrvp
,
2333 bks_name
, kcred
, NULL
, 0);
2334 } else if (bkstore
== 2) {
2335 error
= VOP_RMDIR(ddv
->sdev_attrvp
,
2336 bks_name
, ddv
->sdev_attrvp
, kcred
, NULL
, 0);
2339 /* do not propagate the backing store errors */
2341 sdcmn_err9(("sdev_cleandir: backing store"
2347 kmem_free(bks_name
, len
);
2353 ddv
->sdev_flags
|= SDEV_BUILD
;
2354 rw_exit(&ddv
->sdev_contents
);
2364 * a convenient wrapper for readdir() funcs
2367 add_dir_entry(dirent64_t
*de
, char *nm
, size_t size
, ino_t ino
, offset_t off
)
2369 size_t reclen
= DIRENT64_RECLEN(strlen(nm
));
2373 de
->d_ino
= (ino64_t
)ino
;
2374 de
->d_off
= (off64_t
)off
+ 1;
2375 de
->d_reclen
= (ushort_t
)reclen
;
2376 (void) strncpy(de
->d_name
, nm
, DIRENT64_NAMELEN(reclen
));
2381 * sdev_mount service routines
2384 sdev_copyin_mountargs(struct mounta
*uap
, struct sdev_mountargs
*args
)
2388 if (uap
->datalen
!= sizeof (*args
))
2391 if (error
= copyin(uap
->dataptr
, args
, sizeof (*args
))) {
2392 cmn_err(CE_WARN
, "sdev_copyin_mountargs: can not"
2393 "get user data. error %d\n", error
);
2403 #define nextdp(dp) ((struct dirent64 *) \
2404 (intptr_t)((char *)(dp) + (dp)->d_reclen))
2407 * readdir helper func
2410 devname_readdir_func(vnode_t
*vp
, uio_t
*uiop
, cred_t
*cred
, int *eofp
,
2413 struct sdev_node
*ddv
= VTOSDEV(vp
);
2414 struct sdev_node
*dv
;
2416 ulong_t outcount
= 0;
2418 ulong_t alloc_count
;
2426 int (*vtor
)(struct sdev_node
*) = NULL
;
2430 ASSERT(ddv
->sdev_attr
|| ddv
->sdev_attrvp
);
2431 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
2433 if (uiop
->uio_loffset
>= MAXOFF_T
) {
2439 if (uiop
->uio_iovcnt
!= 1)
2442 if (vp
->v_type
!= VDIR
)
2445 if (ddv
->sdev_flags
& SDEV_VTOR
) {
2446 vtor
= (int (*)(struct sdev_node
*))sdev_get_vtor(ddv
);
2453 soff
= uiop
->uio_loffset
;
2454 iovp
= uiop
->uio_iov
;
2455 alloc_count
= iovp
->iov_len
;
2456 dp
= outbuf
= kmem_alloc(alloc_count
, KM_SLEEP
);
2459 if (ddv
->sdev_state
== SDEV_ZOMBIE
)
2462 if (SDEV_IS_GLOBAL(ddv
)) {
2464 if ((sdev_boot_state
== SDEV_BOOT_STATE_COMPLETE
) &&
2465 !sdev_reconfig_boot
&& (flags
& SDEV_BROWSE
) &&
2466 !SDEV_IS_DYNAMIC(ddv
) && !SDEV_IS_NO_NCACHE(ddv
) &&
2467 ((moddebug
& MODDEBUG_FINI_EBUSY
) == 0) &&
2468 !DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state
) &&
2469 !DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state
) &&
2470 !sdev_reconfig_disable
) {
2472 * invoking "devfsadm" to do system device reconfig
2474 mutex_enter(&ddv
->sdev_lookup_lock
);
2475 SDEV_BLOCK_OTHERS(ddv
,
2476 (SDEV_READDIR
|SDEV_LGWAITING
));
2477 mutex_exit(&ddv
->sdev_lookup_lock
);
2479 sdcmn_err8(("readdir of %s by %s: reconfig\n",
2480 ddv
->sdev_path
, curproc
->p_user
.u_comm
));
2481 if (sdev_reconfig_verbose
) {
2483 "?readdir of %s by %s: reconfig\n",
2484 ddv
->sdev_path
, curproc
->p_user
.u_comm
);
2487 sdev_devfsadmd_thread(ddv
, NULL
, kcred
);
2488 } else if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state
)) {
2490 * compensate the "ls" started later than "devfsadm"
2492 mutex_enter(&ddv
->sdev_lookup_lock
);
2493 SDEV_BLOCK_OTHERS(ddv
, (SDEV_READDIR
|SDEV_LGWAITING
));
2494 mutex_exit(&ddv
->sdev_lookup_lock
);
2498 * release the contents lock so that
2499 * the cache may be updated by devfsadmd
2501 rw_exit(&ddv
->sdev_contents
);
2502 mutex_enter(&ddv
->sdev_lookup_lock
);
2503 if (SDEV_IS_READDIR(ddv
))
2504 (void) sdev_wait4lookup(ddv
, SDEV_READDIR
);
2505 mutex_exit(&ddv
->sdev_lookup_lock
);
2506 rw_enter(&ddv
->sdev_contents
, RW_READER
);
2508 sdcmn_err4(("readdir of directory %s by %s\n",
2509 ddv
->sdev_name
, curproc
->p_user
.u_comm
));
2510 if (ddv
->sdev_flags
& SDEV_BUILD
) {
2511 if (SDEV_IS_PERSIST(ddv
)) {
2512 error
= sdev_filldir_from_store(ddv
,
2515 ddv
->sdev_flags
&= ~SDEV_BUILD
;
2520 /* handle "." and ".." */
2524 this_reclen
= DIRENT64_RECLEN(1);
2525 if (alloc_count
< this_reclen
) {
2530 dp
->d_ino
= (ino64_t
)ddv
->sdev_ino
;
2531 dp
->d_off
= (off64_t
)1;
2532 dp
->d_reclen
= (ushort_t
)this_reclen
;
2534 (void) strncpy(dp
->d_name
, ".",
2535 DIRENT64_NAMELEN(this_reclen
));
2536 outcount
+= dp
->d_reclen
;
2542 this_reclen
= DIRENT64_RECLEN(2);
2543 if (alloc_count
< outcount
+ this_reclen
) {
2548 dp
->d_reclen
= (ushort_t
)this_reclen
;
2549 dp
->d_ino
= (ino64_t
)ddv
->sdev_dotdot
->sdev_ino
;
2550 dp
->d_off
= (off64_t
)2;
2552 (void) strncpy(dp
->d_name
, "..",
2553 DIRENT64_NAMELEN(this_reclen
));
2554 outcount
+= dp
->d_reclen
;
2560 /* gets the cache */
2562 for (dv
= SDEV_FIRST_ENTRY(ddv
); dv
;
2563 dv
= SDEV_NEXT_ENTRY(ddv
, dv
), diroff
++) {
2564 sdcmn_err3(("sdev_readdir: diroff %lld soff %lld for '%s' \n",
2565 diroff
, soff
, dv
->sdev_name
));
2567 /* bypassing pre-matured nodes */
2568 if (diroff
< soff
|| (dv
->sdev_state
!= SDEV_READY
)) {
2569 sdcmn_err3(("sdev_readdir: pre-mature node "
2570 "%s %d\n", dv
->sdev_name
, dv
->sdev_state
));
2575 * Check validity of node
2579 case SDEV_VTOR_VALID
:
2581 case SDEV_VTOR_INVALID
:
2582 case SDEV_VTOR_SKIP
:
2586 "dev fs: validator failed: %s(%p)\n",
2587 dv
->sdev_name
, (void *)dv
);
2593 namelen
= strlen(dv
->sdev_name
);
2594 reclen
= DIRENT64_RECLEN(namelen
);
2595 if (outcount
+ reclen
> alloc_count
) {
2598 dp
->d_reclen
= (ushort_t
)reclen
;
2599 dp
->d_ino
= (ino64_t
)dv
->sdev_ino
;
2600 dp
->d_off
= (off64_t
)diroff
+ 1;
2601 (void) strncpy(dp
->d_name
, dv
->sdev_name
,
2602 DIRENT64_NAMELEN(reclen
));
2608 sdcmn_err4(("sdev_readdir: moving %lu bytes: "
2609 "diroff %lld, soff %lld, dv %p\n", outcount
, diroff
, soff
,
2613 error
= uiomove(outbuf
, outcount
, UIO_READ
, uiop
);
2616 uiop
->uio_loffset
= diroff
;
2622 if (ddv
->sdev_attrvp
) {
2624 attr
.va_ctime
= now
;
2625 attr
.va_atime
= now
;
2626 attr
.va_mask
= AT_CTIME
|AT_ATIME
;
2628 (void) VOP_SETATTR(ddv
->sdev_attrvp
, &attr
, 0, kcred
, NULL
);
2631 kmem_free(outbuf
, alloc_count
);
2636 sdev_modctl_lookup(const char *path
, vnode_t
**r_vp
)
2640 struct sdev_node
*svp
;
2646 ASSERT(INGLOBALZONE(curproc
));
2648 if (error
= pn_get((char *)path
, UIO_SYSSPACE
, &pn
))
2650 nm
= kmem_alloc(MAXNAMELEN
, KM_SLEEP
);
2655 while (pn_pathleft(&pn
)) {
2656 ASSERT(vp
->v_type
== VDIR
|| vp
->v_type
== VLNK
);
2657 (void) pn_getcomponent(&pn
, nm
);
2660 * Deal with the .. special case where we may be
2661 * traversing up across a mount point, to the
2662 * root of this filesystem or global root.
2664 if (nm
[0] == '.' && nm
[1] == '.' && nm
[2] == 0) {
2666 if (VN_CMP(vp
, rootdir
)) {
2668 } else if (vp
->v_flag
& VROOT
) {
2672 vfs_rlock_wait(vfsp
);
2673 vp
= cvp
->v_vfsp
->vfs_vnodecovered
;
2675 (cvp
->v_vfsp
->vfs_flag
& VFS_UNMOUNTED
)) {
2689 error
= VOP_LOOKUP(vp
, nm
, &cvp
, NULL
, 0, NULL
, kcred
, NULL
,
2696 /* traverse mount points encountered on our journey */
2697 if (vn_ismntpt(cvp
) && (error
= traverse(&cvp
)) != 0) {
2704 * symbolic link, can be either relative and absolute
2706 if ((cvp
->v_type
== VLNK
) && pn_pathleft(&pn
)) {
2707 struct pathname linkpath
;
2708 pn_alloc(&linkpath
);
2709 if (error
= pn_getsymlink(cvp
, &linkpath
, kcred
)) {
2713 if (pn_pathleft(&linkpath
) == 0)
2714 (void) pn_set(&linkpath
, ".");
2715 error
= pn_insert(&pn
, &linkpath
, strlen(nm
));
2717 if (pn
.pn_pathlen
== 0) {
2721 if (pn
.pn_path
[0] == '/') {
2736 * Direct the operation to the persisting filesystem
2737 * underlying /dev. Bail if we encounter a
2738 * non-persistent dev entity here.
2740 if (cvp
->v_vfsp
->vfs_fstype
== devtype
) {
2742 if ((VTOSDEV(cvp
)->sdev_flags
& SDEV_PERSIST
) == 0) {
2748 if (VTOSDEV(cvp
) == NULL
) {
2754 if ((vp
= svp
->sdev_attrvp
) == NULL
) {
2769 kmem_free(nm
, MAXNAMELEN
);
2776 * Only return persisted nodes in the filesystem underlying /dev.
2788 sdev_modctl_readdir(const char *dir
, char ***dirlistp
,
2789 int *npathsp
, int *npathsp_alloc
, int checking_empty
)
2791 char **pathlist
= NULL
;
2792 char **newlist
= NULL
;
2794 int npaths_alloc
= 0;
2795 dirent64_t
*dbuf
= NULL
;
2803 struct dirent64
*dp
;
2809 error
= sdev_modctl_lookup(dir
, &vp
);
2810 sdcmn_err11(("modctl readdir: %s by %s: %s\n",
2811 dir
, curproc
->p_user
.u_comm
,
2812 (error
== 0) ? "ok" : "failed"));
2816 dlen
= ndirents
* (sizeof (*dbuf
));
2817 dbuf
= kmem_alloc(dlen
, KM_SLEEP
);
2821 uio
.uio_segflg
= UIO_SYSSPACE
;
2823 uio
.uio_extflg
= UIO_COPY_CACHED
;
2824 uio
.uio_loffset
= 0;
2825 uio
.uio_llimit
= MAXOFFSET_T
;
2829 while (!error
&& !eof
) {
2830 uio
.uio_resid
= dlen
;
2831 iov
.iov_base
= (char *)dbuf
;
2834 (void) VOP_RWLOCK(vp
, V_WRITELOCK_FALSE
, NULL
);
2835 error
= VOP_READDIR(vp
, &uio
, kcred
, &eof
, NULL
, 0);
2836 VOP_RWUNLOCK(vp
, V_WRITELOCK_FALSE
, NULL
);
2838 dbuflen
= dlen
- uio
.uio_resid
;
2840 if (error
|| dbuflen
== 0)
2843 for (dp
= dbuf
; ((intptr_t)dp
< (intptr_t)dbuf
+ dbuflen
);
2844 dp
= (dirent64_t
*)((intptr_t)dp
+ dp
->d_reclen
)) {
2848 if (strcmp(nm
, ".") == 0 || strcmp(nm
, "..") == 0)
2850 if (npaths
== npaths_alloc
) {
2853 kmem_zalloc((npaths_alloc
+ 1) *
2854 sizeof (char *), KM_SLEEP
);
2856 bcopy(pathlist
, newlist
,
2857 npaths
* sizeof (char *));
2859 (npaths
+ 1) * sizeof (char *));
2864 s
= kmem_alloc(n
, KM_SLEEP
);
2866 pathlist
[npaths
++] = s
;
2867 sdcmn_err11((" %s/%s\n", dir
, s
));
2869 /* if checking empty, one entry is as good as many */
2870 if (checking_empty
) {
2881 kmem_free(dbuf
, dlen
);
2886 *dirlistp
= pathlist
;
2888 *npathsp_alloc
= npaths_alloc
;
2894 sdev_modctl_readdir_free(char **pathlist
, int npaths
, int npaths_alloc
)
2898 for (i
= 0; i
< npaths
; i
++) {
2899 n
= strlen(pathlist
[i
]) + 1;
2900 kmem_free(pathlist
[i
], n
);
2903 kmem_free(pathlist
, (npaths_alloc
+ 1) * sizeof (char *));
2907 sdev_modctl_devexists(const char *path
)
2912 error
= sdev_modctl_lookup(path
, &vp
);
2913 sdcmn_err11(("modctl dev exists: %s by %s: %s\n",
2914 path
, curproc
->p_user
.u_comm
,
2915 (error
== 0) ? "ok" : "failed"));
2922 extern int sdev_vnodeops_tbl_size
;
2925 * construct a new template with overrides from vtab
2927 static fs_operation_def_t
*
2928 sdev_merge_vtab(const fs_operation_def_t tab
[])
2930 fs_operation_def_t
*new;
2931 const fs_operation_def_t
*tab_entry
;
2933 /* make a copy of standard vnode ops table */
2934 new = kmem_alloc(sdev_vnodeops_tbl_size
, KM_SLEEP
);
2935 bcopy((void *)sdev_vnodeops_tbl
, new, sdev_vnodeops_tbl_size
);
2937 /* replace the overrides from tab */
2938 for (tab_entry
= tab
; tab_entry
->name
!= NULL
; tab_entry
++) {
2939 fs_operation_def_t
*std_entry
= new;
2940 while (std_entry
->name
) {
2941 if (strcmp(tab_entry
->name
, std_entry
->name
) == 0) {
2942 std_entry
->func
= tab_entry
->func
;
2947 if (std_entry
->name
== NULL
)
2948 cmn_err(CE_NOTE
, "sdev_merge_vtab: entry %s unused.",
2955 /* free memory allocated by sdev_merge_vtab */
2957 sdev_free_vtab(fs_operation_def_t
*new)
2959 kmem_free(new, sdev_vnodeops_tbl_size
);
2963 * a generic setattr() function
2965 * note: flags only supports AT_UID and AT_GID.
2966 * Future enhancements can be done for other types, e.g. AT_MODE
2969 devname_setattr_func(struct vnode
*vp
, struct vattr
*vap
, int flags
,
2970 struct cred
*cred
, int (*callback
)(struct sdev_node
*, struct vattr
*,
2973 struct sdev_node
*dv
= VTOSDEV(vp
);
2974 struct sdev_node
*parent
= dv
->sdev_dotdot
;
2976 uint_t mask
= vap
->va_mask
;
2979 /* some sanity checks */
2980 if (vap
->va_mask
& AT_NOSET
)
2983 if (vap
->va_mask
& AT_SIZE
) {
2984 if (vp
->v_type
== VDIR
) {
2989 /* no need to set attribute, but do not fail either */
2991 rw_enter(&parent
->sdev_contents
, RW_READER
);
2992 if (dv
->sdev_state
== SDEV_ZOMBIE
) {
2993 rw_exit(&parent
->sdev_contents
);
2997 /* If backing store exists, just set it. */
2998 if (dv
->sdev_attrvp
) {
2999 rw_exit(&parent
->sdev_contents
);
3000 return (VOP_SETATTR(dv
->sdev_attrvp
, vap
, flags
, cred
, NULL
));
3004 * Otherwise, for nodes with the persistence attribute, create it.
3006 ASSERT(dv
->sdev_attr
);
3007 if (SDEV_IS_PERSIST(dv
) ||
3008 ((vap
->va_mask
& ~AT_TIMES
) != 0 && !SDEV_IS_DYNAMIC(dv
))) {
3009 sdev_vattr_merge(dv
, vap
);
3010 rw_enter(&dv
->sdev_contents
, RW_WRITER
);
3011 error
= sdev_shadow_node(dv
, cred
);
3012 rw_exit(&dv
->sdev_contents
);
3013 rw_exit(&parent
->sdev_contents
);
3017 return (VOP_SETATTR(dv
->sdev_attrvp
, vap
, flags
, cred
, NULL
));
3022 * sdev_attr was allocated in sdev_mknode
3024 rw_enter(&dv
->sdev_contents
, RW_WRITER
);
3025 error
= secpolicy_vnode_setattr(cred
, vp
, vap
,
3026 dv
->sdev_attr
, flags
, sdev_unlocked_access
, dv
);
3028 rw_exit(&dv
->sdev_contents
);
3029 rw_exit(&parent
->sdev_contents
);
3033 get
= dv
->sdev_attr
;
3034 if (mask
& AT_MODE
) {
3035 get
->va_mode
&= S_IFMT
;
3036 get
->va_mode
|= vap
->va_mode
& ~S_IFMT
;
3039 if ((mask
& AT_UID
) || (mask
& AT_GID
)) {
3041 get
->va_uid
= vap
->va_uid
;
3043 get
->va_gid
= vap
->va_gid
;
3045 * a callback must be provided if the protocol is set
3047 if ((protocol
& AT_UID
) || (protocol
& AT_GID
)) {
3049 error
= callback(dv
, get
, protocol
);
3051 rw_exit(&dv
->sdev_contents
);
3052 rw_exit(&parent
->sdev_contents
);
3058 if (mask
& AT_ATIME
)
3059 get
->va_atime
= vap
->va_atime
;
3060 if (mask
& AT_MTIME
)
3061 get
->va_mtime
= vap
->va_mtime
;
3062 if (mask
& (AT_MODE
| AT_UID
| AT_GID
| AT_CTIME
)) {
3063 gethrestime(&get
->va_ctime
);
3066 sdev_vattr_merge(dv
, get
);
3067 rw_exit(&dv
->sdev_contents
);
3068 rw_exit(&parent
->sdev_contents
);
3073 * a generic inactive() function
3077 devname_inactive_func(struct vnode
*vp
, struct cred
*cred
,
3078 void (*callback
)(struct vnode
*))
3081 struct sdev_node
*dv
= VTOSDEV(vp
);
3082 struct sdev_node
*ddv
= dv
->sdev_dotdot
;
3085 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
3086 state
= dv
->sdev_state
;
3088 mutex_enter(&vp
->v_lock
);
3089 ASSERT(vp
->v_count
>= 1);
3091 if (vp
->v_count
== 1 && callback
!= NULL
)
3094 clean
= (vp
->v_count
== 1) && (state
== SDEV_ZOMBIE
);
3097 * last ref count on the ZOMBIE node is released.
3098 * clean up the sdev_node, and
3099 * release the hold on the backing store node so that
3100 * the ZOMBIE backing stores also cleaned out.
3106 if (vp
->v_type
== VDIR
) {
3109 if ((dv
->sdev_flags
& SDEV_STALE
) == 0)
3110 avl_remove(&ddv
->sdev_entries
, dv
);
3113 mutex_exit(&vp
->v_lock
);
3114 sdev_nodedestroy(dv
, 0);
3117 mutex_exit(&vp
->v_lock
);
3119 rw_exit(&ddv
->sdev_contents
);