1f169c0eaSGlenn Lagasse /* 2f169c0eaSGlenn Lagasse * CDDL HEADER START 3f169c0eaSGlenn Lagasse * 4f169c0eaSGlenn Lagasse * The contents of this file are subject to the terms of the 5f169c0eaSGlenn Lagasse * Common Development and Distribution License (the "License"). 6f169c0eaSGlenn Lagasse * You may not use this file except in compliance with the License. 7f169c0eaSGlenn Lagasse * 8f169c0eaSGlenn Lagasse * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9f169c0eaSGlenn Lagasse * or http://www.opensolaris.org/os/licensing. 10f169c0eaSGlenn Lagasse * See the License for the specific language governing permissions 11f169c0eaSGlenn Lagasse * and limitations under the License. 12f169c0eaSGlenn Lagasse * 13f169c0eaSGlenn Lagasse * When distributing Covered Code, include this CDDL HEADER in each 14f169c0eaSGlenn Lagasse * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15f169c0eaSGlenn Lagasse * If applicable, add the following below this CDDL HEADER, with the 16f169c0eaSGlenn Lagasse * fields enclosed by brackets "[]" replaced with your own identifying 17f169c0eaSGlenn Lagasse * information: Portions Copyright [yyyy] [name of copyright owner] 18f169c0eaSGlenn Lagasse * 19f169c0eaSGlenn Lagasse * CDDL HEADER END 20f169c0eaSGlenn Lagasse */ 21f169c0eaSGlenn Lagasse 22f169c0eaSGlenn Lagasse /* 23f169c0eaSGlenn Lagasse * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 247e0e2549SAlexander Eremin * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 2585aac7c1SIgor Kozhukhov * Copyright 2015 EveryCity Ltd. 269adfa60dSMatthew Ahrens * Copyright (c) 2015 by Delphix. All rights reserved. 2789d19e00SAlexander Eremin */ 28f169c0eaSGlenn Lagasse 29f169c0eaSGlenn Lagasse /* 30f169c0eaSGlenn Lagasse * System includes 31f169c0eaSGlenn Lagasse */ 32f169c0eaSGlenn Lagasse #include <assert.h> 33f169c0eaSGlenn Lagasse #include <errno.h> 347e0e2549SAlexander Eremin #include <libgen.h> 35f169c0eaSGlenn Lagasse #include <libintl.h> 36f169c0eaSGlenn Lagasse #include <libnvpair.h> 37f169c0eaSGlenn Lagasse #include <libzfs.h> 38f169c0eaSGlenn Lagasse #include <stdio.h> 39f169c0eaSGlenn Lagasse #include <stdlib.h> 40f169c0eaSGlenn Lagasse #include <string.h> 41f169c0eaSGlenn Lagasse #include <sys/mntent.h> 42f169c0eaSGlenn Lagasse #include <sys/mnttab.h> 43f169c0eaSGlenn Lagasse #include <sys/mount.h> 44f169c0eaSGlenn Lagasse #include <sys/stat.h> 45f169c0eaSGlenn Lagasse #include <sys/types.h> 46f169c0eaSGlenn Lagasse #include <sys/vfstab.h> 47f169c0eaSGlenn Lagasse #include <sys/zone.h> 48f169c0eaSGlenn Lagasse #include <sys/mkdev.h> 49f169c0eaSGlenn Lagasse #include <unistd.h> 50f169c0eaSGlenn Lagasse 51f169c0eaSGlenn Lagasse #include <libbe.h> 52f169c0eaSGlenn Lagasse #include <libbe_priv.h> 53f169c0eaSGlenn Lagasse 54f169c0eaSGlenn Lagasse #define BE_TMP_MNTPNT "/tmp/.be.XXXXXX" 55f169c0eaSGlenn Lagasse 56f169c0eaSGlenn Lagasse typedef struct dir_data { 57f169c0eaSGlenn Lagasse char *dir; 58f169c0eaSGlenn Lagasse char *ds; 59f169c0eaSGlenn Lagasse } dir_data_t; 60f169c0eaSGlenn Lagasse 61f169c0eaSGlenn Lagasse /* Private function prototypes */ 62f169c0eaSGlenn Lagasse static int be_mount_callback(zfs_handle_t *, void *); 63f169c0eaSGlenn Lagasse static int be_unmount_callback(zfs_handle_t *, void *); 64f169c0eaSGlenn Lagasse static int be_get_legacy_fs_callback(zfs_handle_t *, void *); 65f169c0eaSGlenn Lagasse static int fix_mountpoint(zfs_handle_t *); 66f169c0eaSGlenn Lagasse static int fix_mountpoint_callback(zfs_handle_t *, void *); 67f169c0eaSGlenn Lagasse static int get_mountpoint_from_vfstab(char *, const char *, char *, size_t, 68f169c0eaSGlenn Lagasse boolean_t); 69f169c0eaSGlenn Lagasse static int loopback_mount_shared_fs(zfs_handle_t *, be_mount_data_t *); 70f169c0eaSGlenn Lagasse static int loopback_mount_zonepath(const char *, be_mount_data_t *); 71f169c0eaSGlenn Lagasse static int iter_shared_fs_callback(zfs_handle_t *, void *); 72f169c0eaSGlenn Lagasse static int zpool_shared_fs_callback(zpool_handle_t *, void *); 73f169c0eaSGlenn Lagasse static int unmount_shared_fs(be_unmount_data_t *); 74f169c0eaSGlenn Lagasse static int add_to_fs_list(be_fs_list_data_t *, const char *); 75f169c0eaSGlenn Lagasse static int be_mount_root(zfs_handle_t *, char *); 76f169c0eaSGlenn Lagasse static int be_unmount_root(zfs_handle_t *, be_unmount_data_t *); 77f169c0eaSGlenn Lagasse static int be_mount_zones(zfs_handle_t *, be_mount_data_t *); 78f169c0eaSGlenn Lagasse static int be_unmount_zones(be_unmount_data_t *); 79f169c0eaSGlenn Lagasse static int be_mount_one_zone(zfs_handle_t *, be_mount_data_t *, char *, char *, 80f169c0eaSGlenn Lagasse char *); 81f169c0eaSGlenn Lagasse static int be_unmount_one_zone(be_unmount_data_t *, char *, char *, char *); 82f169c0eaSGlenn Lagasse static int be_get_ds_from_dir_callback(zfs_handle_t *, void *); 833a876192SAlexander Pyhalov static int mount_zfs(zfs_handle_t *, char *); 84f169c0eaSGlenn Lagasse 85f169c0eaSGlenn Lagasse 86f169c0eaSGlenn Lagasse /* ******************************************************************** */ 87f169c0eaSGlenn Lagasse /* Public Functions */ 88f169c0eaSGlenn Lagasse /* ******************************************************************** */ 89f169c0eaSGlenn Lagasse 90f169c0eaSGlenn Lagasse /* 91f169c0eaSGlenn Lagasse * Function: be_mount 92f169c0eaSGlenn Lagasse * Description: Mounts a BE and its subordinate datasets at a given mountpoint. 93f169c0eaSGlenn Lagasse * Parameters: 94f169c0eaSGlenn Lagasse * be_attrs - pointer to nvlist_t of attributes being passed in. 95f169c0eaSGlenn Lagasse * The following attributes are used by this function: 96f169c0eaSGlenn Lagasse * 97f169c0eaSGlenn Lagasse * BE_ATTR_ORIG_BE_NAME *required 98f169c0eaSGlenn Lagasse * BE_ATTR_MOUNTPOINT *required 99f169c0eaSGlenn Lagasse * BE_ATTR_MOUNT_FLAGS *optional 100f169c0eaSGlenn Lagasse * Return: 101f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 102f169c0eaSGlenn Lagasse * be_errno_t - Failure 103f169c0eaSGlenn Lagasse * Scope: 104f169c0eaSGlenn Lagasse * Public 105f169c0eaSGlenn Lagasse */ 106f169c0eaSGlenn Lagasse int 107f169c0eaSGlenn Lagasse be_mount(nvlist_t *be_attrs) 108f169c0eaSGlenn Lagasse { 109f169c0eaSGlenn Lagasse char *be_name = NULL; 110f169c0eaSGlenn Lagasse char *mountpoint = NULL; 111f169c0eaSGlenn Lagasse uint16_t flags = 0; 112f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 113f169c0eaSGlenn Lagasse 114f169c0eaSGlenn Lagasse /* Initialize libzfs handle */ 115f169c0eaSGlenn Lagasse if (!be_zfs_init()) 116f169c0eaSGlenn Lagasse return (BE_ERR_INIT); 117f169c0eaSGlenn Lagasse 118f169c0eaSGlenn Lagasse /* Get original BE name */ 119f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name) 120f169c0eaSGlenn Lagasse != 0) { 121f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: failed to lookup " 122f169c0eaSGlenn Lagasse "BE_ATTR_ORIG_BE_NAME attribute\n")); 123f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 124f169c0eaSGlenn Lagasse } 125f169c0eaSGlenn Lagasse 126f169c0eaSGlenn Lagasse /* Validate original BE name */ 127f169c0eaSGlenn Lagasse if (!be_valid_be_name(be_name)) { 128f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: invalid BE name %s\n"), 129f169c0eaSGlenn Lagasse be_name); 130f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 131f169c0eaSGlenn Lagasse } 132f169c0eaSGlenn Lagasse 133f169c0eaSGlenn Lagasse /* Get mountpoint */ 134f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_MOUNTPOINT, &mountpoint) 135f169c0eaSGlenn Lagasse != 0) { 136f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: failed to lookup " 137f169c0eaSGlenn Lagasse "BE_ATTR_MOUNTPOINT attribute\n")); 138f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 139f169c0eaSGlenn Lagasse } 140f169c0eaSGlenn Lagasse 141f169c0eaSGlenn Lagasse /* Get flags */ 142f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 143f169c0eaSGlenn Lagasse BE_ATTR_MOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) { 144f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: failed to lookup " 145f169c0eaSGlenn Lagasse "BE_ATTR_MOUNT_FLAGS attribute\n")); 146f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 147f169c0eaSGlenn Lagasse } 148f169c0eaSGlenn Lagasse 149f169c0eaSGlenn Lagasse ret = _be_mount(be_name, &mountpoint, flags); 150f169c0eaSGlenn Lagasse 151f169c0eaSGlenn Lagasse be_zfs_fini(); 152f169c0eaSGlenn Lagasse 153f169c0eaSGlenn Lagasse return (ret); 154f169c0eaSGlenn Lagasse } 155f169c0eaSGlenn Lagasse 156f169c0eaSGlenn Lagasse /* 157f169c0eaSGlenn Lagasse * Function: be_unmount 158f169c0eaSGlenn Lagasse * Description: Unmounts a BE and its subordinate datasets. 159f169c0eaSGlenn Lagasse * Parameters: 160f169c0eaSGlenn Lagasse * be_attrs - pointer to nvlist_t of attributes being passed in. 161f169c0eaSGlenn Lagasse * The following attributes are used by this function: 162f169c0eaSGlenn Lagasse * 163f169c0eaSGlenn Lagasse * BE_ATTR_ORIG_BE_NAME *required 164f169c0eaSGlenn Lagasse * BE_ATTR_UNMOUNT_FLAGS *optional 165f169c0eaSGlenn Lagasse * Return: 166f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 167f169c0eaSGlenn Lagasse * be_errno_t - Failure 168f169c0eaSGlenn Lagasse * Scope: 169f169c0eaSGlenn Lagasse * Public 170f169c0eaSGlenn Lagasse */ 171f169c0eaSGlenn Lagasse int 172f169c0eaSGlenn Lagasse be_unmount(nvlist_t *be_attrs) 173f169c0eaSGlenn Lagasse { 174f169c0eaSGlenn Lagasse char *be_name = NULL; 17589d19e00SAlexander Eremin char *be_name_mnt = NULL; 17689d19e00SAlexander Eremin char *ds = NULL; 177f169c0eaSGlenn Lagasse uint16_t flags = 0; 178f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 179f169c0eaSGlenn Lagasse 180f169c0eaSGlenn Lagasse /* Initialize libzfs handle */ 181f169c0eaSGlenn Lagasse if (!be_zfs_init()) 182f169c0eaSGlenn Lagasse return (BE_ERR_INIT); 183f169c0eaSGlenn Lagasse 184f169c0eaSGlenn Lagasse /* Get original BE name */ 185f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name) 186f169c0eaSGlenn Lagasse != 0) { 187f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: failed to lookup " 188f169c0eaSGlenn Lagasse "BE_ATTR_ORIG_BE_NAME attribute\n")); 189f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 190f169c0eaSGlenn Lagasse } 191f169c0eaSGlenn Lagasse 19289d19e00SAlexander Eremin /* Check if we have mountpoint argument instead of BE name */ 19389d19e00SAlexander Eremin if (be_name[0] == '/') { 19489d19e00SAlexander Eremin if ((ds = be_get_ds_from_dir(be_name)) != NULL) { 19589d19e00SAlexander Eremin if ((be_name_mnt = strrchr(ds, '/')) != NULL) { 19689d19e00SAlexander Eremin be_name = be_name_mnt + 1; 19789d19e00SAlexander Eremin } 19889d19e00SAlexander Eremin } else { 19989d19e00SAlexander Eremin be_print_err(gettext("be_unmount: no datasets mounted " 20089d19e00SAlexander Eremin "at '%s'\n"), be_name); 20189d19e00SAlexander Eremin return (BE_ERR_INVAL); 20289d19e00SAlexander Eremin } 20389d19e00SAlexander Eremin } 20489d19e00SAlexander Eremin 205f169c0eaSGlenn Lagasse /* Validate original BE name */ 206f169c0eaSGlenn Lagasse if (!be_valid_be_name(be_name)) { 207f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: invalid BE name %s\n"), 208f169c0eaSGlenn Lagasse be_name); 209f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 210f169c0eaSGlenn Lagasse } 211f169c0eaSGlenn Lagasse 212f169c0eaSGlenn Lagasse /* Get unmount flags */ 213f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 214f169c0eaSGlenn Lagasse BE_ATTR_UNMOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) { 215f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: failed to loookup " 216f169c0eaSGlenn Lagasse "BE_ATTR_UNMOUNT_FLAGS attribute\n")); 217f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 218f169c0eaSGlenn Lagasse } 219f169c0eaSGlenn Lagasse 220f169c0eaSGlenn Lagasse ret = _be_unmount(be_name, flags); 221f169c0eaSGlenn Lagasse 222f169c0eaSGlenn Lagasse be_zfs_fini(); 223f169c0eaSGlenn Lagasse 224f169c0eaSGlenn Lagasse return (ret); 225f169c0eaSGlenn Lagasse } 226f169c0eaSGlenn Lagasse 227f169c0eaSGlenn Lagasse /* ******************************************************************** */ 228f169c0eaSGlenn Lagasse /* Semi-Private Functions */ 229f169c0eaSGlenn Lagasse /* ******************************************************************** */ 230f169c0eaSGlenn Lagasse 231f169c0eaSGlenn Lagasse /* 232f169c0eaSGlenn Lagasse * Function: _be_mount 233f169c0eaSGlenn Lagasse * Description: Mounts a BE. If the altroot is not provided, this function 234f169c0eaSGlenn Lagasse * will generate a temporary mountpoint to mount the BE at. It 235f169c0eaSGlenn Lagasse * will return this temporary mountpoint to the caller via the 236f169c0eaSGlenn Lagasse * altroot reference pointer passed in. This returned value is 237f169c0eaSGlenn Lagasse * allocated on heap storage and is the repsonsibility of the 238f169c0eaSGlenn Lagasse * caller to free. 239f169c0eaSGlenn Lagasse * Parameters: 240f169c0eaSGlenn Lagasse * be_name - pointer to name of BE to mount. 241f169c0eaSGlenn Lagasse * altroot - reference pointer to altroot of where to mount BE. 242f169c0eaSGlenn Lagasse * flags - flag indicating special handling for mounting the BE 243f169c0eaSGlenn Lagasse * Return: 244f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 245f169c0eaSGlenn Lagasse * be_errno_t - Failure 246f169c0eaSGlenn Lagasse * Scope: 247f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 248f169c0eaSGlenn Lagasse */ 249f169c0eaSGlenn Lagasse int 250f169c0eaSGlenn Lagasse _be_mount(char *be_name, char **altroot, int flags) 251f169c0eaSGlenn Lagasse { 252f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 253f169c0eaSGlenn Lagasse be_mount_data_t md = { 0 }; 254f169c0eaSGlenn Lagasse zfs_handle_t *zhp; 255f169c0eaSGlenn Lagasse char obe_root_ds[MAXPATHLEN]; 256f169c0eaSGlenn Lagasse char *mp = NULL; 257f169c0eaSGlenn Lagasse char *tmp_altroot = NULL; 258f169c0eaSGlenn Lagasse int ret = BE_SUCCESS, err = 0; 259f169c0eaSGlenn Lagasse uuid_t uu = { 0 }; 260f169c0eaSGlenn Lagasse boolean_t gen_tmp_altroot = B_FALSE; 261f169c0eaSGlenn Lagasse 262f169c0eaSGlenn Lagasse if (be_name == NULL || altroot == NULL) 263f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 264f169c0eaSGlenn Lagasse 265f169c0eaSGlenn Lagasse /* Set be_name as obe_name in bt structure */ 266f169c0eaSGlenn Lagasse bt.obe_name = be_name; 267f169c0eaSGlenn Lagasse 268f169c0eaSGlenn Lagasse /* Find which zpool obe_name lives in */ 269f169c0eaSGlenn Lagasse if ((err = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 270f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: failed to " 271f169c0eaSGlenn Lagasse "find zpool for BE (%s)\n"), bt.obe_name); 272f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT); 273f169c0eaSGlenn Lagasse } else if (err < 0) { 274f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: zpool_iter failed: %s\n"), 275f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 276f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 277f169c0eaSGlenn Lagasse } 278f169c0eaSGlenn Lagasse 279f169c0eaSGlenn Lagasse /* Generate string for obe_name's root dataset */ 280f169c0eaSGlenn Lagasse be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds, 281f169c0eaSGlenn Lagasse sizeof (obe_root_ds)); 282f169c0eaSGlenn Lagasse bt.obe_root_ds = obe_root_ds; 283f169c0eaSGlenn Lagasse 284f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 285f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 286f169c0eaSGlenn Lagasse NULL) { 287f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: failed to " 288f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), bt.obe_root_ds, 289f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 290f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 291f169c0eaSGlenn Lagasse } 292f169c0eaSGlenn Lagasse 293f169c0eaSGlenn Lagasse /* Make sure BE's root dataset isn't already mounted somewhere */ 294f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, &mp)) { 295f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 296f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: %s is already mounted " 297f169c0eaSGlenn Lagasse "at %s\n"), bt.obe_name, mp != NULL ? mp : ""); 298f169c0eaSGlenn Lagasse free(mp); 299f169c0eaSGlenn Lagasse return (BE_ERR_MOUNTED); 300f169c0eaSGlenn Lagasse } 301f169c0eaSGlenn Lagasse 302f169c0eaSGlenn Lagasse /* 303f169c0eaSGlenn Lagasse * Fix this BE's mountpoint if its root dataset isn't set to 304f169c0eaSGlenn Lagasse * either 'legacy' or '/'. 305f169c0eaSGlenn Lagasse */ 306f169c0eaSGlenn Lagasse if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) { 307f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: mountpoint check " 308f169c0eaSGlenn Lagasse "failed for %s\n"), bt.obe_root_ds); 309f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 310f169c0eaSGlenn Lagasse return (ret); 311f169c0eaSGlenn Lagasse } 312f169c0eaSGlenn Lagasse 313f169c0eaSGlenn Lagasse /* 314f169c0eaSGlenn Lagasse * If altroot not provided, create a temporary alternate root 315f169c0eaSGlenn Lagasse * to mount on 316f169c0eaSGlenn Lagasse */ 317f169c0eaSGlenn Lagasse if (*altroot == NULL) { 318f169c0eaSGlenn Lagasse if ((ret = be_make_tmp_mountpoint(&tmp_altroot)) 319f169c0eaSGlenn Lagasse != BE_SUCCESS) { 320f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: failed to " 321f169c0eaSGlenn Lagasse "make temporary mountpoint\n")); 322f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 323f169c0eaSGlenn Lagasse return (ret); 324f169c0eaSGlenn Lagasse } 325f169c0eaSGlenn Lagasse gen_tmp_altroot = B_TRUE; 326f169c0eaSGlenn Lagasse } else { 327f169c0eaSGlenn Lagasse tmp_altroot = *altroot; 328f169c0eaSGlenn Lagasse } 329f169c0eaSGlenn Lagasse 3307e0e2549SAlexander Eremin md.altroot = tmp_altroot; 3317e0e2549SAlexander Eremin md.shared_fs = flags & BE_MOUNT_FLAG_SHARED_FS; 3327e0e2549SAlexander Eremin md.shared_rw = flags & BE_MOUNT_FLAG_SHARED_RW; 3337e0e2549SAlexander Eremin 334f169c0eaSGlenn Lagasse /* Mount the BE's root file system */ 3357e0e2549SAlexander Eremin if (getzoneid() == GLOBAL_ZONEID) { 3367e0e2549SAlexander Eremin if ((ret = be_mount_root(zhp, tmp_altroot)) != BE_SUCCESS) { 3377e0e2549SAlexander Eremin be_print_err(gettext("be_mount: failed to " 3387e0e2549SAlexander Eremin "mount BE root file system\n")); 3397e0e2549SAlexander Eremin if (gen_tmp_altroot) 3407e0e2549SAlexander Eremin free(tmp_altroot); 3417e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3427e0e2549SAlexander Eremin return (ret); 3437e0e2549SAlexander Eremin } 3447e0e2549SAlexander Eremin } else { 3457e0e2549SAlexander Eremin /* Legacy mount the zone root dataset */ 3467e0e2549SAlexander Eremin if ((ret = be_mount_zone_root(zhp, &md)) != BE_SUCCESS) { 3477e0e2549SAlexander Eremin be_print_err(gettext("be_mount: failed to " 3487e0e2549SAlexander Eremin "mount BE zone root file system\n")); 3497e0e2549SAlexander Eremin free(md.altroot); 3507e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3517e0e2549SAlexander Eremin return (ret); 3527e0e2549SAlexander Eremin } 353f169c0eaSGlenn Lagasse } 354f169c0eaSGlenn Lagasse 355f169c0eaSGlenn Lagasse /* Iterate through BE's children filesystems */ 356f169c0eaSGlenn Lagasse if ((err = zfs_iter_filesystems(zhp, be_mount_callback, 357f169c0eaSGlenn Lagasse tmp_altroot)) != 0) { 358f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount: failed to " 359f169c0eaSGlenn Lagasse "mount BE (%s) on %s\n"), bt.obe_name, tmp_altroot); 360f169c0eaSGlenn Lagasse if (gen_tmp_altroot) 361f169c0eaSGlenn Lagasse free(tmp_altroot); 362f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 363f169c0eaSGlenn Lagasse return (err); 364f169c0eaSGlenn Lagasse } 365f169c0eaSGlenn Lagasse 366f169c0eaSGlenn Lagasse /* 367f169c0eaSGlenn Lagasse * Mount shared file systems if mount flag says so. 368f169c0eaSGlenn Lagasse */ 369f169c0eaSGlenn Lagasse if (md.shared_fs) { 370f169c0eaSGlenn Lagasse /* 371f169c0eaSGlenn Lagasse * Mount all ZFS file systems not under the BE's root dataset 372f169c0eaSGlenn Lagasse */ 373f169c0eaSGlenn Lagasse (void) zpool_iter(g_zfs, zpool_shared_fs_callback, &md); 374f169c0eaSGlenn Lagasse 375f169c0eaSGlenn Lagasse /* TODO: Mount all non-ZFS file systems - Not supported yet */ 376f169c0eaSGlenn Lagasse } 377f169c0eaSGlenn Lagasse 378f169c0eaSGlenn Lagasse /* 379f169c0eaSGlenn Lagasse * If we're in the global zone and the global zone has a valid uuid, 380f169c0eaSGlenn Lagasse * mount all supported non-global zones. 381f169c0eaSGlenn Lagasse */ 382f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID && 383f169c0eaSGlenn Lagasse !(flags & BE_MOUNT_FLAG_NO_ZONES) && 384f169c0eaSGlenn Lagasse be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) { 38540ccc6adSAlexander Eremin if (be_mount_zones(zhp, &md) != BE_SUCCESS) { 38640ccc6adSAlexander Eremin ret = BE_ERR_NO_MOUNTED_ZONE; 387f169c0eaSGlenn Lagasse } 388f169c0eaSGlenn Lagasse } 389f169c0eaSGlenn Lagasse 390f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 391f169c0eaSGlenn Lagasse 392f169c0eaSGlenn Lagasse /* 393f169c0eaSGlenn Lagasse * If a NULL altroot was passed in, pass the generated altroot 394f169c0eaSGlenn Lagasse * back to the caller in altroot. 395f169c0eaSGlenn Lagasse */ 39640ccc6adSAlexander Eremin if (gen_tmp_altroot) { 39740ccc6adSAlexander Eremin if (ret == BE_SUCCESS || ret == BE_ERR_NO_MOUNTED_ZONE) 39840ccc6adSAlexander Eremin *altroot = tmp_altroot; 39940ccc6adSAlexander Eremin else 40040ccc6adSAlexander Eremin free(tmp_altroot); 40140ccc6adSAlexander Eremin } 402f169c0eaSGlenn Lagasse 40340ccc6adSAlexander Eremin return (ret); 404f169c0eaSGlenn Lagasse } 405f169c0eaSGlenn Lagasse 406f169c0eaSGlenn Lagasse /* 407f169c0eaSGlenn Lagasse * Function: _be_unmount 408f169c0eaSGlenn Lagasse * Description: Unmount a BE. 409f169c0eaSGlenn Lagasse * Parameters: 410f169c0eaSGlenn Lagasse * be_name - pointer to name of BE to unmount. 411f169c0eaSGlenn Lagasse * flags - flags for unmounting the BE. 412f169c0eaSGlenn Lagasse * Returns: 413f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 414f169c0eaSGlenn Lagasse * be_errno_t - Failure 415f169c0eaSGlenn Lagasse * Scope: 416f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 417f169c0eaSGlenn Lagasse */ 418f169c0eaSGlenn Lagasse int 419f169c0eaSGlenn Lagasse _be_unmount(char *be_name, int flags) 420f169c0eaSGlenn Lagasse { 421f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 422f169c0eaSGlenn Lagasse be_unmount_data_t ud = { 0 }; 423f169c0eaSGlenn Lagasse zfs_handle_t *zhp; 424f169c0eaSGlenn Lagasse uuid_t uu = { 0 }; 425f169c0eaSGlenn Lagasse char obe_root_ds[MAXPATHLEN]; 426f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 427f169c0eaSGlenn Lagasse char *mp = NULL; 428f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 429f169c0eaSGlenn Lagasse int zret = 0; 430f169c0eaSGlenn Lagasse 431f169c0eaSGlenn Lagasse if (be_name == NULL) 432f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 433f169c0eaSGlenn Lagasse 434f169c0eaSGlenn Lagasse /* Set be_name as obe_name in bt structure */ 435f169c0eaSGlenn Lagasse bt.obe_name = be_name; 436f169c0eaSGlenn Lagasse 437f169c0eaSGlenn Lagasse /* Find which zpool obe_name lives in */ 438f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 439f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: failed to " 440f169c0eaSGlenn Lagasse "find zpool for BE (%s)\n"), bt.obe_name); 441f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT); 442f169c0eaSGlenn Lagasse } else if (zret < 0) { 443f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: " 444f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"), 445f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 446f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 447f169c0eaSGlenn Lagasse return (ret); 448f169c0eaSGlenn Lagasse } 449f169c0eaSGlenn Lagasse 450f169c0eaSGlenn Lagasse /* Generate string for obe_name's root dataset */ 451f169c0eaSGlenn Lagasse be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds, 452f169c0eaSGlenn Lagasse sizeof (obe_root_ds)); 453f169c0eaSGlenn Lagasse bt.obe_root_ds = obe_root_ds; 454f169c0eaSGlenn Lagasse 455f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 456f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 457f169c0eaSGlenn Lagasse NULL) { 458f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: failed to " 459f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), bt.obe_root_ds, 460f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 461f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 462f169c0eaSGlenn Lagasse return (ret); 463f169c0eaSGlenn Lagasse } 464f169c0eaSGlenn Lagasse 465f169c0eaSGlenn Lagasse /* Make sure BE's root dataset is mounted somewhere */ 466f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &mp)) { 467f169c0eaSGlenn Lagasse 468f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: " 469f169c0eaSGlenn Lagasse "(%s) not mounted\n"), bt.obe_name); 470f169c0eaSGlenn Lagasse 471f169c0eaSGlenn Lagasse /* 472f169c0eaSGlenn Lagasse * BE is not mounted, fix this BE's mountpoint if its root 473f169c0eaSGlenn Lagasse * dataset isn't set to either 'legacy' or '/'. 474f169c0eaSGlenn Lagasse */ 475f169c0eaSGlenn Lagasse if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) { 476f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: mountpoint check " 477f169c0eaSGlenn Lagasse "failed for %s\n"), bt.obe_root_ds); 478f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 479f169c0eaSGlenn Lagasse return (ret); 480f169c0eaSGlenn Lagasse } 481f169c0eaSGlenn Lagasse 482f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 48389d19e00SAlexander Eremin return (BE_ERR_NOTMOUNTED); 484f169c0eaSGlenn Lagasse } 485f169c0eaSGlenn Lagasse 486f169c0eaSGlenn Lagasse /* 487f169c0eaSGlenn Lagasse * If we didn't get a mountpoint from the zfs_is_mounted call, 488f169c0eaSGlenn Lagasse * try and get it from its property. 489f169c0eaSGlenn Lagasse */ 490f169c0eaSGlenn Lagasse if (mp == NULL) { 491f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 492f169c0eaSGlenn Lagasse sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 493f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: failed to " 494f169c0eaSGlenn Lagasse "get mountpoint of (%s)\n"), bt.obe_name); 495f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 496f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 497f169c0eaSGlenn Lagasse } 498f169c0eaSGlenn Lagasse } else { 499f169c0eaSGlenn Lagasse (void) strlcpy(mountpoint, mp, sizeof (mountpoint)); 500f169c0eaSGlenn Lagasse free(mp); 501f169c0eaSGlenn Lagasse } 502f169c0eaSGlenn Lagasse 503f169c0eaSGlenn Lagasse /* If BE mounted as current root, fail */ 504f169c0eaSGlenn Lagasse if (strcmp(mountpoint, "/") == 0) { 505f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: " 506f169c0eaSGlenn Lagasse "cannot unmount currently running BE\n")); 507f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 508f169c0eaSGlenn Lagasse return (BE_ERR_UMOUNT_CURR_BE); 509f169c0eaSGlenn Lagasse } 510f169c0eaSGlenn Lagasse 511f169c0eaSGlenn Lagasse ud.altroot = mountpoint; 512f169c0eaSGlenn Lagasse ud.force = flags & BE_UNMOUNT_FLAG_FORCE; 513f169c0eaSGlenn Lagasse 514f169c0eaSGlenn Lagasse /* Unmount all supported non-global zones if we're in the global zone */ 515f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID && 516f169c0eaSGlenn Lagasse be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) { 517f169c0eaSGlenn Lagasse if ((ret = be_unmount_zones(&ud)) != BE_SUCCESS) { 518f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 519f169c0eaSGlenn Lagasse return (ret); 520f169c0eaSGlenn Lagasse } 521f169c0eaSGlenn Lagasse } 522f169c0eaSGlenn Lagasse 523f169c0eaSGlenn Lagasse /* TODO: Unmount all non-ZFS file systems - Not supported yet */ 524f169c0eaSGlenn Lagasse 525f169c0eaSGlenn Lagasse /* Unmount all ZFS file systems not under the BE root dataset */ 526f169c0eaSGlenn Lagasse if ((ret = unmount_shared_fs(&ud)) != BE_SUCCESS) { 527f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: failed to " 528f169c0eaSGlenn Lagasse "unmount shared file systems\n")); 529f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 530f169c0eaSGlenn Lagasse return (ret); 531f169c0eaSGlenn Lagasse } 532f169c0eaSGlenn Lagasse 533f169c0eaSGlenn Lagasse /* Unmount all children datasets under the BE's root dataset */ 534f169c0eaSGlenn Lagasse if ((zret = zfs_iter_filesystems(zhp, be_unmount_callback, 535f169c0eaSGlenn Lagasse &ud)) != 0) { 536f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount: failed to " 537f169c0eaSGlenn Lagasse "unmount BE (%s)\n"), bt.obe_name); 538f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 539f169c0eaSGlenn Lagasse return (zret); 540f169c0eaSGlenn Lagasse } 541f169c0eaSGlenn Lagasse 542f169c0eaSGlenn Lagasse /* Unmount this BE's root filesystem */ 5437e0e2549SAlexander Eremin if (getzoneid() == GLOBAL_ZONEID) { 5447e0e2549SAlexander Eremin if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) { 5457e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 5467e0e2549SAlexander Eremin return (ret); 5477e0e2549SAlexander Eremin } 5487e0e2549SAlexander Eremin } else { 5497e0e2549SAlexander Eremin if ((ret = be_unmount_zone_root(zhp, &ud)) != BE_SUCCESS) { 5507e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 5517e0e2549SAlexander Eremin return (ret); 5527e0e2549SAlexander Eremin } 553f169c0eaSGlenn Lagasse } 554f169c0eaSGlenn Lagasse 555f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 556f169c0eaSGlenn Lagasse 557f169c0eaSGlenn Lagasse return (BE_SUCCESS); 558f169c0eaSGlenn Lagasse } 559f169c0eaSGlenn Lagasse 560f169c0eaSGlenn Lagasse /* 561f169c0eaSGlenn Lagasse * Function: be_mount_zone_root 562f169c0eaSGlenn Lagasse * Description: Mounts the zone root dataset for a zone. 563f169c0eaSGlenn Lagasse * Parameters: 564f169c0eaSGlenn Lagasse * zfs - zfs_handle_t pointer to zone root dataset 565f169c0eaSGlenn Lagasse * md - be_mount_data_t pointer to data for zone to be mounted 566f169c0eaSGlenn Lagasse * Returns: 567f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 568f169c0eaSGlenn Lagasse * be_errno_t - Failure 569f169c0eaSGlenn Lagasse * Scope: 570f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 571f169c0eaSGlenn Lagasse */ 572f169c0eaSGlenn Lagasse int 573f169c0eaSGlenn Lagasse be_mount_zone_root(zfs_handle_t *zhp, be_mount_data_t *md) 574f169c0eaSGlenn Lagasse { 5757e0e2549SAlexander Eremin struct stat buf; 576f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 577f169c0eaSGlenn Lagasse int err = 0; 578f169c0eaSGlenn Lagasse 579f169c0eaSGlenn Lagasse /* Get mountpoint property of dataset */ 580f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 581f169c0eaSGlenn Lagasse sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 582f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_zone_root: failed to " 583f169c0eaSGlenn Lagasse "get mountpoint property for %s: %s\n"), zfs_get_name(zhp), 584f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 585f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 586f169c0eaSGlenn Lagasse } 587f169c0eaSGlenn Lagasse 588f169c0eaSGlenn Lagasse /* 589f169c0eaSGlenn Lagasse * Make sure zone's root dataset is set to 'legacy'. This is 590f169c0eaSGlenn Lagasse * currently a requirement in this implementation of zones 591f169c0eaSGlenn Lagasse * support. 592f169c0eaSGlenn Lagasse */ 593f169c0eaSGlenn Lagasse if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) { 594f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_zone_root: " 595f169c0eaSGlenn Lagasse "zone root dataset mountpoint is not 'legacy'\n")); 596f169c0eaSGlenn Lagasse return (BE_ERR_ZONE_ROOT_NOT_LEGACY); 597f169c0eaSGlenn Lagasse } 598f169c0eaSGlenn Lagasse 5997e0e2549SAlexander Eremin /* Create the mountpoint if it doesn't exist */ 6007e0e2549SAlexander Eremin if (lstat(md->altroot, &buf) != 0) { 6017e0e2549SAlexander Eremin if (mkdirp(md->altroot, 0755) != 0) { 6027e0e2549SAlexander Eremin err = errno; 6037e0e2549SAlexander Eremin be_print_err(gettext("be_mount_zone_root: failed " 6047e0e2549SAlexander Eremin "to create mountpoint %s\n"), md->altroot); 6057e0e2549SAlexander Eremin return (errno_to_be_err(err)); 6067e0e2549SAlexander Eremin } 6077e0e2549SAlexander Eremin } 6087e0e2549SAlexander Eremin 609f169c0eaSGlenn Lagasse /* 610f169c0eaSGlenn Lagasse * Legacy mount the zone root dataset. 611f169c0eaSGlenn Lagasse * 612f169c0eaSGlenn Lagasse * As a workaround for 6176743, we mount the zone's root with the 613f169c0eaSGlenn Lagasse * MS_OVERLAY option in case an alternate BE is mounted, and we're 614f169c0eaSGlenn Lagasse * mounting the root for the zone from the current BE here. When an 615f169c0eaSGlenn Lagasse * alternate BE is mounted, it ties up the zone's zoneroot directory 616f169c0eaSGlenn Lagasse * for the current BE since the zone's zonepath is loopback mounted 617f169c0eaSGlenn Lagasse * from the current BE. 618f169c0eaSGlenn Lagasse * 619f169c0eaSGlenn Lagasse * TODO: The MS_OVERLAY option needs to be removed when 6176743 620f169c0eaSGlenn Lagasse * is fixed. 621f169c0eaSGlenn Lagasse */ 622f169c0eaSGlenn Lagasse if (mount(zfs_get_name(zhp), md->altroot, MS_OVERLAY, MNTTYPE_ZFS, 623f169c0eaSGlenn Lagasse NULL, 0, NULL, 0) != 0) { 624f169c0eaSGlenn Lagasse err = errno; 625f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_zone_root: failed to " 626f169c0eaSGlenn Lagasse "legacy mount zone root dataset (%s) at %s\n"), 627f169c0eaSGlenn Lagasse zfs_get_name(zhp), md->altroot); 628f169c0eaSGlenn Lagasse return (errno_to_be_err(err)); 629f169c0eaSGlenn Lagasse } 630f169c0eaSGlenn Lagasse 631f169c0eaSGlenn Lagasse return (BE_SUCCESS); 632f169c0eaSGlenn Lagasse } 633f169c0eaSGlenn Lagasse 634f169c0eaSGlenn Lagasse /* 635f169c0eaSGlenn Lagasse * Function: be_unmount_zone_root 636f169c0eaSGlenn Lagasse * Description: Unmounts the zone root dataset for a zone. 637f169c0eaSGlenn Lagasse * Parameters: 638f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to zone root dataset 639f169c0eaSGlenn Lagasse * ud - be_unmount_data_t pointer to data for zone to be unmounted 640f169c0eaSGlenn Lagasse * Returns: 641f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 642f169c0eaSGlenn Lagasse * be_errno_t - Failure 643f169c0eaSGlenn Lagasse * Scope: 644f169c0eaSGlenn Lagasse * Semi-private (library wise use only) 645f169c0eaSGlenn Lagasse */ 646f169c0eaSGlenn Lagasse int 647f169c0eaSGlenn Lagasse be_unmount_zone_root(zfs_handle_t *zhp, be_unmount_data_t *ud) 648f169c0eaSGlenn Lagasse { 649f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 650f169c0eaSGlenn Lagasse 651f169c0eaSGlenn Lagasse /* Unmount the dataset */ 652f169c0eaSGlenn Lagasse if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) { 653f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_zone_root: failed to " 654f169c0eaSGlenn Lagasse "unmount zone root dataset %s: %s\n"), zfs_get_name(zhp), 655f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 656f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 657f169c0eaSGlenn Lagasse } 658f169c0eaSGlenn Lagasse 659f169c0eaSGlenn Lagasse /* Get the current mountpoint property for the zone root dataset */ 660f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 661f169c0eaSGlenn Lagasse sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 662f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_zone_root: failed to " 663f169c0eaSGlenn Lagasse "get mountpoint property for zone root dataset (%s): %s\n"), 664f169c0eaSGlenn Lagasse zfs_get_name(zhp), libzfs_error_description(g_zfs)); 665f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 666f169c0eaSGlenn Lagasse } 667f169c0eaSGlenn Lagasse 668f169c0eaSGlenn Lagasse /* If mountpoint not already set to 'legacy', set it to 'legacy' */ 669f169c0eaSGlenn Lagasse if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) { 670f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 671f169c0eaSGlenn Lagasse ZFS_MOUNTPOINT_LEGACY) != 0) { 672f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_zone_root: " 673f169c0eaSGlenn Lagasse "failed to set mountpoint of zone root dataset " 674f169c0eaSGlenn Lagasse "%s to 'legacy': %s\n"), zfs_get_name(zhp), 675f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 676f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 677f169c0eaSGlenn Lagasse } 678f169c0eaSGlenn Lagasse } 679f169c0eaSGlenn Lagasse 680f169c0eaSGlenn Lagasse return (BE_SUCCESS); 681f169c0eaSGlenn Lagasse } 682f169c0eaSGlenn Lagasse 683f169c0eaSGlenn Lagasse /* 684f169c0eaSGlenn Lagasse * Function: be_get_legacy_fs 685f169c0eaSGlenn Lagasse * Description: This function iterates through all non-shared file systems 686f169c0eaSGlenn Lagasse * of a BE and finds the ones with a legacy mountpoint. For 687f169c0eaSGlenn Lagasse * those file systems, it reads the BE's vfstab to get the 688f169c0eaSGlenn Lagasse * mountpoint. If found, it adds that file system to the 689f169c0eaSGlenn Lagasse * be_fs_list_data_t passed in. 690f169c0eaSGlenn Lagasse * 691f169c0eaSGlenn Lagasse * This function can be used to gather legacy mounted file systems 692f169c0eaSGlenn Lagasse * for both global BEs and non-global zone BEs. To get data for 693f169c0eaSGlenn Lagasse * a non-global zone BE, the zoneroot_ds and zoneroot parameters 694f169c0eaSGlenn Lagasse * will be specified, otherwise they should be set to NULL. 695f169c0eaSGlenn Lagasse * Parameters: 696f169c0eaSGlenn Lagasse * be_name - global BE name from which to get legacy file 697f169c0eaSGlenn Lagasse * system list. 698f169c0eaSGlenn Lagasse * be_root_ds - root dataset of global BE. 699f169c0eaSGlenn Lagasse * zoneroot_ds - root dataset of zone. 700f169c0eaSGlenn Lagasse * zoneroot - zoneroot path of zone. 701f169c0eaSGlenn Lagasse * fld - be_fs_list_data_t pointer. 702f169c0eaSGlenn Lagasse * Returns: 703f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 704f169c0eaSGlenn Lagasse * be_errno_t - Failure 705f169c0eaSGlenn Lagasse * Scope: 706f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 707f169c0eaSGlenn Lagasse */ 708f169c0eaSGlenn Lagasse int 709f169c0eaSGlenn Lagasse be_get_legacy_fs(char *be_name, char *be_root_ds, char *zoneroot_ds, 710f169c0eaSGlenn Lagasse char *zoneroot, be_fs_list_data_t *fld) 711f169c0eaSGlenn Lagasse { 712f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 713f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 714f169c0eaSGlenn Lagasse boolean_t mounted_here = B_FALSE; 715f169c0eaSGlenn Lagasse boolean_t zone_mounted_here = B_FALSE; 716f169c0eaSGlenn Lagasse int ret = BE_SUCCESS, err = 0; 717f169c0eaSGlenn Lagasse 718f169c0eaSGlenn Lagasse if (be_name == NULL || be_root_ds == NULL || fld == NULL) 719f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 720f169c0eaSGlenn Lagasse 721f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 722f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) 723f169c0eaSGlenn Lagasse == NULL) { 724f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: failed to " 725f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), be_root_ds, 726f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 727f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 728f169c0eaSGlenn Lagasse return (ret); 729f169c0eaSGlenn Lagasse } 730f169c0eaSGlenn Lagasse 731f169c0eaSGlenn Lagasse /* If BE is not already mounted, mount it. */ 732f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &fld->altroot)) { 733f169c0eaSGlenn Lagasse if ((ret = _be_mount(be_name, &fld->altroot, 734f169c0eaSGlenn Lagasse zoneroot_ds ? BE_MOUNT_FLAG_NULL : 735f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 736f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: " 737f169c0eaSGlenn Lagasse "failed to mount BE %s\n"), be_name); 738f169c0eaSGlenn Lagasse goto cleanup; 739f169c0eaSGlenn Lagasse } 740f169c0eaSGlenn Lagasse 741f169c0eaSGlenn Lagasse mounted_here = B_TRUE; 742f169c0eaSGlenn Lagasse } else if (fld->altroot == NULL) { 743f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: failed to " 744f169c0eaSGlenn Lagasse "get altroot of mounted BE %s: %s\n"), 745f169c0eaSGlenn Lagasse be_name, libzfs_error_description(g_zfs)); 746f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 747f169c0eaSGlenn Lagasse goto cleanup; 748f169c0eaSGlenn Lagasse } 749f169c0eaSGlenn Lagasse 750f169c0eaSGlenn Lagasse /* 751f169c0eaSGlenn Lagasse * If a zone root dataset was passed in, we're wanting to get 752f169c0eaSGlenn Lagasse * legacy mounted file systems for that zone, not the global 753f169c0eaSGlenn Lagasse * BE. 754f169c0eaSGlenn Lagasse */ 755f169c0eaSGlenn Lagasse if (zoneroot_ds != NULL) { 756f169c0eaSGlenn Lagasse be_mount_data_t zone_md = { 0 }; 757f169c0eaSGlenn Lagasse 758f169c0eaSGlenn Lagasse /* Close off handle to global BE's root dataset */ 759f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 760f169c0eaSGlenn Lagasse 761f169c0eaSGlenn Lagasse /* Get handle to zone's root dataset */ 762f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, zoneroot_ds, 763f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 764f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: failed to " 765f169c0eaSGlenn Lagasse "open zone BE root dataset (%s): %s\n"), 766f169c0eaSGlenn Lagasse zoneroot_ds, libzfs_error_description(g_zfs)); 767f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 768f169c0eaSGlenn Lagasse goto cleanup; 769f169c0eaSGlenn Lagasse } 770f169c0eaSGlenn Lagasse 771f169c0eaSGlenn Lagasse /* Make sure the zone we're looking for is mounted */ 772f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &zone_md.altroot)) { 773f169c0eaSGlenn Lagasse char zone_altroot[MAXPATHLEN]; 774f169c0eaSGlenn Lagasse 775f169c0eaSGlenn Lagasse /* Generate alternate root path for zone */ 776f169c0eaSGlenn Lagasse (void) snprintf(zone_altroot, sizeof (zone_altroot), 777f169c0eaSGlenn Lagasse "%s%s", fld->altroot, zoneroot); 778f169c0eaSGlenn Lagasse if ((zone_md.altroot = strdup(zone_altroot)) == NULL) { 779f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: " 780f169c0eaSGlenn Lagasse "memory allocation failed\n")); 781f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 782f169c0eaSGlenn Lagasse goto cleanup; 783f169c0eaSGlenn Lagasse } 784f169c0eaSGlenn Lagasse 785f169c0eaSGlenn Lagasse if ((ret = be_mount_zone_root(zhp, &zone_md)) 786f169c0eaSGlenn Lagasse != BE_SUCCESS) { 787f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: " 788f169c0eaSGlenn Lagasse "failed to mount zone root %s\n"), 789f169c0eaSGlenn Lagasse zoneroot_ds); 790f169c0eaSGlenn Lagasse free(zone_md.altroot); 791f169c0eaSGlenn Lagasse zone_md.altroot = NULL; 792f169c0eaSGlenn Lagasse goto cleanup; 793f169c0eaSGlenn Lagasse } 794f169c0eaSGlenn Lagasse zone_mounted_here = B_TRUE; 795f169c0eaSGlenn Lagasse } 796f169c0eaSGlenn Lagasse 797f169c0eaSGlenn Lagasse free(fld->altroot); 798f169c0eaSGlenn Lagasse fld->altroot = zone_md.altroot; 799f169c0eaSGlenn Lagasse } 800f169c0eaSGlenn Lagasse 801f169c0eaSGlenn Lagasse /* 802f169c0eaSGlenn Lagasse * If the root dataset is in the vfstab with a mountpoint of "/", 803f169c0eaSGlenn Lagasse * add it to the list 804f169c0eaSGlenn Lagasse */ 805f169c0eaSGlenn Lagasse if (get_mountpoint_from_vfstab(fld->altroot, zfs_get_name(zhp), 806f169c0eaSGlenn Lagasse mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS) { 807f169c0eaSGlenn Lagasse if (strcmp(mountpoint, "/") == 0) { 808f169c0eaSGlenn Lagasse if (add_to_fs_list(fld, zfs_get_name(zhp)) 809f169c0eaSGlenn Lagasse != BE_SUCCESS) { 810f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: " 811f169c0eaSGlenn Lagasse "failed to add %s to fs list\n"), 812f169c0eaSGlenn Lagasse zfs_get_name(zhp)); 813f169c0eaSGlenn Lagasse ret = BE_ERR_INVAL; 814f169c0eaSGlenn Lagasse goto cleanup; 815f169c0eaSGlenn Lagasse } 816f169c0eaSGlenn Lagasse } 817f169c0eaSGlenn Lagasse } 818f169c0eaSGlenn Lagasse 819f169c0eaSGlenn Lagasse /* Iterate subordinate file systems looking for legacy mounts */ 820f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback, 821f169c0eaSGlenn Lagasse fld)) != 0) { 822f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: " 823f169c0eaSGlenn Lagasse "failed to iterate %s to get legacy mounts\n"), 824f169c0eaSGlenn Lagasse zfs_get_name(zhp)); 825f169c0eaSGlenn Lagasse } 826f169c0eaSGlenn Lagasse 827f169c0eaSGlenn Lagasse cleanup: 828f169c0eaSGlenn Lagasse /* If we mounted the zone BE, unmount it */ 829f169c0eaSGlenn Lagasse if (zone_mounted_here) { 830f169c0eaSGlenn Lagasse be_unmount_data_t zone_ud = { 0 }; 831f169c0eaSGlenn Lagasse 832f169c0eaSGlenn Lagasse zone_ud.altroot = fld->altroot; 833f169c0eaSGlenn Lagasse zone_ud.force = B_TRUE; 834f169c0eaSGlenn Lagasse if ((err = be_unmount_zone_root(zhp, &zone_ud)) != BE_SUCCESS) { 835f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: " 836f169c0eaSGlenn Lagasse "failed to unmount zone root %s\n"), 837f169c0eaSGlenn Lagasse zoneroot_ds); 838f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS) 839f169c0eaSGlenn Lagasse ret = err; 840f169c0eaSGlenn Lagasse } 841f169c0eaSGlenn Lagasse } 842f169c0eaSGlenn Lagasse 843f169c0eaSGlenn Lagasse /* If we mounted this BE, unmount it */ 844f169c0eaSGlenn Lagasse if (mounted_here) { 845f169c0eaSGlenn Lagasse if ((err = _be_unmount(be_name, 0)) != BE_SUCCESS) { 846f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs: " 847f169c0eaSGlenn Lagasse "failed to unmount %s\n"), be_name); 848f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS) 849f169c0eaSGlenn Lagasse ret = err; 850f169c0eaSGlenn Lagasse } 851f169c0eaSGlenn Lagasse } 852f169c0eaSGlenn Lagasse 853f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 854f169c0eaSGlenn Lagasse 855f169c0eaSGlenn Lagasse free(fld->altroot); 856f169c0eaSGlenn Lagasse fld->altroot = NULL; 857f169c0eaSGlenn Lagasse 858f169c0eaSGlenn Lagasse return (ret); 859f169c0eaSGlenn Lagasse } 860f169c0eaSGlenn Lagasse 861f169c0eaSGlenn Lagasse /* 862f169c0eaSGlenn Lagasse * Function: be_free_fs_list 863f169c0eaSGlenn Lagasse * Description: Function used to free the members of a be_fs_list_data_t 864f169c0eaSGlenn Lagasse * structure. 865f169c0eaSGlenn Lagasse * Parameters: 866f169c0eaSGlenn Lagasse * fld - be_fs_list_data_t pointer to free. 867f169c0eaSGlenn Lagasse * Returns: 868f169c0eaSGlenn Lagasse * None 869f169c0eaSGlenn Lagasse * Scope: 870f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 871f169c0eaSGlenn Lagasse */ 872f169c0eaSGlenn Lagasse void 873f169c0eaSGlenn Lagasse be_free_fs_list(be_fs_list_data_t *fld) 874f169c0eaSGlenn Lagasse { 875f169c0eaSGlenn Lagasse int i; 876f169c0eaSGlenn Lagasse 877f169c0eaSGlenn Lagasse if (fld == NULL) 878f169c0eaSGlenn Lagasse return; 879f169c0eaSGlenn Lagasse 880f169c0eaSGlenn Lagasse free(fld->altroot); 881f169c0eaSGlenn Lagasse 882f169c0eaSGlenn Lagasse if (fld->fs_list == NULL) 883f169c0eaSGlenn Lagasse return; 884f169c0eaSGlenn Lagasse 885f169c0eaSGlenn Lagasse for (i = 0; i < fld->fs_num; i++) 886f169c0eaSGlenn Lagasse free(fld->fs_list[i]); 887f169c0eaSGlenn Lagasse 888f169c0eaSGlenn Lagasse free(fld->fs_list); 889f169c0eaSGlenn Lagasse } 890f169c0eaSGlenn Lagasse 891f169c0eaSGlenn Lagasse /* 892f169c0eaSGlenn Lagasse * Function: be_get_ds_from_dir(char *dir) 893f169c0eaSGlenn Lagasse * Description: Given a directory path, find the underlying dataset mounted 894f169c0eaSGlenn Lagasse * at that directory path if there is one. The returned name 895f169c0eaSGlenn Lagasse * is allocated in heap storage, so the caller is responsible 896f169c0eaSGlenn Lagasse * for freeing it. 897f169c0eaSGlenn Lagasse * Parameters: 898f169c0eaSGlenn Lagasse * dir - char pointer of directory to find. 899f169c0eaSGlenn Lagasse * Returns: 900f169c0eaSGlenn Lagasse * NULL - if directory is not mounted from a dataset. 901f169c0eaSGlenn Lagasse * name of dataset mounted at dir. 902f169c0eaSGlenn Lagasse * Scope: 903f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 904f169c0eaSGlenn Lagasse */ 905f169c0eaSGlenn Lagasse char * 906f169c0eaSGlenn Lagasse be_get_ds_from_dir(char *dir) 907f169c0eaSGlenn Lagasse { 908f169c0eaSGlenn Lagasse dir_data_t dd = { 0 }; 909f169c0eaSGlenn Lagasse char resolved_dir[MAXPATHLEN]; 910f169c0eaSGlenn Lagasse 911f169c0eaSGlenn Lagasse /* Make sure length of dir is within the max length */ 912f169c0eaSGlenn Lagasse if (dir == NULL || strlen(dir) >= MAXPATHLEN) 913f169c0eaSGlenn Lagasse return (NULL); 914f169c0eaSGlenn Lagasse 915f169c0eaSGlenn Lagasse /* Resolve dir in case its lofs mounted */ 916f169c0eaSGlenn Lagasse (void) strlcpy(resolved_dir, dir, sizeof (resolved_dir)); 917f169c0eaSGlenn Lagasse z_resolve_lofs(resolved_dir, sizeof (resolved_dir)); 918f169c0eaSGlenn Lagasse 919f169c0eaSGlenn Lagasse dd.dir = resolved_dir; 920f169c0eaSGlenn Lagasse 921f169c0eaSGlenn Lagasse (void) zfs_iter_root(g_zfs, be_get_ds_from_dir_callback, &dd); 922f169c0eaSGlenn Lagasse 923f169c0eaSGlenn Lagasse return (dd.ds); 924f169c0eaSGlenn Lagasse } 925f169c0eaSGlenn Lagasse 926f169c0eaSGlenn Lagasse /* 927f169c0eaSGlenn Lagasse * Function: be_make_tmp_mountpoint 928f169c0eaSGlenn Lagasse * Description: This function generates a random temporary mountpoint 929f169c0eaSGlenn Lagasse * and creates that mountpoint directory. It returns the 930f169c0eaSGlenn Lagasse * mountpoint in heap storage, so the caller is responsible 931f169c0eaSGlenn Lagasse * for freeing it. 932f169c0eaSGlenn Lagasse * Parameters: 933f169c0eaSGlenn Lagasse * tmp_mp - reference to pointer of where to store generated 934f169c0eaSGlenn Lagasse * temporary mountpoint. 935f169c0eaSGlenn Lagasse * Returns: 936f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 937f169c0eaSGlenn Lagasse * be_errno_t - Failure 938f169c0eaSGlenn Lagasse * Scope: 939f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 940f169c0eaSGlenn Lagasse */ 941f169c0eaSGlenn Lagasse int 942f169c0eaSGlenn Lagasse be_make_tmp_mountpoint(char **tmp_mp) 943f169c0eaSGlenn Lagasse { 944f169c0eaSGlenn Lagasse int err = 0; 945f169c0eaSGlenn Lagasse 946f169c0eaSGlenn Lagasse if ((*tmp_mp = (char *)calloc(1, sizeof (BE_TMP_MNTPNT) + 1)) == NULL) { 947f169c0eaSGlenn Lagasse be_print_err(gettext("be_make_tmp_mountpoint: " 948f169c0eaSGlenn Lagasse "malloc failed\n")); 949f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 950f169c0eaSGlenn Lagasse } 951f169c0eaSGlenn Lagasse (void) strlcpy(*tmp_mp, BE_TMP_MNTPNT, sizeof (BE_TMP_MNTPNT) + 1); 952f169c0eaSGlenn Lagasse if (mkdtemp(*tmp_mp) == NULL) { 953f169c0eaSGlenn Lagasse err = errno; 954f169c0eaSGlenn Lagasse be_print_err(gettext("be_make_tmp_mountpoint: mkdtemp() failed " 955f169c0eaSGlenn Lagasse "for %s: %s\n"), *tmp_mp, strerror(err)); 956f169c0eaSGlenn Lagasse free(*tmp_mp); 957f169c0eaSGlenn Lagasse *tmp_mp = NULL; 958f169c0eaSGlenn Lagasse return (errno_to_be_err(err)); 959f169c0eaSGlenn Lagasse } 960f169c0eaSGlenn Lagasse 961f169c0eaSGlenn Lagasse return (BE_SUCCESS); 962f169c0eaSGlenn Lagasse } 963f169c0eaSGlenn Lagasse 964f169c0eaSGlenn Lagasse /* 965f169c0eaSGlenn Lagasse * Function: be_mount_pool 966f169c0eaSGlenn Lagasse * Description: This function determines if the pool's datase is mounted 967f169c0eaSGlenn Lagasse * and if not it is used to mount the pool's dataset. The 968f169c0eaSGlenn Lagasse * function returns the current mountpoint if we are able 969f169c0eaSGlenn Lagasse * to mount the dataset. 970f169c0eaSGlenn Lagasse * Parameters: 971f169c0eaSGlenn Lagasse * zhp - handle to the pool's dataset 972f169c0eaSGlenn Lagasse * tmp_mntpnt - The temporary mountpoint that the pool's 973f169c0eaSGlenn Lagasse * dataset is mounted on. This is set only 974f169c0eaSGlenn Lagasse * if the attempt to mount the dataset at it's 975f169c0eaSGlenn Lagasse * set mountpoint fails, and we've used a 976f169c0eaSGlenn Lagasse * temporary mount point for this dataset. It 977f169c0eaSGlenn Lagasse * is expected that the caller will free this 978f169c0eaSGlenn Lagasse * memory. 979f169c0eaSGlenn Lagasse * orig_mntpnt - The original mountpoint for the pool. If a 980f169c0eaSGlenn Lagasse * temporary mount point was needed this will 981f169c0eaSGlenn Lagasse * be used to reset the mountpoint property to 982f169c0eaSGlenn Lagasse * it's original mountpoint. It is expected that 983f169c0eaSGlenn Lagasse * the caller will free this memory. 984f169c0eaSGlenn Lagasse * pool_mounted - This flag indicates that the pool was mounted 985f169c0eaSGlenn Lagasse * in this function. 986f169c0eaSGlenn Lagasse * Returns: 987f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 988f169c0eaSGlenn Lagasse * be_errno_t - Failure 989f169c0eaSGlenn Lagasse * Scope: 990f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 991f169c0eaSGlenn Lagasse */ 992f169c0eaSGlenn Lagasse int 993f169c0eaSGlenn Lagasse be_mount_pool( 994f169c0eaSGlenn Lagasse zfs_handle_t *zhp, 995f169c0eaSGlenn Lagasse char **tmp_mntpnt, 996f169c0eaSGlenn Lagasse char **orig_mntpnt, 997f169c0eaSGlenn Lagasse boolean_t *pool_mounted) 998f169c0eaSGlenn Lagasse { 999f169c0eaSGlenn Lagasse 1000f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 1001f169c0eaSGlenn Lagasse int ret = 0; 1002f169c0eaSGlenn Lagasse 1003f169c0eaSGlenn Lagasse *tmp_mntpnt = NULL; 1004f169c0eaSGlenn Lagasse *orig_mntpnt = NULL; 1005f169c0eaSGlenn Lagasse *pool_mounted = B_FALSE; 1006f169c0eaSGlenn Lagasse 1007f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, NULL)) { 1008f169c0eaSGlenn Lagasse if (zfs_mount(zhp, NULL, 0) != 0) { 1009f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 1010f169c0eaSGlenn Lagasse sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 1011f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_pool: failed to " 1012f169c0eaSGlenn Lagasse "get mountpoint of (%s): %s\n"), 1013f169c0eaSGlenn Lagasse zfs_get_name(zhp), 1014f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1015f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1016f169c0eaSGlenn Lagasse } 1017f169c0eaSGlenn Lagasse if ((*orig_mntpnt = strdup(mountpoint)) == NULL) { 1018f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_pool: memory " 1019f169c0eaSGlenn Lagasse "allocation failed\n")); 1020f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 1021f169c0eaSGlenn Lagasse } 1022f169c0eaSGlenn Lagasse /* 1023f169c0eaSGlenn Lagasse * attempt to mount on a temp mountpoint 1024f169c0eaSGlenn Lagasse */ 1025f169c0eaSGlenn Lagasse if ((ret = be_make_tmp_mountpoint(tmp_mntpnt)) 1026f169c0eaSGlenn Lagasse != BE_SUCCESS) { 1027f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_pool: failed " 1028f169c0eaSGlenn Lagasse "to make temporary mountpoint\n")); 1029f169c0eaSGlenn Lagasse free(*orig_mntpnt); 1030f169c0eaSGlenn Lagasse *orig_mntpnt = NULL; 1031f169c0eaSGlenn Lagasse return (ret); 1032f169c0eaSGlenn Lagasse } 1033f169c0eaSGlenn Lagasse 1034f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, 1035f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1036f169c0eaSGlenn Lagasse *tmp_mntpnt) != 0) { 1037f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_pool: failed " 1038f169c0eaSGlenn Lagasse "to set mountpoint of pool dataset %s to " 1039f169c0eaSGlenn Lagasse "%s: %s\n"), zfs_get_name(zhp), 1040f169c0eaSGlenn Lagasse *orig_mntpnt, 1041f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1042f169c0eaSGlenn Lagasse free(*tmp_mntpnt); 1043f169c0eaSGlenn Lagasse free(*orig_mntpnt); 1044f169c0eaSGlenn Lagasse *orig_mntpnt = NULL; 1045f169c0eaSGlenn Lagasse *tmp_mntpnt = NULL; 1046f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1047f169c0eaSGlenn Lagasse } 1048f169c0eaSGlenn Lagasse 1049f169c0eaSGlenn Lagasse if (zfs_mount(zhp, NULL, 0) != 0) { 1050f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_pool: failed " 1051f169c0eaSGlenn Lagasse "to mount dataset %s at %s: %s\n"), 1052f169c0eaSGlenn Lagasse zfs_get_name(zhp), *tmp_mntpnt, 1053f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1054f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1055f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, 1056f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1057f169c0eaSGlenn Lagasse mountpoint) != 0) { 1058f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_pool: " 1059f169c0eaSGlenn Lagasse "failed to set mountpoint of pool " 1060f169c0eaSGlenn Lagasse "dataset %s to %s: %s\n"), 1061f169c0eaSGlenn Lagasse zfs_get_name(zhp), *tmp_mntpnt, 1062f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1063f169c0eaSGlenn Lagasse } 1064f169c0eaSGlenn Lagasse free(*tmp_mntpnt); 1065f169c0eaSGlenn Lagasse free(*orig_mntpnt); 1066f169c0eaSGlenn Lagasse *orig_mntpnt = NULL; 1067f169c0eaSGlenn Lagasse *tmp_mntpnt = NULL; 1068f169c0eaSGlenn Lagasse return (ret); 1069f169c0eaSGlenn Lagasse } 1070f169c0eaSGlenn Lagasse } 1071f169c0eaSGlenn Lagasse *pool_mounted = B_TRUE; 1072f169c0eaSGlenn Lagasse } 1073f169c0eaSGlenn Lagasse 1074f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1075f169c0eaSGlenn Lagasse } 1076f169c0eaSGlenn Lagasse 1077f169c0eaSGlenn Lagasse /* 1078f169c0eaSGlenn Lagasse * Function: be_unmount_pool 1079f169c0eaSGlenn Lagasse * Description: This function is used to unmount the pool's dataset if we 1080f169c0eaSGlenn Lagasse * mounted it previously using be_mount_pool(). 1081f169c0eaSGlenn Lagasse * Parameters: 1082f169c0eaSGlenn Lagasse * zhp - handle to the pool's dataset 1083f169c0eaSGlenn Lagasse * tmp_mntpnt - If a temprary mount point was used this will 1084f169c0eaSGlenn Lagasse * be set. Since this was created in be_mount_pool 1085f169c0eaSGlenn Lagasse * we will need to clean it up here. 1086f169c0eaSGlenn Lagasse * orig_mntpnt - The original mountpoint for the pool. This is 1087f169c0eaSGlenn Lagasse * used to set the dataset mountpoint property 1088f169c0eaSGlenn Lagasse * back to it's original value in the case where a 1089f169c0eaSGlenn Lagasse * temporary mountpoint was used. 1090f169c0eaSGlenn Lagasse * Returns: 1091f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1092f169c0eaSGlenn Lagasse * be_errno_t - Failure 1093f169c0eaSGlenn Lagasse * Scope: 1094f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 1095f169c0eaSGlenn Lagasse */ 1096f169c0eaSGlenn Lagasse int 1097f169c0eaSGlenn Lagasse be_unmount_pool( 1098f169c0eaSGlenn Lagasse zfs_handle_t *zhp, 1099f169c0eaSGlenn Lagasse char *tmp_mntpnt, 1100f169c0eaSGlenn Lagasse char *orig_mntpnt) 1101f169c0eaSGlenn Lagasse { 1102f169c0eaSGlenn Lagasse if (zfs_unmount(zhp, NULL, 0) != 0) { 1103f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_pool: failed to " 1104f169c0eaSGlenn Lagasse "unmount pool (%s): %s\n"), zfs_get_name(zhp), 1105f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1106f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1107f169c0eaSGlenn Lagasse } 1108f169c0eaSGlenn Lagasse if (orig_mntpnt != NULL) { 1109f169c0eaSGlenn Lagasse if (tmp_mntpnt != NULL && 1110f169c0eaSGlenn Lagasse strcmp(orig_mntpnt, tmp_mntpnt) != 0) { 1111f169c0eaSGlenn Lagasse (void) rmdir(tmp_mntpnt); 1112f169c0eaSGlenn Lagasse } 1113f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, 1114f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1115f169c0eaSGlenn Lagasse orig_mntpnt) != 0) { 1116f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_pool: failed " 1117f169c0eaSGlenn Lagasse "to set the mountpoint for dataset (%s) to " 1118f169c0eaSGlenn Lagasse "%s: %s\n"), zfs_get_name(zhp), orig_mntpnt, 1119f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1120f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1121f169c0eaSGlenn Lagasse } 1122f169c0eaSGlenn Lagasse } 1123f169c0eaSGlenn Lagasse 1124f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1125f169c0eaSGlenn Lagasse } 1126f169c0eaSGlenn Lagasse 1127f169c0eaSGlenn Lagasse /* ******************************************************************** */ 1128f169c0eaSGlenn Lagasse /* Private Functions */ 1129f169c0eaSGlenn Lagasse /* ******************************************************************** */ 1130f169c0eaSGlenn Lagasse 1131f169c0eaSGlenn Lagasse /* 1132f169c0eaSGlenn Lagasse * Function: be_mount_callback 1133f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through all of a BE's 1134f169c0eaSGlenn Lagasse * subordinate file systems and to mount them accordingly. 1135f169c0eaSGlenn Lagasse * Parameters: 1136f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current file system being 1137f169c0eaSGlenn Lagasse * processed. 1138f169c0eaSGlenn Lagasse * data - pointer to the altroot of where to mount BE. 1139f169c0eaSGlenn Lagasse * Returns: 1140f169c0eaSGlenn Lagasse * 0 - Success 1141f169c0eaSGlenn Lagasse * be_errno_t - Failure 1142f169c0eaSGlenn Lagasse * Scope: 1143f169c0eaSGlenn Lagasse * Private 1144f169c0eaSGlenn Lagasse */ 1145f169c0eaSGlenn Lagasse static int 1146f169c0eaSGlenn Lagasse be_mount_callback(zfs_handle_t *zhp, void *data) 1147f169c0eaSGlenn Lagasse { 1148f169c0eaSGlenn Lagasse zprop_source_t sourcetype; 1149f169c0eaSGlenn Lagasse const char *fs_name = zfs_get_name(zhp); 11509adfa60dSMatthew Ahrens char source[ZFS_MAX_DATASET_NAME_LEN]; 1151f169c0eaSGlenn Lagasse char *altroot = data; 1152f169c0eaSGlenn Lagasse char zhp_mountpoint[MAXPATHLEN]; 1153f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 1154f169c0eaSGlenn Lagasse int ret = 0; 1155f169c0eaSGlenn Lagasse 1156f169c0eaSGlenn Lagasse /* Get dataset's mountpoint and source values */ 1157f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint, 1158f169c0eaSGlenn Lagasse sizeof (zhp_mountpoint), &sourcetype, source, sizeof (source), 1159f169c0eaSGlenn Lagasse B_FALSE) != 0) { 1160f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_callback: failed to " 1161f169c0eaSGlenn Lagasse "get mountpoint and sourcetype for %s\n"), 1162f169c0eaSGlenn Lagasse fs_name); 1163f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1164f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 1165f169c0eaSGlenn Lagasse } 1166f169c0eaSGlenn Lagasse 1167f169c0eaSGlenn Lagasse /* 1168f169c0eaSGlenn Lagasse * Set this filesystem's 'canmount' property to 'noauto' just incase 11693a876192SAlexander Pyhalov * it's been set 'on'. 1170f169c0eaSGlenn Lagasse */ 1171f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) { 1172f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_callback: failed to " 1173f169c0eaSGlenn Lagasse "set canmount to 'noauto' (%s)\n"), fs_name); 1174f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1175f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 1176f169c0eaSGlenn Lagasse } 1177f169c0eaSGlenn Lagasse 1178f169c0eaSGlenn Lagasse /* 1179f169c0eaSGlenn Lagasse * If the mountpoint is none, there's nothing to do, goto next. 1180f169c0eaSGlenn Lagasse * If the mountpoint is legacy, legacy mount it with mount(2). 1181f169c0eaSGlenn Lagasse * If the mountpoint is inherited, its mountpoint should 1182f169c0eaSGlenn Lagasse * already be set. If it's not, then explicitly fix-up 1183f169c0eaSGlenn Lagasse * the mountpoint now by appending its explicitly set 1184f169c0eaSGlenn Lagasse * mountpoint value to the BE mountpoint. 1185f169c0eaSGlenn Lagasse */ 1186f169c0eaSGlenn Lagasse if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_NONE) == 0) { 1187f169c0eaSGlenn Lagasse goto next; 1188f169c0eaSGlenn Lagasse } else if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1189f169c0eaSGlenn Lagasse /* 1190f169c0eaSGlenn Lagasse * If the mountpoint is set to 'legacy', we need to 1191f169c0eaSGlenn Lagasse * dig into this BE's vfstab to figure out where to 1192f169c0eaSGlenn Lagasse * mount it, and just mount it via mount(2). 1193f169c0eaSGlenn Lagasse */ 1194f169c0eaSGlenn Lagasse if (get_mountpoint_from_vfstab(altroot, fs_name, 1195f169c0eaSGlenn Lagasse mountpoint, sizeof (mountpoint), B_TRUE) == BE_SUCCESS) { 1196f169c0eaSGlenn Lagasse 1197f169c0eaSGlenn Lagasse /* Legacy mount the file system */ 1198f169c0eaSGlenn Lagasse if (mount(fs_name, mountpoint, MS_DATA, 1199f169c0eaSGlenn Lagasse MNTTYPE_ZFS, NULL, 0, NULL, 0) != 0) { 1200f169c0eaSGlenn Lagasse be_print_err( 1201f169c0eaSGlenn Lagasse gettext("be_mount_callback: " 1202f169c0eaSGlenn Lagasse "failed to mount %s on %s\n"), 1203f169c0eaSGlenn Lagasse fs_name, mountpoint); 1204f169c0eaSGlenn Lagasse } 1205f169c0eaSGlenn Lagasse } else { 1206f169c0eaSGlenn Lagasse be_print_err( 1207f169c0eaSGlenn Lagasse gettext("be_mount_callback: " 1208f169c0eaSGlenn Lagasse "no entry for %s in vfstab, " 1209f169c0eaSGlenn Lagasse "skipping ...\n"), fs_name); 1210f169c0eaSGlenn Lagasse } 1211f169c0eaSGlenn Lagasse 1212f169c0eaSGlenn Lagasse goto next; 1213f169c0eaSGlenn Lagasse 12143a876192SAlexander Pyhalov } else if ((sourcetype & (ZPROP_SRC_INHERITED|ZPROP_SRC_LOCAL)) == 0) { 1215f169c0eaSGlenn Lagasse /* 12163a876192SAlexander Pyhalov * Skip dataset if mountpoint is not inherited 12173a876192SAlexander Pyhalov * or explicitly set. 1218f169c0eaSGlenn Lagasse */ 1219f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_callback: " 1220f169c0eaSGlenn Lagasse "mountpoint sourcetype of %s is %d, skipping ...\n"), 1221f169c0eaSGlenn Lagasse fs_name, sourcetype); 1222f169c0eaSGlenn Lagasse 1223f169c0eaSGlenn Lagasse goto next; 1224f169c0eaSGlenn Lagasse } 1225f169c0eaSGlenn Lagasse 1226f169c0eaSGlenn Lagasse /* Mount this filesystem */ 12273a876192SAlexander Pyhalov if (mount_zfs(zhp, altroot) != 0) { 1228f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_callback: failed to " 1229f169c0eaSGlenn Lagasse "mount dataset %s at %s: %s\n"), fs_name, mountpoint, 12303a876192SAlexander Pyhalov strerror(errno)); 1231f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1232f169c0eaSGlenn Lagasse return (BE_ERR_MOUNT); 1233f169c0eaSGlenn Lagasse } 1234f169c0eaSGlenn Lagasse 1235f169c0eaSGlenn Lagasse next: 1236f169c0eaSGlenn Lagasse /* Iterate through this dataset's children and mount them */ 1237f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_mount_callback, 1238f169c0eaSGlenn Lagasse altroot)) != 0) { 1239f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1240f169c0eaSGlenn Lagasse return (ret); 1241f169c0eaSGlenn Lagasse } 1242f169c0eaSGlenn Lagasse 1243f169c0eaSGlenn Lagasse 1244f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1245f169c0eaSGlenn Lagasse return (0); 1246f169c0eaSGlenn Lagasse } 1247f169c0eaSGlenn Lagasse 1248f169c0eaSGlenn Lagasse /* 1249f169c0eaSGlenn Lagasse * Function: be_unmount_callback 1250f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through all of a BE's 1251f169c0eaSGlenn Lagasse * subordinate file systems and to unmount them. 1252f169c0eaSGlenn Lagasse * Parameters: 1253f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current file system being 1254f169c0eaSGlenn Lagasse * processed. 1255f169c0eaSGlenn Lagasse * data - pointer to the mountpoint of where BE is mounted. 1256f169c0eaSGlenn Lagasse * Returns: 1257f169c0eaSGlenn Lagasse * 0 - Success 1258f169c0eaSGlenn Lagasse * be_errno_t - Failure 1259f169c0eaSGlenn Lagasse * Scope: 1260f169c0eaSGlenn Lagasse * Private 1261f169c0eaSGlenn Lagasse */ 1262f169c0eaSGlenn Lagasse static int 1263f169c0eaSGlenn Lagasse be_unmount_callback(zfs_handle_t *zhp, void *data) 1264f169c0eaSGlenn Lagasse { 1265f169c0eaSGlenn Lagasse be_unmount_data_t *ud = data; 1266f169c0eaSGlenn Lagasse zprop_source_t sourcetype; 1267f169c0eaSGlenn Lagasse const char *fs_name = zfs_get_name(zhp); 12689adfa60dSMatthew Ahrens char source[ZFS_MAX_DATASET_NAME_LEN]; 1269f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 1270f169c0eaSGlenn Lagasse char *zhp_mountpoint; 1271f169c0eaSGlenn Lagasse int ret = 0; 1272f169c0eaSGlenn Lagasse 1273f169c0eaSGlenn Lagasse /* Iterate down this dataset's children first */ 1274f169c0eaSGlenn Lagasse if (zfs_iter_filesystems(zhp, be_unmount_callback, ud)) { 1275f169c0eaSGlenn Lagasse ret = BE_ERR_UMOUNT; 1276f169c0eaSGlenn Lagasse goto done; 1277f169c0eaSGlenn Lagasse } 1278f169c0eaSGlenn Lagasse 1279f169c0eaSGlenn Lagasse /* Is dataset even mounted ? */ 1280f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, NULL)) 1281f169c0eaSGlenn Lagasse goto done; 1282f169c0eaSGlenn Lagasse 1283f169c0eaSGlenn Lagasse /* Unmount this file system */ 1284f169c0eaSGlenn Lagasse if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) { 1285f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_callback: " 1286f169c0eaSGlenn Lagasse "failed to unmount %s: %s\n"), fs_name, 1287f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1288f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1289f169c0eaSGlenn Lagasse goto done; 1290f169c0eaSGlenn Lagasse } 1291f169c0eaSGlenn Lagasse 1292f169c0eaSGlenn Lagasse /* Get dataset's current mountpoint and source value */ 1293f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 1294f169c0eaSGlenn Lagasse sizeof (mountpoint), &sourcetype, source, sizeof (source), 1295f169c0eaSGlenn Lagasse B_FALSE) != 0) { 1296f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_callback: " 1297f169c0eaSGlenn Lagasse "failed to get mountpoint and sourcetype for %s: %s\n"), 1298f169c0eaSGlenn Lagasse fs_name, libzfs_error_description(g_zfs)); 1299f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1300f169c0eaSGlenn Lagasse goto done; 1301f169c0eaSGlenn Lagasse } 1302f169c0eaSGlenn Lagasse 1303f169c0eaSGlenn Lagasse if (sourcetype & ZPROP_SRC_INHERITED) { 1304f169c0eaSGlenn Lagasse /* 1305f169c0eaSGlenn Lagasse * If the mountpoint is inherited we don't need to 1306f169c0eaSGlenn Lagasse * do anything. When its parent gets processed 1307f169c0eaSGlenn Lagasse * its mountpoint will be set accordingly. 1308f169c0eaSGlenn Lagasse */ 1309f169c0eaSGlenn Lagasse goto done; 1310f169c0eaSGlenn Lagasse } else if (sourcetype & ZPROP_SRC_LOCAL) { 1311f169c0eaSGlenn Lagasse 1312f169c0eaSGlenn Lagasse if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1313f169c0eaSGlenn Lagasse /* 1314f169c0eaSGlenn Lagasse * If the mountpoint is set to 'legacy', its already 1315f169c0eaSGlenn Lagasse * been unmounted (from above call to zfs_unmount), and 1316f169c0eaSGlenn Lagasse * we don't need to do anything else with it. 1317f169c0eaSGlenn Lagasse */ 1318f169c0eaSGlenn Lagasse goto done; 1319f169c0eaSGlenn Lagasse 1320f169c0eaSGlenn Lagasse } else { 1321f169c0eaSGlenn Lagasse /* 1322f169c0eaSGlenn Lagasse * Else process dataset with explicitly set mountpoint. 1323f169c0eaSGlenn Lagasse */ 1324f169c0eaSGlenn Lagasse 1325f169c0eaSGlenn Lagasse /* 1326f169c0eaSGlenn Lagasse * Get this dataset's mountpoint relative to 1327f169c0eaSGlenn Lagasse * the BE's mountpoint. 1328f169c0eaSGlenn Lagasse */ 1329f169c0eaSGlenn Lagasse if ((strncmp(mountpoint, ud->altroot, 1330f169c0eaSGlenn Lagasse strlen(ud->altroot)) == 0) && 1331f169c0eaSGlenn Lagasse (mountpoint[strlen(ud->altroot)] == '/')) { 1332f169c0eaSGlenn Lagasse 1333f169c0eaSGlenn Lagasse zhp_mountpoint = mountpoint + 1334f169c0eaSGlenn Lagasse strlen(ud->altroot); 1335f169c0eaSGlenn Lagasse 1336f169c0eaSGlenn Lagasse /* Set this dataset's mountpoint value */ 1337f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, 1338f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1339f169c0eaSGlenn Lagasse zhp_mountpoint)) { 1340f169c0eaSGlenn Lagasse be_print_err( 1341f169c0eaSGlenn Lagasse gettext("be_unmount_callback: " 1342f169c0eaSGlenn Lagasse "failed to set mountpoint for " 1343f169c0eaSGlenn Lagasse "%s to %s: %s\n"), fs_name, 1344f169c0eaSGlenn Lagasse zhp_mountpoint, 1345f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1346f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1347f169c0eaSGlenn Lagasse } 1348f169c0eaSGlenn Lagasse } else { 1349f169c0eaSGlenn Lagasse /* 13503a876192SAlexander Pyhalov * Nothing to do, mountpoint shouldn't be 13513a876192SAlexander Pyhalov * corrected. 1352f169c0eaSGlenn Lagasse */ 13533a876192SAlexander Pyhalov goto done; 1354f169c0eaSGlenn Lagasse } 1355f169c0eaSGlenn Lagasse } 1356f169c0eaSGlenn Lagasse } else { 1357f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_callback: " 1358f169c0eaSGlenn Lagasse "mountpoint sourcetype of %s is %d, skipping ...\n"), 1359f169c0eaSGlenn Lagasse fs_name, sourcetype); 1360f169c0eaSGlenn Lagasse ret = BE_ERR_ZFS; 1361f169c0eaSGlenn Lagasse } 1362f169c0eaSGlenn Lagasse 1363f169c0eaSGlenn Lagasse done: 1364f169c0eaSGlenn Lagasse /* Set this filesystem's 'canmount' property to 'noauto' */ 1365f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) { 1366f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_callback: " 1367f169c0eaSGlenn Lagasse "failed to set canmount to 'noauto' (%s)\n"), fs_name); 1368f169c0eaSGlenn Lagasse if (ret == 0) 1369f169c0eaSGlenn Lagasse ret = BE_ERR_ZFS; 1370f169c0eaSGlenn Lagasse } 1371f169c0eaSGlenn Lagasse 1372f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1373f169c0eaSGlenn Lagasse return (ret); 1374f169c0eaSGlenn Lagasse } 1375f169c0eaSGlenn Lagasse 1376f169c0eaSGlenn Lagasse /* 1377f169c0eaSGlenn Lagasse * Function: be_get_legacy_fs_callback 1378f169c0eaSGlenn Lagasse * Description: The callback function is used to iterate through all 1379f169c0eaSGlenn Lagasse * non-shared file systems of a BE, finding ones that have 1380f169c0eaSGlenn Lagasse * a legacy mountpoint and an entry in the BE's vfstab. 1381f169c0eaSGlenn Lagasse * It adds these file systems to the callback data. 1382f169c0eaSGlenn Lagasse * Parameters: 1383f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current file system being 1384f169c0eaSGlenn Lagasse * processed. 1385f169c0eaSGlenn Lagasse * data - be_fs_list_data_t pointer 1386f169c0eaSGlenn Lagasse * Returns: 1387f169c0eaSGlenn Lagasse * 0 - Success 1388f169c0eaSGlenn Lagasse * be_errno_t - Failure 1389f169c0eaSGlenn Lagasse * Scope: 1390f169c0eaSGlenn Lagasse * Private 1391f169c0eaSGlenn Lagasse */ 1392f169c0eaSGlenn Lagasse static int 1393f169c0eaSGlenn Lagasse be_get_legacy_fs_callback(zfs_handle_t *zhp, void *data) 1394f169c0eaSGlenn Lagasse { 1395f169c0eaSGlenn Lagasse be_fs_list_data_t *fld = data; 1396f169c0eaSGlenn Lagasse const char *fs_name = zfs_get_name(zhp); 1397f169c0eaSGlenn Lagasse char zhp_mountpoint[MAXPATHLEN]; 1398f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 1399f169c0eaSGlenn Lagasse int ret = 0; 1400f169c0eaSGlenn Lagasse 1401f169c0eaSGlenn Lagasse /* Get this dataset's mountpoint property */ 1402f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint, 1403f169c0eaSGlenn Lagasse sizeof (zhp_mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 1404f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs_callback: " 1405f169c0eaSGlenn Lagasse "failed to get mountpoint for %s: %s\n"), 1406f169c0eaSGlenn Lagasse fs_name, libzfs_error_description(g_zfs)); 1407f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1408f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1409f169c0eaSGlenn Lagasse return (ret); 1410f169c0eaSGlenn Lagasse } 1411f169c0eaSGlenn Lagasse 1412f169c0eaSGlenn Lagasse /* 1413f169c0eaSGlenn Lagasse * If mountpoint is legacy, try to get its mountpoint from this BE's 1414f169c0eaSGlenn Lagasse * vfstab. If it exists in the vfstab, add this file system to the 1415f169c0eaSGlenn Lagasse * callback data. 1416f169c0eaSGlenn Lagasse */ 1417f169c0eaSGlenn Lagasse if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1418f169c0eaSGlenn Lagasse if (get_mountpoint_from_vfstab(fld->altroot, fs_name, 1419f169c0eaSGlenn Lagasse mountpoint, sizeof (mountpoint), B_FALSE) != BE_SUCCESS) { 1420f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs_callback: " 1421f169c0eaSGlenn Lagasse "no entry for %s in vfstab, " 1422f169c0eaSGlenn Lagasse "skipping ...\n"), fs_name); 1423f169c0eaSGlenn Lagasse 1424f169c0eaSGlenn Lagasse goto next; 1425f169c0eaSGlenn Lagasse } 1426f169c0eaSGlenn Lagasse 1427f169c0eaSGlenn Lagasse /* Record file system into the callback data. */ 1428f169c0eaSGlenn Lagasse if (add_to_fs_list(fld, zfs_get_name(zhp)) != BE_SUCCESS) { 1429f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_legacy_fs_callback: " 1430f169c0eaSGlenn Lagasse "failed to add %s to fs list\n"), mountpoint); 1431f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1432f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 1433f169c0eaSGlenn Lagasse } 1434f169c0eaSGlenn Lagasse } 1435f169c0eaSGlenn Lagasse 1436f169c0eaSGlenn Lagasse next: 1437f169c0eaSGlenn Lagasse /* Iterate through this dataset's children file systems */ 1438f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback, 1439f169c0eaSGlenn Lagasse fld)) != 0) { 1440f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1441f169c0eaSGlenn Lagasse return (ret); 1442f169c0eaSGlenn Lagasse } 1443f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1444f169c0eaSGlenn Lagasse return (0); 1445f169c0eaSGlenn Lagasse } 1446f169c0eaSGlenn Lagasse 1447f169c0eaSGlenn Lagasse /* 1448f169c0eaSGlenn Lagasse * Function: add_to_fs_list 1449f169c0eaSGlenn Lagasse * Description: Function used to add a file system to the fs_list array in 1450f169c0eaSGlenn Lagasse * a be_fs_list_data_t structure. 1451f169c0eaSGlenn Lagasse * Parameters: 1452f169c0eaSGlenn Lagasse * fld - be_fs_list_data_t pointer 1453f169c0eaSGlenn Lagasse * fs - file system to add 1454f169c0eaSGlenn Lagasse * Returns: 1455f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1456f169c0eaSGlenn Lagasse * 1 - Failure 1457f169c0eaSGlenn Lagasse * Scope: 1458f169c0eaSGlenn Lagasse * Private 1459f169c0eaSGlenn Lagasse */ 1460f169c0eaSGlenn Lagasse static int 1461f169c0eaSGlenn Lagasse add_to_fs_list(be_fs_list_data_t *fld, const char *fs) 1462f169c0eaSGlenn Lagasse { 1463f169c0eaSGlenn Lagasse if (fld == NULL || fs == NULL) 1464f169c0eaSGlenn Lagasse return (1); 1465f169c0eaSGlenn Lagasse 1466f169c0eaSGlenn Lagasse if ((fld->fs_list = (char **)realloc(fld->fs_list, 1467f169c0eaSGlenn Lagasse sizeof (char *)*(fld->fs_num + 1))) == NULL) { 1468f169c0eaSGlenn Lagasse be_print_err(gettext("add_to_fs_list: " 1469f169c0eaSGlenn Lagasse "memory allocation failed\n")); 1470f169c0eaSGlenn Lagasse return (1); 1471f169c0eaSGlenn Lagasse } 1472f169c0eaSGlenn Lagasse 1473f169c0eaSGlenn Lagasse if ((fld->fs_list[fld->fs_num++] = strdup(fs)) == NULL) { 1474f169c0eaSGlenn Lagasse be_print_err(gettext("add_to_fs_list: " 1475f169c0eaSGlenn Lagasse "memory allocation failed\n")); 1476f169c0eaSGlenn Lagasse return (1); 1477f169c0eaSGlenn Lagasse } 1478f169c0eaSGlenn Lagasse 1479f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1480f169c0eaSGlenn Lagasse } 1481f169c0eaSGlenn Lagasse 1482f169c0eaSGlenn Lagasse /* 1483f169c0eaSGlenn Lagasse * Function: zpool_shared_fs_callback 1484f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through all existing pools 1485f169c0eaSGlenn Lagasse * to find and mount all shared filesystems. This function 1486f169c0eaSGlenn Lagasse * processes the pool's "pool data" dataset, then uses 1487f169c0eaSGlenn Lagasse * iter_shared_fs_callback to iterate through the pool's 1488f169c0eaSGlenn Lagasse * datasets. 1489f169c0eaSGlenn Lagasse * Parameters: 1490f169c0eaSGlenn Lagasse * zlp - zpool_handle_t pointer to the current pool being 1491f169c0eaSGlenn Lagasse * looked at. 1492f169c0eaSGlenn Lagasse * data - be_mount_data_t pointer 1493f169c0eaSGlenn Lagasse * Returns: 1494f169c0eaSGlenn Lagasse * 0 - Success 1495f169c0eaSGlenn Lagasse * be_errno_t - Failure 1496f169c0eaSGlenn Lagasse * Scope: 1497f169c0eaSGlenn Lagasse * Private 1498f169c0eaSGlenn Lagasse */ 1499f169c0eaSGlenn Lagasse static int 1500f169c0eaSGlenn Lagasse zpool_shared_fs_callback(zpool_handle_t *zlp, void *data) 1501f169c0eaSGlenn Lagasse { 1502f169c0eaSGlenn Lagasse be_mount_data_t *md = data; 1503f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 1504f169c0eaSGlenn Lagasse const char *zpool = zpool_get_name(zlp); 1505f169c0eaSGlenn Lagasse int ret = 0; 1506f169c0eaSGlenn Lagasse 1507f169c0eaSGlenn Lagasse /* 1508f169c0eaSGlenn Lagasse * Get handle to pool's "pool data" dataset 1509f169c0eaSGlenn Lagasse */ 1510f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, zpool, ZFS_TYPE_FILESYSTEM)) == NULL) { 1511f169c0eaSGlenn Lagasse be_print_err(gettext("zpool_shared_fs: " 1512f169c0eaSGlenn Lagasse "failed to open pool dataset %s: %s\n"), zpool, 1513f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1514f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1515f169c0eaSGlenn Lagasse zpool_close(zlp); 1516f169c0eaSGlenn Lagasse return (ret); 1517f169c0eaSGlenn Lagasse } 1518f169c0eaSGlenn Lagasse 1519f169c0eaSGlenn Lagasse /* Process this pool's "pool data" dataset */ 1520f169c0eaSGlenn Lagasse (void) loopback_mount_shared_fs(zhp, md); 1521f169c0eaSGlenn Lagasse 1522f169c0eaSGlenn Lagasse /* Interate through this pool's children */ 1523f169c0eaSGlenn Lagasse (void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md); 1524f169c0eaSGlenn Lagasse 1525f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1526f169c0eaSGlenn Lagasse zpool_close(zlp); 1527f169c0eaSGlenn Lagasse 1528f169c0eaSGlenn Lagasse return (0); 1529f169c0eaSGlenn Lagasse } 1530f169c0eaSGlenn Lagasse 1531f169c0eaSGlenn Lagasse /* 1532f169c0eaSGlenn Lagasse * Function: iter_shared_fs_callback 1533f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through a pool's datasets 1534f169c0eaSGlenn Lagasse * to find and mount all shared filesystems. It makes sure to 1535f169c0eaSGlenn Lagasse * find the BE container dataset of the pool, if it exists, and 1536f169c0eaSGlenn Lagasse * does not process and iterate down that path. 1537f169c0eaSGlenn Lagasse * 1538f169c0eaSGlenn Lagasse * Note - This function iterates linearly down the 1539f169c0eaSGlenn Lagasse * hierarchical dataset paths and mounts things as it goes 1540f169c0eaSGlenn Lagasse * along. It does not make sure that something deeper down 1541f169c0eaSGlenn Lagasse * a dataset path has an interim mountpoint for something 1542f169c0eaSGlenn Lagasse * processed earlier. 1543f169c0eaSGlenn Lagasse * 1544f169c0eaSGlenn Lagasse * Parameters: 1545f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to the current dataset being 1546f169c0eaSGlenn Lagasse * processed. 1547f169c0eaSGlenn Lagasse * data - be_mount_data_t pointer 1548f169c0eaSGlenn Lagasse * Returns: 1549f169c0eaSGlenn Lagasse * 0 - Success 1550f169c0eaSGlenn Lagasse * be_errno_t - Failure 1551f169c0eaSGlenn Lagasse * Scope: 1552f169c0eaSGlenn Lagasse * Private 1553f169c0eaSGlenn Lagasse */ 1554f169c0eaSGlenn Lagasse static int 1555f169c0eaSGlenn Lagasse iter_shared_fs_callback(zfs_handle_t *zhp, void *data) 1556f169c0eaSGlenn Lagasse { 1557f169c0eaSGlenn Lagasse be_mount_data_t *md = data; 1558f169c0eaSGlenn Lagasse const char *name = zfs_get_name(zhp); 1559f169c0eaSGlenn Lagasse char container_ds[MAXPATHLEN]; 1560f169c0eaSGlenn Lagasse char tmp_name[MAXPATHLEN]; 1561f169c0eaSGlenn Lagasse char *pool; 1562f169c0eaSGlenn Lagasse 1563f169c0eaSGlenn Lagasse /* Get the pool's name */ 1564f169c0eaSGlenn Lagasse (void) strlcpy(tmp_name, name, sizeof (tmp_name)); 1565f169c0eaSGlenn Lagasse pool = strtok(tmp_name, "/"); 1566f169c0eaSGlenn Lagasse 1567f169c0eaSGlenn Lagasse if (pool) { 1568f169c0eaSGlenn Lagasse /* Get the name of this pool's container dataset */ 1569f169c0eaSGlenn Lagasse be_make_container_ds(pool, container_ds, 1570f169c0eaSGlenn Lagasse sizeof (container_ds)); 1571f169c0eaSGlenn Lagasse 1572f169c0eaSGlenn Lagasse /* 1573f169c0eaSGlenn Lagasse * If what we're processing is this pool's BE container 1574f169c0eaSGlenn Lagasse * dataset, skip it. 1575f169c0eaSGlenn Lagasse */ 1576f169c0eaSGlenn Lagasse if (strcmp(name, container_ds) == 0) { 1577f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1578f169c0eaSGlenn Lagasse return (0); 1579f169c0eaSGlenn Lagasse } 1580f169c0eaSGlenn Lagasse } else { 1581f169c0eaSGlenn Lagasse /* Getting the pool name failed, return error */ 1582f169c0eaSGlenn Lagasse be_print_err(gettext("iter_shared_fs_callback: " 1583f169c0eaSGlenn Lagasse "failed to get pool name from %s\n"), name); 1584f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1585f169c0eaSGlenn Lagasse return (BE_ERR_POOL_NOENT); 1586f169c0eaSGlenn Lagasse } 1587f169c0eaSGlenn Lagasse 1588f169c0eaSGlenn Lagasse /* Mount this shared filesystem */ 1589f169c0eaSGlenn Lagasse (void) loopback_mount_shared_fs(zhp, md); 1590f169c0eaSGlenn Lagasse 1591f169c0eaSGlenn Lagasse /* Iterate this dataset's children file systems */ 1592f169c0eaSGlenn Lagasse (void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md); 1593f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1594f169c0eaSGlenn Lagasse 1595f169c0eaSGlenn Lagasse return (0); 1596f169c0eaSGlenn Lagasse } 1597f169c0eaSGlenn Lagasse 1598f169c0eaSGlenn Lagasse /* 1599f169c0eaSGlenn Lagasse * Function: loopback_mount_shared_fs 1600f169c0eaSGlenn Lagasse * Description: This function loopback mounts a file system into the altroot 1601f169c0eaSGlenn Lagasse * area of the BE being mounted. Since these are shared file 1602f169c0eaSGlenn Lagasse * systems, they are expected to be already mounted for the 1603f169c0eaSGlenn Lagasse * current BE, and this function just loopback mounts them into 1604f169c0eaSGlenn Lagasse * the BE mountpoint. If they are not mounted for the current 1605f169c0eaSGlenn Lagasse * live system, they are skipped and not mounted into the BE 1606f169c0eaSGlenn Lagasse * we're mounting. 1607f169c0eaSGlenn Lagasse * Parameters: 1608f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to the dataset to loopback mount 1609f169c0eaSGlenn Lagasse * md - be_mount_data_t pointer 1610f169c0eaSGlenn Lagasse * Returns: 1611f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1612f169c0eaSGlenn Lagasse * be_errno_t - Failure 1613f169c0eaSGlenn Lagasse * Scope: 1614f169c0eaSGlenn Lagasse * Private 1615f169c0eaSGlenn Lagasse */ 1616f169c0eaSGlenn Lagasse static int 1617f169c0eaSGlenn Lagasse loopback_mount_shared_fs(zfs_handle_t *zhp, be_mount_data_t *md) 1618f169c0eaSGlenn Lagasse { 1619f169c0eaSGlenn Lagasse char zhp_mountpoint[MAXPATHLEN]; 1620f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 1621f169c0eaSGlenn Lagasse char *mp = NULL; 1622f169c0eaSGlenn Lagasse char optstr[MAX_MNTOPT_STR]; 1623f169c0eaSGlenn Lagasse int mflag = MS_OPTIONSTR; 1624f169c0eaSGlenn Lagasse int err; 1625f169c0eaSGlenn Lagasse 1626f169c0eaSGlenn Lagasse /* 1627f169c0eaSGlenn Lagasse * Check if file system is currently mounted and not delegated 1628f169c0eaSGlenn Lagasse * to a non-global zone (if we're in the global zone) 1629f169c0eaSGlenn Lagasse */ 1630f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, &mp) && (getzoneid() != GLOBAL_ZONEID || 1631f169c0eaSGlenn Lagasse !zfs_prop_get_int(zhp, ZFS_PROP_ZONED))) { 1632f169c0eaSGlenn Lagasse /* 1633f169c0eaSGlenn Lagasse * If we didn't get a mountpoint from the zfs_is_mounted call, 1634f169c0eaSGlenn Lagasse * get it from the mountpoint property. 1635f169c0eaSGlenn Lagasse */ 1636f169c0eaSGlenn Lagasse if (mp == NULL) { 1637f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, 1638f169c0eaSGlenn Lagasse zhp_mountpoint, sizeof (zhp_mountpoint), NULL, 1639f169c0eaSGlenn Lagasse NULL, 0, B_FALSE) != 0) { 1640f169c0eaSGlenn Lagasse be_print_err( 1641f169c0eaSGlenn Lagasse gettext("loopback_mount_shared_fs: " 1642f169c0eaSGlenn Lagasse "failed to get mountpoint property\n")); 1643f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 1644f169c0eaSGlenn Lagasse } 1645f169c0eaSGlenn Lagasse } else { 1646f169c0eaSGlenn Lagasse (void) strlcpy(zhp_mountpoint, mp, 1647f169c0eaSGlenn Lagasse sizeof (zhp_mountpoint)); 1648f169c0eaSGlenn Lagasse free(mp); 1649f169c0eaSGlenn Lagasse } 1650f169c0eaSGlenn Lagasse 1651f169c0eaSGlenn Lagasse (void) snprintf(mountpoint, sizeof (mountpoint), "%s%s", 1652f169c0eaSGlenn Lagasse md->altroot, zhp_mountpoint); 1653f169c0eaSGlenn Lagasse 1654f169c0eaSGlenn Lagasse /* Mount it read-only if read-write was not requested */ 1655f169c0eaSGlenn Lagasse if (!md->shared_rw) { 1656f169c0eaSGlenn Lagasse mflag |= MS_RDONLY; 1657f169c0eaSGlenn Lagasse } 1658f169c0eaSGlenn Lagasse 1659f169c0eaSGlenn Lagasse /* Add the "nosub" option to the mount options string */ 1660f169c0eaSGlenn Lagasse (void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr)); 1661f169c0eaSGlenn Lagasse 1662f169c0eaSGlenn Lagasse /* Loopback mount this dataset at the altroot */ 1663f169c0eaSGlenn Lagasse if (mount(zhp_mountpoint, mountpoint, mflag, MNTTYPE_LOFS, 1664f169c0eaSGlenn Lagasse NULL, 0, optstr, sizeof (optstr)) != 0) { 1665f169c0eaSGlenn Lagasse err = errno; 1666f169c0eaSGlenn Lagasse be_print_err(gettext("loopback_mount_shared_fs: " 1667f169c0eaSGlenn Lagasse "failed to loopback mount %s at %s: %s\n"), 1668f169c0eaSGlenn Lagasse zhp_mountpoint, mountpoint, strerror(err)); 1669f169c0eaSGlenn Lagasse return (BE_ERR_MOUNT); 1670f169c0eaSGlenn Lagasse } 1671f169c0eaSGlenn Lagasse } 1672f169c0eaSGlenn Lagasse 1673f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1674f169c0eaSGlenn Lagasse } 1675f169c0eaSGlenn Lagasse 1676f169c0eaSGlenn Lagasse /* 1677f169c0eaSGlenn Lagasse * Function: loopback_mount_zonepath 1678f169c0eaSGlenn Lagasse * Description: This function loopback mounts a zonepath into the altroot 167940ccc6adSAlexander Eremin * area of the BE being mounted. 1680f169c0eaSGlenn Lagasse * Parameters: 1681f169c0eaSGlenn Lagasse * zonepath - pointer to zone path in the current BE 1682f169c0eaSGlenn Lagasse * md - be_mount_data_t pointer 1683f169c0eaSGlenn Lagasse * Returns: 1684f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1685f169c0eaSGlenn Lagasse * be_errno_t - Failure 1686f169c0eaSGlenn Lagasse * Scope: 1687f169c0eaSGlenn Lagasse * Private 1688f169c0eaSGlenn Lagasse */ 1689f169c0eaSGlenn Lagasse static int 1690f169c0eaSGlenn Lagasse loopback_mount_zonepath(const char *zonepath, be_mount_data_t *md) 1691f169c0eaSGlenn Lagasse { 1692f169c0eaSGlenn Lagasse FILE *fp = (FILE *)NULL; 1693f169c0eaSGlenn Lagasse struct stat st; 1694f169c0eaSGlenn Lagasse char *p; 1695f169c0eaSGlenn Lagasse char *p1; 1696f169c0eaSGlenn Lagasse char *parent_dir; 1697f169c0eaSGlenn Lagasse struct extmnttab extmtab; 1698f169c0eaSGlenn Lagasse dev_t dev = NODEV; 1699f169c0eaSGlenn Lagasse char *parentmnt; 1700f169c0eaSGlenn Lagasse char alt_parentmnt[MAXPATHLEN]; 1701f169c0eaSGlenn Lagasse struct mnttab mntref; 1702f169c0eaSGlenn Lagasse char altzonepath[MAXPATHLEN]; 1703f169c0eaSGlenn Lagasse char optstr[MAX_MNTOPT_STR]; 1704f169c0eaSGlenn Lagasse int mflag = MS_OPTIONSTR; 1705f169c0eaSGlenn Lagasse int ret; 1706f169c0eaSGlenn Lagasse int err; 1707f169c0eaSGlenn Lagasse 1708f169c0eaSGlenn Lagasse fp = fopen(MNTTAB, "r"); 1709f169c0eaSGlenn Lagasse if (fp == NULL) { 1710f169c0eaSGlenn Lagasse err = errno; 1711f169c0eaSGlenn Lagasse be_print_err(gettext("loopback_mount_zonepath: " 1712f169c0eaSGlenn Lagasse "failed to open /etc/mnttab\n")); 1713f169c0eaSGlenn Lagasse return (errno_to_be_err(err)); 1714f169c0eaSGlenn Lagasse } 1715f169c0eaSGlenn Lagasse 1716f169c0eaSGlenn Lagasse /* 1717f169c0eaSGlenn Lagasse * before attempting the loopback mount of zonepath under altroot, 1718f169c0eaSGlenn Lagasse * we need to make sure that all intermediate file systems in the 1719f169c0eaSGlenn Lagasse * zone path are also mounted under altroot 1720f169c0eaSGlenn Lagasse */ 1721f169c0eaSGlenn Lagasse 1722f169c0eaSGlenn Lagasse /* get the parent directory for zonepath */ 1723f169c0eaSGlenn Lagasse p = strrchr(zonepath, '/'); 1724f169c0eaSGlenn Lagasse if (p != NULL && p != zonepath) { 1725f169c0eaSGlenn Lagasse if ((parent_dir = (char *)calloc(sizeof (char), 1726f169c0eaSGlenn Lagasse p - zonepath + 1)) == NULL) { 1727f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 1728f169c0eaSGlenn Lagasse goto done; 1729f169c0eaSGlenn Lagasse } 1730f169c0eaSGlenn Lagasse (void) strlcpy(parent_dir, zonepath, p - zonepath + 1); 1731f169c0eaSGlenn Lagasse if (stat(parent_dir, &st) < 0) { 1732f169c0eaSGlenn Lagasse ret = errno_to_be_err(errno); 1733f169c0eaSGlenn Lagasse be_print_err(gettext("loopback_mount_zonepath: " 1734f169c0eaSGlenn Lagasse "failed to stat %s"), 1735f169c0eaSGlenn Lagasse parent_dir); 1736f169c0eaSGlenn Lagasse free(parent_dir); 1737f169c0eaSGlenn Lagasse goto done; 1738f169c0eaSGlenn Lagasse } 1739f169c0eaSGlenn Lagasse free(parent_dir); 1740f169c0eaSGlenn Lagasse 1741f169c0eaSGlenn Lagasse /* 1742f169c0eaSGlenn Lagasse * After the above stat call, st.st_dev contains ID of the 1743f169c0eaSGlenn Lagasse * device over which parent dir resides. 1744f169c0eaSGlenn Lagasse * Now, search mnttab and find mount point of parent dir device. 1745f169c0eaSGlenn Lagasse */ 1746f169c0eaSGlenn Lagasse 1747f169c0eaSGlenn Lagasse resetmnttab(fp); 1748f169c0eaSGlenn Lagasse while (getextmntent(fp, &extmtab, sizeof (extmtab)) == 0) { 1749f169c0eaSGlenn Lagasse dev = makedev(extmtab.mnt_major, extmtab.mnt_minor); 1750f169c0eaSGlenn Lagasse if (st.st_dev == dev && strcmp(extmtab.mnt_fstype, 1751f169c0eaSGlenn Lagasse MNTTYPE_ZFS) == 0) { 1752f169c0eaSGlenn Lagasse p1 = strchr(extmtab.mnt_special, '/'); 1753f169c0eaSGlenn Lagasse if (p1 == NULL || strncmp(p1 + 1, 1754f169c0eaSGlenn Lagasse BE_CONTAINER_DS_NAME, 4) != 0 || 1755f169c0eaSGlenn Lagasse (*(p1 + 5) != '/' && *(p1 + 5) != '\0')) { 1756f169c0eaSGlenn Lagasse /* 1757f169c0eaSGlenn Lagasse * if parent dir is in a shared file 1758f169c0eaSGlenn Lagasse * system, check whether it is already 1759f169c0eaSGlenn Lagasse * loopback mounted under altroot or 1760f169c0eaSGlenn Lagasse * not. It would have been mounted 1761f169c0eaSGlenn Lagasse * already under altroot if it is in 1762f169c0eaSGlenn Lagasse * a non-shared filesystem. 1763f169c0eaSGlenn Lagasse */ 1764f169c0eaSGlenn Lagasse parentmnt = strdup(extmtab.mnt_mountp); 1765f169c0eaSGlenn Lagasse (void) snprintf(alt_parentmnt, 1766f169c0eaSGlenn Lagasse sizeof (alt_parentmnt), "%s%s", 1767f169c0eaSGlenn Lagasse md->altroot, parentmnt); 1768f169c0eaSGlenn Lagasse mntref.mnt_mountp = alt_parentmnt; 1769f169c0eaSGlenn Lagasse mntref.mnt_special = parentmnt; 1770f169c0eaSGlenn Lagasse mntref.mnt_fstype = MNTTYPE_LOFS; 1771f169c0eaSGlenn Lagasse mntref.mnt_mntopts = NULL; 1772f169c0eaSGlenn Lagasse mntref.mnt_time = NULL; 1773f169c0eaSGlenn Lagasse resetmnttab(fp); 1774f169c0eaSGlenn Lagasse if (getmntany(fp, (struct mnttab *) 1775f169c0eaSGlenn Lagasse &extmtab, &mntref) != 0) { 1776f169c0eaSGlenn Lagasse ret = loopback_mount_zonepath( 1777f169c0eaSGlenn Lagasse parentmnt, md); 1778f169c0eaSGlenn Lagasse if (ret != BE_SUCCESS) { 1779f169c0eaSGlenn Lagasse free(parentmnt); 1780f169c0eaSGlenn Lagasse goto done; 1781f169c0eaSGlenn Lagasse } 1782f169c0eaSGlenn Lagasse } 1783f169c0eaSGlenn Lagasse free(parentmnt); 1784f169c0eaSGlenn Lagasse } 1785f169c0eaSGlenn Lagasse break; 1786f169c0eaSGlenn Lagasse } 1787f169c0eaSGlenn Lagasse } 1788f169c0eaSGlenn Lagasse } 1789f169c0eaSGlenn Lagasse 1790f169c0eaSGlenn Lagasse 1791f169c0eaSGlenn Lagasse if (!md->shared_rw) { 1792f169c0eaSGlenn Lagasse mflag |= MS_RDONLY; 1793f169c0eaSGlenn Lagasse } 1794f169c0eaSGlenn Lagasse 1795f169c0eaSGlenn Lagasse (void) snprintf(altzonepath, sizeof (altzonepath), "%s%s", 1796f169c0eaSGlenn Lagasse md->altroot, zonepath); 1797f169c0eaSGlenn Lagasse 1798f169c0eaSGlenn Lagasse /* Add the "nosub" option to the mount options string */ 1799f169c0eaSGlenn Lagasse (void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr)); 1800f169c0eaSGlenn Lagasse 1801f169c0eaSGlenn Lagasse /* Loopback mount this dataset at the altroot */ 1802f169c0eaSGlenn Lagasse if (mount(zonepath, altzonepath, mflag, MNTTYPE_LOFS, 1803f169c0eaSGlenn Lagasse NULL, 0, optstr, sizeof (optstr)) != 0) { 1804f169c0eaSGlenn Lagasse err = errno; 1805f169c0eaSGlenn Lagasse be_print_err(gettext("loopback_mount_zonepath: " 1806f169c0eaSGlenn Lagasse "failed to loopback mount %s at %s: %s\n"), 1807f169c0eaSGlenn Lagasse zonepath, altzonepath, strerror(err)); 1808f169c0eaSGlenn Lagasse ret = BE_ERR_MOUNT; 1809f169c0eaSGlenn Lagasse goto done; 1810f169c0eaSGlenn Lagasse } 1811f169c0eaSGlenn Lagasse ret = BE_SUCCESS; 1812f169c0eaSGlenn Lagasse 1813f169c0eaSGlenn Lagasse done : 1814f169c0eaSGlenn Lagasse (void) fclose(fp); 1815f169c0eaSGlenn Lagasse return (ret); 1816f169c0eaSGlenn Lagasse } 1817f169c0eaSGlenn Lagasse 1818f169c0eaSGlenn Lagasse /* 1819f169c0eaSGlenn Lagasse * Function: unmount_shared_fs 1820f169c0eaSGlenn Lagasse * Description: This function iterates through the mnttab and finds all 1821f169c0eaSGlenn Lagasse * loopback mount entries that reside within the altroot of 1822f169c0eaSGlenn Lagasse * where the BE is mounted, and unmounts it. 1823f169c0eaSGlenn Lagasse * Parameters: 1824f169c0eaSGlenn Lagasse * ud - be_unmount_data_t pointer 1825f169c0eaSGlenn Lagasse * Returns: 1826f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1827f169c0eaSGlenn Lagasse * be_errno_t - Failure 1828f169c0eaSGlenn Lagasse * Scope: 1829f169c0eaSGlenn Lagasse * Private 1830f169c0eaSGlenn Lagasse */ 1831f169c0eaSGlenn Lagasse static int 1832f169c0eaSGlenn Lagasse unmount_shared_fs(be_unmount_data_t *ud) 1833f169c0eaSGlenn Lagasse { 1834f169c0eaSGlenn Lagasse FILE *fp = NULL; 1835f169c0eaSGlenn Lagasse struct mnttab *table = NULL; 1836f169c0eaSGlenn Lagasse struct mnttab ent; 1837f169c0eaSGlenn Lagasse struct mnttab *entp = NULL; 1838f169c0eaSGlenn Lagasse size_t size = 0; 1839f169c0eaSGlenn Lagasse int read_chunk = 32; 1840f169c0eaSGlenn Lagasse int i; 1841f169c0eaSGlenn Lagasse int altroot_len; 1842f169c0eaSGlenn Lagasse int err = 0; 1843f169c0eaSGlenn Lagasse 1844f169c0eaSGlenn Lagasse errno = 0; 1845f169c0eaSGlenn Lagasse 1846f169c0eaSGlenn Lagasse /* Read in the mnttab into a table */ 1847f169c0eaSGlenn Lagasse if ((fp = fopen(MNTTAB, "r")) == NULL) { 1848f169c0eaSGlenn Lagasse err = errno; 1849f169c0eaSGlenn Lagasse be_print_err(gettext("unmount_shared_fs: " 1850f169c0eaSGlenn Lagasse "failed to open mnttab\n")); 1851f169c0eaSGlenn Lagasse return (errno_to_be_err(err)); 1852f169c0eaSGlenn Lagasse } 1853f169c0eaSGlenn Lagasse 1854f169c0eaSGlenn Lagasse while (getmntent(fp, &ent) == 0) { 1855f169c0eaSGlenn Lagasse if (size % read_chunk == 0) { 1856f169c0eaSGlenn Lagasse table = (struct mnttab *)realloc(table, 1857f169c0eaSGlenn Lagasse (size + read_chunk) * sizeof (ent)); 1858f169c0eaSGlenn Lagasse } 1859f169c0eaSGlenn Lagasse entp = &table[size++]; 1860f169c0eaSGlenn Lagasse 1861f169c0eaSGlenn Lagasse /* 1862f169c0eaSGlenn Lagasse * Copy over the current mnttab entry into our table, 1863f169c0eaSGlenn Lagasse * copying only the fields that we care about. 1864f169c0eaSGlenn Lagasse */ 1865f169c0eaSGlenn Lagasse (void) memset(entp, 0, sizeof (*entp)); 1866f169c0eaSGlenn Lagasse if ((entp->mnt_mountp = strdup(ent.mnt_mountp)) == NULL || 1867f169c0eaSGlenn Lagasse (entp->mnt_fstype = strdup(ent.mnt_fstype)) == NULL) { 1868f169c0eaSGlenn Lagasse be_print_err(gettext("unmount_shared_fs: " 1869f169c0eaSGlenn Lagasse "memory allocation failed\n")); 1870f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 1871f169c0eaSGlenn Lagasse } 1872f169c0eaSGlenn Lagasse } 1873f169c0eaSGlenn Lagasse (void) fclose(fp); 1874f169c0eaSGlenn Lagasse 1875f169c0eaSGlenn Lagasse /* 1876f169c0eaSGlenn Lagasse * Process the mnttab entries in reverse order, looking for 1877f169c0eaSGlenn Lagasse * loopback mount entries mounted under our altroot. 1878f169c0eaSGlenn Lagasse */ 1879f169c0eaSGlenn Lagasse altroot_len = strlen(ud->altroot); 1880f169c0eaSGlenn Lagasse for (i = size; i > 0; i--) { 1881f169c0eaSGlenn Lagasse entp = &table[i - 1]; 1882f169c0eaSGlenn Lagasse 1883f169c0eaSGlenn Lagasse /* If not of type lofs, skip */ 1884f169c0eaSGlenn Lagasse if (strcmp(entp->mnt_fstype, MNTTYPE_LOFS) != 0) 1885f169c0eaSGlenn Lagasse continue; 1886f169c0eaSGlenn Lagasse 1887f169c0eaSGlenn Lagasse /* If inside the altroot, unmount it */ 1888f169c0eaSGlenn Lagasse if (strncmp(entp->mnt_mountp, ud->altroot, altroot_len) == 0 && 1889f169c0eaSGlenn Lagasse entp->mnt_mountp[altroot_len] == '/') { 1890f169c0eaSGlenn Lagasse if (umount(entp->mnt_mountp) != 0) { 1891f169c0eaSGlenn Lagasse err = errno; 1892f169c0eaSGlenn Lagasse if (err == EBUSY) { 1893f169c0eaSGlenn Lagasse (void) sleep(1); 1894f169c0eaSGlenn Lagasse err = errno = 0; 1895f169c0eaSGlenn Lagasse if (umount(entp->mnt_mountp) != 0) 1896f169c0eaSGlenn Lagasse err = errno; 1897f169c0eaSGlenn Lagasse } 1898f169c0eaSGlenn Lagasse if (err != 0) { 1899f169c0eaSGlenn Lagasse be_print_err(gettext( 1900f169c0eaSGlenn Lagasse "unmount_shared_fs: " 1901f169c0eaSGlenn Lagasse "failed to unmount shared file " 1902f169c0eaSGlenn Lagasse "system %s: %s\n"), 1903f169c0eaSGlenn Lagasse entp->mnt_mountp, strerror(err)); 1904f169c0eaSGlenn Lagasse return (errno_to_be_err(err)); 1905f169c0eaSGlenn Lagasse } 1906f169c0eaSGlenn Lagasse } 1907f169c0eaSGlenn Lagasse } 1908f169c0eaSGlenn Lagasse } 1909f169c0eaSGlenn Lagasse 1910f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1911f169c0eaSGlenn Lagasse } 1912f169c0eaSGlenn Lagasse 1913f169c0eaSGlenn Lagasse /* 1914f169c0eaSGlenn Lagasse * Function: get_mountpoint_from_vfstab 1915f169c0eaSGlenn Lagasse * Description: This function digs into the vfstab in the given altroot, 1916f169c0eaSGlenn Lagasse * and searches for an entry for the fs passed in. If found, 1917f169c0eaSGlenn Lagasse * it returns the mountpoint of that fs in the mountpoint 1918f169c0eaSGlenn Lagasse * buffer passed in. If the get_alt_mountpoint flag is set, 1919f169c0eaSGlenn Lagasse * it returns the mountpoint with the altroot prepended. 1920f169c0eaSGlenn Lagasse * Parameters: 1921f169c0eaSGlenn Lagasse * altroot - pointer to the alternate root location 1922f169c0eaSGlenn Lagasse * fs - pointer to the file system name to look for in the 1923f169c0eaSGlenn Lagasse * vfstab in altroot 1924f169c0eaSGlenn Lagasse * mountpoint - pointer to buffer of where the mountpoint of 1925f169c0eaSGlenn Lagasse * fs will be returned. 1926f169c0eaSGlenn Lagasse * size_mp - size of mountpoint argument 1927f169c0eaSGlenn Lagasse * get_alt_mountpoint - flag to indicate whether or not the 1928f169c0eaSGlenn Lagasse * mountpoint should be populated with the altroot 1929f169c0eaSGlenn Lagasse * prepended. 1930f169c0eaSGlenn Lagasse * Returns: 1931f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1932f169c0eaSGlenn Lagasse * 1 - Failure 1933f169c0eaSGlenn Lagasse * Scope: 1934f169c0eaSGlenn Lagasse * Private 1935f169c0eaSGlenn Lagasse */ 1936f169c0eaSGlenn Lagasse static int 1937f169c0eaSGlenn Lagasse get_mountpoint_from_vfstab(char *altroot, const char *fs, char *mountpoint, 1938f169c0eaSGlenn Lagasse size_t size_mp, boolean_t get_alt_mountpoint) 1939f169c0eaSGlenn Lagasse { 1940f169c0eaSGlenn Lagasse struct vfstab vp; 1941f169c0eaSGlenn Lagasse FILE *fp = NULL; 1942f169c0eaSGlenn Lagasse char alt_vfstab[MAXPATHLEN]; 1943f169c0eaSGlenn Lagasse 1944f169c0eaSGlenn Lagasse /* Generate path to alternate root vfstab */ 1945f169c0eaSGlenn Lagasse (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab", 1946f169c0eaSGlenn Lagasse altroot); 1947f169c0eaSGlenn Lagasse 1948f169c0eaSGlenn Lagasse /* Open alternate root vfstab */ 1949f169c0eaSGlenn Lagasse if ((fp = fopen(alt_vfstab, "r")) == NULL) { 1950f169c0eaSGlenn Lagasse be_print_err(gettext("get_mountpoint_from_vfstab: " 1951f169c0eaSGlenn Lagasse "failed to open vfstab (%s)\n"), alt_vfstab); 1952f169c0eaSGlenn Lagasse return (1); 1953f169c0eaSGlenn Lagasse } 1954f169c0eaSGlenn Lagasse 1955f169c0eaSGlenn Lagasse if (getvfsspec(fp, &vp, (char *)fs) == 0) { 1956f169c0eaSGlenn Lagasse /* 1957f169c0eaSGlenn Lagasse * Found entry for fs, grab its mountpoint. 1958f169c0eaSGlenn Lagasse * If the flag to prepend the altroot into the mountpoint 1959f169c0eaSGlenn Lagasse * is set, prepend it. Otherwise, just return the mountpoint. 1960f169c0eaSGlenn Lagasse */ 1961f169c0eaSGlenn Lagasse if (get_alt_mountpoint) { 1962f169c0eaSGlenn Lagasse (void) snprintf(mountpoint, size_mp, "%s%s", altroot, 1963f169c0eaSGlenn Lagasse vp.vfs_mountp); 1964f169c0eaSGlenn Lagasse } else { 1965f169c0eaSGlenn Lagasse (void) strlcpy(mountpoint, vp.vfs_mountp, size_mp); 1966f169c0eaSGlenn Lagasse } 1967f169c0eaSGlenn Lagasse } else { 1968f169c0eaSGlenn Lagasse (void) fclose(fp); 1969f169c0eaSGlenn Lagasse return (1); 1970f169c0eaSGlenn Lagasse } 1971f169c0eaSGlenn Lagasse 1972f169c0eaSGlenn Lagasse (void) fclose(fp); 1973f169c0eaSGlenn Lagasse 1974f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1975f169c0eaSGlenn Lagasse } 1976f169c0eaSGlenn Lagasse 1977f169c0eaSGlenn Lagasse /* 1978f169c0eaSGlenn Lagasse * Function: fix_mountpoint_callback 1979f169c0eaSGlenn Lagasse * Description: This callback function is used to iterate through a BE's 1980f169c0eaSGlenn Lagasse * children filesystems to check if its mountpoint is currently 1981f169c0eaSGlenn Lagasse * set to be mounted at some specified altroot. If so, fix it by 1982f169c0eaSGlenn Lagasse * removing altroot from the beginning of its mountpoint. 1983f169c0eaSGlenn Lagasse * 1984f169c0eaSGlenn Lagasse * Note - There's no way to tell if a child filesystem's 1985f169c0eaSGlenn Lagasse * mountpoint isn't broken, and just happens to begin with 1986f169c0eaSGlenn Lagasse * the altroot we're looking for. In this case, this function 1987f169c0eaSGlenn Lagasse * will errantly remove the altroot portion from the beginning 1988f169c0eaSGlenn Lagasse * of this filesystem's mountpoint. 1989f169c0eaSGlenn Lagasse * 1990f169c0eaSGlenn Lagasse * Parameters: 1991f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to filesystem being processed. 1992f169c0eaSGlenn Lagasse * data - altroot of where BE is to be mounted. 1993f169c0eaSGlenn Lagasse * Returns: 1994f169c0eaSGlenn Lagasse * 0 - Success 1995f169c0eaSGlenn Lagasse * be_errno_t - Failure 1996f169c0eaSGlenn Lagasse * Scope: 1997f169c0eaSGlenn Lagasse * Private 1998f169c0eaSGlenn Lagasse */ 1999f169c0eaSGlenn Lagasse static int 2000f169c0eaSGlenn Lagasse fix_mountpoint_callback(zfs_handle_t *zhp, void *data) 2001f169c0eaSGlenn Lagasse { 2002f169c0eaSGlenn Lagasse zprop_source_t sourcetype; 20039adfa60dSMatthew Ahrens char source[ZFS_MAX_DATASET_NAME_LEN]; 2004f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 2005f169c0eaSGlenn Lagasse char *zhp_mountpoint = NULL; 2006f169c0eaSGlenn Lagasse char *altroot = data; 2007f169c0eaSGlenn Lagasse int ret = 0; 2008f169c0eaSGlenn Lagasse 2009f169c0eaSGlenn Lagasse /* Get dataset's mountpoint and source values */ 2010f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 2011f169c0eaSGlenn Lagasse sizeof (mountpoint), &sourcetype, source, sizeof (source), 2012f169c0eaSGlenn Lagasse B_FALSE) != 0) { 2013f169c0eaSGlenn Lagasse be_print_err(gettext("fix_mountpoint_callback: " 2014f169c0eaSGlenn Lagasse "failed to get mountpoint and sourcetype for %s\n"), 2015f169c0eaSGlenn Lagasse zfs_get_name(zhp)); 2016f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2017f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 2018f169c0eaSGlenn Lagasse } 2019f169c0eaSGlenn Lagasse 2020f169c0eaSGlenn Lagasse /* 2021f169c0eaSGlenn Lagasse * If the mountpoint is not inherited and the mountpoint is not 2022f169c0eaSGlenn Lagasse * 'legacy', this file system potentially needs its mountpoint 2023f169c0eaSGlenn Lagasse * fixed. 2024f169c0eaSGlenn Lagasse */ 2025f169c0eaSGlenn Lagasse if (!(sourcetype & ZPROP_SRC_INHERITED) && 2026f169c0eaSGlenn Lagasse strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) { 2027f169c0eaSGlenn Lagasse 2028f169c0eaSGlenn Lagasse /* 2029f169c0eaSGlenn Lagasse * Check if this file system's current mountpoint is 2030f169c0eaSGlenn Lagasse * under the altroot we're fixing it against. 2031f169c0eaSGlenn Lagasse */ 2032f169c0eaSGlenn Lagasse if (strncmp(mountpoint, altroot, strlen(altroot)) == 0 && 2033f169c0eaSGlenn Lagasse mountpoint[strlen(altroot)] == '/') { 2034f169c0eaSGlenn Lagasse 2035f169c0eaSGlenn Lagasse /* 2036f169c0eaSGlenn Lagasse * Get this dataset's mountpoint relative to the 2037f169c0eaSGlenn Lagasse * altroot. 2038f169c0eaSGlenn Lagasse */ 2039f169c0eaSGlenn Lagasse zhp_mountpoint = mountpoint + strlen(altroot); 2040f169c0eaSGlenn Lagasse 2041f169c0eaSGlenn Lagasse /* Fix this dataset's mountpoint value */ 2042f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, 2043f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 2044f169c0eaSGlenn Lagasse zhp_mountpoint)) { 2045f169c0eaSGlenn Lagasse be_print_err(gettext("fix_mountpoint_callback: " 2046f169c0eaSGlenn Lagasse "failed to set mountpoint for %s to " 2047f169c0eaSGlenn Lagasse "%s: %s\n"), zfs_get_name(zhp), 2048f169c0eaSGlenn Lagasse zhp_mountpoint, 2049f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2050f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2051f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2052f169c0eaSGlenn Lagasse return (ret); 2053f169c0eaSGlenn Lagasse } 2054f169c0eaSGlenn Lagasse } 2055f169c0eaSGlenn Lagasse } 2056f169c0eaSGlenn Lagasse 2057f169c0eaSGlenn Lagasse /* Iterate through this dataset's children and fix them */ 2058f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, fix_mountpoint_callback, 2059f169c0eaSGlenn Lagasse altroot)) != 0) { 2060f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2061f169c0eaSGlenn Lagasse return (ret); 2062f169c0eaSGlenn Lagasse } 2063f169c0eaSGlenn Lagasse 2064f169c0eaSGlenn Lagasse 2065f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2066f169c0eaSGlenn Lagasse return (0); 2067f169c0eaSGlenn Lagasse } 2068f169c0eaSGlenn Lagasse 2069f169c0eaSGlenn Lagasse /* 2070f169c0eaSGlenn Lagasse * Function: be_mount_root 2071f169c0eaSGlenn Lagasse * Description: This function mounts the root dataset of a BE at the 2072f169c0eaSGlenn Lagasse * specified altroot. 2073f169c0eaSGlenn Lagasse * Parameters: 2074f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to root dataset of a BE that is 2075f169c0eaSGlenn Lagasse * to be mounted at altroot. 2076f169c0eaSGlenn Lagasse * altroot - location of where to mount the BE root. 2077f169c0eaSGlenn Lagasse * Return: 2078f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2079f169c0eaSGlenn Lagasse * be_errno_t - Failure 2080f169c0eaSGlenn Lagasse * Scope: 2081f169c0eaSGlenn Lagasse * Private 2082f169c0eaSGlenn Lagasse */ 2083f169c0eaSGlenn Lagasse static int 2084f169c0eaSGlenn Lagasse be_mount_root(zfs_handle_t *zhp, char *altroot) 2085f169c0eaSGlenn Lagasse { 2086f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 2087f169c0eaSGlenn Lagasse 2088f169c0eaSGlenn Lagasse /* Get mountpoint property of dataset */ 2089f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 2090f169c0eaSGlenn Lagasse sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2091f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_root: failed to " 2092f169c0eaSGlenn Lagasse "get mountpoint property for %s: %s\n"), zfs_get_name(zhp), 2093f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2094f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2095f169c0eaSGlenn Lagasse } 2096f169c0eaSGlenn Lagasse 2097f169c0eaSGlenn Lagasse /* 2098f169c0eaSGlenn Lagasse * Set the canmount property for the BE's root dataset to 'noauto' just 20993a876192SAlexander Pyhalov * in case it's been set to 'on'. 2100f169c0eaSGlenn Lagasse */ 2101f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") 2102f169c0eaSGlenn Lagasse != 0) { 2103f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_root: failed to " 2104f169c0eaSGlenn Lagasse "set canmount property to 'noauto' (%s): %s\n"), 2105f169c0eaSGlenn Lagasse zfs_get_name(zhp), libzfs_error_description(g_zfs)); 2106f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2107f169c0eaSGlenn Lagasse } 2108f169c0eaSGlenn Lagasse 2109f169c0eaSGlenn Lagasse /* Mount the BE's root filesystem */ 21103a876192SAlexander Pyhalov if (mount_zfs(zhp, altroot) != 0) { 2111f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_root: failed to " 2112f169c0eaSGlenn Lagasse "mount dataset %s at %s: %s\n"), zfs_get_name(zhp), 21133a876192SAlexander Pyhalov altroot, strerror(errno)); 21143a876192SAlexander Pyhalov return (BE_ERR_ZFS); 2115f169c0eaSGlenn Lagasse } 2116f169c0eaSGlenn Lagasse 2117f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2118f169c0eaSGlenn Lagasse } 2119f169c0eaSGlenn Lagasse 2120f169c0eaSGlenn Lagasse /* 2121f169c0eaSGlenn Lagasse * Function: be_unmount_root 2122f169c0eaSGlenn Lagasse * Description: This function unmounts the root dataset of a BE, but before 2123f169c0eaSGlenn Lagasse * unmounting, it looks at the BE's vfstab to determine 2124f169c0eaSGlenn Lagasse * if the root dataset mountpoint should be left as 'legacy' 2125f169c0eaSGlenn Lagasse * or '/'. If the vfstab contains an entry for this root 2126f169c0eaSGlenn Lagasse * dataset with a mountpoint of '/', it sets the mountpoint 2127f169c0eaSGlenn Lagasse * property to 'legacy'. 2128f169c0eaSGlenn Lagasse * 2129f169c0eaSGlenn Lagasse * Parameters: 2130f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer of the BE root dataset that 2131f169c0eaSGlenn Lagasse * is currently mounted. 2132f169c0eaSGlenn Lagasse * ud - be_unmount_data_t pointer providing unmount data 2133f169c0eaSGlenn Lagasse * for the given BE root dataset. 2134f169c0eaSGlenn Lagasse * Returns: 2135f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2136f169c0eaSGlenn Lagasse * be_errno_t - Failure 2137f169c0eaSGlenn Lagasse * Scope: 2138f169c0eaSGlenn Lagasse * Private 2139f169c0eaSGlenn Lagasse */ 2140f169c0eaSGlenn Lagasse static int 2141f169c0eaSGlenn Lagasse be_unmount_root(zfs_handle_t *zhp, be_unmount_data_t *ud) 2142f169c0eaSGlenn Lagasse { 2143f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 2144f169c0eaSGlenn Lagasse boolean_t is_legacy = B_FALSE; 2145f169c0eaSGlenn Lagasse 2146f169c0eaSGlenn Lagasse /* See if this is a legacy mounted root */ 2147f169c0eaSGlenn Lagasse if (get_mountpoint_from_vfstab(ud->altroot, zfs_get_name(zhp), 2148f169c0eaSGlenn Lagasse mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS && 2149f169c0eaSGlenn Lagasse strcmp(mountpoint, "/") == 0) { 2150f169c0eaSGlenn Lagasse is_legacy = B_TRUE; 2151f169c0eaSGlenn Lagasse } 2152f169c0eaSGlenn Lagasse 2153f169c0eaSGlenn Lagasse /* Unmount the dataset */ 2154f169c0eaSGlenn Lagasse if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) { 2155f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_root: failed to " 2156f169c0eaSGlenn Lagasse "unmount BE root dataset %s: %s\n"), zfs_get_name(zhp), 2157f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2158f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2159f169c0eaSGlenn Lagasse } 2160f169c0eaSGlenn Lagasse 2161f169c0eaSGlenn Lagasse /* Set canmount property for this BE's root filesystem to noauto */ 2162f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") 2163f169c0eaSGlenn Lagasse != 0) { 2164f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_root: failed to " 2165f169c0eaSGlenn Lagasse "set canmount property for %s to 'noauto': %s\n"), 2166f169c0eaSGlenn Lagasse zfs_get_name(zhp), libzfs_error_description(g_zfs)); 2167f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2168f169c0eaSGlenn Lagasse } 2169f169c0eaSGlenn Lagasse 2170f169c0eaSGlenn Lagasse /* 2171f169c0eaSGlenn Lagasse * Set mountpoint for BE's root dataset back to '/', or 'legacy' 2172f169c0eaSGlenn Lagasse * if its a legacy mounted root. 2173f169c0eaSGlenn Lagasse */ 2174f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 2175f169c0eaSGlenn Lagasse is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/") != 0) { 2176f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_root: failed to " 2177f169c0eaSGlenn Lagasse "set mountpoint of %s to %s\n"), zfs_get_name(zhp), 2178f169c0eaSGlenn Lagasse is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/"); 2179f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2180f169c0eaSGlenn Lagasse } 2181f169c0eaSGlenn Lagasse 2182f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2183f169c0eaSGlenn Lagasse } 2184f169c0eaSGlenn Lagasse 2185f169c0eaSGlenn Lagasse /* 2186f169c0eaSGlenn Lagasse * Function: fix_mountpoint 2187f169c0eaSGlenn Lagasse * Description: This function checks the mountpoint of an unmounted BE to make 2188f169c0eaSGlenn Lagasse * sure that it is set to either 'legacy' or '/'. If it's not, 2189f169c0eaSGlenn Lagasse * then we're in a situation where an unmounted BE has some random 2190f169c0eaSGlenn Lagasse * mountpoint set for it. (This could happen if the system was 2191f169c0eaSGlenn Lagasse * rebooted while an inactive BE was mounted). This function 2192f169c0eaSGlenn Lagasse * attempts to fix its mountpoints. 2193f169c0eaSGlenn Lagasse * Parameters: 2194f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to root dataset of the BE 2195f169c0eaSGlenn Lagasse * whose mountpoint needs to be checked. 2196f169c0eaSGlenn Lagasse * Return: 2197f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2198f169c0eaSGlenn Lagasse * be_errno_t - Failure 2199f169c0eaSGlenn Lagasse * Scope: 2200f169c0eaSGlenn Lagasse * Private 2201f169c0eaSGlenn Lagasse */ 2202f169c0eaSGlenn Lagasse static int 2203f169c0eaSGlenn Lagasse fix_mountpoint(zfs_handle_t *zhp) 2204f169c0eaSGlenn Lagasse { 2205f169c0eaSGlenn Lagasse be_unmount_data_t ud = { 0 }; 2206f169c0eaSGlenn Lagasse char *altroot = NULL; 2207f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 2208f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 2209f169c0eaSGlenn Lagasse 2210f169c0eaSGlenn Lagasse /* 2211f169c0eaSGlenn Lagasse * Record what this BE's root dataset mountpoint property is currently 2212f169c0eaSGlenn Lagasse * set to. 2213f169c0eaSGlenn Lagasse */ 2214f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 2215f169c0eaSGlenn Lagasse sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2216f169c0eaSGlenn Lagasse be_print_err(gettext("fix_mountpoint: failed to get " 2217f169c0eaSGlenn Lagasse "mountpoint property of (%s): %s\n"), zfs_get_name(zhp), 2218f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2219f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 2220f169c0eaSGlenn Lagasse } 2221f169c0eaSGlenn Lagasse 2222f169c0eaSGlenn Lagasse /* 2223f169c0eaSGlenn Lagasse * If the root dataset mountpoint is set to 'legacy' or '/', we're okay. 2224f169c0eaSGlenn Lagasse */ 2225f169c0eaSGlenn Lagasse if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0 || 2226f169c0eaSGlenn Lagasse strcmp(mountpoint, "/") == 0) { 2227f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2228f169c0eaSGlenn Lagasse } 2229f169c0eaSGlenn Lagasse 2230f169c0eaSGlenn Lagasse /* 2231f169c0eaSGlenn Lagasse * Iterate through this BE's children datasets and fix 2232f169c0eaSGlenn Lagasse * them if they need fixing. 2233f169c0eaSGlenn Lagasse */ 2234f169c0eaSGlenn Lagasse if (zfs_iter_filesystems(zhp, fix_mountpoint_callback, mountpoint) 2235f169c0eaSGlenn Lagasse != 0) { 2236f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 2237f169c0eaSGlenn Lagasse } 2238f169c0eaSGlenn Lagasse 2239f169c0eaSGlenn Lagasse /* 2240f169c0eaSGlenn Lagasse * The process of mounting and unmounting the root file system 2241f169c0eaSGlenn Lagasse * will fix its mountpoint to correctly be either 'legacy' or '/' 2242f169c0eaSGlenn Lagasse * since be_unmount_root will do the right thing by looking at 2243f169c0eaSGlenn Lagasse * its vfstab. 2244f169c0eaSGlenn Lagasse */ 2245f169c0eaSGlenn Lagasse 2246f169c0eaSGlenn Lagasse /* Generate temporary altroot to mount the root file system */ 2247f169c0eaSGlenn Lagasse if ((ret = be_make_tmp_mountpoint(&altroot)) != BE_SUCCESS) { 2248f169c0eaSGlenn Lagasse be_print_err(gettext("fix_mountpoint: failed to " 2249f169c0eaSGlenn Lagasse "make temporary mountpoint\n")); 2250f169c0eaSGlenn Lagasse return (ret); 2251f169c0eaSGlenn Lagasse } 2252f169c0eaSGlenn Lagasse 2253f169c0eaSGlenn Lagasse /* Mount and unmount the root. */ 2254f169c0eaSGlenn Lagasse if ((ret = be_mount_root(zhp, altroot)) != BE_SUCCESS) { 2255f169c0eaSGlenn Lagasse be_print_err(gettext("fix_mountpoint: failed to " 2256f169c0eaSGlenn Lagasse "mount BE root file system\n")); 2257f169c0eaSGlenn Lagasse goto cleanup; 2258f169c0eaSGlenn Lagasse } 2259f169c0eaSGlenn Lagasse ud.altroot = altroot; 2260f169c0eaSGlenn Lagasse if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) { 2261f169c0eaSGlenn Lagasse be_print_err(gettext("fix_mountpoint: failed to " 2262f169c0eaSGlenn Lagasse "unmount BE root file system\n")); 2263f169c0eaSGlenn Lagasse goto cleanup; 2264f169c0eaSGlenn Lagasse } 2265f169c0eaSGlenn Lagasse 2266f169c0eaSGlenn Lagasse cleanup: 2267f169c0eaSGlenn Lagasse free(altroot); 2268f169c0eaSGlenn Lagasse 2269f169c0eaSGlenn Lagasse return (ret); 2270f169c0eaSGlenn Lagasse } 2271f169c0eaSGlenn Lagasse 2272f169c0eaSGlenn Lagasse /* 2273f169c0eaSGlenn Lagasse * Function: be_mount_zones 2274f169c0eaSGlenn Lagasse * Description: This function finds all supported non-global zones in the 2275f169c0eaSGlenn Lagasse * given global BE and mounts them with respect to where the 2276f169c0eaSGlenn Lagasse * global BE is currently mounted. The global BE datasets 2277f169c0eaSGlenn Lagasse * (including its shared datasets) are expected to already 2278f169c0eaSGlenn Lagasse * be mounted. 2279f169c0eaSGlenn Lagasse * Parameters: 2280f169c0eaSGlenn Lagasse * be_zhp - zfs_handle_t pointer to the root dataset of the 2281f169c0eaSGlenn Lagasse * global BE. 2282f169c0eaSGlenn Lagasse * md - be_mount_data_t pointer to data for global BE. 2283f169c0eaSGlenn Lagasse * Returns: 2284f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2285f169c0eaSGlenn Lagasse * be_errno_t - Failure 2286f169c0eaSGlenn Lagasse * Scope: 2287f169c0eaSGlenn Lagasse * Private 2288f169c0eaSGlenn Lagasse */ 2289f169c0eaSGlenn Lagasse static int 2290f169c0eaSGlenn Lagasse be_mount_zones(zfs_handle_t *be_zhp, be_mount_data_t *md) 2291f169c0eaSGlenn Lagasse { 2292f169c0eaSGlenn Lagasse zoneBrandList_t *brands = NULL; 2293f169c0eaSGlenn Lagasse zoneList_t zlst = NULL; 2294f169c0eaSGlenn Lagasse char *zonename = NULL; 2295f169c0eaSGlenn Lagasse char *zonepath = NULL; 2296f169c0eaSGlenn Lagasse char *zonepath_ds = NULL; 2297f169c0eaSGlenn Lagasse int k; 2298f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 2299f169c0eaSGlenn Lagasse 2300f169c0eaSGlenn Lagasse z_set_zone_root(md->altroot); 2301f169c0eaSGlenn Lagasse 2302f169c0eaSGlenn Lagasse if ((brands = be_get_supported_brandlist()) == NULL) { 2303f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_zones: " 2304f169c0eaSGlenn Lagasse "no supported brands\n")); 2305f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2306f169c0eaSGlenn Lagasse } 2307f169c0eaSGlenn Lagasse 2308f169c0eaSGlenn Lagasse zlst = z_get_nonglobal_zone_list_by_brand(brands); 2309f169c0eaSGlenn Lagasse if (zlst == NULL) { 2310f169c0eaSGlenn Lagasse z_free_brand_list(brands); 2311f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2312f169c0eaSGlenn Lagasse } 2313f169c0eaSGlenn Lagasse 2314f169c0eaSGlenn Lagasse for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) { 2315f169c0eaSGlenn Lagasse if (z_zlist_get_current_state(zlst, k) == 2316f169c0eaSGlenn Lagasse ZONE_STATE_INSTALLED) { 2317f169c0eaSGlenn Lagasse zonepath = z_zlist_get_zonepath(zlst, k); 2318f169c0eaSGlenn Lagasse 2319f169c0eaSGlenn Lagasse /* 2320f169c0eaSGlenn Lagasse * Get the dataset of this zonepath in current BE. 2321f169c0eaSGlenn Lagasse * If its not a dataset, skip it. 2322f169c0eaSGlenn Lagasse */ 2323f169c0eaSGlenn Lagasse if ((zonepath_ds = be_get_ds_from_dir(zonepath)) 2324f169c0eaSGlenn Lagasse == NULL) 2325f169c0eaSGlenn Lagasse continue; 2326f169c0eaSGlenn Lagasse 2327f169c0eaSGlenn Lagasse /* 2328f169c0eaSGlenn Lagasse * Check if this zone is supported based on 2329f169c0eaSGlenn Lagasse * the dataset of its zonepath 2330f169c0eaSGlenn Lagasse */ 2331f169c0eaSGlenn Lagasse if (!be_zone_supported(zonepath_ds)) { 2332f169c0eaSGlenn Lagasse free(zonepath_ds); 2333f169c0eaSGlenn Lagasse zonepath_ds = NULL; 2334f169c0eaSGlenn Lagasse continue; 2335f169c0eaSGlenn Lagasse } 2336f169c0eaSGlenn Lagasse 2337f169c0eaSGlenn Lagasse /* 2338f169c0eaSGlenn Lagasse * if BE's shared file systems are already mounted, 2339f169c0eaSGlenn Lagasse * zone path dataset would have already been lofs 2340f169c0eaSGlenn Lagasse * mounted under altroot. Otherwise, we need to do 2341f169c0eaSGlenn Lagasse * it here. 2342f169c0eaSGlenn Lagasse */ 2343f169c0eaSGlenn Lagasse if (!md->shared_fs) { 2344f169c0eaSGlenn Lagasse ret = loopback_mount_zonepath(zonepath, md); 2345f169c0eaSGlenn Lagasse if (ret != BE_SUCCESS) 2346f169c0eaSGlenn Lagasse goto done; 2347f169c0eaSGlenn Lagasse } 2348f169c0eaSGlenn Lagasse 2349f169c0eaSGlenn Lagasse 2350f169c0eaSGlenn Lagasse /* Mount this zone */ 2351f169c0eaSGlenn Lagasse ret = be_mount_one_zone(be_zhp, md, zonename, 2352f169c0eaSGlenn Lagasse zonepath, zonepath_ds); 2353f169c0eaSGlenn Lagasse 2354f169c0eaSGlenn Lagasse free(zonepath_ds); 2355f169c0eaSGlenn Lagasse zonepath_ds = NULL; 2356f169c0eaSGlenn Lagasse 2357f169c0eaSGlenn Lagasse if (ret != BE_SUCCESS) { 2358f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_zones: " 2359f169c0eaSGlenn Lagasse "failed to mount zone %s under " 2360f169c0eaSGlenn Lagasse "altroot %s\n"), zonename, md->altroot); 2361f169c0eaSGlenn Lagasse goto done; 2362f169c0eaSGlenn Lagasse } 2363f169c0eaSGlenn Lagasse } 2364f169c0eaSGlenn Lagasse } 2365f169c0eaSGlenn Lagasse 2366f169c0eaSGlenn Lagasse done: 2367f169c0eaSGlenn Lagasse z_free_brand_list(brands); 2368f169c0eaSGlenn Lagasse z_free_zone_list(zlst); 2369f169c0eaSGlenn Lagasse /* 2370f169c0eaSGlenn Lagasse * libinstzones caches mnttab and uses cached version for resolving lofs 2371f169c0eaSGlenn Lagasse * mounts when we call z_resolve_lofs. It creates the cached version 2372f169c0eaSGlenn Lagasse * when the first call to z_resolve_lofs happens. So, library's cached 2373f169c0eaSGlenn Lagasse * mnttab doesn't contain entries for lofs mounts created in the above 2374f169c0eaSGlenn Lagasse * loop. Because of this, subsequent calls to z_resolve_lofs would fail 2375f169c0eaSGlenn Lagasse * to resolve these lofs mounts. So, here we destroy library's cached 2376f169c0eaSGlenn Lagasse * mnttab to force its recreation when the next call to z_resolve_lofs 2377f169c0eaSGlenn Lagasse * happens. 2378f169c0eaSGlenn Lagasse */ 2379f169c0eaSGlenn Lagasse z_destroyMountTable(); 2380f169c0eaSGlenn Lagasse return (ret); 2381f169c0eaSGlenn Lagasse } 2382f169c0eaSGlenn Lagasse 2383f169c0eaSGlenn Lagasse /* 2384f169c0eaSGlenn Lagasse * Function: be_unmount_zones 2385f169c0eaSGlenn Lagasse * Description: This function finds all supported non-global zones in the 2386f169c0eaSGlenn Lagasse * given mounted global BE and unmounts them. 2387f169c0eaSGlenn Lagasse * Parameters: 2388f169c0eaSGlenn Lagasse * ud - unmount_data_t pointer data for the global BE. 2389f169c0eaSGlenn Lagasse * Returns: 2390f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2391f169c0eaSGlenn Lagasse * be_errno_t - Failure 2392f169c0eaSGlenn Lagasse * Scope: 2393f169c0eaSGlenn Lagasse * Private 2394f169c0eaSGlenn Lagasse */ 2395f169c0eaSGlenn Lagasse static int 2396f169c0eaSGlenn Lagasse be_unmount_zones(be_unmount_data_t *ud) 2397f169c0eaSGlenn Lagasse { 2398f169c0eaSGlenn Lagasse zoneBrandList_t *brands = NULL; 2399f169c0eaSGlenn Lagasse zoneList_t zlst = NULL; 2400f169c0eaSGlenn Lagasse char *zonename = NULL; 2401f169c0eaSGlenn Lagasse char *zonepath = NULL; 2402f169c0eaSGlenn Lagasse char alt_zonepath[MAXPATHLEN]; 2403f169c0eaSGlenn Lagasse char *zonepath_ds = NULL; 2404f169c0eaSGlenn Lagasse int k; 2405f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 2406f169c0eaSGlenn Lagasse 2407f169c0eaSGlenn Lagasse z_set_zone_root(ud->altroot); 2408f169c0eaSGlenn Lagasse 2409f169c0eaSGlenn Lagasse if ((brands = be_get_supported_brandlist()) == NULL) { 2410f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_zones: " 2411f169c0eaSGlenn Lagasse "no supported brands\n")); 2412f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2413f169c0eaSGlenn Lagasse } 2414f169c0eaSGlenn Lagasse 2415f169c0eaSGlenn Lagasse zlst = z_get_nonglobal_zone_list_by_brand(brands); 2416f169c0eaSGlenn Lagasse if (zlst == NULL) { 2417f169c0eaSGlenn Lagasse z_free_brand_list(brands); 2418f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2419f169c0eaSGlenn Lagasse } 2420f169c0eaSGlenn Lagasse 2421f169c0eaSGlenn Lagasse for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) { 2422f169c0eaSGlenn Lagasse if (z_zlist_get_current_state(zlst, k) == 2423f169c0eaSGlenn Lagasse ZONE_STATE_INSTALLED) { 2424f169c0eaSGlenn Lagasse zonepath = z_zlist_get_zonepath(zlst, k); 2425f169c0eaSGlenn Lagasse 2426f169c0eaSGlenn Lagasse /* Build zone's zonepath wrt the global BE altroot */ 2427f169c0eaSGlenn Lagasse (void) snprintf(alt_zonepath, sizeof (alt_zonepath), 2428f169c0eaSGlenn Lagasse "%s%s", ud->altroot, zonepath); 2429f169c0eaSGlenn Lagasse 2430f169c0eaSGlenn Lagasse /* 2431f169c0eaSGlenn Lagasse * Get the dataset of this zonepath. If its not 2432f169c0eaSGlenn Lagasse * a dataset, skip it. 2433f169c0eaSGlenn Lagasse */ 2434f169c0eaSGlenn Lagasse if ((zonepath_ds = be_get_ds_from_dir(alt_zonepath)) 2435f169c0eaSGlenn Lagasse == NULL) 2436f169c0eaSGlenn Lagasse continue; 2437f169c0eaSGlenn Lagasse 2438f169c0eaSGlenn Lagasse /* 2439f169c0eaSGlenn Lagasse * Check if this zone is supported based on the 2440f169c0eaSGlenn Lagasse * dataset of its zonepath. 2441f169c0eaSGlenn Lagasse */ 2442f169c0eaSGlenn Lagasse if (!be_zone_supported(zonepath_ds)) { 2443f169c0eaSGlenn Lagasse free(zonepath_ds); 2444f169c0eaSGlenn Lagasse zonepath_ds = NULL; 2445f169c0eaSGlenn Lagasse continue; 2446f169c0eaSGlenn Lagasse } 2447f169c0eaSGlenn Lagasse 2448f169c0eaSGlenn Lagasse /* Unmount this zone */ 2449f169c0eaSGlenn Lagasse ret = be_unmount_one_zone(ud, zonename, zonepath, 2450f169c0eaSGlenn Lagasse zonepath_ds); 2451f169c0eaSGlenn Lagasse 2452f169c0eaSGlenn Lagasse free(zonepath_ds); 2453f169c0eaSGlenn Lagasse zonepath_ds = NULL; 2454f169c0eaSGlenn Lagasse 2455f169c0eaSGlenn Lagasse if (ret != BE_SUCCESS) { 2456f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_zones:" 2457f169c0eaSGlenn Lagasse " failed to unmount zone %s from " 2458f169c0eaSGlenn Lagasse "altroot %s\n"), zonename, ud->altroot); 2459f169c0eaSGlenn Lagasse goto done; 2460f169c0eaSGlenn Lagasse } 2461f169c0eaSGlenn Lagasse } 2462f169c0eaSGlenn Lagasse } 2463f169c0eaSGlenn Lagasse 2464f169c0eaSGlenn Lagasse done: 2465f169c0eaSGlenn Lagasse z_free_brand_list(brands); 2466f169c0eaSGlenn Lagasse z_free_zone_list(zlst); 2467f169c0eaSGlenn Lagasse return (ret); 2468f169c0eaSGlenn Lagasse } 2469f169c0eaSGlenn Lagasse 2470f169c0eaSGlenn Lagasse /* 2471f169c0eaSGlenn Lagasse * Function: be_mount_one_zone 2472f169c0eaSGlenn Lagasse * Description: This function is called to mount one zone for a given 2473f169c0eaSGlenn Lagasse * global BE. 2474f169c0eaSGlenn Lagasse * Parameters: 2475f169c0eaSGlenn Lagasse * be_zhp - zfs_handle_t pointer to the root dataset of the 2476f169c0eaSGlenn Lagasse * global BE 2477f169c0eaSGlenn Lagasse * md - be_mount_data_t pointer to data for global BE 2478f169c0eaSGlenn Lagasse * zonename - name of zone to mount 2479f169c0eaSGlenn Lagasse * zonepath - zonepath of zone to mount 2480f169c0eaSGlenn Lagasse * zonepath_ds - dataset for the zonepath 2481f169c0eaSGlenn Lagasse * Returns: 2482f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2483f169c0eaSGlenn Lagasse * be_errno_t - Failure 2484f169c0eaSGlenn Lagasse * Scope: 2485f169c0eaSGlenn Lagasse * Private 2486f169c0eaSGlenn Lagasse */ 2487f169c0eaSGlenn Lagasse static int 2488f169c0eaSGlenn Lagasse be_mount_one_zone(zfs_handle_t *be_zhp, be_mount_data_t *md, char *zonename, 2489f169c0eaSGlenn Lagasse char *zonepath, char *zonepath_ds) 2490f169c0eaSGlenn Lagasse { 2491f169c0eaSGlenn Lagasse be_mount_data_t zone_md = { 0 }; 2492f169c0eaSGlenn Lagasse zfs_handle_t *zone_zhp = NULL; 2493f169c0eaSGlenn Lagasse char zone_altroot[MAXPATHLEN]; 2494f169c0eaSGlenn Lagasse char zoneroot[MAXPATHLEN]; 2495f169c0eaSGlenn Lagasse char zoneroot_ds[MAXPATHLEN]; 2496f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 2497f169c0eaSGlenn Lagasse 2498f169c0eaSGlenn Lagasse /* Find the active zone root dataset for this zone for this BE */ 2499f169c0eaSGlenn Lagasse if ((ret = be_find_active_zone_root(be_zhp, zonepath_ds, zoneroot_ds, 2500f169c0eaSGlenn Lagasse sizeof (zoneroot_ds))) == BE_ERR_ZONE_NO_ACTIVE_ROOT) { 2501f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_one_zone: did not " 2502f169c0eaSGlenn Lagasse "find active zone root for zone %s, skipping ...\n"), 2503f169c0eaSGlenn Lagasse zonename); 2504f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2505f169c0eaSGlenn Lagasse } else if (ret != BE_SUCCESS) { 2506f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_one_zone: failed to " 2507f169c0eaSGlenn Lagasse "find active zone root for zone %s\n"), zonename); 2508f169c0eaSGlenn Lagasse return (ret); 2509f169c0eaSGlenn Lagasse } 2510f169c0eaSGlenn Lagasse 2511f169c0eaSGlenn Lagasse /* Get handle to active zoneroot dataset */ 2512f169c0eaSGlenn Lagasse if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM)) 2513f169c0eaSGlenn Lagasse == NULL) { 2514f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_one_zone: failed to " 2515f169c0eaSGlenn Lagasse "open zone root dataset (%s): %s\n"), zoneroot_ds, 2516f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2517f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2518f169c0eaSGlenn Lagasse } 2519f169c0eaSGlenn Lagasse 2520f169c0eaSGlenn Lagasse /* Generate string for zone's altroot path */ 2521f169c0eaSGlenn Lagasse be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot)); 2522f169c0eaSGlenn Lagasse (void) strlcpy(zone_altroot, md->altroot, sizeof (zone_altroot)); 2523f169c0eaSGlenn Lagasse (void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot)); 2524f169c0eaSGlenn Lagasse 2525f169c0eaSGlenn Lagasse /* Build mount_data for the zone */ 2526f169c0eaSGlenn Lagasse zone_md.altroot = zone_altroot; 2527f169c0eaSGlenn Lagasse zone_md.shared_fs = md->shared_fs; 2528f169c0eaSGlenn Lagasse zone_md.shared_rw = md->shared_rw; 2529f169c0eaSGlenn Lagasse 2530f169c0eaSGlenn Lagasse /* Mount the zone's root file system */ 2531f169c0eaSGlenn Lagasse if ((ret = be_mount_zone_root(zone_zhp, &zone_md)) != BE_SUCCESS) { 2532f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_one_zone: failed to " 2533f169c0eaSGlenn Lagasse "mount zone root file system at %s\n"), zone_altroot); 2534f169c0eaSGlenn Lagasse goto done; 2535f169c0eaSGlenn Lagasse } 2536f169c0eaSGlenn Lagasse 2537f169c0eaSGlenn Lagasse /* Iterate through zone's children filesystems */ 2538f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zone_zhp, be_mount_callback, 2539f169c0eaSGlenn Lagasse zone_altroot)) != 0) { 2540f169c0eaSGlenn Lagasse be_print_err(gettext("be_mount_one_zone: failed to " 2541f169c0eaSGlenn Lagasse "mount zone subordinate file systems at %s\n"), 2542f169c0eaSGlenn Lagasse zone_altroot); 2543f169c0eaSGlenn Lagasse goto done; 2544f169c0eaSGlenn Lagasse } 2545f169c0eaSGlenn Lagasse 2546f169c0eaSGlenn Lagasse /* TODO: Mount all shared file systems for this zone */ 2547f169c0eaSGlenn Lagasse 2548f169c0eaSGlenn Lagasse done: 2549f169c0eaSGlenn Lagasse ZFS_CLOSE(zone_zhp); 2550f169c0eaSGlenn Lagasse return (ret); 2551f169c0eaSGlenn Lagasse } 2552f169c0eaSGlenn Lagasse 2553f169c0eaSGlenn Lagasse /* 2554f169c0eaSGlenn Lagasse * Function: be_unmount_one_zone 2555f169c0eaSGlenn Lagasse * Description: This function unmount one zone for a give global BE. 2556f169c0eaSGlenn Lagasse * Parameters: 2557f169c0eaSGlenn Lagasse * ud - be_unmount_data_t pointer to data for global BE 2558f169c0eaSGlenn Lagasse * zonename - name of zone to unmount 2559f169c0eaSGlenn Lagasse * zonepath - zonepath of the zone to unmount 2560f169c0eaSGlenn Lagasse * zonepath_ds - dataset for the zonepath 2561f169c0eaSGlenn Lagasse * Returns: 2562f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2563f169c0eaSGlenn Lagasse * be_errno_t - Failure 2564f169c0eaSGlenn Lagasse * Scope: 2565f169c0eaSGlenn Lagasse * Private 2566f169c0eaSGlenn Lagasse */ 2567f169c0eaSGlenn Lagasse static int 2568f169c0eaSGlenn Lagasse be_unmount_one_zone(be_unmount_data_t *ud, char *zonename, char *zonepath, 2569f169c0eaSGlenn Lagasse char *zonepath_ds) 2570f169c0eaSGlenn Lagasse { 2571f169c0eaSGlenn Lagasse be_unmount_data_t zone_ud = { 0 }; 2572f169c0eaSGlenn Lagasse zfs_handle_t *zone_zhp = NULL; 2573f169c0eaSGlenn Lagasse char zone_altroot[MAXPATHLEN]; 2574f169c0eaSGlenn Lagasse char zoneroot[MAXPATHLEN]; 2575f169c0eaSGlenn Lagasse char zoneroot_ds[MAXPATHLEN]; 2576f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 2577f169c0eaSGlenn Lagasse 2578f169c0eaSGlenn Lagasse /* Generate string for zone's alternate root path */ 2579f169c0eaSGlenn Lagasse be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot)); 2580f169c0eaSGlenn Lagasse (void) strlcpy(zone_altroot, ud->altroot, sizeof (zone_altroot)); 2581f169c0eaSGlenn Lagasse (void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot)); 2582f169c0eaSGlenn Lagasse 2583f169c0eaSGlenn Lagasse /* Build be_unmount_data for zone */ 2584f169c0eaSGlenn Lagasse zone_ud.altroot = zone_altroot; 2585f169c0eaSGlenn Lagasse zone_ud.force = ud->force; 2586f169c0eaSGlenn Lagasse 2587f169c0eaSGlenn Lagasse /* Find the mounted zone root dataset for this zone for this BE */ 2588f169c0eaSGlenn Lagasse if ((ret = be_find_mounted_zone_root(zone_altroot, zonepath_ds, 2589f169c0eaSGlenn Lagasse zoneroot_ds, sizeof (zoneroot_ds))) == BE_ERR_NO_MOUNTED_ZONE) { 2590f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_one_zone: did not " 2591f169c0eaSGlenn Lagasse "find any zone root mounted for zone %s\n"), zonename); 2592f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2593f169c0eaSGlenn Lagasse } else if (ret != BE_SUCCESS) { 2594f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_one_zone: failed to " 2595f169c0eaSGlenn Lagasse "find mounted zone root for zone %s\n"), zonename); 2596f169c0eaSGlenn Lagasse return (ret); 2597f169c0eaSGlenn Lagasse } 2598f169c0eaSGlenn Lagasse 2599f169c0eaSGlenn Lagasse /* Get handle to zoneroot dataset mounted for this BE */ 2600f169c0eaSGlenn Lagasse if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM)) 2601f169c0eaSGlenn Lagasse == NULL) { 2602f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_one_zone: failed to " 2603f169c0eaSGlenn Lagasse "open mounted zone root dataset (%s): %s\n"), zoneroot_ds, 2604f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2605f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2606f169c0eaSGlenn Lagasse } 2607f169c0eaSGlenn Lagasse 2608f169c0eaSGlenn Lagasse /* TODO: Unmount all shared file systems for this zone */ 2609f169c0eaSGlenn Lagasse 2610f169c0eaSGlenn Lagasse /* Iterate through zone's children filesystems and unmount them */ 2611f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zone_zhp, be_unmount_callback, 2612f169c0eaSGlenn Lagasse &zone_ud)) != 0) { 2613f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_one_zone: failed to " 2614f169c0eaSGlenn Lagasse "unmount zone subordinate file systems at %s\n"), 2615f169c0eaSGlenn Lagasse zone_altroot); 2616f169c0eaSGlenn Lagasse goto done; 2617f169c0eaSGlenn Lagasse } 2618f169c0eaSGlenn Lagasse 2619f169c0eaSGlenn Lagasse /* Unmount the zone's root filesystem */ 2620f169c0eaSGlenn Lagasse if ((ret = be_unmount_zone_root(zone_zhp, &zone_ud)) != BE_SUCCESS) { 2621f169c0eaSGlenn Lagasse be_print_err(gettext("be_unmount_one_zone: failed to " 2622f169c0eaSGlenn Lagasse "unmount zone root file system at %s\n"), zone_altroot); 2623f169c0eaSGlenn Lagasse goto done; 2624f169c0eaSGlenn Lagasse } 2625f169c0eaSGlenn Lagasse 2626f169c0eaSGlenn Lagasse done: 2627f169c0eaSGlenn Lagasse ZFS_CLOSE(zone_zhp); 2628f169c0eaSGlenn Lagasse return (ret); 2629f169c0eaSGlenn Lagasse } 2630f169c0eaSGlenn Lagasse 2631f169c0eaSGlenn Lagasse /* 2632f169c0eaSGlenn Lagasse * Function: be_get_ds_from_dir_callback 2633f169c0eaSGlenn Lagasse * Description: This is a callback function used to iterate all datasets 2634f169c0eaSGlenn Lagasse * to find the one that is currently mounted at the directory 2635f169c0eaSGlenn Lagasse * being searched for. If matched, the name of the dataset is 2636f169c0eaSGlenn Lagasse * returned in heap storage, so the caller is responsible for 2637f169c0eaSGlenn Lagasse * freeing it. 2638f169c0eaSGlenn Lagasse * Parameters: 2639f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current dataset being processed. 2640f169c0eaSGlenn Lagasse * data - dir_data_t pointer providing name of directory being 2641f169c0eaSGlenn Lagasse * searched for. 2642f169c0eaSGlenn Lagasse * Returns: 2643f169c0eaSGlenn Lagasse * 1 - This dataset is mounted at directory being searched for. 2644f169c0eaSGlenn Lagasse * 0 - This dataset is not mounted at directory being searched for. 2645f169c0eaSGlenn Lagasse * Scope: 2646f169c0eaSGlenn Lagasse * Private 2647f169c0eaSGlenn Lagasse */ 2648f169c0eaSGlenn Lagasse static int 2649f169c0eaSGlenn Lagasse be_get_ds_from_dir_callback(zfs_handle_t *zhp, void *data) 2650f169c0eaSGlenn Lagasse { 2651f169c0eaSGlenn Lagasse dir_data_t *dd = data; 2652f169c0eaSGlenn Lagasse char *mp = NULL; 2653f169c0eaSGlenn Lagasse int zret = 0; 2654f169c0eaSGlenn Lagasse 2655f169c0eaSGlenn Lagasse if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2656f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2657f169c0eaSGlenn Lagasse return (0); 2658f169c0eaSGlenn Lagasse } 2659f169c0eaSGlenn Lagasse 2660f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, &mp) && mp != NULL && 2661f169c0eaSGlenn Lagasse strcmp(mp, dd->dir) == 0) { 2662f169c0eaSGlenn Lagasse if ((dd->ds = strdup(zfs_get_name(zhp))) == NULL) { 2663f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_ds_from_dir_callback: " 2664f169c0eaSGlenn Lagasse "memory allocation failed\n")); 2665f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2666f169c0eaSGlenn Lagasse return (0); 2667f169c0eaSGlenn Lagasse } 2668f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2669f169c0eaSGlenn Lagasse return (1); 2670f169c0eaSGlenn Lagasse } 2671f169c0eaSGlenn Lagasse 2672f169c0eaSGlenn Lagasse zret = zfs_iter_filesystems(zhp, be_get_ds_from_dir_callback, dd); 2673f169c0eaSGlenn Lagasse 2674f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2675f169c0eaSGlenn Lagasse 2676f169c0eaSGlenn Lagasse return (zret); 2677f169c0eaSGlenn Lagasse } 26783a876192SAlexander Pyhalov 26793a876192SAlexander Pyhalov /* 26803a876192SAlexander Pyhalov * Function: mount_zfs 26813a876192SAlexander Pyhalov * Description: This is a function to mount zfs filesystem to alternative 26823a876192SAlexander Pyhalov * root without changing zfs mountpoint property. Logic is 26833a876192SAlexander Pyhalov * similar to zfs_mount. 26843a876192SAlexander Pyhalov * Parameters: 26853a876192SAlexander Pyhalov * zhp - zfs_handle_t pointer to current dataset being processed. 26863a876192SAlexander Pyhalov * altroot - char pointer to current alternative root. 26873a876192SAlexander Pyhalov * Returns: 26883a876192SAlexander Pyhalov * BE_SUCCESS - Success 26893a876192SAlexander Pyhalov * be_errno_t - Failure 26903a876192SAlexander Pyhalov * Scope: 26913a876192SAlexander Pyhalov * Private 26923a876192SAlexander Pyhalov */ 26933a876192SAlexander Pyhalov static int 26943a876192SAlexander Pyhalov mount_zfs(zfs_handle_t *zhp, char *altroot) 26953a876192SAlexander Pyhalov { 26963a876192SAlexander Pyhalov int flags = 0; 26973a876192SAlexander Pyhalov char mountpoint[MAXPATHLEN]; 26983a876192SAlexander Pyhalov char real_mountpoint[MAXPATHLEN]; 26993a876192SAlexander Pyhalov char source[MAXNAMELEN]; 2700*19f5167cSToomas Soome char optstr[MAX_MNTOPT_STR]; 27013a876192SAlexander Pyhalov zprop_source_t sourcetype; 27023a876192SAlexander Pyhalov struct stat buf; 27033a876192SAlexander Pyhalov 2704*19f5167cSToomas Soome optstr[0] = '\0'; 2705*19f5167cSToomas Soome 27063a876192SAlexander Pyhalov /* Get dataset's mountpoint and source values */ 27073a876192SAlexander Pyhalov if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 27083a876192SAlexander Pyhalov sizeof (mountpoint), &sourcetype, source, sizeof (source), 27093a876192SAlexander Pyhalov B_FALSE) != 0) { 27103a876192SAlexander Pyhalov be_print_err(gettext("mount_zfs: " 27113a876192SAlexander Pyhalov "failed to get mountpoint and sourcetype for %s\n"), 27123a876192SAlexander Pyhalov zfs_get_name(zhp)); 27133a876192SAlexander Pyhalov ZFS_CLOSE(zhp); 27143a876192SAlexander Pyhalov return (BE_ERR_ZFS); 27153a876192SAlexander Pyhalov } 27163a876192SAlexander Pyhalov 27173a876192SAlexander Pyhalov if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0 || 27183a876192SAlexander Pyhalov strcmp(mountpoint, "/") == 0) { 27193a876192SAlexander Pyhalov /* 27203a876192SAlexander Pyhalov * We are called only from be_mount_root or be_mount_callback 27213a876192SAlexander Pyhalov * when mountpoint != LEGACY 27223a876192SAlexander Pyhalov */ 27233a876192SAlexander Pyhalov mountpoint[0] = '\0'; 27243a876192SAlexander Pyhalov } 27253a876192SAlexander Pyhalov 27263a876192SAlexander Pyhalov (void) snprintf(real_mountpoint, MAXPATHLEN, "%s%s", altroot, 27273a876192SAlexander Pyhalov mountpoint); 27283a876192SAlexander Pyhalov 27293a876192SAlexander Pyhalov if (zpool_get_prop_int(zfs_get_pool_handle(zhp), ZPOOL_PROP_READONLY, 27303a876192SAlexander Pyhalov NULL)) 27313a876192SAlexander Pyhalov flags |= MS_RDONLY; 27323a876192SAlexander Pyhalov 27333a876192SAlexander Pyhalov /* Create the directory if it doesn't already exist */ 27343a876192SAlexander Pyhalov if (lstat(real_mountpoint, &buf) != 0) { 27353a876192SAlexander Pyhalov if (mkdirp(real_mountpoint, 0755) != 0) { 27363a876192SAlexander Pyhalov be_print_err(gettext("mount_zfs: " 27373a876192SAlexander Pyhalov "failed to create mountpoint for %s\n"), 27383a876192SAlexander Pyhalov zfs_get_name(zhp)); 27393a876192SAlexander Pyhalov ZFS_CLOSE(zhp); 27403a876192SAlexander Pyhalov return (BE_ERR_ZFS); 27413a876192SAlexander Pyhalov } 27423a876192SAlexander Pyhalov } 27433a876192SAlexander Pyhalov 2744*19f5167cSToomas Soome if (mount(zfs_get_name(zhp), real_mountpoint, MS_OPTIONSTR | flags, 2745*19f5167cSToomas Soome MNTTYPE_ZFS, NULL, 0, optstr, sizeof (optstr))) { 27463a876192SAlexander Pyhalov be_print_err(gettext("mount_zfs: failed to " 27473a876192SAlexander Pyhalov "mount dataset %s at %s\n"), zfs_get_name(zhp), 27483a876192SAlexander Pyhalov real_mountpoint); 27493a876192SAlexander Pyhalov return (BE_ERR_ZFS); 27503a876192SAlexander Pyhalov } 27513a876192SAlexander Pyhalov 27523a876192SAlexander Pyhalov return (BE_SUCCESS); 27533a876192SAlexander Pyhalov } 2754