Print this page
    
3740 Poor ZFS send / receive performance due to snapshot hold / release processing
Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libzfs/common/libzfs_dataset.c
          +++ new/usr/src/lib/libzfs/common/libzfs_dataset.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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright (c) 2012 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
  26   26   * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
  27   27   */
  28   28  
  29   29  #include <ctype.h>
  30   30  #include <errno.h>
  31   31  #include <libintl.h>
  32   32  #include <math.h>
  33   33  #include <stdio.h>
  34   34  #include <stdlib.h>
  35   35  #include <strings.h>
  36   36  #include <unistd.h>
  37   37  #include <stddef.h>
  38   38  #include <zone.h>
  39   39  #include <fcntl.h>
  40   40  #include <sys/mntent.h>
  41   41  #include <sys/mount.h>
  42   42  #include <priv.h>
  43   43  #include <pwd.h>
  44   44  #include <grp.h>
  45   45  #include <stddef.h>
  46   46  #include <ucred.h>
  47   47  #include <idmap.h>
  48   48  #include <aclutils.h>
  49   49  #include <directory.h>
  50   50  
  51   51  #include <sys/dnode.h>
  52   52  #include <sys/spa.h>
  53   53  #include <sys/zap.h>
  54   54  #include <libzfs.h>
  55   55  
  56   56  #include "zfs_namecheck.h"
  57   57  #include "zfs_prop.h"
  58   58  #include "libzfs_impl.h"
  59   59  #include "zfs_deleg.h"
  60   60  
  61   61  static int userquota_propname_decode(const char *propname, boolean_t zoned,
  62   62      zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
  63   63  
  64   64  /*
  65   65   * Given a single type (not a mask of types), return the type in a human
  66   66   * readable form.
  67   67   */
  68   68  const char *
  69   69  zfs_type_to_name(zfs_type_t type)
  70   70  {
  71   71          switch (type) {
  72   72          case ZFS_TYPE_FILESYSTEM:
  73   73                  return (dgettext(TEXT_DOMAIN, "filesystem"));
  74   74          case ZFS_TYPE_SNAPSHOT:
  75   75                  return (dgettext(TEXT_DOMAIN, "snapshot"));
  76   76          case ZFS_TYPE_VOLUME:
  77   77                  return (dgettext(TEXT_DOMAIN, "volume"));
  78   78          }
  79   79  
  80   80          return (NULL);
  81   81  }
  82   82  
  83   83  /*
  84   84   * Given a path and mask of ZFS types, return a string describing this dataset.
  85   85   * This is used when we fail to open a dataset and we cannot get an exact type.
  86   86   * We guess what the type would have been based on the path and the mask of
  87   87   * acceptable types.
  88   88   */
  89   89  static const char *
  90   90  path_to_str(const char *path, int types)
  91   91  {
  92   92          /*
  93   93           * When given a single type, always report the exact type.
  94   94           */
  95   95          if (types == ZFS_TYPE_SNAPSHOT)
  96   96                  return (dgettext(TEXT_DOMAIN, "snapshot"));
  97   97          if (types == ZFS_TYPE_FILESYSTEM)
  98   98                  return (dgettext(TEXT_DOMAIN, "filesystem"));
  99   99          if (types == ZFS_TYPE_VOLUME)
 100  100                  return (dgettext(TEXT_DOMAIN, "volume"));
 101  101  
 102  102          /*
 103  103           * The user is requesting more than one type of dataset.  If this is the
 104  104           * case, consult the path itself.  If we're looking for a snapshot, and
 105  105           * a '@' is found, then report it as "snapshot".  Otherwise, remove the
 106  106           * snapshot attribute and try again.
 107  107           */
 108  108          if (types & ZFS_TYPE_SNAPSHOT) {
 109  109                  if (strchr(path, '@') != NULL)
 110  110                          return (dgettext(TEXT_DOMAIN, "snapshot"));
 111  111                  return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
 112  112          }
 113  113  
 114  114          /*
 115  115           * The user has requested either filesystems or volumes.
 116  116           * We have no way of knowing a priori what type this would be, so always
 117  117           * report it as "filesystem" or "volume", our two primitive types.
 118  118           */
 119  119          if (types & ZFS_TYPE_FILESYSTEM)
 120  120                  return (dgettext(TEXT_DOMAIN, "filesystem"));
 121  121  
 122  122          assert(types & ZFS_TYPE_VOLUME);
 123  123          return (dgettext(TEXT_DOMAIN, "volume"));
 124  124  }
 125  125  
 126  126  /*
 127  127   * Validate a ZFS path.  This is used even before trying to open the dataset, to
 128  128   * provide a more meaningful error message.  We call zfs_error_aux() to
 129  129   * explain exactly why the name was not valid.
 130  130   */
 131  131  int
 132  132  zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
 133  133      boolean_t modifying)
 134  134  {
 135  135          namecheck_err_t why;
 136  136          char what;
 137  137  
 138  138          (void) zfs_prop_get_table();
 139  139          if (dataset_namecheck(path, &why, &what) != 0) {
 140  140                  if (hdl != NULL) {
 141  141                          switch (why) {
 142  142                          case NAME_ERR_TOOLONG:
 143  143                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 144  144                                      "name is too long"));
 145  145                                  break;
 146  146  
 147  147                          case NAME_ERR_LEADING_SLASH:
 148  148                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 149  149                                      "leading slash in name"));
 150  150                                  break;
 151  151  
 152  152                          case NAME_ERR_EMPTY_COMPONENT:
 153  153                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 154  154                                      "empty component in name"));
 155  155                                  break;
 156  156  
 157  157                          case NAME_ERR_TRAILING_SLASH:
 158  158                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 159  159                                      "trailing slash in name"));
 160  160                                  break;
 161  161  
 162  162                          case NAME_ERR_INVALCHAR:
 163  163                                  zfs_error_aux(hdl,
 164  164                                      dgettext(TEXT_DOMAIN, "invalid character "
 165  165                                      "'%c' in name"), what);
 166  166                                  break;
 167  167  
 168  168                          case NAME_ERR_MULTIPLE_AT:
 169  169                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 170  170                                      "multiple '@' delimiters in name"));
 171  171                                  break;
 172  172  
 173  173                          case NAME_ERR_NOLETTER:
 174  174                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 175  175                                      "pool doesn't begin with a letter"));
 176  176                                  break;
 177  177  
 178  178                          case NAME_ERR_RESERVED:
 179  179                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 180  180                                      "name is reserved"));
 181  181                                  break;
 182  182  
 183  183                          case NAME_ERR_DISKLIKE:
 184  184                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 185  185                                      "reserved disk name"));
 186  186                                  break;
 187  187                          }
 188  188                  }
 189  189  
 190  190                  return (0);
 191  191          }
 192  192  
 193  193          if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
 194  194                  if (hdl != NULL)
 195  195                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 196  196                              "snapshot delimiter '@' in filesystem name"));
 197  197                  return (0);
 198  198          }
 199  199  
 200  200          if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
 201  201                  if (hdl != NULL)
 202  202                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 203  203                              "missing '@' delimiter in snapshot name"));
 204  204                  return (0);
 205  205          }
 206  206  
 207  207          if (modifying && strchr(path, '%') != NULL) {
 208  208                  if (hdl != NULL)
 209  209                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 210  210                              "invalid character %c in name"), '%');
 211  211                  return (0);
 212  212          }
 213  213  
 214  214          return (-1);
 215  215  }
 216  216  
 217  217  int
 218  218  zfs_name_valid(const char *name, zfs_type_t type)
 219  219  {
 220  220          if (type == ZFS_TYPE_POOL)
 221  221                  return (zpool_name_valid(NULL, B_FALSE, name));
 222  222          return (zfs_validate_name(NULL, name, type, B_FALSE));
 223  223  }
 224  224  
 225  225  /*
 226  226   * This function takes the raw DSL properties, and filters out the user-defined
 227  227   * properties into a separate nvlist.
 228  228   */
 229  229  static nvlist_t *
 230  230  process_user_props(zfs_handle_t *zhp, nvlist_t *props)
 231  231  {
 232  232          libzfs_handle_t *hdl = zhp->zfs_hdl;
 233  233          nvpair_t *elem;
 234  234          nvlist_t *propval;
 235  235          nvlist_t *nvl;
 236  236  
 237  237          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
 238  238                  (void) no_memory(hdl);
 239  239                  return (NULL);
 240  240          }
 241  241  
 242  242          elem = NULL;
 243  243          while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 244  244                  if (!zfs_prop_user(nvpair_name(elem)))
 245  245                          continue;
 246  246  
 247  247                  verify(nvpair_value_nvlist(elem, &propval) == 0);
 248  248                  if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
 249  249                          nvlist_free(nvl);
 250  250                          (void) no_memory(hdl);
 251  251                          return (NULL);
 252  252                  }
 253  253          }
 254  254  
 255  255          return (nvl);
 256  256  }
 257  257  
 258  258  static zpool_handle_t *
 259  259  zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
 260  260  {
 261  261          libzfs_handle_t *hdl = zhp->zfs_hdl;
 262  262          zpool_handle_t *zph;
 263  263  
 264  264          if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
 265  265                  if (hdl->libzfs_pool_handles != NULL)
 266  266                          zph->zpool_next = hdl->libzfs_pool_handles;
 267  267                  hdl->libzfs_pool_handles = zph;
 268  268          }
 269  269          return (zph);
 270  270  }
 271  271  
 272  272  static zpool_handle_t *
 273  273  zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
 274  274  {
 275  275          libzfs_handle_t *hdl = zhp->zfs_hdl;
 276  276          zpool_handle_t *zph = hdl->libzfs_pool_handles;
 277  277  
 278  278          while ((zph != NULL) &&
 279  279              (strncmp(pool_name, zpool_get_name(zph), len) != 0))
 280  280                  zph = zph->zpool_next;
 281  281          return (zph);
 282  282  }
 283  283  
 284  284  /*
 285  285   * Returns a handle to the pool that contains the provided dataset.
 286  286   * If a handle to that pool already exists then that handle is returned.
 287  287   * Otherwise, a new handle is created and added to the list of handles.
 288  288   */
 289  289  static zpool_handle_t *
 290  290  zpool_handle(zfs_handle_t *zhp)
 291  291  {
 292  292          char *pool_name;
 293  293          int len;
 294  294          zpool_handle_t *zph;
 295  295  
 296  296          len = strcspn(zhp->zfs_name, "/@") + 1;
 297  297          pool_name = zfs_alloc(zhp->zfs_hdl, len);
 298  298          (void) strlcpy(pool_name, zhp->zfs_name, len);
 299  299  
 300  300          zph = zpool_find_handle(zhp, pool_name, len);
 301  301          if (zph == NULL)
 302  302                  zph = zpool_add_handle(zhp, pool_name);
 303  303  
 304  304          free(pool_name);
 305  305          return (zph);
 306  306  }
 307  307  
 308  308  void
 309  309  zpool_free_handles(libzfs_handle_t *hdl)
 310  310  {
 311  311          zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
 312  312  
 313  313          while (zph != NULL) {
 314  314                  next = zph->zpool_next;
 315  315                  zpool_close(zph);
 316  316                  zph = next;
 317  317          }
 318  318          hdl->libzfs_pool_handles = NULL;
 319  319  }
 320  320  
 321  321  /*
 322  322   * Utility function to gather stats (objset and zpl) for the given object.
 323  323   */
 324  324  static int
 325  325  get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
 326  326  {
 327  327          libzfs_handle_t *hdl = zhp->zfs_hdl;
 328  328  
 329  329          (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
 330  330  
 331  331          while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
 332  332                  if (errno == ENOMEM) {
 333  333                          if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
 334  334                                  return (-1);
 335  335                          }
 336  336                  } else {
 337  337                          return (-1);
 338  338                  }
 339  339          }
 340  340          return (0);
 341  341  }
 342  342  
 343  343  /*
 344  344   * Utility function to get the received properties of the given object.
 345  345   */
 346  346  static int
 347  347  get_recvd_props_ioctl(zfs_handle_t *zhp)
 348  348  {
 349  349          libzfs_handle_t *hdl = zhp->zfs_hdl;
 350  350          nvlist_t *recvdprops;
 351  351          zfs_cmd_t zc = { 0 };
 352  352          int err;
 353  353  
 354  354          if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
 355  355                  return (-1);
 356  356  
 357  357          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 358  358  
 359  359          while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
 360  360                  if (errno == ENOMEM) {
 361  361                          if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
 362  362                                  return (-1);
 363  363                          }
 364  364                  } else {
 365  365                          zcmd_free_nvlists(&zc);
 366  366                          return (-1);
 367  367                  }
 368  368          }
 369  369  
 370  370          err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
 371  371          zcmd_free_nvlists(&zc);
 372  372          if (err != 0)
 373  373                  return (-1);
 374  374  
 375  375          nvlist_free(zhp->zfs_recvd_props);
 376  376          zhp->zfs_recvd_props = recvdprops;
 377  377  
 378  378          return (0);
 379  379  }
 380  380  
 381  381  static int
 382  382  put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
 383  383  {
 384  384          nvlist_t *allprops, *userprops;
 385  385  
 386  386          zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
 387  387  
 388  388          if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
 389  389                  return (-1);
 390  390          }
 391  391  
 392  392          /*
 393  393           * XXX Why do we store the user props separately, in addition to
 394  394           * storing them in zfs_props?
 395  395           */
 396  396          if ((userprops = process_user_props(zhp, allprops)) == NULL) {
 397  397                  nvlist_free(allprops);
 398  398                  return (-1);
 399  399          }
 400  400  
 401  401          nvlist_free(zhp->zfs_props);
 402  402          nvlist_free(zhp->zfs_user_props);
 403  403  
 404  404          zhp->zfs_props = allprops;
 405  405          zhp->zfs_user_props = userprops;
 406  406  
 407  407          return (0);
 408  408  }
 409  409  
 410  410  static int
 411  411  get_stats(zfs_handle_t *zhp)
 412  412  {
 413  413          int rc = 0;
 414  414          zfs_cmd_t zc = { 0 };
 415  415  
 416  416          if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
 417  417                  return (-1);
 418  418          if (get_stats_ioctl(zhp, &zc) != 0)
 419  419                  rc = -1;
 420  420          else if (put_stats_zhdl(zhp, &zc) != 0)
 421  421                  rc = -1;
 422  422          zcmd_free_nvlists(&zc);
 423  423          return (rc);
 424  424  }
 425  425  
 426  426  /*
 427  427   * Refresh the properties currently stored in the handle.
 428  428   */
 429  429  void
 430  430  zfs_refresh_properties(zfs_handle_t *zhp)
 431  431  {
 432  432          (void) get_stats(zhp);
 433  433  }
 434  434  
 435  435  /*
 436  436   * Makes a handle from the given dataset name.  Used by zfs_open() and
 437  437   * zfs_iter_* to create child handles on the fly.
 438  438   */
 439  439  static int
 440  440  make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
 441  441  {
 442  442          if (put_stats_zhdl(zhp, zc) != 0)
 443  443                  return (-1);
 444  444  
 445  445          /*
 446  446           * We've managed to open the dataset and gather statistics.  Determine
 447  447           * the high-level type.
 448  448           */
 449  449          if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
 450  450                  zhp->zfs_head_type = ZFS_TYPE_VOLUME;
 451  451          else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
 452  452                  zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
 453  453          else
 454  454                  abort();
 455  455  
 456  456          if (zhp->zfs_dmustats.dds_is_snapshot)
 457  457                  zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
 458  458          else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
 459  459                  zhp->zfs_type = ZFS_TYPE_VOLUME;
 460  460          else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
 461  461                  zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
 462  462          else
 463  463                  abort();        /* we should never see any other types */
 464  464  
 465  465          if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
 466  466                  return (-1);
 467  467  
 468  468          return (0);
 469  469  }
 470  470  
 471  471  zfs_handle_t *
 472  472  make_dataset_handle(libzfs_handle_t *hdl, const char *path)
 473  473  {
 474  474          zfs_cmd_t zc = { 0 };
 475  475  
 476  476          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 477  477  
 478  478          if (zhp == NULL)
 479  479                  return (NULL);
 480  480  
 481  481          zhp->zfs_hdl = hdl;
 482  482          (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
 483  483          if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
 484  484                  free(zhp);
 485  485                  return (NULL);
 486  486          }
 487  487          if (get_stats_ioctl(zhp, &zc) == -1) {
 488  488                  zcmd_free_nvlists(&zc);
 489  489                  free(zhp);
 490  490                  return (NULL);
 491  491          }
 492  492          if (make_dataset_handle_common(zhp, &zc) == -1) {
 493  493                  free(zhp);
 494  494                  zhp = NULL;
 495  495          }
 496  496          zcmd_free_nvlists(&zc);
 497  497          return (zhp);
 498  498  }
 499  499  
 500  500  zfs_handle_t *
 501  501  make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
 502  502  {
 503  503          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 504  504  
 505  505          if (zhp == NULL)
 506  506                  return (NULL);
 507  507  
 508  508          zhp->zfs_hdl = hdl;
 509  509          (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
 510  510          if (make_dataset_handle_common(zhp, zc) == -1) {
 511  511                  free(zhp);
 512  512                  return (NULL);
 513  513          }
 514  514          return (zhp);
 515  515  }
 516  516  
 517  517  zfs_handle_t *
 518  518  zfs_handle_dup(zfs_handle_t *zhp_orig)
 519  519  {
 520  520          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 521  521  
 522  522          if (zhp == NULL)
 523  523                  return (NULL);
 524  524  
 525  525          zhp->zfs_hdl = zhp_orig->zfs_hdl;
 526  526          zhp->zpool_hdl = zhp_orig->zpool_hdl;
 527  527          (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
 528  528              sizeof (zhp->zfs_name));
 529  529          zhp->zfs_type = zhp_orig->zfs_type;
 530  530          zhp->zfs_head_type = zhp_orig->zfs_head_type;
 531  531          zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
 532  532          if (zhp_orig->zfs_props != NULL) {
 533  533                  if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
 534  534                          (void) no_memory(zhp->zfs_hdl);
 535  535                          zfs_close(zhp);
 536  536                          return (NULL);
 537  537                  }
 538  538          }
 539  539          if (zhp_orig->zfs_user_props != NULL) {
 540  540                  if (nvlist_dup(zhp_orig->zfs_user_props,
 541  541                      &zhp->zfs_user_props, 0) != 0) {
 542  542                          (void) no_memory(zhp->zfs_hdl);
 543  543                          zfs_close(zhp);
 544  544                          return (NULL);
 545  545                  }
 546  546          }
 547  547          if (zhp_orig->zfs_recvd_props != NULL) {
 548  548                  if (nvlist_dup(zhp_orig->zfs_recvd_props,
 549  549                      &zhp->zfs_recvd_props, 0)) {
 550  550                          (void) no_memory(zhp->zfs_hdl);
 551  551                          zfs_close(zhp);
 552  552                          return (NULL);
 553  553                  }
 554  554          }
 555  555          zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
 556  556          if (zhp_orig->zfs_mntopts != NULL) {
 557  557                  zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
 558  558                      zhp_orig->zfs_mntopts);
 559  559          }
 560  560          zhp->zfs_props_table = zhp_orig->zfs_props_table;
 561  561          return (zhp);
 562  562  }
 563  563  
 564  564  /*
 565  565   * Opens the given snapshot, filesystem, or volume.   The 'types'
 566  566   * argument is a mask of acceptable types.  The function will print an
 567  567   * appropriate error message and return NULL if it can't be opened.
 568  568   */
 569  569  zfs_handle_t *
 570  570  zfs_open(libzfs_handle_t *hdl, const char *path, int types)
 571  571  {
 572  572          zfs_handle_t *zhp;
 573  573          char errbuf[1024];
 574  574  
 575  575          (void) snprintf(errbuf, sizeof (errbuf),
 576  576              dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
 577  577  
 578  578          /*
 579  579           * Validate the name before we even try to open it.
 580  580           */
 581  581          if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) {
 582  582                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 583  583                      "invalid dataset name"));
 584  584                  (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
 585  585                  return (NULL);
 586  586          }
 587  587  
 588  588          /*
 589  589           * Try to get stats for the dataset, which will tell us if it exists.
 590  590           */
 591  591          errno = 0;
 592  592          if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
 593  593                  (void) zfs_standard_error(hdl, errno, errbuf);
 594  594                  return (NULL);
 595  595          }
 596  596  
 597  597          if (!(types & zhp->zfs_type)) {
 598  598                  (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
 599  599                  zfs_close(zhp);
 600  600                  return (NULL);
 601  601          }
 602  602  
 603  603          return (zhp);
 604  604  }
 605  605  
 606  606  /*
 607  607   * Release a ZFS handle.  Nothing to do but free the associated memory.
 608  608   */
 609  609  void
 610  610  zfs_close(zfs_handle_t *zhp)
 611  611  {
 612  612          if (zhp->zfs_mntopts)
 613  613                  free(zhp->zfs_mntopts);
 614  614          nvlist_free(zhp->zfs_props);
 615  615          nvlist_free(zhp->zfs_user_props);
 616  616          nvlist_free(zhp->zfs_recvd_props);
 617  617          free(zhp);
 618  618  }
 619  619  
 620  620  typedef struct mnttab_node {
 621  621          struct mnttab mtn_mt;
 622  622          avl_node_t mtn_node;
 623  623  } mnttab_node_t;
 624  624  
 625  625  static int
 626  626  libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
 627  627  {
 628  628          const mnttab_node_t *mtn1 = arg1;
 629  629          const mnttab_node_t *mtn2 = arg2;
 630  630          int rv;
 631  631  
 632  632          rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
 633  633  
 634  634          if (rv == 0)
 635  635                  return (0);
 636  636          return (rv > 0 ? 1 : -1);
 637  637  }
 638  638  
 639  639  void
 640  640  libzfs_mnttab_init(libzfs_handle_t *hdl)
 641  641  {
 642  642          assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
 643  643          avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
 644  644              sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
 645  645  }
 646  646  
 647  647  void
 648  648  libzfs_mnttab_update(libzfs_handle_t *hdl)
 649  649  {
 650  650          struct mnttab entry;
 651  651  
 652  652          rewind(hdl->libzfs_mnttab);
 653  653          while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
 654  654                  mnttab_node_t *mtn;
 655  655  
 656  656                  if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
 657  657                          continue;
 658  658                  mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
 659  659                  mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
 660  660                  mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
 661  661                  mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
 662  662                  mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
 663  663                  avl_add(&hdl->libzfs_mnttab_cache, mtn);
 664  664          }
 665  665  }
 666  666  
 667  667  void
 668  668  libzfs_mnttab_fini(libzfs_handle_t *hdl)
 669  669  {
 670  670          void *cookie = NULL;
 671  671          mnttab_node_t *mtn;
 672  672  
 673  673          while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) {
 674  674                  free(mtn->mtn_mt.mnt_special);
 675  675                  free(mtn->mtn_mt.mnt_mountp);
 676  676                  free(mtn->mtn_mt.mnt_fstype);
 677  677                  free(mtn->mtn_mt.mnt_mntopts);
 678  678                  free(mtn);
 679  679          }
 680  680          avl_destroy(&hdl->libzfs_mnttab_cache);
 681  681  }
 682  682  
 683  683  void
 684  684  libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
 685  685  {
 686  686          hdl->libzfs_mnttab_enable = enable;
 687  687  }
 688  688  
 689  689  int
 690  690  libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
 691  691      struct mnttab *entry)
 692  692  {
 693  693          mnttab_node_t find;
 694  694          mnttab_node_t *mtn;
 695  695  
 696  696          if (!hdl->libzfs_mnttab_enable) {
 697  697                  struct mnttab srch = { 0 };
 698  698  
 699  699                  if (avl_numnodes(&hdl->libzfs_mnttab_cache))
 700  700                          libzfs_mnttab_fini(hdl);
 701  701                  rewind(hdl->libzfs_mnttab);
 702  702                  srch.mnt_special = (char *)fsname;
 703  703                  srch.mnt_fstype = MNTTYPE_ZFS;
 704  704                  if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
 705  705                          return (0);
 706  706                  else
 707  707                          return (ENOENT);
 708  708          }
 709  709  
 710  710          if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
 711  711                  libzfs_mnttab_update(hdl);
 712  712  
 713  713          find.mtn_mt.mnt_special = (char *)fsname;
 714  714          mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
 715  715          if (mtn) {
 716  716                  *entry = mtn->mtn_mt;
 717  717                  return (0);
 718  718          }
 719  719          return (ENOENT);
 720  720  }
 721  721  
 722  722  void
 723  723  libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
 724  724      const char *mountp, const char *mntopts)
 725  725  {
 726  726          mnttab_node_t *mtn;
 727  727  
 728  728          if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
 729  729                  return;
 730  730          mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
 731  731          mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
 732  732          mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
 733  733          mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
 734  734          mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
 735  735          avl_add(&hdl->libzfs_mnttab_cache, mtn);
 736  736  }
 737  737  
 738  738  void
 739  739  libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
 740  740  {
 741  741          mnttab_node_t find;
 742  742          mnttab_node_t *ret;
 743  743  
 744  744          find.mtn_mt.mnt_special = (char *)fsname;
 745  745          if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) {
 746  746                  avl_remove(&hdl->libzfs_mnttab_cache, ret);
 747  747                  free(ret->mtn_mt.mnt_special);
 748  748                  free(ret->mtn_mt.mnt_mountp);
 749  749                  free(ret->mtn_mt.mnt_fstype);
 750  750                  free(ret->mtn_mt.mnt_mntopts);
 751  751                  free(ret);
 752  752          }
 753  753  }
 754  754  
 755  755  int
 756  756  zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
 757  757  {
 758  758          zpool_handle_t *zpool_handle = zhp->zpool_hdl;
 759  759  
 760  760          if (zpool_handle == NULL)
 761  761                  return (-1);
 762  762  
 763  763          *spa_version = zpool_get_prop_int(zpool_handle,
 764  764              ZPOOL_PROP_VERSION, NULL);
 765  765          return (0);
 766  766  }
 767  767  
 768  768  /*
 769  769   * The choice of reservation property depends on the SPA version.
 770  770   */
 771  771  static int
 772  772  zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
 773  773  {
 774  774          int spa_version;
 775  775  
 776  776          if (zfs_spa_version(zhp, &spa_version) < 0)
 777  777                  return (-1);
 778  778  
 779  779          if (spa_version >= SPA_VERSION_REFRESERVATION)
 780  780                  *resv_prop = ZFS_PROP_REFRESERVATION;
 781  781          else
 782  782                  *resv_prop = ZFS_PROP_RESERVATION;
 783  783  
 784  784          return (0);
 785  785  }
 786  786  
 787  787  /*
 788  788   * Given an nvlist of properties to set, validates that they are correct, and
 789  789   * parses any numeric properties (index, boolean, etc) if they are specified as
 790  790   * strings.
 791  791   */
 792  792  nvlist_t *
 793  793  zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
 794  794      uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
 795  795  {
 796  796          nvpair_t *elem;
 797  797          uint64_t intval;
 798  798          char *strval;
 799  799          zfs_prop_t prop;
 800  800          nvlist_t *ret;
 801  801          int chosen_normal = -1;
 802  802          int chosen_utf = -1;
 803  803  
 804  804          if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
 805  805                  (void) no_memory(hdl);
 806  806                  return (NULL);
 807  807          }
 808  808  
 809  809          /*
 810  810           * Make sure this property is valid and applies to this type.
 811  811           */
 812  812  
 813  813          elem = NULL;
 814  814          while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
 815  815                  const char *propname = nvpair_name(elem);
 816  816  
 817  817                  prop = zfs_name_to_prop(propname);
 818  818                  if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
 819  819                          /*
 820  820                           * This is a user property: make sure it's a
 821  821                           * string, and that it's less than ZAP_MAXNAMELEN.
 822  822                           */
 823  823                          if (nvpair_type(elem) != DATA_TYPE_STRING) {
 824  824                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 825  825                                      "'%s' must be a string"), propname);
 826  826                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 827  827                                  goto error;
 828  828                          }
 829  829  
 830  830                          if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
 831  831                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 832  832                                      "property name '%s' is too long"),
 833  833                                      propname);
 834  834                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 835  835                                  goto error;
 836  836                          }
 837  837  
 838  838                          (void) nvpair_value_string(elem, &strval);
 839  839                          if (nvlist_add_string(ret, propname, strval) != 0) {
 840  840                                  (void) no_memory(hdl);
 841  841                                  goto error;
 842  842                          }
 843  843                          continue;
 844  844                  }
 845  845  
 846  846                  /*
 847  847                   * Currently, only user properties can be modified on
 848  848                   * snapshots.
 849  849                   */
 850  850                  if (type == ZFS_TYPE_SNAPSHOT) {
 851  851                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 852  852                              "this property can not be modified for snapshots"));
 853  853                          (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
 854  854                          goto error;
 855  855                  }
 856  856  
 857  857                  if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
 858  858                          zfs_userquota_prop_t uqtype;
 859  859                          char newpropname[128];
 860  860                          char domain[128];
 861  861                          uint64_t rid;
 862  862                          uint64_t valary[3];
 863  863  
 864  864                          if (userquota_propname_decode(propname, zoned,
 865  865                              &uqtype, domain, sizeof (domain), &rid) != 0) {
 866  866                                  zfs_error_aux(hdl,
 867  867                                      dgettext(TEXT_DOMAIN,
 868  868                                      "'%s' has an invalid user/group name"),
 869  869                                      propname);
 870  870                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 871  871                                  goto error;
 872  872                          }
 873  873  
 874  874                          if (uqtype != ZFS_PROP_USERQUOTA &&
 875  875                              uqtype != ZFS_PROP_GROUPQUOTA) {
 876  876                                  zfs_error_aux(hdl,
 877  877                                      dgettext(TEXT_DOMAIN, "'%s' is readonly"),
 878  878                                      propname);
 879  879                                  (void) zfs_error(hdl, EZFS_PROPREADONLY,
 880  880                                      errbuf);
 881  881                                  goto error;
 882  882                          }
 883  883  
 884  884                          if (nvpair_type(elem) == DATA_TYPE_STRING) {
 885  885                                  (void) nvpair_value_string(elem, &strval);
 886  886                                  if (strcmp(strval, "none") == 0) {
 887  887                                          intval = 0;
 888  888                                  } else if (zfs_nicestrtonum(hdl,
 889  889                                      strval, &intval) != 0) {
 890  890                                          (void) zfs_error(hdl,
 891  891                                              EZFS_BADPROP, errbuf);
 892  892                                          goto error;
 893  893                                  }
 894  894                          } else if (nvpair_type(elem) ==
 895  895                              DATA_TYPE_UINT64) {
 896  896                                  (void) nvpair_value_uint64(elem, &intval);
 897  897                                  if (intval == 0) {
 898  898                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 899  899                                              "use 'none' to disable "
 900  900                                              "userquota/groupquota"));
 901  901                                          goto error;
 902  902                                  }
 903  903                          } else {
 904  904                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 905  905                                      "'%s' must be a number"), propname);
 906  906                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 907  907                                  goto error;
 908  908                          }
 909  909  
 910  910                          /*
 911  911                           * Encode the prop name as
 912  912                           * userquota@<hex-rid>-domain, to make it easy
 913  913                           * for the kernel to decode.
 914  914                           */
 915  915                          (void) snprintf(newpropname, sizeof (newpropname),
 916  916                              "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
 917  917                              (longlong_t)rid, domain);
 918  918                          valary[0] = uqtype;
 919  919                          valary[1] = rid;
 920  920                          valary[2] = intval;
 921  921                          if (nvlist_add_uint64_array(ret, newpropname,
 922  922                              valary, 3) != 0) {
 923  923                                  (void) no_memory(hdl);
 924  924                                  goto error;
 925  925                          }
 926  926                          continue;
 927  927                  } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
 928  928                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 929  929                              "'%s' is readonly"),
 930  930                              propname);
 931  931                          (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
 932  932                          goto error;
 933  933                  }
 934  934  
 935  935                  if (prop == ZPROP_INVAL) {
 936  936                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 937  937                              "invalid property '%s'"), propname);
 938  938                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 939  939                          goto error;
 940  940                  }
 941  941  
 942  942                  if (!zfs_prop_valid_for_type(prop, type)) {
 943  943                          zfs_error_aux(hdl,
 944  944                              dgettext(TEXT_DOMAIN, "'%s' does not "
 945  945                              "apply to datasets of this type"), propname);
 946  946                          (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
 947  947                          goto error;
 948  948                  }
 949  949  
 950  950                  if (zfs_prop_readonly(prop) &&
 951  951                      (!zfs_prop_setonce(prop) || zhp != NULL)) {
 952  952                          zfs_error_aux(hdl,
 953  953                              dgettext(TEXT_DOMAIN, "'%s' is readonly"),
 954  954                              propname);
 955  955                          (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
 956  956                          goto error;
 957  957                  }
 958  958  
 959  959                  if (zprop_parse_value(hdl, elem, prop, type, ret,
 960  960                      &strval, &intval, errbuf) != 0)
 961  961                          goto error;
 962  962  
 963  963                  /*
 964  964                   * Perform some additional checks for specific properties.
 965  965                   */
 966  966                  switch (prop) {
 967  967                  case ZFS_PROP_VERSION:
 968  968                  {
 969  969                          int version;
 970  970  
 971  971                          if (zhp == NULL)
 972  972                                  break;
 973  973                          version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
 974  974                          if (intval < version) {
 975  975                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 976  976                                      "Can not downgrade; already at version %u"),
 977  977                                      version);
 978  978                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 979  979                                  goto error;
 980  980                          }
 981  981                          break;
 982  982                  }
 983  983  
 984  984                  case ZFS_PROP_RECORDSIZE:
 985  985                  case ZFS_PROP_VOLBLOCKSIZE:
 986  986                          /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
 987  987                          if (intval < SPA_MINBLOCKSIZE ||
 988  988                              intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) {
 989  989                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 990  990                                      "'%s' must be power of 2 from %u "
 991  991                                      "to %uk"), propname,
 992  992                                      (uint_t)SPA_MINBLOCKSIZE,
 993  993                                      (uint_t)SPA_MAXBLOCKSIZE >> 10);
 994  994                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 995  995                                  goto error;
 996  996                          }
 997  997                          break;
 998  998  
 999  999                  case ZFS_PROP_MLSLABEL:
1000 1000                  {
1001 1001                          /*
1002 1002                           * Verify the mlslabel string and convert to
1003 1003                           * internal hex label string.
1004 1004                           */
1005 1005  
1006 1006                          m_label_t *new_sl;
1007 1007                          char *hex = NULL;       /* internal label string */
1008 1008  
1009 1009                          /* Default value is already OK. */
1010 1010                          if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
1011 1011                                  break;
1012 1012  
1013 1013                          /* Verify the label can be converted to binary form */
1014 1014                          if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
1015 1015                              (str_to_label(strval, &new_sl, MAC_LABEL,
1016 1016                              L_NO_CORRECTION, NULL) == -1)) {
1017 1017                                  goto badlabel;
1018 1018                          }
1019 1019  
1020 1020                          /* Now translate to hex internal label string */
1021 1021                          if (label_to_str(new_sl, &hex, M_INTERNAL,
1022 1022                              DEF_NAMES) != 0) {
1023 1023                                  if (hex)
1024 1024                                          free(hex);
1025 1025                                  goto badlabel;
1026 1026                          }
1027 1027                          m_label_free(new_sl);
1028 1028  
1029 1029                          /* If string is already in internal form, we're done. */
1030 1030                          if (strcmp(strval, hex) == 0) {
1031 1031                                  free(hex);
1032 1032                                  break;
1033 1033                          }
1034 1034  
1035 1035                          /* Replace the label string with the internal form. */
1036 1036                          (void) nvlist_remove(ret, zfs_prop_to_name(prop),
1037 1037                              DATA_TYPE_STRING);
1038 1038                          verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
1039 1039                              hex) == 0);
1040 1040                          free(hex);
1041 1041  
1042 1042                          break;
1043 1043  
1044 1044  badlabel:
1045 1045                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1046 1046                              "invalid mlslabel '%s'"), strval);
1047 1047                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1048 1048                          m_label_free(new_sl);   /* OK if null */
1049 1049                          goto error;
1050 1050  
1051 1051                  }
1052 1052  
1053 1053                  case ZFS_PROP_MOUNTPOINT:
1054 1054                  {
1055 1055                          namecheck_err_t why;
1056 1056  
1057 1057                          if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
1058 1058                              strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
1059 1059                                  break;
1060 1060  
1061 1061                          if (mountpoint_namecheck(strval, &why)) {
1062 1062                                  switch (why) {
1063 1063                                  case NAME_ERR_LEADING_SLASH:
1064 1064                                          zfs_error_aux(hdl,
1065 1065                                              dgettext(TEXT_DOMAIN,
1066 1066                                              "'%s' must be an absolute path, "
1067 1067                                              "'none', or 'legacy'"), propname);
1068 1068                                          break;
1069 1069                                  case NAME_ERR_TOOLONG:
1070 1070                                          zfs_error_aux(hdl,
1071 1071                                              dgettext(TEXT_DOMAIN,
1072 1072                                              "component of '%s' is too long"),
1073 1073                                              propname);
1074 1074                                          break;
1075 1075                                  }
1076 1076                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1077 1077                                  goto error;
1078 1078                          }
1079 1079                  }
1080 1080  
1081 1081                          /*FALLTHRU*/
1082 1082  
1083 1083                  case ZFS_PROP_SHARESMB:
1084 1084                  case ZFS_PROP_SHARENFS:
1085 1085                          /*
1086 1086                           * For the mountpoint and sharenfs or sharesmb
1087 1087                           * properties, check if it can be set in a
1088 1088                           * global/non-global zone based on
1089 1089                           * the zoned property value:
1090 1090                           *
1091 1091                           *              global zone         non-global zone
1092 1092                           * --------------------------------------------------
1093 1093                           * zoned=on     mountpoint (no)     mountpoint (yes)
1094 1094                           *              sharenfs (no)       sharenfs (no)
1095 1095                           *              sharesmb (no)       sharesmb (no)
1096 1096                           *
1097 1097                           * zoned=off    mountpoint (yes)        N/A
1098 1098                           *              sharenfs (yes)
1099 1099                           *              sharesmb (yes)
1100 1100                           */
1101 1101                          if (zoned) {
1102 1102                                  if (getzoneid() == GLOBAL_ZONEID) {
1103 1103                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1104 1104                                              "'%s' cannot be set on "
1105 1105                                              "dataset in a non-global zone"),
1106 1106                                              propname);
1107 1107                                          (void) zfs_error(hdl, EZFS_ZONED,
1108 1108                                              errbuf);
1109 1109                                          goto error;
1110 1110                                  } else if (prop == ZFS_PROP_SHARENFS ||
1111 1111                                      prop == ZFS_PROP_SHARESMB) {
1112 1112                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1113 1113                                              "'%s' cannot be set in "
1114 1114                                              "a non-global zone"), propname);
1115 1115                                          (void) zfs_error(hdl, EZFS_ZONED,
1116 1116                                              errbuf);
1117 1117                                          goto error;
1118 1118                                  }
1119 1119                          } else if (getzoneid() != GLOBAL_ZONEID) {
1120 1120                                  /*
1121 1121                                   * If zoned property is 'off', this must be in
1122 1122                                   * a global zone. If not, something is wrong.
1123 1123                                   */
1124 1124                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1125 1125                                      "'%s' cannot be set while dataset "
1126 1126                                      "'zoned' property is set"), propname);
1127 1127                                  (void) zfs_error(hdl, EZFS_ZONED, errbuf);
1128 1128                                  goto error;
1129 1129                          }
1130 1130  
1131 1131                          /*
1132 1132                           * At this point, it is legitimate to set the
1133 1133                           * property. Now we want to make sure that the
1134 1134                           * property value is valid if it is sharenfs.
1135 1135                           */
1136 1136                          if ((prop == ZFS_PROP_SHARENFS ||
1137 1137                              prop == ZFS_PROP_SHARESMB) &&
1138 1138                              strcmp(strval, "on") != 0 &&
1139 1139                              strcmp(strval, "off") != 0) {
1140 1140                                  zfs_share_proto_t proto;
1141 1141  
1142 1142                                  if (prop == ZFS_PROP_SHARESMB)
1143 1143                                          proto = PROTO_SMB;
1144 1144                                  else
1145 1145                                          proto = PROTO_NFS;
1146 1146  
1147 1147                                  /*
1148 1148                                   * Must be an valid sharing protocol
1149 1149                                   * option string so init the libshare
1150 1150                                   * in order to enable the parser and
1151 1151                                   * then parse the options. We use the
1152 1152                                   * control API since we don't care about
1153 1153                                   * the current configuration and don't
1154 1154                                   * want the overhead of loading it
1155 1155                                   * until we actually do something.
1156 1156                                   */
1157 1157  
1158 1158                                  if (zfs_init_libshare(hdl,
1159 1159                                      SA_INIT_CONTROL_API) != SA_OK) {
1160 1160                                          /*
1161 1161                                           * An error occurred so we can't do
1162 1162                                           * anything
1163 1163                                           */
1164 1164                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1165 1165                                              "'%s' cannot be set: problem "
1166 1166                                              "in share initialization"),
1167 1167                                              propname);
1168 1168                                          (void) zfs_error(hdl, EZFS_BADPROP,
1169 1169                                              errbuf);
1170 1170                                          goto error;
1171 1171                                  }
1172 1172  
1173 1173                                  if (zfs_parse_options(strval, proto) != SA_OK) {
1174 1174                                          /*
1175 1175                                           * There was an error in parsing so
1176 1176                                           * deal with it by issuing an error
1177 1177                                           * message and leaving after
1178 1178                                           * uninitializing the the libshare
1179 1179                                           * interface.
1180 1180                                           */
1181 1181                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1182 1182                                              "'%s' cannot be set to invalid "
1183 1183                                              "options"), propname);
1184 1184                                          (void) zfs_error(hdl, EZFS_BADPROP,
1185 1185                                              errbuf);
1186 1186                                          zfs_uninit_libshare(hdl);
1187 1187                                          goto error;
1188 1188                                  }
1189 1189                                  zfs_uninit_libshare(hdl);
1190 1190                          }
1191 1191  
1192 1192                          break;
1193 1193                  case ZFS_PROP_UTF8ONLY:
1194 1194                          chosen_utf = (int)intval;
1195 1195                          break;
1196 1196                  case ZFS_PROP_NORMALIZE:
1197 1197                          chosen_normal = (int)intval;
1198 1198                          break;
1199 1199                  }
1200 1200  
1201 1201                  /*
1202 1202                   * For changes to existing volumes, we have some additional
1203 1203                   * checks to enforce.
1204 1204                   */
1205 1205                  if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
1206 1206                          uint64_t volsize = zfs_prop_get_int(zhp,
1207 1207                              ZFS_PROP_VOLSIZE);
1208 1208                          uint64_t blocksize = zfs_prop_get_int(zhp,
1209 1209                              ZFS_PROP_VOLBLOCKSIZE);
1210 1210                          char buf[64];
1211 1211  
1212 1212                          switch (prop) {
1213 1213                          case ZFS_PROP_RESERVATION:
1214 1214                          case ZFS_PROP_REFRESERVATION:
1215 1215                                  if (intval > volsize) {
1216 1216                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1217 1217                                              "'%s' is greater than current "
1218 1218                                              "volume size"), propname);
1219 1219                                          (void) zfs_error(hdl, EZFS_BADPROP,
1220 1220                                              errbuf);
1221 1221                                          goto error;
1222 1222                                  }
1223 1223                                  break;
1224 1224  
1225 1225                          case ZFS_PROP_VOLSIZE:
1226 1226                                  if (intval % blocksize != 0) {
1227 1227                                          zfs_nicenum(blocksize, buf,
1228 1228                                              sizeof (buf));
1229 1229                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1230 1230                                              "'%s' must be a multiple of "
1231 1231                                              "volume block size (%s)"),
1232 1232                                              propname, buf);
1233 1233                                          (void) zfs_error(hdl, EZFS_BADPROP,
1234 1234                                              errbuf);
1235 1235                                          goto error;
1236 1236                                  }
1237 1237  
1238 1238                                  if (intval == 0) {
1239 1239                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1240 1240                                              "'%s' cannot be zero"),
1241 1241                                              propname);
1242 1242                                          (void) zfs_error(hdl, EZFS_BADPROP,
1243 1243                                              errbuf);
1244 1244                                          goto error;
1245 1245                                  }
1246 1246                                  break;
1247 1247                          }
1248 1248                  }
1249 1249          }
1250 1250  
1251 1251          /*
1252 1252           * If normalization was chosen, but no UTF8 choice was made,
1253 1253           * enforce rejection of non-UTF8 names.
1254 1254           *
1255 1255           * If normalization was chosen, but rejecting non-UTF8 names
1256 1256           * was explicitly not chosen, it is an error.
1257 1257           */
1258 1258          if (chosen_normal > 0 && chosen_utf < 0) {
1259 1259                  if (nvlist_add_uint64(ret,
1260 1260                      zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
1261 1261                          (void) no_memory(hdl);
1262 1262                          goto error;
1263 1263                  }
1264 1264          } else if (chosen_normal > 0 && chosen_utf == 0) {
1265 1265                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1266 1266                      "'%s' must be set 'on' if normalization chosen"),
1267 1267                      zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
1268 1268                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1269 1269                  goto error;
1270 1270          }
1271 1271          return (ret);
1272 1272  
1273 1273  error:
1274 1274          nvlist_free(ret);
1275 1275          return (NULL);
1276 1276  }
1277 1277  
1278 1278  int
1279 1279  zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1280 1280  {
1281 1281          uint64_t old_volsize;
1282 1282          uint64_t new_volsize;
1283 1283          uint64_t old_reservation;
1284 1284          uint64_t new_reservation;
1285 1285          zfs_prop_t resv_prop;
1286 1286          nvlist_t *props;
1287 1287  
1288 1288          /*
1289 1289           * If this is an existing volume, and someone is setting the volsize,
1290 1290           * make sure that it matches the reservation, or add it if necessary.
1291 1291           */
1292 1292          old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1293 1293          if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
1294 1294                  return (-1);
1295 1295          old_reservation = zfs_prop_get_int(zhp, resv_prop);
1296 1296  
1297 1297          props = fnvlist_alloc();
1298 1298          fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1299 1299              zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
1300 1300  
1301 1301          if ((zvol_volsize_to_reservation(old_volsize, props) !=
1302 1302              old_reservation) || nvlist_exists(nvl,
1303 1303              zfs_prop_to_name(resv_prop))) {
1304 1304                  fnvlist_free(props);
1305 1305                  return (0);
1306 1306          }
1307 1307          if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1308 1308              &new_volsize) != 0) {
1309 1309                  fnvlist_free(props);
1310 1310                  return (-1);
1311 1311          }
1312 1312          new_reservation = zvol_volsize_to_reservation(new_volsize, props);
1313 1313          fnvlist_free(props);
1314 1314  
1315 1315          if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
1316 1316              new_reservation) != 0) {
1317 1317                  (void) no_memory(zhp->zfs_hdl);
1318 1318                  return (-1);
1319 1319          }
1320 1320          return (1);
1321 1321  }
1322 1322  
1323 1323  void
1324 1324  zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
1325 1325      char *errbuf)
1326 1326  {
1327 1327          switch (err) {
1328 1328  
1329 1329          case ENOSPC:
1330 1330                  /*
1331 1331                   * For quotas and reservations, ENOSPC indicates
1332 1332                   * something different; setting a quota or reservation
1333 1333                   * doesn't use any disk space.
1334 1334                   */
1335 1335                  switch (prop) {
1336 1336                  case ZFS_PROP_QUOTA:
1337 1337                  case ZFS_PROP_REFQUOTA:
1338 1338                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1339 1339                              "size is less than current used or "
1340 1340                              "reserved space"));
1341 1341                          (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1342 1342                          break;
1343 1343  
1344 1344                  case ZFS_PROP_RESERVATION:
1345 1345                  case ZFS_PROP_REFRESERVATION:
1346 1346                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1347 1347                              "size is greater than available space"));
1348 1348                          (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1349 1349                          break;
1350 1350  
1351 1351                  default:
1352 1352                          (void) zfs_standard_error(hdl, err, errbuf);
1353 1353                          break;
1354 1354                  }
1355 1355                  break;
1356 1356  
1357 1357          case EBUSY:
1358 1358                  (void) zfs_standard_error(hdl, EBUSY, errbuf);
1359 1359                  break;
1360 1360  
1361 1361          case EROFS:
1362 1362                  (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
1363 1363                  break;
1364 1364  
1365 1365          case ENOTSUP:
1366 1366                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1367 1367                      "pool and or dataset must be upgraded to set this "
1368 1368                      "property or value"));
1369 1369                  (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
1370 1370                  break;
1371 1371  
1372 1372          case ERANGE:
1373 1373                  if (prop == ZFS_PROP_COMPRESSION) {
1374 1374                          (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1375 1375                              "property setting is not allowed on "
1376 1376                              "bootable datasets"));
1377 1377                          (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
1378 1378                  } else {
1379 1379                          (void) zfs_standard_error(hdl, err, errbuf);
1380 1380                  }
1381 1381                  break;
1382 1382  
1383 1383          case EINVAL:
1384 1384                  if (prop == ZPROP_INVAL) {
1385 1385                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1386 1386                  } else {
1387 1387                          (void) zfs_standard_error(hdl, err, errbuf);
1388 1388                  }
1389 1389                  break;
1390 1390  
1391 1391          case EOVERFLOW:
1392 1392                  /*
1393 1393                   * This platform can't address a volume this big.
1394 1394                   */
1395 1395  #ifdef _ILP32
1396 1396                  if (prop == ZFS_PROP_VOLSIZE) {
1397 1397                          (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
1398 1398                          break;
1399 1399                  }
1400 1400  #endif
1401 1401                  /* FALLTHROUGH */
1402 1402          default:
1403 1403                  (void) zfs_standard_error(hdl, err, errbuf);
1404 1404          }
1405 1405  }
1406 1406  
1407 1407  /*
1408 1408   * Given a property name and value, set the property for the given dataset.
1409 1409   */
1410 1410  int
1411 1411  zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1412 1412  {
1413 1413          zfs_cmd_t zc = { 0 };
1414 1414          int ret = -1;
1415 1415          prop_changelist_t *cl = NULL;
1416 1416          char errbuf[1024];
1417 1417          libzfs_handle_t *hdl = zhp->zfs_hdl;
1418 1418          nvlist_t *nvl = NULL, *realprops;
1419 1419          zfs_prop_t prop;
1420 1420          boolean_t do_prefix = B_TRUE;
1421 1421          int added_resv;
1422 1422  
1423 1423          (void) snprintf(errbuf, sizeof (errbuf),
1424 1424              dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1425 1425              zhp->zfs_name);
1426 1426  
1427 1427          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
1428 1428              nvlist_add_string(nvl, propname, propval) != 0) {
1429 1429                  (void) no_memory(hdl);
1430 1430                  goto error;
1431 1431          }
1432 1432  
1433 1433          if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl,
1434 1434              zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
1435 1435                  goto error;
1436 1436  
1437 1437          nvlist_free(nvl);
1438 1438          nvl = realprops;
1439 1439  
1440 1440          prop = zfs_name_to_prop(propname);
1441 1441  
1442 1442          if (prop == ZFS_PROP_VOLSIZE) {
1443 1443                  if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1)
1444 1444                          goto error;
1445 1445          }
1446 1446  
1447 1447          if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
1448 1448                  goto error;
1449 1449  
1450 1450          if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1451 1451                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1452 1452                      "child dataset with inherited mountpoint is used "
1453 1453                      "in a non-global zone"));
1454 1454                  ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1455 1455                  goto error;
1456 1456          }
1457 1457  
1458 1458          /*
1459 1459           * We don't want to unmount & remount the dataset when changing
1460 1460           * its canmount property to 'on' or 'noauto'.  We only use
1461 1461           * the changelist logic to unmount when setting canmount=off.
1462 1462           */
1463 1463          if (prop == ZFS_PROP_CANMOUNT) {
1464 1464                  uint64_t idx;
1465 1465                  int err = zprop_string_to_index(prop, propval, &idx,
1466 1466                      ZFS_TYPE_DATASET);
1467 1467                  if (err == 0 && idx != ZFS_CANMOUNT_OFF)
1468 1468                          do_prefix = B_FALSE;
1469 1469          }
1470 1470  
1471 1471          if (do_prefix && (ret = changelist_prefix(cl)) != 0)
1472 1472                  goto error;
1473 1473  
1474 1474          /*
1475 1475           * Execute the corresponding ioctl() to set this property.
1476 1476           */
1477 1477          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1478 1478  
1479 1479          if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1480 1480                  goto error;
1481 1481  
1482 1482          ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1483 1483  
1484 1484          if (ret != 0) {
1485 1485                  zfs_setprop_error(hdl, prop, errno, errbuf);
1486 1486                  if (added_resv && errno == ENOSPC) {
1487 1487                          /* clean up the volsize property we tried to set */
1488 1488                          uint64_t old_volsize = zfs_prop_get_int(zhp,
1489 1489                              ZFS_PROP_VOLSIZE);
1490 1490                          nvlist_free(nvl);
1491 1491                          zcmd_free_nvlists(&zc);
1492 1492                          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1493 1493                                  goto error;
1494 1494                          if (nvlist_add_uint64(nvl,
1495 1495                              zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1496 1496                              old_volsize) != 0)
1497 1497                                  goto error;
1498 1498                          if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1499 1499                                  goto error;
1500 1500                          (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1501 1501                  }
1502 1502          } else {
1503 1503                  if (do_prefix)
1504 1504                          ret = changelist_postfix(cl);
1505 1505  
1506 1506                  /*
1507 1507                   * Refresh the statistics so the new property value
1508 1508                   * is reflected.
1509 1509                   */
1510 1510                  if (ret == 0)
1511 1511                          (void) get_stats(zhp);
1512 1512          }
1513 1513  
1514 1514  error:
1515 1515          nvlist_free(nvl);
1516 1516          zcmd_free_nvlists(&zc);
1517 1517          if (cl)
1518 1518                  changelist_free(cl);
1519 1519          return (ret);
1520 1520  }
1521 1521  
1522 1522  /*
1523 1523   * Given a property, inherit the value from the parent dataset, or if received
1524 1524   * is TRUE, revert to the received value, if any.
1525 1525   */
1526 1526  int
1527 1527  zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
1528 1528  {
1529 1529          zfs_cmd_t zc = { 0 };
1530 1530          int ret;
1531 1531          prop_changelist_t *cl;
1532 1532          libzfs_handle_t *hdl = zhp->zfs_hdl;
1533 1533          char errbuf[1024];
1534 1534          zfs_prop_t prop;
1535 1535  
1536 1536          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1537 1537              "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
1538 1538  
1539 1539          zc.zc_cookie = received;
1540 1540          if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
1541 1541                  /*
1542 1542                   * For user properties, the amount of work we have to do is very
1543 1543                   * small, so just do it here.
1544 1544                   */
1545 1545                  if (!zfs_prop_user(propname)) {
1546 1546                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1547 1547                              "invalid property"));
1548 1548                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
1549 1549                  }
1550 1550  
1551 1551                  (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1552 1552                  (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1553 1553  
1554 1554                  if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
1555 1555                          return (zfs_standard_error(hdl, errno, errbuf));
1556 1556  
1557 1557                  return (0);
1558 1558          }
1559 1559  
1560 1560          /*
1561 1561           * Verify that this property is inheritable.
1562 1562           */
1563 1563          if (zfs_prop_readonly(prop))
1564 1564                  return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
1565 1565  
1566 1566          if (!zfs_prop_inheritable(prop) && !received)
1567 1567                  return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
1568 1568  
1569 1569          /*
1570 1570           * Check to see if the value applies to this type
1571 1571           */
1572 1572          if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1573 1573                  return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
1574 1574  
1575 1575          /*
1576 1576           * Normalize the name, to get rid of shorthand abbreviations.
1577 1577           */
1578 1578          propname = zfs_prop_to_name(prop);
1579 1579          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1580 1580          (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1581 1581  
1582 1582          if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
1583 1583              zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
1584 1584                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1585 1585                      "dataset is used in a non-global zone"));
1586 1586                  return (zfs_error(hdl, EZFS_ZONED, errbuf));
1587 1587          }
1588 1588  
1589 1589          /*
1590 1590           * Determine datasets which will be affected by this change, if any.
1591 1591           */
1592 1592          if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
1593 1593                  return (-1);
1594 1594  
1595 1595          if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1596 1596                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1597 1597                      "child dataset with inherited mountpoint is used "
1598 1598                      "in a non-global zone"));
1599 1599                  ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1600 1600                  goto error;
1601 1601          }
1602 1602  
1603 1603          if ((ret = changelist_prefix(cl)) != 0)
1604 1604                  goto error;
1605 1605  
1606 1606          if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
1607 1607                  return (zfs_standard_error(hdl, errno, errbuf));
1608 1608          } else {
1609 1609  
1610 1610                  if ((ret = changelist_postfix(cl)) != 0)
1611 1611                          goto error;
1612 1612  
1613 1613                  /*
1614 1614                   * Refresh the statistics so the new property is reflected.
1615 1615                   */
1616 1616                  (void) get_stats(zhp);
1617 1617          }
1618 1618  
1619 1619  error:
1620 1620          changelist_free(cl);
1621 1621          return (ret);
1622 1622  }
1623 1623  
1624 1624  /*
1625 1625   * True DSL properties are stored in an nvlist.  The following two functions
1626 1626   * extract them appropriately.
1627 1627   */
1628 1628  static uint64_t
1629 1629  getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1630 1630  {
1631 1631          nvlist_t *nv;
1632 1632          uint64_t value;
1633 1633  
1634 1634          *source = NULL;
1635 1635          if (nvlist_lookup_nvlist(zhp->zfs_props,
1636 1636              zfs_prop_to_name(prop), &nv) == 0) {
1637 1637                  verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
1638 1638                  (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1639 1639          } else {
1640 1640                  verify(!zhp->zfs_props_table ||
1641 1641                      zhp->zfs_props_table[prop] == B_TRUE);
1642 1642                  value = zfs_prop_default_numeric(prop);
1643 1643                  *source = "";
1644 1644          }
1645 1645  
1646 1646          return (value);
1647 1647  }
1648 1648  
1649 1649  static char *
1650 1650  getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1651 1651  {
1652 1652          nvlist_t *nv;
1653 1653          char *value;
1654 1654  
1655 1655          *source = NULL;
1656 1656          if (nvlist_lookup_nvlist(zhp->zfs_props,
1657 1657              zfs_prop_to_name(prop), &nv) == 0) {
1658 1658                  verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
1659 1659                  (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1660 1660          } else {
1661 1661                  verify(!zhp->zfs_props_table ||
1662 1662                      zhp->zfs_props_table[prop] == B_TRUE);
1663 1663                  if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
1664 1664                          value = "";
1665 1665                  *source = "";
1666 1666          }
1667 1667  
1668 1668          return (value);
1669 1669  }
1670 1670  
1671 1671  static boolean_t
1672 1672  zfs_is_recvd_props_mode(zfs_handle_t *zhp)
1673 1673  {
1674 1674          return (zhp->zfs_props == zhp->zfs_recvd_props);
1675 1675  }
1676 1676  
1677 1677  static void
1678 1678  zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1679 1679  {
1680 1680          *cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
1681 1681          zhp->zfs_props = zhp->zfs_recvd_props;
1682 1682  }
1683 1683  
1684 1684  static void
1685 1685  zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1686 1686  {
1687 1687          zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
1688 1688          *cookie = 0;
1689 1689  }
1690 1690  
1691 1691  /*
1692 1692   * Internal function for getting a numeric property.  Both zfs_prop_get() and
1693 1693   * zfs_prop_get_int() are built using this interface.
1694 1694   *
1695 1695   * Certain properties can be overridden using 'mount -o'.  In this case, scan
1696 1696   * the contents of the /etc/mnttab entry, searching for the appropriate options.
1697 1697   * If they differ from the on-disk values, report the current values and mark
1698 1698   * the source "temporary".
1699 1699   */
1700 1700  static int
1701 1701  get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
1702 1702      char **source, uint64_t *val)
1703 1703  {
1704 1704          zfs_cmd_t zc = { 0 };
1705 1705          nvlist_t *zplprops = NULL;
1706 1706          struct mnttab mnt;
1707 1707          char *mntopt_on = NULL;
1708 1708          char *mntopt_off = NULL;
1709 1709          boolean_t received = zfs_is_recvd_props_mode(zhp);
1710 1710  
1711 1711          *source = NULL;
1712 1712  
1713 1713          switch (prop) {
1714 1714          case ZFS_PROP_ATIME:
1715 1715                  mntopt_on = MNTOPT_ATIME;
1716 1716                  mntopt_off = MNTOPT_NOATIME;
1717 1717                  break;
1718 1718  
1719 1719          case ZFS_PROP_DEVICES:
1720 1720                  mntopt_on = MNTOPT_DEVICES;
1721 1721                  mntopt_off = MNTOPT_NODEVICES;
1722 1722                  break;
1723 1723  
1724 1724          case ZFS_PROP_EXEC:
1725 1725                  mntopt_on = MNTOPT_EXEC;
1726 1726                  mntopt_off = MNTOPT_NOEXEC;
1727 1727                  break;
1728 1728  
1729 1729          case ZFS_PROP_READONLY:
1730 1730                  mntopt_on = MNTOPT_RO;
1731 1731                  mntopt_off = MNTOPT_RW;
1732 1732                  break;
1733 1733  
1734 1734          case ZFS_PROP_SETUID:
1735 1735                  mntopt_on = MNTOPT_SETUID;
1736 1736                  mntopt_off = MNTOPT_NOSETUID;
1737 1737                  break;
1738 1738  
1739 1739          case ZFS_PROP_XATTR:
1740 1740                  mntopt_on = MNTOPT_XATTR;
1741 1741                  mntopt_off = MNTOPT_NOXATTR;
1742 1742                  break;
1743 1743  
1744 1744          case ZFS_PROP_NBMAND:
1745 1745                  mntopt_on = MNTOPT_NBMAND;
1746 1746                  mntopt_off = MNTOPT_NONBMAND;
1747 1747                  break;
1748 1748          }
1749 1749  
1750 1750          /*
1751 1751           * Because looking up the mount options is potentially expensive
1752 1752           * (iterating over all of /etc/mnttab), we defer its calculation until
1753 1753           * we're looking up a property which requires its presence.
1754 1754           */
1755 1755          if (!zhp->zfs_mntcheck &&
1756 1756              (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
1757 1757                  libzfs_handle_t *hdl = zhp->zfs_hdl;
1758 1758                  struct mnttab entry;
1759 1759  
1760 1760                  if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
1761 1761                          zhp->zfs_mntopts = zfs_strdup(hdl,
1762 1762                              entry.mnt_mntopts);
1763 1763                          if (zhp->zfs_mntopts == NULL)
1764 1764                                  return (-1);
1765 1765                  }
1766 1766  
1767 1767                  zhp->zfs_mntcheck = B_TRUE;
1768 1768          }
1769 1769  
1770 1770          if (zhp->zfs_mntopts == NULL)
1771 1771                  mnt.mnt_mntopts = "";
1772 1772          else
1773 1773                  mnt.mnt_mntopts = zhp->zfs_mntopts;
1774 1774  
1775 1775          switch (prop) {
1776 1776          case ZFS_PROP_ATIME:
1777 1777          case ZFS_PROP_DEVICES:
1778 1778          case ZFS_PROP_EXEC:
1779 1779          case ZFS_PROP_READONLY:
1780 1780          case ZFS_PROP_SETUID:
1781 1781          case ZFS_PROP_XATTR:
1782 1782          case ZFS_PROP_NBMAND:
1783 1783                  *val = getprop_uint64(zhp, prop, source);
1784 1784  
1785 1785                  if (received)
1786 1786                          break;
1787 1787  
1788 1788                  if (hasmntopt(&mnt, mntopt_on) && !*val) {
1789 1789                          *val = B_TRUE;
1790 1790                          if (src)
1791 1791                                  *src = ZPROP_SRC_TEMPORARY;
1792 1792                  } else if (hasmntopt(&mnt, mntopt_off) && *val) {
1793 1793                          *val = B_FALSE;
1794 1794                          if (src)
1795 1795                                  *src = ZPROP_SRC_TEMPORARY;
1796 1796                  }
1797 1797                  break;
1798 1798  
1799 1799          case ZFS_PROP_CANMOUNT:
1800 1800          case ZFS_PROP_VOLSIZE:
1801 1801          case ZFS_PROP_QUOTA:
1802 1802          case ZFS_PROP_REFQUOTA:
1803 1803          case ZFS_PROP_RESERVATION:
1804 1804          case ZFS_PROP_REFRESERVATION:
1805 1805                  *val = getprop_uint64(zhp, prop, source);
1806 1806  
1807 1807                  if (*source == NULL) {
1808 1808                          /* not default, must be local */
1809 1809                          *source = zhp->zfs_name;
1810 1810                  }
1811 1811                  break;
1812 1812  
1813 1813          case ZFS_PROP_MOUNTED:
1814 1814                  *val = (zhp->zfs_mntopts != NULL);
1815 1815                  break;
1816 1816  
1817 1817          case ZFS_PROP_NUMCLONES:
1818 1818                  *val = zhp->zfs_dmustats.dds_num_clones;
1819 1819                  break;
1820 1820  
1821 1821          case ZFS_PROP_VERSION:
1822 1822          case ZFS_PROP_NORMALIZE:
1823 1823          case ZFS_PROP_UTF8ONLY:
1824 1824          case ZFS_PROP_CASE:
1825 1825                  if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
1826 1826                      zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
1827 1827                          return (-1);
1828 1828                  (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1829 1829                  if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
1830 1830                          zcmd_free_nvlists(&zc);
1831 1831                          return (-1);
1832 1832                  }
1833 1833                  if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
1834 1834                      nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
1835 1835                      val) != 0) {
1836 1836                          zcmd_free_nvlists(&zc);
1837 1837                          return (-1);
1838 1838                  }
1839 1839                  if (zplprops)
1840 1840                          nvlist_free(zplprops);
1841 1841                  zcmd_free_nvlists(&zc);
1842 1842                  break;
1843 1843  
1844 1844          default:
1845 1845                  switch (zfs_prop_get_type(prop)) {
1846 1846                  case PROP_TYPE_NUMBER:
1847 1847                  case PROP_TYPE_INDEX:
1848 1848                          *val = getprop_uint64(zhp, prop, source);
1849 1849                          /*
1850 1850                           * If we tried to use a default value for a
1851 1851                           * readonly property, it means that it was not
1852 1852                           * present.
1853 1853                           */
1854 1854                          if (zfs_prop_readonly(prop) &&
1855 1855                              *source != NULL && (*source)[0] == '\0') {
1856 1856                                  *source = NULL;
1857 1857                          }
1858 1858                          break;
1859 1859  
1860 1860                  case PROP_TYPE_STRING:
1861 1861                  default:
1862 1862                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
1863 1863                              "cannot get non-numeric property"));
1864 1864                          return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
1865 1865                              dgettext(TEXT_DOMAIN, "internal error")));
1866 1866                  }
1867 1867          }
1868 1868  
1869 1869          return (0);
1870 1870  }
1871 1871  
1872 1872  /*
1873 1873   * Calculate the source type, given the raw source string.
1874 1874   */
1875 1875  static void
1876 1876  get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
1877 1877      char *statbuf, size_t statlen)
1878 1878  {
1879 1879          if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
1880 1880                  return;
1881 1881  
1882 1882          if (source == NULL) {
1883 1883                  *srctype = ZPROP_SRC_NONE;
1884 1884          } else if (source[0] == '\0') {
1885 1885                  *srctype = ZPROP_SRC_DEFAULT;
1886 1886          } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
1887 1887                  *srctype = ZPROP_SRC_RECEIVED;
1888 1888          } else {
1889 1889                  if (strcmp(source, zhp->zfs_name) == 0) {
1890 1890                          *srctype = ZPROP_SRC_LOCAL;
1891 1891                  } else {
1892 1892                          (void) strlcpy(statbuf, source, statlen);
1893 1893                          *srctype = ZPROP_SRC_INHERITED;
1894 1894                  }
1895 1895          }
1896 1896  
1897 1897  }
1898 1898  
1899 1899  int
1900 1900  zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
1901 1901      size_t proplen, boolean_t literal)
1902 1902  {
1903 1903          zfs_prop_t prop;
1904 1904          int err = 0;
1905 1905  
1906 1906          if (zhp->zfs_recvd_props == NULL)
1907 1907                  if (get_recvd_props_ioctl(zhp) != 0)
1908 1908                          return (-1);
1909 1909  
1910 1910          prop = zfs_name_to_prop(propname);
1911 1911  
1912 1912          if (prop != ZPROP_INVAL) {
1913 1913                  uint64_t cookie;
1914 1914                  if (!nvlist_exists(zhp->zfs_recvd_props, propname))
1915 1915                          return (-1);
1916 1916                  zfs_set_recvd_props_mode(zhp, &cookie);
1917 1917                  err = zfs_prop_get(zhp, prop, propbuf, proplen,
1918 1918                      NULL, NULL, 0, literal);
1919 1919                  zfs_unset_recvd_props_mode(zhp, &cookie);
1920 1920          } else {
1921 1921                  nvlist_t *propval;
1922 1922                  char *recvdval;
1923 1923                  if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
1924 1924                      propname, &propval) != 0)
1925 1925                          return (-1);
1926 1926                  verify(nvlist_lookup_string(propval, ZPROP_VALUE,
1927 1927                      &recvdval) == 0);
1928 1928                  (void) strlcpy(propbuf, recvdval, proplen);
1929 1929          }
1930 1930  
1931 1931          return (err == 0 ? 0 : -1);
1932 1932  }
1933 1933  
1934 1934  static int
1935 1935  get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
1936 1936  {
1937 1937          nvlist_t *value;
1938 1938          nvpair_t *pair;
1939 1939  
1940 1940          value = zfs_get_clones_nvl(zhp);
1941 1941          if (value == NULL)
1942 1942                  return (-1);
1943 1943  
1944 1944          propbuf[0] = '\0';
1945 1945          for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
1946 1946              pair = nvlist_next_nvpair(value, pair)) {
1947 1947                  if (propbuf[0] != '\0')
1948 1948                          (void) strlcat(propbuf, ",", proplen);
1949 1949                  (void) strlcat(propbuf, nvpair_name(pair), proplen);
1950 1950          }
1951 1951  
1952 1952          return (0);
1953 1953  }
1954 1954  
1955 1955  struct get_clones_arg {
1956 1956          uint64_t numclones;
1957 1957          nvlist_t *value;
1958 1958          const char *origin;
1959 1959          char buf[ZFS_MAXNAMELEN];
1960 1960  };
1961 1961  
1962 1962  int
1963 1963  get_clones_cb(zfs_handle_t *zhp, void *arg)
1964 1964  {
1965 1965          struct get_clones_arg *gca = arg;
1966 1966  
1967 1967          if (gca->numclones == 0) {
1968 1968                  zfs_close(zhp);
1969 1969                  return (0);
1970 1970          }
1971 1971  
1972 1972          if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
1973 1973              NULL, NULL, 0, B_TRUE) != 0)
1974 1974                  goto out;
1975 1975          if (strcmp(gca->buf, gca->origin) == 0) {
1976 1976                  fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
1977 1977                  gca->numclones--;
1978 1978          }
1979 1979  
1980 1980  out:
1981 1981          (void) zfs_iter_children(zhp, get_clones_cb, gca);
1982 1982          zfs_close(zhp);
1983 1983          return (0);
1984 1984  }
1985 1985  
1986 1986  nvlist_t *
1987 1987  zfs_get_clones_nvl(zfs_handle_t *zhp)
1988 1988  {
1989 1989          nvlist_t *nv, *value;
1990 1990  
1991 1991          if (nvlist_lookup_nvlist(zhp->zfs_props,
1992 1992              zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
1993 1993                  struct get_clones_arg gca;
1994 1994  
1995 1995                  /*
1996 1996                   * if this is a snapshot, then the kernel wasn't able
1997 1997                   * to get the clones.  Do it by slowly iterating.
1998 1998                   */
1999 1999                  if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
2000 2000                          return (NULL);
2001 2001                  if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
2002 2002                          return (NULL);
2003 2003                  if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
2004 2004                          nvlist_free(nv);
2005 2005                          return (NULL);
2006 2006                  }
2007 2007  
2008 2008                  gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
2009 2009                  gca.value = value;
2010 2010                  gca.origin = zhp->zfs_name;
2011 2011  
2012 2012                  if (gca.numclones != 0) {
2013 2013                          zfs_handle_t *root;
2014 2014                          char pool[ZFS_MAXNAMELEN];
2015 2015                          char *cp = pool;
2016 2016  
2017 2017                          /* get the pool name */
2018 2018                          (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
2019 2019                          (void) strsep(&cp, "/@");
2020 2020                          root = zfs_open(zhp->zfs_hdl, pool,
2021 2021                              ZFS_TYPE_FILESYSTEM);
2022 2022  
2023 2023                          (void) get_clones_cb(root, &gca);
2024 2024                  }
2025 2025  
2026 2026                  if (gca.numclones != 0 ||
2027 2027                      nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
2028 2028                      nvlist_add_nvlist(zhp->zfs_props,
2029 2029                      zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
2030 2030                          nvlist_free(nv);
2031 2031                          nvlist_free(value);
2032 2032                          return (NULL);
2033 2033                  }
2034 2034                  nvlist_free(nv);
2035 2035                  nvlist_free(value);
2036 2036                  verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
2037 2037                      zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
2038 2038          }
2039 2039  
2040 2040          verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
2041 2041  
2042 2042          return (value);
2043 2043  }
2044 2044  
2045 2045  /*
2046 2046   * Retrieve a property from the given object.  If 'literal' is specified, then
2047 2047   * numbers are left as exact values.  Otherwise, numbers are converted to a
2048 2048   * human-readable form.
2049 2049   *
2050 2050   * Returns 0 on success, or -1 on error.
2051 2051   */
2052 2052  int
2053 2053  zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
2054 2054      zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
2055 2055  {
2056 2056          char *source = NULL;
2057 2057          uint64_t val;
2058 2058          char *str;
2059 2059          const char *strval;
2060 2060          boolean_t received = zfs_is_recvd_props_mode(zhp);
2061 2061  
2062 2062          /*
2063 2063           * Check to see if this property applies to our object
2064 2064           */
2065 2065          if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
2066 2066                  return (-1);
2067 2067  
2068 2068          if (received && zfs_prop_readonly(prop))
2069 2069                  return (-1);
2070 2070  
2071 2071          if (src)
2072 2072                  *src = ZPROP_SRC_NONE;
2073 2073  
2074 2074          switch (prop) {
2075 2075          case ZFS_PROP_CREATION:
2076 2076                  /*
2077 2077                   * 'creation' is a time_t stored in the statistics.  We convert
2078 2078                   * this into a string unless 'literal' is specified.
2079 2079                   */
2080 2080                  {
2081 2081                          val = getprop_uint64(zhp, prop, &source);
2082 2082                          time_t time = (time_t)val;
2083 2083                          struct tm t;
2084 2084  
2085 2085                          if (literal ||
2086 2086                              localtime_r(&time, &t) == NULL ||
2087 2087                              strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
2088 2088                              &t) == 0)
2089 2089                                  (void) snprintf(propbuf, proplen, "%llu", val);
2090 2090                  }
2091 2091                  break;
2092 2092  
2093 2093          case ZFS_PROP_MOUNTPOINT:
2094 2094                  /*
2095 2095                   * Getting the precise mountpoint can be tricky.
2096 2096                   *
2097 2097                   *  - for 'none' or 'legacy', return those values.
2098 2098                   *  - for inherited mountpoints, we want to take everything
2099 2099                   *    after our ancestor and append it to the inherited value.
2100 2100                   *
2101 2101                   * If the pool has an alternate root, we want to prepend that
2102 2102                   * root to any values we return.
2103 2103                   */
2104 2104  
2105 2105                  str = getprop_string(zhp, prop, &source);
2106 2106  
2107 2107                  if (str[0] == '/') {
2108 2108                          char buf[MAXPATHLEN];
2109 2109                          char *root = buf;
2110 2110                          const char *relpath;
2111 2111  
2112 2112                          /*
2113 2113                           * If we inherit the mountpoint, even from a dataset
2114 2114                           * with a received value, the source will be the path of
2115 2115                           * the dataset we inherit from. If source is
2116 2116                           * ZPROP_SOURCE_VAL_RECVD, the received value is not
2117 2117                           * inherited.
2118 2118                           */
2119 2119                          if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
2120 2120                                  relpath = "";
2121 2121                          } else {
2122 2122                                  relpath = zhp->zfs_name + strlen(source);
2123 2123                                  if (relpath[0] == '/')
2124 2124                                          relpath++;
2125 2125                          }
2126 2126  
2127 2127                          if ((zpool_get_prop(zhp->zpool_hdl,
2128 2128                              ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) ||
2129 2129                              (strcmp(root, "-") == 0))
2130 2130                                  root[0] = '\0';
2131 2131                          /*
2132 2132                           * Special case an alternate root of '/'. This will
2133 2133                           * avoid having multiple leading slashes in the
2134 2134                           * mountpoint path.
2135 2135                           */
2136 2136                          if (strcmp(root, "/") == 0)
2137 2137                                  root++;
2138 2138  
2139 2139                          /*
2140 2140                           * If the mountpoint is '/' then skip over this
2141 2141                           * if we are obtaining either an alternate root or
2142 2142                           * an inherited mountpoint.
2143 2143                           */
2144 2144                          if (str[1] == '\0' && (root[0] != '\0' ||
2145 2145                              relpath[0] != '\0'))
2146 2146                                  str++;
2147 2147  
2148 2148                          if (relpath[0] == '\0')
2149 2149                                  (void) snprintf(propbuf, proplen, "%s%s",
2150 2150                                      root, str);
2151 2151                          else
2152 2152                                  (void) snprintf(propbuf, proplen, "%s%s%s%s",
2153 2153                                      root, str, relpath[0] == '@' ? "" : "/",
2154 2154                                      relpath);
2155 2155                  } else {
2156 2156                          /* 'legacy' or 'none' */
2157 2157                          (void) strlcpy(propbuf, str, proplen);
2158 2158                  }
2159 2159  
2160 2160                  break;
2161 2161  
2162 2162          case ZFS_PROP_ORIGIN:
2163 2163                  (void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
2164 2164                      proplen);
2165 2165                  /*
2166 2166                   * If there is no parent at all, return failure to indicate that
2167 2167                   * it doesn't apply to this dataset.
2168 2168                   */
2169 2169                  if (propbuf[0] == '\0')
2170 2170                          return (-1);
2171 2171                  break;
2172 2172  
2173 2173          case ZFS_PROP_CLONES:
2174 2174                  if (get_clones_string(zhp, propbuf, proplen) != 0)
2175 2175                          return (-1);
2176 2176                  break;
2177 2177  
2178 2178          case ZFS_PROP_QUOTA:
2179 2179          case ZFS_PROP_REFQUOTA:
2180 2180          case ZFS_PROP_RESERVATION:
2181 2181          case ZFS_PROP_REFRESERVATION:
2182 2182  
2183 2183                  if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2184 2184                          return (-1);
2185 2185  
2186 2186                  /*
2187 2187                   * If quota or reservation is 0, we translate this into 'none'
2188 2188                   * (unless literal is set), and indicate that it's the default
2189 2189                   * value.  Otherwise, we print the number nicely and indicate
2190 2190                   * that its set locally.
2191 2191                   */
2192 2192                  if (val == 0) {
2193 2193                          if (literal)
2194 2194                                  (void) strlcpy(propbuf, "0", proplen);
2195 2195                          else
2196 2196                                  (void) strlcpy(propbuf, "none", proplen);
2197 2197                  } else {
2198 2198                          if (literal)
2199 2199                                  (void) snprintf(propbuf, proplen, "%llu",
2200 2200                                      (u_longlong_t)val);
2201 2201                          else
2202 2202                                  zfs_nicenum(val, propbuf, proplen);
2203 2203                  }
2204 2204                  break;
2205 2205  
2206 2206          case ZFS_PROP_REFRATIO:
2207 2207          case ZFS_PROP_COMPRESSRATIO:
2208 2208                  if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2209 2209                          return (-1);
2210 2210                  (void) snprintf(propbuf, proplen, "%llu.%02llux",
2211 2211                      (u_longlong_t)(val / 100),
2212 2212                      (u_longlong_t)(val % 100));
2213 2213                  break;
2214 2214  
2215 2215          case ZFS_PROP_TYPE:
2216 2216                  switch (zhp->zfs_type) {
2217 2217                  case ZFS_TYPE_FILESYSTEM:
2218 2218                          str = "filesystem";
2219 2219                          break;
2220 2220                  case ZFS_TYPE_VOLUME:
2221 2221                          str = "volume";
2222 2222                          break;
2223 2223                  case ZFS_TYPE_SNAPSHOT:
2224 2224                          str = "snapshot";
2225 2225                          break;
2226 2226                  default:
2227 2227                          abort();
2228 2228                  }
2229 2229                  (void) snprintf(propbuf, proplen, "%s", str);
2230 2230                  break;
2231 2231  
2232 2232          case ZFS_PROP_MOUNTED:
2233 2233                  /*
2234 2234                   * The 'mounted' property is a pseudo-property that described
2235 2235                   * whether the filesystem is currently mounted.  Even though
2236 2236                   * it's a boolean value, the typical values of "on" and "off"
2237 2237                   * don't make sense, so we translate to "yes" and "no".
2238 2238                   */
2239 2239                  if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
2240 2240                      src, &source, &val) != 0)
2241 2241                          return (-1);
2242 2242                  if (val)
2243 2243                          (void) strlcpy(propbuf, "yes", proplen);
2244 2244                  else
2245 2245                          (void) strlcpy(propbuf, "no", proplen);
2246 2246                  break;
2247 2247  
2248 2248          case ZFS_PROP_NAME:
2249 2249                  /*
2250 2250                   * The 'name' property is a pseudo-property derived from the
2251 2251                   * dataset name.  It is presented as a real property to simplify
2252 2252                   * consumers.
2253 2253                   */
2254 2254                  (void) strlcpy(propbuf, zhp->zfs_name, proplen);
2255 2255                  break;
2256 2256  
2257 2257          case ZFS_PROP_MLSLABEL:
2258 2258                  {
2259 2259                          m_label_t *new_sl = NULL;
2260 2260                          char *ascii = NULL;     /* human readable label */
2261 2261  
2262 2262                          (void) strlcpy(propbuf,
2263 2263                              getprop_string(zhp, prop, &source), proplen);
2264 2264  
2265 2265                          if (literal || (strcasecmp(propbuf,
2266 2266                              ZFS_MLSLABEL_DEFAULT) == 0))
2267 2267                                  break;
2268 2268  
2269 2269                          /*
2270 2270                           * Try to translate the internal hex string to
2271 2271                           * human-readable output.  If there are any
2272 2272                           * problems just use the hex string.
2273 2273                           */
2274 2274  
2275 2275                          if (str_to_label(propbuf, &new_sl, MAC_LABEL,
2276 2276                              L_NO_CORRECTION, NULL) == -1) {
2277 2277                                  m_label_free(new_sl);
2278 2278                                  break;
2279 2279                          }
2280 2280  
2281 2281                          if (label_to_str(new_sl, &ascii, M_LABEL,
2282 2282                              DEF_NAMES) != 0) {
2283 2283                                  if (ascii)
2284 2284                                          free(ascii);
2285 2285                                  m_label_free(new_sl);
2286 2286                                  break;
2287 2287                          }
2288 2288                          m_label_free(new_sl);
2289 2289  
2290 2290                          (void) strlcpy(propbuf, ascii, proplen);
2291 2291                          free(ascii);
2292 2292                  }
2293 2293                  break;
2294 2294  
2295 2295          case ZFS_PROP_GUID:
2296 2296                  /*
2297 2297                   * GUIDs are stored as numbers, but they are identifiers.
2298 2298                   * We don't want them to be pretty printed, because pretty
2299 2299                   * printing mangles the ID into a truncated and useless value.
2300 2300                   */
2301 2301                  if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2302 2302                          return (-1);
2303 2303                  (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
2304 2304                  break;
2305 2305  
2306 2306          default:
2307 2307                  switch (zfs_prop_get_type(prop)) {
2308 2308                  case PROP_TYPE_NUMBER:
2309 2309                          if (get_numeric_property(zhp, prop, src,
2310 2310                              &source, &val) != 0)
2311 2311                                  return (-1);
2312 2312                          if (literal)
2313 2313                                  (void) snprintf(propbuf, proplen, "%llu",
2314 2314                                      (u_longlong_t)val);
2315 2315                          else
2316 2316                                  zfs_nicenum(val, propbuf, proplen);
2317 2317                          break;
2318 2318  
2319 2319                  case PROP_TYPE_STRING:
2320 2320                          (void) strlcpy(propbuf,
2321 2321                              getprop_string(zhp, prop, &source), proplen);
2322 2322                          break;
2323 2323  
2324 2324                  case PROP_TYPE_INDEX:
2325 2325                          if (get_numeric_property(zhp, prop, src,
2326 2326                              &source, &val) != 0)
2327 2327                                  return (-1);
2328 2328                          if (zfs_prop_index_to_string(prop, val, &strval) != 0)
2329 2329                                  return (-1);
2330 2330                          (void) strlcpy(propbuf, strval, proplen);
2331 2331                          break;
2332 2332  
2333 2333                  default:
2334 2334                          abort();
2335 2335                  }
2336 2336          }
2337 2337  
2338 2338          get_source(zhp, src, source, statbuf, statlen);
2339 2339  
2340 2340          return (0);
2341 2341  }
2342 2342  
2343 2343  /*
2344 2344   * Utility function to get the given numeric property.  Does no validation that
2345 2345   * the given property is the appropriate type; should only be used with
2346 2346   * hard-coded property types.
2347 2347   */
2348 2348  uint64_t
2349 2349  zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
2350 2350  {
2351 2351          char *source;
2352 2352          uint64_t val;
2353 2353  
2354 2354          (void) get_numeric_property(zhp, prop, NULL, &source, &val);
2355 2355  
2356 2356          return (val);
2357 2357  }
2358 2358  
2359 2359  int
2360 2360  zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
2361 2361  {
2362 2362          char buf[64];
2363 2363  
2364 2364          (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
2365 2365          return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
2366 2366  }
2367 2367  
2368 2368  /*
2369 2369   * Similar to zfs_prop_get(), but returns the value as an integer.
2370 2370   */
2371 2371  int
2372 2372  zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
2373 2373      zprop_source_t *src, char *statbuf, size_t statlen)
2374 2374  {
2375 2375          char *source;
2376 2376  
2377 2377          /*
2378 2378           * Check to see if this property applies to our object
2379 2379           */
2380 2380          if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
2381 2381                  return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
2382 2382                      dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
2383 2383                      zfs_prop_to_name(prop)));
2384 2384          }
2385 2385  
2386 2386          if (src)
2387 2387                  *src = ZPROP_SRC_NONE;
2388 2388  
2389 2389          if (get_numeric_property(zhp, prop, src, &source, value) != 0)
2390 2390                  return (-1);
2391 2391  
2392 2392          get_source(zhp, src, source, statbuf, statlen);
2393 2393  
2394 2394          return (0);
2395 2395  }
2396 2396  
2397 2397  static int
2398 2398  idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
2399 2399      char **domainp, idmap_rid_t *ridp)
2400 2400  {
2401 2401          idmap_get_handle_t *get_hdl = NULL;
2402 2402          idmap_stat status;
2403 2403          int err = EINVAL;
2404 2404  
2405 2405          if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
2406 2406                  goto out;
2407 2407  
2408 2408          if (isuser) {
2409 2409                  err = idmap_get_sidbyuid(get_hdl, id,
2410 2410                      IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2411 2411          } else {
2412 2412                  err = idmap_get_sidbygid(get_hdl, id,
2413 2413                      IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2414 2414          }
2415 2415          if (err == IDMAP_SUCCESS &&
2416 2416              idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
2417 2417              status == IDMAP_SUCCESS)
2418 2418                  err = 0;
2419 2419          else
2420 2420                  err = EINVAL;
2421 2421  out:
2422 2422          if (get_hdl)
2423 2423                  idmap_get_destroy(get_hdl);
2424 2424          return (err);
2425 2425  }
2426 2426  
2427 2427  /*
2428 2428   * convert the propname into parameters needed by kernel
2429 2429   * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
2430 2430   * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
2431 2431   */
2432 2432  static int
2433 2433  userquota_propname_decode(const char *propname, boolean_t zoned,
2434 2434      zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
2435 2435  {
2436 2436          zfs_userquota_prop_t type;
2437 2437          char *cp, *end;
2438 2438          char *numericsid = NULL;
2439 2439          boolean_t isuser;
2440 2440  
2441 2441          domain[0] = '\0';
2442 2442  
2443 2443          /* Figure out the property type ({user|group}{quota|space}) */
2444 2444          for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
2445 2445                  if (strncmp(propname, zfs_userquota_prop_prefixes[type],
2446 2446                      strlen(zfs_userquota_prop_prefixes[type])) == 0)
2447 2447                          break;
2448 2448          }
2449 2449          if (type == ZFS_NUM_USERQUOTA_PROPS)
2450 2450                  return (EINVAL);
2451 2451          *typep = type;
2452 2452  
2453 2453          isuser = (type == ZFS_PROP_USERQUOTA ||
2454 2454              type == ZFS_PROP_USERUSED);
2455 2455  
2456 2456          cp = strchr(propname, '@') + 1;
2457 2457  
2458 2458          if (strchr(cp, '@')) {
2459 2459                  /*
2460 2460                   * It's a SID name (eg "user@domain") that needs to be
2461 2461                   * turned into S-1-domainID-RID.
2462 2462                   */
2463 2463                  directory_error_t e;
2464 2464                  if (zoned && getzoneid() == GLOBAL_ZONEID)
2465 2465                          return (ENOENT);
2466 2466                  if (isuser) {
2467 2467                          e = directory_sid_from_user_name(NULL,
2468 2468                              cp, &numericsid);
2469 2469                  } else {
2470 2470                          e = directory_sid_from_group_name(NULL,
2471 2471                              cp, &numericsid);
2472 2472                  }
2473 2473                  if (e != NULL) {
2474 2474                          directory_error_free(e);
2475 2475                          return (ENOENT);
2476 2476                  }
2477 2477                  if (numericsid == NULL)
2478 2478                          return (ENOENT);
2479 2479                  cp = numericsid;
2480 2480                  /* will be further decoded below */
2481 2481          }
2482 2482  
2483 2483          if (strncmp(cp, "S-1-", 4) == 0) {
2484 2484                  /* It's a numeric SID (eg "S-1-234-567-89") */
2485 2485                  (void) strlcpy(domain, cp, domainlen);
2486 2486                  cp = strrchr(domain, '-');
2487 2487                  *cp = '\0';
2488 2488                  cp++;
2489 2489  
2490 2490                  errno = 0;
2491 2491                  *ridp = strtoull(cp, &end, 10);
2492 2492                  if (numericsid) {
2493 2493                          free(numericsid);
2494 2494                          numericsid = NULL;
2495 2495                  }
2496 2496                  if (errno != 0 || *end != '\0')
2497 2497                          return (EINVAL);
2498 2498          } else if (!isdigit(*cp)) {
2499 2499                  /*
2500 2500                   * It's a user/group name (eg "user") that needs to be
2501 2501                   * turned into a uid/gid
2502 2502                   */
2503 2503                  if (zoned && getzoneid() == GLOBAL_ZONEID)
2504 2504                          return (ENOENT);
2505 2505                  if (isuser) {
2506 2506                          struct passwd *pw;
2507 2507                          pw = getpwnam(cp);
2508 2508                          if (pw == NULL)
2509 2509                                  return (ENOENT);
2510 2510                          *ridp = pw->pw_uid;
2511 2511                  } else {
2512 2512                          struct group *gr;
2513 2513                          gr = getgrnam(cp);
2514 2514                          if (gr == NULL)
2515 2515                                  return (ENOENT);
2516 2516                          *ridp = gr->gr_gid;
2517 2517                  }
2518 2518          } else {
2519 2519                  /* It's a user/group ID (eg "12345"). */
2520 2520                  uid_t id = strtoul(cp, &end, 10);
2521 2521                  idmap_rid_t rid;
2522 2522                  char *mapdomain;
2523 2523  
2524 2524                  if (*end != '\0')
2525 2525                          return (EINVAL);
2526 2526                  if (id > MAXUID) {
2527 2527                          /* It's an ephemeral ID. */
2528 2528                          if (idmap_id_to_numeric_domain_rid(id, isuser,
2529 2529                              &mapdomain, &rid) != 0)
2530 2530                                  return (ENOENT);
2531 2531                          (void) strlcpy(domain, mapdomain, domainlen);
2532 2532                          *ridp = rid;
2533 2533                  } else {
2534 2534                          *ridp = id;
2535 2535                  }
2536 2536          }
2537 2537  
2538 2538          ASSERT3P(numericsid, ==, NULL);
2539 2539          return (0);
2540 2540  }
2541 2541  
2542 2542  static int
2543 2543  zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
2544 2544      uint64_t *propvalue, zfs_userquota_prop_t *typep)
2545 2545  {
2546 2546          int err;
2547 2547          zfs_cmd_t zc = { 0 };
2548 2548  
2549 2549          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2550 2550  
2551 2551          err = userquota_propname_decode(propname,
2552 2552              zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
2553 2553              typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
2554 2554          zc.zc_objset_type = *typep;
2555 2555          if (err)
2556 2556                  return (err);
2557 2557  
2558 2558          err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
2559 2559          if (err)
2560 2560                  return (err);
2561 2561  
2562 2562          *propvalue = zc.zc_cookie;
2563 2563          return (0);
2564 2564  }
2565 2565  
2566 2566  int
2567 2567  zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
2568 2568      uint64_t *propvalue)
2569 2569  {
2570 2570          zfs_userquota_prop_t type;
2571 2571  
2572 2572          return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
2573 2573              &type));
2574 2574  }
2575 2575  
2576 2576  int
2577 2577  zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
2578 2578      char *propbuf, int proplen, boolean_t literal)
2579 2579  {
2580 2580          int err;
2581 2581          uint64_t propvalue;
2582 2582          zfs_userquota_prop_t type;
2583 2583  
2584 2584          err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
2585 2585              &type);
2586 2586  
2587 2587          if (err)
2588 2588                  return (err);
2589 2589  
2590 2590          if (literal) {
2591 2591                  (void) snprintf(propbuf, proplen, "%llu", propvalue);
2592 2592          } else if (propvalue == 0 &&
2593 2593              (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
2594 2594                  (void) strlcpy(propbuf, "none", proplen);
2595 2595          } else {
2596 2596                  zfs_nicenum(propvalue, propbuf, proplen);
2597 2597          }
2598 2598          return (0);
2599 2599  }
2600 2600  
2601 2601  int
2602 2602  zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
2603 2603      uint64_t *propvalue)
2604 2604  {
2605 2605          int err;
2606 2606          zfs_cmd_t zc = { 0 };
2607 2607          const char *snapname;
2608 2608  
2609 2609          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2610 2610  
2611 2611          snapname = strchr(propname, '@') + 1;
2612 2612          if (strchr(snapname, '@')) {
2613 2613                  (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
2614 2614          } else {
2615 2615                  /* snapname is the short name, append it to zhp's fsname */
2616 2616                  char *cp;
2617 2617  
2618 2618                  (void) strlcpy(zc.zc_value, zhp->zfs_name,
2619 2619                      sizeof (zc.zc_value));
2620 2620                  cp = strchr(zc.zc_value, '@');
2621 2621                  if (cp != NULL)
2622 2622                          *cp = '\0';
2623 2623                  (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
2624 2624                  (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
2625 2625          }
2626 2626  
2627 2627          err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
2628 2628          if (err)
2629 2629                  return (err);
2630 2630  
2631 2631          *propvalue = zc.zc_cookie;
2632 2632          return (0);
2633 2633  }
2634 2634  
2635 2635  int
2636 2636  zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
2637 2637      char *propbuf, int proplen, boolean_t literal)
2638 2638  {
2639 2639          int err;
2640 2640          uint64_t propvalue;
2641 2641  
2642 2642          err = zfs_prop_get_written_int(zhp, propname, &propvalue);
2643 2643  
2644 2644          if (err)
2645 2645                  return (err);
2646 2646  
2647 2647          if (literal) {
2648 2648                  (void) snprintf(propbuf, proplen, "%llu", propvalue);
2649 2649          } else {
2650 2650                  zfs_nicenum(propvalue, propbuf, proplen);
2651 2651          }
2652 2652          return (0);
2653 2653  }
2654 2654  
2655 2655  /*
2656 2656   * Returns the name of the given zfs handle.
2657 2657   */
2658 2658  const char *
2659 2659  zfs_get_name(const zfs_handle_t *zhp)
2660 2660  {
2661 2661          return (zhp->zfs_name);
2662 2662  }
2663 2663  
2664 2664  /*
2665 2665   * Returns the type of the given zfs handle.
2666 2666   */
2667 2667  zfs_type_t
2668 2668  zfs_get_type(const zfs_handle_t *zhp)
2669 2669  {
2670 2670          return (zhp->zfs_type);
2671 2671  }
2672 2672  
2673 2673  /*
2674 2674   * Is one dataset name a child dataset of another?
2675 2675   *
2676 2676   * Needs to handle these cases:
2677 2677   * Dataset 1    "a/foo"         "a/foo"         "a/foo"         "a/foo"
2678 2678   * Dataset 2    "a/fo"          "a/foobar"      "a/bar/baz"     "a/foo/bar"
2679 2679   * Descendant?  No.             No.             No.             Yes.
2680 2680   */
2681 2681  static boolean_t
2682 2682  is_descendant(const char *ds1, const char *ds2)
2683 2683  {
2684 2684          size_t d1len = strlen(ds1);
2685 2685  
2686 2686          /* ds2 can't be a descendant if it's smaller */
2687 2687          if (strlen(ds2) < d1len)
2688 2688                  return (B_FALSE);
2689 2689  
2690 2690          /* otherwise, compare strings and verify that there's a '/' char */
2691 2691          return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
2692 2692  }
2693 2693  
2694 2694  /*
2695 2695   * Given a complete name, return just the portion that refers to the parent.
2696 2696   * Will return -1 if there is no parent (path is just the name of the
2697 2697   * pool).
2698 2698   */
2699 2699  static int
2700 2700  parent_name(const char *path, char *buf, size_t buflen)
2701 2701  {
2702 2702          char *slashp;
2703 2703  
2704 2704          (void) strlcpy(buf, path, buflen);
2705 2705  
2706 2706          if ((slashp = strrchr(buf, '/')) == NULL)
2707 2707                  return (-1);
2708 2708          *slashp = '\0';
2709 2709  
2710 2710          return (0);
2711 2711  }
2712 2712  
2713 2713  /*
2714 2714   * If accept_ancestor is false, then check to make sure that the given path has
2715 2715   * a parent, and that it exists.  If accept_ancestor is true, then find the
2716 2716   * closest existing ancestor for the given path.  In prefixlen return the
2717 2717   * length of already existing prefix of the given path.  We also fetch the
2718 2718   * 'zoned' property, which is used to validate property settings when creating
2719 2719   * new datasets.
2720 2720   */
2721 2721  static int
2722 2722  check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
2723 2723      boolean_t accept_ancestor, int *prefixlen)
2724 2724  {
2725 2725          zfs_cmd_t zc = { 0 };
2726 2726          char parent[ZFS_MAXNAMELEN];
2727 2727          char *slash;
2728 2728          zfs_handle_t *zhp;
2729 2729          char errbuf[1024];
2730 2730          uint64_t is_zoned;
2731 2731  
2732 2732          (void) snprintf(errbuf, sizeof (errbuf),
2733 2733              dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
2734 2734  
2735 2735          /* get parent, and check to see if this is just a pool */
2736 2736          if (parent_name(path, parent, sizeof (parent)) != 0) {
2737 2737                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2738 2738                      "missing dataset name"));
2739 2739                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2740 2740          }
2741 2741  
2742 2742          /* check to see if the pool exists */
2743 2743          if ((slash = strchr(parent, '/')) == NULL)
2744 2744                  slash = parent + strlen(parent);
2745 2745          (void) strncpy(zc.zc_name, parent, slash - parent);
2746 2746          zc.zc_name[slash - parent] = '\0';
2747 2747          if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
2748 2748              errno == ENOENT) {
2749 2749                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2750 2750                      "no such pool '%s'"), zc.zc_name);
2751 2751                  return (zfs_error(hdl, EZFS_NOENT, errbuf));
2752 2752          }
2753 2753  
2754 2754          /* check to see if the parent dataset exists */
2755 2755          while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
2756 2756                  if (errno == ENOENT && accept_ancestor) {
2757 2757                          /*
2758 2758                           * Go deeper to find an ancestor, give up on top level.
2759 2759                           */
2760 2760                          if (parent_name(parent, parent, sizeof (parent)) != 0) {
2761 2761                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2762 2762                                      "no such pool '%s'"), zc.zc_name);
2763 2763                                  return (zfs_error(hdl, EZFS_NOENT, errbuf));
2764 2764                          }
2765 2765                  } else if (errno == ENOENT) {
2766 2766                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2767 2767                              "parent does not exist"));
2768 2768                          return (zfs_error(hdl, EZFS_NOENT, errbuf));
2769 2769                  } else
2770 2770                          return (zfs_standard_error(hdl, errno, errbuf));
2771 2771          }
2772 2772  
2773 2773          is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
2774 2774          if (zoned != NULL)
2775 2775                  *zoned = is_zoned;
2776 2776  
2777 2777          /* we are in a non-global zone, but parent is in the global zone */
2778 2778          if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
2779 2779                  (void) zfs_standard_error(hdl, EPERM, errbuf);
2780 2780                  zfs_close(zhp);
2781 2781                  return (-1);
2782 2782          }
2783 2783  
2784 2784          /* make sure parent is a filesystem */
2785 2785          if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2786 2786                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2787 2787                      "parent is not a filesystem"));
2788 2788                  (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
2789 2789                  zfs_close(zhp);
2790 2790                  return (-1);
2791 2791          }
2792 2792  
2793 2793          zfs_close(zhp);
2794 2794          if (prefixlen != NULL)
2795 2795                  *prefixlen = strlen(parent);
2796 2796          return (0);
2797 2797  }
2798 2798  
2799 2799  /*
2800 2800   * Finds whether the dataset of the given type(s) exists.
2801 2801   */
2802 2802  boolean_t
2803 2803  zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
2804 2804  {
2805 2805          zfs_handle_t *zhp;
2806 2806  
2807 2807          if (!zfs_validate_name(hdl, path, types, B_FALSE))
2808 2808                  return (B_FALSE);
2809 2809  
2810 2810          /*
2811 2811           * Try to get stats for the dataset, which will tell us if it exists.
2812 2812           */
2813 2813          if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
2814 2814                  int ds_type = zhp->zfs_type;
2815 2815  
2816 2816                  zfs_close(zhp);
2817 2817                  if (types & ds_type)
2818 2818                          return (B_TRUE);
2819 2819          }
2820 2820          return (B_FALSE);
2821 2821  }
2822 2822  
2823 2823  /*
2824 2824   * Given a path to 'target', create all the ancestors between
2825 2825   * the prefixlen portion of the path, and the target itself.
2826 2826   * Fail if the initial prefixlen-ancestor does not already exist.
2827 2827   */
2828 2828  int
2829 2829  create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
2830 2830  {
2831 2831          zfs_handle_t *h;
2832 2832          char *cp;
2833 2833          const char *opname;
2834 2834  
2835 2835          /* make sure prefix exists */
2836 2836          cp = target + prefixlen;
2837 2837          if (*cp != '/') {
2838 2838                  assert(strchr(cp, '/') == NULL);
2839 2839                  h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2840 2840          } else {
2841 2841                  *cp = '\0';
2842 2842                  h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2843 2843                  *cp = '/';
2844 2844          }
2845 2845          if (h == NULL)
2846 2846                  return (-1);
2847 2847          zfs_close(h);
2848 2848  
2849 2849          /*
2850 2850           * Attempt to create, mount, and share any ancestor filesystems,
2851 2851           * up to the prefixlen-long one.
2852 2852           */
2853 2853          for (cp = target + prefixlen + 1;
2854 2854              cp = strchr(cp, '/'); *cp = '/', cp++) {
2855 2855  
2856 2856                  *cp = '\0';
2857 2857  
2858 2858                  h = make_dataset_handle(hdl, target);
2859 2859                  if (h) {
2860 2860                          /* it already exists, nothing to do here */
2861 2861                          zfs_close(h);
2862 2862                          continue;
2863 2863                  }
2864 2864  
2865 2865                  if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
2866 2866                      NULL) != 0) {
2867 2867                          opname = dgettext(TEXT_DOMAIN, "create");
2868 2868                          goto ancestorerr;
2869 2869                  }
2870 2870  
2871 2871                  h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2872 2872                  if (h == NULL) {
2873 2873                          opname = dgettext(TEXT_DOMAIN, "open");
2874 2874                          goto ancestorerr;
2875 2875                  }
2876 2876  
2877 2877                  if (zfs_mount(h, NULL, 0) != 0) {
2878 2878                          opname = dgettext(TEXT_DOMAIN, "mount");
2879 2879                          goto ancestorerr;
2880 2880                  }
2881 2881  
2882 2882                  if (zfs_share(h) != 0) {
2883 2883                          opname = dgettext(TEXT_DOMAIN, "share");
2884 2884                          goto ancestorerr;
2885 2885                  }
2886 2886  
2887 2887                  zfs_close(h);
2888 2888          }
2889 2889  
2890 2890          return (0);
2891 2891  
2892 2892  ancestorerr:
2893 2893          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2894 2894              "failed to %s ancestor '%s'"), opname, target);
2895 2895          return (-1);
2896 2896  }
2897 2897  
2898 2898  /*
2899 2899   * Creates non-existing ancestors of the given path.
2900 2900   */
2901 2901  int
2902 2902  zfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
2903 2903  {
2904 2904          int prefix;
2905 2905          char *path_copy;
2906 2906          int rc;
2907 2907  
2908 2908          if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
2909 2909                  return (-1);
2910 2910  
2911 2911          if ((path_copy = strdup(path)) != NULL) {
2912 2912                  rc = create_parents(hdl, path_copy, prefix);
2913 2913                  free(path_copy);
2914 2914          }
2915 2915          if (path_copy == NULL || rc != 0)
2916 2916                  return (-1);
2917 2917  
2918 2918          return (0);
2919 2919  }
2920 2920  
2921 2921  /*
2922 2922   * Create a new filesystem or volume.
2923 2923   */
2924 2924  int
2925 2925  zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
2926 2926      nvlist_t *props)
2927 2927  {
2928 2928          int ret;
2929 2929          uint64_t size = 0;
2930 2930          uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
2931 2931          char errbuf[1024];
2932 2932          uint64_t zoned;
2933 2933          dmu_objset_type_t ost;
2934 2934  
2935 2935          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2936 2936              "cannot create '%s'"), path);
2937 2937  
2938 2938          /* validate the path, taking care to note the extended error message */
2939 2939          if (!zfs_validate_name(hdl, path, type, B_TRUE))
2940 2940                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2941 2941  
2942 2942          /* validate parents exist */
2943 2943          if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
2944 2944                  return (-1);
2945 2945  
2946 2946          /*
2947 2947           * The failure modes when creating a dataset of a different type over
2948 2948           * one that already exists is a little strange.  In particular, if you
2949 2949           * try to create a dataset on top of an existing dataset, the ioctl()
2950 2950           * will return ENOENT, not EEXIST.  To prevent this from happening, we
2951 2951           * first try to see if the dataset exists.
2952 2952           */
2953 2953          if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
2954 2954                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2955 2955                      "dataset already exists"));
2956 2956                  return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2957 2957          }
2958 2958  
2959 2959          if (type == ZFS_TYPE_VOLUME)
2960 2960                  ost = DMU_OST_ZVOL;
2961 2961          else
2962 2962                  ost = DMU_OST_ZFS;
2963 2963  
2964 2964          if (props && (props = zfs_valid_proplist(hdl, type, props,
2965 2965              zoned, NULL, errbuf)) == 0)
2966 2966                  return (-1);
2967 2967  
2968 2968          if (type == ZFS_TYPE_VOLUME) {
2969 2969                  /*
2970 2970                   * If we are creating a volume, the size and block size must
2971 2971                   * satisfy a few restraints.  First, the blocksize must be a
2972 2972                   * valid block size between SPA_{MIN,MAX}BLOCKSIZE.  Second, the
2973 2973                   * volsize must be a multiple of the block size, and cannot be
2974 2974                   * zero.
2975 2975                   */
2976 2976                  if (props == NULL || nvlist_lookup_uint64(props,
2977 2977                      zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
2978 2978                          nvlist_free(props);
2979 2979                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2980 2980                              "missing volume size"));
2981 2981                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2982 2982                  }
2983 2983  
2984 2984                  if ((ret = nvlist_lookup_uint64(props,
2985 2985                      zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
2986 2986                      &blocksize)) != 0) {
2987 2987                          if (ret == ENOENT) {
2988 2988                                  blocksize = zfs_prop_default_numeric(
2989 2989                                      ZFS_PROP_VOLBLOCKSIZE);
2990 2990                          } else {
2991 2991                                  nvlist_free(props);
2992 2992                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2993 2993                                      "missing volume block size"));
2994 2994                                  return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2995 2995                          }
2996 2996                  }
2997 2997  
2998 2998                  if (size == 0) {
2999 2999                          nvlist_free(props);
3000 3000                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3001 3001                              "volume size cannot be zero"));
3002 3002                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3003 3003                  }
3004 3004  
3005 3005                  if (size % blocksize != 0) {
3006 3006                          nvlist_free(props);
3007 3007                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3008 3008                              "volume size must be a multiple of volume block "
3009 3009                              "size"));
3010 3010                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3011 3011                  }
3012 3012          }
3013 3013  
3014 3014          /* create the dataset */
3015 3015          ret = lzc_create(path, ost, props);
3016 3016          nvlist_free(props);
3017 3017  
3018 3018          /* check for failure */
3019 3019          if (ret != 0) {
3020 3020                  char parent[ZFS_MAXNAMELEN];
3021 3021                  (void) parent_name(path, parent, sizeof (parent));
3022 3022  
3023 3023                  switch (errno) {
3024 3024                  case ENOENT:
3025 3025                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3026 3026                              "no such parent '%s'"), parent);
3027 3027                          return (zfs_error(hdl, EZFS_NOENT, errbuf));
3028 3028  
3029 3029                  case EINVAL:
3030 3030                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3031 3031                              "parent '%s' is not a filesystem"), parent);
3032 3032                          return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3033 3033  
3034 3034                  case EDOM:
3035 3035                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3036 3036                              "volume block size must be power of 2 from "
3037 3037                              "%u to %uk"),
3038 3038                              (uint_t)SPA_MINBLOCKSIZE,
3039 3039                              (uint_t)SPA_MAXBLOCKSIZE >> 10);
3040 3040  
3041 3041                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3042 3042  
3043 3043                  case ENOTSUP:
3044 3044                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3045 3045                              "pool must be upgraded to set this "
3046 3046                              "property or value"));
3047 3047                          return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
3048 3048  #ifdef _ILP32
3049 3049                  case EOVERFLOW:
3050 3050                          /*
3051 3051                           * This platform can't address a volume this big.
3052 3052                           */
3053 3053                          if (type == ZFS_TYPE_VOLUME)
3054 3054                                  return (zfs_error(hdl, EZFS_VOLTOOBIG,
3055 3055                                      errbuf));
3056 3056  #endif
3057 3057                          /* FALLTHROUGH */
3058 3058                  default:
3059 3059                          return (zfs_standard_error(hdl, errno, errbuf));
3060 3060                  }
3061 3061          }
3062 3062  
3063 3063          return (0);
3064 3064  }
3065 3065  
3066 3066  /*
3067 3067   * Destroys the given dataset.  The caller must make sure that the filesystem
3068 3068   * isn't mounted, and that there are no active dependents. If the file system
3069 3069   * does not exist this function does nothing.
3070 3070   */
3071 3071  int
3072 3072  zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
3073 3073  {
3074 3074          zfs_cmd_t zc = { 0 };
3075 3075  
3076 3076          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3077 3077  
3078 3078          if (ZFS_IS_VOLUME(zhp)) {
3079 3079                  zc.zc_objset_type = DMU_OST_ZVOL;
3080 3080          } else {
3081 3081                  zc.zc_objset_type = DMU_OST_ZFS;
3082 3082          }
3083 3083  
3084 3084          zc.zc_defer_destroy = defer;
3085 3085          if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
3086 3086              errno != ENOENT) {
3087 3087                  return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3088 3088                      dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3089 3089                      zhp->zfs_name));
3090 3090          }
3091 3091  
3092 3092          remove_mountpoint(zhp);
3093 3093  
3094 3094          return (0);
3095 3095  }
3096 3096  
3097 3097  struct destroydata {
3098 3098          nvlist_t *nvl;
3099 3099          const char *snapname;
3100 3100  };
3101 3101  
3102 3102  static int
3103 3103  zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
3104 3104  {
3105 3105          struct destroydata *dd = arg;
3106 3106          zfs_handle_t *szhp;
3107 3107          char name[ZFS_MAXNAMELEN];
3108 3108          int rv = 0;
3109 3109  
3110 3110          (void) snprintf(name, sizeof (name),
3111 3111              "%s@%s", zhp->zfs_name, dd->snapname);
3112 3112  
3113 3113          szhp = make_dataset_handle(zhp->zfs_hdl, name);
3114 3114          if (szhp) {
3115 3115                  verify(nvlist_add_boolean(dd->nvl, name) == 0);
3116 3116                  zfs_close(szhp);
3117 3117          }
3118 3118  
3119 3119          rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
3120 3120          zfs_close(zhp);
3121 3121          return (rv);
3122 3122  }
3123 3123  
3124 3124  /*
3125 3125   * Destroys all snapshots with the given name in zhp & descendants.
3126 3126   */
3127 3127  int
3128 3128  zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
3129 3129  {
3130 3130          int ret;
3131 3131          struct destroydata dd = { 0 };
3132 3132  
3133 3133          dd.snapname = snapname;
3134 3134          verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
3135 3135          (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
3136 3136  
3137 3137          if (nvlist_next_nvpair(dd.nvl, NULL) == NULL) {
3138 3138                  ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
3139 3139                      dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
3140 3140                      zhp->zfs_name, snapname);
3141 3141          } else {
3142 3142                  ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
3143 3143          }
3144 3144          nvlist_free(dd.nvl);
3145 3145          return (ret);
3146 3146  }
3147 3147  
3148 3148  /*
3149 3149   * Destroys all the snapshots named in the nvlist.
3150 3150   */
3151 3151  int
3152 3152  zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
3153 3153  {
3154 3154          int ret;
3155 3155          nvlist_t *errlist;
3156 3156  
3157 3157          ret = lzc_destroy_snaps(snaps, defer, &errlist);
3158 3158  
3159 3159          if (ret == 0)
3160 3160                  return (0);
3161 3161  
3162 3162          if (nvlist_next_nvpair(errlist, NULL) == NULL) {
3163 3163                  char errbuf[1024];
3164 3164                  (void) snprintf(errbuf, sizeof (errbuf),
3165 3165                      dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
3166 3166  
3167 3167                  ret = zfs_standard_error(hdl, ret, errbuf);
3168 3168          }
3169 3169          for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
3170 3170              pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
3171 3171                  char errbuf[1024];
3172 3172                  (void) snprintf(errbuf, sizeof (errbuf),
3173 3173                      dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
3174 3174                      nvpair_name(pair));
3175 3175  
3176 3176                  switch (fnvpair_value_int32(pair)) {
3177 3177                  case EEXIST:
3178 3178                          zfs_error_aux(hdl,
3179 3179                              dgettext(TEXT_DOMAIN, "snapshot is cloned"));
3180 3180                          ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
3181 3181                          break;
3182 3182                  default:
3183 3183                          ret = zfs_standard_error(hdl, errno, errbuf);
3184 3184                          break;
3185 3185                  }
3186 3186          }
3187 3187  
3188 3188          return (ret);
3189 3189  }
3190 3190  
3191 3191  /*
3192 3192   * Clones the given dataset.  The target must be of the same type as the source.
3193 3193   */
3194 3194  int
3195 3195  zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
3196 3196  {
3197 3197          char parent[ZFS_MAXNAMELEN];
3198 3198          int ret;
3199 3199          char errbuf[1024];
3200 3200          libzfs_handle_t *hdl = zhp->zfs_hdl;
3201 3201          uint64_t zoned;
3202 3202  
3203 3203          assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
3204 3204  
3205 3205          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3206 3206              "cannot create '%s'"), target);
3207 3207  
3208 3208          /* validate the target/clone name */
3209 3209          if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
3210 3210                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3211 3211  
3212 3212          /* validate parents exist */
3213 3213          if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
3214 3214                  return (-1);
3215 3215  
3216 3216          (void) parent_name(target, parent, sizeof (parent));
3217 3217  
3218 3218          /* do the clone */
3219 3219  
3220 3220          if (props) {
3221 3221                  zfs_type_t type;
3222 3222                  if (ZFS_IS_VOLUME(zhp)) {
3223 3223                          type = ZFS_TYPE_VOLUME;
3224 3224                  } else {
3225 3225                          type = ZFS_TYPE_FILESYSTEM;
3226 3226                  }
3227 3227                  if ((props = zfs_valid_proplist(hdl, type, props, zoned,
3228 3228                      zhp, errbuf)) == NULL)
3229 3229                          return (-1);
3230 3230          }
3231 3231  
3232 3232          ret = lzc_clone(target, zhp->zfs_name, props);
3233 3233          nvlist_free(props);
3234 3234  
3235 3235          if (ret != 0) {
3236 3236                  switch (errno) {
3237 3237  
3238 3238                  case ENOENT:
3239 3239                          /*
3240 3240                           * The parent doesn't exist.  We should have caught this
3241 3241                           * above, but there may a race condition that has since
3242 3242                           * destroyed the parent.
3243 3243                           *
3244 3244                           * At this point, we don't know whether it's the source
3245 3245                           * that doesn't exist anymore, or whether the target
3246 3246                           * dataset doesn't exist.
3247 3247                           */
3248 3248                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3249 3249                              "no such parent '%s'"), parent);
3250 3250                          return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
3251 3251  
3252 3252                  case EXDEV:
3253 3253                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3254 3254                              "source and target pools differ"));
3255 3255                          return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
3256 3256                              errbuf));
3257 3257  
3258 3258                  default:
3259 3259                          return (zfs_standard_error(zhp->zfs_hdl, errno,
3260 3260                              errbuf));
3261 3261                  }
3262 3262          }
3263 3263  
3264 3264          return (ret);
3265 3265  }
3266 3266  
3267 3267  /*
3268 3268   * Promotes the given clone fs to be the clone parent.
3269 3269   */
3270 3270  int
3271 3271  zfs_promote(zfs_handle_t *zhp)
3272 3272  {
3273 3273          libzfs_handle_t *hdl = zhp->zfs_hdl;
3274 3274          zfs_cmd_t zc = { 0 };
3275 3275          char parent[MAXPATHLEN];
3276 3276          int ret;
3277 3277          char errbuf[1024];
3278 3278  
3279 3279          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3280 3280              "cannot promote '%s'"), zhp->zfs_name);
3281 3281  
3282 3282          if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3283 3283                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3284 3284                      "snapshots can not be promoted"));
3285 3285                  return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3286 3286          }
3287 3287  
3288 3288          (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent));
3289 3289          if (parent[0] == '\0') {
3290 3290                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3291 3291                      "not a cloned filesystem"));
3292 3292                  return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3293 3293          }
3294 3294  
3295 3295          (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin,
3296 3296              sizeof (zc.zc_value));
3297 3297          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3298 3298          ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
3299 3299  
3300 3300          if (ret != 0) {
3301 3301                  int save_errno = errno;
3302 3302  
3303 3303                  switch (save_errno) {
3304 3304                  case EEXIST:
3305 3305                          /* There is a conflicting snapshot name. */
3306 3306                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3307 3307                              "conflicting snapshot '%s' from parent '%s'"),
3308 3308                              zc.zc_string, parent);
3309 3309                          return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3310 3310  
3311 3311                  default:
3312 3312                          return (zfs_standard_error(hdl, save_errno, errbuf));
3313 3313                  }
3314 3314          }
3315 3315          return (ret);
3316 3316  }
3317 3317  
3318 3318  typedef struct snapdata {
3319 3319          nvlist_t *sd_nvl;
3320 3320          const char *sd_snapname;
3321 3321  } snapdata_t;
3322 3322  
3323 3323  static int
3324 3324  zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
3325 3325  {
3326 3326          snapdata_t *sd = arg;
3327 3327          char name[ZFS_MAXNAMELEN];
3328 3328          int rv = 0;
3329 3329  
3330 3330          (void) snprintf(name, sizeof (name),
3331 3331              "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
3332 3332  
3333 3333          fnvlist_add_boolean(sd->sd_nvl, name);
3334 3334  
3335 3335          rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
3336 3336          zfs_close(zhp);
3337 3337          return (rv);
3338 3338  }
3339 3339  
3340 3340  /*
3341 3341   * Creates snapshots.  The keys in the snaps nvlist are the snapshots to be
3342 3342   * created.
3343 3343   */
3344 3344  int
3345 3345  zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
3346 3346  {
3347 3347          int ret;
3348 3348          char errbuf[1024];
3349 3349          nvpair_t *elem;
3350 3350          nvlist_t *errors;
3351 3351  
3352 3352          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3353 3353              "cannot create snapshots "));
3354 3354  
3355 3355          elem = NULL;
3356 3356          while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
3357 3357                  const char *snapname = nvpair_name(elem);
3358 3358  
3359 3359                  /* validate the target name */
3360 3360                  if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
3361 3361                      B_TRUE)) {
3362 3362                          (void) snprintf(errbuf, sizeof (errbuf),
3363 3363                              dgettext(TEXT_DOMAIN,
3364 3364                              "cannot create snapshot '%s'"), snapname);
3365 3365                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3366 3366                  }
3367 3367          }
3368 3368  
3369 3369          if (props != NULL &&
3370 3370              (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
3371 3371              props, B_FALSE, NULL, errbuf)) == NULL) {
3372 3372                  return (-1);
3373 3373          }
3374 3374  
3375 3375          ret = lzc_snapshot(snaps, props, &errors);
3376 3376  
3377 3377          if (ret != 0) {
3378 3378                  boolean_t printed = B_FALSE;
3379 3379                  for (elem = nvlist_next_nvpair(errors, NULL);
3380 3380                      elem != NULL;
3381 3381                      elem = nvlist_next_nvpair(errors, elem)) {
3382 3382                          (void) snprintf(errbuf, sizeof (errbuf),
3383 3383                              dgettext(TEXT_DOMAIN,
3384 3384                              "cannot create snapshot '%s'"), nvpair_name(elem));
3385 3385                          (void) zfs_standard_error(hdl,
3386 3386                              fnvpair_value_int32(elem), errbuf);
3387 3387                          printed = B_TRUE;
3388 3388                  }
3389 3389                  if (!printed) {
3390 3390                          switch (ret) {
3391 3391                          case EXDEV:
3392 3392                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3393 3393                                      "multiple snapshots of same "
3394 3394                                      "fs not allowed"));
3395 3395                                  (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
3396 3396  
3397 3397                                  break;
3398 3398                          default:
3399 3399                                  (void) zfs_standard_error(hdl, ret, errbuf);
3400 3400                          }
3401 3401                  }
3402 3402          }
3403 3403  
3404 3404          nvlist_free(props);
3405 3405          nvlist_free(errors);
3406 3406          return (ret);
3407 3407  }
3408 3408  
3409 3409  int
3410 3410  zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
3411 3411      nvlist_t *props)
3412 3412  {
3413 3413          int ret;
3414 3414          snapdata_t sd = { 0 };
3415 3415          char fsname[ZFS_MAXNAMELEN];
3416 3416          char *cp;
3417 3417          zfs_handle_t *zhp;
3418 3418          char errbuf[1024];
3419 3419  
3420 3420          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3421 3421              "cannot snapshot %s"), path);
3422 3422  
3423 3423          if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
3424 3424                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3425 3425  
3426 3426          (void) strlcpy(fsname, path, sizeof (fsname));
3427 3427          cp = strchr(fsname, '@');
3428 3428          *cp = '\0';
3429 3429          sd.sd_snapname = cp + 1;
3430 3430  
3431 3431          if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
3432 3432              ZFS_TYPE_VOLUME)) == NULL) {
3433 3433                  return (-1);
3434 3434          }
3435 3435  
3436 3436          verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
3437 3437          if (recursive) {
3438 3438                  (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
3439 3439          } else {
3440 3440                  fnvlist_add_boolean(sd.sd_nvl, path);
3441 3441          }
3442 3442  
3443 3443          ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
3444 3444          nvlist_free(sd.sd_nvl);
3445 3445          zfs_close(zhp);
3446 3446          return (ret);
3447 3447  }
3448 3448  
3449 3449  /*
3450 3450   * Destroy any more recent snapshots.  We invoke this callback on any dependents
3451 3451   * of the snapshot first.  If the 'cb_dependent' member is non-zero, then this
3452 3452   * is a dependent and we should just destroy it without checking the transaction
3453 3453   * group.
3454 3454   */
3455 3455  typedef struct rollback_data {
3456 3456          const char      *cb_target;             /* the snapshot */
3457 3457          uint64_t        cb_create;              /* creation time reference */
3458 3458          boolean_t       cb_error;
3459 3459          boolean_t       cb_dependent;
3460 3460          boolean_t       cb_force;
3461 3461  } rollback_data_t;
3462 3462  
3463 3463  static int
3464 3464  rollback_destroy(zfs_handle_t *zhp, void *data)
3465 3465  {
3466 3466          rollback_data_t *cbp = data;
3467 3467  
3468 3468          if (!cbp->cb_dependent) {
3469 3469                  if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 &&
3470 3470                      zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
3471 3471                      zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
3472 3472                      cbp->cb_create) {
3473 3473  
3474 3474                          cbp->cb_dependent = B_TRUE;
3475 3475                          cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
3476 3476                              rollback_destroy, cbp);
3477 3477                          cbp->cb_dependent = B_FALSE;
3478 3478  
3479 3479                          cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
3480 3480                  }
3481 3481          } else {
3482 3482                  /* We must destroy this clone; first unmount it */
3483 3483                  prop_changelist_t *clp;
3484 3484  
3485 3485                  clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
3486 3486                      cbp->cb_force ? MS_FORCE: 0);
3487 3487                  if (clp == NULL || changelist_prefix(clp) != 0) {
3488 3488                          cbp->cb_error = B_TRUE;
3489 3489                          zfs_close(zhp);
3490 3490                          return (0);
3491 3491                  }
3492 3492                  if (zfs_destroy(zhp, B_FALSE) != 0)
3493 3493                          cbp->cb_error = B_TRUE;
3494 3494                  else
3495 3495                          changelist_remove(clp, zhp->zfs_name);
3496 3496                  (void) changelist_postfix(clp);
3497 3497                  changelist_free(clp);
3498 3498          }
3499 3499  
3500 3500          zfs_close(zhp);
3501 3501          return (0);
3502 3502  }
3503 3503  
3504 3504  /*
3505 3505   * Given a dataset, rollback to a specific snapshot, discarding any
3506 3506   * data changes since then and making it the active dataset.
3507 3507   *
3508 3508   * Any snapshots more recent than the target are destroyed, along with
3509 3509   * their dependents.
3510 3510   */
3511 3511  int
3512 3512  zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
3513 3513  {
3514 3514          rollback_data_t cb = { 0 };
3515 3515          int err;
3516 3516          zfs_cmd_t zc = { 0 };
3517 3517          boolean_t restore_resv = 0;
3518 3518          uint64_t old_volsize, new_volsize;
3519 3519          zfs_prop_t resv_prop;
3520 3520  
3521 3521          assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3522 3522              zhp->zfs_type == ZFS_TYPE_VOLUME);
3523 3523  
3524 3524          /*
3525 3525           * Destroy all recent snapshots and their dependents.
3526 3526           */
3527 3527          cb.cb_force = force;
3528 3528          cb.cb_target = snap->zfs_name;
3529 3529          cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3530 3530          (void) zfs_iter_children(zhp, rollback_destroy, &cb);
3531 3531  
3532 3532          if (cb.cb_error)
3533 3533                  return (-1);
3534 3534  
3535 3535          /*
3536 3536           * Now that we have verified that the snapshot is the latest,
3537 3537           * rollback to the given snapshot.
3538 3538           */
3539 3539  
3540 3540          if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
3541 3541                  if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
3542 3542                          return (-1);
3543 3543                  old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3544 3544                  restore_resv =
3545 3545                      (old_volsize == zfs_prop_get_int(zhp, resv_prop));
3546 3546          }
3547 3547  
3548 3548          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3549 3549  
3550 3550          if (ZFS_IS_VOLUME(zhp))
3551 3551                  zc.zc_objset_type = DMU_OST_ZVOL;
3552 3552          else
3553 3553                  zc.zc_objset_type = DMU_OST_ZFS;
3554 3554  
3555 3555          /*
3556 3556           * We rely on zfs_iter_children() to verify that there are no
3557 3557           * newer snapshots for the given dataset.  Therefore, we can
3558 3558           * simply pass the name on to the ioctl() call.  There is still
3559 3559           * an unlikely race condition where the user has taken a
3560 3560           * snapshot since we verified that this was the most recent.
3561 3561           *
3562 3562           */
3563 3563          if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) {
3564 3564                  (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3565 3565                      dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
3566 3566                      zhp->zfs_name);
3567 3567                  return (err);
3568 3568          }
3569 3569  
3570 3570          /*
3571 3571           * For volumes, if the pre-rollback volsize matched the pre-
3572 3572           * rollback reservation and the volsize has changed then set
3573 3573           * the reservation property to the post-rollback volsize.
3574 3574           * Make a new handle since the rollback closed the dataset.
3575 3575           */
3576 3576          if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
3577 3577              (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
3578 3578                  if (restore_resv) {
3579 3579                          new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3580 3580                          if (old_volsize != new_volsize)
3581 3581                                  err = zfs_prop_set_int(zhp, resv_prop,
3582 3582                                      new_volsize);
3583 3583                  }
3584 3584                  zfs_close(zhp);
3585 3585          }
3586 3586          return (err);
3587 3587  }
3588 3588  
3589 3589  /*
3590 3590   * Renames the given dataset.
3591 3591   */
3592 3592  int
3593 3593  zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
3594 3594      boolean_t force_unmount)
3595 3595  {
3596 3596          int ret;
3597 3597          zfs_cmd_t zc = { 0 };
3598 3598          char *delim;
3599 3599          prop_changelist_t *cl = NULL;
3600 3600          zfs_handle_t *zhrp = NULL;
3601 3601          char *parentname = NULL;
3602 3602          char parent[ZFS_MAXNAMELEN];
3603 3603          libzfs_handle_t *hdl = zhp->zfs_hdl;
3604 3604          char errbuf[1024];
3605 3605  
3606 3606          /* if we have the same exact name, just return success */
3607 3607          if (strcmp(zhp->zfs_name, target) == 0)
3608 3608                  return (0);
3609 3609  
3610 3610          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3611 3611              "cannot rename to '%s'"), target);
3612 3612  
3613 3613          /*
3614 3614           * Make sure the target name is valid
3615 3615           */
3616 3616          if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3617 3617                  if ((strchr(target, '@') == NULL) ||
3618 3618                      *target == '@') {
3619 3619                          /*
3620 3620                           * Snapshot target name is abbreviated,
3621 3621                           * reconstruct full dataset name
3622 3622                           */
3623 3623                          (void) strlcpy(parent, zhp->zfs_name,
3624 3624                              sizeof (parent));
3625 3625                          delim = strchr(parent, '@');
3626 3626                          if (strchr(target, '@') == NULL)
3627 3627                                  *(++delim) = '\0';
3628 3628                          else
3629 3629                                  *delim = '\0';
3630 3630                          (void) strlcat(parent, target, sizeof (parent));
3631 3631                          target = parent;
3632 3632                  } else {
3633 3633                          /*
3634 3634                           * Make sure we're renaming within the same dataset.
3635 3635                           */
3636 3636                          delim = strchr(target, '@');
3637 3637                          if (strncmp(zhp->zfs_name, target, delim - target)
3638 3638                              != 0 || zhp->zfs_name[delim - target] != '@') {
3639 3639                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3640 3640                                      "snapshots must be part of same "
3641 3641                                      "dataset"));
3642 3642                                  return (zfs_error(hdl, EZFS_CROSSTARGET,
3643 3643                                      errbuf));
3644 3644                          }
3645 3645                  }
3646 3646                  if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
3647 3647                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3648 3648          } else {
3649 3649                  if (recursive) {
3650 3650                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3651 3651                              "recursive rename must be a snapshot"));
3652 3652                          return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3653 3653                  }
3654 3654  
3655 3655                  if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
3656 3656                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3657 3657  
3658 3658                  /* validate parents */
3659 3659                  if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
3660 3660                          return (-1);
3661 3661  
3662 3662                  /* make sure we're in the same pool */
3663 3663                  verify((delim = strchr(target, '/')) != NULL);
3664 3664                  if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
3665 3665                      zhp->zfs_name[delim - target] != '/') {
3666 3666                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3667 3667                              "datasets must be within same pool"));
3668 3668                          return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
3669 3669                  }
3670 3670  
3671 3671                  /* new name cannot be a child of the current dataset name */
3672 3672                  if (is_descendant(zhp->zfs_name, target)) {
3673 3673                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3674 3674                              "New dataset name cannot be a descendant of "
3675 3675                              "current dataset name"));
3676 3676                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3677 3677                  }
3678 3678          }
3679 3679  
3680 3680          (void) snprintf(errbuf, sizeof (errbuf),
3681 3681              dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
3682 3682  
3683 3683          if (getzoneid() == GLOBAL_ZONEID &&
3684 3684              zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
3685 3685                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3686 3686                      "dataset is used in a non-global zone"));
3687 3687                  return (zfs_error(hdl, EZFS_ZONED, errbuf));
3688 3688          }
3689 3689  
3690 3690          if (recursive) {
3691 3691  
3692 3692                  parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
3693 3693                  if (parentname == NULL) {
3694 3694                          ret = -1;
3695 3695                          goto error;
3696 3696                  }
3697 3697                  delim = strchr(parentname, '@');
3698 3698                  *delim = '\0';
3699 3699                  zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
3700 3700                  if (zhrp == NULL) {
3701 3701                          ret = -1;
3702 3702                          goto error;
3703 3703                  }
3704 3704  
3705 3705          } else {
3706 3706                  if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
3707 3707                      force_unmount ? MS_FORCE : 0)) == NULL)
3708 3708                          return (-1);
3709 3709  
3710 3710                  if (changelist_haszonedchild(cl)) {
3711 3711                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3712 3712                              "child dataset with inherited mountpoint is used "
3713 3713                              "in a non-global zone"));
3714 3714                          (void) zfs_error(hdl, EZFS_ZONED, errbuf);
3715 3715                          goto error;
3716 3716                  }
3717 3717  
3718 3718                  if ((ret = changelist_prefix(cl)) != 0)
3719 3719                          goto error;
3720 3720          }
3721 3721  
3722 3722          if (ZFS_IS_VOLUME(zhp))
3723 3723                  zc.zc_objset_type = DMU_OST_ZVOL;
3724 3724          else
3725 3725                  zc.zc_objset_type = DMU_OST_ZFS;
3726 3726  
3727 3727          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3728 3728          (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
3729 3729  
3730 3730          zc.zc_cookie = recursive;
3731 3731  
3732 3732          if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
3733 3733                  /*
3734 3734                   * if it was recursive, the one that actually failed will
3735 3735                   * be in zc.zc_name
3736 3736                   */
3737 3737                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3738 3738                      "cannot rename '%s'"), zc.zc_name);
3739 3739  
3740 3740                  if (recursive && errno == EEXIST) {
3741 3741                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3742 3742                              "a child dataset already has a snapshot "
3743 3743                              "with the new name"));
3744 3744                          (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
3745 3745                  } else {
3746 3746                          (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
3747 3747                  }
3748 3748  
3749 3749                  /*
3750 3750                   * On failure, we still want to remount any filesystems that
3751 3751                   * were previously mounted, so we don't alter the system state.
3752 3752                   */
3753 3753                  if (!recursive)
3754 3754                          (void) changelist_postfix(cl);
3755 3755          } else {
3756 3756                  if (!recursive) {
3757 3757                          changelist_rename(cl, zfs_get_name(zhp), target);
3758 3758                          ret = changelist_postfix(cl);
3759 3759                  }
3760 3760          }
3761 3761  
3762 3762  error:
3763 3763          if (parentname) {
3764 3764                  free(parentname);
3765 3765          }
3766 3766          if (zhrp) {
3767 3767                  zfs_close(zhrp);
3768 3768          }
3769 3769          if (cl) {
3770 3770                  changelist_free(cl);
3771 3771          }
3772 3772          return (ret);
3773 3773  }
3774 3774  
3775 3775  nvlist_t *
3776 3776  zfs_get_user_props(zfs_handle_t *zhp)
3777 3777  {
3778 3778          return (zhp->zfs_user_props);
3779 3779  }
3780 3780  
3781 3781  nvlist_t *
3782 3782  zfs_get_recvd_props(zfs_handle_t *zhp)
3783 3783  {
3784 3784          if (zhp->zfs_recvd_props == NULL)
3785 3785                  if (get_recvd_props_ioctl(zhp) != 0)
3786 3786                          return (NULL);
3787 3787          return (zhp->zfs_recvd_props);
3788 3788  }
3789 3789  
3790 3790  /*
3791 3791   * This function is used by 'zfs list' to determine the exact set of columns to
3792 3792   * display, and their maximum widths.  This does two main things:
3793 3793   *
3794 3794   *      - If this is a list of all properties, then expand the list to include
3795 3795   *        all native properties, and set a flag so that for each dataset we look
3796 3796   *        for new unique user properties and add them to the list.
3797 3797   *
3798 3798   *      - For non fixed-width properties, keep track of the maximum width seen
3799 3799   *        so that we can size the column appropriately. If the user has
3800 3800   *        requested received property values, we also need to compute the width
3801 3801   *        of the RECEIVED column.
3802 3802   */
3803 3803  int
3804 3804  zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received)
3805 3805  {
3806 3806          libzfs_handle_t *hdl = zhp->zfs_hdl;
3807 3807          zprop_list_t *entry;
3808 3808          zprop_list_t **last, **start;
3809 3809          nvlist_t *userprops, *propval;
3810 3810          nvpair_t *elem;
3811 3811          char *strval;
3812 3812          char buf[ZFS_MAXPROPLEN];
3813 3813  
3814 3814          if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
3815 3815                  return (-1);
3816 3816  
3817 3817          userprops = zfs_get_user_props(zhp);
3818 3818  
3819 3819          entry = *plp;
3820 3820          if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
3821 3821                  /*
3822 3822                   * Go through and add any user properties as necessary.  We
3823 3823                   * start by incrementing our list pointer to the first
3824 3824                   * non-native property.
3825 3825                   */
3826 3826                  start = plp;
3827 3827                  while (*start != NULL) {
3828 3828                          if ((*start)->pl_prop == ZPROP_INVAL)
3829 3829                                  break;
3830 3830                          start = &(*start)->pl_next;
3831 3831                  }
3832 3832  
3833 3833                  elem = NULL;
3834 3834                  while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
3835 3835                          /*
3836 3836                           * See if we've already found this property in our list.
3837 3837                           */
3838 3838                          for (last = start; *last != NULL;
3839 3839                              last = &(*last)->pl_next) {
3840 3840                                  if (strcmp((*last)->pl_user_prop,
3841 3841                                      nvpair_name(elem)) == 0)
3842 3842                                          break;
3843 3843                          }
3844 3844  
3845 3845                          if (*last == NULL) {
3846 3846                                  if ((entry = zfs_alloc(hdl,
3847 3847                                      sizeof (zprop_list_t))) == NULL ||
3848 3848                                      ((entry->pl_user_prop = zfs_strdup(hdl,
3849 3849                                      nvpair_name(elem)))) == NULL) {
3850 3850                                          free(entry);
3851 3851                                          return (-1);
3852 3852                                  }
3853 3853  
3854 3854                                  entry->pl_prop = ZPROP_INVAL;
3855 3855                                  entry->pl_width = strlen(nvpair_name(elem));
3856 3856                                  entry->pl_all = B_TRUE;
3857 3857                                  *last = entry;
3858 3858                          }
3859 3859                  }
3860 3860          }
3861 3861  
3862 3862          /*
3863 3863           * Now go through and check the width of any non-fixed columns
3864 3864           */
3865 3865          for (entry = *plp; entry != NULL; entry = entry->pl_next) {
3866 3866                  if (entry->pl_fixed)
3867 3867                          continue;
3868 3868  
3869 3869                  if (entry->pl_prop != ZPROP_INVAL) {
3870 3870                          if (zfs_prop_get(zhp, entry->pl_prop,
3871 3871                              buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) {
3872 3872                                  if (strlen(buf) > entry->pl_width)
3873 3873                                          entry->pl_width = strlen(buf);
3874 3874                          }
3875 3875                          if (received && zfs_prop_get_recvd(zhp,
3876 3876                              zfs_prop_to_name(entry->pl_prop),
3877 3877                              buf, sizeof (buf), B_FALSE) == 0)
3878 3878                                  if (strlen(buf) > entry->pl_recvd_width)
3879 3879                                          entry->pl_recvd_width = strlen(buf);
3880 3880                  } else {
3881 3881                          if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
3882 3882                              &propval) == 0) {
3883 3883                                  verify(nvlist_lookup_string(propval,
3884 3884                                      ZPROP_VALUE, &strval) == 0);
3885 3885                                  if (strlen(strval) > entry->pl_width)
3886 3886                                          entry->pl_width = strlen(strval);
3887 3887                          }
3888 3888                          if (received && zfs_prop_get_recvd(zhp,
3889 3889                              entry->pl_user_prop,
3890 3890                              buf, sizeof (buf), B_FALSE) == 0)
3891 3891                                  if (strlen(buf) > entry->pl_recvd_width)
3892 3892                                          entry->pl_recvd_width = strlen(buf);
3893 3893                  }
3894 3894          }
3895 3895  
3896 3896          return (0);
3897 3897  }
3898 3898  
3899 3899  int
3900 3900  zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
3901 3901      char *resource, void *export, void *sharetab,
3902 3902      int sharemax, zfs_share_op_t operation)
3903 3903  {
3904 3904          zfs_cmd_t zc = { 0 };
3905 3905          int error;
3906 3906  
3907 3907          (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3908 3908          (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
3909 3909          if (resource)
3910 3910                  (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
3911 3911          zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
3912 3912          zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
3913 3913          zc.zc_share.z_sharetype = operation;
3914 3914          zc.zc_share.z_sharemax = sharemax;
3915 3915          error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
3916 3916          return (error);
3917 3917  }
3918 3918  
3919 3919  void
3920 3920  zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
3921 3921  {
3922 3922          nvpair_t *curr;
3923 3923  
3924 3924          /*
3925 3925           * Keep a reference to the props-table against which we prune the
3926 3926           * properties.
3927 3927           */
3928 3928          zhp->zfs_props_table = props;
3929 3929  
3930 3930          curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
3931 3931  
3932 3932          while (curr) {
3933 3933                  zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
3934 3934                  nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
3935 3935  
3936 3936                  /*
3937 3937                   * User properties will result in ZPROP_INVAL, and since we
3938 3938                   * only know how to prune standard ZFS properties, we always
3939 3939                   * leave these in the list.  This can also happen if we
3940 3940                   * encounter an unknown DSL property (when running older
3941 3941                   * software, for example).
3942 3942                   */
3943 3943                  if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
3944 3944                          (void) nvlist_remove(zhp->zfs_props,
3945 3945                              nvpair_name(curr), nvpair_type(curr));
3946 3946                  curr = next;
3947 3947          }
3948 3948  }
3949 3949  
3950 3950  static int
3951 3951  zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
3952 3952      zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
3953 3953  {
3954 3954          zfs_cmd_t zc = { 0 };
3955 3955          nvlist_t *nvlist = NULL;
3956 3956          int error;
3957 3957  
3958 3958          (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3959 3959          (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
3960 3960          zc.zc_cookie = (uint64_t)cmd;
3961 3961  
3962 3962          if (cmd == ZFS_SMB_ACL_RENAME) {
3963 3963                  if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
3964 3964                          (void) no_memory(hdl);
3965 3965                          return (NULL);
3966 3966                  }
3967 3967          }
3968 3968  
3969 3969          switch (cmd) {
3970 3970          case ZFS_SMB_ACL_ADD:
3971 3971          case ZFS_SMB_ACL_REMOVE:
3972 3972                  (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
3973 3973                  break;
3974 3974          case ZFS_SMB_ACL_RENAME:
3975 3975                  if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
3976 3976                      resource1) != 0) {
3977 3977                                  (void) no_memory(hdl);
3978 3978                                  return (-1);
3979 3979                  }
3980 3980                  if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
3981 3981                      resource2) != 0) {
3982 3982                                  (void) no_memory(hdl);
3983 3983                                  return (-1);
3984 3984                  }
3985 3985                  if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
3986 3986                          nvlist_free(nvlist);
3987 3987                          return (-1);
3988 3988                  }
3989 3989                  break;
3990 3990          case ZFS_SMB_ACL_PURGE:
3991 3991                  break;
3992 3992          default:
3993 3993                  return (-1);
3994 3994          }
3995 3995          error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
3996 3996          if (nvlist)
3997 3997                  nvlist_free(nvlist);
3998 3998          return (error);
3999 3999  }
4000 4000  
4001 4001  int
4002 4002  zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
4003 4003      char *path, char *resource)
4004 4004  {
4005 4005          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
4006 4006              resource, NULL));
4007 4007  }
4008 4008  
4009 4009  int
4010 4010  zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
4011 4011      char *path, char *resource)
4012 4012  {
4013 4013          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
4014 4014              resource, NULL));
4015 4015  }
4016 4016  
4017 4017  int
4018 4018  zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
4019 4019  {
4020 4020          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
4021 4021              NULL, NULL));
4022 4022  }
4023 4023  
4024 4024  int
4025 4025  zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
4026 4026      char *oldname, char *newname)
4027 4027  {
4028 4028          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
4029 4029              oldname, newname));
4030 4030  }
4031 4031  
4032 4032  int
4033 4033  zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
4034 4034      zfs_userspace_cb_t func, void *arg)
4035 4035  {
4036 4036          zfs_cmd_t zc = { 0 };
4037 4037          zfs_useracct_t buf[100];
4038 4038          libzfs_handle_t *hdl = zhp->zfs_hdl;
4039 4039          int ret;
4040 4040  
4041 4041          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4042 4042  
4043 4043          zc.zc_objset_type = type;
4044 4044          zc.zc_nvlist_dst = (uintptr_t)buf;
4045 4045  
4046 4046          for (;;) {
4047 4047                  zfs_useracct_t *zua = buf;
4048 4048  
4049 4049                  zc.zc_nvlist_dst_size = sizeof (buf);
4050 4050                  if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
4051 4051                          char errbuf[1024];
4052 4052  
4053 4053                          (void) snprintf(errbuf, sizeof (errbuf),
4054 4054                              dgettext(TEXT_DOMAIN,
4055 4055                              "cannot get used/quota for %s"), zc.zc_name);
4056 4056                          return (zfs_standard_error_fmt(hdl, errno, errbuf));
4057 4057                  }
4058 4058                  if (zc.zc_nvlist_dst_size == 0)
4059 4059                          break;
4060 4060  
4061 4061                  while (zc.zc_nvlist_dst_size > 0) {
4062 4062                          if ((ret = func(arg, zua->zu_domain, zua->zu_rid,
4063 4063                              zua->zu_space)) != 0)
4064 4064                                  return (ret);
4065 4065                          zua++;
4066 4066                          zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4067 4067                  }
4068 4068          }
4069 4069  
4070 4070          return (0);
4071 4071  }
4072 4072  
4073 4073  struct holdarg {
  
    | 
      ↓ open down ↓ | 
    4073 lines elided | 
    
      ↑ open up ↑ | 
  
4074 4074          nvlist_t *nvl;
4075 4075          const char *snapname;
4076 4076          const char *tag;
4077 4077          boolean_t recursive;
4078 4078  };
4079 4079  
4080 4080  static int
4081 4081  zfs_hold_one(zfs_handle_t *zhp, void *arg)
4082 4082  {
4083 4083          struct holdarg *ha = arg;
4084      -        zfs_handle_t *szhp;
4085 4084          char name[ZFS_MAXNAMELEN];
4086 4085          int rv = 0;
4087 4086  
4088 4087          (void) snprintf(name, sizeof (name),
4089 4088              "%s@%s", zhp->zfs_name, ha->snapname);
4090 4089  
4091      -        szhp = make_dataset_handle(zhp->zfs_hdl, name);
4092      -        if (szhp) {
     4090 +        if (lzc_exists(name))
4093 4091                  fnvlist_add_string(ha->nvl, name, ha->tag);
4094      -                zfs_close(szhp);
4095      -        }
4096 4092  
4097 4093          if (ha->recursive)
4098 4094                  rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4099 4095          zfs_close(zhp);
4100 4096          return (rv);
4101 4097  }
4102 4098  
4103 4099  int
4104 4100  zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4105      -    boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
     4101 +    boolean_t recursive, int cleanup_fd)
4106 4102  {
4107 4103          int ret;
4108 4104          struct holdarg ha;
4109      -        nvlist_t *errors;
4110      -        libzfs_handle_t *hdl = zhp->zfs_hdl;
4111      -        char errbuf[1024];
4112      -        nvpair_t *elem;
4113 4105  
4114 4106          ha.nvl = fnvlist_alloc();
4115 4107          ha.snapname = snapname;
4116 4108          ha.tag = tag;
4117 4109          ha.recursive = recursive;
4118 4110          (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4119      -        ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
     4111 +        ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4120 4112          fnvlist_free(ha.nvl);
4121 4113  
4122      -        if (ret == 0)
     4114 +        return (ret);
     4115 +}
     4116 +
     4117 +int
     4118 +zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
     4119 +{
     4120 +        int ret;
     4121 +        nvlist_t *errors;
     4122 +        libzfs_handle_t *hdl = zhp->zfs_hdl;
     4123 +        char errbuf[1024];
     4124 +        nvpair_t *elem;
     4125 + 
     4126 +        errors = NULL;
     4127 +        ret = lzc_hold(holds, cleanup_fd, &errors);
     4128 + 
     4129 +        if (ret == 0) {
     4130 +                /* There may be errors even in the success case. */
     4131 +                fnvlist_free(errors);
4123 4132                  return (0);
     4133 +        }
4124 4134  
4125 4135          if (nvlist_next_nvpair(errors, NULL) == NULL) {
4126 4136                  /* no hold-specific errors */
4127 4137                  (void) snprintf(errbuf, sizeof (errbuf),
4128 4138                      dgettext(TEXT_DOMAIN, "cannot hold"));
4129 4139                  switch (ret) {
4130 4140                  case ENOTSUP:
4131 4141                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4132 4142                              "pool must be upgraded"));
4133 4143                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4134 4144                          break;
4135 4145                  case EINVAL:
4136 4146                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4137 4147                          break;
4138 4148                  default:
4139 4149                          (void) zfs_standard_error(hdl, ret, errbuf);
4140 4150                  }
4141 4151          }
4142 4152  
4143 4153          for (elem = nvlist_next_nvpair(errors, NULL);
4144 4154              elem != NULL;
4145 4155              elem = nvlist_next_nvpair(errors, elem)) {
4146 4156                  (void) snprintf(errbuf, sizeof (errbuf),
4147 4157                      dgettext(TEXT_DOMAIN,
4148 4158                      "cannot hold snapshot '%s'"), nvpair_name(elem));
4149 4159                  switch (fnvpair_value_int32(elem)) {
4150 4160                  case E2BIG:
4151 4161                          /*
4152 4162                           * Temporary tags wind up having the ds object id
4153 4163                           * prepended. So even if we passed the length check
4154 4164                           * above, it's still possible for the tag to wind
  
    | 
      ↓ open down ↓ | 
    21 lines elided | 
    
      ↑ open up ↑ | 
  
4155 4165                           * up being slightly too long.
4156 4166                           */
4157 4167                          (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4158 4168                          break;
4159 4169                  case EINVAL:
4160 4170                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4161 4171                          break;
4162 4172                  case EEXIST:
4163 4173                          (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4164 4174                          break;
4165      -                case ENOENT:
4166      -                        if (enoent_ok)
4167      -                                return (ENOENT);
4168      -                        /* FALLTHROUGH */
4169 4175                  default:
4170 4176                          (void) zfs_standard_error(hdl,
4171 4177                              fnvpair_value_int32(elem), errbuf);
4172 4178                  }
4173 4179          }
4174 4180  
4175 4181          fnvlist_free(errors);
4176 4182          return (ret);
4177 4183  }
4178 4184  
4179      -struct releasearg {
4180      -        nvlist_t *nvl;
4181      -        const char *snapname;
4182      -        const char *tag;
4183      -        boolean_t recursive;
4184      -};
4185      -
4186 4185  static int
4187 4186  zfs_release_one(zfs_handle_t *zhp, void *arg)
4188 4187  {
4189 4188          struct holdarg *ha = arg;
4190      -        zfs_handle_t *szhp;
4191 4189          char name[ZFS_MAXNAMELEN];
4192 4190          int rv = 0;
4193 4191  
4194 4192          (void) snprintf(name, sizeof (name),
4195 4193              "%s@%s", zhp->zfs_name, ha->snapname);
4196 4194  
4197      -        szhp = make_dataset_handle(zhp->zfs_hdl, name);
4198      -        if (szhp) {
     4195 +        if (lzc_exists(name)) {
4199 4196                  nvlist_t *holds = fnvlist_alloc();
4200 4197                  fnvlist_add_boolean(holds, ha->tag);
4201 4198                  fnvlist_add_nvlist(ha->nvl, name, holds);
4202      -                zfs_close(szhp);
     4199 +                fnvlist_free(holds);
4203 4200          }
4204 4201  
4205 4202          if (ha->recursive)
4206 4203                  rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4207 4204          zfs_close(zhp);
4208 4205          return (rv);
4209 4206  }
4210 4207  
4211 4208  int
4212 4209  zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4213 4210      boolean_t recursive)
4214 4211  {
4215 4212          int ret;
  
    | 
      ↓ open down ↓ | 
    3 lines elided | 
    
      ↑ open up ↑ | 
  
4216 4213          struct holdarg ha;
4217 4214          nvlist_t *errors;
4218 4215          nvpair_t *elem;
4219 4216          libzfs_handle_t *hdl = zhp->zfs_hdl;
4220 4217  
4221 4218          ha.nvl = fnvlist_alloc();
4222 4219          ha.snapname = snapname;
4223 4220          ha.tag = tag;
4224 4221          ha.recursive = recursive;
4225 4222          (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
     4223 +        errors = NULL;
4226 4224          ret = lzc_release(ha.nvl, &errors);
4227 4225          fnvlist_free(ha.nvl);
4228 4226  
4229      -        if (ret == 0)
     4227 +        if (ret == 0) {
     4228 +                /* There may be errors even in the success case. */
     4229 +                fnvlist_free(errors);
4230 4230                  return (0);
     4231 +        }
4231 4232  
4232 4233          if (nvlist_next_nvpair(errors, NULL) == NULL) {
4233 4234                  /* no hold-specific errors */
4234 4235                  char errbuf[1024];
4235 4236  
4236 4237                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4237 4238                      "cannot release"));
4238 4239                  switch (errno) {
4239 4240                  case ENOTSUP:
4240 4241                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4241 4242                              "pool must be upgraded"));
4242 4243                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4243 4244                          break;
4244 4245                  default:
4245 4246                          (void) zfs_standard_error_fmt(hdl, errno, errbuf);
4246 4247                  }
4247 4248          }
4248 4249  
4249 4250          for (elem = nvlist_next_nvpair(errors, NULL);
4250 4251              elem != NULL;
4251 4252              elem = nvlist_next_nvpair(errors, elem)) {
4252 4253                  char errbuf[1024];
4253 4254  
4254 4255                  (void) snprintf(errbuf, sizeof (errbuf),
4255 4256                      dgettext(TEXT_DOMAIN,
4256 4257                      "cannot release hold from snapshot '%s'"),
4257 4258                      nvpair_name(elem));
4258 4259                  switch (fnvpair_value_int32(elem)) {
4259 4260                  case ESRCH:
4260 4261                          (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
4261 4262                          break;
4262 4263                  case EINVAL:
4263 4264                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4264 4265                          break;
4265 4266                  default:
4266 4267                          (void) zfs_standard_error_fmt(hdl,
4267 4268                              fnvpair_value_int32(elem), errbuf);
4268 4269                  }
4269 4270          }
4270 4271  
4271 4272          fnvlist_free(errors);
4272 4273          return (ret);
4273 4274  }
4274 4275  
4275 4276  int
4276 4277  zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
4277 4278  {
4278 4279          zfs_cmd_t zc = { 0 };
4279 4280          libzfs_handle_t *hdl = zhp->zfs_hdl;
4280 4281          int nvsz = 2048;
4281 4282          void *nvbuf;
4282 4283          int err = 0;
4283 4284          char errbuf[1024];
4284 4285  
4285 4286          assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4286 4287              zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4287 4288  
4288 4289  tryagain:
4289 4290  
4290 4291          nvbuf = malloc(nvsz);
4291 4292          if (nvbuf == NULL) {
4292 4293                  err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
4293 4294                  goto out;
4294 4295          }
4295 4296  
4296 4297          zc.zc_nvlist_dst_size = nvsz;
4297 4298          zc.zc_nvlist_dst = (uintptr_t)nvbuf;
4298 4299  
4299 4300          (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN);
4300 4301  
4301 4302          if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
4302 4303                  (void) snprintf(errbuf, sizeof (errbuf),
4303 4304                      dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
4304 4305                      zc.zc_name);
4305 4306                  switch (errno) {
4306 4307                  case ENOMEM:
4307 4308                          free(nvbuf);
4308 4309                          nvsz = zc.zc_nvlist_dst_size;
4309 4310                          goto tryagain;
4310 4311  
4311 4312                  case ENOTSUP:
4312 4313                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4313 4314                              "pool must be upgraded"));
4314 4315                          err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4315 4316                          break;
4316 4317                  case EINVAL:
4317 4318                          err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4318 4319                          break;
4319 4320                  case ENOENT:
4320 4321                          err = zfs_error(hdl, EZFS_NOENT, errbuf);
4321 4322                          break;
4322 4323                  default:
4323 4324                          err = zfs_standard_error_fmt(hdl, errno, errbuf);
4324 4325                          break;
4325 4326                  }
4326 4327          } else {
4327 4328                  /* success */
4328 4329                  int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
4329 4330                  if (rc) {
4330 4331                          (void) snprintf(errbuf, sizeof (errbuf), dgettext(
4331 4332                              TEXT_DOMAIN, "cannot get permissions on '%s'"),
4332 4333                              zc.zc_name);
4333 4334                          err = zfs_standard_error_fmt(hdl, rc, errbuf);
4334 4335                  }
4335 4336          }
4336 4337  
4337 4338          free(nvbuf);
4338 4339  out:
4339 4340          return (err);
4340 4341  }
4341 4342  
4342 4343  int
4343 4344  zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
4344 4345  {
4345 4346          zfs_cmd_t zc = { 0 };
4346 4347          libzfs_handle_t *hdl = zhp->zfs_hdl;
4347 4348          char *nvbuf;
4348 4349          char errbuf[1024];
4349 4350          size_t nvsz;
4350 4351          int err;
4351 4352  
4352 4353          assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4353 4354              zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4354 4355  
4355 4356          err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
4356 4357          assert(err == 0);
4357 4358  
4358 4359          nvbuf = malloc(nvsz);
4359 4360  
4360 4361          err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
4361 4362          assert(err == 0);
4362 4363  
4363 4364          zc.zc_nvlist_src_size = nvsz;
4364 4365          zc.zc_nvlist_src = (uintptr_t)nvbuf;
4365 4366          zc.zc_perm_action = un;
4366 4367  
4367 4368          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4368 4369  
4369 4370          if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
4370 4371                  (void) snprintf(errbuf, sizeof (errbuf),
4371 4372                      dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
4372 4373                      zc.zc_name);
4373 4374                  switch (errno) {
4374 4375                  case ENOTSUP:
4375 4376                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4376 4377                              "pool must be upgraded"));
4377 4378                          err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4378 4379                          break;
4379 4380                  case EINVAL:
4380 4381                          err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4381 4382                          break;
4382 4383                  case ENOENT:
4383 4384                          err = zfs_error(hdl, EZFS_NOENT, errbuf);
4384 4385                          break;
4385 4386                  default:
4386 4387                          err = zfs_standard_error_fmt(hdl, errno, errbuf);
4387 4388                          break;
4388 4389                  }
4389 4390          }
4390 4391  
4391 4392          free(nvbuf);
4392 4393  
4393 4394          return (err);
4394 4395  }
4395 4396  
4396 4397  int
4397 4398  zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
4398 4399  {
4399 4400          int err;
4400 4401          char errbuf[1024];
4401 4402  
4402 4403          err = lzc_get_holds(zhp->zfs_name, nvl);
4403 4404  
4404 4405          if (err != 0) {
4405 4406                  libzfs_handle_t *hdl = zhp->zfs_hdl;
4406 4407  
4407 4408                  (void) snprintf(errbuf, sizeof (errbuf),
4408 4409                      dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
4409 4410                      zhp->zfs_name);
4410 4411                  switch (err) {
4411 4412                  case ENOTSUP:
4412 4413                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4413 4414                              "pool must be upgraded"));
4414 4415                          err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4415 4416                          break;
4416 4417                  case EINVAL:
4417 4418                          err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4418 4419                          break;
4419 4420                  case ENOENT:
4420 4421                          err = zfs_error(hdl, EZFS_NOENT, errbuf);
4421 4422                          break;
4422 4423                  default:
4423 4424                          err = zfs_standard_error_fmt(hdl, errno, errbuf);
4424 4425                          break;
4425 4426                  }
4426 4427          }
4427 4428  
4428 4429          return (err);
4429 4430  }
4430 4431  
4431 4432  uint64_t
4432 4433  zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
4433 4434  {
4434 4435          uint64_t numdb;
4435 4436          uint64_t nblocks, volblocksize;
4436 4437          int ncopies;
4437 4438          char *strval;
4438 4439  
4439 4440          if (nvlist_lookup_string(props,
4440 4441              zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
4441 4442                  ncopies = atoi(strval);
4442 4443          else
4443 4444                  ncopies = 1;
4444 4445          if (nvlist_lookup_uint64(props,
4445 4446              zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
4446 4447              &volblocksize) != 0)
4447 4448                  volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
4448 4449          nblocks = volsize/volblocksize;
4449 4450          /* start with metadnode L0-L6 */
4450 4451          numdb = 7;
4451 4452          /* calculate number of indirects */
4452 4453          while (nblocks > 1) {
4453 4454                  nblocks += DNODES_PER_LEVEL - 1;
4454 4455                  nblocks /= DNODES_PER_LEVEL;
4455 4456                  numdb += nblocks;
4456 4457          }
4457 4458          numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
4458 4459          volsize *= ncopies;
4459 4460          /*
4460 4461           * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
4461 4462           * compressed, but in practice they compress down to about
4462 4463           * 1100 bytes
4463 4464           */
4464 4465          numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
4465 4466          volsize += numdb;
4466 4467          return (volsize);
4467 4468  }
  
    | 
      ↓ open down ↓ | 
    227 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX