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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2015 EveryCity Ltd.
26 * Copyright (c) 2015 by Delphix. All rights reserved.
36 #include <libnvpair.h>
41 #include <sys/mntent.h>
42 #include <sys/mnttab.h>
43 #include <sys/mount.h>
45 #include <sys/types.h>
46 #include <sys/vfstab.h>
48 #include <sys/mkdev.h>
52 #include <libbe_priv.h>
54 #define BE_TMP_MNTPNT "/tmp/.be.XXXXXX"
56 typedef struct dir_data
{
61 /* Private function prototypes */
62 static int be_mount_callback(zfs_handle_t
*, void *);
63 static int be_unmount_callback(zfs_handle_t
*, void *);
64 static int be_get_legacy_fs_callback(zfs_handle_t
*, void *);
65 static int fix_mountpoint(zfs_handle_t
*);
66 static int fix_mountpoint_callback(zfs_handle_t
*, void *);
67 static int get_mountpoint_from_vfstab(char *, const char *, char *, size_t,
69 static int loopback_mount_shared_fs(zfs_handle_t
*, be_mount_data_t
*);
70 static int loopback_mount_zonepath(const char *, be_mount_data_t
*);
71 static int iter_shared_fs_callback(zfs_handle_t
*, void *);
72 static int zpool_shared_fs_callback(zpool_handle_t
*, void *);
73 static int unmount_shared_fs(be_unmount_data_t
*);
74 static int add_to_fs_list(be_fs_list_data_t
*, const char *);
75 static int be_mount_root(zfs_handle_t
*, char *);
76 static int be_unmount_root(zfs_handle_t
*, be_unmount_data_t
*);
77 static int be_mount_zones(zfs_handle_t
*, be_mount_data_t
*);
78 static int be_unmount_zones(be_unmount_data_t
*);
79 static int be_mount_one_zone(zfs_handle_t
*, be_mount_data_t
*, char *, char *,
81 static int be_unmount_one_zone(be_unmount_data_t
*, char *, char *, char *);
82 static int be_get_ds_from_dir_callback(zfs_handle_t
*, void *);
83 static int mount_zfs(zfs_handle_t
*, char *);
86 /* ******************************************************************** */
87 /* Public Functions */
88 /* ******************************************************************** */
92 * Description: Mounts a BE and its subordinate datasets at a given mountpoint.
94 * be_attrs - pointer to nvlist_t of attributes being passed in.
95 * The following attributes are used by this function:
97 * BE_ATTR_ORIG_BE_NAME *required
98 * BE_ATTR_MOUNTPOINT *required
99 * BE_ATTR_MOUNT_FLAGS *optional
101 * BE_SUCCESS - Success
102 * be_errno_t - Failure
107 be_mount(nvlist_t
*be_attrs
)
109 char *be_name
= NULL
;
110 char *mountpoint
= NULL
;
112 int ret
= BE_SUCCESS
;
114 /* Initialize libzfs handle */
116 return (BE_ERR_INIT
);
118 /* Get original BE name */
119 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
121 be_print_err(gettext("be_mount: failed to lookup "
122 "BE_ATTR_ORIG_BE_NAME attribute\n"));
123 return (BE_ERR_INVAL
);
126 /* Validate original BE name */
127 if (!be_valid_be_name(be_name
)) {
128 be_print_err(gettext("be_mount: invalid BE name %s\n"),
130 return (BE_ERR_INVAL
);
134 if (nvlist_lookup_string(be_attrs
, BE_ATTR_MOUNTPOINT
, &mountpoint
)
136 be_print_err(gettext("be_mount: failed to lookup "
137 "BE_ATTR_MOUNTPOINT attribute\n"));
138 return (BE_ERR_INVAL
);
142 if (nvlist_lookup_pairs(be_attrs
, NV_FLAG_NOENTOK
,
143 BE_ATTR_MOUNT_FLAGS
, DATA_TYPE_UINT16
, &flags
, NULL
) != 0) {
144 be_print_err(gettext("be_mount: failed to lookup "
145 "BE_ATTR_MOUNT_FLAGS attribute\n"));
146 return (BE_ERR_INVAL
);
149 ret
= _be_mount(be_name
, &mountpoint
, flags
);
157 * Function: be_unmount
158 * Description: Unmounts a BE and its subordinate datasets.
160 * be_attrs - pointer to nvlist_t of attributes being passed in.
161 * The following attributes are used by this function:
163 * BE_ATTR_ORIG_BE_NAME *required
164 * BE_ATTR_UNMOUNT_FLAGS *optional
166 * BE_SUCCESS - Success
167 * be_errno_t - Failure
172 be_unmount(nvlist_t
*be_attrs
)
174 char *be_name
= NULL
;
175 char *be_name_mnt
= NULL
;
178 int ret
= BE_SUCCESS
;
180 /* Initialize libzfs handle */
182 return (BE_ERR_INIT
);
184 /* Get original BE name */
185 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
187 be_print_err(gettext("be_unmount: failed to lookup "
188 "BE_ATTR_ORIG_BE_NAME attribute\n"));
189 return (BE_ERR_INVAL
);
192 /* Check if we have mountpoint argument instead of BE name */
193 if (be_name
[0] == '/') {
194 if ((ds
= be_get_ds_from_dir(be_name
)) != NULL
) {
195 if ((be_name_mnt
= strrchr(ds
, '/')) != NULL
) {
196 be_name
= be_name_mnt
+ 1;
199 be_print_err(gettext("be_unmount: no datasets mounted "
200 "at '%s'\n"), be_name
);
201 return (BE_ERR_INVAL
);
205 /* Validate original BE name */
206 if (!be_valid_be_name(be_name
)) {
207 be_print_err(gettext("be_unmount: invalid BE name %s\n"),
209 return (BE_ERR_INVAL
);
212 /* Get unmount flags */
213 if (nvlist_lookup_pairs(be_attrs
, NV_FLAG_NOENTOK
,
214 BE_ATTR_UNMOUNT_FLAGS
, DATA_TYPE_UINT16
, &flags
, NULL
) != 0) {
215 be_print_err(gettext("be_unmount: failed to loookup "
216 "BE_ATTR_UNMOUNT_FLAGS attribute\n"));
217 return (BE_ERR_INVAL
);
220 ret
= _be_unmount(be_name
, flags
);
227 /* ******************************************************************** */
228 /* Semi-Private Functions */
229 /* ******************************************************************** */
232 * Function: _be_mount
233 * Description: Mounts a BE. If the altroot is not provided, this function
234 * will generate a temporary mountpoint to mount the BE at. It
235 * will return this temporary mountpoint to the caller via the
236 * altroot reference pointer passed in. This returned value is
237 * allocated on heap storage and is the repsonsibility of the
240 * be_name - pointer to name of BE to mount.
241 * altroot - reference pointer to altroot of where to mount BE.
242 * flags - flag indicating special handling for mounting the BE
244 * BE_SUCCESS - Success
245 * be_errno_t - Failure
247 * Semi-private (library wide use only)
250 _be_mount(char *be_name
, char **altroot
, int flags
)
252 be_transaction_data_t bt
= { 0 };
253 be_mount_data_t md
= { 0 };
255 char obe_root_ds
[MAXPATHLEN
];
257 char *tmp_altroot
= NULL
;
258 int ret
= BE_SUCCESS
, err
= 0;
260 boolean_t gen_tmp_altroot
= B_FALSE
;
262 if (be_name
== NULL
|| altroot
== NULL
)
263 return (BE_ERR_INVAL
);
265 /* Set be_name as obe_name in bt structure */
266 bt
.obe_name
= be_name
;
268 /* Find which zpool obe_name lives in */
269 if ((err
= zpool_iter(g_zfs
, be_find_zpool_callback
, &bt
)) == 0) {
270 be_print_err(gettext("be_mount: failed to "
271 "find zpool for BE (%s)\n"), bt
.obe_name
);
272 return (BE_ERR_BE_NOENT
);
273 } else if (err
< 0) {
274 be_print_err(gettext("be_mount: zpool_iter failed: %s\n"),
275 libzfs_error_description(g_zfs
));
276 return (zfs_err_to_be_err(g_zfs
));
279 /* Generate string for obe_name's root dataset */
280 be_make_root_ds(bt
.obe_zpool
, bt
.obe_name
, obe_root_ds
,
281 sizeof (obe_root_ds
));
282 bt
.obe_root_ds
= obe_root_ds
;
284 /* Get handle to BE's root dataset */
285 if ((zhp
= zfs_open(g_zfs
, bt
.obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
287 be_print_err(gettext("be_mount: failed to "
288 "open BE root dataset (%s): %s\n"), bt
.obe_root_ds
,
289 libzfs_error_description(g_zfs
));
290 return (zfs_err_to_be_err(g_zfs
));
293 /* Make sure BE's root dataset isn't already mounted somewhere */
294 if (zfs_is_mounted(zhp
, &mp
)) {
296 be_print_err(gettext("be_mount: %s is already mounted "
297 "at %s\n"), bt
.obe_name
, mp
!= NULL
? mp
: "");
299 return (BE_ERR_MOUNTED
);
303 * Fix this BE's mountpoint if its root dataset isn't set to
304 * either 'legacy' or '/'.
306 if ((ret
= fix_mountpoint(zhp
)) != BE_SUCCESS
) {
307 be_print_err(gettext("be_mount: mountpoint check "
308 "failed for %s\n"), bt
.obe_root_ds
);
314 * If altroot not provided, create a temporary alternate root
317 if (*altroot
== NULL
) {
318 if ((ret
= be_make_tmp_mountpoint(&tmp_altroot
))
320 be_print_err(gettext("be_mount: failed to "
321 "make temporary mountpoint\n"));
325 gen_tmp_altroot
= B_TRUE
;
327 tmp_altroot
= *altroot
;
330 md
.altroot
= tmp_altroot
;
331 md
.shared_fs
= flags
& BE_MOUNT_FLAG_SHARED_FS
;
332 md
.shared_rw
= flags
& BE_MOUNT_FLAG_SHARED_RW
;
334 /* Mount the BE's root file system */
335 if (getzoneid() == GLOBAL_ZONEID
) {
336 if ((ret
= be_mount_root(zhp
, tmp_altroot
)) != BE_SUCCESS
) {
337 be_print_err(gettext("be_mount: failed to "
338 "mount BE root file system\n"));
345 /* Legacy mount the zone root dataset */
346 if ((ret
= be_mount_zone_root(zhp
, &md
)) != BE_SUCCESS
) {
347 be_print_err(gettext("be_mount: failed to "
348 "mount BE zone root file system\n"));
355 /* Iterate through BE's children filesystems */
356 if ((err
= zfs_iter_filesystems(zhp
, be_mount_callback
,
357 tmp_altroot
)) != 0) {
358 be_print_err(gettext("be_mount: failed to "
359 "mount BE (%s) on %s\n"), bt
.obe_name
, tmp_altroot
);
367 * Mount shared file systems if mount flag says so.
371 * Mount all ZFS file systems not under the BE's root dataset
373 (void) zpool_iter(g_zfs
, zpool_shared_fs_callback
, &md
);
375 /* TODO: Mount all non-ZFS file systems - Not supported yet */
379 * If we're in the global zone and the global zone has a valid uuid,
380 * mount all supported non-global zones.
382 if (getzoneid() == GLOBAL_ZONEID
&&
383 !(flags
& BE_MOUNT_FLAG_NO_ZONES
) &&
384 be_get_uuid(bt
.obe_root_ds
, &uu
) == BE_SUCCESS
) {
385 if (be_mount_zones(zhp
, &md
) != BE_SUCCESS
) {
386 ret
= BE_ERR_NO_MOUNTED_ZONE
;
393 * If a NULL altroot was passed in, pass the generated altroot
394 * back to the caller in altroot.
396 if (gen_tmp_altroot
) {
397 if (ret
== BE_SUCCESS
|| ret
== BE_ERR_NO_MOUNTED_ZONE
)
398 *altroot
= tmp_altroot
;
407 * Function: _be_unmount
408 * Description: Unmount a BE.
410 * be_name - pointer to name of BE to unmount.
411 * flags - flags for unmounting the BE.
413 * BE_SUCCESS - Success
414 * be_errno_t - Failure
416 * Semi-private (library wide use only)
419 _be_unmount(char *be_name
, int flags
)
421 be_transaction_data_t bt
= { 0 };
422 be_unmount_data_t ud
= { 0 };
425 char obe_root_ds
[MAXPATHLEN
];
426 char mountpoint
[MAXPATHLEN
];
428 int ret
= BE_SUCCESS
;
432 return (BE_ERR_INVAL
);
434 /* Set be_name as obe_name in bt structure */
435 bt
.obe_name
= be_name
;
437 /* Find which zpool obe_name lives in */
438 if ((zret
= zpool_iter(g_zfs
, be_find_zpool_callback
, &bt
)) == 0) {
439 be_print_err(gettext("be_unmount: failed to "
440 "find zpool for BE (%s)\n"), bt
.obe_name
);
441 return (BE_ERR_BE_NOENT
);
442 } else if (zret
< 0) {
443 be_print_err(gettext("be_unmount: "
444 "zpool_iter failed: %s\n"),
445 libzfs_error_description(g_zfs
));
446 ret
= zfs_err_to_be_err(g_zfs
);
450 /* Generate string for obe_name's root dataset */
451 be_make_root_ds(bt
.obe_zpool
, bt
.obe_name
, obe_root_ds
,
452 sizeof (obe_root_ds
));
453 bt
.obe_root_ds
= obe_root_ds
;
455 /* Get handle to BE's root dataset */
456 if ((zhp
= zfs_open(g_zfs
, bt
.obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
458 be_print_err(gettext("be_unmount: failed to "
459 "open BE root dataset (%s): %s\n"), bt
.obe_root_ds
,
460 libzfs_error_description(g_zfs
));
461 ret
= zfs_err_to_be_err(g_zfs
);
465 /* Make sure BE's root dataset is mounted somewhere */
466 if (!zfs_is_mounted(zhp
, &mp
)) {
468 be_print_err(gettext("be_unmount: "
469 "(%s) not mounted\n"), bt
.obe_name
);
472 * BE is not mounted, fix this BE's mountpoint if its root
473 * dataset isn't set to either 'legacy' or '/'.
475 if ((ret
= fix_mountpoint(zhp
)) != BE_SUCCESS
) {
476 be_print_err(gettext("be_unmount: mountpoint check "
477 "failed for %s\n"), bt
.obe_root_ds
);
483 return (BE_ERR_NOTMOUNTED
);
487 * If we didn't get a mountpoint from the zfs_is_mounted call,
488 * try and get it from its property.
491 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
492 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
493 be_print_err(gettext("be_unmount: failed to "
494 "get mountpoint of (%s)\n"), bt
.obe_name
);
499 (void) strlcpy(mountpoint
, mp
, sizeof (mountpoint
));
503 /* If BE mounted as current root, fail */
504 if (strcmp(mountpoint
, "/") == 0) {
505 be_print_err(gettext("be_unmount: "
506 "cannot unmount currently running BE\n"));
508 return (BE_ERR_UMOUNT_CURR_BE
);
511 ud
.altroot
= mountpoint
;
512 ud
.force
= flags
& BE_UNMOUNT_FLAG_FORCE
;
514 /* Unmount all supported non-global zones if we're in the global zone */
515 if (getzoneid() == GLOBAL_ZONEID
&&
516 be_get_uuid(bt
.obe_root_ds
, &uu
) == BE_SUCCESS
) {
517 if ((ret
= be_unmount_zones(&ud
)) != BE_SUCCESS
) {
523 /* TODO: Unmount all non-ZFS file systems - Not supported yet */
525 /* Unmount all ZFS file systems not under the BE root dataset */
526 if ((ret
= unmount_shared_fs(&ud
)) != BE_SUCCESS
) {
527 be_print_err(gettext("be_unmount: failed to "
528 "unmount shared file systems\n"));
533 /* Unmount all children datasets under the BE's root dataset */
534 if ((zret
= zfs_iter_filesystems(zhp
, be_unmount_callback
,
536 be_print_err(gettext("be_unmount: failed to "
537 "unmount BE (%s)\n"), bt
.obe_name
);
542 /* Unmount this BE's root filesystem */
543 if (getzoneid() == GLOBAL_ZONEID
) {
544 if ((ret
= be_unmount_root(zhp
, &ud
)) != BE_SUCCESS
) {
549 if ((ret
= be_unmount_zone_root(zhp
, &ud
)) != BE_SUCCESS
) {
561 * Function: be_mount_zone_root
562 * Description: Mounts the zone root dataset for a zone.
564 * zfs - zfs_handle_t pointer to zone root dataset
565 * md - be_mount_data_t pointer to data for zone to be mounted
567 * BE_SUCCESS - Success
568 * be_errno_t - Failure
570 * Semi-private (library wide use only)
573 be_mount_zone_root(zfs_handle_t
*zhp
, be_mount_data_t
*md
)
576 char mountpoint
[MAXPATHLEN
];
579 /* Get mountpoint property of dataset */
580 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
581 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
582 be_print_err(gettext("be_mount_zone_root: failed to "
583 "get mountpoint property for %s: %s\n"), zfs_get_name(zhp
),
584 libzfs_error_description(g_zfs
));
585 return (zfs_err_to_be_err(g_zfs
));
589 * Make sure zone's root dataset is set to 'legacy'. This is
590 * currently a requirement in this implementation of zones
593 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) != 0) {
594 be_print_err(gettext("be_mount_zone_root: "
595 "zone root dataset mountpoint is not 'legacy'\n"));
596 return (BE_ERR_ZONE_ROOT_NOT_LEGACY
);
599 /* Create the mountpoint if it doesn't exist */
600 if (lstat(md
->altroot
, &buf
) != 0) {
601 if (mkdirp(md
->altroot
, 0755) != 0) {
603 be_print_err(gettext("be_mount_zone_root: failed "
604 "to create mountpoint %s\n"), md
->altroot
);
605 return (errno_to_be_err(err
));
610 * Legacy mount the zone root dataset.
612 * As a workaround for 6176743, we mount the zone's root with the
613 * MS_OVERLAY option in case an alternate BE is mounted, and we're
614 * mounting the root for the zone from the current BE here. When an
615 * alternate BE is mounted, it ties up the zone's zoneroot directory
616 * for the current BE since the zone's zonepath is loopback mounted
617 * from the current BE.
619 * TODO: The MS_OVERLAY option needs to be removed when 6176743
622 if (mount(zfs_get_name(zhp
), md
->altroot
, MS_OVERLAY
, MNTTYPE_ZFS
,
623 NULL
, 0, NULL
, 0) != 0) {
625 be_print_err(gettext("be_mount_zone_root: failed to "
626 "legacy mount zone root dataset (%s) at %s\n"),
627 zfs_get_name(zhp
), md
->altroot
);
628 return (errno_to_be_err(err
));
635 * Function: be_unmount_zone_root
636 * Description: Unmounts the zone root dataset for a zone.
638 * zhp - zfs_handle_t pointer to zone root dataset
639 * ud - be_unmount_data_t pointer to data for zone to be unmounted
641 * BE_SUCCESS - Success
642 * be_errno_t - Failure
644 * Semi-private (library wise use only)
647 be_unmount_zone_root(zfs_handle_t
*zhp
, be_unmount_data_t
*ud
)
649 char mountpoint
[MAXPATHLEN
];
651 /* Unmount the dataset */
652 if (zfs_unmount(zhp
, NULL
, ud
->force
? MS_FORCE
: 0) != 0) {
653 be_print_err(gettext("be_unmount_zone_root: failed to "
654 "unmount zone root dataset %s: %s\n"), zfs_get_name(zhp
),
655 libzfs_error_description(g_zfs
));
656 return (zfs_err_to_be_err(g_zfs
));
659 /* Get the current mountpoint property for the zone root dataset */
660 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
661 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
662 be_print_err(gettext("be_unmount_zone_root: failed to "
663 "get mountpoint property for zone root dataset (%s): %s\n"),
664 zfs_get_name(zhp
), libzfs_error_description(g_zfs
));
665 return (zfs_err_to_be_err(g_zfs
));
668 /* If mountpoint not already set to 'legacy', set it to 'legacy' */
669 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) != 0) {
670 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
671 ZFS_MOUNTPOINT_LEGACY
) != 0) {
672 be_print_err(gettext("be_unmount_zone_root: "
673 "failed to set mountpoint of zone root dataset "
674 "%s to 'legacy': %s\n"), zfs_get_name(zhp
),
675 libzfs_error_description(g_zfs
));
676 return (zfs_err_to_be_err(g_zfs
));
684 * Function: be_get_legacy_fs
685 * Description: This function iterates through all non-shared file systems
686 * of a BE and finds the ones with a legacy mountpoint. For
687 * those file systems, it reads the BE's vfstab to get the
688 * mountpoint. If found, it adds that file system to the
689 * be_fs_list_data_t passed in.
691 * This function can be used to gather legacy mounted file systems
692 * for both global BEs and non-global zone BEs. To get data for
693 * a non-global zone BE, the zoneroot_ds and zoneroot parameters
694 * will be specified, otherwise they should be set to NULL.
696 * be_name - global BE name from which to get legacy file
698 * be_root_ds - root dataset of global BE.
699 * zoneroot_ds - root dataset of zone.
700 * zoneroot - zoneroot path of zone.
701 * fld - be_fs_list_data_t pointer.
703 * BE_SUCCESS - Success
704 * be_errno_t - Failure
706 * Semi-private (library wide use only)
709 be_get_legacy_fs(char *be_name
, char *be_root_ds
, char *zoneroot_ds
,
710 char *zoneroot
, be_fs_list_data_t
*fld
)
712 zfs_handle_t
*zhp
= NULL
;
713 char mountpoint
[MAXPATHLEN
];
714 boolean_t mounted_here
= B_FALSE
;
715 boolean_t zone_mounted_here
= B_FALSE
;
716 int ret
= BE_SUCCESS
, err
= 0;
718 if (be_name
== NULL
|| be_root_ds
== NULL
|| fld
== NULL
)
719 return (BE_ERR_INVAL
);
721 /* Get handle to BE's root dataset */
722 if ((zhp
= zfs_open(g_zfs
, be_root_ds
, ZFS_TYPE_FILESYSTEM
))
724 be_print_err(gettext("be_get_legacy_fs: failed to "
725 "open BE root dataset (%s): %s\n"), be_root_ds
,
726 libzfs_error_description(g_zfs
));
727 ret
= zfs_err_to_be_err(g_zfs
);
731 /* If BE is not already mounted, mount it. */
732 if (!zfs_is_mounted(zhp
, &fld
->altroot
)) {
733 if ((ret
= _be_mount(be_name
, &fld
->altroot
,
734 zoneroot_ds
? BE_MOUNT_FLAG_NULL
:
735 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
736 be_print_err(gettext("be_get_legacy_fs: "
737 "failed to mount BE %s\n"), be_name
);
741 mounted_here
= B_TRUE
;
742 } else if (fld
->altroot
== NULL
) {
743 be_print_err(gettext("be_get_legacy_fs: failed to "
744 "get altroot of mounted BE %s: %s\n"),
745 be_name
, libzfs_error_description(g_zfs
));
746 ret
= zfs_err_to_be_err(g_zfs
);
751 * If a zone root dataset was passed in, we're wanting to get
752 * legacy mounted file systems for that zone, not the global
755 if (zoneroot_ds
!= NULL
) {
756 be_mount_data_t zone_md
= { 0 };
758 /* Close off handle to global BE's root dataset */
761 /* Get handle to zone's root dataset */
762 if ((zhp
= zfs_open(g_zfs
, zoneroot_ds
,
763 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
764 be_print_err(gettext("be_get_legacy_fs: failed to "
765 "open zone BE root dataset (%s): %s\n"),
766 zoneroot_ds
, libzfs_error_description(g_zfs
));
767 ret
= zfs_err_to_be_err(g_zfs
);
771 /* Make sure the zone we're looking for is mounted */
772 if (!zfs_is_mounted(zhp
, &zone_md
.altroot
)) {
773 char zone_altroot
[MAXPATHLEN
];
775 /* Generate alternate root path for zone */
776 (void) snprintf(zone_altroot
, sizeof (zone_altroot
),
777 "%s%s", fld
->altroot
, zoneroot
);
778 if ((zone_md
.altroot
= strdup(zone_altroot
)) == NULL
) {
779 be_print_err(gettext("be_get_legacy_fs: "
780 "memory allocation failed\n"));
785 if ((ret
= be_mount_zone_root(zhp
, &zone_md
))
787 be_print_err(gettext("be_get_legacy_fs: "
788 "failed to mount zone root %s\n"),
790 free(zone_md
.altroot
);
791 zone_md
.altroot
= NULL
;
794 zone_mounted_here
= B_TRUE
;
798 fld
->altroot
= zone_md
.altroot
;
802 * If the root dataset is in the vfstab with a mountpoint of "/",
805 if (get_mountpoint_from_vfstab(fld
->altroot
, zfs_get_name(zhp
),
806 mountpoint
, sizeof (mountpoint
), B_FALSE
) == BE_SUCCESS
) {
807 if (strcmp(mountpoint
, "/") == 0) {
808 if (add_to_fs_list(fld
, zfs_get_name(zhp
))
810 be_print_err(gettext("be_get_legacy_fs: "
811 "failed to add %s to fs list\n"),
819 /* Iterate subordinate file systems looking for legacy mounts */
820 if ((ret
= zfs_iter_filesystems(zhp
, be_get_legacy_fs_callback
,
822 be_print_err(gettext("be_get_legacy_fs: "
823 "failed to iterate %s to get legacy mounts\n"),
828 /* If we mounted the zone BE, unmount it */
829 if (zone_mounted_here
) {
830 be_unmount_data_t zone_ud
= { 0 };
832 zone_ud
.altroot
= fld
->altroot
;
833 zone_ud
.force
= B_TRUE
;
834 if ((err
= be_unmount_zone_root(zhp
, &zone_ud
)) != BE_SUCCESS
) {
835 be_print_err(gettext("be_get_legacy_fs: "
836 "failed to unmount zone root %s\n"),
838 if (ret
== BE_SUCCESS
)
843 /* If we mounted this BE, unmount it */
845 if ((err
= _be_unmount(be_name
, 0)) != BE_SUCCESS
) {
846 be_print_err(gettext("be_get_legacy_fs: "
847 "failed to unmount %s\n"), be_name
);
848 if (ret
== BE_SUCCESS
)
862 * Function: be_free_fs_list
863 * Description: Function used to free the members of a be_fs_list_data_t
866 * fld - be_fs_list_data_t pointer to free.
870 * Semi-private (library wide use only)
873 be_free_fs_list(be_fs_list_data_t
*fld
)
882 if (fld
->fs_list
== NULL
)
885 for (i
= 0; i
< fld
->fs_num
; i
++)
886 free(fld
->fs_list
[i
]);
892 * Function: be_get_ds_from_dir(char *dir)
893 * Description: Given a directory path, find the underlying dataset mounted
894 * at that directory path if there is one. The returned name
895 * is allocated in heap storage, so the caller is responsible
898 * dir - char pointer of directory to find.
900 * NULL - if directory is not mounted from a dataset.
901 * name of dataset mounted at dir.
903 * Semi-private (library wide use only)
906 be_get_ds_from_dir(char *dir
)
908 dir_data_t dd
= { 0 };
909 char resolved_dir
[MAXPATHLEN
];
911 /* Make sure length of dir is within the max length */
912 if (dir
== NULL
|| strlen(dir
) >= MAXPATHLEN
)
915 /* Resolve dir in case its lofs mounted */
916 (void) strlcpy(resolved_dir
, dir
, sizeof (resolved_dir
));
918 dd
.dir
= resolved_dir
;
920 (void) zfs_iter_root(g_zfs
, be_get_ds_from_dir_callback
, &dd
);
926 * Function: be_make_tmp_mountpoint
927 * Description: This function generates a random temporary mountpoint
928 * and creates that mountpoint directory. It returns the
929 * mountpoint in heap storage, so the caller is responsible
932 * tmp_mp - reference to pointer of where to store generated
933 * temporary mountpoint.
935 * BE_SUCCESS - Success
936 * be_errno_t - Failure
938 * Semi-private (library wide use only)
941 be_make_tmp_mountpoint(char **tmp_mp
)
945 if ((*tmp_mp
= (char *)calloc(1, sizeof (BE_TMP_MNTPNT
) + 1)) == NULL
) {
946 be_print_err(gettext("be_make_tmp_mountpoint: "
948 return (BE_ERR_NOMEM
);
950 (void) strlcpy(*tmp_mp
, BE_TMP_MNTPNT
, sizeof (BE_TMP_MNTPNT
) + 1);
951 if (mkdtemp(*tmp_mp
) == NULL
) {
953 be_print_err(gettext("be_make_tmp_mountpoint: mkdtemp() failed "
954 "for %s: %s\n"), *tmp_mp
, strerror(err
));
957 return (errno_to_be_err(err
));
964 * Function: be_mount_pool
965 * Description: This function determines if the pool's datase is mounted
966 * and if not it is used to mount the pool's dataset. The
967 * function returns the current mountpoint if we are able
968 * to mount the dataset.
970 * zhp - handle to the pool's dataset
971 * tmp_mntpnt - The temporary mountpoint that the pool's
972 * dataset is mounted on. This is set only
973 * if the attempt to mount the dataset at it's
974 * set mountpoint fails, and we've used a
975 * temporary mount point for this dataset. It
976 * is expected that the caller will free this
978 * orig_mntpnt - The original mountpoint for the pool. If a
979 * temporary mount point was needed this will
980 * be used to reset the mountpoint property to
981 * it's original mountpoint. It is expected that
982 * the caller will free this memory.
983 * pool_mounted - This flag indicates that the pool was mounted
986 * BE_SUCCESS - Success
987 * be_errno_t - Failure
989 * Semi-private (library wide use only)
996 boolean_t
*pool_mounted
)
999 char mountpoint
[MAXPATHLEN
];
1003 *orig_mntpnt
= NULL
;
1004 *pool_mounted
= B_FALSE
;
1006 if (!zfs_is_mounted(zhp
, NULL
)) {
1007 if (zfs_mount(zhp
, NULL
, 0) != 0) {
1008 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
1009 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
1010 be_print_err(gettext("be_mount_pool: failed to "
1011 "get mountpoint of (%s): %s\n"),
1013 libzfs_error_description(g_zfs
));
1014 return (zfs_err_to_be_err(g_zfs
));
1016 if ((*orig_mntpnt
= strdup(mountpoint
)) == NULL
) {
1017 be_print_err(gettext("be_mount_pool: memory "
1018 "allocation failed\n"));
1019 return (BE_ERR_NOMEM
);
1022 * attempt to mount on a temp mountpoint
1024 if ((ret
= be_make_tmp_mountpoint(tmp_mntpnt
))
1026 be_print_err(gettext("be_mount_pool: failed "
1027 "to make temporary mountpoint\n"));
1029 *orig_mntpnt
= NULL
;
1033 if (zfs_prop_set(zhp
,
1034 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1035 *tmp_mntpnt
) != 0) {
1036 be_print_err(gettext("be_mount_pool: failed "
1037 "to set mountpoint of pool dataset %s to "
1038 "%s: %s\n"), zfs_get_name(zhp
),
1040 libzfs_error_description(g_zfs
));
1043 *orig_mntpnt
= NULL
;
1045 return (zfs_err_to_be_err(g_zfs
));
1048 if (zfs_mount(zhp
, NULL
, 0) != 0) {
1049 be_print_err(gettext("be_mount_pool: failed "
1050 "to mount dataset %s at %s: %s\n"),
1051 zfs_get_name(zhp
), *tmp_mntpnt
,
1052 libzfs_error_description(g_zfs
));
1053 ret
= zfs_err_to_be_err(g_zfs
);
1054 if (zfs_prop_set(zhp
,
1055 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1057 be_print_err(gettext("be_mount_pool: "
1058 "failed to set mountpoint of pool "
1059 "dataset %s to %s: %s\n"),
1060 zfs_get_name(zhp
), *tmp_mntpnt
,
1061 libzfs_error_description(g_zfs
));
1065 *orig_mntpnt
= NULL
;
1070 *pool_mounted
= B_TRUE
;
1073 return (BE_SUCCESS
);
1077 * Function: be_unmount_pool
1078 * Description: This function is used to unmount the pool's dataset if we
1079 * mounted it previously using be_mount_pool().
1081 * zhp - handle to the pool's dataset
1082 * tmp_mntpnt - If a temprary mount point was used this will
1083 * be set. Since this was created in be_mount_pool
1084 * we will need to clean it up here.
1085 * orig_mntpnt - The original mountpoint for the pool. This is
1086 * used to set the dataset mountpoint property
1087 * back to it's original value in the case where a
1088 * temporary mountpoint was used.
1090 * BE_SUCCESS - Success
1091 * be_errno_t - Failure
1093 * Semi-private (library wide use only)
1101 if (zfs_unmount(zhp
, NULL
, 0) != 0) {
1102 be_print_err(gettext("be_unmount_pool: failed to "
1103 "unmount pool (%s): %s\n"), zfs_get_name(zhp
),
1104 libzfs_error_description(g_zfs
));
1105 return (zfs_err_to_be_err(g_zfs
));
1107 if (orig_mntpnt
!= NULL
) {
1108 if (tmp_mntpnt
!= NULL
&&
1109 strcmp(orig_mntpnt
, tmp_mntpnt
) != 0) {
1110 (void) rmdir(tmp_mntpnt
);
1112 if (zfs_prop_set(zhp
,
1113 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1114 orig_mntpnt
) != 0) {
1115 be_print_err(gettext("be_unmount_pool: failed "
1116 "to set the mountpoint for dataset (%s) to "
1117 "%s: %s\n"), zfs_get_name(zhp
), orig_mntpnt
,
1118 libzfs_error_description(g_zfs
));
1119 return (zfs_err_to_be_err(g_zfs
));
1123 return (BE_SUCCESS
);
1126 /* ******************************************************************** */
1127 /* Private Functions */
1128 /* ******************************************************************** */
1131 * Function: be_mount_callback
1132 * Description: Callback function used to iterate through all of a BE's
1133 * subordinate file systems and to mount them accordingly.
1135 * zhp - zfs_handle_t pointer to current file system being
1137 * data - pointer to the altroot of where to mount BE.
1140 * be_errno_t - Failure
1145 be_mount_callback(zfs_handle_t
*zhp
, void *data
)
1147 zprop_source_t sourcetype
;
1148 const char *fs_name
= zfs_get_name(zhp
);
1149 char source
[ZFS_MAX_DATASET_NAME_LEN
];
1150 char *altroot
= data
;
1151 char zhp_mountpoint
[MAXPATHLEN
];
1152 char mountpoint
[MAXPATHLEN
];
1155 /* Get dataset's mountpoint and source values */
1156 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, zhp_mountpoint
,
1157 sizeof (zhp_mountpoint
), &sourcetype
, source
, sizeof (source
),
1159 be_print_err(gettext("be_mount_callback: failed to "
1160 "get mountpoint and sourcetype for %s\n"),
1163 return (BE_ERR_ZFS
);
1167 * Set this filesystem's 'canmount' property to 'noauto' just incase
1168 * it's been set 'on'.
1170 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")) {
1171 be_print_err(gettext("be_mount_callback: failed to "
1172 "set canmount to 'noauto' (%s)\n"), fs_name
);
1174 return (BE_ERR_ZFS
);
1178 * If the mountpoint is none, there's nothing to do, goto next.
1179 * If the mountpoint is legacy, legacy mount it with mount(2).
1180 * If the mountpoint is inherited, its mountpoint should
1181 * already be set. If it's not, then explicitly fix-up
1182 * the mountpoint now by appending its explicitly set
1183 * mountpoint value to the BE mountpoint.
1185 if (strcmp(zhp_mountpoint
, ZFS_MOUNTPOINT_NONE
) == 0) {
1187 } else if (strcmp(zhp_mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1189 * If the mountpoint is set to 'legacy', we need to
1190 * dig into this BE's vfstab to figure out where to
1191 * mount it, and just mount it via mount(2).
1193 if (get_mountpoint_from_vfstab(altroot
, fs_name
,
1194 mountpoint
, sizeof (mountpoint
), B_TRUE
) == BE_SUCCESS
) {
1196 /* Legacy mount the file system */
1197 if (mount(fs_name
, mountpoint
, MS_DATA
,
1198 MNTTYPE_ZFS
, NULL
, 0, NULL
, 0) != 0) {
1200 gettext("be_mount_callback: "
1201 "failed to mount %s on %s\n"),
1202 fs_name
, mountpoint
);
1206 gettext("be_mount_callback: "
1207 "no entry for %s in vfstab, "
1208 "skipping ...\n"), fs_name
);
1213 } else if ((sourcetype
& (ZPROP_SRC_INHERITED
|ZPROP_SRC_LOCAL
)) == 0) {
1215 * Skip dataset if mountpoint is not inherited
1216 * or explicitly set.
1218 be_print_err(gettext("be_mount_callback: "
1219 "mountpoint sourcetype of %s is %d, skipping ...\n"),
1220 fs_name
, sourcetype
);
1225 /* Mount this filesystem */
1226 if (mount_zfs(zhp
, altroot
) != 0) {
1227 be_print_err(gettext("be_mount_callback: failed to "
1228 "mount dataset %s at %s: %s\n"), fs_name
, mountpoint
,
1231 return (BE_ERR_MOUNT
);
1235 /* Iterate through this dataset's children and mount them */
1236 if ((ret
= zfs_iter_filesystems(zhp
, be_mount_callback
,
1248 * Function: be_unmount_callback
1249 * Description: Callback function used to iterate through all of a BE's
1250 * subordinate file systems and to unmount them.
1252 * zhp - zfs_handle_t pointer to current file system being
1254 * data - pointer to the mountpoint of where BE is mounted.
1257 * be_errno_t - Failure
1262 be_unmount_callback(zfs_handle_t
*zhp
, void *data
)
1264 be_unmount_data_t
*ud
= data
;
1265 zprop_source_t sourcetype
;
1266 const char *fs_name
= zfs_get_name(zhp
);
1267 char source
[ZFS_MAX_DATASET_NAME_LEN
];
1268 char mountpoint
[MAXPATHLEN
];
1269 char *zhp_mountpoint
;
1272 /* Iterate down this dataset's children first */
1273 if (zfs_iter_filesystems(zhp
, be_unmount_callback
, ud
)) {
1274 ret
= BE_ERR_UMOUNT
;
1278 /* Is dataset even mounted ? */
1279 if (!zfs_is_mounted(zhp
, NULL
))
1282 /* Unmount this file system */
1283 if (zfs_unmount(zhp
, NULL
, ud
->force
? MS_FORCE
: 0) != 0) {
1284 be_print_err(gettext("be_unmount_callback: "
1285 "failed to unmount %s: %s\n"), fs_name
,
1286 libzfs_error_description(g_zfs
));
1287 ret
= zfs_err_to_be_err(g_zfs
);
1291 /* Get dataset's current mountpoint and source value */
1292 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
1293 sizeof (mountpoint
), &sourcetype
, source
, sizeof (source
),
1295 be_print_err(gettext("be_unmount_callback: "
1296 "failed to get mountpoint and sourcetype for %s: %s\n"),
1297 fs_name
, libzfs_error_description(g_zfs
));
1298 ret
= zfs_err_to_be_err(g_zfs
);
1302 if (sourcetype
& ZPROP_SRC_INHERITED
) {
1304 * If the mountpoint is inherited we don't need to
1305 * do anything. When its parent gets processed
1306 * its mountpoint will be set accordingly.
1309 } else if (sourcetype
& ZPROP_SRC_LOCAL
) {
1311 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1313 * If the mountpoint is set to 'legacy', its already
1314 * been unmounted (from above call to zfs_unmount), and
1315 * we don't need to do anything else with it.
1321 * Else process dataset with explicitly set mountpoint.
1325 * Get this dataset's mountpoint relative to
1326 * the BE's mountpoint.
1328 if ((strncmp(mountpoint
, ud
->altroot
,
1329 strlen(ud
->altroot
)) == 0) &&
1330 (mountpoint
[strlen(ud
->altroot
)] == '/')) {
1332 zhp_mountpoint
= mountpoint
+
1333 strlen(ud
->altroot
);
1335 /* Set this dataset's mountpoint value */
1336 if (zfs_prop_set(zhp
,
1337 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1340 gettext("be_unmount_callback: "
1341 "failed to set mountpoint for "
1342 "%s to %s: %s\n"), fs_name
,
1344 libzfs_error_description(g_zfs
));
1345 ret
= zfs_err_to_be_err(g_zfs
);
1349 * Nothing to do, mountpoint shouldn't be
1356 be_print_err(gettext("be_unmount_callback: "
1357 "mountpoint sourcetype of %s is %d, skipping ...\n"),
1358 fs_name
, sourcetype
);
1363 /* Set this filesystem's 'canmount' property to 'noauto' */
1364 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")) {
1365 be_print_err(gettext("be_unmount_callback: "
1366 "failed to set canmount to 'noauto' (%s)\n"), fs_name
);
1376 * Function: be_get_legacy_fs_callback
1377 * Description: The callback function is used to iterate through all
1378 * non-shared file systems of a BE, finding ones that have
1379 * a legacy mountpoint and an entry in the BE's vfstab.
1380 * It adds these file systems to the callback data.
1382 * zhp - zfs_handle_t pointer to current file system being
1384 * data - be_fs_list_data_t pointer
1387 * be_errno_t - Failure
1392 be_get_legacy_fs_callback(zfs_handle_t
*zhp
, void *data
)
1394 be_fs_list_data_t
*fld
= data
;
1395 const char *fs_name
= zfs_get_name(zhp
);
1396 char zhp_mountpoint
[MAXPATHLEN
];
1397 char mountpoint
[MAXPATHLEN
];
1400 /* Get this dataset's mountpoint property */
1401 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, zhp_mountpoint
,
1402 sizeof (zhp_mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
1403 be_print_err(gettext("be_get_legacy_fs_callback: "
1404 "failed to get mountpoint for %s: %s\n"),
1405 fs_name
, libzfs_error_description(g_zfs
));
1406 ret
= zfs_err_to_be_err(g_zfs
);
1412 * If mountpoint is legacy, try to get its mountpoint from this BE's
1413 * vfstab. If it exists in the vfstab, add this file system to the
1416 if (strcmp(zhp_mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1417 if (get_mountpoint_from_vfstab(fld
->altroot
, fs_name
,
1418 mountpoint
, sizeof (mountpoint
), B_FALSE
) != BE_SUCCESS
) {
1419 be_print_err(gettext("be_get_legacy_fs_callback: "
1420 "no entry for %s in vfstab, "
1421 "skipping ...\n"), fs_name
);
1426 /* Record file system into the callback data. */
1427 if (add_to_fs_list(fld
, zfs_get_name(zhp
)) != BE_SUCCESS
) {
1428 be_print_err(gettext("be_get_legacy_fs_callback: "
1429 "failed to add %s to fs list\n"), mountpoint
);
1431 return (BE_ERR_NOMEM
);
1436 /* Iterate through this dataset's children file systems */
1437 if ((ret
= zfs_iter_filesystems(zhp
, be_get_legacy_fs_callback
,
1447 * Function: add_to_fs_list
1448 * Description: Function used to add a file system to the fs_list array in
1449 * a be_fs_list_data_t structure.
1451 * fld - be_fs_list_data_t pointer
1452 * fs - file system to add
1454 * BE_SUCCESS - Success
1460 add_to_fs_list(be_fs_list_data_t
*fld
, const char *fs
)
1462 if (fld
== NULL
|| fs
== NULL
)
1465 if ((fld
->fs_list
= reallocarray(fld
->fs_list
, fld
->fs_num
+ 1,
1466 sizeof (char *))) == NULL
) {
1467 be_print_err(gettext("add_to_fs_list: "
1468 "memory allocation failed\n"));
1472 if ((fld
->fs_list
[fld
->fs_num
++] = strdup(fs
)) == NULL
) {
1473 be_print_err(gettext("add_to_fs_list: "
1474 "memory allocation failed\n"));
1478 return (BE_SUCCESS
);
1482 * Function: zpool_shared_fs_callback
1483 * Description: Callback function used to iterate through all existing pools
1484 * to find and mount all shared filesystems. This function
1485 * processes the pool's "pool data" dataset, then uses
1486 * iter_shared_fs_callback to iterate through the pool's
1489 * zlp - zpool_handle_t pointer to the current pool being
1491 * data - be_mount_data_t pointer
1494 * be_errno_t - Failure
1499 zpool_shared_fs_callback(zpool_handle_t
*zlp
, void *data
)
1501 be_mount_data_t
*md
= data
;
1502 zfs_handle_t
*zhp
= NULL
;
1503 const char *zpool
= zpool_get_name(zlp
);
1507 * Get handle to pool's "pool data" dataset
1509 if ((zhp
= zfs_open(g_zfs
, zpool
, ZFS_TYPE_FILESYSTEM
)) == NULL
) {
1510 be_print_err(gettext("zpool_shared_fs: "
1511 "failed to open pool dataset %s: %s\n"), zpool
,
1512 libzfs_error_description(g_zfs
));
1513 ret
= zfs_err_to_be_err(g_zfs
);
1518 /* Process this pool's "pool data" dataset */
1519 (void) loopback_mount_shared_fs(zhp
, md
);
1521 /* Interate through this pool's children */
1522 (void) zfs_iter_filesystems(zhp
, iter_shared_fs_callback
, md
);
1531 * Function: iter_shared_fs_callback
1532 * Description: Callback function used to iterate through a pool's datasets
1533 * to find and mount all shared filesystems. It makes sure to
1534 * find the BE container dataset of the pool, if it exists, and
1535 * does not process and iterate down that path.
1537 * Note - This function iterates linearly down the
1538 * hierarchical dataset paths and mounts things as it goes
1539 * along. It does not make sure that something deeper down
1540 * a dataset path has an interim mountpoint for something
1541 * processed earlier.
1544 * zhp - zfs_handle_t pointer to the current dataset being
1546 * data - be_mount_data_t pointer
1549 * be_errno_t - Failure
1554 iter_shared_fs_callback(zfs_handle_t
*zhp
, void *data
)
1556 be_mount_data_t
*md
= data
;
1557 const char *name
= zfs_get_name(zhp
);
1558 char container_ds
[MAXPATHLEN
];
1559 char tmp_name
[MAXPATHLEN
];
1562 /* Get the pool's name */
1563 (void) strlcpy(tmp_name
, name
, sizeof (tmp_name
));
1564 pool
= strtok(tmp_name
, "/");
1567 /* Get the name of this pool's container dataset */
1568 be_make_container_ds(pool
, container_ds
,
1569 sizeof (container_ds
));
1572 * If what we're processing is this pool's BE container
1575 if (strcmp(name
, container_ds
) == 0) {
1580 /* Getting the pool name failed, return error */
1581 be_print_err(gettext("iter_shared_fs_callback: "
1582 "failed to get pool name from %s\n"), name
);
1584 return (BE_ERR_POOL_NOENT
);
1587 /* Mount this shared filesystem */
1588 (void) loopback_mount_shared_fs(zhp
, md
);
1590 /* Iterate this dataset's children file systems */
1591 (void) zfs_iter_filesystems(zhp
, iter_shared_fs_callback
, md
);
1598 * Function: loopback_mount_shared_fs
1599 * Description: This function loopback mounts a file system into the altroot
1600 * area of the BE being mounted. Since these are shared file
1601 * systems, they are expected to be already mounted for the
1602 * current BE, and this function just loopback mounts them into
1603 * the BE mountpoint. If they are not mounted for the current
1604 * live system, they are skipped and not mounted into the BE
1607 * zhp - zfs_handle_t pointer to the dataset to loopback mount
1608 * md - be_mount_data_t pointer
1610 * BE_SUCCESS - Success
1611 * be_errno_t - Failure
1616 loopback_mount_shared_fs(zfs_handle_t
*zhp
, be_mount_data_t
*md
)
1618 char zhp_mountpoint
[MAXPATHLEN
];
1619 char mountpoint
[MAXPATHLEN
];
1621 char optstr
[MAX_MNTOPT_STR
];
1622 int mflag
= MS_OPTIONSTR
;
1626 * Check if file system is currently mounted and not delegated
1627 * to a non-global zone (if we're in the global zone)
1629 if (zfs_is_mounted(zhp
, &mp
) && (getzoneid() != GLOBAL_ZONEID
||
1630 !zfs_prop_get_int(zhp
, ZFS_PROP_ZONED
))) {
1632 * If we didn't get a mountpoint from the zfs_is_mounted call,
1633 * get it from the mountpoint property.
1636 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
,
1637 zhp_mountpoint
, sizeof (zhp_mountpoint
), NULL
,
1638 NULL
, 0, B_FALSE
) != 0) {
1640 gettext("loopback_mount_shared_fs: "
1641 "failed to get mountpoint property\n"));
1642 return (BE_ERR_ZFS
);
1645 (void) strlcpy(zhp_mountpoint
, mp
,
1646 sizeof (zhp_mountpoint
));
1650 (void) snprintf(mountpoint
, sizeof (mountpoint
), "%s%s",
1651 md
->altroot
, zhp_mountpoint
);
1653 /* Mount it read-only if read-write was not requested */
1654 if (!md
->shared_rw
) {
1658 /* Add the "nosub" option to the mount options string */
1659 (void) strlcpy(optstr
, MNTOPT_NOSUB
, sizeof (optstr
));
1661 /* Loopback mount this dataset at the altroot */
1662 if (mount(zhp_mountpoint
, mountpoint
, mflag
, MNTTYPE_LOFS
,
1663 NULL
, 0, optstr
, sizeof (optstr
)) != 0) {
1665 be_print_err(gettext("loopback_mount_shared_fs: "
1666 "failed to loopback mount %s at %s: %s\n"),
1667 zhp_mountpoint
, mountpoint
, strerror(err
));
1668 return (BE_ERR_MOUNT
);
1672 return (BE_SUCCESS
);
1676 * Function: loopback_mount_zonepath
1677 * Description: This function loopback mounts a zonepath into the altroot
1678 * area of the BE being mounted.
1680 * zonepath - pointer to zone path in the current BE
1681 * md - be_mount_data_t pointer
1683 * BE_SUCCESS - Success
1684 * be_errno_t - Failure
1689 loopback_mount_zonepath(const char *zonepath
, be_mount_data_t
*md
)
1696 struct extmnttab extmtab
;
1699 char alt_parentmnt
[MAXPATHLEN
];
1700 struct mnttab mntref
;
1701 char altzonepath
[MAXPATHLEN
];
1702 char optstr
[MAX_MNTOPT_STR
];
1703 int mflag
= MS_OPTIONSTR
;
1707 fp
= fopen(MNTTAB
, "r");
1710 be_print_err(gettext("loopback_mount_zonepath: "
1711 "failed to open /etc/mnttab\n"));
1712 return (errno_to_be_err(err
));
1716 * before attempting the loopback mount of zonepath under altroot,
1717 * we need to make sure that all intermediate file systems in the
1718 * zone path are also mounted under altroot
1721 /* get the parent directory for zonepath */
1722 p
= strrchr(zonepath
, '/');
1723 if (p
!= NULL
&& p
!= zonepath
) {
1724 if ((parent_dir
= (char *)calloc(sizeof (char),
1725 p
- zonepath
+ 1)) == NULL
) {
1729 (void) strlcpy(parent_dir
, zonepath
, p
- zonepath
+ 1);
1730 if (stat(parent_dir
, &st
) < 0) {
1731 ret
= errno_to_be_err(errno
);
1732 be_print_err(gettext("loopback_mount_zonepath: "
1733 "failed to stat %s"),
1741 * After the above stat call, st.st_dev contains ID of the
1742 * device over which parent dir resides.
1743 * Now, search mnttab and find mount point of parent dir device.
1747 while (getextmntent(fp
, &extmtab
, sizeof (extmtab
)) == 0) {
1748 dev
= makedev(extmtab
.mnt_major
, extmtab
.mnt_minor
);
1749 if (st
.st_dev
== dev
&& strcmp(extmtab
.mnt_fstype
,
1750 MNTTYPE_ZFS
) == 0) {
1751 p1
= strchr(extmtab
.mnt_special
, '/');
1752 if (p1
== NULL
|| strncmp(p1
+ 1,
1753 BE_CONTAINER_DS_NAME
, 4) != 0 ||
1754 (*(p1
+ 5) != '/' && *(p1
+ 5) != '\0')) {
1756 * if parent dir is in a shared file
1757 * system, check whether it is already
1758 * loopback mounted under altroot or
1759 * not. It would have been mounted
1760 * already under altroot if it is in
1761 * a non-shared filesystem.
1763 parentmnt
= strdup(extmtab
.mnt_mountp
);
1764 (void) snprintf(alt_parentmnt
,
1765 sizeof (alt_parentmnt
), "%s%s",
1766 md
->altroot
, parentmnt
);
1767 mntref
.mnt_mountp
= alt_parentmnt
;
1768 mntref
.mnt_special
= parentmnt
;
1769 mntref
.mnt_fstype
= MNTTYPE_LOFS
;
1770 mntref
.mnt_mntopts
= NULL
;
1771 mntref
.mnt_time
= NULL
;
1773 if (getmntany(fp
, (struct mnttab
*)
1774 &extmtab
, &mntref
) != 0) {
1775 ret
= loopback_mount_zonepath(
1777 if (ret
!= BE_SUCCESS
) {
1790 if (!md
->shared_rw
) {
1794 (void) snprintf(altzonepath
, sizeof (altzonepath
), "%s%s",
1795 md
->altroot
, zonepath
);
1797 /* Add the "nosub" option to the mount options string */
1798 (void) strlcpy(optstr
, MNTOPT_NOSUB
, sizeof (optstr
));
1800 /* Loopback mount this dataset at the altroot */
1801 if (mount(zonepath
, altzonepath
, mflag
, MNTTYPE_LOFS
,
1802 NULL
, 0, optstr
, sizeof (optstr
)) != 0) {
1804 be_print_err(gettext("loopback_mount_zonepath: "
1805 "failed to loopback mount %s at %s: %s\n"),
1806 zonepath
, altzonepath
, strerror(err
));
1818 * Function: unmount_shared_fs
1819 * Description: This function iterates through the mnttab and finds all
1820 * loopback mount entries that reside within the altroot of
1821 * where the BE is mounted, and unmounts it.
1823 * ud - be_unmount_data_t pointer
1825 * BE_SUCCESS - Success
1826 * be_errno_t - Failure
1831 unmount_shared_fs(be_unmount_data_t
*ud
)
1834 struct mnttab
*table
= NULL
;
1836 struct mnttab
*entp
= NULL
;
1838 int read_chunk
= 32;
1845 /* Read in the mnttab into a table */
1846 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1848 be_print_err(gettext("unmount_shared_fs: "
1849 "failed to open mnttab\n"));
1850 return (errno_to_be_err(err
));
1853 while (getmntent(fp
, &ent
) == 0) {
1854 if (size
% read_chunk
== 0) {
1855 table
= reallocarray(table
, size
+ read_chunk
,
1858 entp
= &table
[size
++];
1861 * Copy over the current mnttab entry into our table,
1862 * copying only the fields that we care about.
1864 (void) memset(entp
, 0, sizeof (*entp
));
1865 if ((entp
->mnt_mountp
= strdup(ent
.mnt_mountp
)) == NULL
||
1866 (entp
->mnt_fstype
= strdup(ent
.mnt_fstype
)) == NULL
) {
1867 be_print_err(gettext("unmount_shared_fs: "
1868 "memory allocation failed\n"));
1869 return (BE_ERR_NOMEM
);
1875 * Process the mnttab entries in reverse order, looking for
1876 * loopback mount entries mounted under our altroot.
1878 altroot_len
= strlen(ud
->altroot
);
1879 for (i
= size
; i
> 0; i
--) {
1880 entp
= &table
[i
- 1];
1882 /* If not of type lofs, skip */
1883 if (strcmp(entp
->mnt_fstype
, MNTTYPE_LOFS
) != 0)
1886 /* If inside the altroot, unmount it */
1887 if (strncmp(entp
->mnt_mountp
, ud
->altroot
, altroot_len
) == 0 &&
1888 entp
->mnt_mountp
[altroot_len
] == '/') {
1889 if (umount(entp
->mnt_mountp
) != 0) {
1894 if (umount(entp
->mnt_mountp
) != 0)
1898 be_print_err(gettext(
1899 "unmount_shared_fs: "
1900 "failed to unmount shared file "
1902 entp
->mnt_mountp
, strerror(err
));
1903 return (errno_to_be_err(err
));
1909 return (BE_SUCCESS
);
1913 * Function: get_mountpoint_from_vfstab
1914 * Description: This function digs into the vfstab in the given altroot,
1915 * and searches for an entry for the fs passed in. If found,
1916 * it returns the mountpoint of that fs in the mountpoint
1917 * buffer passed in. If the get_alt_mountpoint flag is set,
1918 * it returns the mountpoint with the altroot prepended.
1920 * altroot - pointer to the alternate root location
1921 * fs - pointer to the file system name to look for in the
1923 * mountpoint - pointer to buffer of where the mountpoint of
1924 * fs will be returned.
1925 * size_mp - size of mountpoint argument
1926 * get_alt_mountpoint - flag to indicate whether or not the
1927 * mountpoint should be populated with the altroot
1930 * BE_SUCCESS - Success
1936 get_mountpoint_from_vfstab(char *altroot
, const char *fs
, char *mountpoint
,
1937 size_t size_mp
, boolean_t get_alt_mountpoint
)
1941 char alt_vfstab
[MAXPATHLEN
];
1943 /* Generate path to alternate root vfstab */
1944 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
1947 /* Open alternate root vfstab */
1948 if ((fp
= fopen(alt_vfstab
, "r")) == NULL
) {
1949 be_print_err(gettext("get_mountpoint_from_vfstab: "
1950 "failed to open vfstab (%s)\n"), alt_vfstab
);
1954 if (getvfsspec(fp
, &vp
, (char *)fs
) == 0) {
1956 * Found entry for fs, grab its mountpoint.
1957 * If the flag to prepend the altroot into the mountpoint
1958 * is set, prepend it. Otherwise, just return the mountpoint.
1960 if (get_alt_mountpoint
) {
1961 (void) snprintf(mountpoint
, size_mp
, "%s%s", altroot
,
1964 (void) strlcpy(mountpoint
, vp
.vfs_mountp
, size_mp
);
1973 return (BE_SUCCESS
);
1977 * Function: fix_mountpoint_callback
1978 * Description: This callback function is used to iterate through a BE's
1979 * children filesystems to check if its mountpoint is currently
1980 * set to be mounted at some specified altroot. If so, fix it by
1981 * removing altroot from the beginning of its mountpoint.
1983 * Note - There's no way to tell if a child filesystem's
1984 * mountpoint isn't broken, and just happens to begin with
1985 * the altroot we're looking for. In this case, this function
1986 * will errantly remove the altroot portion from the beginning
1987 * of this filesystem's mountpoint.
1990 * zhp - zfs_handle_t pointer to filesystem being processed.
1991 * data - altroot of where BE is to be mounted.
1994 * be_errno_t - Failure
1999 fix_mountpoint_callback(zfs_handle_t
*zhp
, void *data
)
2001 zprop_source_t sourcetype
;
2002 char source
[ZFS_MAX_DATASET_NAME_LEN
];
2003 char mountpoint
[MAXPATHLEN
];
2004 char *zhp_mountpoint
= NULL
;
2005 char *altroot
= data
;
2008 /* Get dataset's mountpoint and source values */
2009 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
2010 sizeof (mountpoint
), &sourcetype
, source
, sizeof (source
),
2012 be_print_err(gettext("fix_mountpoint_callback: "
2013 "failed to get mountpoint and sourcetype for %s\n"),
2016 return (BE_ERR_ZFS
);
2020 * If the mountpoint is not inherited and the mountpoint is not
2021 * 'legacy', this file system potentially needs its mountpoint
2024 if (!(sourcetype
& ZPROP_SRC_INHERITED
) &&
2025 strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) != 0) {
2028 * Check if this file system's current mountpoint is
2029 * under the altroot we're fixing it against.
2031 if (strncmp(mountpoint
, altroot
, strlen(altroot
)) == 0 &&
2032 mountpoint
[strlen(altroot
)] == '/') {
2035 * Get this dataset's mountpoint relative to the
2038 zhp_mountpoint
= mountpoint
+ strlen(altroot
);
2040 /* Fix this dataset's mountpoint value */
2041 if (zfs_prop_set(zhp
,
2042 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
2044 be_print_err(gettext("fix_mountpoint_callback: "
2045 "failed to set mountpoint for %s to "
2046 "%s: %s\n"), zfs_get_name(zhp
),
2048 libzfs_error_description(g_zfs
));
2049 ret
= zfs_err_to_be_err(g_zfs
);
2056 /* Iterate through this dataset's children and fix them */
2057 if ((ret
= zfs_iter_filesystems(zhp
, fix_mountpoint_callback
,
2069 * Function: be_mount_root
2070 * Description: This function mounts the root dataset of a BE at the
2071 * specified altroot.
2073 * zhp - zfs_handle_t pointer to root dataset of a BE that is
2074 * to be mounted at altroot.
2075 * altroot - location of where to mount the BE root.
2077 * BE_SUCCESS - Success
2078 * be_errno_t - Failure
2083 be_mount_root(zfs_handle_t
*zhp
, char *altroot
)
2085 char mountpoint
[MAXPATHLEN
];
2087 /* Get mountpoint property of dataset */
2088 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
2089 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
2090 be_print_err(gettext("be_mount_root: failed to "
2091 "get mountpoint property for %s: %s\n"), zfs_get_name(zhp
),
2092 libzfs_error_description(g_zfs
));
2093 return (zfs_err_to_be_err(g_zfs
));
2097 * Set the canmount property for the BE's root dataset to 'noauto' just
2098 * in case it's been set to 'on'.
2100 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")
2102 be_print_err(gettext("be_mount_root: failed to "
2103 "set canmount property to 'noauto' (%s): %s\n"),
2104 zfs_get_name(zhp
), libzfs_error_description(g_zfs
));
2105 return (zfs_err_to_be_err(g_zfs
));
2108 /* Mount the BE's root filesystem */
2109 if (mount_zfs(zhp
, altroot
) != 0) {
2110 be_print_err(gettext("be_mount_root: failed to "
2111 "mount dataset %s at %s: %s\n"), zfs_get_name(zhp
),
2112 altroot
, strerror(errno
));
2113 return (BE_ERR_ZFS
);
2116 return (BE_SUCCESS
);
2120 * Function: be_unmount_root
2121 * Description: This function unmounts the root dataset of a BE, but before
2122 * unmounting, it looks at the BE's vfstab to determine
2123 * if the root dataset mountpoint should be left as 'legacy'
2124 * or '/'. If the vfstab contains an entry for this root
2125 * dataset with a mountpoint of '/', it sets the mountpoint
2126 * property to 'legacy'.
2129 * zhp - zfs_handle_t pointer of the BE root dataset that
2130 * is currently mounted.
2131 * ud - be_unmount_data_t pointer providing unmount data
2132 * for the given BE root dataset.
2134 * BE_SUCCESS - Success
2135 * be_errno_t - Failure
2140 be_unmount_root(zfs_handle_t
*zhp
, be_unmount_data_t
*ud
)
2142 char mountpoint
[MAXPATHLEN
];
2143 boolean_t is_legacy
= B_FALSE
;
2145 /* See if this is a legacy mounted root */
2146 if (get_mountpoint_from_vfstab(ud
->altroot
, zfs_get_name(zhp
),
2147 mountpoint
, sizeof (mountpoint
), B_FALSE
) == BE_SUCCESS
&&
2148 strcmp(mountpoint
, "/") == 0) {
2152 /* Unmount the dataset */
2153 if (zfs_unmount(zhp
, NULL
, ud
->force
? MS_FORCE
: 0) != 0) {
2154 be_print_err(gettext("be_unmount_root: failed to "
2155 "unmount BE root dataset %s: %s\n"), zfs_get_name(zhp
),
2156 libzfs_error_description(g_zfs
));
2157 return (zfs_err_to_be_err(g_zfs
));
2160 /* Set canmount property for this BE's root filesystem to noauto */
2161 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")
2163 be_print_err(gettext("be_unmount_root: failed to "
2164 "set canmount property for %s to 'noauto': %s\n"),
2165 zfs_get_name(zhp
), libzfs_error_description(g_zfs
));
2166 return (zfs_err_to_be_err(g_zfs
));
2170 * Set mountpoint for BE's root dataset back to '/', or 'legacy'
2171 * if its a legacy mounted root.
2173 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
2174 is_legacy
? ZFS_MOUNTPOINT_LEGACY
: "/") != 0) {
2175 be_print_err(gettext("be_unmount_root: failed to "
2176 "set mountpoint of %s to %s\n"), zfs_get_name(zhp
),
2177 is_legacy
? ZFS_MOUNTPOINT_LEGACY
: "/");
2178 return (zfs_err_to_be_err(g_zfs
));
2181 return (BE_SUCCESS
);
2185 * Function: fix_mountpoint
2186 * Description: This function checks the mountpoint of an unmounted BE to make
2187 * sure that it is set to either 'legacy' or '/'. If it's not,
2188 * then we're in a situation where an unmounted BE has some random
2189 * mountpoint set for it. (This could happen if the system was
2190 * rebooted while an inactive BE was mounted). This function
2191 * attempts to fix its mountpoints.
2193 * zhp - zfs_handle_t pointer to root dataset of the BE
2194 * whose mountpoint needs to be checked.
2196 * BE_SUCCESS - Success
2197 * be_errno_t - Failure
2202 fix_mountpoint(zfs_handle_t
*zhp
)
2204 be_unmount_data_t ud
= { 0 };
2205 char *altroot
= NULL
;
2206 char mountpoint
[MAXPATHLEN
];
2207 int ret
= BE_SUCCESS
;
2210 * Record what this BE's root dataset mountpoint property is currently
2213 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
2214 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
2215 be_print_err(gettext("fix_mountpoint: failed to get "
2216 "mountpoint property of (%s): %s\n"), zfs_get_name(zhp
),
2217 libzfs_error_description(g_zfs
));
2218 return (BE_ERR_ZFS
);
2222 * If the root dataset mountpoint is set to 'legacy' or '/', we're okay.
2224 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0 ||
2225 strcmp(mountpoint
, "/") == 0) {
2226 return (BE_SUCCESS
);
2230 * Iterate through this BE's children datasets and fix
2231 * them if they need fixing.
2233 if (zfs_iter_filesystems(zhp
, fix_mountpoint_callback
, mountpoint
)
2235 return (BE_ERR_ZFS
);
2239 * The process of mounting and unmounting the root file system
2240 * will fix its mountpoint to correctly be either 'legacy' or '/'
2241 * since be_unmount_root will do the right thing by looking at
2245 /* Generate temporary altroot to mount the root file system */
2246 if ((ret
= be_make_tmp_mountpoint(&altroot
)) != BE_SUCCESS
) {
2247 be_print_err(gettext("fix_mountpoint: failed to "
2248 "make temporary mountpoint\n"));
2252 /* Mount and unmount the root. */
2253 if ((ret
= be_mount_root(zhp
, altroot
)) != BE_SUCCESS
) {
2254 be_print_err(gettext("fix_mountpoint: failed to "
2255 "mount BE root file system\n"));
2258 ud
.altroot
= altroot
;
2259 if ((ret
= be_unmount_root(zhp
, &ud
)) != BE_SUCCESS
) {
2260 be_print_err(gettext("fix_mountpoint: failed to "
2261 "unmount BE root file system\n"));
2272 * Function: be_mount_zones
2273 * Description: This function finds all supported non-global zones in the
2274 * given global BE and mounts them with respect to where the
2275 * global BE is currently mounted. The global BE datasets
2276 * (including its shared datasets) are expected to already
2279 * be_zhp - zfs_handle_t pointer to the root dataset of the
2281 * md - be_mount_data_t pointer to data for global BE.
2283 * BE_SUCCESS - Success
2284 * be_errno_t - Failure
2289 be_mount_zones(zfs_handle_t
*be_zhp
, be_mount_data_t
*md
)
2291 char *zonepath_ds
= NULL
;
2292 int ret
= BE_SUCCESS
;
2296 zonecfg_set_root((const char *)md
->altroot
);
2298 cookie
= setzoneent();
2299 while((ze
= getzoneent_private(cookie
)) != NULL
) {
2301 if (strcmp(ze
->zone_name
, "global") == 0)
2304 /* Skip zones that aren't at least installed */
2305 if (ze
->zone_state
== ZONE_STATE_INSTALLED
) {
2307 if (((zonepath_ds
= be_get_ds_from_dir(ze
->zone_path
)) == NULL
) ||
2308 !be_zone_supported(zonepath_ds
)) {
2315 * if BE's shared file systems are already mounted,
2316 * zone path dataset would have already been lofs
2317 * mounted under altroot. Otherwise, we need to do
2320 if (!md
->shared_fs
) {
2321 ret
= loopback_mount_zonepath(ze
->zone_path
, md
);
2322 if (ret
!= BE_SUCCESS
)
2326 /* Mount this zone */
2327 ret
= be_mount_one_zone(be_zhp
, md
, ze
->zone_name
,
2328 ze
->zone_path
, zonepath_ds
);
2333 if (ret
!= BE_SUCCESS
) {
2334 be_print_err(gettext("be_mount_zones: "
2335 "failed to mount zone %s under "
2336 "altroot %s\n"), ze
->zone_name
, md
->altroot
);
2350 * Function: be_unmount_zones
2351 * Description: This function finds all supported non-global zones in the
2352 * given mounted global BE and unmounts them.
2354 * ud - unmount_data_t pointer data for the global BE.
2356 * BE_SUCCESS - Success
2357 * be_errno_t - Failure
2362 be_unmount_zones(be_unmount_data_t
*ud
)
2364 char alt_zonepath
[MAXPATHLEN
];
2365 char *zonepath_ds
= NULL
;
2366 int ret
= BE_SUCCESS
;
2370 zonecfg_set_root((const char *)ud
->altroot
);
2372 cookie
= setzoneent();
2373 while((ze
= getzoneent_private(cookie
)) != NULL
) {
2375 if (strcmp(ze
->zone_name
, "global") == 0)
2378 if (ze
->zone_state
== ZONE_STATE_INSTALLED
) {
2380 /* Build zone's zonepath wrt the global BE altroot */
2381 (void) snprintf(alt_zonepath
, sizeof (alt_zonepath
),
2382 "%s%s", ud
->altroot
, ze
->zone_path
);
2385 * Get the dataset of this zonepath. If its not
2386 * a dataset, skip it.
2388 if ((zonepath_ds
= be_get_ds_from_dir(alt_zonepath
))
2393 * Check if this zone is supported based on the
2394 * dataset of its zonepath.
2396 if (!be_zone_supported(zonepath_ds
)) {
2403 /* Unmount this zone */
2404 ret
= be_unmount_one_zone(ud
, ze
->zone_name
, ze
->zone_path
,
2410 if (ret
!= BE_SUCCESS
) {
2411 be_print_err(gettext("be_unmount_zones:"
2412 " failed to unmount zone %s from "
2413 "altroot %s\n"), ze
->zone_name
, ud
->altroot
);
2427 * Function: be_mount_one_zone
2428 * Description: This function is called to mount one zone for a given
2431 * be_zhp - zfs_handle_t pointer to the root dataset of the
2433 * md - be_mount_data_t pointer to data for global BE
2434 * zonename - name of zone to mount
2435 * zonepath - zonepath of zone to mount
2436 * zonepath_ds - dataset for the zonepath
2438 * BE_SUCCESS - Success
2439 * be_errno_t - Failure
2444 be_mount_one_zone(zfs_handle_t
*be_zhp
, be_mount_data_t
*md
, char *zonename
,
2445 char *zonepath
, char *zonepath_ds
)
2447 be_mount_data_t zone_md
= { 0 };
2448 zfs_handle_t
*zone_zhp
= NULL
;
2449 char zone_altroot
[MAXPATHLEN
];
2450 char zoneroot
[MAXPATHLEN
];
2451 char zoneroot_ds
[MAXPATHLEN
];
2452 int ret
= BE_SUCCESS
;
2454 /* Find the active zone root dataset for this zone for this BE */
2455 if ((ret
= be_find_active_zone_root(be_zhp
, zonepath_ds
, zoneroot_ds
,
2456 sizeof (zoneroot_ds
))) == BE_ERR_ZONE_NO_ACTIVE_ROOT
) {
2457 be_print_err(gettext("be_mount_one_zone: did not "
2458 "find active zone root for zone %s, skipping ...\n"),
2460 return (BE_SUCCESS
);
2461 } else if (ret
!= BE_SUCCESS
) {
2462 be_print_err(gettext("be_mount_one_zone: failed to "
2463 "find active zone root for zone %s\n"), zonename
);
2467 /* Get handle to active zoneroot dataset */
2468 if ((zone_zhp
= zfs_open(g_zfs
, zoneroot_ds
, ZFS_TYPE_FILESYSTEM
))
2470 be_print_err(gettext("be_mount_one_zone: failed to "
2471 "open zone root dataset (%s): %s\n"), zoneroot_ds
,
2472 libzfs_error_description(g_zfs
));
2473 return (zfs_err_to_be_err(g_zfs
));
2476 /* Generate string for zone's altroot path */
2477 be_make_zoneroot(zonepath
, zoneroot
, sizeof (zoneroot
));
2478 (void) strlcpy(zone_altroot
, md
->altroot
, sizeof (zone_altroot
));
2479 (void) strlcat(zone_altroot
, zoneroot
, sizeof (zone_altroot
));
2481 /* Build mount_data for the zone */
2482 zone_md
.altroot
= zone_altroot
;
2483 zone_md
.shared_fs
= md
->shared_fs
;
2484 zone_md
.shared_rw
= md
->shared_rw
;
2486 /* Mount the zone's root file system */
2487 if ((ret
= be_mount_zone_root(zone_zhp
, &zone_md
)) != BE_SUCCESS
) {
2488 be_print_err(gettext("be_mount_one_zone: failed to "
2489 "mount zone root file system at %s\n"), zone_altroot
);
2493 /* Iterate through zone's children filesystems */
2494 if ((ret
= zfs_iter_filesystems(zone_zhp
, be_mount_callback
,
2495 zone_altroot
)) != 0) {
2496 be_print_err(gettext("be_mount_one_zone: failed to "
2497 "mount zone subordinate file systems at %s\n"),
2502 /* TODO: Mount all shared file systems for this zone */
2505 ZFS_CLOSE(zone_zhp
);
2510 * Function: be_unmount_one_zone
2511 * Description: This function unmount one zone for a give global BE.
2513 * ud - be_unmount_data_t pointer to data for global BE
2514 * zonename - name of zone to unmount
2515 * zonepath - zonepath of the zone to unmount
2516 * zonepath_ds - dataset for the zonepath
2518 * BE_SUCCESS - Success
2519 * be_errno_t - Failure
2524 be_unmount_one_zone(be_unmount_data_t
*ud
, char *zonename
, char *zonepath
,
2527 be_unmount_data_t zone_ud
= { 0 };
2528 zfs_handle_t
*zone_zhp
= NULL
;
2529 char zone_altroot
[MAXPATHLEN
];
2530 char zoneroot
[MAXPATHLEN
];
2531 char zoneroot_ds
[MAXPATHLEN
];
2532 int ret
= BE_SUCCESS
;
2534 /* Generate string for zone's alternate root path */
2535 be_make_zoneroot(zonepath
, zoneroot
, sizeof (zoneroot
));
2536 (void) strlcpy(zone_altroot
, ud
->altroot
, sizeof (zone_altroot
));
2537 (void) strlcat(zone_altroot
, zoneroot
, sizeof (zone_altroot
));
2539 /* Build be_unmount_data for zone */
2540 zone_ud
.altroot
= zone_altroot
;
2541 zone_ud
.force
= ud
->force
;
2543 /* Find the mounted zone root dataset for this zone for this BE */
2544 if ((ret
= be_find_mounted_zone_root(zone_altroot
, zonepath_ds
,
2545 zoneroot_ds
, sizeof (zoneroot_ds
))) == BE_ERR_NO_MOUNTED_ZONE
) {
2546 be_print_err(gettext("be_unmount_one_zone: did not "
2547 "find any zone root mounted for zone %s\n"), zonename
);
2548 return (BE_SUCCESS
);
2549 } else if (ret
!= BE_SUCCESS
) {
2550 be_print_err(gettext("be_unmount_one_zone: failed to "
2551 "find mounted zone root for zone %s\n"), zonename
);
2555 /* Get handle to zoneroot dataset mounted for this BE */
2556 if ((zone_zhp
= zfs_open(g_zfs
, zoneroot_ds
, ZFS_TYPE_FILESYSTEM
))
2558 be_print_err(gettext("be_unmount_one_zone: failed to "
2559 "open mounted zone root dataset (%s): %s\n"), zoneroot_ds
,
2560 libzfs_error_description(g_zfs
));
2561 return (zfs_err_to_be_err(g_zfs
));
2564 /* TODO: Unmount all shared file systems for this zone */
2566 /* Iterate through zone's children filesystems and unmount them */
2567 if ((ret
= zfs_iter_filesystems(zone_zhp
, be_unmount_callback
,
2569 be_print_err(gettext("be_unmount_one_zone: failed to "
2570 "unmount zone subordinate file systems at %s\n"),
2575 /* Unmount the zone's root filesystem */
2576 if ((ret
= be_unmount_zone_root(zone_zhp
, &zone_ud
)) != BE_SUCCESS
) {
2577 be_print_err(gettext("be_unmount_one_zone: failed to "
2578 "unmount zone root file system at %s\n"), zone_altroot
);
2583 ZFS_CLOSE(zone_zhp
);
2588 * Function: be_get_ds_from_dir_callback
2589 * Description: This is a callback function used to iterate all datasets
2590 * to find the one that is currently mounted at the directory
2591 * being searched for. If matched, the name of the dataset is
2592 * returned in heap storage, so the caller is responsible for
2595 * zhp - zfs_handle_t pointer to current dataset being processed.
2596 * data - dir_data_t pointer providing name of directory being
2599 * 1 - This dataset is mounted at directory being searched for.
2600 * 0 - This dataset is not mounted at directory being searched for.
2605 be_get_ds_from_dir_callback(zfs_handle_t
*zhp
, void *data
)
2607 dir_data_t
*dd
= data
;
2611 if (zfs_get_type(zhp
) != ZFS_TYPE_FILESYSTEM
) {
2616 if (zfs_is_mounted(zhp
, &mp
) && mp
!= NULL
&&
2617 strcmp(mp
, dd
->dir
) == 0) {
2618 if ((dd
->ds
= strdup(zfs_get_name(zhp
))) == NULL
) {
2619 be_print_err(gettext("be_get_ds_from_dir_callback: "
2620 "memory allocation failed\n"));
2628 zret
= zfs_iter_filesystems(zhp
, be_get_ds_from_dir_callback
, dd
);
2636 * Function: mount_zfs
2637 * Description: This is a function to mount zfs filesystem to alternative
2638 * root without changing zfs mountpoint property. Logic is
2639 * similar to zfs_mount.
2641 * zhp - zfs_handle_t pointer to current dataset being processed.
2642 * altroot - char pointer to current alternative root.
2644 * BE_SUCCESS - Success
2645 * be_errno_t - Failure
2650 mount_zfs(zfs_handle_t
*zhp
, char *altroot
)
2653 char mountpoint
[MAXPATHLEN
];
2654 char real_mountpoint
[MAXPATHLEN
];
2655 char source
[MAXNAMELEN
];
2656 char optstr
[MAX_MNTOPT_STR
];
2657 zprop_source_t sourcetype
;
2662 /* Get dataset's mountpoint and source values */
2663 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
2664 sizeof (mountpoint
), &sourcetype
, source
, sizeof (source
),
2666 be_print_err(gettext("mount_zfs: "
2667 "failed to get mountpoint and sourcetype for %s\n"),
2670 return (BE_ERR_ZFS
);
2673 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0 ||
2674 strcmp(mountpoint
, "/") == 0) {
2676 * We are called only from be_mount_root or be_mount_callback
2677 * when mountpoint != LEGACY
2679 mountpoint
[0] = '\0';
2682 (void) snprintf(real_mountpoint
, MAXPATHLEN
, "%s%s", altroot
,
2685 if (zpool_get_prop_int(zfs_get_pool_handle(zhp
), ZPOOL_PROP_READONLY
,
2689 /* Create the directory if it doesn't already exist */
2690 if (lstat(real_mountpoint
, &buf
) != 0) {
2691 if (mkdirp(real_mountpoint
, 0755) != 0) {
2692 be_print_err(gettext("mount_zfs: "
2693 "failed to create mountpoint for %s\n"),
2696 return (BE_ERR_ZFS
);
2700 if (mount(zfs_get_name(zhp
), real_mountpoint
, MS_OPTIONSTR
| flags
,
2701 MNTTYPE_ZFS
, NULL
, 0, optstr
, sizeof (optstr
))) {
2702 be_print_err(gettext("mount_zfs: failed to "
2703 "mount dataset %s at %s\n"), zfs_get_name(zhp
),
2705 return (BE_ERR_ZFS
);
2708 return (BE_SUCCESS
);