Print this page
    
cstyle fixes
dsl_dataset_set_fsid_guid should use ZFS_SPACE_CHECK_RESERVED
dsl_dataset_set_fsid_guid _check and _sync func declared static,
removed from dsl_dataset.h
rewrite unique_valid
6333 ZFS should let the user specify or modify the fsid_guid of a dataset
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libzfs/common/libzfs_changelist.c
          +++ new/usr/src/lib/libzfs/common/libzfs_changelist.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
  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 2010 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   *
  26   26   * Portions Copyright 2007 Ramprakash Jelari
  27   27   */
  28   28  
  29   29  #include <libintl.h>
  30   30  #include <libuutil.h>
  31   31  #include <stddef.h>
  32   32  #include <stdlib.h>
  33   33  #include <string.h>
  34   34  #include <unistd.h>
  35   35  #include <zone.h>
  36   36  
  37   37  #include <libzfs.h>
  38   38  
  39   39  #include "libzfs_impl.h"
  40   40  
  41   41  /*
  42   42   * Structure to keep track of dataset state.  Before changing the 'sharenfs' or
  43   43   * 'mountpoint' property, we record whether the filesystem was previously
  44   44   * mounted/shared.  This prior state dictates whether we remount/reshare the
  45   45   * dataset after the property has been changed.
  46   46   *
  47   47   * The interface consists of the following sequence of functions:
  48   48   *
  49   49   *      changelist_gather()
  50   50   *      changelist_prefix()
  51   51   *      < change property >
  52   52   *      changelist_postfix()
  53   53   *      changelist_free()
  54   54   *
  55   55   * Other interfaces:
  56   56   *
  57   57   * changelist_remove() - remove a node from a gathered list
  58   58   * changelist_rename() - renames all datasets appropriately when doing a rename
  59   59   * changelist_unshare() - unshares all the nodes in a given changelist
  60   60   * changelist_haszonedchild() - check if there is any child exported to
  61   61   *                              a local zone
  62   62   */
  63   63  typedef struct prop_changenode {
  64   64          zfs_handle_t            *cn_handle;
  65   65          int                     cn_shared;
  66   66          int                     cn_mounted;
  67   67          int                     cn_zoned;
  68   68          boolean_t               cn_needpost;    /* is postfix() needed? */
  69   69          uu_list_node_t          cn_listnode;
  70   70  } prop_changenode_t;
  71   71  
  72   72  struct prop_changelist {
  73   73          zfs_prop_t              cl_prop;
  74   74          zfs_prop_t              cl_realprop;
  75   75          zfs_prop_t              cl_shareprop;  /* used with sharenfs/sharesmb */
  76   76          uu_list_pool_t          *cl_pool;
  77   77          uu_list_t               *cl_list;
  78   78          boolean_t               cl_waslegacy;
  79   79          boolean_t               cl_allchildren;
  80   80          boolean_t               cl_alldependents;
  81   81          int                     cl_mflags;      /* Mount flags */
  82   82          int                     cl_gflags;      /* Gather request flags */
  83   83          boolean_t               cl_haszonedchild;
  84   84          boolean_t               cl_sorted;
  85   85  };
  86   86  
  87   87  /*
  88   88   * If the property is 'mountpoint', go through and unmount filesystems as
  89   89   * necessary.  We don't do the same for 'sharenfs', because we can just re-share
  90   90   * with different options without interrupting service. We do handle 'sharesmb'
  91   91   * since there may be old resource names that need to be removed.
  92   92   */
  93   93  int
  94   94  changelist_prefix(prop_changelist_t *clp)
  95   95  {
  96   96          prop_changenode_t *cn;
  97   97          int ret = 0;
  98   98  
  99   99          if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
 100  100              clp->cl_prop != ZFS_PROP_SHARESMB)
 101  101                  return (0);
 102  102  
 103  103          for (cn = uu_list_first(clp->cl_list); cn != NULL;
 104  104              cn = uu_list_next(clp->cl_list, cn)) {
 105  105  
 106  106                  /* if a previous loop failed, set the remaining to false */
 107  107                  if (ret == -1) {
 108  108                          cn->cn_needpost = B_FALSE;
 109  109                          continue;
 110  110                  }
 111  111  
 112  112                  /*
 113  113                   * If we are in the global zone, but this dataset is exported
 114  114                   * to a local zone, do nothing.
 115  115                   */
 116  116                  if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
 117  117                          continue;
 118  118  
 119  119                  if (!ZFS_IS_VOLUME(cn->cn_handle)) {
 120  120                          /*
 121  121                           * Do the property specific processing.
 122  122                           */
 123  123                          switch (clp->cl_prop) {
 124  124                          case ZFS_PROP_MOUNTPOINT:
 125  125                                  if (zfs_unmount(cn->cn_handle, NULL,
 126  126                                      clp->cl_mflags) != 0) {
 127  127                                          ret = -1;
 128  128                                          cn->cn_needpost = B_FALSE;
 129  129                                  }
 130  130                                  break;
 131  131                          case ZFS_PROP_SHARESMB:
 132  132                                  (void) zfs_unshare_smb(cn->cn_handle, NULL);
 133  133                                  break;
 134  134                          }
 135  135                  }
 136  136          }
 137  137  
 138  138          if (ret == -1)
 139  139                  (void) changelist_postfix(clp);
 140  140  
 141  141          return (ret);
 142  142  }
 143  143  
 144  144  /*
 145  145   * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
 146  146   * reshare the filesystems as necessary.  In changelist_gather() we recorded
 147  147   * whether the filesystem was previously shared or mounted.  The action we take
 148  148   * depends on the previous state, and whether the value was previously 'legacy'.
 149  149   * For non-legacy properties, we only remount/reshare the filesystem if it was
 150  150   * previously mounted/shared.  Otherwise, we always remount/reshare the
 151  151   * filesystem.
 152  152   */
 153  153  int
 154  154  changelist_postfix(prop_changelist_t *clp)
 155  155  {
 156  156          prop_changenode_t *cn;
 157  157          char shareopts[ZFS_MAXPROPLEN];
 158  158          int errors = 0;
 159  159          libzfs_handle_t *hdl;
 160  160  
 161  161          /*
 162  162           * If we're changing the mountpoint, attempt to destroy the underlying
 163  163           * mountpoint.  All other datasets will have inherited from this dataset
 164  164           * (in which case their mountpoints exist in the filesystem in the new
 165  165           * location), or have explicit mountpoints set (in which case they won't
 166  166           * be in the changelist).
 167  167           */
 168  168          if ((cn = uu_list_last(clp->cl_list)) == NULL)
 169  169                  return (0);
 170  170  
 171  171          if (clp->cl_prop == ZFS_PROP_MOUNTPOINT)
 172  172                  remove_mountpoint(cn->cn_handle);
 173  173  
 174  174          /*
 175  175           * It is possible that the changelist_prefix() used libshare
 176  176           * to unshare some entries. Since libshare caches data, an
 177  177           * attempt to reshare during postfix can fail unless libshare
 178  178           * is uninitialized here so that it will reinitialize later.
 179  179           */
 180  180          if (cn->cn_handle != NULL) {
 181  181                  hdl = cn->cn_handle->zfs_hdl;
 182  182                  assert(hdl != NULL);
 183  183                  zfs_uninit_libshare(hdl);
 184  184          }
 185  185  
 186  186          /*
 187  187           * We walk the datasets in reverse, because we want to mount any parent
 188  188           * datasets before mounting the children.  We walk all datasets even if
 189  189           * there are errors.
 190  190           */
 191  191          for (cn = uu_list_last(clp->cl_list); cn != NULL;
 192  192              cn = uu_list_prev(clp->cl_list, cn)) {
 193  193  
 194  194                  boolean_t sharenfs;
 195  195                  boolean_t sharesmb;
 196  196                  boolean_t mounted;
 197  197  
 198  198                  /*
 199  199                   * If we are in the global zone, but this dataset is exported
 200  200                   * to a local zone, do nothing.
 201  201                   */
 202  202                  if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
 203  203                          continue;
 204  204  
 205  205                  /* Only do post-processing if it's required */
 206  206                  if (!cn->cn_needpost)
 207  207                          continue;
 208  208                  cn->cn_needpost = B_FALSE;
 209  209  
 210  210                  zfs_refresh_properties(cn->cn_handle);
 211  211  
 212  212                  if (ZFS_IS_VOLUME(cn->cn_handle))
 213  213                          continue;
 214  214  
 215  215                  /*
 216  216                   * Remount if previously mounted or mountpoint was legacy,
 217  217                   * or sharenfs or sharesmb  property is set.
 218  218                   */
 219  219                  sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
 220  220                      shareopts, sizeof (shareopts), NULL, NULL, 0,
 221  221                      B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
 222  222  
 223  223                  sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
 224  224                      shareopts, sizeof (shareopts), NULL, NULL, 0,
 225  225                      B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
 226  226  
 227  227                  mounted = zfs_is_mounted(cn->cn_handle, NULL);
 228  228  
 229  229                  if (!mounted && (cn->cn_mounted ||
 230  230                      ((sharenfs || sharesmb || clp->cl_waslegacy) &&
 231  231                      (zfs_prop_get_int(cn->cn_handle,
 232  232                      ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) {
 233  233  
 234  234                          if (zfs_mount(cn->cn_handle, NULL, 0) != 0)
 235  235                                  errors++;
 236  236                          else
 237  237                                  mounted = TRUE;
 238  238                  }
 239  239  
 240  240                  /*
 241  241                   * If the file system is mounted we always re-share even
 242  242                   * if the filesystem is currently shared, so that we can
 243  243                   * adopt any new options.
 244  244                   */
 245  245                  if (sharenfs && mounted)
 246  246                          errors += zfs_share_nfs(cn->cn_handle);
 247  247                  else if (cn->cn_shared || clp->cl_waslegacy)
 248  248                          errors += zfs_unshare_nfs(cn->cn_handle, NULL);
 249  249                  if (sharesmb && mounted)
 250  250                          errors += zfs_share_smb(cn->cn_handle);
 251  251                  else if (cn->cn_shared || clp->cl_waslegacy)
 252  252                          errors += zfs_unshare_smb(cn->cn_handle, NULL);
 253  253          }
 254  254  
 255  255          return (errors ? -1 : 0);
 256  256  }
 257  257  
 258  258  /*
 259  259   * Is this "dataset" a child of "parent"?
 260  260   */
 261  261  boolean_t
 262  262  isa_child_of(const char *dataset, const char *parent)
 263  263  {
 264  264          int len;
 265  265  
 266  266          len = strlen(parent);
 267  267  
 268  268          if (strncmp(dataset, parent, len) == 0 &&
 269  269              (dataset[len] == '@' || dataset[len] == '/' ||
 270  270              dataset[len] == '\0'))
 271  271                  return (B_TRUE);
 272  272          else
 273  273                  return (B_FALSE);
 274  274  
 275  275  }
 276  276  
 277  277  /*
 278  278   * If we rename a filesystem, child filesystem handles are no longer valid
 279  279   * since we identify each dataset by its name in the ZFS namespace.  As a
 280  280   * result, we have to go through and fix up all the names appropriately.  We
 281  281   * could do this automatically if libzfs kept track of all open handles, but
 282  282   * this is a lot less work.
 283  283   */
 284  284  void
 285  285  changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
 286  286  {
 287  287          prop_changenode_t *cn;
 288  288          char newname[ZFS_MAXNAMELEN];
 289  289  
 290  290          for (cn = uu_list_first(clp->cl_list); cn != NULL;
 291  291              cn = uu_list_next(clp->cl_list, cn)) {
 292  292                  /*
 293  293                   * Do not rename a clone that's not in the source hierarchy.
 294  294                   */
 295  295                  if (!isa_child_of(cn->cn_handle->zfs_name, src))
 296  296                          continue;
 297  297  
 298  298                  /*
 299  299                   * Destroy the previous mountpoint if needed.
 300  300                   */
 301  301                  remove_mountpoint(cn->cn_handle);
 302  302  
 303  303                  (void) strlcpy(newname, dst, sizeof (newname));
 304  304                  (void) strcat(newname, cn->cn_handle->zfs_name + strlen(src));
 305  305  
 306  306                  (void) strlcpy(cn->cn_handle->zfs_name, newname,
 307  307                      sizeof (cn->cn_handle->zfs_name));
 308  308          }
 309  309  }
 310  310  
 311  311  /*
 312  312   * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property,
 313  313   * unshare all the datasets in the list.
 314  314   */
 315  315  int
 316  316  changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto)
 317  317  {
 318  318          prop_changenode_t *cn;
 319  319          int ret = 0;
 320  320  
 321  321          if (clp->cl_prop != ZFS_PROP_SHARENFS &&
 322  322              clp->cl_prop != ZFS_PROP_SHARESMB)
 323  323                  return (0);
 324  324  
 325  325          for (cn = uu_list_first(clp->cl_list); cn != NULL;
 326  326              cn = uu_list_next(clp->cl_list, cn)) {
 327  327                  if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0)
 328  328                          ret = -1;
 329  329          }
 330  330  
 331  331          return (ret);
 332  332  }
 333  333  
 334  334  /*
 335  335   * Check if there is any child exported to a local zone in a given changelist.
 336  336   * This information has already been recorded while gathering the changelist
 337  337   * via changelist_gather().
 338  338   */
 339  339  int
 340  340  changelist_haszonedchild(prop_changelist_t *clp)
 341  341  {
 342  342          return (clp->cl_haszonedchild);
 343  343  }
 344  344  
 345  345  /*
 346  346   * Remove a node from a gathered list.
 347  347   */
 348  348  void
 349  349  changelist_remove(prop_changelist_t *clp, const char *name)
 350  350  {
 351  351          prop_changenode_t *cn;
 352  352  
 353  353          for (cn = uu_list_first(clp->cl_list); cn != NULL;
 354  354              cn = uu_list_next(clp->cl_list, cn)) {
 355  355  
 356  356                  if (strcmp(cn->cn_handle->zfs_name, name) == 0) {
 357  357                          uu_list_remove(clp->cl_list, cn);
 358  358                          zfs_close(cn->cn_handle);
 359  359                          free(cn);
 360  360                          return;
 361  361                  }
 362  362          }
 363  363  }
 364  364  
 365  365  /*
 366  366   * Release any memory associated with a changelist.
 367  367   */
 368  368  void
 369  369  changelist_free(prop_changelist_t *clp)
 370  370  {
 371  371          prop_changenode_t *cn;
 372  372          void *cookie;
 373  373  
 374  374          if (clp->cl_list) {
 375  375                  cookie = NULL;
 376  376                  while ((cn = uu_list_teardown(clp->cl_list, &cookie)) != NULL) {
 377  377                          zfs_close(cn->cn_handle);
 378  378                          free(cn);
 379  379                  }
 380  380  
 381  381                  uu_list_destroy(clp->cl_list);
 382  382          }
 383  383          if (clp->cl_pool)
 384  384                  uu_list_pool_destroy(clp->cl_pool);
 385  385  
 386  386          free(clp);
 387  387  }
 388  388  
 389  389  static int
 390  390  change_one(zfs_handle_t *zhp, void *data)
 391  391  {
 392  392          prop_changelist_t *clp = data;
 393  393          char property[ZFS_MAXPROPLEN];
 394  394          char where[64];
 395  395          prop_changenode_t *cn;
 396  396          zprop_source_t sourcetype;
 397  397          zprop_source_t share_sourcetype;
 398  398  
 399  399          /*
 400  400           * We only want to unmount/unshare those filesystems that may inherit
 401  401           * from the target filesystem.  If we find any filesystem with a
 402  402           * locally set mountpoint, we ignore any children since changing the
 403  403           * property will not affect them.  If this is a rename, we iterate
 404  404           * over all children regardless, since we need them unmounted in
 405  405           * order to do the rename.  Also, if this is a volume and we're doing
 406  406           * a rename, then always add it to the changelist.
 407  407           */
 408  408  
 409  409          if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
 410  410              zfs_prop_get(zhp, clp->cl_prop, property,
 411  411              sizeof (property), &sourcetype, where, sizeof (where),
 412  412              B_FALSE) != 0) {
 413  413                  zfs_close(zhp);
 414  414                  return (0);
 415  415          }
 416  416  
 417  417          /*
 418  418           * If we are "watching" sharenfs or sharesmb
 419  419           * then check out the companion property which is tracked
 420  420           * in cl_shareprop
 421  421           */
 422  422          if (clp->cl_shareprop != ZPROP_INVAL &&
 423  423              zfs_prop_get(zhp, clp->cl_shareprop, property,
 424  424              sizeof (property), &share_sourcetype, where, sizeof (where),
 425  425              B_FALSE) != 0) {
 426  426                  zfs_close(zhp);
 427  427                  return (0);
 428  428          }
 429  429  
 430  430          if (clp->cl_alldependents || clp->cl_allchildren ||
 431  431              sourcetype == ZPROP_SRC_DEFAULT ||
 432  432              sourcetype == ZPROP_SRC_INHERITED ||
 433  433              (clp->cl_shareprop != ZPROP_INVAL &&
 434  434              (share_sourcetype == ZPROP_SRC_DEFAULT ||
 435  435              share_sourcetype == ZPROP_SRC_INHERITED))) {
 436  436                  if ((cn = zfs_alloc(zfs_get_handle(zhp),
 437  437                      sizeof (prop_changenode_t))) == NULL) {
 438  438                          zfs_close(zhp);
 439  439                          return (-1);
 440  440                  }
 441  441  
 442  442                  cn->cn_handle = zhp;
 443  443                  cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
 444  444                      zfs_is_mounted(zhp, NULL);
 445  445                  cn->cn_shared = zfs_is_shared(zhp);
 446  446                  cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
 447  447                  cn->cn_needpost = B_TRUE;
 448  448  
 449  449                  /* Indicate if any child is exported to a local zone. */
 450  450                  if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
 451  451                          clp->cl_haszonedchild = B_TRUE;
 452  452  
 453  453                  uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
 454  454  
 455  455                  if (clp->cl_sorted) {
 456  456                          uu_list_index_t idx;
 457  457  
 458  458                          (void) uu_list_find(clp->cl_list, cn, NULL,
 459  459                              &idx);
 460  460                          uu_list_insert(clp->cl_list, cn, idx);
 461  461                  } else {
 462  462                          /*
 463  463                           * Add this child to beginning of the list. Children
 464  464                           * below this one in the hierarchy will get added above
 465  465                           * this one in the list. This produces a list in
 466  466                           * reverse dataset name order.
 467  467                           * This is necessary when the original mountpoint
 468  468                           * is legacy or none.
 469  469                           */
 470  470                          ASSERT(!clp->cl_alldependents);
 471  471                          verify(uu_list_insert_before(clp->cl_list,
 472  472                              uu_list_first(clp->cl_list), cn) == 0);
 473  473                  }
 474  474  
 475  475                  if (!clp->cl_alldependents)
 476  476                          return (zfs_iter_children(zhp, change_one, data));
 477  477          } else {
 478  478                  zfs_close(zhp);
 479  479          }
 480  480  
 481  481          return (0);
 482  482  }
 483  483  
 484  484  /*ARGSUSED*/
 485  485  static int
 486  486  compare_mountpoints(const void *a, const void *b, void *unused)
 487  487  {
 488  488          const prop_changenode_t *ca = a;
 489  489          const prop_changenode_t *cb = b;
 490  490  
 491  491          char mounta[MAXPATHLEN];
 492  492          char mountb[MAXPATHLEN];
 493  493  
 494  494          boolean_t hasmounta, hasmountb;
 495  495  
 496  496          /*
 497  497           * When unsharing or unmounting filesystems, we need to do it in
 498  498           * mountpoint order.  This allows the user to have a mountpoint
 499  499           * hierarchy that is different from the dataset hierarchy, and still
 500  500           * allow it to be changed.  However, if either dataset doesn't have a
 501  501           * mountpoint (because it is a volume or a snapshot), we place it at the
 502  502           * end of the list, because it doesn't affect our change at all.
 503  503           */
 504  504          hasmounta = (zfs_prop_get(ca->cn_handle, ZFS_PROP_MOUNTPOINT, mounta,
 505  505              sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
 506  506          hasmountb = (zfs_prop_get(cb->cn_handle, ZFS_PROP_MOUNTPOINT, mountb,
 507  507              sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
 508  508  
 509  509          if (!hasmounta && hasmountb)
 510  510                  return (-1);
 511  511          else if (hasmounta && !hasmountb)
 512  512                  return (1);
 513  513          else if (!hasmounta && !hasmountb)
 514  514                  return (0);
 515  515          else
 516  516                  return (strcmp(mountb, mounta));
 517  517  }
 518  518  
 519  519  /*
 520  520   * Given a ZFS handle and a property, construct a complete list of datasets
 521  521   * that need to be modified as part of this process.  For anything but the
 522  522   * 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
 523  523   * Otherwise, we iterate over all children and look for any datasets that
 524  524   * inherit the property.  For each such dataset, we add it to the list and
 525  525   * mark whether it was shared beforehand.
 526  526   */
 527  527  prop_changelist_t *
 528  528  changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
 529  529      int mnt_flags)
 530  530  {
 531  531          prop_changelist_t *clp;
 532  532          prop_changenode_t *cn;
 533  533          zfs_handle_t *temp;
 534  534          char property[ZFS_MAXPROPLEN];
 535  535          uu_compare_fn_t *compare = NULL;
 536  536          boolean_t legacy = B_FALSE;
 537  537  
 538  538          if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
 539  539                  return (NULL);
 540  540  
 541  541          /*
 542  542           * For mountpoint-related tasks, we want to sort everything by
 543  543           * mountpoint, so that we mount and unmount them in the appropriate
 544  544           * order, regardless of their position in the hierarchy.
 545  545           */
 546  546          if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
 547  547              prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
 548  548              prop == ZFS_PROP_SHARESMB) {
 549  549  
 550  550                  if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
 551  551                      property, sizeof (property),
 552  552                      NULL, NULL, 0, B_FALSE) == 0 &&
 553  553                      (strcmp(property, "legacy") == 0 ||
 554  554                      strcmp(property, "none") == 0)) {
 555  555  
 556  556                          legacy = B_TRUE;
 557  557                  }
 558  558                  if (!legacy) {
 559  559                          compare = compare_mountpoints;
 560  560                          clp->cl_sorted = B_TRUE;
 561  561                  }
 562  562          }
 563  563  
 564  564          clp->cl_pool = uu_list_pool_create("changelist_pool",
 565  565              sizeof (prop_changenode_t),
 566  566              offsetof(prop_changenode_t, cn_listnode),
 567  567              compare, 0);
 568  568          if (clp->cl_pool == NULL) {
 569  569                  assert(uu_error() == UU_ERROR_NO_MEMORY);
 570  570                  (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
 571  571                  changelist_free(clp);
 572  572                  return (NULL);
 573  573          }
 574  574  
 575  575          clp->cl_list = uu_list_create(clp->cl_pool, NULL,
 576  576              clp->cl_sorted ? UU_LIST_SORTED : 0);
 577  577          clp->cl_gflags = gather_flags;
 578  578          clp->cl_mflags = mnt_flags;
 579  579  
 580  580          if (clp->cl_list == NULL) {
 581  581                  assert(uu_error() == UU_ERROR_NO_MEMORY);
 582  582                  (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
 583  583                  changelist_free(clp);
 584  584                  return (NULL);
 585  585          }
 586  586  
 587  587          /*
 588  588           * If this is a rename or the 'zoned' property, we pretend we're
 589  589           * changing the mountpoint and flag it so we can catch all children in
 590  590           * change_one().
 591  591           *
 592  592           * Flag cl_alldependents to catch all children plus the dependents
 593  593           * (clones) that are not in the hierarchy.
 594  594           */
  
    | ↓ open down ↓ | 594 lines elided | ↑ open up ↑ | 
 595  595          if (prop == ZFS_PROP_NAME) {
 596  596                  clp->cl_prop = ZFS_PROP_MOUNTPOINT;
 597  597                  clp->cl_alldependents = B_TRUE;
 598  598          } else if (prop == ZFS_PROP_ZONED) {
 599  599                  clp->cl_prop = ZFS_PROP_MOUNTPOINT;
 600  600                  clp->cl_allchildren = B_TRUE;
 601  601          } else if (prop == ZFS_PROP_CANMOUNT) {
 602  602                  clp->cl_prop = ZFS_PROP_MOUNTPOINT;
 603  603          } else if (prop == ZFS_PROP_VOLSIZE) {
 604  604                  clp->cl_prop = ZFS_PROP_MOUNTPOINT;
      605 +        } else if (prop == ZFS_PROP_FSID_GUID) {
      606 +                clp->cl_prop = ZFS_PROP_MOUNTPOINT;
 605  607          } else {
 606  608                  clp->cl_prop = prop;
 607  609          }
 608  610          clp->cl_realprop = prop;
 609  611  
 610  612          if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
 611  613              clp->cl_prop != ZFS_PROP_SHARENFS &&
 612  614              clp->cl_prop != ZFS_PROP_SHARESMB)
 613  615                  return (clp);
 614  616  
 615  617          /*
 616  618           * If watching SHARENFS or SHARESMB then
 617  619           * also watch its companion property.
 618  620           */
 619  621          if (clp->cl_prop == ZFS_PROP_SHARENFS)
 620  622                  clp->cl_shareprop = ZFS_PROP_SHARESMB;
 621  623          else if (clp->cl_prop == ZFS_PROP_SHARESMB)
 622  624                  clp->cl_shareprop = ZFS_PROP_SHARENFS;
 623  625  
 624  626          if (clp->cl_alldependents) {
 625  627                  if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
 626  628                          changelist_free(clp);
 627  629                          return (NULL);
 628  630                  }
 629  631          } else if (zfs_iter_children(zhp, change_one, clp) != 0) {
 630  632                  changelist_free(clp);
 631  633                  return (NULL);
 632  634          }
 633  635  
 634  636          /*
 635  637           * We have to re-open ourselves because we auto-close all the handles
 636  638           * and can't tell the difference.
 637  639           */
 638  640          if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
 639  641              ZFS_TYPE_DATASET)) == NULL) {
 640  642                  changelist_free(clp);
 641  643                  return (NULL);
 642  644          }
 643  645  
 644  646          /*
 645  647           * Always add ourself to the list.  We add ourselves to the end so that
 646  648           * we're the last to be unmounted.
 647  649           */
 648  650          if ((cn = zfs_alloc(zhp->zfs_hdl,
 649  651              sizeof (prop_changenode_t))) == NULL) {
 650  652                  zfs_close(temp);
 651  653                  changelist_free(clp);
 652  654                  return (NULL);
 653  655          }
 654  656  
 655  657          cn->cn_handle = temp;
 656  658          cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
 657  659              zfs_is_mounted(temp, NULL);
 658  660          cn->cn_shared = zfs_is_shared(temp);
 659  661          cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
 660  662          cn->cn_needpost = B_TRUE;
 661  663  
 662  664          uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
 663  665          if (clp->cl_sorted) {
 664  666                  uu_list_index_t idx;
 665  667                  (void) uu_list_find(clp->cl_list, cn, NULL, &idx);
 666  668                  uu_list_insert(clp->cl_list, cn, idx);
 667  669          } else {
 668  670                  /*
 669  671                   * Add the target dataset to the end of the list.
 670  672                   * The list is not really unsorted. The list will be
 671  673                   * in reverse dataset name order. This is necessary
 672  674                   * when the original mountpoint is legacy or none.
 673  675                   */
 674  676                  verify(uu_list_insert_after(clp->cl_list,
 675  677                      uu_list_last(clp->cl_list), cn) == 0);
 676  678          }
 677  679  
 678  680          /*
 679  681           * If the mountpoint property was previously 'legacy', or 'none',
 680  682           * record it as the behavior of changelist_postfix() will be different.
 681  683           */
 682  684          if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) && legacy) {
 683  685                  /*
 684  686                   * do not automatically mount ex-legacy datasets if
 685  687                   * we specifically set canmount to noauto
 686  688                   */
 687  689                  if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) !=
 688  690                      ZFS_CANMOUNT_NOAUTO)
 689  691                          clp->cl_waslegacy = B_TRUE;
 690  692          }
 691  693  
 692  694          return (clp);
 693  695  }
  
    | ↓ open down ↓ | 79 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX