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