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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2013 Joyent, Inc. All rights reserved.
27 /* vnode ops for the /dev/zvol directory */
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/sysmacros.h>
33 #include <sys/sunndi.h>
34 #include <sys/sunldi.h>
35 #include <fs/fs_subr.h>
36 #include <sys/fs/dv_node.h>
37 #include <sys/fs/sdev_impl.h>
38 #include <sys/zfs_ioctl.h>
39 #include <sys/policy.h>
41 #include <sys/vfs_opreg.h>
43 struct vnodeops
*devzvol_vnodeops
;
44 static uint64_t devzvol_gen
= 0;
45 static uint64_t devzvol_zclist
;
46 static size_t devzvol_zclist_size
;
47 static ldi_ident_t devzvol_li
;
48 static ldi_handle_t devzvol_lh
;
49 static kmutex_t devzvol_mtx
;
50 static boolean_t devzvol_isopen
;
51 static major_t devzvol_major
;
54 * we need to use ddi_mod* since fs/dev gets loaded early on in
55 * startup(), and linking fs/dev to fs/zfs would drag in a lot of
56 * other stuff (like drv/random) before the rest of the system is
59 ddi_modhandle_t zfs_mod
;
61 int (*szn2m
)(char *, minor_t
*);
64 sdev_zvol_create_minor(char *dsname
)
68 return ((*szcm
)(dsname
));
72 sdev_zvol_name2minor(char *dsname
, minor_t
*minor
)
76 return ((*szn2m
)(dsname
, minor
));
85 devzvol_li
= ldi_ident_from_anon();
86 if (ldi_open_by_name("/dev/zfs", FREAD
| FWRITE
, kcred
,
87 &devzvol_lh
, devzvol_li
))
89 if (zfs_mod
== NULL
&& ((zfs_mod
= ddi_modopen("fs/zfs",
90 KRTLD_MODE_FIRST
, &rc
)) == NULL
)) {
93 ASSERT(szcm
== NULL
&& szn2m
== NULL
);
94 if ((szcm
= (int (*)(char *))
95 ddi_modsym(zfs_mod
, "zvol_create_minor", &rc
)) == NULL
) {
96 cmn_err(CE_WARN
, "couldn't resolve zvol_create_minor");
99 if ((szn2m
= (int(*)(char *, minor_t
*))
100 ddi_modsym(zfs_mod
, "zvol_name2minor", &rc
)) == NULL
) {
101 cmn_err(CE_WARN
, "couldn't resolve zvol_name2minor");
104 if (ldi_get_dev(devzvol_lh
, &dv
))
106 devzvol_major
= getmajor(dv
);
115 (void) ldi_close(devzvol_lh
, FREAD
|FWRITE
, kcred
);
116 ldi_ident_release(devzvol_li
);
117 if (zfs_mod
!= NULL
) {
118 (void) ddi_modclose(zfs_mod
);
124 devzvol_handle_ioctl(int cmd
, zfs_cmd_t
*zc
, size_t *alloc_size
)
131 if (cmd
!= ZFS_IOC_POOL_CONFIGS
)
132 mutex_enter(&devzvol_mtx
);
133 if (!devzvol_isopen
) {
134 if ((rc
= devzvol_open_zfs()) == 0) {
135 devzvol_isopen
= B_TRUE
;
137 if (cmd
!= ZFS_IOC_POOL_CONFIGS
)
138 mutex_exit(&devzvol_mtx
);
142 cookie
= zc
->zc_cookie
;
144 zc
->zc_nvlist_dst
= (uint64_t)(intptr_t)kmem_alloc(size
,
146 zc
->zc_nvlist_dst_size
= size
;
147 rc
= ldi_ioctl(devzvol_lh
, cmd
, (intptr_t)zc
, FKIOCTL
, kcred
,
151 newsize
= zc
->zc_nvlist_dst_size
;
152 ASSERT(newsize
> size
);
153 kmem_free((void *)(uintptr_t)zc
->zc_nvlist_dst
, size
);
155 zc
->zc_cookie
= cookie
;
158 if (alloc_size
== NULL
)
159 kmem_free((void *)(uintptr_t)zc
->zc_nvlist_dst
, size
);
162 if (cmd
!= ZFS_IOC_POOL_CONFIGS
)
163 mutex_exit(&devzvol_mtx
);
167 /* figures out if the objset exists and returns its type */
169 devzvol_objset_check(char *dsname
, dmu_objset_type_t
*type
)
175 zc
= kmem_zalloc(sizeof (zfs_cmd_t
), KM_SLEEP
);
176 (void) strlcpy(zc
->zc_name
, dsname
, MAXPATHLEN
);
178 ispool
= (strchr(dsname
, '/') == NULL
) ? B_TRUE
: B_FALSE
;
179 if (!ispool
&& sdev_zvol_name2minor(dsname
, NULL
) == 0) {
180 sdcmn_err13(("found cached minor node"));
182 *type
= DMU_OST_ZVOL
;
183 kmem_free(zc
, sizeof (zfs_cmd_t
));
186 rc
= devzvol_handle_ioctl(ispool
? ZFS_IOC_POOL_STATS
:
187 ZFS_IOC_OBJSET_STATS
, zc
, NULL
);
189 *type
= (ispool
) ? DMU_OST_ZFS
:
190 zc
->zc_objset_stats
.dds_type
;
191 kmem_free(zc
, sizeof (zfs_cmd_t
));
196 * returns what the zfs dataset name should be, given the /dev/zvol
197 * path and an optional name; otherwise NULL
200 devzvol_make_dsname(const char *path
, const char *name
)
206 if (strcmp(path
, ZVOL_DIR
) == 0)
208 if (name
&& (strcmp(name
, ".") == 0 || strcmp(name
, "..") == 0))
210 ptr
= path
+ strlen(ZVOL_DIR
);
211 if (strncmp(ptr
, "/dsk", 4) == 0)
212 ptr
+= strlen("/dsk");
213 else if (strncmp(ptr
, "/rdsk", 5) == 0)
214 ptr
+= strlen("/rdsk");
222 dslen
++; /* plus null */
224 dslen
+= strlen(name
) + 1; /* plus slash */
225 dsname
= kmem_zalloc(dslen
, KM_SLEEP
);
227 (void) strlcpy(dsname
, ptr
, dslen
);
229 (void) strlcat(dsname
, "/", dslen
);
232 (void) strlcat(dsname
, name
, dslen
);
237 * check if the zvol's sdev_node is still valid, which means make
238 * sure the zvol is still valid. zvol minors aren't proactively
239 * destroyed when the zvol is destroyed, so we use a validator to clean
240 * these up (in other words, when such nodes are encountered during
241 * subsequent lookup() and readdir() operations) so that only valid
242 * nodes are returned. The ordering between devname_lookup_func and
243 * devzvol_validate is a little inefficient in the case of invalid
244 * or stale nodes because devname_lookup_func calls
245 * devzvol_create_{dir, link}, then the validator says it's invalid,
246 * and then the node gets cleaned up.
249 devzvol_validate(struct sdev_node
*dv
)
251 dmu_objset_type_t do_type
;
253 char *nm
= dv
->sdev_name
;
256 sdcmn_err13(("validating ('%s' '%s')", dv
->sdev_path
, nm
));
258 * validate only READY nodes; if someone is sitting on the
259 * directory of a dataset that just got destroyed we could
260 * get a zombie node which we just skip.
262 if (dv
->sdev_state
!= SDEV_READY
) {
263 sdcmn_err13(("skipping '%s'", nm
));
264 return (SDEV_VTOR_SKIP
);
267 if ((strcmp(dv
->sdev_path
, ZVOL_DIR
"/dsk") == 0) ||
268 (strcmp(dv
->sdev_path
, ZVOL_DIR
"/rdsk") == 0))
269 return (SDEV_VTOR_VALID
);
270 dsname
= devzvol_make_dsname(dv
->sdev_path
, NULL
);
272 return (SDEV_VTOR_INVALID
);
274 rc
= devzvol_objset_check(dsname
, &do_type
);
275 sdcmn_err13((" '%s' rc %d", dsname
, rc
));
277 kmem_free(dsname
, strlen(dsname
) + 1);
278 return (SDEV_VTOR_INVALID
);
280 sdcmn_err13((" v_type %d do_type %d",
281 SDEVTOV(dv
)->v_type
, do_type
));
282 if ((SDEVTOV(dv
)->v_type
== VLNK
&& do_type
!= DMU_OST_ZVOL
) ||
283 ((SDEVTOV(dv
)->v_type
== VBLK
|| SDEVTOV(dv
)->v_type
== VCHR
) &&
284 do_type
!= DMU_OST_ZVOL
) ||
285 (SDEVTOV(dv
)->v_type
== VDIR
&& do_type
== DMU_OST_ZVOL
)) {
286 kmem_free(dsname
, strlen(dsname
) + 1);
287 return (SDEV_VTOR_STALE
);
289 if (SDEVTOV(dv
)->v_type
== VLNK
) {
292 minor_t lminor
, ominor
;
294 rc
= sdev_getlink(SDEVTOV(dv
), &link
);
297 ptr
= strrchr(link
, ':') + 1;
298 rc
= ddi_strtol(ptr
, NULL
, 10, &val
);
299 kmem_free(link
, strlen(link
) + 1);
300 ASSERT(rc
== 0 && val
!= 0);
301 lminor
= (minor_t
)val
;
302 if (sdev_zvol_name2minor(dsname
, &ominor
) < 0 ||
304 kmem_free(dsname
, strlen(dsname
) + 1);
305 return (SDEV_VTOR_STALE
);
308 kmem_free(dsname
, strlen(dsname
) + 1);
309 return (SDEV_VTOR_VALID
);
313 * creates directories as needed in response to a readdir
316 devzvol_create_pool_dirs(struct vnode
*dvp
)
320 nvpair_t
*elem
= NULL
;
325 sdcmn_err13(("devzvol_create_pool_dirs"));
326 zc
= kmem_zalloc(sizeof (zfs_cmd_t
), KM_SLEEP
);
327 mutex_enter(&devzvol_mtx
);
328 zc
->zc_cookie
= devzvol_gen
;
330 rc
= devzvol_handle_ioctl(ZFS_IOC_POOL_CONFIGS
, zc
, &size
);
334 ASSERT(devzvol_gen
!= zc
->zc_cookie
);
335 devzvol_gen
= zc
->zc_cookie
;
337 kmem_free((void *)(uintptr_t)devzvol_zclist
,
338 devzvol_zclist_size
);
339 devzvol_zclist
= zc
->zc_nvlist_dst
;
340 devzvol_zclist_size
= size
;
344 * no change in the configuration; still need
345 * to do lookups in case we did a lookup in
346 * zvol/rdsk but not zvol/dsk (or vice versa)
348 kmem_free((void *)(uintptr_t)zc
->zc_nvlist_dst
,
352 kmem_free((void *)(uintptr_t)zc
->zc_nvlist_dst
,
356 rc
= nvlist_unpack((char *)(uintptr_t)devzvol_zclist
,
357 devzvol_zclist_size
, &nv
, 0);
360 kmem_free((void *)(uintptr_t)devzvol_zclist
,
361 devzvol_zclist_size
);
363 devzvol_zclist
= NULL
;
364 devzvol_zclist_size
= 0;
367 mutex_exit(&devzvol_mtx
);
368 while ((elem
= nvlist_next_nvpair(nv
, elem
)) != NULL
) {
370 ASSERT(dvp
->v_count
> 0);
371 rc
= VOP_LOOKUP(dvp
, nvpair_name(elem
), &vp
, NULL
, 0,
372 NULL
, kcred
, NULL
, 0, NULL
);
373 /* should either work, or not be visible from a zone */
374 ASSERT(rc
== 0 || rc
== ENOENT
);
380 mutex_enter(&devzvol_mtx
);
381 if (devzvol_isopen
&& pools
== 0) {
382 /* clean up so zfs can be unloaded */
384 devzvol_isopen
= B_FALSE
;
387 mutex_exit(&devzvol_mtx
);
388 kmem_free(zc
, sizeof (zfs_cmd_t
));
393 devzvol_create_dir(struct sdev_node
*ddv
, char *nm
, void **arg
,
394 cred_t
*cred
, void *whatever
, char *whichever
)
397 struct vattr
*vap
= (struct vattr
*)arg
;
399 sdcmn_err13(("create_dir (%s) (%s) '%s'", ddv
->sdev_name
,
400 ddv
->sdev_path
, nm
));
401 ASSERT(strncmp(ddv
->sdev_path
, ZVOL_DIR
,
402 strlen(ZVOL_DIR
)) == 0);
403 *vap
= *sdev_getdefault_attr(VDIR
);
413 devzvol_create_link(struct sdev_node
*ddv
, char *nm
,
414 void **arg
, cred_t
*cred
, void *whatever
, char *whichever
)
417 char *pathname
= (char *)*arg
;
421 char str
[MAXNAMELEN
];
422 sdcmn_err13(("create_link (%s) (%s) '%s'", ddv
->sdev_name
,
423 ddv
->sdev_path
, nm
));
424 dsname
= devzvol_make_dsname(ddv
->sdev_path
, nm
);
425 rc
= sdev_zvol_create_minor(dsname
);
426 if ((rc
!= 0 && rc
!= EEXIST
&& rc
!= EBUSY
) ||
427 sdev_zvol_name2minor(dsname
, &minor
)) {
428 sdcmn_err13(("devzvol_create_link %d", rc
));
429 kmem_free(dsname
, strlen(dsname
) + 1);
432 kmem_free(dsname
, strlen(dsname
) + 1);
435 * This is a valid zvol; create a symlink that points to the
436 * minor which was created under /devices/pseudo/zfs@0
439 for (x
= ddv
->sdev_path
; x
= strchr(x
, '/'); x
++)
440 (void) strcat(pathname
, "../");
441 (void) snprintf(str
, sizeof (str
), ZVOL_PSEUDO_DEV
"%u", minor
);
442 (void) strncat(pathname
, str
, MAXPATHLEN
);
443 if (strncmp(ddv
->sdev_path
, ZVOL_FULL_RDEV_DIR
,
444 strlen(ZVOL_FULL_RDEV_DIR
)) == 0)
445 (void) strcat(pathname
, ",raw");
449 /* Clean zvol sdev_nodes that are no longer valid. */
451 devzvol_prunedir(struct sdev_node
*ddv
)
453 struct sdev_node
*dv
;
455 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
457 sdcmn_err13(("prunedir '%s'", ddv
->sdev_name
));
458 ASSERT(strncmp(ddv
->sdev_path
, ZVOL_DIR
, strlen(ZVOL_DIR
)) == 0);
459 if (rw_tryupgrade(&ddv
->sdev_contents
) == 0) {
460 rw_exit(&ddv
->sdev_contents
);
461 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
464 dv
= SDEV_FIRST_ENTRY(ddv
);
466 sdcmn_err13(("sdev_name '%s'", dv
->sdev_name
));
468 switch (devzvol_validate(dv
)) {
469 case SDEV_VTOR_VALID
:
471 dv
= SDEV_NEXT_ENTRY(ddv
, dv
);
473 case SDEV_VTOR_INVALID
:
474 sdcmn_err7(("prunedir: destroy invalid "
475 "node: %s\n", dv
->sdev_name
));
479 if ((SDEVTOV(dv
)->v_type
== VDIR
) &&
480 (sdev_cleandir(dv
, NULL
, 0) != 0)) {
481 dv
= SDEV_NEXT_ENTRY(ddv
, dv
);
485 /* remove the cache node */
486 sdev_cache_update(ddv
, &dv
, dv
->sdev_name
,
489 dv
= SDEV_FIRST_ENTRY(ddv
);
491 rw_downgrade(&ddv
->sdev_contents
);
495 * This function is used to create a dir or dev inside a zone's /dev when the
496 * zone has a zvol that is dynamically created within the zone (i.e. inside
497 * of a delegated dataset. Since there is no /devices tree within a zone,
498 * we create the chr/blk devices directly inside the zone's /dev instead of
502 devzvol_mk_ngz_node(struct sdev_node
*parent
, char *nm
)
506 enum vtype expected_type
= VDIR
;
507 dmu_objset_type_t do_type
;
508 struct sdev_node
*dv
= NULL
;
512 bzero(&vattr
, sizeof (vattr
));
514 vattr
.va_mask
= AT_TYPE
|AT_MODE
|AT_UID
|AT_GID
;
515 vattr
.va_uid
= SDEV_UID_DEFAULT
;
516 vattr
.va_gid
= SDEV_GID_DEFAULT
;
517 vattr
.va_type
= VNON
;
518 vattr
.va_atime
= now
;
519 vattr
.va_mtime
= now
;
520 vattr
.va_ctime
= now
;
522 if ((dsname
= devzvol_make_dsname(parent
->sdev_path
, nm
)) == NULL
)
525 if (devzvol_objset_check(dsname
, &do_type
) != 0) {
526 kmem_free(dsname
, strlen(dsname
) + 1);
529 if (do_type
== DMU_OST_ZVOL
)
530 expected_type
= VBLK
;
532 if (expected_type
== VDIR
) {
533 vattr
.va_type
= VDIR
;
534 vattr
.va_mode
= SDEV_DIRMODE_DEFAULT
;
540 rc
= sdev_zvol_create_minor(dsname
);
541 if ((rc
!= 0 && rc
!= EEXIST
&& rc
!= EBUSY
) ||
542 sdev_zvol_name2minor(dsname
, &minor
)) {
543 kmem_free(dsname
, strlen(dsname
) + 1);
547 devnum
= makedevice(devzvol_major
, minor
);
548 vattr
.va_rdev
= devnum
;
550 if (strstr(parent
->sdev_path
, "/rdsk/") != NULL
)
551 vattr
.va_type
= VCHR
;
553 vattr
.va_type
= VBLK
;
554 vattr
.va_mode
= SDEV_DEVMODE_DEFAULT
;
556 kmem_free(dsname
, strlen(dsname
) + 1);
558 rw_enter(&parent
->sdev_contents
, RW_WRITER
);
560 res
= sdev_mknode(parent
, nm
, &dv
, &vattr
,
561 NULL
, NULL
, kcred
, SDEV_READY
);
562 rw_exit(&parent
->sdev_contents
);
572 devzvol_lookup(struct vnode
*dvp
, char *nm
, struct vnode
**vpp
,
573 struct pathname
*pnp
, int flags
, struct vnode
*rdir
, struct cred
*cred
,
574 caller_context_t
*ct
, int *direntflags
, pathname_t
*realpnp
)
576 enum vtype expected_type
= VDIR
;
577 struct sdev_node
*parent
= VTOSDEV(dvp
);
579 dmu_objset_type_t do_type
;
582 sdcmn_err13(("devzvol_lookup '%s' '%s'", parent
->sdev_path
, nm
));
584 /* execute access is required to search the directory */
585 if ((error
= VOP_ACCESS(dvp
, VEXEC
, 0, cred
, ct
)) != 0)
588 rw_enter(&parent
->sdev_contents
, RW_READER
);
589 if (SDEV_IS_GLOBAL(parent
)) {
591 * During iter_datasets, don't create GZ dev when running in
592 * NGZ. We can't return ENOENT here since that could
593 * incorrectly trigger the creation of the dev from the
594 * recursive call through prof_filldir during iter_datasets.
596 if (getzoneid() != GLOBAL_ZONEID
) {
597 rw_exit(&parent
->sdev_contents
);
603 rw_exit(&parent
->sdev_contents
);
606 * If we're in the global zone and reach down into a non-global
607 * zone's /dev/zvol then this action could trigger the creation
608 * of all of the zvol devices for every zone into the non-global
609 * zone's /dev tree. This could be a big security hole. To
610 * prevent this, disallow the global zone from looking inside
611 * a non-global zones /dev/zvol. This behavior is similar to
612 * delegated datasets, which cannot be used by the global zone.
614 if (getzoneid() == GLOBAL_ZONEID
)
617 res
= prof_lookup(dvp
, nm
, vpp
, cred
);
620 * We won't find a zvol that was dynamically created inside
621 * a NGZ, within a delegated dataset, in the zone's dev profile
622 * but prof_lookup will also find it via sdev_cache_lookup.
626 * We have to create the sdev node for the dymamically
629 if (devzvol_mk_ngz_node(parent
, nm
) != 0)
631 res
= prof_lookup(dvp
, nm
, vpp
, cred
);
637 dsname
= devzvol_make_dsname(parent
->sdev_path
, nm
);
638 rw_exit(&parent
->sdev_contents
);
639 sdcmn_err13(("rvp dsname %s", dsname
? dsname
: "(null)"));
641 error
= devzvol_objset_check(dsname
, &do_type
);
646 if (do_type
== DMU_OST_ZVOL
)
647 expected_type
= VLNK
;
650 * the callbacks expect:
652 * parent->sdev_path nm
654 * /dev/zvol/{r}dsk <pool name>
655 * /dev/zvol/{r}dsk/<dataset name> <last ds component>
657 * sdev_name is always last path component of sdev_path
659 if (expected_type
== VDIR
) {
660 error
= devname_lookup_func(parent
, nm
, vpp
, cred
,
661 devzvol_create_dir
, SDEV_VATTR
);
663 error
= devname_lookup_func(parent
, nm
, vpp
, cred
,
664 devzvol_create_link
, SDEV_VLINK
);
666 sdcmn_err13(("devzvol_lookup %d %d", expected_type
, error
));
667 ASSERT(error
|| ((*vpp
)->v_type
== expected_type
));
670 kmem_free(dsname
, strlen(dsname
) + 1);
671 sdcmn_err13(("devzvol_lookup %d", error
));
676 * We allow create to find existing nodes
677 * - if the node doesn't exist - EROFS
678 * - creating an existing dir read-only succeeds, otherwise EISDIR
679 * - exclusive creates fail - EEXIST
683 devzvol_create(struct vnode
*dvp
, char *nm
, struct vattr
*vap
, vcexcl_t excl
,
684 int mode
, struct vnode
**vpp
, struct cred
*cred
, int flag
,
685 caller_context_t
*ct
, vsecattr_t
*vsecp
)
692 error
= devzvol_lookup(dvp
, nm
, &vp
, NULL
, 0, NULL
, cred
, ct
, NULL
,
697 else if (vp
->v_type
== VDIR
&& (mode
& VWRITE
))
700 error
= VOP_ACCESS(vp
, mode
, 0, cred
, ct
);
706 } else if (error
== ENOENT
) {
713 void sdev_iter_snapshots(struct vnode
*dvp
, char *name
);
716 sdev_iter_datasets(struct vnode
*dvp
, int arg
, char *name
)
721 sdcmn_err13(("iter name is '%s' (arg %x)", name
, arg
));
722 zc
= kmem_zalloc(sizeof (zfs_cmd_t
), KM_SLEEP
);
723 (void) strcpy(zc
->zc_name
, name
);
725 while ((rc
= devzvol_handle_ioctl(arg
, zc
, B_FALSE
)) == 0) {
729 sdcmn_err13((" name %s", zc
->zc_name
));
730 if (strchr(zc
->zc_name
, '$') || strchr(zc
->zc_name
, '%'))
732 ptr
= strrchr(zc
->zc_name
, '/') + 1;
733 rc
= devzvol_lookup(dvp
, ptr
, &vpp
, NULL
, 0, NULL
,
734 kcred
, NULL
, NULL
, NULL
);
737 } else if (rc
== ENOENT
) {
741 * EBUSY == problem with zvols's dmu holds?
742 * EPERM when in a NGZ and traversing up and out.
746 if (arg
== ZFS_IOC_DATASET_LIST_NEXT
&&
747 zc
->zc_objset_stats
.dds_type
!= DMU_OST_ZFS
)
748 sdev_iter_snapshots(dvp
, zc
->zc_name
);
750 (void) strcpy(zc
->zc_name
, name
);
752 kmem_free(zc
, sizeof (zfs_cmd_t
));
756 sdev_iter_snapshots(struct vnode
*dvp
, char *name
)
758 sdev_iter_datasets(dvp
, ZFS_IOC_SNAPSHOT_LIST_NEXT
, name
);
763 devzvol_readdir(struct vnode
*dvp
, struct uio
*uiop
, struct cred
*cred
,
764 int *eofp
, caller_context_t
*ct_unused
, int flags_unused
)
766 struct sdev_node
*sdvp
= VTOSDEV(dvp
);
769 sdcmn_err13(("zv readdir of '%s' %s'", sdvp
->sdev_path
,
772 if (strcmp(sdvp
->sdev_path
, ZVOL_DIR
) == 0) {
775 rw_exit(&sdvp
->sdev_contents
);
776 (void) devname_lookup_func(sdvp
, "dsk", &vp
, cred
,
777 devzvol_create_dir
, SDEV_VATTR
);
779 (void) devname_lookup_func(sdvp
, "rdsk", &vp
, cred
,
780 devzvol_create_dir
, SDEV_VATTR
);
782 rw_enter(&sdvp
->sdev_contents
, RW_READER
);
783 return (devname_readdir_func(dvp
, uiop
, cred
, eofp
, 0));
785 if (uiop
->uio_offset
== 0)
786 devzvol_prunedir(sdvp
);
787 ptr
= sdvp
->sdev_path
+ strlen(ZVOL_DIR
);
788 if ((strcmp(ptr
, "/dsk") == 0) || (strcmp(ptr
, "/rdsk") == 0)) {
789 rw_exit(&sdvp
->sdev_contents
);
790 devzvol_create_pool_dirs(dvp
);
791 rw_enter(&sdvp
->sdev_contents
, RW_READER
);
792 return (devname_readdir_func(dvp
, uiop
, cred
, eofp
, 0));
795 ptr
= strchr(ptr
+ 1, '/');
799 rw_exit(&sdvp
->sdev_contents
);
800 sdev_iter_datasets(dvp
, ZFS_IOC_DATASET_LIST_NEXT
, ptr
);
801 rw_enter(&sdvp
->sdev_contents
, RW_READER
);
802 return (devname_readdir_func(dvp
, uiop
, cred
, eofp
, 0));
805 const fs_operation_def_t devzvol_vnodeops_tbl
[] = {
806 VOPNAME_READDIR
, { .vop_readdir
= devzvol_readdir
},
807 VOPNAME_LOOKUP
, { .vop_lookup
= devzvol_lookup
},
808 VOPNAME_CREATE
, { .vop_create
= devzvol_create
},
809 VOPNAME_RENAME
, { .error
= fs_nosys
},
810 VOPNAME_MKDIR
, { .error
= fs_nosys
},
811 VOPNAME_RMDIR
, { .error
= fs_nosys
},
812 VOPNAME_REMOVE
, { .error
= fs_nosys
},
813 VOPNAME_SYMLINK
, { .error
= fs_nosys
},