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