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.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
35 #include <libnvpair.h>
40 #include <sys/mntent.h>
41 #include <sys/mnttab.h>
42 #include <sys/mount.h>
44 #include <sys/types.h>
45 #include <sys/vfstab.h>
47 #include <sys/mkdev.h>
51 #include <libbe_priv.h>
53 #define BE_TMP_MNTPNT "/tmp/.be.XXXXXX"
55 typedef struct dir_data
{
60 /* Private function prototypes */
61 static int be_mount_callback(zfs_handle_t
*, void *);
62 static int be_unmount_callback(zfs_handle_t
*, void *);
63 static int be_get_legacy_fs_callback(zfs_handle_t
*, void *);
64 static int fix_mountpoint(zfs_handle_t
*);
65 static int fix_mountpoint_callback(zfs_handle_t
*, void *);
66 static int get_mountpoint_from_vfstab(char *, const char *, char *, size_t,
68 static int loopback_mount_shared_fs(zfs_handle_t
*, be_mount_data_t
*);
69 static int loopback_mount_zonepath(const char *, be_mount_data_t
*);
70 static int iter_shared_fs_callback(zfs_handle_t
*, void *);
71 static int zpool_shared_fs_callback(zpool_handle_t
*, void *);
72 static int unmount_shared_fs(be_unmount_data_t
*);
73 static int add_to_fs_list(be_fs_list_data_t
*, const char *);
74 static int be_mount_root(zfs_handle_t
*, char *);
75 static int be_unmount_root(zfs_handle_t
*, be_unmount_data_t
*);
76 static int be_mount_zones(zfs_handle_t
*, be_mount_data_t
*);
77 static int be_unmount_zones(be_unmount_data_t
*);
78 static int be_mount_one_zone(zfs_handle_t
*, be_mount_data_t
*, char *, char *,
80 static int be_unmount_one_zone(be_unmount_data_t
*, char *, char *, char *);
81 static int be_get_ds_from_dir_callback(zfs_handle_t
*, void *);
84 /* ******************************************************************** */
85 /* Public Functions */
86 /* ******************************************************************** */
90 * Description: Mounts a BE and its subordinate datasets at a given mountpoint.
92 * be_attrs - pointer to nvlist_t of attributes being passed in.
93 * The following attributes are used by this function:
95 * BE_ATTR_ORIG_BE_NAME *required
96 * BE_ATTR_MOUNTPOINT *required
97 * BE_ATTR_MOUNT_FLAGS *optional
99 * BE_SUCCESS - Success
100 * be_errno_t - Failure
105 be_mount(nvlist_t
*be_attrs
)
107 char *be_name
= NULL
;
108 char *mountpoint
= NULL
;
110 int ret
= BE_SUCCESS
;
112 /* Initialize libzfs handle */
114 return (BE_ERR_INIT
);
116 /* Get original BE name */
117 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
119 be_print_err(gettext("be_mount: failed to lookup "
120 "BE_ATTR_ORIG_BE_NAME attribute\n"));
121 return (BE_ERR_INVAL
);
124 /* Validate original BE name */
125 if (!be_valid_be_name(be_name
)) {
126 be_print_err(gettext("be_mount: invalid BE name %s\n"),
128 return (BE_ERR_INVAL
);
132 if (nvlist_lookup_string(be_attrs
, BE_ATTR_MOUNTPOINT
, &mountpoint
)
134 be_print_err(gettext("be_mount: failed to lookup "
135 "BE_ATTR_MOUNTPOINT attribute\n"));
136 return (BE_ERR_INVAL
);
140 if (nvlist_lookup_pairs(be_attrs
, NV_FLAG_NOENTOK
,
141 BE_ATTR_MOUNT_FLAGS
, DATA_TYPE_UINT16
, &flags
, NULL
) != 0) {
142 be_print_err(gettext("be_mount: failed to lookup "
143 "BE_ATTR_MOUNT_FLAGS attribute\n"));
144 return (BE_ERR_INVAL
);
147 ret
= _be_mount(be_name
, &mountpoint
, flags
);
155 * Function: be_unmount
156 * Description: Unmounts a BE and its subordinate datasets.
158 * be_attrs - pointer to nvlist_t of attributes being passed in.
159 * The following attributes are used by this function:
161 * BE_ATTR_ORIG_BE_NAME *required
162 * BE_ATTR_UNMOUNT_FLAGS *optional
164 * BE_SUCCESS - Success
165 * be_errno_t - Failure
170 be_unmount(nvlist_t
*be_attrs
)
172 char *be_name
= NULL
;
173 char *be_name_mnt
= NULL
;
176 int ret
= BE_SUCCESS
;
178 /* Initialize libzfs handle */
180 return (BE_ERR_INIT
);
182 /* Get original BE name */
183 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
185 be_print_err(gettext("be_unmount: failed to lookup "
186 "BE_ATTR_ORIG_BE_NAME attribute\n"));
187 return (BE_ERR_INVAL
);
190 /* Check if we have mountpoint argument instead of BE name */
191 if (be_name
[0] == '/') {
192 if ((ds
= be_get_ds_from_dir(be_name
)) != NULL
) {
193 if ((be_name_mnt
= strrchr(ds
, '/')) != NULL
) {
195 be_name
= be_name_mnt
+ 1;
198 be_print_err(gettext("be_unmount: no datasets mounted "
199 "at '%s'\n"), be_name
);
200 return (BE_ERR_INVAL
);
204 /* Validate original BE name */
205 if (!be_valid_be_name(be_name
)) {
206 be_print_err(gettext("be_unmount: invalid BE name %s\n"),
208 return (BE_ERR_INVAL
);
211 /* Get unmount flags */
212 if (nvlist_lookup_pairs(be_attrs
, NV_FLAG_NOENTOK
,
213 BE_ATTR_UNMOUNT_FLAGS
, DATA_TYPE_UINT16
, &flags
, NULL
) != 0) {
214 be_print_err(gettext("be_unmount: failed to loookup "
215 "BE_ATTR_UNMOUNT_FLAGS attribute\n"));
216 return (BE_ERR_INVAL
);
219 ret
= _be_unmount(be_name
, flags
);
226 /* ******************************************************************** */
227 /* Semi-Private Functions */
228 /* ******************************************************************** */
231 * Function: _be_mount
232 * Description: Mounts a BE. If the altroot is not provided, this function
233 * will generate a temporary mountpoint to mount the BE at. It
234 * will return this temporary mountpoint to the caller via the
235 * altroot reference pointer passed in. This returned value is
236 * allocated on heap storage and is the repsonsibility of the
239 * be_name - pointer to name of BE to mount.
240 * altroot - reference pointer to altroot of where to mount BE.
241 * flags - flag indicating special handling for mounting the BE
243 * BE_SUCCESS - Success
244 * be_errno_t - Failure
246 * Semi-private (library wide use only)
249 _be_mount(char *be_name
, char **altroot
, int flags
)
251 be_transaction_data_t bt
= { 0 };
252 be_mount_data_t md
= { 0 };
254 char obe_root_ds
[MAXPATHLEN
];
256 char *tmp_altroot
= NULL
;
257 int ret
= BE_SUCCESS
, err
= 0;
259 boolean_t gen_tmp_altroot
= B_FALSE
;
261 if (be_name
== NULL
|| altroot
== NULL
)
262 return (BE_ERR_INVAL
);
264 /* Set be_name as obe_name in bt structure */
265 bt
.obe_name
= be_name
;
267 /* Find which zpool obe_name lives in */
268 if ((err
= zpool_iter(g_zfs
, be_find_zpool_callback
, &bt
)) == 0) {
269 be_print_err(gettext("be_mount: failed to "
270 "find zpool for BE (%s)\n"), bt
.obe_name
);
271 return (BE_ERR_BE_NOENT
);
272 } else if (err
< 0) {
273 be_print_err(gettext("be_mount: zpool_iter failed: %s\n"),
274 libzfs_error_description(g_zfs
));
275 return (zfs_err_to_be_err(g_zfs
));
278 /* Generate string for obe_name's root dataset */
279 be_make_root_ds(bt
.obe_zpool
, bt
.obe_name
, obe_root_ds
,
280 sizeof (obe_root_ds
));
281 bt
.obe_root_ds
= obe_root_ds
;
283 /* Get handle to BE's root dataset */
284 if ((zhp
= zfs_open(g_zfs
, bt
.obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
286 be_print_err(gettext("be_mount: failed to "
287 "open BE root dataset (%s): %s\n"), bt
.obe_root_ds
,
288 libzfs_error_description(g_zfs
));
289 return (zfs_err_to_be_err(g_zfs
));
292 /* Make sure BE's root dataset isn't already mounted somewhere */
293 if (zfs_is_mounted(zhp
, &mp
)) {
295 be_print_err(gettext("be_mount: %s is already mounted "
296 "at %s\n"), bt
.obe_name
, mp
!= NULL
? mp
: "");
298 return (BE_ERR_MOUNTED
);
302 * Fix this BE's mountpoint if its root dataset isn't set to
303 * either 'legacy' or '/'.
305 if ((ret
= fix_mountpoint(zhp
)) != BE_SUCCESS
) {
306 be_print_err(gettext("be_mount: mountpoint check "
307 "failed for %s\n"), bt
.obe_root_ds
);
313 * If altroot not provided, create a temporary alternate root
316 if (*altroot
== NULL
) {
317 if ((ret
= be_make_tmp_mountpoint(&tmp_altroot
))
319 be_print_err(gettext("be_mount: failed to "
320 "make temporary mountpoint\n"));
324 gen_tmp_altroot
= B_TRUE
;
326 tmp_altroot
= *altroot
;
329 /* Mount the BE's root file system */
330 if ((ret
= be_mount_root(zhp
, tmp_altroot
)) != BE_SUCCESS
) {
331 be_print_err(gettext("be_mount: failed to "
332 "mount BE root file system\n"));
339 /* Iterate through BE's children filesystems */
340 if ((err
= zfs_iter_filesystems(zhp
, be_mount_callback
,
341 tmp_altroot
)) != 0) {
342 be_print_err(gettext("be_mount: failed to "
343 "mount BE (%s) on %s\n"), bt
.obe_name
, tmp_altroot
);
350 md
.altroot
= tmp_altroot
;
351 md
.shared_fs
= flags
& BE_MOUNT_FLAG_SHARED_FS
;
352 md
.shared_rw
= flags
& BE_MOUNT_FLAG_SHARED_RW
;
355 * Mount shared file systems if mount flag says so.
359 * Mount all ZFS file systems not under the BE's root dataset
361 (void) zpool_iter(g_zfs
, zpool_shared_fs_callback
, &md
);
363 /* TODO: Mount all non-ZFS file systems - Not supported yet */
367 * If we're in the global zone and the global zone has a valid uuid,
368 * mount all supported non-global zones.
370 if (getzoneid() == GLOBAL_ZONEID
&&
371 !(flags
& BE_MOUNT_FLAG_NO_ZONES
) &&
372 be_get_uuid(bt
.obe_root_ds
, &uu
) == BE_SUCCESS
) {
373 if ((ret
= be_mount_zones(zhp
, &md
)) != BE_SUCCESS
) {
374 (void) _be_unmount(bt
.obe_name
, 0);
385 * If a NULL altroot was passed in, pass the generated altroot
386 * back to the caller in altroot.
389 *altroot
= tmp_altroot
;
395 * Function: _be_unmount
396 * Description: Unmount a BE.
398 * be_name - pointer to name of BE to unmount.
399 * flags - flags for unmounting the BE.
401 * BE_SUCCESS - Success
402 * be_errno_t - Failure
404 * Semi-private (library wide use only)
407 _be_unmount(char *be_name
, int flags
)
409 be_transaction_data_t bt
= { 0 };
410 be_unmount_data_t ud
= { 0 };
413 char obe_root_ds
[MAXPATHLEN
];
414 char mountpoint
[MAXPATHLEN
];
416 int ret
= BE_SUCCESS
;
420 return (BE_ERR_INVAL
);
422 /* Set be_name as obe_name in bt structure */
423 bt
.obe_name
= be_name
;
425 /* Find which zpool obe_name lives in */
426 if ((zret
= zpool_iter(g_zfs
, be_find_zpool_callback
, &bt
)) == 0) {
427 be_print_err(gettext("be_unmount: failed to "
428 "find zpool for BE (%s)\n"), bt
.obe_name
);
429 return (BE_ERR_BE_NOENT
);
430 } else if (zret
< 0) {
431 be_print_err(gettext("be_unmount: "
432 "zpool_iter failed: %s\n"),
433 libzfs_error_description(g_zfs
));
434 ret
= zfs_err_to_be_err(g_zfs
);
438 /* Generate string for obe_name's root dataset */
439 be_make_root_ds(bt
.obe_zpool
, bt
.obe_name
, obe_root_ds
,
440 sizeof (obe_root_ds
));
441 bt
.obe_root_ds
= obe_root_ds
;
443 /* Get handle to BE's root dataset */
444 if ((zhp
= zfs_open(g_zfs
, bt
.obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
446 be_print_err(gettext("be_unmount: failed to "
447 "open BE root dataset (%s): %s\n"), bt
.obe_root_ds
,
448 libzfs_error_description(g_zfs
));
449 ret
= zfs_err_to_be_err(g_zfs
);
453 /* Make sure BE's root dataset is mounted somewhere */
454 if (!zfs_is_mounted(zhp
, &mp
)) {
456 be_print_err(gettext("be_unmount: "
457 "(%s) not mounted\n"), bt
.obe_name
);
460 * BE is not mounted, fix this BE's mountpoint if its root
461 * dataset isn't set to either 'legacy' or '/'.
463 if ((ret
= fix_mountpoint(zhp
)) != BE_SUCCESS
) {
464 be_print_err(gettext("be_unmount: mountpoint check "
465 "failed for %s\n"), bt
.obe_root_ds
);
471 return (BE_ERR_NOTMOUNTED
);
475 * If we didn't get a mountpoint from the zfs_is_mounted call,
476 * try and get it from its property.
479 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
480 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
481 be_print_err(gettext("be_unmount: failed to "
482 "get mountpoint of (%s)\n"), bt
.obe_name
);
487 (void) strlcpy(mountpoint
, mp
, sizeof (mountpoint
));
491 /* If BE mounted as current root, fail */
492 if (strcmp(mountpoint
, "/") == 0) {
493 be_print_err(gettext("be_unmount: "
494 "cannot unmount currently running BE\n"));
496 return (BE_ERR_UMOUNT_CURR_BE
);
499 ud
.altroot
= mountpoint
;
500 ud
.force
= flags
& BE_UNMOUNT_FLAG_FORCE
;
502 /* Unmount all supported non-global zones if we're in the global zone */
503 if (getzoneid() == GLOBAL_ZONEID
&&
504 be_get_uuid(bt
.obe_root_ds
, &uu
) == BE_SUCCESS
) {
505 if ((ret
= be_unmount_zones(&ud
)) != BE_SUCCESS
) {
511 /* TODO: Unmount all non-ZFS file systems - Not supported yet */
513 /* Unmount all ZFS file systems not under the BE root dataset */
514 if ((ret
= unmount_shared_fs(&ud
)) != BE_SUCCESS
) {
515 be_print_err(gettext("be_unmount: failed to "
516 "unmount shared file systems\n"));
521 /* Unmount all children datasets under the BE's root dataset */
522 if ((zret
= zfs_iter_filesystems(zhp
, be_unmount_callback
,
524 be_print_err(gettext("be_unmount: failed to "
525 "unmount BE (%s)\n"), bt
.obe_name
);
530 /* Unmount this BE's root filesystem */
531 if ((ret
= be_unmount_root(zhp
, &ud
)) != BE_SUCCESS
) {
542 * Function: be_mount_zone_root
543 * Description: Mounts the zone root dataset for a zone.
545 * zfs - zfs_handle_t pointer to zone root dataset
546 * md - be_mount_data_t pointer to data for zone to be mounted
548 * BE_SUCCESS - Success
549 * be_errno_t - Failure
551 * Semi-private (library wide use only)
554 be_mount_zone_root(zfs_handle_t
*zhp
, be_mount_data_t
*md
)
556 char mountpoint
[MAXPATHLEN
];
559 /* Get mountpoint property of dataset */
560 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
561 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
562 be_print_err(gettext("be_mount_zone_root: failed to "
563 "get mountpoint property for %s: %s\n"), zfs_get_name(zhp
),
564 libzfs_error_description(g_zfs
));
565 return (zfs_err_to_be_err(g_zfs
));
569 * Make sure zone's root dataset is set to 'legacy'. This is
570 * currently a requirement in this implementation of zones
573 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) != 0) {
574 be_print_err(gettext("be_mount_zone_root: "
575 "zone root dataset mountpoint is not 'legacy'\n"));
576 return (BE_ERR_ZONE_ROOT_NOT_LEGACY
);
580 * Legacy mount the zone root dataset.
582 * As a workaround for 6176743, we mount the zone's root with the
583 * MS_OVERLAY option in case an alternate BE is mounted, and we're
584 * mounting the root for the zone from the current BE here. When an
585 * alternate BE is mounted, it ties up the zone's zoneroot directory
586 * for the current BE since the zone's zonepath is loopback mounted
587 * from the current BE.
589 * TODO: The MS_OVERLAY option needs to be removed when 6176743
592 if (mount(zfs_get_name(zhp
), md
->altroot
, MS_OVERLAY
, MNTTYPE_ZFS
,
593 NULL
, 0, NULL
, 0) != 0) {
595 be_print_err(gettext("be_mount_zone_root: failed to "
596 "legacy mount zone root dataset (%s) at %s\n"),
597 zfs_get_name(zhp
), md
->altroot
);
598 return (errno_to_be_err(err
));
605 * Function: be_unmount_zone_root
606 * Description: Unmounts the zone root dataset for a zone.
608 * zhp - zfs_handle_t pointer to zone root dataset
609 * ud - be_unmount_data_t pointer to data for zone to be unmounted
611 * BE_SUCCESS - Success
612 * be_errno_t - Failure
614 * Semi-private (library wise use only)
617 be_unmount_zone_root(zfs_handle_t
*zhp
, be_unmount_data_t
*ud
)
619 char mountpoint
[MAXPATHLEN
];
621 /* Unmount the dataset */
622 if (zfs_unmount(zhp
, NULL
, ud
->force
? MS_FORCE
: 0) != 0) {
623 be_print_err(gettext("be_unmount_zone_root: failed to "
624 "unmount zone root dataset %s: %s\n"), zfs_get_name(zhp
),
625 libzfs_error_description(g_zfs
));
626 return (zfs_err_to_be_err(g_zfs
));
629 /* Get the current mountpoint property for the zone root dataset */
630 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
631 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
632 be_print_err(gettext("be_unmount_zone_root: failed to "
633 "get mountpoint property for zone root dataset (%s): %s\n"),
634 zfs_get_name(zhp
), libzfs_error_description(g_zfs
));
635 return (zfs_err_to_be_err(g_zfs
));
638 /* If mountpoint not already set to 'legacy', set it to 'legacy' */
639 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) != 0) {
640 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
641 ZFS_MOUNTPOINT_LEGACY
) != 0) {
642 be_print_err(gettext("be_unmount_zone_root: "
643 "failed to set mountpoint of zone root dataset "
644 "%s to 'legacy': %s\n"), zfs_get_name(zhp
),
645 libzfs_error_description(g_zfs
));
646 return (zfs_err_to_be_err(g_zfs
));
654 * Function: be_get_legacy_fs
655 * Description: This function iterates through all non-shared file systems
656 * of a BE and finds the ones with a legacy mountpoint. For
657 * those file systems, it reads the BE's vfstab to get the
658 * mountpoint. If found, it adds that file system to the
659 * be_fs_list_data_t passed in.
661 * This function can be used to gather legacy mounted file systems
662 * for both global BEs and non-global zone BEs. To get data for
663 * a non-global zone BE, the zoneroot_ds and zoneroot parameters
664 * will be specified, otherwise they should be set to NULL.
666 * be_name - global BE name from which to get legacy file
668 * be_root_ds - root dataset of global BE.
669 * zoneroot_ds - root dataset of zone.
670 * zoneroot - zoneroot path of zone.
671 * fld - be_fs_list_data_t pointer.
673 * BE_SUCCESS - Success
674 * be_errno_t - Failure
676 * Semi-private (library wide use only)
679 be_get_legacy_fs(char *be_name
, char *be_root_ds
, char *zoneroot_ds
,
680 char *zoneroot
, be_fs_list_data_t
*fld
)
682 zfs_handle_t
*zhp
= NULL
;
683 char mountpoint
[MAXPATHLEN
];
684 boolean_t mounted_here
= B_FALSE
;
685 boolean_t zone_mounted_here
= B_FALSE
;
686 int ret
= BE_SUCCESS
, err
= 0;
688 if (be_name
== NULL
|| be_root_ds
== NULL
|| fld
== NULL
)
689 return (BE_ERR_INVAL
);
691 /* Get handle to BE's root dataset */
692 if ((zhp
= zfs_open(g_zfs
, be_root_ds
, ZFS_TYPE_FILESYSTEM
))
694 be_print_err(gettext("be_get_legacy_fs: failed to "
695 "open BE root dataset (%s): %s\n"), be_root_ds
,
696 libzfs_error_description(g_zfs
));
697 ret
= zfs_err_to_be_err(g_zfs
);
701 /* If BE is not already mounted, mount it. */
702 if (!zfs_is_mounted(zhp
, &fld
->altroot
)) {
703 if ((ret
= _be_mount(be_name
, &fld
->altroot
,
704 zoneroot_ds
? BE_MOUNT_FLAG_NULL
:
705 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
706 be_print_err(gettext("be_get_legacy_fs: "
707 "failed to mount BE %s\n"), be_name
);
711 mounted_here
= B_TRUE
;
712 } else if (fld
->altroot
== NULL
) {
713 be_print_err(gettext("be_get_legacy_fs: failed to "
714 "get altroot of mounted BE %s: %s\n"),
715 be_name
, libzfs_error_description(g_zfs
));
716 ret
= zfs_err_to_be_err(g_zfs
);
721 * If a zone root dataset was passed in, we're wanting to get
722 * legacy mounted file systems for that zone, not the global
725 if (zoneroot_ds
!= NULL
) {
726 be_mount_data_t zone_md
= { 0 };
728 /* Close off handle to global BE's root dataset */
731 /* Get handle to zone's root dataset */
732 if ((zhp
= zfs_open(g_zfs
, zoneroot_ds
,
733 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
734 be_print_err(gettext("be_get_legacy_fs: failed to "
735 "open zone BE root dataset (%s): %s\n"),
736 zoneroot_ds
, libzfs_error_description(g_zfs
));
737 ret
= zfs_err_to_be_err(g_zfs
);
741 /* Make sure the zone we're looking for is mounted */
742 if (!zfs_is_mounted(zhp
, &zone_md
.altroot
)) {
743 char zone_altroot
[MAXPATHLEN
];
745 /* Generate alternate root path for zone */
746 (void) snprintf(zone_altroot
, sizeof (zone_altroot
),
747 "%s%s", fld
->altroot
, zoneroot
);
748 if ((zone_md
.altroot
= strdup(zone_altroot
)) == NULL
) {
749 be_print_err(gettext("be_get_legacy_fs: "
750 "memory allocation failed\n"));
755 if ((ret
= be_mount_zone_root(zhp
, &zone_md
))
757 be_print_err(gettext("be_get_legacy_fs: "
758 "failed to mount zone root %s\n"),
760 free(zone_md
.altroot
);
761 zone_md
.altroot
= NULL
;
764 zone_mounted_here
= B_TRUE
;
768 fld
->altroot
= zone_md
.altroot
;
772 * If the root dataset is in the vfstab with a mountpoint of "/",
775 if (get_mountpoint_from_vfstab(fld
->altroot
, zfs_get_name(zhp
),
776 mountpoint
, sizeof (mountpoint
), B_FALSE
) == BE_SUCCESS
) {
777 if (strcmp(mountpoint
, "/") == 0) {
778 if (add_to_fs_list(fld
, zfs_get_name(zhp
))
780 be_print_err(gettext("be_get_legacy_fs: "
781 "failed to add %s to fs list\n"),
789 /* Iterate subordinate file systems looking for legacy mounts */
790 if ((ret
= zfs_iter_filesystems(zhp
, be_get_legacy_fs_callback
,
792 be_print_err(gettext("be_get_legacy_fs: "
793 "failed to iterate %s to get legacy mounts\n"),
798 /* If we mounted the zone BE, unmount it */
799 if (zone_mounted_here
) {
800 be_unmount_data_t zone_ud
= { 0 };
802 zone_ud
.altroot
= fld
->altroot
;
803 zone_ud
.force
= B_TRUE
;
804 if ((err
= be_unmount_zone_root(zhp
, &zone_ud
)) != BE_SUCCESS
) {
805 be_print_err(gettext("be_get_legacy_fs: "
806 "failed to unmount zone root %s\n"),
808 if (ret
== BE_SUCCESS
)
813 /* If we mounted this BE, unmount it */
815 if ((err
= _be_unmount(be_name
, 0)) != BE_SUCCESS
) {
816 be_print_err(gettext("be_get_legacy_fs: "
817 "failed to unmount %s\n"), be_name
);
818 if (ret
== BE_SUCCESS
)
832 * Function: be_free_fs_list
833 * Description: Function used to free the members of a be_fs_list_data_t
836 * fld - be_fs_list_data_t pointer to free.
840 * Semi-private (library wide use only)
843 be_free_fs_list(be_fs_list_data_t
*fld
)
852 if (fld
->fs_list
== NULL
)
855 for (i
= 0; i
< fld
->fs_num
; i
++)
856 free(fld
->fs_list
[i
]);
862 * Function: be_get_ds_from_dir(char *dir)
863 * Description: Given a directory path, find the underlying dataset mounted
864 * at that directory path if there is one. The returned name
865 * is allocated in heap storage, so the caller is responsible
868 * dir - char pointer of directory to find.
870 * NULL - if directory is not mounted from a dataset.
871 * name of dataset mounted at dir.
873 * Semi-private (library wide use only)
876 be_get_ds_from_dir(char *dir
)
878 dir_data_t dd
= { 0 };
879 char resolved_dir
[MAXPATHLEN
];
881 /* Make sure length of dir is within the max length */
882 if (dir
== NULL
|| strlen(dir
) >= MAXPATHLEN
)
885 /* Resolve dir in case its lofs mounted */
886 (void) strlcpy(resolved_dir
, dir
, sizeof (resolved_dir
));
887 z_resolve_lofs(resolved_dir
, sizeof (resolved_dir
));
889 dd
.dir
= resolved_dir
;
891 (void) zfs_iter_root(g_zfs
, be_get_ds_from_dir_callback
, &dd
);
897 * Function: be_make_tmp_mountpoint
898 * Description: This function generates a random temporary mountpoint
899 * and creates that mountpoint directory. It returns the
900 * mountpoint in heap storage, so the caller is responsible
903 * tmp_mp - reference to pointer of where to store generated
904 * temporary mountpoint.
906 * BE_SUCCESS - Success
907 * be_errno_t - Failure
909 * Semi-private (library wide use only)
912 be_make_tmp_mountpoint(char **tmp_mp
)
916 if ((*tmp_mp
= (char *)calloc(1, sizeof (BE_TMP_MNTPNT
) + 1)) == NULL
) {
917 be_print_err(gettext("be_make_tmp_mountpoint: "
919 return (BE_ERR_NOMEM
);
921 (void) strlcpy(*tmp_mp
, BE_TMP_MNTPNT
, sizeof (BE_TMP_MNTPNT
) + 1);
922 if (mkdtemp(*tmp_mp
) == NULL
) {
924 be_print_err(gettext("be_make_tmp_mountpoint: mkdtemp() failed "
925 "for %s: %s\n"), *tmp_mp
, strerror(err
));
928 return (errno_to_be_err(err
));
935 * Function: be_mount_pool
936 * Description: This function determines if the pool's datase is mounted
937 * and if not it is used to mount the pool's dataset. The
938 * function returns the current mountpoint if we are able
939 * to mount the dataset.
941 * zhp - handle to the pool's dataset
942 * tmp_mntpnt - The temporary mountpoint that the pool's
943 * dataset is mounted on. This is set only
944 * if the attempt to mount the dataset at it's
945 * set mountpoint fails, and we've used a
946 * temporary mount point for this dataset. It
947 * is expected that the caller will free this
949 * orig_mntpnt - The original mountpoint for the pool. If a
950 * temporary mount point was needed this will
951 * be used to reset the mountpoint property to
952 * it's original mountpoint. It is expected that
953 * the caller will free this memory.
954 * pool_mounted - This flag indicates that the pool was mounted
957 * BE_SUCCESS - Success
958 * be_errno_t - Failure
960 * Semi-private (library wide use only)
967 boolean_t
*pool_mounted
)
970 char mountpoint
[MAXPATHLEN
];
975 *pool_mounted
= B_FALSE
;
977 if (!zfs_is_mounted(zhp
, NULL
)) {
978 if (zfs_mount(zhp
, NULL
, 0) != 0) {
979 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
980 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
981 be_print_err(gettext("be_mount_pool: failed to "
982 "get mountpoint of (%s): %s\n"),
984 libzfs_error_description(g_zfs
));
985 return (zfs_err_to_be_err(g_zfs
));
987 if ((*orig_mntpnt
= strdup(mountpoint
)) == NULL
) {
988 be_print_err(gettext("be_mount_pool: memory "
989 "allocation failed\n"));
990 return (BE_ERR_NOMEM
);
993 * attempt to mount on a temp mountpoint
995 if ((ret
= be_make_tmp_mountpoint(tmp_mntpnt
))
997 be_print_err(gettext("be_mount_pool: failed "
998 "to make temporary mountpoint\n"));
1000 *orig_mntpnt
= NULL
;
1004 if (zfs_prop_set(zhp
,
1005 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1006 *tmp_mntpnt
) != 0) {
1007 be_print_err(gettext("be_mount_pool: failed "
1008 "to set mountpoint of pool dataset %s to "
1009 "%s: %s\n"), zfs_get_name(zhp
),
1011 libzfs_error_description(g_zfs
));
1014 *orig_mntpnt
= NULL
;
1016 return (zfs_err_to_be_err(g_zfs
));
1019 if (zfs_mount(zhp
, NULL
, 0) != 0) {
1020 be_print_err(gettext("be_mount_pool: failed "
1021 "to mount dataset %s at %s: %s\n"),
1022 zfs_get_name(zhp
), *tmp_mntpnt
,
1023 libzfs_error_description(g_zfs
));
1024 ret
= zfs_err_to_be_err(g_zfs
);
1025 if (zfs_prop_set(zhp
,
1026 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1028 be_print_err(gettext("be_mount_pool: "
1029 "failed to set mountpoint of pool "
1030 "dataset %s to %s: %s\n"),
1031 zfs_get_name(zhp
), *tmp_mntpnt
,
1032 libzfs_error_description(g_zfs
));
1036 *orig_mntpnt
= NULL
;
1041 *pool_mounted
= B_TRUE
;
1044 return (BE_SUCCESS
);
1048 * Function: be_unmount_pool
1049 * Description: This function is used to unmount the pool's dataset if we
1050 * mounted it previously using be_mount_pool().
1052 * zhp - handle to the pool's dataset
1053 * tmp_mntpnt - If a temprary mount point was used this will
1054 * be set. Since this was created in be_mount_pool
1055 * we will need to clean it up here.
1056 * orig_mntpnt - The original mountpoint for the pool. This is
1057 * used to set the dataset mountpoint property
1058 * back to it's original value in the case where a
1059 * temporary mountpoint was used.
1061 * BE_SUCCESS - Success
1062 * be_errno_t - Failure
1064 * Semi-private (library wide use only)
1072 if (zfs_unmount(zhp
, NULL
, 0) != 0) {
1073 be_print_err(gettext("be_unmount_pool: failed to "
1074 "unmount pool (%s): %s\n"), zfs_get_name(zhp
),
1075 libzfs_error_description(g_zfs
));
1076 return (zfs_err_to_be_err(g_zfs
));
1078 if (orig_mntpnt
!= NULL
) {
1079 if (tmp_mntpnt
!= NULL
&&
1080 strcmp(orig_mntpnt
, tmp_mntpnt
) != 0) {
1081 (void) rmdir(tmp_mntpnt
);
1083 if (zfs_prop_set(zhp
,
1084 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1085 orig_mntpnt
) != 0) {
1086 be_print_err(gettext("be_unmount_pool: failed "
1087 "to set the mountpoint for dataset (%s) to "
1088 "%s: %s\n"), zfs_get_name(zhp
), orig_mntpnt
,
1089 libzfs_error_description(g_zfs
));
1090 return (zfs_err_to_be_err(g_zfs
));
1094 return (BE_SUCCESS
);
1097 /* ******************************************************************** */
1098 /* Private Functions */
1099 /* ******************************************************************** */
1102 * Function: be_mount_callback
1103 * Description: Callback function used to iterate through all of a BE's
1104 * subordinate file systems and to mount them accordingly.
1106 * zhp - zfs_handle_t pointer to current file system being
1108 * data - pointer to the altroot of where to mount BE.
1111 * be_errno_t - Failure
1116 be_mount_callback(zfs_handle_t
*zhp
, void *data
)
1118 zprop_source_t sourcetype
;
1119 const char *fs_name
= zfs_get_name(zhp
);
1120 char source
[ZFS_MAXNAMELEN
];
1121 char *altroot
= data
;
1122 char zhp_mountpoint
[MAXPATHLEN
];
1123 char mountpoint
[MAXPATHLEN
];
1126 /* Get dataset's mountpoint and source values */
1127 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, zhp_mountpoint
,
1128 sizeof (zhp_mountpoint
), &sourcetype
, source
, sizeof (source
),
1130 be_print_err(gettext("be_mount_callback: failed to "
1131 "get mountpoint and sourcetype for %s\n"),
1134 return (BE_ERR_ZFS
);
1138 * Set this filesystem's 'canmount' property to 'noauto' just incase
1139 * it's been set 'on'. We do this so that when we change its
1140 * mountpoint zfs won't immediately try to mount it.
1142 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")) {
1143 be_print_err(gettext("be_mount_callback: failed to "
1144 "set canmount to 'noauto' (%s)\n"), fs_name
);
1146 return (BE_ERR_ZFS
);
1150 * If the mountpoint is none, there's nothing to do, goto next.
1151 * If the mountpoint is legacy, legacy mount it with mount(2).
1152 * If the mountpoint is inherited, its mountpoint should
1153 * already be set. If it's not, then explicitly fix-up
1154 * the mountpoint now by appending its explicitly set
1155 * mountpoint value to the BE mountpoint.
1157 if (strcmp(zhp_mountpoint
, ZFS_MOUNTPOINT_NONE
) == 0) {
1159 } else if (strcmp(zhp_mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1161 * If the mountpoint is set to 'legacy', we need to
1162 * dig into this BE's vfstab to figure out where to
1163 * mount it, and just mount it via mount(2).
1165 if (get_mountpoint_from_vfstab(altroot
, fs_name
,
1166 mountpoint
, sizeof (mountpoint
), B_TRUE
) == BE_SUCCESS
) {
1168 /* Legacy mount the file system */
1169 if (mount(fs_name
, mountpoint
, MS_DATA
,
1170 MNTTYPE_ZFS
, NULL
, 0, NULL
, 0) != 0) {
1172 gettext("be_mount_callback: "
1173 "failed to mount %s on %s\n"),
1174 fs_name
, mountpoint
);
1178 gettext("be_mount_callback: "
1179 "no entry for %s in vfstab, "
1180 "skipping ...\n"), fs_name
);
1185 } else if (sourcetype
& ZPROP_SRC_INHERITED
) {
1187 * If the mountpoint is inherited, its parent should have
1188 * already been processed so its current mountpoint value
1189 * is what its mountpoint ought to be.
1191 (void) strlcpy(mountpoint
, zhp_mountpoint
, sizeof (mountpoint
));
1192 } else if (sourcetype
& ZPROP_SRC_LOCAL
) {
1194 * Else process dataset with explicitly set mountpoint.
1196 (void) snprintf(mountpoint
, sizeof (mountpoint
),
1197 "%s%s", altroot
, zhp_mountpoint
);
1199 /* Set the new mountpoint for the dataset */
1200 if (zfs_prop_set(zhp
,
1201 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1203 be_print_err(gettext("be_mount_callback: "
1204 "failed to set mountpoint for %s to "
1205 "%s\n"), fs_name
, mountpoint
);
1207 return (BE_ERR_ZFS
);
1210 be_print_err(gettext("be_mount_callback: "
1211 "mountpoint sourcetype of %s is %d, skipping ...\n"),
1212 fs_name
, sourcetype
);
1217 /* Mount this filesystem */
1218 if (zfs_mount(zhp
, NULL
, 0) != 0) {
1219 be_print_err(gettext("be_mount_callback: failed to "
1220 "mount dataset %s at %s: %s\n"), fs_name
, mountpoint
,
1221 libzfs_error_description(g_zfs
));
1223 * Set this filesystem's 'mountpoint' property back to what
1226 if (sourcetype
& ZPROP_SRC_LOCAL
&&
1227 strcmp(zhp_mountpoint
, ZFS_MOUNTPOINT_LEGACY
) != 0) {
1228 (void) zfs_prop_set(zhp
,
1229 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1234 return (BE_ERR_MOUNT
);
1238 /* Iterate through this dataset's children and mount them */
1239 if ((ret
= zfs_iter_filesystems(zhp
, be_mount_callback
,
1251 * Function: be_unmount_callback
1252 * Description: Callback function used to iterate through all of a BE's
1253 * subordinate file systems and to unmount them.
1255 * zhp - zfs_handle_t pointer to current file system being
1257 * data - pointer to the mountpoint of where BE is mounted.
1260 * be_errno_t - Failure
1265 be_unmount_callback(zfs_handle_t
*zhp
, void *data
)
1267 be_unmount_data_t
*ud
= data
;
1268 zprop_source_t sourcetype
;
1269 const char *fs_name
= zfs_get_name(zhp
);
1270 char source
[ZFS_MAXNAMELEN
];
1271 char mountpoint
[MAXPATHLEN
];
1272 char *zhp_mountpoint
;
1275 /* Iterate down this dataset's children first */
1276 if (zfs_iter_filesystems(zhp
, be_unmount_callback
, ud
)) {
1277 ret
= BE_ERR_UMOUNT
;
1281 /* Is dataset even mounted ? */
1282 if (!zfs_is_mounted(zhp
, NULL
))
1285 /* Unmount this file system */
1286 if (zfs_unmount(zhp
, NULL
, ud
->force
? MS_FORCE
: 0) != 0) {
1287 be_print_err(gettext("be_unmount_callback: "
1288 "failed to unmount %s: %s\n"), fs_name
,
1289 libzfs_error_description(g_zfs
));
1290 ret
= zfs_err_to_be_err(g_zfs
);
1294 /* Get dataset's current mountpoint and source value */
1295 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
1296 sizeof (mountpoint
), &sourcetype
, source
, sizeof (source
),
1298 be_print_err(gettext("be_unmount_callback: "
1299 "failed to get mountpoint and sourcetype for %s: %s\n"),
1300 fs_name
, libzfs_error_description(g_zfs
));
1301 ret
= zfs_err_to_be_err(g_zfs
);
1305 if (sourcetype
& ZPROP_SRC_INHERITED
) {
1307 * If the mountpoint is inherited we don't need to
1308 * do anything. When its parent gets processed
1309 * its mountpoint will be set accordingly.
1312 } else if (sourcetype
& ZPROP_SRC_LOCAL
) {
1314 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1316 * If the mountpoint is set to 'legacy', its already
1317 * been unmounted (from above call to zfs_unmount), and
1318 * we don't need to do anything else with it.
1324 * Else process dataset with explicitly set mountpoint.
1328 * Get this dataset's mountpoint relative to
1329 * the BE's mountpoint.
1331 if ((strncmp(mountpoint
, ud
->altroot
,
1332 strlen(ud
->altroot
)) == 0) &&
1333 (mountpoint
[strlen(ud
->altroot
)] == '/')) {
1335 zhp_mountpoint
= mountpoint
+
1336 strlen(ud
->altroot
);
1338 /* Set this dataset's mountpoint value */
1339 if (zfs_prop_set(zhp
,
1340 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
1343 gettext("be_unmount_callback: "
1344 "failed to set mountpoint for "
1345 "%s to %s: %s\n"), fs_name
,
1347 libzfs_error_description(g_zfs
));
1348 ret
= zfs_err_to_be_err(g_zfs
);
1352 gettext("be_unmount_callback: "
1353 "%s not mounted under BE's altroot %s, "
1354 "skipping ...\n"), fs_name
, ud
->altroot
);
1356 * fs_name is mounted but not under the
1359 ret
= BE_ERR_INVALMOUNTPOINT
;
1363 be_print_err(gettext("be_unmount_callback: "
1364 "mountpoint sourcetype of %s is %d, skipping ...\n"),
1365 fs_name
, sourcetype
);
1370 /* Set this filesystem's 'canmount' property to 'noauto' */
1371 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")) {
1372 be_print_err(gettext("be_unmount_callback: "
1373 "failed to set canmount to 'noauto' (%s)\n"), fs_name
);
1383 * Function: be_get_legacy_fs_callback
1384 * Description: The callback function is used to iterate through all
1385 * non-shared file systems of a BE, finding ones that have
1386 * a legacy mountpoint and an entry in the BE's vfstab.
1387 * It adds these file systems to the callback data.
1389 * zhp - zfs_handle_t pointer to current file system being
1391 * data - be_fs_list_data_t pointer
1394 * be_errno_t - Failure
1399 be_get_legacy_fs_callback(zfs_handle_t
*zhp
, void *data
)
1401 be_fs_list_data_t
*fld
= data
;
1402 const char *fs_name
= zfs_get_name(zhp
);
1403 char zhp_mountpoint
[MAXPATHLEN
];
1404 char mountpoint
[MAXPATHLEN
];
1407 /* Get this dataset's mountpoint property */
1408 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, zhp_mountpoint
,
1409 sizeof (zhp_mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
1410 be_print_err(gettext("be_get_legacy_fs_callback: "
1411 "failed to get mountpoint for %s: %s\n"),
1412 fs_name
, libzfs_error_description(g_zfs
));
1413 ret
= zfs_err_to_be_err(g_zfs
);
1419 * If mountpoint is legacy, try to get its mountpoint from this BE's
1420 * vfstab. If it exists in the vfstab, add this file system to the
1423 if (strcmp(zhp_mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1424 if (get_mountpoint_from_vfstab(fld
->altroot
, fs_name
,
1425 mountpoint
, sizeof (mountpoint
), B_FALSE
) != BE_SUCCESS
) {
1426 be_print_err(gettext("be_get_legacy_fs_callback: "
1427 "no entry for %s in vfstab, "
1428 "skipping ...\n"), fs_name
);
1433 /* Record file system into the callback data. */
1434 if (add_to_fs_list(fld
, zfs_get_name(zhp
)) != BE_SUCCESS
) {
1435 be_print_err(gettext("be_get_legacy_fs_callback: "
1436 "failed to add %s to fs list\n"), mountpoint
);
1438 return (BE_ERR_NOMEM
);
1443 /* Iterate through this dataset's children file systems */
1444 if ((ret
= zfs_iter_filesystems(zhp
, be_get_legacy_fs_callback
,
1454 * Function: add_to_fs_list
1455 * Description: Function used to add a file system to the fs_list array in
1456 * a be_fs_list_data_t structure.
1458 * fld - be_fs_list_data_t pointer
1459 * fs - file system to add
1461 * BE_SUCCESS - Success
1467 add_to_fs_list(be_fs_list_data_t
*fld
, const char *fs
)
1469 if (fld
== NULL
|| fs
== NULL
)
1472 if ((fld
->fs_list
= (char **)realloc(fld
->fs_list
,
1473 sizeof (char *)*(fld
->fs_num
+ 1))) == NULL
) {
1474 be_print_err(gettext("add_to_fs_list: "
1475 "memory allocation failed\n"));
1479 if ((fld
->fs_list
[fld
->fs_num
++] = strdup(fs
)) == NULL
) {
1480 be_print_err(gettext("add_to_fs_list: "
1481 "memory allocation failed\n"));
1485 return (BE_SUCCESS
);
1489 * Function: zpool_shared_fs_callback
1490 * Description: Callback function used to iterate through all existing pools
1491 * to find and mount all shared filesystems. This function
1492 * processes the pool's "pool data" dataset, then uses
1493 * iter_shared_fs_callback to iterate through the pool's
1496 * zlp - zpool_handle_t pointer to the current pool being
1498 * data - be_mount_data_t pointer
1501 * be_errno_t - Failure
1506 zpool_shared_fs_callback(zpool_handle_t
*zlp
, void *data
)
1508 be_mount_data_t
*md
= data
;
1509 zfs_handle_t
*zhp
= NULL
;
1510 const char *zpool
= zpool_get_name(zlp
);
1514 * Get handle to pool's "pool data" dataset
1516 if ((zhp
= zfs_open(g_zfs
, zpool
, ZFS_TYPE_FILESYSTEM
)) == NULL
) {
1517 be_print_err(gettext("zpool_shared_fs: "
1518 "failed to open pool dataset %s: %s\n"), zpool
,
1519 libzfs_error_description(g_zfs
));
1520 ret
= zfs_err_to_be_err(g_zfs
);
1525 /* Process this pool's "pool data" dataset */
1526 (void) loopback_mount_shared_fs(zhp
, md
);
1528 /* Interate through this pool's children */
1529 (void) zfs_iter_filesystems(zhp
, iter_shared_fs_callback
, md
);
1538 * Function: iter_shared_fs_callback
1539 * Description: Callback function used to iterate through a pool's datasets
1540 * to find and mount all shared filesystems. It makes sure to
1541 * find the BE container dataset of the pool, if it exists, and
1542 * does not process and iterate down that path.
1544 * Note - This function iterates linearly down the
1545 * hierarchical dataset paths and mounts things as it goes
1546 * along. It does not make sure that something deeper down
1547 * a dataset path has an interim mountpoint for something
1548 * processed earlier.
1551 * zhp - zfs_handle_t pointer to the current dataset being
1553 * data - be_mount_data_t pointer
1556 * be_errno_t - Failure
1561 iter_shared_fs_callback(zfs_handle_t
*zhp
, void *data
)
1563 be_mount_data_t
*md
= data
;
1564 const char *name
= zfs_get_name(zhp
);
1565 char container_ds
[MAXPATHLEN
];
1566 char tmp_name
[MAXPATHLEN
];
1569 /* Get the pool's name */
1570 (void) strlcpy(tmp_name
, name
, sizeof (tmp_name
));
1571 pool
= strtok(tmp_name
, "/");
1574 /* Get the name of this pool's container dataset */
1575 be_make_container_ds(pool
, container_ds
,
1576 sizeof (container_ds
));
1579 * If what we're processing is this pool's BE container
1582 if (strcmp(name
, container_ds
) == 0) {
1587 /* Getting the pool name failed, return error */
1588 be_print_err(gettext("iter_shared_fs_callback: "
1589 "failed to get pool name from %s\n"), name
);
1591 return (BE_ERR_POOL_NOENT
);
1594 /* Mount this shared filesystem */
1595 (void) loopback_mount_shared_fs(zhp
, md
);
1597 /* Iterate this dataset's children file systems */
1598 (void) zfs_iter_filesystems(zhp
, iter_shared_fs_callback
, md
);
1605 * Function: loopback_mount_shared_fs
1606 * Description: This function loopback mounts a file system into the altroot
1607 * area of the BE being mounted. Since these are shared file
1608 * systems, they are expected to be already mounted for the
1609 * current BE, and this function just loopback mounts them into
1610 * the BE mountpoint. If they are not mounted for the current
1611 * live system, they are skipped and not mounted into the BE
1614 * zhp - zfs_handle_t pointer to the dataset to loopback mount
1615 * md - be_mount_data_t pointer
1617 * BE_SUCCESS - Success
1618 * be_errno_t - Failure
1623 loopback_mount_shared_fs(zfs_handle_t
*zhp
, be_mount_data_t
*md
)
1625 char zhp_mountpoint
[MAXPATHLEN
];
1626 char mountpoint
[MAXPATHLEN
];
1628 char optstr
[MAX_MNTOPT_STR
];
1629 int mflag
= MS_OPTIONSTR
;
1633 * Check if file system is currently mounted and not delegated
1634 * to a non-global zone (if we're in the global zone)
1636 if (zfs_is_mounted(zhp
, &mp
) && (getzoneid() != GLOBAL_ZONEID
||
1637 !zfs_prop_get_int(zhp
, ZFS_PROP_ZONED
))) {
1639 * If we didn't get a mountpoint from the zfs_is_mounted call,
1640 * get it from the mountpoint property.
1643 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
,
1644 zhp_mountpoint
, sizeof (zhp_mountpoint
), NULL
,
1645 NULL
, 0, B_FALSE
) != 0) {
1647 gettext("loopback_mount_shared_fs: "
1648 "failed to get mountpoint property\n"));
1649 return (BE_ERR_ZFS
);
1652 (void) strlcpy(zhp_mountpoint
, mp
,
1653 sizeof (zhp_mountpoint
));
1657 (void) snprintf(mountpoint
, sizeof (mountpoint
), "%s%s",
1658 md
->altroot
, zhp_mountpoint
);
1660 /* Mount it read-only if read-write was not requested */
1661 if (!md
->shared_rw
) {
1665 /* Add the "nosub" option to the mount options string */
1666 (void) strlcpy(optstr
, MNTOPT_NOSUB
, sizeof (optstr
));
1668 /* Loopback mount this dataset at the altroot */
1669 if (mount(zhp_mountpoint
, mountpoint
, mflag
, MNTTYPE_LOFS
,
1670 NULL
, 0, optstr
, sizeof (optstr
)) != 0) {
1672 be_print_err(gettext("loopback_mount_shared_fs: "
1673 "failed to loopback mount %s at %s: %s\n"),
1674 zhp_mountpoint
, mountpoint
, strerror(err
));
1675 return (BE_ERR_MOUNT
);
1679 return (BE_SUCCESS
);
1683 * Function: loopback_mount_zonepath
1684 * Description: This function loopback mounts a zonepath into the altroot
1685 * area of the BE being mounted. Since these are shared file
1686 * systems, they are expected to be already mounted for the
1687 * current BE, and this function just loopback mounts them into
1688 * the BE mountpoint.
1690 * zonepath - pointer to zone path in the current BE
1691 * md - be_mount_data_t pointer
1693 * BE_SUCCESS - Success
1694 * be_errno_t - Failure
1699 loopback_mount_zonepath(const char *zonepath
, be_mount_data_t
*md
)
1701 FILE *fp
= (FILE *)NULL
;
1706 struct extmnttab extmtab
;
1709 char alt_parentmnt
[MAXPATHLEN
];
1710 struct mnttab mntref
;
1711 char altzonepath
[MAXPATHLEN
];
1712 char optstr
[MAX_MNTOPT_STR
];
1713 int mflag
= MS_OPTIONSTR
;
1717 fp
= fopen(MNTTAB
, "r");
1720 be_print_err(gettext("loopback_mount_zonepath: "
1721 "failed to open /etc/mnttab\n"));
1722 return (errno_to_be_err(err
));
1726 * before attempting the loopback mount of zonepath under altroot,
1727 * we need to make sure that all intermediate file systems in the
1728 * zone path are also mounted under altroot
1731 /* get the parent directory for zonepath */
1732 p
= strrchr(zonepath
, '/');
1733 if (p
!= NULL
&& p
!= zonepath
) {
1734 if ((parent_dir
= (char *)calloc(sizeof (char),
1735 p
- zonepath
+ 1)) == NULL
) {
1739 (void) strlcpy(parent_dir
, zonepath
, p
- zonepath
+ 1);
1740 if (stat(parent_dir
, &st
) < 0) {
1741 ret
= errno_to_be_err(errno
);
1742 be_print_err(gettext("loopback_mount_zonepath: "
1743 "failed to stat %s"),
1751 * After the above stat call, st.st_dev contains ID of the
1752 * device over which parent dir resides.
1753 * Now, search mnttab and find mount point of parent dir device.
1757 while (getextmntent(fp
, &extmtab
, sizeof (extmtab
)) == 0) {
1758 dev
= makedev(extmtab
.mnt_major
, extmtab
.mnt_minor
);
1759 if (st
.st_dev
== dev
&& strcmp(extmtab
.mnt_fstype
,
1760 MNTTYPE_ZFS
) == 0) {
1761 p1
= strchr(extmtab
.mnt_special
, '/');
1762 if (p1
== NULL
|| strncmp(p1
+ 1,
1763 BE_CONTAINER_DS_NAME
, 4) != 0 ||
1764 (*(p1
+ 5) != '/' && *(p1
+ 5) != '\0')) {
1766 * if parent dir is in a shared file
1767 * system, check whether it is already
1768 * loopback mounted under altroot or
1769 * not. It would have been mounted
1770 * already under altroot if it is in
1771 * a non-shared filesystem.
1773 parentmnt
= strdup(extmtab
.mnt_mountp
);
1774 (void) snprintf(alt_parentmnt
,
1775 sizeof (alt_parentmnt
), "%s%s",
1776 md
->altroot
, parentmnt
);
1777 mntref
.mnt_mountp
= alt_parentmnt
;
1778 mntref
.mnt_special
= parentmnt
;
1779 mntref
.mnt_fstype
= MNTTYPE_LOFS
;
1780 mntref
.mnt_mntopts
= NULL
;
1781 mntref
.mnt_time
= NULL
;
1783 if (getmntany(fp
, (struct mnttab
*)
1784 &extmtab
, &mntref
) != 0) {
1785 ret
= loopback_mount_zonepath(
1787 if (ret
!= BE_SUCCESS
) {
1800 if (!md
->shared_rw
) {
1804 (void) snprintf(altzonepath
, sizeof (altzonepath
), "%s%s",
1805 md
->altroot
, zonepath
);
1807 /* Add the "nosub" option to the mount options string */
1808 (void) strlcpy(optstr
, MNTOPT_NOSUB
, sizeof (optstr
));
1810 /* Loopback mount this dataset at the altroot */
1811 if (mount(zonepath
, altzonepath
, mflag
, MNTTYPE_LOFS
,
1812 NULL
, 0, optstr
, sizeof (optstr
)) != 0) {
1814 be_print_err(gettext("loopback_mount_zonepath: "
1815 "failed to loopback mount %s at %s: %s\n"),
1816 zonepath
, altzonepath
, strerror(err
));
1828 * Function: unmount_shared_fs
1829 * Description: This function iterates through the mnttab and finds all
1830 * loopback mount entries that reside within the altroot of
1831 * where the BE is mounted, and unmounts it.
1833 * ud - be_unmount_data_t pointer
1835 * BE_SUCCESS - Success
1836 * be_errno_t - Failure
1841 unmount_shared_fs(be_unmount_data_t
*ud
)
1844 struct mnttab
*table
= NULL
;
1846 struct mnttab
*entp
= NULL
;
1848 int read_chunk
= 32;
1855 /* Read in the mnttab into a table */
1856 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1858 be_print_err(gettext("unmount_shared_fs: "
1859 "failed to open mnttab\n"));
1860 return (errno_to_be_err(err
));
1863 while (getmntent(fp
, &ent
) == 0) {
1864 if (size
% read_chunk
== 0) {
1865 table
= (struct mnttab
*)realloc(table
,
1866 (size
+ read_chunk
) * sizeof (ent
));
1868 entp
= &table
[size
++];
1871 * Copy over the current mnttab entry into our table,
1872 * copying only the fields that we care about.
1874 (void) memset(entp
, 0, sizeof (*entp
));
1875 if ((entp
->mnt_mountp
= strdup(ent
.mnt_mountp
)) == NULL
||
1876 (entp
->mnt_fstype
= strdup(ent
.mnt_fstype
)) == NULL
) {
1877 be_print_err(gettext("unmount_shared_fs: "
1878 "memory allocation failed\n"));
1879 return (BE_ERR_NOMEM
);
1885 * Process the mnttab entries in reverse order, looking for
1886 * loopback mount entries mounted under our altroot.
1888 altroot_len
= strlen(ud
->altroot
);
1889 for (i
= size
; i
> 0; i
--) {
1890 entp
= &table
[i
- 1];
1892 /* If not of type lofs, skip */
1893 if (strcmp(entp
->mnt_fstype
, MNTTYPE_LOFS
) != 0)
1896 /* If inside the altroot, unmount it */
1897 if (strncmp(entp
->mnt_mountp
, ud
->altroot
, altroot_len
) == 0 &&
1898 entp
->mnt_mountp
[altroot_len
] == '/') {
1899 if (umount(entp
->mnt_mountp
) != 0) {
1904 if (umount(entp
->mnt_mountp
) != 0)
1908 be_print_err(gettext(
1909 "unmount_shared_fs: "
1910 "failed to unmount shared file "
1912 entp
->mnt_mountp
, strerror(err
));
1913 return (errno_to_be_err(err
));
1919 return (BE_SUCCESS
);
1923 * Function: get_mountpoint_from_vfstab
1924 * Description: This function digs into the vfstab in the given altroot,
1925 * and searches for an entry for the fs passed in. If found,
1926 * it returns the mountpoint of that fs in the mountpoint
1927 * buffer passed in. If the get_alt_mountpoint flag is set,
1928 * it returns the mountpoint with the altroot prepended.
1930 * altroot - pointer to the alternate root location
1931 * fs - pointer to the file system name to look for in the
1933 * mountpoint - pointer to buffer of where the mountpoint of
1934 * fs will be returned.
1935 * size_mp - size of mountpoint argument
1936 * get_alt_mountpoint - flag to indicate whether or not the
1937 * mountpoint should be populated with the altroot
1940 * BE_SUCCESS - Success
1946 get_mountpoint_from_vfstab(char *altroot
, const char *fs
, char *mountpoint
,
1947 size_t size_mp
, boolean_t get_alt_mountpoint
)
1951 char alt_vfstab
[MAXPATHLEN
];
1953 /* Generate path to alternate root vfstab */
1954 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
1957 /* Open alternate root vfstab */
1958 if ((fp
= fopen(alt_vfstab
, "r")) == NULL
) {
1959 be_print_err(gettext("get_mountpoint_from_vfstab: "
1960 "failed to open vfstab (%s)\n"), alt_vfstab
);
1964 if (getvfsspec(fp
, &vp
, (char *)fs
) == 0) {
1966 * Found entry for fs, grab its mountpoint.
1967 * If the flag to prepend the altroot into the mountpoint
1968 * is set, prepend it. Otherwise, just return the mountpoint.
1970 if (get_alt_mountpoint
) {
1971 (void) snprintf(mountpoint
, size_mp
, "%s%s", altroot
,
1974 (void) strlcpy(mountpoint
, vp
.vfs_mountp
, size_mp
);
1983 return (BE_SUCCESS
);
1987 * Function: fix_mountpoint_callback
1988 * Description: This callback function is used to iterate through a BE's
1989 * children filesystems to check if its mountpoint is currently
1990 * set to be mounted at some specified altroot. If so, fix it by
1991 * removing altroot from the beginning of its mountpoint.
1993 * Note - There's no way to tell if a child filesystem's
1994 * mountpoint isn't broken, and just happens to begin with
1995 * the altroot we're looking for. In this case, this function
1996 * will errantly remove the altroot portion from the beginning
1997 * of this filesystem's mountpoint.
2000 * zhp - zfs_handle_t pointer to filesystem being processed.
2001 * data - altroot of where BE is to be mounted.
2004 * be_errno_t - Failure
2009 fix_mountpoint_callback(zfs_handle_t
*zhp
, void *data
)
2011 zprop_source_t sourcetype
;
2012 char source
[ZFS_MAXNAMELEN
];
2013 char mountpoint
[MAXPATHLEN
];
2014 char *zhp_mountpoint
= NULL
;
2015 char *altroot
= data
;
2018 /* Get dataset's mountpoint and source values */
2019 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
2020 sizeof (mountpoint
), &sourcetype
, source
, sizeof (source
),
2022 be_print_err(gettext("fix_mountpoint_callback: "
2023 "failed to get mountpoint and sourcetype for %s\n"),
2026 return (BE_ERR_ZFS
);
2030 * If the mountpoint is not inherited and the mountpoint is not
2031 * 'legacy', this file system potentially needs its mountpoint
2034 if (!(sourcetype
& ZPROP_SRC_INHERITED
) &&
2035 strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) != 0) {
2038 * Check if this file system's current mountpoint is
2039 * under the altroot we're fixing it against.
2041 if (strncmp(mountpoint
, altroot
, strlen(altroot
)) == 0 &&
2042 mountpoint
[strlen(altroot
)] == '/') {
2045 * Get this dataset's mountpoint relative to the
2048 zhp_mountpoint
= mountpoint
+ strlen(altroot
);
2050 /* Fix this dataset's mountpoint value */
2051 if (zfs_prop_set(zhp
,
2052 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
2054 be_print_err(gettext("fix_mountpoint_callback: "
2055 "failed to set mountpoint for %s to "
2056 "%s: %s\n"), zfs_get_name(zhp
),
2058 libzfs_error_description(g_zfs
));
2059 ret
= zfs_err_to_be_err(g_zfs
);
2066 /* Iterate through this dataset's children and fix them */
2067 if ((ret
= zfs_iter_filesystems(zhp
, fix_mountpoint_callback
,
2079 * Function: be_mount_root
2080 * Description: This function mounts the root dataset of a BE at the
2081 * specified altroot.
2083 * zhp - zfs_handle_t pointer to root dataset of a BE that is
2084 * to be mounted at altroot.
2085 * altroot - location of where to mount the BE root.
2087 * BE_SUCCESS - Success
2088 * be_errno_t - Failure
2093 be_mount_root(zfs_handle_t
*zhp
, char *altroot
)
2095 char mountpoint
[MAXPATHLEN
];
2097 /* Get mountpoint property of dataset */
2098 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
2099 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
2100 be_print_err(gettext("be_mount_root: failed to "
2101 "get mountpoint property for %s: %s\n"), zfs_get_name(zhp
),
2102 libzfs_error_description(g_zfs
));
2103 return (zfs_err_to_be_err(g_zfs
));
2107 * Set the canmount property for the BE's root dataset to 'noauto' just
2108 * in case it's been set to 'on'. We do this so that when we change its
2109 * mountpoint, zfs won't immediately try to mount it.
2111 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")
2113 be_print_err(gettext("be_mount_root: failed to "
2114 "set canmount property to 'noauto' (%s): %s\n"),
2115 zfs_get_name(zhp
), libzfs_error_description(g_zfs
));
2116 return (zfs_err_to_be_err(g_zfs
));
2119 /* Set mountpoint for BE's root filesystem */
2120 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
), altroot
)
2122 be_print_err(gettext("be_mount_root: failed to "
2123 "set mountpoint of %s to %s: %s\n"),
2124 zfs_get_name(zhp
), altroot
,
2125 libzfs_error_description(g_zfs
));
2126 return (zfs_err_to_be_err(g_zfs
));
2129 /* Mount the BE's root filesystem */
2130 if (zfs_mount(zhp
, NULL
, 0) != 0) {
2131 be_print_err(gettext("be_mount_root: failed to "
2132 "mount dataset %s at %s: %s\n"), zfs_get_name(zhp
),
2133 altroot
, libzfs_error_description(g_zfs
));
2135 * Set this BE's root filesystem 'mountpoint' property
2136 * back to what it was before.
2138 (void) zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
2140 return (zfs_err_to_be_err(g_zfs
));
2143 return (BE_SUCCESS
);
2147 * Function: be_unmount_root
2148 * Description: This function unmounts the root dataset of a BE, but before
2149 * unmounting, it looks at the BE's vfstab to determine
2150 * if the root dataset mountpoint should be left as 'legacy'
2151 * or '/'. If the vfstab contains an entry for this root
2152 * dataset with a mountpoint of '/', it sets the mountpoint
2153 * property to 'legacy'.
2156 * zhp - zfs_handle_t pointer of the BE root dataset that
2157 * is currently mounted.
2158 * ud - be_unmount_data_t pointer providing unmount data
2159 * for the given BE root dataset.
2161 * BE_SUCCESS - Success
2162 * be_errno_t - Failure
2167 be_unmount_root(zfs_handle_t
*zhp
, be_unmount_data_t
*ud
)
2169 char mountpoint
[MAXPATHLEN
];
2170 boolean_t is_legacy
= B_FALSE
;
2172 /* See if this is a legacy mounted root */
2173 if (get_mountpoint_from_vfstab(ud
->altroot
, zfs_get_name(zhp
),
2174 mountpoint
, sizeof (mountpoint
), B_FALSE
) == BE_SUCCESS
&&
2175 strcmp(mountpoint
, "/") == 0) {
2179 /* Unmount the dataset */
2180 if (zfs_unmount(zhp
, NULL
, ud
->force
? MS_FORCE
: 0) != 0) {
2181 be_print_err(gettext("be_unmount_root: failed to "
2182 "unmount BE root dataset %s: %s\n"), zfs_get_name(zhp
),
2183 libzfs_error_description(g_zfs
));
2184 return (zfs_err_to_be_err(g_zfs
));
2187 /* Set canmount property for this BE's root filesystem to noauto */
2188 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_CANMOUNT
), "noauto")
2190 be_print_err(gettext("be_unmount_root: failed to "
2191 "set canmount property for %s to 'noauto': %s\n"),
2192 zfs_get_name(zhp
), libzfs_error_description(g_zfs
));
2193 return (zfs_err_to_be_err(g_zfs
));
2197 * Set mountpoint for BE's root dataset back to '/', or 'legacy'
2198 * if its a legacy mounted root.
2200 if (zfs_prop_set(zhp
, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT
),
2201 is_legacy
? ZFS_MOUNTPOINT_LEGACY
: "/") != 0) {
2202 be_print_err(gettext("be_unmount_root: failed to "
2203 "set mountpoint of %s to %s\n"), zfs_get_name(zhp
),
2204 is_legacy
? ZFS_MOUNTPOINT_LEGACY
: "/");
2205 return (zfs_err_to_be_err(g_zfs
));
2208 return (BE_SUCCESS
);
2212 * Function: fix_mountpoint
2213 * Description: This function checks the mountpoint of an unmounted BE to make
2214 * sure that it is set to either 'legacy' or '/'. If it's not,
2215 * then we're in a situation where an unmounted BE has some random
2216 * mountpoint set for it. (This could happen if the system was
2217 * rebooted while an inactive BE was mounted). This function
2218 * attempts to fix its mountpoints.
2220 * zhp - zfs_handle_t pointer to root dataset of the BE
2221 * whose mountpoint needs to be checked.
2223 * BE_SUCCESS - Success
2224 * be_errno_t - Failure
2229 fix_mountpoint(zfs_handle_t
*zhp
)
2231 be_unmount_data_t ud
= { 0 };
2232 char *altroot
= NULL
;
2233 char mountpoint
[MAXPATHLEN
];
2234 int ret
= BE_SUCCESS
;
2237 * Record what this BE's root dataset mountpoint property is currently
2240 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
2241 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
2242 be_print_err(gettext("fix_mountpoint: failed to get "
2243 "mountpoint property of (%s): %s\n"), zfs_get_name(zhp
),
2244 libzfs_error_description(g_zfs
));
2245 return (BE_ERR_ZFS
);
2249 * If the root dataset mountpoint is set to 'legacy' or '/', we're okay.
2251 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0 ||
2252 strcmp(mountpoint
, "/") == 0) {
2253 return (BE_SUCCESS
);
2257 * Iterate through this BE's children datasets and fix
2258 * them if they need fixing.
2260 if (zfs_iter_filesystems(zhp
, fix_mountpoint_callback
, mountpoint
)
2262 return (BE_ERR_ZFS
);
2266 * The process of mounting and unmounting the root file system
2267 * will fix its mountpoint to correctly be either 'legacy' or '/'
2268 * since be_unmount_root will do the right thing by looking at
2272 /* Generate temporary altroot to mount the root file system */
2273 if ((ret
= be_make_tmp_mountpoint(&altroot
)) != BE_SUCCESS
) {
2274 be_print_err(gettext("fix_mountpoint: failed to "
2275 "make temporary mountpoint\n"));
2279 /* Mount and unmount the root. */
2280 if ((ret
= be_mount_root(zhp
, altroot
)) != BE_SUCCESS
) {
2281 be_print_err(gettext("fix_mountpoint: failed to "
2282 "mount BE root file system\n"));
2285 ud
.altroot
= altroot
;
2286 if ((ret
= be_unmount_root(zhp
, &ud
)) != BE_SUCCESS
) {
2287 be_print_err(gettext("fix_mountpoint: failed to "
2288 "unmount BE root file system\n"));
2299 * Function: be_mount_zones
2300 * Description: This function finds all supported non-global zones in the
2301 * given global BE and mounts them with respect to where the
2302 * global BE is currently mounted. The global BE datasets
2303 * (including its shared datasets) are expected to already
2306 * be_zhp - zfs_handle_t pointer to the root dataset of the
2308 * md - be_mount_data_t pointer to data for global BE.
2310 * BE_SUCCESS - Success
2311 * be_errno_t - Failure
2316 be_mount_zones(zfs_handle_t
*be_zhp
, be_mount_data_t
*md
)
2318 zoneBrandList_t
*brands
= NULL
;
2319 zoneList_t zlst
= NULL
;
2320 char *zonename
= NULL
;
2321 char *zonepath
= NULL
;
2322 char *zonepath_ds
= NULL
;
2324 int ret
= BE_SUCCESS
;
2326 z_set_zone_root(md
->altroot
);
2328 if ((brands
= be_get_supported_brandlist()) == NULL
) {
2329 be_print_err(gettext("be_mount_zones: "
2330 "no supported brands\n"));
2331 return (BE_SUCCESS
);
2334 zlst
= z_get_nonglobal_zone_list_by_brand(brands
);
2336 z_free_brand_list(brands
);
2337 return (BE_SUCCESS
);
2340 for (k
= 0; (zonename
= z_zlist_get_zonename(zlst
, k
)) != NULL
; k
++) {
2341 if (z_zlist_get_current_state(zlst
, k
) ==
2342 ZONE_STATE_INSTALLED
) {
2343 zonepath
= z_zlist_get_zonepath(zlst
, k
);
2346 * Get the dataset of this zonepath in current BE.
2347 * If its not a dataset, skip it.
2349 if ((zonepath_ds
= be_get_ds_from_dir(zonepath
))
2354 * Check if this zone is supported based on
2355 * the dataset of its zonepath
2357 if (!be_zone_supported(zonepath_ds
)) {
2364 * if BE's shared file systems are already mounted,
2365 * zone path dataset would have already been lofs
2366 * mounted under altroot. Otherwise, we need to do
2369 if (!md
->shared_fs
) {
2370 ret
= loopback_mount_zonepath(zonepath
, md
);
2371 if (ret
!= BE_SUCCESS
)
2376 /* Mount this zone */
2377 ret
= be_mount_one_zone(be_zhp
, md
, zonename
,
2378 zonepath
, zonepath_ds
);
2383 if (ret
!= BE_SUCCESS
) {
2384 be_print_err(gettext("be_mount_zones: "
2385 "failed to mount zone %s under "
2386 "altroot %s\n"), zonename
, md
->altroot
);
2393 z_free_brand_list(brands
);
2394 z_free_zone_list(zlst
);
2396 * libinstzones caches mnttab and uses cached version for resolving lofs
2397 * mounts when we call z_resolve_lofs. It creates the cached version
2398 * when the first call to z_resolve_lofs happens. So, library's cached
2399 * mnttab doesn't contain entries for lofs mounts created in the above
2400 * loop. Because of this, subsequent calls to z_resolve_lofs would fail
2401 * to resolve these lofs mounts. So, here we destroy library's cached
2402 * mnttab to force its recreation when the next call to z_resolve_lofs
2405 z_destroyMountTable();
2410 * Function: be_unmount_zones
2411 * Description: This function finds all supported non-global zones in the
2412 * given mounted global BE and unmounts them.
2414 * ud - unmount_data_t pointer data for the global BE.
2416 * BE_SUCCESS - Success
2417 * be_errno_t - Failure
2422 be_unmount_zones(be_unmount_data_t
*ud
)
2424 zoneBrandList_t
*brands
= NULL
;
2425 zoneList_t zlst
= NULL
;
2426 char *zonename
= NULL
;
2427 char *zonepath
= NULL
;
2428 char alt_zonepath
[MAXPATHLEN
];
2429 char *zonepath_ds
= NULL
;
2431 int ret
= BE_SUCCESS
;
2433 z_set_zone_root(ud
->altroot
);
2435 if ((brands
= be_get_supported_brandlist()) == NULL
) {
2436 be_print_err(gettext("be_unmount_zones: "
2437 "no supported brands\n"));
2438 return (BE_SUCCESS
);
2441 zlst
= z_get_nonglobal_zone_list_by_brand(brands
);
2443 z_free_brand_list(brands
);
2444 return (BE_SUCCESS
);
2447 for (k
= 0; (zonename
= z_zlist_get_zonename(zlst
, k
)) != NULL
; k
++) {
2448 if (z_zlist_get_current_state(zlst
, k
) ==
2449 ZONE_STATE_INSTALLED
) {
2450 zonepath
= z_zlist_get_zonepath(zlst
, k
);
2452 /* Build zone's zonepath wrt the global BE altroot */
2453 (void) snprintf(alt_zonepath
, sizeof (alt_zonepath
),
2454 "%s%s", ud
->altroot
, zonepath
);
2457 * Get the dataset of this zonepath. If its not
2458 * a dataset, skip it.
2460 if ((zonepath_ds
= be_get_ds_from_dir(alt_zonepath
))
2465 * Check if this zone is supported based on the
2466 * dataset of its zonepath.
2468 if (!be_zone_supported(zonepath_ds
)) {
2474 /* Unmount this zone */
2475 ret
= be_unmount_one_zone(ud
, zonename
, zonepath
,
2481 if (ret
!= BE_SUCCESS
) {
2482 be_print_err(gettext("be_unmount_zones:"
2483 " failed to unmount zone %s from "
2484 "altroot %s\n"), zonename
, ud
->altroot
);
2491 z_free_brand_list(brands
);
2492 z_free_zone_list(zlst
);
2497 * Function: be_mount_one_zone
2498 * Description: This function is called to mount one zone for a given
2501 * be_zhp - zfs_handle_t pointer to the root dataset of the
2503 * md - be_mount_data_t pointer to data for global BE
2504 * zonename - name of zone to mount
2505 * zonepath - zonepath of zone to mount
2506 * zonepath_ds - dataset for the zonepath
2508 * BE_SUCCESS - Success
2509 * be_errno_t - Failure
2514 be_mount_one_zone(zfs_handle_t
*be_zhp
, be_mount_data_t
*md
, char *zonename
,
2515 char *zonepath
, char *zonepath_ds
)
2517 be_mount_data_t zone_md
= { 0 };
2518 zfs_handle_t
*zone_zhp
= NULL
;
2519 char zone_altroot
[MAXPATHLEN
];
2520 char zoneroot
[MAXPATHLEN
];
2521 char zoneroot_ds
[MAXPATHLEN
];
2522 int ret
= BE_SUCCESS
;
2524 /* Find the active zone root dataset for this zone for this BE */
2525 if ((ret
= be_find_active_zone_root(be_zhp
, zonepath_ds
, zoneroot_ds
,
2526 sizeof (zoneroot_ds
))) == BE_ERR_ZONE_NO_ACTIVE_ROOT
) {
2527 be_print_err(gettext("be_mount_one_zone: did not "
2528 "find active zone root for zone %s, skipping ...\n"),
2530 return (BE_SUCCESS
);
2531 } else if (ret
!= BE_SUCCESS
) {
2532 be_print_err(gettext("be_mount_one_zone: failed to "
2533 "find active zone root for zone %s\n"), zonename
);
2537 /* Get handle to active zoneroot dataset */
2538 if ((zone_zhp
= zfs_open(g_zfs
, zoneroot_ds
, ZFS_TYPE_FILESYSTEM
))
2540 be_print_err(gettext("be_mount_one_zone: failed to "
2541 "open zone root dataset (%s): %s\n"), zoneroot_ds
,
2542 libzfs_error_description(g_zfs
));
2543 return (zfs_err_to_be_err(g_zfs
));
2546 /* Generate string for zone's altroot path */
2547 be_make_zoneroot(zonepath
, zoneroot
, sizeof (zoneroot
));
2548 (void) strlcpy(zone_altroot
, md
->altroot
, sizeof (zone_altroot
));
2549 (void) strlcat(zone_altroot
, zoneroot
, sizeof (zone_altroot
));
2551 /* Build mount_data for the zone */
2552 zone_md
.altroot
= zone_altroot
;
2553 zone_md
.shared_fs
= md
->shared_fs
;
2554 zone_md
.shared_rw
= md
->shared_rw
;
2556 /* Mount the zone's root file system */
2557 if ((ret
= be_mount_zone_root(zone_zhp
, &zone_md
)) != BE_SUCCESS
) {
2558 be_print_err(gettext("be_mount_one_zone: failed to "
2559 "mount zone root file system at %s\n"), zone_altroot
);
2563 /* Iterate through zone's children filesystems */
2564 if ((ret
= zfs_iter_filesystems(zone_zhp
, be_mount_callback
,
2565 zone_altroot
)) != 0) {
2566 be_print_err(gettext("be_mount_one_zone: failed to "
2567 "mount zone subordinate file systems at %s\n"),
2572 /* TODO: Mount all shared file systems for this zone */
2575 ZFS_CLOSE(zone_zhp
);
2580 * Function: be_unmount_one_zone
2581 * Description: This function unmount one zone for a give global BE.
2583 * ud - be_unmount_data_t pointer to data for global BE
2584 * zonename - name of zone to unmount
2585 * zonepath - zonepath of the zone to unmount
2586 * zonepath_ds - dataset for the zonepath
2588 * BE_SUCCESS - Success
2589 * be_errno_t - Failure
2594 be_unmount_one_zone(be_unmount_data_t
*ud
, char *zonename
, char *zonepath
,
2597 be_unmount_data_t zone_ud
= { 0 };
2598 zfs_handle_t
*zone_zhp
= NULL
;
2599 char zone_altroot
[MAXPATHLEN
];
2600 char zoneroot
[MAXPATHLEN
];
2601 char zoneroot_ds
[MAXPATHLEN
];
2602 int ret
= BE_SUCCESS
;
2604 /* Generate string for zone's alternate root path */
2605 be_make_zoneroot(zonepath
, zoneroot
, sizeof (zoneroot
));
2606 (void) strlcpy(zone_altroot
, ud
->altroot
, sizeof (zone_altroot
));
2607 (void) strlcat(zone_altroot
, zoneroot
, sizeof (zone_altroot
));
2609 /* Build be_unmount_data for zone */
2610 zone_ud
.altroot
= zone_altroot
;
2611 zone_ud
.force
= ud
->force
;
2613 /* Find the mounted zone root dataset for this zone for this BE */
2614 if ((ret
= be_find_mounted_zone_root(zone_altroot
, zonepath_ds
,
2615 zoneroot_ds
, sizeof (zoneroot_ds
))) == BE_ERR_NO_MOUNTED_ZONE
) {
2616 be_print_err(gettext("be_unmount_one_zone: did not "
2617 "find any zone root mounted for zone %s\n"), zonename
);
2618 return (BE_SUCCESS
);
2619 } else if (ret
!= BE_SUCCESS
) {
2620 be_print_err(gettext("be_unmount_one_zone: failed to "
2621 "find mounted zone root for zone %s\n"), zonename
);
2625 /* Get handle to zoneroot dataset mounted for this BE */
2626 if ((zone_zhp
= zfs_open(g_zfs
, zoneroot_ds
, ZFS_TYPE_FILESYSTEM
))
2628 be_print_err(gettext("be_unmount_one_zone: failed to "
2629 "open mounted zone root dataset (%s): %s\n"), zoneroot_ds
,
2630 libzfs_error_description(g_zfs
));
2631 return (zfs_err_to_be_err(g_zfs
));
2634 /* TODO: Unmount all shared file systems for this zone */
2636 /* Iterate through zone's children filesystems and unmount them */
2637 if ((ret
= zfs_iter_filesystems(zone_zhp
, be_unmount_callback
,
2639 be_print_err(gettext("be_unmount_one_zone: failed to "
2640 "unmount zone subordinate file systems at %s\n"),
2645 /* Unmount the zone's root filesystem */
2646 if ((ret
= be_unmount_zone_root(zone_zhp
, &zone_ud
)) != BE_SUCCESS
) {
2647 be_print_err(gettext("be_unmount_one_zone: failed to "
2648 "unmount zone root file system at %s\n"), zone_altroot
);
2653 ZFS_CLOSE(zone_zhp
);
2658 * Function: be_get_ds_from_dir_callback
2659 * Description: This is a callback function used to iterate all datasets
2660 * to find the one that is currently mounted at the directory
2661 * being searched for. If matched, the name of the dataset is
2662 * returned in heap storage, so the caller is responsible for
2665 * zhp - zfs_handle_t pointer to current dataset being processed.
2666 * data - dir_data_t pointer providing name of directory being
2669 * 1 - This dataset is mounted at directory being searched for.
2670 * 0 - This dataset is not mounted at directory being searched for.
2675 be_get_ds_from_dir_callback(zfs_handle_t
*zhp
, void *data
)
2677 dir_data_t
*dd
= data
;
2681 if (zfs_get_type(zhp
) != ZFS_TYPE_FILESYSTEM
) {
2686 if (zfs_is_mounted(zhp
, &mp
) && mp
!= NULL
&&
2687 strcmp(mp
, dd
->dir
) == 0) {
2688 if ((dd
->ds
= strdup(zfs_get_name(zhp
))) == NULL
) {
2689 be_print_err(gettext("be_get_ds_from_dir_callback: "
2690 "memory allocation failed\n"));
2698 zret
= zfs_iter_filesystems(zhp
, be_get_ds_from_dir_callback
, dd
);