Print this page
    
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
    
      
        | 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
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  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      - * Copyright 2019 Joyent, Inc.
       24 + */
       25 +
       26 +/*
       27 + * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  25   28   * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  26   29   * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
  27   30   * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
  28   31   * Copyright (c) 2013 Martin Matuska. All rights reserved.
  29   32   * Copyright (c) 2013 Steven Hartland. All rights reserved.
  30   33   * Copyright (c) 2014 Integros [integros.com]
  31      - * Copyright 2017 Nexenta Systems, Inc.
       34 + * Copyright 2018 Nexenta Systems, Inc.
  32   35   * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  33   36   * Copyright 2017-2018 RackTop Systems.
  34   37   */
  35   38  
  36   39  #include <ctype.h>
  37   40  #include <errno.h>
  38   41  #include <libintl.h>
  39   42  #include <math.h>
  40   43  #include <stdio.h>
  41   44  #include <stdlib.h>
  42   45  #include <strings.h>
  43   46  #include <unistd.h>
  44   47  #include <stddef.h>
  45   48  #include <zone.h>
  46   49  #include <fcntl.h>
  47   50  #include <sys/mntent.h>
  48   51  #include <sys/mount.h>
  49   52  #include <priv.h>
  50   53  #include <pwd.h>
  51   54  #include <grp.h>
  52   55  #include <stddef.h>
  53   56  #include <ucred.h>
  54   57  #include <idmap.h>
  55   58  #include <aclutils.h>
  56   59  #include <directory.h>
  57   60  #include <time.h>
  58   61  
  59   62  #include <sys/dnode.h>
  60   63  #include <sys/spa.h>
  61   64  #include <sys/zap.h>
  62   65  #include <sys/dsl_crypt.h>
  63   66  #include <libzfs.h>
  64   67  
  65   68  #include "zfs_namecheck.h"
  66   69  #include "zfs_prop.h"
  67   70  #include "libzfs_impl.h"
  68   71  #include "zfs_deleg.h"
  69   72  
  70   73  static int userquota_propname_decode(const char *propname, boolean_t zoned,
  71   74      zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
  72   75  
  73   76  /*
  74   77   * Given a single type (not a mask of types), return the type in a human
  75   78   * readable form.
  76   79   */
  77   80  const char *
  78   81  zfs_type_to_name(zfs_type_t type)
  79   82  {
  80   83          switch (type) {
  81   84          case ZFS_TYPE_FILESYSTEM:
  82   85                  return (dgettext(TEXT_DOMAIN, "filesystem"));
  83   86          case ZFS_TYPE_SNAPSHOT:
  84   87                  return (dgettext(TEXT_DOMAIN, "snapshot"));
  85   88          case ZFS_TYPE_VOLUME:
  86   89                  return (dgettext(TEXT_DOMAIN, "volume"));
  87   90          case ZFS_TYPE_POOL:
  88   91                  return (dgettext(TEXT_DOMAIN, "pool"));
  89   92          case ZFS_TYPE_BOOKMARK:
  90   93                  return (dgettext(TEXT_DOMAIN, "bookmark"));
  91   94          default:
  92   95                  assert(!"unhandled zfs_type_t");
  93   96          }
  94   97  
  95   98          return (NULL);
  96   99  }
  97  100  
  98  101  /*
  99  102   * Validate a ZFS path.  This is used even before trying to open the dataset, to
 100  103   * provide a more meaningful error message.  We call zfs_error_aux() to
 101  104   * explain exactly why the name was not valid.
 102  105   */
 103  106  int
 104  107  zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
 105  108      boolean_t modifying)
 106  109  {
 107  110          namecheck_err_t why;
 108  111          char what;
 109  112  
 110  113          if (entity_namecheck(path, &why, &what) != 0) {
 111  114                  if (hdl != NULL) {
 112  115                          switch (why) {
 113  116                          case NAME_ERR_TOOLONG:
 114  117                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 115  118                                      "name is too long"));
 116  119                                  break;
 117  120  
 118  121                          case NAME_ERR_LEADING_SLASH:
 119  122                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 120  123                                      "leading slash in name"));
 121  124                                  break;
 122  125  
 123  126                          case NAME_ERR_EMPTY_COMPONENT:
 124  127                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 125  128                                      "empty component in name"));
 126  129                                  break;
 127  130  
 128  131                          case NAME_ERR_TRAILING_SLASH:
 129  132                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 130  133                                      "trailing slash in name"));
 131  134                                  break;
 132  135  
 133  136                          case NAME_ERR_INVALCHAR:
 134  137                                  zfs_error_aux(hdl,
 135  138                                      dgettext(TEXT_DOMAIN, "invalid character "
 136  139                                      "'%c' in name"), what);
 137  140                                  break;
 138  141  
 139  142                          case NAME_ERR_MULTIPLE_DELIMITERS:
 140  143                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 141  144                                      "multiple '@' and/or '#' delimiters in "
 142  145                                      "name"));
 143  146                                  break;
 144  147  
 145  148                          case NAME_ERR_NOLETTER:
 146  149                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 147  150                                      "pool doesn't begin with a letter"));
 148  151                                  break;
 149  152  
 150  153                          case NAME_ERR_RESERVED:
 151  154                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 152  155                                      "name is reserved"));
 153  156                                  break;
 154  157  
 155  158                          case NAME_ERR_DISKLIKE:
 156  159                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 157  160                                      "reserved disk name"));
 158  161                                  break;
 159  162  
 160  163                          default:
 161  164                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 162  165                                      "(%d) not defined"), why);
 163  166                                  break;
 164  167                          }
 165  168                  }
 166  169  
 167  170                  return (0);
 168  171          }
 169  172  
 170  173          if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
 171  174                  if (hdl != NULL)
 172  175                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 173  176                              "snapshot delimiter '@' is not expected here"));
 174  177                  return (0);
 175  178          }
 176  179  
 177  180          if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
 178  181                  if (hdl != NULL)
 179  182                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 180  183                              "missing '@' delimiter in snapshot name"));
 181  184                  return (0);
 182  185          }
 183  186  
 184  187          if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) {
 185  188                  if (hdl != NULL)
 186  189                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 187  190                              "bookmark delimiter '#' is not expected here"));
 188  191                  return (0);
 189  192          }
 190  193  
 191  194          if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) {
 192  195                  if (hdl != NULL)
 193  196                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 194  197                              "missing '#' delimiter in bookmark name"));
 195  198                  return (0);
 196  199          }
 197  200  
 198  201          if (modifying && strchr(path, '%') != NULL) {
 199  202                  if (hdl != NULL)
 200  203                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 201  204                              "invalid character %c in name"), '%');
 202  205                  return (0);
 203  206          }
 204  207  
 205  208          return (-1);
 206  209  }
 207  210  
 208  211  int
 209  212  zfs_name_valid(const char *name, zfs_type_t type)
 210  213  {
 211  214          if (type == ZFS_TYPE_POOL)
 212  215                  return (zpool_name_valid(NULL, B_FALSE, name));
 213  216          return (zfs_validate_name(NULL, name, type, B_FALSE));
 214  217  }
 215  218  
 216  219  /*
 217  220   * This function takes the raw DSL properties, and filters out the user-defined
 218  221   * properties into a separate nvlist.
 219  222   */
 220  223  static nvlist_t *
 221  224  process_user_props(zfs_handle_t *zhp, nvlist_t *props)
 222  225  {
 223  226          libzfs_handle_t *hdl = zhp->zfs_hdl;
 224  227          nvpair_t *elem;
 225  228          nvlist_t *propval;
 226  229          nvlist_t *nvl;
 227  230  
 228  231          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
 229  232                  (void) no_memory(hdl);
 230  233                  return (NULL);
 231  234          }
 232  235  
 233  236          elem = NULL;
 234  237          while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 235  238                  if (!zfs_prop_user(nvpair_name(elem)))
 236  239                          continue;
 237  240  
 238  241                  verify(nvpair_value_nvlist(elem, &propval) == 0);
 239  242                  if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
 240  243                          nvlist_free(nvl);
 241  244                          (void) no_memory(hdl);
 242  245                          return (NULL);
 243  246                  }
 244  247          }
 245  248  
 246  249          return (nvl);
 247  250  }
 248  251  
 249  252  static zpool_handle_t *
 250  253  zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
 251  254  {
 252  255          libzfs_handle_t *hdl = zhp->zfs_hdl;
 253  256          zpool_handle_t *zph;
 254  257  
 255  258          if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
 256  259                  if (hdl->libzfs_pool_handles != NULL)
 257  260                          zph->zpool_next = hdl->libzfs_pool_handles;
 258  261                  hdl->libzfs_pool_handles = zph;
 259  262          }
 260  263          return (zph);
 261  264  }
 262  265  
 263  266  static zpool_handle_t *
 264  267  zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
 265  268  {
 266  269          libzfs_handle_t *hdl = zhp->zfs_hdl;
 267  270          zpool_handle_t *zph = hdl->libzfs_pool_handles;
 268  271  
 269  272          while ((zph != NULL) &&
 270  273              (strncmp(pool_name, zpool_get_name(zph), len) != 0))
 271  274                  zph = zph->zpool_next;
 272  275          return (zph);
 273  276  }
 274  277  
 275  278  /*
 276  279   * Returns a handle to the pool that contains the provided dataset.
 277  280   * If a handle to that pool already exists then that handle is returned.
 278  281   * Otherwise, a new handle is created and added to the list of handles.
 279  282   */
 280  283  static zpool_handle_t *
 281  284  zpool_handle(zfs_handle_t *zhp)
 282  285  {
 283  286          char *pool_name;
 284  287          int len;
 285  288          zpool_handle_t *zph;
 286  289  
 287  290          len = strcspn(zhp->zfs_name, "/@#") + 1;
 288  291          pool_name = zfs_alloc(zhp->zfs_hdl, len);
 289  292          (void) strlcpy(pool_name, zhp->zfs_name, len);
 290  293  
 291  294          zph = zpool_find_handle(zhp, pool_name, len);
 292  295          if (zph == NULL)
 293  296                  zph = zpool_add_handle(zhp, pool_name);
 294  297  
 295  298          free(pool_name);
 296  299          return (zph);
 297  300  }
 298  301  
 299  302  void
 300  303  zpool_free_handles(libzfs_handle_t *hdl)
 301  304  {
 302  305          zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
 303  306  
 304  307          while (zph != NULL) {
 305  308                  next = zph->zpool_next;
 306  309                  zpool_close(zph);
 307  310                  zph = next;
 308  311          }
 309  312          hdl->libzfs_pool_handles = NULL;
 310  313  }
 311  314  
 312  315  /*
 313  316   * Utility function to gather stats (objset and zpl) for the given object.
 314  317   */
 315  318  static int
 316  319  get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
 317  320  {
 318  321          libzfs_handle_t *hdl = zhp->zfs_hdl;
 319  322  
 320  323          (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
 321  324  
 322  325          while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
 323  326                  if (errno == ENOMEM) {
 324  327                          if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
 325  328                                  return (-1);
 326  329                          }
 327  330                  } else {
 328  331                          return (-1);
 329  332                  }
 330  333          }
 331  334          return (0);
 332  335  }
 333  336  
 334  337  /*
 335  338   * Utility function to get the received properties of the given object.
 336  339   */
 337  340  static int
 338  341  get_recvd_props_ioctl(zfs_handle_t *zhp)
 339  342  {
 340  343          libzfs_handle_t *hdl = zhp->zfs_hdl;
 341  344          nvlist_t *recvdprops;
 342  345          zfs_cmd_t zc = { 0 };
 343  346          int err;
 344  347  
 345  348          if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
 346  349                  return (-1);
 347  350  
 348  351          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 349  352  
 350  353          while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
 351  354                  if (errno == ENOMEM) {
 352  355                          if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
 353  356                                  return (-1);
 354  357                          }
 355  358                  } else {
 356  359                          zcmd_free_nvlists(&zc);
 357  360                          return (-1);
 358  361                  }
 359  362          }
 360  363  
 361  364          err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
 362  365          zcmd_free_nvlists(&zc);
 363  366          if (err != 0)
 364  367                  return (-1);
 365  368  
 366  369          nvlist_free(zhp->zfs_recvd_props);
 367  370          zhp->zfs_recvd_props = recvdprops;
 368  371  
 369  372          return (0);
 370  373  }
 371  374  
 372  375  static int
 373  376  put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
 374  377  {
 375  378          nvlist_t *allprops, *userprops;
 376  379  
 377  380          zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
 378  381  
 379  382          if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
 380  383                  return (-1);
 381  384          }
 382  385  
 383  386          /*
 384  387           * XXX Why do we store the user props separately, in addition to
 385  388           * storing them in zfs_props?
 386  389           */
 387  390          if ((userprops = process_user_props(zhp, allprops)) == NULL) {
 388  391                  nvlist_free(allprops);
 389  392                  return (-1);
 390  393          }
 391  394  
 392  395          nvlist_free(zhp->zfs_props);
 393  396          nvlist_free(zhp->zfs_user_props);
 394  397  
 395  398          zhp->zfs_props = allprops;
 396  399          zhp->zfs_user_props = userprops;
 397  400  
 398  401          return (0);
 399  402  }
 400  403  
 401  404  static int
 402  405  get_stats(zfs_handle_t *zhp)
 403  406  {
 404  407          int rc = 0;
 405  408          zfs_cmd_t zc = { 0 };
 406  409  
 407  410          if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
 408  411                  return (-1);
 409  412          if (get_stats_ioctl(zhp, &zc) != 0)
 410  413                  rc = -1;
 411  414          else if (put_stats_zhdl(zhp, &zc) != 0)
 412  415                  rc = -1;
 413  416          zcmd_free_nvlists(&zc);
 414  417          return (rc);
 415  418  }
 416  419  
 417  420  /*
 418  421   * Refresh the properties currently stored in the handle.
 419  422   */
 420  423  void
 421  424  zfs_refresh_properties(zfs_handle_t *zhp)
 422  425  {
 423  426          (void) get_stats(zhp);
 424  427  }
 425  428  
 426  429  /*
 427  430   * Makes a handle from the given dataset name.  Used by zfs_open() and
 428  431   * zfs_iter_* to create child handles on the fly.
 429  432   */
 430  433  static int
 431  434  make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
 432  435  {
 433  436          if (put_stats_zhdl(zhp, zc) != 0)
 434  437                  return (-1);
 435  438  
 436  439          /*
 437  440           * We've managed to open the dataset and gather statistics.  Determine
 438  441           * the high-level type.
 439  442           */
 440  443          if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
 441  444                  zhp->zfs_head_type = ZFS_TYPE_VOLUME;
 442  445          else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
 443  446                  zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
 444  447          else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
 445  448                  return (-1);
 446  449          else
 447  450                  abort();
 448  451  
 449  452          if (zhp->zfs_dmustats.dds_is_snapshot)
 450  453                  zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
 451  454          else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
 452  455                  zhp->zfs_type = ZFS_TYPE_VOLUME;
 453  456          else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
 454  457                  zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
 455  458          else
 456  459                  abort();        /* we should never see any other types */
 457  460  
 458  461          if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
 459  462                  return (-1);
 460  463  
 461  464          return (0);
 462  465  }
 463  466  
 464  467  zfs_handle_t *
 465  468  make_dataset_handle(libzfs_handle_t *hdl, const char *path)
 466  469  {
 467  470          zfs_cmd_t zc = { 0 };
 468  471  
 469  472          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 470  473  
 471  474          if (zhp == NULL)
 472  475                  return (NULL);
 473  476  
 474  477          zhp->zfs_hdl = hdl;
 475  478          (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
 476  479          if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
 477  480                  free(zhp);
 478  481                  return (NULL);
 479  482          }
 480  483          if (get_stats_ioctl(zhp, &zc) == -1) {
 481  484                  zcmd_free_nvlists(&zc);
 482  485                  free(zhp);
 483  486                  return (NULL);
 484  487          }
 485  488          if (make_dataset_handle_common(zhp, &zc) == -1) {
 486  489                  free(zhp);
 487  490                  zhp = NULL;
 488  491          }
 489  492          zcmd_free_nvlists(&zc);
 490  493          return (zhp);
 491  494  }
 492  495  
 493  496  zfs_handle_t *
 494  497  make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
 495  498  {
 496  499          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 497  500  
 498  501          if (zhp == NULL)
 499  502                  return (NULL);
 500  503  
 501  504          zhp->zfs_hdl = hdl;
 502  505          (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
 503  506          if (make_dataset_handle_common(zhp, zc) == -1) {
 504  507                  free(zhp);
 505  508                  return (NULL);
 506  509          }
 507  510          return (zhp);
 508  511  }
 509  512  
 510  513  zfs_handle_t *
 511  514  make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc)
 512  515  {
 513  516          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 514  517  
 515  518          if (zhp == NULL)
 516  519                  return (NULL);
 517  520  
 518  521          zhp->zfs_hdl = pzhp->zfs_hdl;
 519  522          (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
 520  523          zhp->zfs_head_type = pzhp->zfs_type;
 521  524          zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
 522  525          zhp->zpool_hdl = zpool_handle(zhp);
 523  526          return (zhp);
 524  527  }
 525  528  
 526  529  zfs_handle_t *
 527  530  zfs_handle_dup(zfs_handle_t *zhp_orig)
 528  531  {
 529  532          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 530  533  
 531  534          if (zhp == NULL)
 532  535                  return (NULL);
 533  536  
 534  537          zhp->zfs_hdl = zhp_orig->zfs_hdl;
 535  538          zhp->zpool_hdl = zhp_orig->zpool_hdl;
 536  539          (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
 537  540              sizeof (zhp->zfs_name));
 538  541          zhp->zfs_type = zhp_orig->zfs_type;
 539  542          zhp->zfs_head_type = zhp_orig->zfs_head_type;
 540  543          zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
 541  544          if (zhp_orig->zfs_props != NULL) {
 542  545                  if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
 543  546                          (void) no_memory(zhp->zfs_hdl);
 544  547                          zfs_close(zhp);
 545  548                          return (NULL);
 546  549                  }
 547  550          }
 548  551          if (zhp_orig->zfs_user_props != NULL) {
 549  552                  if (nvlist_dup(zhp_orig->zfs_user_props,
 550  553                      &zhp->zfs_user_props, 0) != 0) {
 551  554                          (void) no_memory(zhp->zfs_hdl);
 552  555                          zfs_close(zhp);
 553  556                          return (NULL);
 554  557                  }
 555  558          }
 556  559          if (zhp_orig->zfs_recvd_props != NULL) {
 557  560                  if (nvlist_dup(zhp_orig->zfs_recvd_props,
 558  561                      &zhp->zfs_recvd_props, 0)) {
 559  562                          (void) no_memory(zhp->zfs_hdl);
 560  563                          zfs_close(zhp);
 561  564                          return (NULL);
 562  565                  }
 563  566          }
 564  567          zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
 565  568          if (zhp_orig->zfs_mntopts != NULL) {
 566  569                  zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
 567  570                      zhp_orig->zfs_mntopts);
 568  571          }
 569  572          zhp->zfs_props_table = zhp_orig->zfs_props_table;
 570  573          return (zhp);
 571  574  }
 572  575  
 573  576  boolean_t
 574  577  zfs_bookmark_exists(const char *path)
 575  578  {
 576  579          nvlist_t *bmarks;
 577  580          nvlist_t *props;
 578  581          char fsname[ZFS_MAX_DATASET_NAME_LEN];
 579  582          char *bmark_name;
 580  583          char *pound;
 581  584          int err;
 582  585          boolean_t rv;
 583  586  
 584  587  
 585  588          (void) strlcpy(fsname, path, sizeof (fsname));
 586  589          pound = strchr(fsname, '#');
 587  590          if (pound == NULL)
 588  591                  return (B_FALSE);
 589  592  
 590  593          *pound = '\0';
 591  594          bmark_name = pound + 1;
 592  595          props = fnvlist_alloc();
 593  596          err = lzc_get_bookmarks(fsname, props, &bmarks);
 594  597          nvlist_free(props);
 595  598          if (err != 0) {
 596  599                  nvlist_free(bmarks);
 597  600                  return (B_FALSE);
 598  601          }
 599  602  
 600  603          rv = nvlist_exists(bmarks, bmark_name);
 601  604          nvlist_free(bmarks);
 602  605          return (rv);
 603  606  }
 604  607  
 605  608  zfs_handle_t *
 606  609  make_bookmark_handle(zfs_handle_t *parent, const char *path,
 607  610      nvlist_t *bmark_props)
 608  611  {
 609  612          zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
 610  613  
 611  614          if (zhp == NULL)
 612  615                  return (NULL);
 613  616  
 614  617          /* Fill in the name. */
 615  618          zhp->zfs_hdl = parent->zfs_hdl;
 616  619          (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
 617  620  
 618  621          /* Set the property lists. */
 619  622          if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
 620  623                  free(zhp);
 621  624                  return (NULL);
 622  625          }
 623  626  
 624  627          /* Set the types. */
 625  628          zhp->zfs_head_type = parent->zfs_head_type;
 626  629          zhp->zfs_type = ZFS_TYPE_BOOKMARK;
 627  630  
 628  631          if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
 629  632                  nvlist_free(zhp->zfs_props);
 630  633                  free(zhp);
 631  634                  return (NULL);
 632  635          }
 633  636  
 634  637          return (zhp);
 635  638  }
 636  639  
 637  640  struct zfs_open_bookmarks_cb_data {
 638  641          const char *path;
 639  642          zfs_handle_t *zhp;
 640  643  };
 641  644  
 642  645  static int
 643  646  zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data)
 644  647  {
 645  648          struct zfs_open_bookmarks_cb_data *dp = data;
 646  649  
 647  650          /*
 648  651           * Is it the one we are looking for?
 649  652           */
 650  653          if (strcmp(dp->path, zfs_get_name(zhp)) == 0) {
 651  654                  /*
 652  655                   * We found it.  Save it and let the caller know we are done.
 653  656                   */
 654  657                  dp->zhp = zhp;
 655  658                  return (EEXIST);
 656  659          }
 657  660  
 658  661          /*
 659  662           * Not found.  Close the handle and ask for another one.
 660  663           */
 661  664          zfs_close(zhp);
 662  665          return (0);
 663  666  }
 664  667  
 665  668  /*
 666  669   * Opens the given snapshot, bookmark, filesystem, or volume.   The 'types'
 667  670   * argument is a mask of acceptable types.  The function will print an
 668  671   * appropriate error message and return NULL if it can't be opened.
 669  672   */
 670  673  zfs_handle_t *
 671  674  zfs_open(libzfs_handle_t *hdl, const char *path, int types)
 672  675  {
 673  676          zfs_handle_t *zhp;
 674  677          char errbuf[1024];
 675  678          char *bookp;
 676  679  
 677  680          (void) snprintf(errbuf, sizeof (errbuf),
 678  681              dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
 679  682  
 680  683          /*
 681  684           * Validate the name before we even try to open it.
 682  685           */
 683  686          if (!zfs_validate_name(hdl, path, types, B_FALSE)) {
 684  687                  (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
 685  688                  return (NULL);
 686  689          }
 687  690  
 688  691          /*
 689  692           * Bookmarks needs to be handled separately.
 690  693           */
 691  694          bookp = strchr(path, '#');
 692  695          if (bookp == NULL) {
 693  696                  /*
 694  697                   * Try to get stats for the dataset, which will tell us if it
 695  698                   * exists.
 696  699                   */
 697  700                  errno = 0;
 698  701                  if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
 699  702                          (void) zfs_standard_error(hdl, errno, errbuf);
 700  703                          return (NULL);
 701  704                  }
 702  705          } else {
 703  706                  char dsname[ZFS_MAX_DATASET_NAME_LEN];
 704  707                  zfs_handle_t *pzhp;
 705  708                  struct zfs_open_bookmarks_cb_data cb_data = {path, NULL};
 706  709  
 707  710                  /*
 708  711                   * We need to cut out '#' and everything after '#'
 709  712                   * to get the parent dataset name only.
 710  713                   */
 711  714                  assert(bookp - path < sizeof (dsname));
 712  715                  (void) strncpy(dsname, path, bookp - path);
 713  716                  dsname[bookp - path] = '\0';
 714  717  
 715  718                  /*
 716  719                   * Create handle for the parent dataset.
 717  720                   */
 718  721                  errno = 0;
 719  722                  if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) {
 720  723                          (void) zfs_standard_error(hdl, errno, errbuf);
 721  724                          return (NULL);
 722  725                  }
 723  726  
 724  727                  /*
 725  728                   * Iterate bookmarks to find the right one.
 726  729                   */
 727  730                  errno = 0;
 728  731                  if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb,
 729  732                      &cb_data) == 0) && (cb_data.zhp == NULL)) {
 730  733                          (void) zfs_error(hdl, EZFS_NOENT, errbuf);
 731  734                          zfs_close(pzhp);
 732  735                          return (NULL);
 733  736                  }
 734  737                  if (cb_data.zhp == NULL) {
 735  738                          (void) zfs_standard_error(hdl, errno, errbuf);
 736  739                          zfs_close(pzhp);
 737  740                          return (NULL);
 738  741                  }
 739  742                  zhp = cb_data.zhp;
 740  743  
 741  744                  /*
 742  745                   * Cleanup.
 743  746                   */
 744  747                  zfs_close(pzhp);
 745  748          }
 746  749  
 747  750          if (!(types & zhp->zfs_type)) {
 748  751                  (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
 749  752                  zfs_close(zhp);
 750  753                  return (NULL);
 751  754          }
 752  755  
 753  756          return (zhp);
 754  757  }
 755  758  
 756  759  /*
 757  760   * Release a ZFS handle.  Nothing to do but free the associated memory.
 758  761   */
 759  762  void
 760  763  zfs_close(zfs_handle_t *zhp)
 761  764  {
 762  765          if (zhp->zfs_mntopts)
 763  766                  free(zhp->zfs_mntopts);
 764  767          nvlist_free(zhp->zfs_props);
 765  768          nvlist_free(zhp->zfs_user_props);
 766  769          nvlist_free(zhp->zfs_recvd_props);
 767  770          free(zhp);
 768  771  }
 769  772  
 770  773  typedef struct mnttab_node {
 771  774          struct mnttab mtn_mt;
 772  775          avl_node_t mtn_node;
 773  776  } mnttab_node_t;
 774  777  
 775  778  static int
 776  779  libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
 777  780  {
 778  781          const mnttab_node_t *mtn1 = (const mnttab_node_t *)arg1;
 779  782          const mnttab_node_t *mtn2 = (const mnttab_node_t *)arg2;
 780  783          int rv;
 781  784  
 782  785          rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
 783  786  
 784  787          if (rv == 0)
 785  788                  return (0);
 786  789          return (rv > 0 ? 1 : -1);
 787  790  }
 788  791  
 789  792  void
 790  793  libzfs_mnttab_init(libzfs_handle_t *hdl)
 791  794  {
 792  795          (void) mutex_init(&hdl->libzfs_mnttab_cache_lock,
 793  796              LOCK_NORMAL | LOCK_ERRORCHECK, NULL);
 794  797          assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
 795  798          avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
 796  799              sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
 797  800  }
 798  801  
 799  802  void
 800  803  libzfs_mnttab_update(libzfs_handle_t *hdl)
 801  804  {
 802  805          struct mnttab entry;
 803  806  
 804  807          rewind(hdl->libzfs_mnttab);
 805  808          while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
 806  809                  mnttab_node_t *mtn;
 807  810  
 808  811                  if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
 809  812                          continue;
 810  813                  mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
 811  814                  mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
 812  815                  mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
 813  816                  mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
 814  817                  mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
 815  818                  avl_add(&hdl->libzfs_mnttab_cache, mtn);
 816  819          }
 817  820  }
 818  821  
 819  822  void
 820  823  libzfs_mnttab_fini(libzfs_handle_t *hdl)
 821  824  {
 822  825          void *cookie = NULL;
 823  826          mnttab_node_t *mtn;
 824  827  
 825  828          while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))
 826  829              != NULL) {
 827  830                  free(mtn->mtn_mt.mnt_special);
 828  831                  free(mtn->mtn_mt.mnt_mountp);
 829  832                  free(mtn->mtn_mt.mnt_fstype);
 830  833                  free(mtn->mtn_mt.mnt_mntopts);
 831  834                  free(mtn);
 832  835          }
 833  836          avl_destroy(&hdl->libzfs_mnttab_cache);
 834  837          (void) mutex_destroy(&hdl->libzfs_mnttab_cache_lock);
 835  838  }
 836  839  
 837  840  void
 838  841  libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
 839  842  {
 840  843          hdl->libzfs_mnttab_enable = enable;
 841  844  }
 842  845  
 843  846  int
 844  847  libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
 845  848      struct mnttab *entry)
 846  849  {
 847  850          mnttab_node_t find;
 848  851          mnttab_node_t *mtn;
 849  852          int ret = ENOENT;
 850  853  
 851  854          if (!hdl->libzfs_mnttab_enable) {
 852  855                  struct mnttab srch = { 0 };
 853  856  
 854  857                  if (avl_numnodes(&hdl->libzfs_mnttab_cache))
 855  858                          libzfs_mnttab_fini(hdl);
 856  859                  rewind(hdl->libzfs_mnttab);
 857  860                  srch.mnt_special = (char *)fsname;
 858  861                  srch.mnt_fstype = MNTTYPE_ZFS;
 859  862                  if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
 860  863                          return (0);
 861  864                  else
 862  865                          return (ENOENT);
 863  866          }
 864  867  
 865  868          mutex_enter(&hdl->libzfs_mnttab_cache_lock);
 866  869          if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
 867  870                  libzfs_mnttab_update(hdl);
 868  871  
 869  872          find.mtn_mt.mnt_special = (char *)fsname;
 870  873          mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
 871  874          if (mtn) {
 872  875                  *entry = mtn->mtn_mt;
 873  876                  ret = 0;
 874  877          }
 875  878          mutex_exit(&hdl->libzfs_mnttab_cache_lock);
 876  879          return (ret);
 877  880  }
 878  881  
 879  882  void
 880  883  libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
 881  884      const char *mountp, const char *mntopts)
 882  885  {
 883  886          mnttab_node_t *mtn;
 884  887  
 885  888          mutex_enter(&hdl->libzfs_mnttab_cache_lock);
 886  889          if (avl_numnodes(&hdl->libzfs_mnttab_cache) != 0) {
 887  890                  mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
 888  891                  mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
 889  892                  mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
 890  893                  mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
 891  894                  mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
 892  895                  avl_add(&hdl->libzfs_mnttab_cache, mtn);
 893  896          }
 894  897          mutex_exit(&hdl->libzfs_mnttab_cache_lock);
 895  898  }
 896  899  
 897  900  void
 898  901  libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
 899  902  {
 900  903          mnttab_node_t find;
 901  904          mnttab_node_t *ret;
 902  905  
 903  906          mutex_enter(&hdl->libzfs_mnttab_cache_lock);
 904  907          find.mtn_mt.mnt_special = (char *)fsname;
 905  908          if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))
 906  909              != NULL) {
 907  910                  avl_remove(&hdl->libzfs_mnttab_cache, ret);
 908  911                  free(ret->mtn_mt.mnt_special);
 909  912                  free(ret->mtn_mt.mnt_mountp);
 910  913                  free(ret->mtn_mt.mnt_fstype);
 911  914                  free(ret->mtn_mt.mnt_mntopts);
 912  915                  free(ret);
 913  916          }
 914  917          mutex_exit(&hdl->libzfs_mnttab_cache_lock);
 915  918  }
 916  919  
 917  920  int
 918  921  zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
 919  922  {
 920  923          zpool_handle_t *zpool_handle = zhp->zpool_hdl;
 921  924  
 922  925          if (zpool_handle == NULL)
 923  926                  return (-1);
 924  927  
 925  928          *spa_version = zpool_get_prop_int(zpool_handle,
 926  929              ZPOOL_PROP_VERSION, NULL);
 927  930          return (0);
 928  931  }
 929  932  
 930  933  /*
 931  934   * The choice of reservation property depends on the SPA version.
 932  935   */
 933  936  static int
 934  937  zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
 935  938  {
 936  939          int spa_version;
 937  940  
 938  941          if (zfs_spa_version(zhp, &spa_version) < 0)
 939  942                  return (-1);
 940  943  
 941  944          if (spa_version >= SPA_VERSION_REFRESERVATION)
 942  945                  *resv_prop = ZFS_PROP_REFRESERVATION;
 943  946          else
 944  947                  *resv_prop = ZFS_PROP_RESERVATION;
 945  948  
 946  949          return (0);
 947  950  }
 948  951  
 949  952  /*
 950  953   * Given an nvlist of properties to set, validates that they are correct, and
 951  954   * parses any numeric properties (index, boolean, etc) if they are specified as
 952  955   * strings.
 953  956   */
 954  957  nvlist_t *
 955  958  zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
 956  959      uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
 957  960      boolean_t key_params_ok, const char *errbuf)
 958  961  {
 959  962          nvpair_t *elem;
 960  963          uint64_t intval;
 961  964          char *strval;
 962  965          zfs_prop_t prop;
 963  966          nvlist_t *ret;
 964  967          int chosen_normal = -1;
 965  968          int chosen_utf = -1;
 966  969  
 967  970          if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
 968  971                  (void) no_memory(hdl);
 969  972                  return (NULL);
 970  973          }
 971  974  
 972  975          /*
 973  976           * Make sure this property is valid and applies to this type.
 974  977           */
 975  978  
 976  979          elem = NULL;
 977  980          while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
 978  981                  const char *propname = nvpair_name(elem);
 979  982  
 980  983                  prop = zfs_name_to_prop(propname);
 981  984                  if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
 982  985                          /*
 983  986                           * This is a user property: make sure it's a
 984  987                           * string, and that it's less than ZAP_MAXNAMELEN.
 985  988                           */
 986  989                          if (nvpair_type(elem) != DATA_TYPE_STRING) {
 987  990                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 988  991                                      "'%s' must be a string"), propname);
 989  992                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 990  993                                  goto error;
 991  994                          }
 992  995  
 993  996                          if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
 994  997                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 995  998                                      "property name '%s' is too long"),
 996  999                                      propname);
 997 1000                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 998 1001                                  goto error;
 999 1002                          }
1000 1003  
1001 1004                          (void) nvpair_value_string(elem, &strval);
1002 1005                          if (nvlist_add_string(ret, propname, strval) != 0) {
1003 1006                                  (void) no_memory(hdl);
1004 1007                                  goto error;
1005 1008                          }
1006 1009                          continue;
1007 1010                  }
1008 1011  
1009 1012                  /*
1010 1013                   * Currently, only user properties can be modified on
1011 1014                   * snapshots.
1012 1015                   */
1013 1016                  if (type == ZFS_TYPE_SNAPSHOT) {
1014 1017                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1015 1018                              "this property can not be modified for snapshots"));
1016 1019                          (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
1017 1020                          goto error;
1018 1021                  }
1019 1022  
1020 1023                  if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
1021 1024                          zfs_userquota_prop_t uqtype;
1022 1025                          char newpropname[128];
1023 1026                          char domain[128];
1024 1027                          uint64_t rid;
1025 1028                          uint64_t valary[3];
1026 1029  
1027 1030                          if (userquota_propname_decode(propname, zoned,
1028 1031                              &uqtype, domain, sizeof (domain), &rid) != 0) {
1029 1032                                  zfs_error_aux(hdl,
1030 1033                                      dgettext(TEXT_DOMAIN,
1031 1034                                      "'%s' has an invalid user/group name"),
1032 1035                                      propname);
1033 1036                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1034 1037                                  goto error;
1035 1038                          }
1036 1039  
1037 1040                          if (uqtype != ZFS_PROP_USERQUOTA &&
1038 1041                              uqtype != ZFS_PROP_GROUPQUOTA &&
1039 1042                              uqtype != ZFS_PROP_USEROBJQUOTA &&
1040 1043                              uqtype != ZFS_PROP_GROUPOBJQUOTA &&
1041 1044                              uqtype != ZFS_PROP_PROJECTQUOTA &&
1042 1045                              uqtype != ZFS_PROP_PROJECTOBJQUOTA) {
1043 1046                                  zfs_error_aux(hdl,
1044 1047                                      dgettext(TEXT_DOMAIN, "'%s' is readonly"),
1045 1048                                      propname);
1046 1049                                  (void) zfs_error(hdl, EZFS_PROPREADONLY,
1047 1050                                      errbuf);
1048 1051                                  goto error;
1049 1052                          }
1050 1053  
1051 1054                          if (nvpair_type(elem) == DATA_TYPE_STRING) {
1052 1055                                  (void) nvpair_value_string(elem, &strval);
1053 1056                                  if (strcmp(strval, "none") == 0) {
1054 1057                                          intval = 0;
1055 1058                                  } else if (zfs_nicestrtonum(hdl,
1056 1059                                      strval, &intval) != 0) {
1057 1060                                          (void) zfs_error(hdl,
1058 1061                                              EZFS_BADPROP, errbuf);
1059 1062                                          goto error;
1060 1063                                  }
1061 1064                          } else if (nvpair_type(elem) ==
1062 1065                              DATA_TYPE_UINT64) {
1063 1066                                  (void) nvpair_value_uint64(elem, &intval);
1064 1067                                  if (intval == 0) {
1065 1068                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1066 1069                                              "use 'none' to disable "
1067 1070                                              "{user|group|project}quota"));
1068 1071                                          goto error;
1069 1072                                  }
1070 1073                          } else {
1071 1074                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1072 1075                                      "'%s' must be a number"), propname);
1073 1076                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1074 1077                                  goto error;
1075 1078                          }
1076 1079  
1077 1080                          /*
1078 1081                           * Encode the prop name as
1079 1082                           * userquota@<hex-rid>-domain, to make it easy
1080 1083                           * for the kernel to decode.
1081 1084                           */
1082 1085                          (void) snprintf(newpropname, sizeof (newpropname),
1083 1086                              "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
1084 1087                              (longlong_t)rid, domain);
1085 1088                          valary[0] = uqtype;
1086 1089                          valary[1] = rid;
1087 1090                          valary[2] = intval;
1088 1091                          if (nvlist_add_uint64_array(ret, newpropname,
1089 1092                              valary, 3) != 0) {
1090 1093                                  (void) no_memory(hdl);
1091 1094                                  goto error;
1092 1095                          }
1093 1096                          continue;
1094 1097                  } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
1095 1098                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1096 1099                              "'%s' is readonly"),
1097 1100                              propname);
1098 1101                          (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
1099 1102                          goto error;
1100 1103                  }
1101 1104  
1102 1105                  if (prop == ZPROP_INVAL) {
1103 1106                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1104 1107                              "invalid property '%s'"), propname);
1105 1108                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1106 1109                          goto error;
1107 1110                  }
1108 1111  
1109 1112                  if (!zfs_prop_valid_for_type(prop, type)) {
1110 1113                          zfs_error_aux(hdl,
1111 1114                              dgettext(TEXT_DOMAIN, "'%s' does not "
1112 1115                              "apply to datasets of this type"), propname);
1113 1116                          (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
1114 1117                          goto error;
1115 1118                  }
1116 1119  
1117 1120                  if (zfs_prop_readonly(prop) &&
1118 1121                      !(zfs_prop_setonce(prop) && zhp == NULL) &&
1119 1122                      !(zfs_prop_encryption_key_param(prop) && key_params_ok)) {
1120 1123                          zfs_error_aux(hdl,
1121 1124                              dgettext(TEXT_DOMAIN, "'%s' is readonly"),
1122 1125                              propname);
1123 1126                          (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
1124 1127                          goto error;
1125 1128                  }
1126 1129  
1127 1130                  if (zprop_parse_value(hdl, elem, prop, type, ret,
1128 1131                      &strval, &intval, errbuf) != 0)
1129 1132                          goto error;
1130 1133  
1131 1134                  /*
1132 1135                   * Perform some additional checks for specific properties.
1133 1136                   */
1134 1137                  switch (prop) {
1135 1138                  case ZFS_PROP_VERSION:
1136 1139                  {
1137 1140                          int version;
1138 1141  
1139 1142                          if (zhp == NULL)
1140 1143                                  break;
1141 1144                          version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1142 1145                          if (intval < version) {
1143 1146                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1144 1147                                      "Can not downgrade; already at version %u"),
1145 1148                                      version);
1146 1149                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1147 1150                                  goto error;
1148 1151                          }
1149 1152                          break;
1150 1153                  }
1151 1154  
1152 1155                  case ZFS_PROP_VOLBLOCKSIZE:
1153 1156                  case ZFS_PROP_RECORDSIZE:
1154 1157                  {
1155 1158                          int maxbs = SPA_MAXBLOCKSIZE;
1156 1159                          if (zpool_hdl != NULL) {
1157 1160                                  maxbs = zpool_get_prop_int(zpool_hdl,
1158 1161                                      ZPOOL_PROP_MAXBLOCKSIZE, NULL);
1159 1162                          }
1160 1163                          /*
1161 1164                           * Volumes are limited to a volblocksize of 128KB,
1162 1165                           * because they typically service workloads with
1163 1166                           * small random writes, which incur a large performance
1164 1167                           * penalty with large blocks.
1165 1168                           */
1166 1169                          if (prop == ZFS_PROP_VOLBLOCKSIZE)
1167 1170                                  maxbs = SPA_OLD_MAXBLOCKSIZE;
1168 1171                          /*
1169 1172                           * The value must be a power of two between
1170 1173                           * SPA_MINBLOCKSIZE and maxbs.
1171 1174                           */
1172 1175                          if (intval < SPA_MINBLOCKSIZE ||
1173 1176                              intval > maxbs || !ISP2(intval)) {
1174 1177                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1175 1178                                      "'%s' must be power of 2 from 512B "
1176 1179                                      "to %uKB"), propname, maxbs >> 10);
1177 1180                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1178 1181                                  goto error;
1179 1182                          }
1180 1183                          break;
1181 1184                  }
1182 1185  
1183 1186                  case ZFS_PROP_SPECIAL_SMALL_BLOCKS:
1184 1187                          if (zpool_hdl != NULL) {
1185 1188                                  char state[64] = "";
1186 1189  
1187 1190                                  /*
1188 1191                                   * Issue a warning but do not fail so that
1189 1192                                   * tests for setable properties succeed.
1190 1193                                   */
1191 1194                                  if (zpool_prop_get_feature(zpool_hdl,
1192 1195                                      "feature@allocation_classes", state,
1193 1196                                      sizeof (state)) != 0 ||
1194 1197                                      strcmp(state, ZFS_FEATURE_ACTIVE) != 0) {
1195 1198                                          (void) fprintf(stderr, gettext(
1196 1199                                              "%s: property requires a special "
1197 1200                                              "device in the pool\n"), propname);
1198 1201                                  }
1199 1202                          }
1200 1203                          if (intval != 0 &&
1201 1204                              (intval < SPA_MINBLOCKSIZE ||
1202 1205                              intval > SPA_OLD_MAXBLOCKSIZE || !ISP2(intval))) {
1203 1206                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1204 1207                                      "invalid '%s=%d' property: must be zero or "
1205 1208                                      "a power of 2 from 512B to 128K"), propname,
1206 1209                                      intval);
1207 1210                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1208 1211                                  goto error;
1209 1212                          }
1210 1213                          break;
1211 1214  
1212 1215                  case ZFS_PROP_MLSLABEL:
1213 1216                  {
1214 1217                          /*
1215 1218                           * Verify the mlslabel string and convert to
1216 1219                           * internal hex label string.
1217 1220                           */
1218 1221  
1219 1222                          m_label_t *new_sl;
1220 1223                          char *hex = NULL;       /* internal label string */
1221 1224  
1222 1225                          /* Default value is already OK. */
1223 1226                          if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
1224 1227                                  break;
1225 1228  
1226 1229                          /* Verify the label can be converted to binary form */
1227 1230                          if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
1228 1231                              (str_to_label(strval, &new_sl, MAC_LABEL,
1229 1232                              L_NO_CORRECTION, NULL) == -1)) {
1230 1233                                  goto badlabel;
1231 1234                          }
1232 1235  
1233 1236                          /* Now translate to hex internal label string */
1234 1237                          if (label_to_str(new_sl, &hex, M_INTERNAL,
1235 1238                              DEF_NAMES) != 0) {
1236 1239                                  if (hex)
1237 1240                                          free(hex);
1238 1241                                  goto badlabel;
1239 1242                          }
1240 1243                          m_label_free(new_sl);
1241 1244  
1242 1245                          /* If string is already in internal form, we're done. */
1243 1246                          if (strcmp(strval, hex) == 0) {
1244 1247                                  free(hex);
1245 1248                                  break;
1246 1249                          }
1247 1250  
1248 1251                          /* Replace the label string with the internal form. */
1249 1252                          (void) nvlist_remove(ret, zfs_prop_to_name(prop),
1250 1253                              DATA_TYPE_STRING);
1251 1254                          verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
1252 1255                              hex) == 0);
1253 1256                          free(hex);
1254 1257  
1255 1258                          break;
1256 1259  
1257 1260  badlabel:
1258 1261                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1259 1262                              "invalid mlslabel '%s'"), strval);
1260 1263                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1261 1264                          m_label_free(new_sl);   /* OK if null */
1262 1265                          goto error;
1263 1266  
1264 1267                  }
1265 1268  
1266 1269                  case ZFS_PROP_MOUNTPOINT:
1267 1270                  {
1268 1271                          namecheck_err_t why;
1269 1272  
1270 1273                          if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
1271 1274                              strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
1272 1275                                  break;
1273 1276  
1274 1277                          if (mountpoint_namecheck(strval, &why)) {
1275 1278                                  switch (why) {
1276 1279                                  case NAME_ERR_LEADING_SLASH:
1277 1280                                          zfs_error_aux(hdl,
1278 1281                                              dgettext(TEXT_DOMAIN,
1279 1282                                              "'%s' must be an absolute path, "
1280 1283                                              "'none', or 'legacy'"), propname);
1281 1284                                          break;
1282 1285                                  case NAME_ERR_TOOLONG:
1283 1286                                          zfs_error_aux(hdl,
1284 1287                                              dgettext(TEXT_DOMAIN,
1285 1288                                              "component of '%s' is too long"),
1286 1289                                              propname);
1287 1290                                          break;
1288 1291  
1289 1292                                  default:
1290 1293                                          zfs_error_aux(hdl,
1291 1294                                              dgettext(TEXT_DOMAIN,
1292 1295                                              "(%d) not defined"),
1293 1296                                              why);
1294 1297                                          break;
1295 1298                                  }
1296 1299                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1297 1300                                  goto error;
1298 1301                          }
1299 1302                  }
1300 1303  
1301 1304                          /*FALLTHRU*/
1302 1305  
1303 1306                  case ZFS_PROP_SHARESMB:
  
    | 
      ↓ open down ↓ | 
    1262 lines elided | 
    
      ↑ open up ↑ | 
  
1304 1307                  case ZFS_PROP_SHARENFS:
1305 1308                          /*
1306 1309                           * For the mountpoint and sharenfs or sharesmb
1307 1310                           * properties, check if it can be set in a
1308 1311                           * global/non-global zone based on
1309 1312                           * the zoned property value:
1310 1313                           *
1311 1314                           *              global zone         non-global zone
1312 1315                           * --------------------------------------------------
1313 1316                           * zoned=on     mountpoint (no)     mountpoint (yes)
1314      -                         *              sharenfs (no)       sharenfs (no)
1315      -                         *              sharesmb (no)       sharesmb (no)
     1317 +                         *              sharenfs (no)       sharenfs (yes)
     1318 +                         *              sharesmb (no)       sharesmb (yes)
1316 1319                           *
1317 1320                           * zoned=off    mountpoint (yes)        N/A
1318 1321                           *              sharenfs (yes)
1319 1322                           *              sharesmb (yes)
1320 1323                           */
1321 1324                          if (zoned) {
1322 1325                                  if (getzoneid() == GLOBAL_ZONEID) {
1323 1326                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1324 1327                                              "'%s' cannot be set on "
1325 1328                                              "dataset in a non-global zone"),
1326 1329                                              propname);
1327 1330                                          (void) zfs_error(hdl, EZFS_ZONED,
1328 1331                                              errbuf);
1329      -                                        goto error;
1330      -                                } else if (prop == ZFS_PROP_SHARENFS ||
1331      -                                    prop == ZFS_PROP_SHARESMB) {
1332      -                                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1333      -                                            "'%s' cannot be set in "
1334      -                                            "a non-global zone"), propname);
1335      -                                        (void) zfs_error(hdl, EZFS_ZONED,
1336      -                                            errbuf);
1337 1332                                          goto error;
1338 1333                                  }
1339 1334                          } else if (getzoneid() != GLOBAL_ZONEID) {
1340 1335                                  /*
1341 1336                                   * If zoned property is 'off', this must be in
1342 1337                                   * a global zone. If not, something is wrong.
1343 1338                                   */
1344 1339                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1345 1340                                      "'%s' cannot be set while dataset "
1346 1341                                      "'zoned' property is set"), propname);
1347 1342                                  (void) zfs_error(hdl, EZFS_ZONED, errbuf);
1348 1343                                  goto error;
1349 1344                          }
1350 1345  
1351 1346                          /*
1352 1347                           * At this point, it is legitimate to set the
1353 1348                           * property. Now we want to make sure that the
1354 1349                           * property value is valid if it is sharenfs.
1355 1350                           */
1356 1351                          if ((prop == ZFS_PROP_SHARENFS ||
1357 1352                              prop == ZFS_PROP_SHARESMB) &&
1358 1353                              strcmp(strval, "on") != 0 &&
1359 1354                              strcmp(strval, "off") != 0) {
1360 1355                                  zfs_share_proto_t proto;
1361 1356  
1362 1357                                  if (prop == ZFS_PROP_SHARESMB)
1363 1358                                          proto = PROTO_SMB;
1364 1359                                  else
1365 1360                                          proto = PROTO_NFS;
1366 1361  
1367 1362                                  /*
1368 1363                                   * Must be an valid sharing protocol
1369 1364                                   * option string so init the libshare
1370 1365                                   * in order to enable the parser and
1371 1366                                   * then parse the options. We use the
1372 1367                                   * control API since we don't care about
1373 1368                                   * the current configuration and don't
1374 1369                                   * want the overhead of loading it
1375 1370                                   * until we actually do something.
1376 1371                                   */
1377 1372  
1378 1373                                  if (zfs_init_libshare(hdl,
1379 1374                                      SA_INIT_CONTROL_API) != SA_OK) {
1380 1375                                          /*
1381 1376                                           * An error occurred so we can't do
1382 1377                                           * anything
1383 1378                                           */
1384 1379                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1385 1380                                              "'%s' cannot be set: problem "
1386 1381                                              "in share initialization"),
1387 1382                                              propname);
1388 1383                                          (void) zfs_error(hdl, EZFS_BADPROP,
1389 1384                                              errbuf);
1390 1385                                          goto error;
1391 1386                                  }
1392 1387  
1393 1388                                  if (zfs_parse_options(strval, proto) != SA_OK) {
1394 1389                                          /*
1395 1390                                           * There was an error in parsing so
1396 1391                                           * deal with it by issuing an error
1397 1392                                           * message and leaving after
1398 1393                                           * uninitializing the the libshare
1399 1394                                           * interface.
1400 1395                                           */
1401 1396                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1402 1397                                              "'%s' cannot be set to invalid "
1403 1398                                              "options"), propname);
1404 1399                                          (void) zfs_error(hdl, EZFS_BADPROP,
1405 1400                                              errbuf);
1406 1401                                          zfs_uninit_libshare(hdl);
1407 1402                                          goto error;
1408 1403                                  }
1409 1404                                  zfs_uninit_libshare(hdl);
1410 1405                          }
1411 1406  
1412 1407                          break;
1413 1408  
1414 1409                  case ZFS_PROP_KEYLOCATION:
1415 1410                          if (!zfs_prop_valid_keylocation(strval, B_FALSE)) {
1416 1411                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1417 1412                                      "invalid keylocation"));
1418 1413                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1419 1414                                  goto error;
1420 1415                          }
1421 1416  
1422 1417                          if (zhp != NULL) {
1423 1418                                  uint64_t crypt =
1424 1419                                      zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);
1425 1420  
1426 1421                                  if (crypt == ZIO_CRYPT_OFF &&
1427 1422                                      strcmp(strval, "none") != 0) {
1428 1423                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1429 1424                                              "keylocation must be 'none' "
1430 1425                                              "for unencrypted datasets"));
1431 1426                                          (void) zfs_error(hdl, EZFS_BADPROP,
1432 1427                                              errbuf);
1433 1428                                          goto error;
1434 1429                                  } else if (crypt != ZIO_CRYPT_OFF &&
1435 1430                                      strcmp(strval, "none") == 0) {
1436 1431                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1437 1432                                              "keylocation must not be 'none' "
1438 1433                                              "for encrypted datasets"));
1439 1434                                          (void) zfs_error(hdl, EZFS_BADPROP,
1440 1435                                              errbuf);
1441 1436                                          goto error;
1442 1437                                  }
1443 1438                          }
1444 1439                          break;
1445 1440  
1446 1441                  case ZFS_PROP_PBKDF2_ITERS:
1447 1442                          if (intval < MIN_PBKDF2_ITERATIONS) {
1448 1443                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1449 1444                                      "minimum pbkdf2 iterations is %u"),
1450 1445                                      MIN_PBKDF2_ITERATIONS);
1451 1446                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1452 1447                                  goto error;
1453 1448                          }
1454 1449                          break;
1455 1450  
1456 1451                  case ZFS_PROP_UTF8ONLY:
1457 1452                          chosen_utf = (int)intval;
1458 1453                          break;
1459 1454  
1460 1455                  case ZFS_PROP_NORMALIZE:
1461 1456                          chosen_normal = (int)intval;
1462 1457                          break;
1463 1458  
1464 1459                  default:
1465 1460                          break;
1466 1461                  }
1467 1462  
1468 1463                  /*
1469 1464                   * For changes to existing volumes, we have some additional
1470 1465                   * checks to enforce.
1471 1466                   */
1472 1467                  if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
1473 1468                          uint64_t volsize = zfs_prop_get_int(zhp,
1474 1469                              ZFS_PROP_VOLSIZE);
1475 1470                          uint64_t blocksize = zfs_prop_get_int(zhp,
1476 1471                              ZFS_PROP_VOLBLOCKSIZE);
1477 1472                          char buf[64];
1478 1473  
1479 1474                          switch (prop) {
1480 1475                          case ZFS_PROP_RESERVATION:
1481 1476                                  if (intval > volsize) {
1482 1477                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1483 1478                                              "'%s' is greater than current "
1484 1479                                              "volume size"), propname);
1485 1480                                          (void) zfs_error(hdl, EZFS_BADPROP,
1486 1481                                              errbuf);
1487 1482                                          goto error;
1488 1483                                  }
1489 1484                                  break;
1490 1485  
1491 1486                          case ZFS_PROP_REFRESERVATION:
1492 1487                                  if (intval > volsize && intval != UINT64_MAX) {
1493 1488                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1494 1489                                              "'%s' is greater than current "
1495 1490                                              "volume size"), propname);
1496 1491                                          (void) zfs_error(hdl, EZFS_BADPROP,
1497 1492                                              errbuf);
1498 1493                                          goto error;
1499 1494                                  }
1500 1495                                  break;
1501 1496  
1502 1497                          case ZFS_PROP_VOLSIZE:
1503 1498                                  if (intval % blocksize != 0) {
1504 1499                                          zfs_nicenum(blocksize, buf,
1505 1500                                              sizeof (buf));
1506 1501                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1507 1502                                              "'%s' must be a multiple of "
1508 1503                                              "volume block size (%s)"),
1509 1504                                              propname, buf);
1510 1505                                          (void) zfs_error(hdl, EZFS_BADPROP,
1511 1506                                              errbuf);
1512 1507                                          goto error;
1513 1508                                  }
1514 1509  
1515 1510                                  if (intval == 0) {
1516 1511                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1517 1512                                              "'%s' cannot be zero"),
1518 1513                                              propname);
1519 1514                                          (void) zfs_error(hdl, EZFS_BADPROP,
1520 1515                                              errbuf);
1521 1516                                          goto error;
1522 1517                                  }
1523 1518                                  break;
1524 1519  
1525 1520                          default:
1526 1521                                  break;
1527 1522                          }
1528 1523                  }
1529 1524  
1530 1525                  /* check encryption properties */
1531 1526                  if (zhp != NULL) {
1532 1527                          int64_t crypt = zfs_prop_get_int(zhp,
1533 1528                              ZFS_PROP_ENCRYPTION);
1534 1529  
1535 1530                          switch (prop) {
1536 1531                          case ZFS_PROP_COPIES:
1537 1532                                  if (crypt != ZIO_CRYPT_OFF && intval > 2) {
1538 1533                                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1539 1534                                              "encrypted datasets cannot have "
1540 1535                                              "3 copies"));
1541 1536                                          (void) zfs_error(hdl, EZFS_BADPROP,
1542 1537                                              errbuf);
1543 1538                                          goto error;
1544 1539                                  }
1545 1540                                  break;
1546 1541                          default:
1547 1542                                  break;
1548 1543                          }
1549 1544                  }
1550 1545          }
1551 1546  
1552 1547          /*
1553 1548           * If normalization was chosen, but no UTF8 choice was made,
1554 1549           * enforce rejection of non-UTF8 names.
1555 1550           *
1556 1551           * If normalization was chosen, but rejecting non-UTF8 names
1557 1552           * was explicitly not chosen, it is an error.
1558 1553           */
1559 1554          if (chosen_normal > 0 && chosen_utf < 0) {
1560 1555                  if (nvlist_add_uint64(ret,
1561 1556                      zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
1562 1557                          (void) no_memory(hdl);
1563 1558                          goto error;
1564 1559                  }
1565 1560          } else if (chosen_normal > 0 && chosen_utf == 0) {
1566 1561                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1567 1562                      "'%s' must be set 'on' if normalization chosen"),
1568 1563                      zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
1569 1564                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1570 1565                  goto error;
1571 1566          }
1572 1567          return (ret);
1573 1568  
1574 1569  error:
1575 1570          nvlist_free(ret);
1576 1571          return (NULL);
1577 1572  }
1578 1573  
1579 1574  int
1580 1575  zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1581 1576  {
1582 1577          uint64_t old_volsize;
1583 1578          uint64_t new_volsize;
1584 1579          uint64_t old_reservation;
1585 1580          uint64_t new_reservation;
1586 1581          zfs_prop_t resv_prop;
1587 1582          nvlist_t *props;
1588 1583          zpool_handle_t *zph = zpool_handle(zhp);
1589 1584  
1590 1585          /*
1591 1586           * If this is an existing volume, and someone is setting the volsize,
1592 1587           * make sure that it matches the reservation, or add it if necessary.
1593 1588           */
1594 1589          old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1595 1590          if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
1596 1591                  return (-1);
1597 1592          old_reservation = zfs_prop_get_int(zhp, resv_prop);
1598 1593  
1599 1594          props = fnvlist_alloc();
1600 1595          fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1601 1596              zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
1602 1597  
1603 1598          if ((zvol_volsize_to_reservation(zph, old_volsize, props) !=
1604 1599              old_reservation) || nvlist_exists(nvl,
1605 1600              zfs_prop_to_name(resv_prop))) {
1606 1601                  fnvlist_free(props);
1607 1602                  return (0);
1608 1603          }
1609 1604          if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1610 1605              &new_volsize) != 0) {
1611 1606                  fnvlist_free(props);
1612 1607                  return (-1);
1613 1608          }
1614 1609          new_reservation = zvol_volsize_to_reservation(zph, new_volsize, props);
1615 1610          fnvlist_free(props);
1616 1611  
1617 1612          if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
1618 1613              new_reservation) != 0) {
1619 1614                  (void) no_memory(zhp->zfs_hdl);
1620 1615                  return (-1);
1621 1616          }
1622 1617          return (1);
1623 1618  }
1624 1619  
1625 1620  /*
1626 1621   * Helper for 'zfs {set|clone} refreservation=auto'.  Must be called after
1627 1622   * zfs_valid_proplist(), as it is what sets the UINT64_MAX sentinal value.
1628 1623   * Return codes must match zfs_add_synthetic_resv().
1629 1624   */
1630 1625  static int
1631 1626  zfs_fix_auto_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1632 1627  {
1633 1628          uint64_t volsize;
1634 1629          uint64_t resvsize;
1635 1630          zfs_prop_t prop;
1636 1631          nvlist_t *props;
1637 1632  
1638 1633          if (!ZFS_IS_VOLUME(zhp)) {
1639 1634                  return (0);
1640 1635          }
1641 1636  
1642 1637          if (zfs_which_resv_prop(zhp, &prop) != 0) {
1643 1638                  return (-1);
1644 1639          }
1645 1640  
1646 1641          if (prop != ZFS_PROP_REFRESERVATION) {
1647 1642                  return (0);
1648 1643          }
1649 1644  
1650 1645          if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(prop), &resvsize) != 0) {
1651 1646                  /* No value being set, so it can't be "auto" */
1652 1647                  return (0);
1653 1648          }
1654 1649          if (resvsize != UINT64_MAX) {
1655 1650                  /* Being set to a value other than "auto" */
1656 1651                  return (0);
1657 1652          }
1658 1653  
1659 1654          props = fnvlist_alloc();
1660 1655  
1661 1656          fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1662 1657              zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
1663 1658  
1664 1659          if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1665 1660              &volsize) != 0) {
1666 1661                  volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1667 1662          }
1668 1663  
1669 1664          resvsize = zvol_volsize_to_reservation(zpool_handle(zhp), volsize,
1670 1665              props);
1671 1666          fnvlist_free(props);
1672 1667  
1673 1668          (void) nvlist_remove_all(nvl, zfs_prop_to_name(prop));
1674 1669          if (nvlist_add_uint64(nvl, zfs_prop_to_name(prop), resvsize) != 0) {
1675 1670                  (void) no_memory(zhp->zfs_hdl);
1676 1671                  return (-1);
1677 1672          }
1678 1673          return (1);
1679 1674  }
1680 1675  
1681 1676  void
1682 1677  zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
1683 1678      char *errbuf)
1684 1679  {
1685 1680          switch (err) {
1686 1681  
1687 1682          case ENOSPC:
1688 1683                  /*
1689 1684                   * For quotas and reservations, ENOSPC indicates
1690 1685                   * something different; setting a quota or reservation
1691 1686                   * doesn't use any disk space.
1692 1687                   */
1693 1688                  switch (prop) {
1694 1689                  case ZFS_PROP_QUOTA:
1695 1690                  case ZFS_PROP_REFQUOTA:
1696 1691                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1697 1692                              "size is less than current used or "
1698 1693                              "reserved space"));
1699 1694                          (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1700 1695                          break;
1701 1696  
1702 1697                  case ZFS_PROP_RESERVATION:
1703 1698                  case ZFS_PROP_REFRESERVATION:
1704 1699                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1705 1700                              "size is greater than available space"));
1706 1701                          (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1707 1702                          break;
1708 1703  
1709 1704                  default:
1710 1705                          (void) zfs_standard_error(hdl, err, errbuf);
1711 1706                          break;
1712 1707                  }
1713 1708                  break;
1714 1709  
1715 1710          case EBUSY:
1716 1711                  (void) zfs_standard_error(hdl, EBUSY, errbuf);
1717 1712                  break;
1718 1713  
1719 1714          case EROFS:
1720 1715                  (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
1721 1716                  break;
1722 1717  
1723 1718          case E2BIG:
1724 1719                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1725 1720                      "property value too long"));
1726 1721                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1727 1722                  break;
1728 1723  
1729 1724          case ENOTSUP:
1730 1725                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1731 1726                      "pool and or dataset must be upgraded to set this "
1732 1727                      "property or value"));
1733 1728                  (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
1734 1729                  break;
1735 1730  
1736 1731          case ERANGE:
1737 1732                  if (prop == ZFS_PROP_COMPRESSION ||
1738 1733                      prop == ZFS_PROP_RECORDSIZE) {
1739 1734                          (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1740 1735                              "property setting is not allowed on "
1741 1736                              "bootable datasets"));
1742 1737                          (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
1743 1738                  } else if (prop == ZFS_PROP_CHECKSUM ||
1744 1739                      prop == ZFS_PROP_DEDUP) {
1745 1740                          (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1746 1741                              "property setting is not allowed on "
1747 1742                              "root pools"));
1748 1743                          (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
1749 1744                  } else {
1750 1745                          (void) zfs_standard_error(hdl, err, errbuf);
1751 1746                  }
1752 1747                  break;
1753 1748  
1754 1749          case EINVAL:
1755 1750                  if (prop == ZPROP_INVAL) {
1756 1751                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1757 1752                  } else {
1758 1753                          (void) zfs_standard_error(hdl, err, errbuf);
1759 1754                  }
1760 1755                  break;
1761 1756  
1762 1757          case EACCES:
1763 1758                  if (prop == ZFS_PROP_KEYLOCATION) {
1764 1759                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1765 1760                              "keylocation may only be set on encryption roots"));
1766 1761                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1767 1762                  } else {
1768 1763                          (void) zfs_standard_error(hdl, err, errbuf);
1769 1764                  }
1770 1765                  break;
1771 1766  
1772 1767          case EOVERFLOW:
1773 1768                  /*
1774 1769                   * This platform can't address a volume this big.
1775 1770                   */
1776 1771  #ifdef _ILP32
1777 1772                  if (prop == ZFS_PROP_VOLSIZE) {
1778 1773                          (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
1779 1774                          break;
1780 1775                  }
1781 1776  #endif
1782 1777                  /* FALLTHROUGH */
1783 1778          default:
1784 1779                  (void) zfs_standard_error(hdl, err, errbuf);
1785 1780          }
1786 1781  }
1787 1782  
1788 1783  /*
1789 1784   * Given a property name and value, set the property for the given dataset.
1790 1785   */
1791 1786  int
1792 1787  zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1793 1788  {
1794 1789          int ret = -1;
1795 1790          char errbuf[1024];
1796 1791          libzfs_handle_t *hdl = zhp->zfs_hdl;
1797 1792          nvlist_t *nvl = NULL;
1798 1793  
1799 1794          (void) snprintf(errbuf, sizeof (errbuf),
1800 1795              dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1801 1796              zhp->zfs_name);
1802 1797  
1803 1798          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
1804 1799              nvlist_add_string(nvl, propname, propval) != 0) {
1805 1800                  (void) no_memory(hdl);
1806 1801                  goto error;
1807 1802          }
1808 1803  
1809 1804          ret = zfs_prop_set_list(zhp, nvl);
1810 1805  
1811 1806  error:
1812 1807          nvlist_free(nvl);
1813 1808          return (ret);
1814 1809  }
1815 1810  
1816 1811  
1817 1812  
1818 1813  /*
1819 1814   * Given an nvlist of property names and values, set the properties for the
1820 1815   * given dataset.
1821 1816   */
1822 1817  int
1823 1818  zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
1824 1819  {
1825 1820          zfs_cmd_t zc = { 0 };
1826 1821          int ret = -1;
1827 1822          prop_changelist_t **cls = NULL;
1828 1823          int cl_idx;
1829 1824          char errbuf[1024];
1830 1825          libzfs_handle_t *hdl = zhp->zfs_hdl;
1831 1826          nvlist_t *nvl;
1832 1827          int nvl_len;
1833 1828          int added_resv = 0;
1834 1829  
1835 1830          (void) snprintf(errbuf, sizeof (errbuf),
1836 1831              dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1837 1832              zhp->zfs_name);
1838 1833  
1839 1834          if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
1840 1835              zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
1841 1836              B_FALSE, errbuf)) == NULL)
1842 1837                  goto error;
1843 1838  
1844 1839          /*
1845 1840           * We have to check for any extra properties which need to be added
1846 1841           * before computing the length of the nvlist.
1847 1842           */
1848 1843          for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1849 1844              elem != NULL;
1850 1845              elem = nvlist_next_nvpair(nvl, elem)) {
1851 1846                  if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
1852 1847                      (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
1853 1848                          goto error;
1854 1849                  }
1855 1850          }
1856 1851  
1857 1852          if (added_resv != 1 &&
1858 1853              (added_resv = zfs_fix_auto_resv(zhp, nvl)) == -1) {
1859 1854                  goto error;
1860 1855          }
1861 1856  
1862 1857          /*
1863 1858           * Check how many properties we're setting and allocate an array to
1864 1859           * store changelist pointers for postfix().
1865 1860           */
1866 1861          nvl_len = 0;
1867 1862          for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1868 1863              elem != NULL;
1869 1864              elem = nvlist_next_nvpair(nvl, elem))
1870 1865                  nvl_len++;
1871 1866          if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
1872 1867                  goto error;
1873 1868  
1874 1869          cl_idx = 0;
1875 1870          for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1876 1871              elem != NULL;
1877 1872              elem = nvlist_next_nvpair(nvl, elem)) {
1878 1873  
1879 1874                  zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
1880 1875  
1881 1876                  assert(cl_idx < nvl_len);
1882 1877                  /*
1883 1878                   * We don't want to unmount & remount the dataset when changing
1884 1879                   * its canmount property to 'on' or 'noauto'.  We only use
1885 1880                   * the changelist logic to unmount when setting canmount=off.
1886 1881                   */
1887 1882                  if (prop != ZFS_PROP_CANMOUNT ||
1888 1883                      (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF &&
1889 1884                      zfs_is_mounted(zhp, NULL))) {
1890 1885                          cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
1891 1886                          if (cls[cl_idx] == NULL)
1892 1887                                  goto error;
1893 1888                  }
1894 1889  
1895 1890                  if (prop == ZFS_PROP_MOUNTPOINT &&
1896 1891                      changelist_haszonedchild(cls[cl_idx])) {
1897 1892                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1898 1893                              "child dataset with inherited mountpoint is used "
1899 1894                              "in a non-global zone"));
1900 1895                          ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1901 1896                          goto error;
1902 1897                  }
1903 1898  
1904 1899                  if (cls[cl_idx] != NULL &&
1905 1900                      (ret = changelist_prefix(cls[cl_idx])) != 0)
1906 1901                          goto error;
1907 1902  
1908 1903                  cl_idx++;
1909 1904          }
1910 1905          assert(cl_idx == nvl_len);
1911 1906  
1912 1907          /*
1913 1908           * Execute the corresponding ioctl() to set this list of properties.
1914 1909           */
1915 1910          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1916 1911  
1917 1912          if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
1918 1913              (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
1919 1914                  goto error;
1920 1915  
1921 1916          ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1922 1917  
1923 1918          if (ret != 0) {
1924 1919                  if (zc.zc_nvlist_dst_filled == B_FALSE) {
1925 1920                          (void) zfs_standard_error(hdl, errno, errbuf);
1926 1921                          goto error;
1927 1922                  }
1928 1923  
1929 1924                  /* Get the list of unset properties back and report them. */
1930 1925                  nvlist_t *errorprops = NULL;
1931 1926                  if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
1932 1927                          goto error;
1933 1928                  for (nvpair_t *elem = nvlist_next_nvpair(errorprops, NULL);
1934 1929                      elem != NULL;
1935 1930                      elem = nvlist_next_nvpair(errorprops, elem)) {
1936 1931                          zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
1937 1932                          zfs_setprop_error(hdl, prop, errno, errbuf);
1938 1933                  }
1939 1934                  nvlist_free(errorprops);
1940 1935  
1941 1936                  if (added_resv && errno == ENOSPC) {
1942 1937                          /* clean up the volsize property we tried to set */
1943 1938                          uint64_t old_volsize = zfs_prop_get_int(zhp,
1944 1939                              ZFS_PROP_VOLSIZE);
1945 1940                          nvlist_free(nvl);
1946 1941                          nvl = NULL;
1947 1942                          zcmd_free_nvlists(&zc);
1948 1943  
1949 1944                          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1950 1945                                  goto error;
1951 1946                          if (nvlist_add_uint64(nvl,
1952 1947                              zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1953 1948                              old_volsize) != 0)
1954 1949                                  goto error;
1955 1950                          if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1956 1951                                  goto error;
1957 1952                          (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1958 1953                  }
1959 1954          } else {
1960 1955                  for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
1961 1956                          if (cls[cl_idx] != NULL) {
1962 1957                                  int clp_err = changelist_postfix(cls[cl_idx]);
1963 1958                                  if (clp_err != 0)
1964 1959                                          ret = clp_err;
1965 1960                          }
1966 1961                  }
1967 1962  
1968 1963                  /*
1969 1964                   * Refresh the statistics so the new property value
1970 1965                   * is reflected.
1971 1966                   */
1972 1967                  if (ret == 0)
1973 1968                          (void) get_stats(zhp);
1974 1969          }
1975 1970  
1976 1971  error:
1977 1972          nvlist_free(nvl);
1978 1973          zcmd_free_nvlists(&zc);
1979 1974          if (cls != NULL) {
1980 1975                  for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
1981 1976                          if (cls[cl_idx] != NULL)
1982 1977                                  changelist_free(cls[cl_idx]);
1983 1978                  }
1984 1979                  free(cls);
1985 1980          }
1986 1981          return (ret);
1987 1982  }
1988 1983  
1989 1984  /*
1990 1985   * Given a property, inherit the value from the parent dataset, or if received
1991 1986   * is TRUE, revert to the received value, if any.
1992 1987   */
1993 1988  int
1994 1989  zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
1995 1990  {
1996 1991          zfs_cmd_t zc = { 0 };
1997 1992          int ret;
1998 1993          prop_changelist_t *cl;
1999 1994          libzfs_handle_t *hdl = zhp->zfs_hdl;
2000 1995          char errbuf[1024];
2001 1996          zfs_prop_t prop;
2002 1997  
2003 1998          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2004 1999              "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
2005 2000  
2006 2001          zc.zc_cookie = received;
2007 2002          if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
2008 2003                  /*
2009 2004                   * For user properties, the amount of work we have to do is very
2010 2005                   * small, so just do it here.
2011 2006                   */
2012 2007                  if (!zfs_prop_user(propname)) {
2013 2008                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2014 2009                              "invalid property"));
2015 2010                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2016 2011                  }
2017 2012  
2018 2013                  (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2019 2014                  (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
2020 2015  
2021 2016                  if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
2022 2017                          return (zfs_standard_error(hdl, errno, errbuf));
2023 2018  
2024 2019                  return (0);
2025 2020          }
2026 2021  
2027 2022          /*
2028 2023           * Verify that this property is inheritable.
2029 2024           */
2030 2025          if (zfs_prop_readonly(prop))
2031 2026                  return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
2032 2027  
2033 2028          if (!zfs_prop_inheritable(prop) && !received)
2034 2029                  return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
2035 2030  
2036 2031          /*
2037 2032           * Check to see if the value applies to this type
2038 2033           */
2039 2034          if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
2040 2035                  return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
2041 2036  
2042 2037          /*
2043 2038           * Normalize the name, to get rid of shorthand abbreviations.
2044 2039           */
2045 2040          propname = zfs_prop_to_name(prop);
2046 2041          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2047 2042          (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
2048 2043  
2049 2044          if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
2050 2045              zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
2051 2046                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2052 2047                      "dataset is used in a non-global zone"));
2053 2048                  return (zfs_error(hdl, EZFS_ZONED, errbuf));
2054 2049          }
2055 2050  
2056 2051          /*
2057 2052           * Determine datasets which will be affected by this change, if any.
2058 2053           */
2059 2054          if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
2060 2055                  return (-1);
2061 2056  
2062 2057          if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
2063 2058                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2064 2059                      "child dataset with inherited mountpoint is used "
2065 2060                      "in a non-global zone"));
2066 2061                  ret = zfs_error(hdl, EZFS_ZONED, errbuf);
2067 2062                  goto error;
2068 2063          }
2069 2064  
2070 2065          if ((ret = changelist_prefix(cl)) != 0)
2071 2066                  goto error;
2072 2067  
2073 2068          if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
2074 2069                  return (zfs_standard_error(hdl, errno, errbuf));
2075 2070          } else {
2076 2071  
2077 2072                  if ((ret = changelist_postfix(cl)) != 0)
2078 2073                          goto error;
2079 2074  
2080 2075                  /*
2081 2076                   * Refresh the statistics so the new property is reflected.
2082 2077                   */
2083 2078                  (void) get_stats(zhp);
2084 2079          }
2085 2080  
2086 2081  error:
2087 2082          changelist_free(cl);
2088 2083          return (ret);
2089 2084  }
2090 2085  
2091 2086  /*
2092 2087   * True DSL properties are stored in an nvlist.  The following two functions
2093 2088   * extract them appropriately.
2094 2089   */
2095 2090  static uint64_t
2096 2091  getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
2097 2092  {
2098 2093          nvlist_t *nv;
2099 2094          uint64_t value;
2100 2095  
2101 2096          *source = NULL;
2102 2097          if (nvlist_lookup_nvlist(zhp->zfs_props,
2103 2098              zfs_prop_to_name(prop), &nv) == 0) {
2104 2099                  verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
2105 2100                  (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
2106 2101          } else {
2107 2102                  verify(!zhp->zfs_props_table ||
2108 2103                      zhp->zfs_props_table[prop] == B_TRUE);
2109 2104                  value = zfs_prop_default_numeric(prop);
2110 2105                  *source = "";
2111 2106          }
2112 2107  
2113 2108          return (value);
2114 2109  }
2115 2110  
2116 2111  static const char *
2117 2112  getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
2118 2113  {
2119 2114          nvlist_t *nv;
2120 2115          const char *value;
2121 2116  
2122 2117          *source = NULL;
2123 2118          if (nvlist_lookup_nvlist(zhp->zfs_props,
2124 2119              zfs_prop_to_name(prop), &nv) == 0) {
2125 2120                  value = fnvlist_lookup_string(nv, ZPROP_VALUE);
2126 2121                  (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
2127 2122          } else {
2128 2123                  verify(!zhp->zfs_props_table ||
2129 2124                      zhp->zfs_props_table[prop] == B_TRUE);
2130 2125                  value = zfs_prop_default_string(prop);
2131 2126                  *source = "";
2132 2127          }
2133 2128  
2134 2129          return (value);
2135 2130  }
2136 2131  
2137 2132  static boolean_t
2138 2133  zfs_is_recvd_props_mode(zfs_handle_t *zhp)
2139 2134  {
2140 2135          return (zhp->zfs_props == zhp->zfs_recvd_props);
2141 2136  }
2142 2137  
2143 2138  static void
2144 2139  zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
2145 2140  {
2146 2141          *cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
2147 2142          zhp->zfs_props = zhp->zfs_recvd_props;
2148 2143  }
2149 2144  
2150 2145  static void
2151 2146  zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
2152 2147  {
2153 2148          zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
2154 2149          *cookie = 0;
2155 2150  }
2156 2151  
2157 2152  /*
2158 2153   * Internal function for getting a numeric property.  Both zfs_prop_get() and
2159 2154   * zfs_prop_get_int() are built using this interface.
2160 2155   *
2161 2156   * Certain properties can be overridden using 'mount -o'.  In this case, scan
2162 2157   * the contents of the /etc/mnttab entry, searching for the appropriate options.
2163 2158   * If they differ from the on-disk values, report the current values and mark
2164 2159   * the source "temporary".
2165 2160   */
2166 2161  static int
2167 2162  get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
2168 2163      char **source, uint64_t *val)
2169 2164  {
2170 2165          zfs_cmd_t zc = { 0 };
2171 2166          nvlist_t *zplprops = NULL;
2172 2167          struct mnttab mnt;
2173 2168          char *mntopt_on = NULL;
2174 2169          char *mntopt_off = NULL;
2175 2170          boolean_t received = zfs_is_recvd_props_mode(zhp);
2176 2171  
2177 2172          *source = NULL;
2178 2173  
2179 2174          switch (prop) {
2180 2175          case ZFS_PROP_ATIME:
2181 2176                  mntopt_on = MNTOPT_ATIME;
2182 2177                  mntopt_off = MNTOPT_NOATIME;
2183 2178                  break;
2184 2179  
2185 2180          case ZFS_PROP_DEVICES:
2186 2181                  mntopt_on = MNTOPT_DEVICES;
2187 2182                  mntopt_off = MNTOPT_NODEVICES;
2188 2183                  break;
2189 2184  
2190 2185          case ZFS_PROP_EXEC:
2191 2186                  mntopt_on = MNTOPT_EXEC;
2192 2187                  mntopt_off = MNTOPT_NOEXEC;
2193 2188                  break;
2194 2189  
2195 2190          case ZFS_PROP_READONLY:
2196 2191                  mntopt_on = MNTOPT_RO;
2197 2192                  mntopt_off = MNTOPT_RW;
2198 2193                  break;
2199 2194  
2200 2195          case ZFS_PROP_SETUID:
2201 2196                  mntopt_on = MNTOPT_SETUID;
2202 2197                  mntopt_off = MNTOPT_NOSETUID;
2203 2198                  break;
2204 2199  
2205 2200          case ZFS_PROP_XATTR:
2206 2201                  mntopt_on = MNTOPT_XATTR;
2207 2202                  mntopt_off = MNTOPT_NOXATTR;
2208 2203                  break;
2209 2204  
2210 2205          case ZFS_PROP_NBMAND:
2211 2206                  mntopt_on = MNTOPT_NBMAND;
2212 2207                  mntopt_off = MNTOPT_NONBMAND;
2213 2208                  break;
2214 2209  
2215 2210          default:
2216 2211                  break;
2217 2212          }
2218 2213  
2219 2214          /*
2220 2215           * Because looking up the mount options is potentially expensive
2221 2216           * (iterating over all of /etc/mnttab), we defer its calculation until
2222 2217           * we're looking up a property which requires its presence.
2223 2218           */
2224 2219          if (!zhp->zfs_mntcheck &&
2225 2220              (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
2226 2221                  libzfs_handle_t *hdl = zhp->zfs_hdl;
2227 2222                  struct mnttab entry;
2228 2223  
2229 2224                  if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
2230 2225                          zhp->zfs_mntopts = zfs_strdup(hdl,
2231 2226                              entry.mnt_mntopts);
2232 2227                          if (zhp->zfs_mntopts == NULL)
2233 2228                                  return (-1);
2234 2229                  }
2235 2230  
2236 2231                  zhp->zfs_mntcheck = B_TRUE;
2237 2232          }
2238 2233  
2239 2234          if (zhp->zfs_mntopts == NULL)
2240 2235                  mnt.mnt_mntopts = "";
2241 2236          else
2242 2237                  mnt.mnt_mntopts = zhp->zfs_mntopts;
2243 2238  
2244 2239          switch (prop) {
2245 2240          case ZFS_PROP_ATIME:
2246 2241          case ZFS_PROP_DEVICES:
2247 2242          case ZFS_PROP_EXEC:
2248 2243          case ZFS_PROP_READONLY:
2249 2244          case ZFS_PROP_SETUID:
2250 2245          case ZFS_PROP_XATTR:
2251 2246          case ZFS_PROP_NBMAND:
2252 2247                  *val = getprop_uint64(zhp, prop, source);
2253 2248  
2254 2249                  if (received)
2255 2250                          break;
2256 2251  
2257 2252                  if (hasmntopt(&mnt, mntopt_on) && !*val) {
2258 2253                          *val = B_TRUE;
2259 2254                          if (src)
2260 2255                                  *src = ZPROP_SRC_TEMPORARY;
2261 2256                  } else if (hasmntopt(&mnt, mntopt_off) && *val) {
2262 2257                          *val = B_FALSE;
2263 2258                          if (src)
2264 2259                                  *src = ZPROP_SRC_TEMPORARY;
2265 2260                  }
2266 2261                  break;
2267 2262  
2268 2263          case ZFS_PROP_CANMOUNT:
2269 2264          case ZFS_PROP_VOLSIZE:
2270 2265          case ZFS_PROP_QUOTA:
2271 2266          case ZFS_PROP_REFQUOTA:
2272 2267          case ZFS_PROP_RESERVATION:
2273 2268          case ZFS_PROP_REFRESERVATION:
2274 2269          case ZFS_PROP_FILESYSTEM_LIMIT:
2275 2270          case ZFS_PROP_SNAPSHOT_LIMIT:
2276 2271          case ZFS_PROP_FILESYSTEM_COUNT:
2277 2272          case ZFS_PROP_SNAPSHOT_COUNT:
2278 2273                  *val = getprop_uint64(zhp, prop, source);
2279 2274  
2280 2275                  if (*source == NULL) {
2281 2276                          /* not default, must be local */
2282 2277                          *source = zhp->zfs_name;
2283 2278                  }
2284 2279                  break;
2285 2280  
2286 2281          case ZFS_PROP_MOUNTED:
2287 2282                  *val = (zhp->zfs_mntopts != NULL);
2288 2283                  break;
2289 2284  
2290 2285          case ZFS_PROP_NUMCLONES:
2291 2286                  *val = zhp->zfs_dmustats.dds_num_clones;
2292 2287                  break;
2293 2288  
2294 2289          case ZFS_PROP_VERSION:
2295 2290          case ZFS_PROP_NORMALIZE:
2296 2291          case ZFS_PROP_UTF8ONLY:
2297 2292          case ZFS_PROP_CASE:
2298 2293                  if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
2299 2294                      zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
2300 2295                          return (-1);
2301 2296                  (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2302 2297                  if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
2303 2298                          zcmd_free_nvlists(&zc);
2304 2299                          return (-1);
2305 2300                  }
2306 2301                  if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
2307 2302                      nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
2308 2303                      val) != 0) {
2309 2304                          zcmd_free_nvlists(&zc);
2310 2305                          return (-1);
2311 2306                  }
2312 2307                  nvlist_free(zplprops);
2313 2308                  zcmd_free_nvlists(&zc);
2314 2309                  break;
2315 2310  
2316 2311          case ZFS_PROP_INCONSISTENT:
2317 2312                  *val = zhp->zfs_dmustats.dds_inconsistent;
2318 2313                  break;
2319 2314  
2320 2315          default:
2321 2316                  switch (zfs_prop_get_type(prop)) {
2322 2317                  case PROP_TYPE_NUMBER:
2323 2318                  case PROP_TYPE_INDEX:
2324 2319                          *val = getprop_uint64(zhp, prop, source);
2325 2320                          /*
2326 2321                           * If we tried to use a default value for a
2327 2322                           * readonly property, it means that it was not
2328 2323                           * present.  Note this only applies to "truly"
2329 2324                           * readonly properties, not set-once properties
2330 2325                           * like volblocksize.
2331 2326                           */
2332 2327                          if (zfs_prop_readonly(prop) &&
2333 2328                              !zfs_prop_setonce(prop) &&
2334 2329                              *source != NULL && (*source)[0] == '\0') {
2335 2330                                  *source = NULL;
2336 2331                                  return (-1);
2337 2332                          }
2338 2333                          break;
2339 2334  
2340 2335                  case PROP_TYPE_STRING:
2341 2336                  default:
2342 2337                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
2343 2338                              "cannot get non-numeric property"));
2344 2339                          return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
2345 2340                              dgettext(TEXT_DOMAIN, "internal error")));
2346 2341                  }
2347 2342          }
2348 2343  
2349 2344          return (0);
2350 2345  }
2351 2346  
2352 2347  /*
2353 2348   * Calculate the source type, given the raw source string.
2354 2349   */
2355 2350  static void
2356 2351  get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
2357 2352      char *statbuf, size_t statlen)
2358 2353  {
2359 2354          if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
2360 2355                  return;
2361 2356  
2362 2357          if (source == NULL) {
2363 2358                  *srctype = ZPROP_SRC_NONE;
2364 2359          } else if (source[0] == '\0') {
2365 2360                  *srctype = ZPROP_SRC_DEFAULT;
2366 2361          } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
2367 2362                  *srctype = ZPROP_SRC_RECEIVED;
2368 2363          } else {
2369 2364                  if (strcmp(source, zhp->zfs_name) == 0) {
2370 2365                          *srctype = ZPROP_SRC_LOCAL;
2371 2366                  } else {
2372 2367                          (void) strlcpy(statbuf, source, statlen);
2373 2368                          *srctype = ZPROP_SRC_INHERITED;
2374 2369                  }
2375 2370          }
2376 2371  
2377 2372  }
2378 2373  
2379 2374  int
2380 2375  zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
2381 2376      size_t proplen, boolean_t literal)
2382 2377  {
2383 2378          zfs_prop_t prop;
2384 2379          int err = 0;
2385 2380  
2386 2381          if (zhp->zfs_recvd_props == NULL)
2387 2382                  if (get_recvd_props_ioctl(zhp) != 0)
2388 2383                          return (-1);
2389 2384  
2390 2385          prop = zfs_name_to_prop(propname);
2391 2386  
2392 2387          if (prop != ZPROP_INVAL) {
2393 2388                  uint64_t cookie;
2394 2389                  if (!nvlist_exists(zhp->zfs_recvd_props, propname))
2395 2390                          return (-1);
2396 2391                  zfs_set_recvd_props_mode(zhp, &cookie);
2397 2392                  err = zfs_prop_get(zhp, prop, propbuf, proplen,
2398 2393                      NULL, NULL, 0, literal);
2399 2394                  zfs_unset_recvd_props_mode(zhp, &cookie);
2400 2395          } else {
2401 2396                  nvlist_t *propval;
2402 2397                  char *recvdval;
2403 2398                  if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
2404 2399                      propname, &propval) != 0)
2405 2400                          return (-1);
2406 2401                  verify(nvlist_lookup_string(propval, ZPROP_VALUE,
2407 2402                      &recvdval) == 0);
2408 2403                  (void) strlcpy(propbuf, recvdval, proplen);
2409 2404          }
2410 2405  
2411 2406          return (err == 0 ? 0 : -1);
2412 2407  }
2413 2408  
2414 2409  static int
2415 2410  get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
2416 2411  {
2417 2412          nvlist_t *value;
2418 2413          nvpair_t *pair;
2419 2414  
2420 2415          value = zfs_get_clones_nvl(zhp);
2421 2416          if (value == NULL)
2422 2417                  return (-1);
2423 2418  
2424 2419          propbuf[0] = '\0';
2425 2420          for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
2426 2421              pair = nvlist_next_nvpair(value, pair)) {
2427 2422                  if (propbuf[0] != '\0')
2428 2423                          (void) strlcat(propbuf, ",", proplen);
2429 2424                  (void) strlcat(propbuf, nvpair_name(pair), proplen);
2430 2425          }
2431 2426  
2432 2427          return (0);
2433 2428  }
2434 2429  
2435 2430  struct get_clones_arg {
2436 2431          uint64_t numclones;
2437 2432          nvlist_t *value;
2438 2433          const char *origin;
2439 2434          char buf[ZFS_MAX_DATASET_NAME_LEN];
2440 2435  };
2441 2436  
2442 2437  int
2443 2438  get_clones_cb(zfs_handle_t *zhp, void *arg)
2444 2439  {
2445 2440          struct get_clones_arg *gca = arg;
2446 2441  
2447 2442          if (gca->numclones == 0) {
2448 2443                  zfs_close(zhp);
2449 2444                  return (0);
2450 2445          }
2451 2446  
2452 2447          if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
2453 2448              NULL, NULL, 0, B_TRUE) != 0)
2454 2449                  goto out;
2455 2450          if (strcmp(gca->buf, gca->origin) == 0) {
2456 2451                  fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
2457 2452                  gca->numclones--;
2458 2453          }
2459 2454  
2460 2455  out:
2461 2456          (void) zfs_iter_children(zhp, get_clones_cb, gca);
2462 2457          zfs_close(zhp);
2463 2458          return (0);
2464 2459  }
2465 2460  
2466 2461  nvlist_t *
2467 2462  zfs_get_clones_nvl(zfs_handle_t *zhp)
2468 2463  {
2469 2464          nvlist_t *nv, *value;
2470 2465  
2471 2466          if (nvlist_lookup_nvlist(zhp->zfs_props,
2472 2467              zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
2473 2468                  struct get_clones_arg gca;
2474 2469  
2475 2470                  /*
2476 2471                   * if this is a snapshot, then the kernel wasn't able
2477 2472                   * to get the clones.  Do it by slowly iterating.
2478 2473                   */
2479 2474                  if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
2480 2475                          return (NULL);
2481 2476                  if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
2482 2477                          return (NULL);
2483 2478                  if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
2484 2479                          nvlist_free(nv);
2485 2480                          return (NULL);
2486 2481                  }
2487 2482  
2488 2483                  gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
2489 2484                  gca.value = value;
2490 2485                  gca.origin = zhp->zfs_name;
2491 2486  
2492 2487                  if (gca.numclones != 0) {
2493 2488                          zfs_handle_t *root;
2494 2489                          char pool[ZFS_MAX_DATASET_NAME_LEN];
2495 2490                          char *cp = pool;
2496 2491  
2497 2492                          /* get the pool name */
2498 2493                          (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
2499 2494                          (void) strsep(&cp, "/@");
2500 2495                          root = zfs_open(zhp->zfs_hdl, pool,
2501 2496                              ZFS_TYPE_FILESYSTEM);
2502 2497  
2503 2498                          (void) get_clones_cb(root, &gca);
2504 2499                  }
2505 2500  
2506 2501                  if (gca.numclones != 0 ||
2507 2502                      nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
2508 2503                      nvlist_add_nvlist(zhp->zfs_props,
2509 2504                      zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
2510 2505                          nvlist_free(nv);
2511 2506                          nvlist_free(value);
2512 2507                          return (NULL);
2513 2508                  }
2514 2509                  nvlist_free(nv);
2515 2510                  nvlist_free(value);
2516 2511                  verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
2517 2512                      zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
2518 2513          }
2519 2514  
2520 2515          verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
2521 2516  
2522 2517          return (value);
2523 2518  }
2524 2519  
2525 2520  /*
2526 2521   * Accepts a property and value and checks that the value
2527 2522   * matches the one found by the channel program. If they are
2528 2523   * not equal, print both of them.
2529 2524   */
2530 2525  void
2531 2526  zcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval,
2532 2527      const char *strval)
2533 2528  {
2534 2529          if (!zhp->zfs_hdl->libzfs_prop_debug)
2535 2530                  return;
2536 2531          int error;
2537 2532          char *poolname = zhp->zpool_hdl->zpool_name;
2538 2533          const char *program =
2539 2534              "args = ...\n"
2540 2535              "ds = args['dataset']\n"
2541 2536              "prop = args['property']\n"
2542 2537              "value, setpoint = zfs.get_prop(ds, prop)\n"
2543 2538              "return {value=value, setpoint=setpoint}\n";
2544 2539          nvlist_t *outnvl;
2545 2540          nvlist_t *retnvl;
2546 2541          nvlist_t *argnvl = fnvlist_alloc();
2547 2542  
2548 2543          fnvlist_add_string(argnvl, "dataset", zhp->zfs_name);
2549 2544          fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop));
2550 2545  
2551 2546          error = lzc_channel_program_nosync(poolname, program,
2552 2547              10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl);
2553 2548  
2554 2549          if (error == 0) {
2555 2550                  retnvl = fnvlist_lookup_nvlist(outnvl, "return");
2556 2551                  if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) {
2557 2552                          int64_t ans;
2558 2553                          error = nvlist_lookup_int64(retnvl, "value", &ans);
2559 2554                          if (error != 0) {
2560 2555                                  (void) fprintf(stderr, "zcp check error: %u\n",
2561 2556                                      error);
2562 2557                                  return;
2563 2558                          }
2564 2559                          if (ans != intval) {
2565 2560                                  (void) fprintf(stderr,
2566 2561                                      "%s: zfs found %lld, but zcp found %lld\n",
2567 2562                                      zfs_prop_to_name(prop),
2568 2563                                      (longlong_t)intval, (longlong_t)ans);
2569 2564                          }
2570 2565                  } else {
2571 2566                          char *str_ans;
2572 2567                          error = nvlist_lookup_string(retnvl, "value", &str_ans);
2573 2568                          if (error != 0) {
2574 2569                                  (void) fprintf(stderr, "zcp check error: %u\n",
2575 2570                                      error);
2576 2571                                  return;
2577 2572                          }
2578 2573                          if (strcmp(strval, str_ans) != 0) {
2579 2574                                  (void) fprintf(stderr,
2580 2575                                      "%s: zfs found %s, but zcp found %s\n",
2581 2576                                      zfs_prop_to_name(prop),
2582 2577                                      strval, str_ans);
2583 2578                          }
2584 2579                  }
2585 2580          } else {
2586 2581                  (void) fprintf(stderr,
2587 2582                      "zcp check failed, channel program error: %u\n", error);
2588 2583          }
2589 2584          nvlist_free(argnvl);
2590 2585          nvlist_free(outnvl);
2591 2586  }
2592 2587  
2593 2588  /*
2594 2589   * Retrieve a property from the given object.  If 'literal' is specified, then
2595 2590   * numbers are left as exact values.  Otherwise, numbers are converted to a
2596 2591   * human-readable form.
2597 2592   *
2598 2593   * Returns 0 on success, or -1 on error.
2599 2594   */
2600 2595  int
2601 2596  zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
2602 2597      zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
2603 2598  {
2604 2599          char *source = NULL;
2605 2600          uint64_t val;
2606 2601          const char *str;
2607 2602          const char *strval;
2608 2603          boolean_t received = zfs_is_recvd_props_mode(zhp);
2609 2604  
2610 2605          /*
2611 2606           * Check to see if this property applies to our object
2612 2607           */
2613 2608          if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
2614 2609                  return (-1);
2615 2610  
2616 2611          if (received && zfs_prop_readonly(prop))
2617 2612                  return (-1);
2618 2613  
2619 2614          if (src)
2620 2615                  *src = ZPROP_SRC_NONE;
2621 2616  
2622 2617          switch (prop) {
2623 2618          case ZFS_PROP_CREATION:
2624 2619                  /*
2625 2620                   * 'creation' is a time_t stored in the statistics.  We convert
2626 2621                   * this into a string unless 'literal' is specified.
2627 2622                   */
2628 2623                  {
2629 2624                          val = getprop_uint64(zhp, prop, &source);
2630 2625                          time_t time = (time_t)val;
2631 2626                          struct tm t;
2632 2627  
2633 2628                          if (literal ||
2634 2629                              localtime_r(&time, &t) == NULL ||
2635 2630                              strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
2636 2631                              &t) == 0)
2637 2632                                  (void) snprintf(propbuf, proplen, "%llu", val);
2638 2633                  }
2639 2634                  zcp_check(zhp, prop, val, NULL);
2640 2635                  break;
2641 2636  
2642 2637          case ZFS_PROP_MOUNTPOINT:
2643 2638                  /*
2644 2639                   * Getting the precise mountpoint can be tricky.
2645 2640                   *
2646 2641                   *  - for 'none' or 'legacy', return those values.
2647 2642                   *  - for inherited mountpoints, we want to take everything
2648 2643                   *    after our ancestor and append it to the inherited value.
2649 2644                   *
2650 2645                   * If the pool has an alternate root, we want to prepend that
2651 2646                   * root to any values we return.
2652 2647                   */
2653 2648  
2654 2649                  str = getprop_string(zhp, prop, &source);
2655 2650  
2656 2651                  if (str[0] == '/') {
2657 2652                          char buf[MAXPATHLEN];
2658 2653                          char *root = buf;
2659 2654                          const char *relpath;
2660 2655  
2661 2656                          /*
2662 2657                           * If we inherit the mountpoint, even from a dataset
2663 2658                           * with a received value, the source will be the path of
2664 2659                           * the dataset we inherit from. If source is
2665 2660                           * ZPROP_SOURCE_VAL_RECVD, the received value is not
2666 2661                           * inherited.
2667 2662                           */
2668 2663                          if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
2669 2664                                  relpath = "";
2670 2665                          } else {
2671 2666                                  relpath = zhp->zfs_name + strlen(source);
2672 2667                                  if (relpath[0] == '/')
2673 2668                                          relpath++;
2674 2669                          }
2675 2670  
2676 2671                          if ((zpool_get_prop(zhp->zpool_hdl,
2677 2672                              ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
2678 2673                              B_FALSE)) || (strcmp(root, "-") == 0))
2679 2674                                  root[0] = '\0';
2680 2675                          /*
2681 2676                           * Special case an alternate root of '/'. This will
2682 2677                           * avoid having multiple leading slashes in the
2683 2678                           * mountpoint path.
2684 2679                           */
2685 2680                          if (strcmp(root, "/") == 0)
2686 2681                                  root++;
2687 2682  
2688 2683                          /*
2689 2684                           * If the mountpoint is '/' then skip over this
2690 2685                           * if we are obtaining either an alternate root or
2691 2686                           * an inherited mountpoint.
2692 2687                           */
2693 2688                          if (str[1] == '\0' && (root[0] != '\0' ||
2694 2689                              relpath[0] != '\0'))
2695 2690                                  str++;
2696 2691  
2697 2692                          if (relpath[0] == '\0')
2698 2693                                  (void) snprintf(propbuf, proplen, "%s%s",
2699 2694                                      root, str);
2700 2695                          else
2701 2696                                  (void) snprintf(propbuf, proplen, "%s%s%s%s",
2702 2697                                      root, str, relpath[0] == '@' ? "" : "/",
2703 2698                                      relpath);
2704 2699                  } else {
2705 2700                          /* 'legacy' or 'none' */
2706 2701                          (void) strlcpy(propbuf, str, proplen);
2707 2702                  }
2708 2703                  zcp_check(zhp, prop, 0, propbuf);
2709 2704                  break;
2710 2705  
2711 2706          case ZFS_PROP_ORIGIN:
2712 2707                  str = getprop_string(zhp, prop, &source);
2713 2708                  if (str == NULL)
2714 2709                          return (-1);
2715 2710                  (void) strlcpy(propbuf, str, proplen);
2716 2711                  zcp_check(zhp, prop, 0, str);
2717 2712                  break;
2718 2713  
2719 2714          case ZFS_PROP_CLONES:
2720 2715                  if (get_clones_string(zhp, propbuf, proplen) != 0)
2721 2716                          return (-1);
2722 2717                  break;
2723 2718  
2724 2719          case ZFS_PROP_QUOTA:
2725 2720          case ZFS_PROP_REFQUOTA:
2726 2721          case ZFS_PROP_RESERVATION:
2727 2722          case ZFS_PROP_REFRESERVATION:
2728 2723  
2729 2724                  if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2730 2725                          return (-1);
2731 2726                  /*
2732 2727                   * If quota or reservation is 0, we translate this into 'none'
2733 2728                   * (unless literal is set), and indicate that it's the default
2734 2729                   * value.  Otherwise, we print the number nicely and indicate
2735 2730                   * that its set locally.
2736 2731                   */
2737 2732                  if (val == 0) {
2738 2733                          if (literal)
2739 2734                                  (void) strlcpy(propbuf, "0", proplen);
2740 2735                          else
2741 2736                                  (void) strlcpy(propbuf, "none", proplen);
2742 2737                  } else {
2743 2738                          if (literal)
2744 2739                                  (void) snprintf(propbuf, proplen, "%llu",
2745 2740                                      (u_longlong_t)val);
2746 2741                          else
2747 2742                                  zfs_nicenum(val, propbuf, proplen);
2748 2743                  }
2749 2744                  zcp_check(zhp, prop, val, NULL);
2750 2745                  break;
2751 2746  
2752 2747          case ZFS_PROP_FILESYSTEM_LIMIT:
2753 2748          case ZFS_PROP_SNAPSHOT_LIMIT:
2754 2749          case ZFS_PROP_FILESYSTEM_COUNT:
2755 2750          case ZFS_PROP_SNAPSHOT_COUNT:
2756 2751  
2757 2752                  if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2758 2753                          return (-1);
2759 2754  
2760 2755                  /*
2761 2756                   * If limit is UINT64_MAX, we translate this into 'none' (unless
2762 2757                   * literal is set), and indicate that it's the default value.
2763 2758                   * Otherwise, we print the number nicely and indicate that it's
2764 2759                   * set locally.
2765 2760                   */
2766 2761                  if (literal) {
2767 2762                          (void) snprintf(propbuf, proplen, "%llu",
2768 2763                              (u_longlong_t)val);
2769 2764                  } else if (val == UINT64_MAX) {
2770 2765                          (void) strlcpy(propbuf, "none", proplen);
2771 2766                  } else {
2772 2767                          zfs_nicenum(val, propbuf, proplen);
2773 2768                  }
2774 2769  
2775 2770                  zcp_check(zhp, prop, val, NULL);
2776 2771                  break;
2777 2772  
2778 2773          case ZFS_PROP_REFRATIO:
2779 2774          case ZFS_PROP_COMPRESSRATIO:
2780 2775                  if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2781 2776                          return (-1);
2782 2777                  (void) snprintf(propbuf, proplen, "%llu.%02llux",
2783 2778                      (u_longlong_t)(val / 100),
2784 2779                      (u_longlong_t)(val % 100));
2785 2780                  zcp_check(zhp, prop, val, NULL);
2786 2781                  break;
2787 2782  
2788 2783          case ZFS_PROP_TYPE:
2789 2784                  switch (zhp->zfs_type) {
2790 2785                  case ZFS_TYPE_FILESYSTEM:
2791 2786                          str = "filesystem";
2792 2787                          break;
2793 2788                  case ZFS_TYPE_VOLUME:
2794 2789                          str = "volume";
2795 2790                          break;
2796 2791                  case ZFS_TYPE_SNAPSHOT:
2797 2792                          str = "snapshot";
2798 2793                          break;
2799 2794                  case ZFS_TYPE_BOOKMARK:
2800 2795                          str = "bookmark";
2801 2796                          break;
2802 2797                  default:
2803 2798                          abort();
2804 2799                  }
2805 2800                  (void) snprintf(propbuf, proplen, "%s", str);
2806 2801                  zcp_check(zhp, prop, 0, propbuf);
2807 2802                  break;
2808 2803  
2809 2804          case ZFS_PROP_MOUNTED:
2810 2805                  /*
2811 2806                   * The 'mounted' property is a pseudo-property that described
2812 2807                   * whether the filesystem is currently mounted.  Even though
2813 2808                   * it's a boolean value, the typical values of "on" and "off"
2814 2809                   * don't make sense, so we translate to "yes" and "no".
2815 2810                   */
2816 2811                  if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
2817 2812                      src, &source, &val) != 0)
2818 2813                          return (-1);
2819 2814                  if (val)
2820 2815                          (void) strlcpy(propbuf, "yes", proplen);
2821 2816                  else
2822 2817                          (void) strlcpy(propbuf, "no", proplen);
2823 2818                  break;
2824 2819  
2825 2820          case ZFS_PROP_NAME:
2826 2821                  /*
2827 2822                   * The 'name' property is a pseudo-property derived from the
2828 2823                   * dataset name.  It is presented as a real property to simplify
2829 2824                   * consumers.
2830 2825                   */
2831 2826                  (void) strlcpy(propbuf, zhp->zfs_name, proplen);
2832 2827                  zcp_check(zhp, prop, 0, propbuf);
2833 2828                  break;
2834 2829  
2835 2830          case ZFS_PROP_MLSLABEL:
2836 2831                  {
2837 2832                          m_label_t *new_sl = NULL;
2838 2833                          char *ascii = NULL;     /* human readable label */
2839 2834  
2840 2835                          (void) strlcpy(propbuf,
2841 2836                              getprop_string(zhp, prop, &source), proplen);
2842 2837  
2843 2838                          if (literal || (strcasecmp(propbuf,
2844 2839                              ZFS_MLSLABEL_DEFAULT) == 0))
2845 2840                                  break;
2846 2841  
2847 2842                          /*
2848 2843                           * Try to translate the internal hex string to
2849 2844                           * human-readable output.  If there are any
2850 2845                           * problems just use the hex string.
2851 2846                           */
2852 2847  
2853 2848                          if (str_to_label(propbuf, &new_sl, MAC_LABEL,
2854 2849                              L_NO_CORRECTION, NULL) == -1) {
2855 2850                                  m_label_free(new_sl);
2856 2851                                  break;
2857 2852                          }
2858 2853  
2859 2854                          if (label_to_str(new_sl, &ascii, M_LABEL,
2860 2855                              DEF_NAMES) != 0) {
2861 2856                                  if (ascii)
2862 2857                                          free(ascii);
2863 2858                                  m_label_free(new_sl);
2864 2859                                  break;
2865 2860                          }
2866 2861                          m_label_free(new_sl);
2867 2862  
2868 2863                          (void) strlcpy(propbuf, ascii, proplen);
2869 2864                          free(ascii);
2870 2865                  }
2871 2866                  break;
2872 2867  
2873 2868          case ZFS_PROP_GUID:
2874 2869          case ZFS_PROP_CREATETXG:
2875 2870                  /*
2876 2871                   * GUIDs are stored as numbers, but they are identifiers.
2877 2872                   * We don't want them to be pretty printed, because pretty
2878 2873                   * printing mangles the ID into a truncated and useless value.
2879 2874                   */
2880 2875                  if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2881 2876                          return (-1);
2882 2877                  (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
2883 2878                  zcp_check(zhp, prop, val, NULL);
2884 2879                  break;
2885 2880  
2886 2881          default:
2887 2882                  switch (zfs_prop_get_type(prop)) {
2888 2883                  case PROP_TYPE_NUMBER:
2889 2884                          if (get_numeric_property(zhp, prop, src,
2890 2885                              &source, &val) != 0) {
2891 2886                                  return (-1);
2892 2887                          }
2893 2888  
2894 2889                          if (literal) {
2895 2890                                  (void) snprintf(propbuf, proplen, "%llu",
2896 2891                                      (u_longlong_t)val);
2897 2892                          } else {
2898 2893                                  zfs_nicenum(val, propbuf, proplen);
2899 2894                          }
2900 2895                          zcp_check(zhp, prop, val, NULL);
2901 2896                          break;
2902 2897  
2903 2898                  case PROP_TYPE_STRING:
2904 2899                          str = getprop_string(zhp, prop, &source);
2905 2900                          if (str == NULL)
2906 2901                                  return (-1);
2907 2902  
2908 2903                          (void) strlcpy(propbuf, str, proplen);
2909 2904                          zcp_check(zhp, prop, 0, str);
2910 2905                          break;
2911 2906  
2912 2907                  case PROP_TYPE_INDEX:
2913 2908                          if (get_numeric_property(zhp, prop, src,
2914 2909                              &source, &val) != 0)
2915 2910                                  return (-1);
2916 2911                          if (zfs_prop_index_to_string(prop, val, &strval) != 0)
2917 2912                                  return (-1);
2918 2913  
2919 2914                          (void) strlcpy(propbuf, strval, proplen);
2920 2915                          zcp_check(zhp, prop, 0, strval);
2921 2916                          break;
2922 2917  
2923 2918                  default:
2924 2919                          abort();
2925 2920                  }
2926 2921          }
2927 2922  
2928 2923          get_source(zhp, src, source, statbuf, statlen);
2929 2924  
2930 2925          return (0);
2931 2926  }
2932 2927  
2933 2928  /*
2934 2929   * Utility function to get the given numeric property.  Does no validation that
2935 2930   * the given property is the appropriate type; should only be used with
2936 2931   * hard-coded property types.
2937 2932   */
2938 2933  uint64_t
2939 2934  zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
2940 2935  {
2941 2936          char *source;
2942 2937          uint64_t val;
2943 2938  
2944 2939          (void) get_numeric_property(zhp, prop, NULL, &source, &val);
2945 2940  
2946 2941          return (val);
2947 2942  }
2948 2943  
2949 2944  int
2950 2945  zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
2951 2946  {
2952 2947          char buf[64];
2953 2948  
2954 2949          (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
2955 2950          return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
2956 2951  }
2957 2952  
2958 2953  /*
2959 2954   * Similar to zfs_prop_get(), but returns the value as an integer.
2960 2955   */
2961 2956  int
2962 2957  zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
2963 2958      zprop_source_t *src, char *statbuf, size_t statlen)
2964 2959  {
2965 2960          char *source;
2966 2961  
2967 2962          /*
2968 2963           * Check to see if this property applies to our object
2969 2964           */
2970 2965          if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
2971 2966                  return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
2972 2967                      dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
2973 2968                      zfs_prop_to_name(prop)));
2974 2969          }
2975 2970  
2976 2971          if (src)
2977 2972                  *src = ZPROP_SRC_NONE;
2978 2973  
2979 2974          if (get_numeric_property(zhp, prop, src, &source, value) != 0)
2980 2975                  return (-1);
2981 2976  
2982 2977          get_source(zhp, src, source, statbuf, statlen);
2983 2978  
2984 2979          return (0);
2985 2980  }
2986 2981  
2987 2982  static int
2988 2983  idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
2989 2984      char **domainp, idmap_rid_t *ridp)
2990 2985  {
2991 2986          idmap_get_handle_t *get_hdl = NULL;
2992 2987          idmap_stat status;
2993 2988          int err = EINVAL;
2994 2989  
2995 2990          if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
2996 2991                  goto out;
2997 2992  
2998 2993          if (isuser) {
2999 2994                  err = idmap_get_sidbyuid(get_hdl, id,
3000 2995                      IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
3001 2996          } else {
3002 2997                  err = idmap_get_sidbygid(get_hdl, id,
3003 2998                      IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
3004 2999          }
3005 3000          if (err == IDMAP_SUCCESS &&
3006 3001              idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
3007 3002              status == IDMAP_SUCCESS)
3008 3003                  err = 0;
3009 3004          else
3010 3005                  err = EINVAL;
3011 3006  out:
3012 3007          if (get_hdl)
3013 3008                  idmap_get_destroy(get_hdl);
3014 3009          return (err);
3015 3010  }
3016 3011  
3017 3012  /*
3018 3013   * convert the propname into parameters needed by kernel
3019 3014   * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
3020 3015   * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
3021 3016   * Eg: groupquota@staff -> ZFS_PROP_GROUPQUOTA, "", 1234
3022 3017   * Eg: groupused@staff -> ZFS_PROP_GROUPUSED, "", 1234
3023 3018   * Eg: projectquota@123 -> ZFS_PROP_PROJECTQUOTA, "", 123
3024 3019   * Eg: projectused@789 -> ZFS_PROP_PROJECTUSED, "", 789
3025 3020   */
3026 3021  static int
3027 3022  userquota_propname_decode(const char *propname, boolean_t zoned,
3028 3023      zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
3029 3024  {
3030 3025          zfs_userquota_prop_t type;
3031 3026          char *cp;
3032 3027          boolean_t isuser;
3033 3028          boolean_t isgroup;
3034 3029          boolean_t isproject;
3035 3030          struct passwd *pw;
3036 3031          struct group *gr;
3037 3032  
3038 3033          domain[0] = '\0';
3039 3034  
3040 3035          /* Figure out the property type ({user|group|project}{quota|space}) */
3041 3036          for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
3042 3037                  if (strncmp(propname, zfs_userquota_prop_prefixes[type],
3043 3038                      strlen(zfs_userquota_prop_prefixes[type])) == 0)
3044 3039                          break;
3045 3040          }
3046 3041          if (type == ZFS_NUM_USERQUOTA_PROPS)
3047 3042                  return (EINVAL);
3048 3043          *typep = type;
3049 3044  
3050 3045          isuser = (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_USERUSED ||
3051 3046              type == ZFS_PROP_USEROBJQUOTA ||
3052 3047              type == ZFS_PROP_USEROBJUSED);
3053 3048          isgroup = (type == ZFS_PROP_GROUPQUOTA || type == ZFS_PROP_GROUPUSED ||
3054 3049              type == ZFS_PROP_GROUPOBJQUOTA ||
3055 3050              type == ZFS_PROP_GROUPOBJUSED);
3056 3051          isproject = (type == ZFS_PROP_PROJECTQUOTA ||
3057 3052              type == ZFS_PROP_PROJECTUSED || type == ZFS_PROP_PROJECTOBJQUOTA ||
3058 3053              type == ZFS_PROP_PROJECTOBJUSED);
3059 3054  
3060 3055          cp = strchr(propname, '@') + 1;
3061 3056  
3062 3057          if (isuser && (pw = getpwnam(cp)) != NULL) {
3063 3058                  if (zoned && getzoneid() == GLOBAL_ZONEID)
3064 3059                          return (ENOENT);
3065 3060                  *ridp = pw->pw_uid;
3066 3061          } else if (isgroup && (gr = getgrnam(cp)) != NULL) {
3067 3062                  if (zoned && getzoneid() == GLOBAL_ZONEID)
3068 3063                          return (ENOENT);
3069 3064                  *ridp = gr->gr_gid;
3070 3065          } else if (!isproject && strchr(cp, '@')) {
3071 3066                  /*
3072 3067                   * It's a SID name (eg "user@domain") that needs to be
3073 3068                   * turned into S-1-domainID-RID.
3074 3069                   */
3075 3070                  directory_error_t e;
3076 3071                  char *numericsid = NULL;
3077 3072                  char *end;
3078 3073  
3079 3074                  if (zoned && getzoneid() == GLOBAL_ZONEID)
3080 3075                          return (ENOENT);
3081 3076                  if (isuser) {
3082 3077                          e = directory_sid_from_user_name(NULL,
3083 3078                              cp, &numericsid);
3084 3079                  } else {
3085 3080                          e = directory_sid_from_group_name(NULL,
3086 3081                              cp, &numericsid);
3087 3082                  }
3088 3083                  if (e != NULL) {
3089 3084                          directory_error_free(e);
3090 3085                          return (ENOENT);
3091 3086                  }
3092 3087                  if (numericsid == NULL)
3093 3088                          return (ENOENT);
3094 3089                  cp = numericsid;
3095 3090                  (void) strlcpy(domain, cp, domainlen);
3096 3091                  cp = strrchr(domain, '-');
3097 3092                  *cp = '\0';
3098 3093                  cp++;
3099 3094  
3100 3095                  errno = 0;
3101 3096                  *ridp = strtoull(cp, &end, 10);
3102 3097                  free(numericsid);
3103 3098  
3104 3099                  if (errno != 0 || *end != '\0')
3105 3100                          return (EINVAL);
3106 3101          } else {
3107 3102                  /* It's a user/group/project ID (eg "12345"). */
3108 3103                  char *end;
3109 3104                  uid_t id = strtoul(cp, &end, 10);
3110 3105                  if (*end != '\0')
3111 3106                          return (EINVAL);
3112 3107                  if (id > MAXUID && !isproject) {
3113 3108                          /* It's an ephemeral ID. */
3114 3109                          idmap_rid_t rid;
3115 3110                          char *mapdomain;
3116 3111  
3117 3112                          if (idmap_id_to_numeric_domain_rid(id, isuser,
3118 3113                              &mapdomain, &rid) != 0)
3119 3114                                  return (ENOENT);
3120 3115                          (void) strlcpy(domain, mapdomain, domainlen);
3121 3116                          *ridp = rid;
3122 3117                  } else {
3123 3118                          *ridp = id;
3124 3119                  }
3125 3120          }
3126 3121  
3127 3122          return (0);
3128 3123  }
3129 3124  
3130 3125  static int
3131 3126  zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
3132 3127      uint64_t *propvalue, zfs_userquota_prop_t *typep)
3133 3128  {
3134 3129          int err;
3135 3130          zfs_cmd_t zc = { 0 };
3136 3131  
3137 3132          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3138 3133  
3139 3134          err = userquota_propname_decode(propname,
3140 3135              zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
3141 3136              typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
3142 3137          zc.zc_objset_type = *typep;
3143 3138          if (err)
3144 3139                  return (err);
3145 3140  
3146 3141          err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
3147 3142          if (err)
3148 3143                  return (err);
3149 3144  
3150 3145          *propvalue = zc.zc_cookie;
3151 3146          return (0);
3152 3147  }
3153 3148  
3154 3149  int
3155 3150  zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
3156 3151      uint64_t *propvalue)
3157 3152  {
3158 3153          zfs_userquota_prop_t type;
3159 3154  
3160 3155          return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
3161 3156              &type));
3162 3157  }
3163 3158  
3164 3159  int
3165 3160  zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
3166 3161      char *propbuf, int proplen, boolean_t literal)
3167 3162  {
3168 3163          int err;
3169 3164          uint64_t propvalue;
3170 3165          zfs_userquota_prop_t type;
3171 3166  
3172 3167          err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
3173 3168              &type);
3174 3169  
3175 3170          if (err)
3176 3171                  return (err);
3177 3172  
3178 3173          if (literal) {
3179 3174                  (void) snprintf(propbuf, proplen, "%llu", propvalue);
3180 3175          } else if (propvalue == 0 &&
3181 3176              (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA ||
3182 3177              type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
3183 3178              type == ZFS_PROP_PROJECTQUOTA || ZFS_PROP_PROJECTOBJQUOTA)) {
3184 3179                  (void) strlcpy(propbuf, "none", proplen);
3185 3180          } else if (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA ||
3186 3181              type == ZFS_PROP_USERUSED || type == ZFS_PROP_GROUPUSED ||
3187 3182              type == ZFS_PROP_PROJECTUSED || type == ZFS_PROP_PROJECTQUOTA) {
3188 3183                  zfs_nicenum(propvalue, propbuf, proplen);
3189 3184          } else {
3190 3185                  zfs_nicenum(propvalue, propbuf, proplen);
3191 3186          }
3192 3187          return (0);
3193 3188  }
3194 3189  
3195 3190  int
3196 3191  zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
3197 3192      uint64_t *propvalue)
3198 3193  {
3199 3194          int err;
3200 3195          zfs_cmd_t zc = { 0 };
3201 3196          const char *snapname;
3202 3197  
3203 3198          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3204 3199  
3205 3200          snapname = strchr(propname, '@') + 1;
3206 3201          if (strchr(snapname, '@')) {
3207 3202                  (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
3208 3203          } else {
3209 3204                  /* snapname is the short name, append it to zhp's fsname */
3210 3205                  char *cp;
3211 3206  
3212 3207                  (void) strlcpy(zc.zc_value, zhp->zfs_name,
3213 3208                      sizeof (zc.zc_value));
3214 3209                  cp = strchr(zc.zc_value, '@');
3215 3210                  if (cp != NULL)
3216 3211                          *cp = '\0';
3217 3212                  (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
3218 3213                  (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
3219 3214          }
3220 3215  
3221 3216          err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
3222 3217          if (err)
3223 3218                  return (err);
3224 3219  
3225 3220          *propvalue = zc.zc_cookie;
3226 3221          return (0);
3227 3222  }
3228 3223  
3229 3224  int
3230 3225  zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
3231 3226      char *propbuf, int proplen, boolean_t literal)
3232 3227  {
3233 3228          int err;
3234 3229          uint64_t propvalue;
3235 3230  
3236 3231          err = zfs_prop_get_written_int(zhp, propname, &propvalue);
3237 3232  
3238 3233          if (err)
3239 3234                  return (err);
3240 3235  
3241 3236          if (literal) {
3242 3237                  (void) snprintf(propbuf, proplen, "%llu", propvalue);
3243 3238          } else {
3244 3239                  zfs_nicenum(propvalue, propbuf, proplen);
3245 3240          }
3246 3241          return (0);
3247 3242  }
3248 3243  
3249 3244  /*
3250 3245   * Returns the name of the given zfs handle.
3251 3246   */
3252 3247  const char *
3253 3248  zfs_get_name(const zfs_handle_t *zhp)
3254 3249  {
3255 3250          return (zhp->zfs_name);
3256 3251  }
3257 3252  
3258 3253  /*
3259 3254   * Returns the name of the parent pool for the given zfs handle.
3260 3255   */
3261 3256  const char *
3262 3257  zfs_get_pool_name(const zfs_handle_t *zhp)
3263 3258  {
3264 3259          return (zhp->zpool_hdl->zpool_name);
3265 3260  }
3266 3261  
3267 3262  /*
3268 3263   * Returns the type of the given zfs handle.
3269 3264   */
3270 3265  zfs_type_t
3271 3266  zfs_get_type(const zfs_handle_t *zhp)
3272 3267  {
3273 3268          return (zhp->zfs_type);
3274 3269  }
3275 3270  
3276 3271  /*
3277 3272   * Is one dataset name a child dataset of another?
3278 3273   *
3279 3274   * Needs to handle these cases:
3280 3275   * Dataset 1    "a/foo"         "a/foo"         "a/foo"         "a/foo"
3281 3276   * Dataset 2    "a/fo"          "a/foobar"      "a/bar/baz"     "a/foo/bar"
3282 3277   * Descendant?  No.             No.             No.             Yes.
3283 3278   */
3284 3279  static boolean_t
3285 3280  is_descendant(const char *ds1, const char *ds2)
3286 3281  {
3287 3282          size_t d1len = strlen(ds1);
3288 3283  
3289 3284          /* ds2 can't be a descendant if it's smaller */
3290 3285          if (strlen(ds2) < d1len)
3291 3286                  return (B_FALSE);
3292 3287  
3293 3288          /* otherwise, compare strings and verify that there's a '/' char */
3294 3289          return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
3295 3290  }
3296 3291  
3297 3292  /*
3298 3293   * Given a complete name, return just the portion that refers to the parent.
3299 3294   * Will return -1 if there is no parent (path is just the name of the
3300 3295   * pool).
3301 3296   */
3302 3297  static int
3303 3298  parent_name(const char *path, char *buf, size_t buflen)
3304 3299  {
3305 3300          char *slashp;
3306 3301  
3307 3302          (void) strlcpy(buf, path, buflen);
3308 3303  
3309 3304          if ((slashp = strrchr(buf, '/')) == NULL)
3310 3305                  return (-1);
3311 3306          *slashp = '\0';
3312 3307  
3313 3308          return (0);
3314 3309  }
3315 3310  
3316 3311  int
3317 3312  zfs_parent_name(zfs_handle_t *zhp, char *buf, size_t buflen)
3318 3313  {
3319 3314          return (parent_name(zfs_get_name(zhp), buf, buflen));
3320 3315  }
3321 3316  
3322 3317  /*
3323 3318   * If accept_ancestor is false, then check to make sure that the given path has
3324 3319   * a parent, and that it exists.  If accept_ancestor is true, then find the
3325 3320   * closest existing ancestor for the given path.  In prefixlen return the
3326 3321   * length of already existing prefix of the given path.  We also fetch the
3327 3322   * 'zoned' property, which is used to validate property settings when creating
3328 3323   * new datasets.
3329 3324   */
3330 3325  static int
3331 3326  check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
3332 3327      boolean_t accept_ancestor, int *prefixlen)
3333 3328  {
3334 3329          zfs_cmd_t zc = { 0 };
3335 3330          char parent[ZFS_MAX_DATASET_NAME_LEN];
3336 3331          char *slash;
3337 3332          zfs_handle_t *zhp;
3338 3333          char errbuf[1024];
3339 3334          uint64_t is_zoned;
3340 3335  
3341 3336          (void) snprintf(errbuf, sizeof (errbuf),
3342 3337              dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
3343 3338  
3344 3339          /* get parent, and check to see if this is just a pool */
3345 3340          if (parent_name(path, parent, sizeof (parent)) != 0) {
3346 3341                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3347 3342                      "missing dataset name"));
3348 3343                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3349 3344          }
3350 3345  
3351 3346          /* check to see if the pool exists */
3352 3347          if ((slash = strchr(parent, '/')) == NULL)
3353 3348                  slash = parent + strlen(parent);
3354 3349          (void) strncpy(zc.zc_name, parent, slash - parent);
3355 3350          zc.zc_name[slash - parent] = '\0';
3356 3351          if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
3357 3352              errno == ENOENT) {
3358 3353                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3359 3354                      "no such pool '%s'"), zc.zc_name);
3360 3355                  return (zfs_error(hdl, EZFS_NOENT, errbuf));
3361 3356          }
3362 3357  
3363 3358          /* check to see if the parent dataset exists */
3364 3359          while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
3365 3360                  if (errno == ENOENT && accept_ancestor) {
3366 3361                          /*
3367 3362                           * Go deeper to find an ancestor, give up on top level.
3368 3363                           */
3369 3364                          if (parent_name(parent, parent, sizeof (parent)) != 0) {
3370 3365                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3371 3366                                      "no such pool '%s'"), zc.zc_name);
3372 3367                                  return (zfs_error(hdl, EZFS_NOENT, errbuf));
3373 3368                          }
3374 3369                  } else if (errno == ENOENT) {
3375 3370                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3376 3371                              "parent does not exist"));
3377 3372                          return (zfs_error(hdl, EZFS_NOENT, errbuf));
3378 3373                  } else
3379 3374                          return (zfs_standard_error(hdl, errno, errbuf));
3380 3375          }
3381 3376  
3382 3377          is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
3383 3378          if (zoned != NULL)
3384 3379                  *zoned = is_zoned;
3385 3380  
3386 3381          /* we are in a non-global zone, but parent is in the global zone */
3387 3382          if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
3388 3383                  (void) zfs_standard_error(hdl, EPERM, errbuf);
3389 3384                  zfs_close(zhp);
3390 3385                  return (-1);
3391 3386          }
3392 3387  
3393 3388          /* make sure parent is a filesystem */
3394 3389          if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
3395 3390                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3396 3391                      "parent is not a filesystem"));
3397 3392                  (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
3398 3393                  zfs_close(zhp);
3399 3394                  return (-1);
3400 3395          }
3401 3396  
3402 3397          zfs_close(zhp);
3403 3398          if (prefixlen != NULL)
3404 3399                  *prefixlen = strlen(parent);
3405 3400          return (0);
3406 3401  }
3407 3402  
3408 3403  /*
3409 3404   * Finds whether the dataset of the given type(s) exists.
3410 3405   */
3411 3406  boolean_t
3412 3407  zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
3413 3408  {
3414 3409          zfs_handle_t *zhp;
3415 3410  
3416 3411          if (!zfs_validate_name(hdl, path, types, B_FALSE))
3417 3412                  return (B_FALSE);
3418 3413  
3419 3414          /*
3420 3415           * Try to get stats for the dataset, which will tell us if it exists.
3421 3416           */
3422 3417          if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
3423 3418                  int ds_type = zhp->zfs_type;
3424 3419  
3425 3420                  zfs_close(zhp);
3426 3421                  if (types & ds_type)
3427 3422                          return (B_TRUE);
3428 3423          }
3429 3424          return (B_FALSE);
3430 3425  }
3431 3426  
3432 3427  /*
3433 3428   * Given a path to 'target', create all the ancestors between
3434 3429   * the prefixlen portion of the path, and the target itself.
3435 3430   * Fail if the initial prefixlen-ancestor does not already exist.
3436 3431   */
3437 3432  int
3438 3433  create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
3439 3434  {
3440 3435          zfs_handle_t *h;
3441 3436          char *cp;
3442 3437          const char *opname;
3443 3438  
3444 3439          /* make sure prefix exists */
3445 3440          cp = target + prefixlen;
3446 3441          if (*cp != '/') {
3447 3442                  assert(strchr(cp, '/') == NULL);
3448 3443                  h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3449 3444          } else {
3450 3445                  *cp = '\0';
3451 3446                  h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3452 3447                  *cp = '/';
3453 3448          }
3454 3449          if (h == NULL)
3455 3450                  return (-1);
3456 3451          zfs_close(h);
3457 3452  
3458 3453          /*
3459 3454           * Attempt to create, mount, and share any ancestor filesystems,
3460 3455           * up to the prefixlen-long one.
3461 3456           */
3462 3457          for (cp = target + prefixlen + 1;
3463 3458              (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) {
3464 3459  
3465 3460                  *cp = '\0';
3466 3461  
3467 3462                  h = make_dataset_handle(hdl, target);
3468 3463                  if (h) {
3469 3464                          /* it already exists, nothing to do here */
3470 3465                          zfs_close(h);
3471 3466                          continue;
3472 3467                  }
3473 3468  
3474 3469                  if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
3475 3470                      NULL) != 0) {
3476 3471                          opname = dgettext(TEXT_DOMAIN, "create");
3477 3472                          goto ancestorerr;
3478 3473                  }
3479 3474  
3480 3475                  h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3481 3476                  if (h == NULL) {
3482 3477                          opname = dgettext(TEXT_DOMAIN, "open");
3483 3478                          goto ancestorerr;
3484 3479                  }
3485 3480  
3486 3481                  if (zfs_mount(h, NULL, 0) != 0) {
3487 3482                          opname = dgettext(TEXT_DOMAIN, "mount");
3488 3483                          goto ancestorerr;
3489 3484                  }
3490 3485  
3491 3486                  if (zfs_share(h) != 0) {
3492 3487                          opname = dgettext(TEXT_DOMAIN, "share");
3493 3488                          goto ancestorerr;
3494 3489                  }
3495 3490  
3496 3491                  zfs_close(h);
3497 3492          }
3498 3493  
3499 3494          return (0);
3500 3495  
3501 3496  ancestorerr:
3502 3497          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3503 3498              "failed to %s ancestor '%s'"), opname, target);
3504 3499          return (-1);
3505 3500  }
3506 3501  
3507 3502  /*
3508 3503   * Creates non-existing ancestors of the given path.
3509 3504   */
3510 3505  int
3511 3506  zfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
3512 3507  {
3513 3508          int prefix;
3514 3509          char *path_copy;
3515 3510          char errbuf[1024];
3516 3511          int rc = 0;
3517 3512  
3518 3513          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3519 3514              "cannot create '%s'"), path);
3520 3515  
3521 3516          /*
3522 3517           * Check that we are not passing the nesting limit
3523 3518           * before we start creating any ancestors.
3524 3519           */
3525 3520          if (dataset_nestcheck(path) != 0) {
3526 3521                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3527 3522                      "maximum name nesting depth exceeded"));
3528 3523                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3529 3524          }
3530 3525  
3531 3526          if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
3532 3527                  return (-1);
3533 3528  
3534 3529          if ((path_copy = strdup(path)) != NULL) {
3535 3530                  rc = create_parents(hdl, path_copy, prefix);
3536 3531                  free(path_copy);
3537 3532          }
3538 3533          if (path_copy == NULL || rc != 0)
3539 3534                  return (-1);
3540 3535  
3541 3536          return (0);
3542 3537  }
3543 3538  
3544 3539  /*
3545 3540   * Create a new filesystem or volume.
3546 3541   */
3547 3542  int
3548 3543  zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
3549 3544      nvlist_t *props)
3550 3545  {
3551 3546          int ret;
3552 3547          uint64_t size = 0;
3553 3548          uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
3554 3549          uint8_t *wkeydata = NULL;
3555 3550          uint_t wkeylen = 0;
3556 3551          char errbuf[1024];
3557 3552          char parent[MAXNAMELEN];
3558 3553          uint64_t zoned;
3559 3554          enum lzc_dataset_type ost;
3560 3555          zpool_handle_t *zpool_handle;
3561 3556  
3562 3557          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3563 3558              "cannot create '%s'"), path);
3564 3559  
3565 3560          /* validate the path, taking care to note the extended error message */
3566 3561          if (!zfs_validate_name(hdl, path, type, B_TRUE))
3567 3562                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3568 3563  
3569 3564          if (dataset_nestcheck(path) != 0) {
3570 3565                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3571 3566                      "maximum name nesting depth exceeded"));
3572 3567                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3573 3568          }
3574 3569  
3575 3570          /* validate parents exist */
3576 3571          if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
3577 3572                  return (-1);
3578 3573  
3579 3574          /*
3580 3575           * The failure modes when creating a dataset of a different type over
3581 3576           * one that already exists is a little strange.  In particular, if you
3582 3577           * try to create a dataset on top of an existing dataset, the ioctl()
3583 3578           * will return ENOENT, not EEXIST.  To prevent this from happening, we
3584 3579           * first try to see if the dataset exists.
3585 3580           */
3586 3581          if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
3587 3582                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3588 3583                      "dataset already exists"));
3589 3584                  return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3590 3585          }
3591 3586  
3592 3587          if (type == ZFS_TYPE_VOLUME)
3593 3588                  ost = LZC_DATSET_TYPE_ZVOL;
3594 3589          else
3595 3590                  ost = LZC_DATSET_TYPE_ZFS;
3596 3591  
3597 3592          /* open zpool handle for prop validation */
3598 3593          char pool_path[ZFS_MAX_DATASET_NAME_LEN];
3599 3594          (void) strlcpy(pool_path, path, sizeof (pool_path));
3600 3595  
3601 3596          /* truncate pool_path at first slash */
3602 3597          char *p = strchr(pool_path, '/');
3603 3598          if (p != NULL)
3604 3599                  *p = '\0';
3605 3600  
3606 3601          if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL)
3607 3602                  return (-1);
3608 3603  
3609 3604          if (props && (props = zfs_valid_proplist(hdl, type, props,
3610 3605              zoned, NULL, zpool_handle, B_TRUE, errbuf)) == 0) {
3611 3606                  zpool_close(zpool_handle);
3612 3607                  return (-1);
3613 3608          }
3614 3609          zpool_close(zpool_handle);
3615 3610  
3616 3611          if (type == ZFS_TYPE_VOLUME) {
3617 3612                  /*
3618 3613                   * If we are creating a volume, the size and block size must
3619 3614                   * satisfy a few restraints.  First, the blocksize must be a
3620 3615                   * valid block size between SPA_{MIN,MAX}BLOCKSIZE.  Second, the
3621 3616                   * volsize must be a multiple of the block size, and cannot be
3622 3617                   * zero.
3623 3618                   */
3624 3619                  if (props == NULL || nvlist_lookup_uint64(props,
3625 3620                      zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
3626 3621                          nvlist_free(props);
3627 3622                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3628 3623                              "missing volume size"));
3629 3624                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3630 3625                  }
3631 3626  
3632 3627                  if ((ret = nvlist_lookup_uint64(props,
3633 3628                      zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
3634 3629                      &blocksize)) != 0) {
3635 3630                          if (ret == ENOENT) {
3636 3631                                  blocksize = zfs_prop_default_numeric(
3637 3632                                      ZFS_PROP_VOLBLOCKSIZE);
3638 3633                          } else {
3639 3634                                  nvlist_free(props);
3640 3635                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3641 3636                                      "missing volume block size"));
3642 3637                                  return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3643 3638                          }
3644 3639                  }
3645 3640  
3646 3641                  if (size == 0) {
3647 3642                          nvlist_free(props);
3648 3643                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3649 3644                              "volume size cannot be zero"));
3650 3645                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3651 3646                  }
3652 3647  
3653 3648                  if (size % blocksize != 0) {
3654 3649                          nvlist_free(props);
3655 3650                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3656 3651                              "volume size must be a multiple of volume block "
3657 3652                              "size"));
3658 3653                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3659 3654                  }
3660 3655          }
3661 3656  
3662 3657          (void) parent_name(path, parent, sizeof (parent));
3663 3658          if (zfs_crypto_create(hdl, parent, props, NULL, B_TRUE,
3664 3659              &wkeydata, &wkeylen) != 0) {
3665 3660                  nvlist_free(props);
3666 3661                  return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));
3667 3662          }
3668 3663  
3669 3664          /* create the dataset */
3670 3665          ret = lzc_create(path, ost, props, wkeydata, wkeylen);
3671 3666          nvlist_free(props);
3672 3667          if (wkeydata != NULL)
3673 3668                  free(wkeydata);
3674 3669  
3675 3670          /* check for failure */
3676 3671          if (ret != 0) {
3677 3672                  switch (errno) {
3678 3673                  case ENOENT:
3679 3674                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3680 3675                              "no such parent '%s'"), parent);
3681 3676                          return (zfs_error(hdl, EZFS_NOENT, errbuf));
3682 3677  
3683 3678                  case EINVAL:
3684 3679                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3685 3680                              "parent '%s' is not a filesystem"), parent);
3686 3681                          return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3687 3682  
3688 3683                  case ENOTSUP:
3689 3684                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3690 3685                              "pool must be upgraded to set this "
3691 3686                              "property or value"));
3692 3687                          return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
3693 3688                  case ERANGE:
3694 3689                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3695 3690                              "invalid property value(s) specified"));
3696 3691                          return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3697 3692                  case EACCES:
3698 3693                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3699 3694                              "encryption root's key is not loaded "
3700 3695                              "or provided"));
3701 3696                          return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));
3702 3697  
3703 3698  #ifdef _ILP32
3704 3699                  case EOVERFLOW:
3705 3700                          /*
3706 3701                           * This platform can't address a volume this big.
3707 3702                           */
3708 3703                          if (type == ZFS_TYPE_VOLUME)
3709 3704                                  return (zfs_error(hdl, EZFS_VOLTOOBIG,
3710 3705                                      errbuf));
3711 3706  #endif
3712 3707                          /* FALLTHROUGH */
3713 3708                  default:
3714 3709                          return (zfs_standard_error(hdl, errno, errbuf));
3715 3710                  }
3716 3711          }
3717 3712  
3718 3713          return (0);
3719 3714  }
3720 3715  
3721 3716  /*
3722 3717   * Destroys the given dataset.  The caller must make sure that the filesystem
3723 3718   * isn't mounted, and that there are no active dependents. If the file system
3724 3719   * does not exist this function does nothing.
3725 3720   */
3726 3721  int
3727 3722  zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
3728 3723  {
3729 3724          int error;
3730 3725  
3731 3726          if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT && defer)
3732 3727                  return (EINVAL);
3733 3728  
3734 3729          if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
3735 3730                  nvlist_t *nv = fnvlist_alloc();
3736 3731                  fnvlist_add_boolean(nv, zhp->zfs_name);
3737 3732                  error = lzc_destroy_bookmarks(nv, NULL);
3738 3733                  fnvlist_free(nv);
3739 3734                  if (error != 0) {
3740 3735                          return (zfs_standard_error_fmt(zhp->zfs_hdl, error,
3741 3736                              dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3742 3737                              zhp->zfs_name));
3743 3738                  }
3744 3739                  return (0);
3745 3740          }
3746 3741  
3747 3742          if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3748 3743                  nvlist_t *nv = fnvlist_alloc();
3749 3744                  fnvlist_add_boolean(nv, zhp->zfs_name);
3750 3745                  error = lzc_destroy_snaps(nv, defer, NULL);
3751 3746                  fnvlist_free(nv);
3752 3747          } else {
3753 3748                  error = lzc_destroy(zhp->zfs_name);
3754 3749          }
3755 3750  
3756 3751          if (error != 0 && error != ENOENT) {
3757 3752                  return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3758 3753                      dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3759 3754                      zhp->zfs_name));
3760 3755          }
3761 3756  
3762 3757          remove_mountpoint(zhp);
3763 3758  
3764 3759          return (0);
3765 3760  }
3766 3761  
3767 3762  struct destroydata {
3768 3763          nvlist_t *nvl;
3769 3764          const char *snapname;
3770 3765  };
3771 3766  
3772 3767  static int
3773 3768  zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
3774 3769  {
3775 3770          struct destroydata *dd = arg;
3776 3771          char name[ZFS_MAX_DATASET_NAME_LEN];
3777 3772          int rv = 0;
3778 3773  
3779 3774          (void) snprintf(name, sizeof (name),
3780 3775              "%s@%s", zhp->zfs_name, dd->snapname);
3781 3776  
3782 3777          if (lzc_exists(name))
3783 3778                  verify(nvlist_add_boolean(dd->nvl, name) == 0);
3784 3779  
3785 3780          rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
3786 3781          zfs_close(zhp);
3787 3782          return (rv);
3788 3783  }
3789 3784  
3790 3785  /*
3791 3786   * Destroys all snapshots with the given name in zhp & descendants.
3792 3787   */
3793 3788  int
3794 3789  zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
3795 3790  {
3796 3791          int ret;
3797 3792          struct destroydata dd = { 0 };
3798 3793  
3799 3794          dd.snapname = snapname;
3800 3795          verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
3801 3796          (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
3802 3797  
3803 3798          if (nvlist_empty(dd.nvl)) {
3804 3799                  ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
3805 3800                      dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
3806 3801                      zhp->zfs_name, snapname);
3807 3802          } else {
3808 3803                  ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
3809 3804          }
3810 3805          nvlist_free(dd.nvl);
3811 3806          return (ret);
3812 3807  }
3813 3808  
3814 3809  /*
3815 3810   * Destroys all the snapshots named in the nvlist.
3816 3811   */
3817 3812  int
3818 3813  zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
3819 3814  {
3820 3815          int ret;
3821 3816          nvlist_t *errlist = NULL;
3822 3817  
3823 3818          ret = lzc_destroy_snaps(snaps, defer, &errlist);
3824 3819  
3825 3820          if (ret == 0) {
3826 3821                  nvlist_free(errlist);
3827 3822                  return (0);
3828 3823          }
3829 3824  
3830 3825          if (nvlist_empty(errlist)) {
3831 3826                  char errbuf[1024];
3832 3827                  (void) snprintf(errbuf, sizeof (errbuf),
3833 3828                      dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
3834 3829  
3835 3830                  ret = zfs_standard_error(hdl, ret, errbuf);
3836 3831          }
3837 3832          for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
3838 3833              pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
3839 3834                  char errbuf[1024];
3840 3835                  (void) snprintf(errbuf, sizeof (errbuf),
3841 3836                      dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
3842 3837                      nvpair_name(pair));
3843 3838  
3844 3839                  switch (fnvpair_value_int32(pair)) {
3845 3840                  case EEXIST:
3846 3841                          zfs_error_aux(hdl,
3847 3842                              dgettext(TEXT_DOMAIN, "snapshot is cloned"));
3848 3843                          ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
3849 3844                          break;
3850 3845                  default:
3851 3846                          ret = zfs_standard_error(hdl, errno, errbuf);
3852 3847                          break;
3853 3848                  }
3854 3849          }
3855 3850  
3856 3851          nvlist_free(errlist);
3857 3852          return (ret);
3858 3853  }
3859 3854  
3860 3855  /*
3861 3856   * Clones the given dataset.  The target must be of the same type as the source.
3862 3857   */
3863 3858  int
3864 3859  zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
3865 3860  {
3866 3861          char parent[ZFS_MAX_DATASET_NAME_LEN];
3867 3862          int ret;
3868 3863          char errbuf[1024];
3869 3864          libzfs_handle_t *hdl = zhp->zfs_hdl;
3870 3865          uint64_t zoned;
3871 3866  
3872 3867          assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
3873 3868  
3874 3869          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3875 3870              "cannot create '%s'"), target);
3876 3871  
3877 3872          /* validate the target/clone name */
3878 3873          if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
3879 3874                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3880 3875  
3881 3876          /* validate parents exist */
3882 3877          if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
3883 3878                  return (-1);
3884 3879  
3885 3880          (void) parent_name(target, parent, sizeof (parent));
3886 3881  
3887 3882          /* do the clone */
3888 3883  
3889 3884          if (props) {
3890 3885                  zfs_type_t type;
3891 3886  
3892 3887                  if (ZFS_IS_VOLUME(zhp)) {
3893 3888                          type = ZFS_TYPE_VOLUME;
3894 3889                  } else {
3895 3890                          type = ZFS_TYPE_FILESYSTEM;
3896 3891                  }
3897 3892                  if ((props = zfs_valid_proplist(hdl, type, props, zoned,
3898 3893                      zhp, zhp->zpool_hdl, B_TRUE, errbuf)) == NULL)
3899 3894                          return (-1);
3900 3895                  if (zfs_fix_auto_resv(zhp, props) == -1) {
3901 3896                          nvlist_free(props);
3902 3897                          return (-1);
3903 3898                  }
3904 3899          }
3905 3900  
3906 3901          if (zfs_crypto_clone_check(hdl, zhp, parent, props) != 0) {
3907 3902                  nvlist_free(props);
3908 3903                  return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));
3909 3904          }
3910 3905  
3911 3906          ret = lzc_clone(target, zhp->zfs_name, props);
3912 3907          nvlist_free(props);
3913 3908  
3914 3909          if (ret != 0) {
3915 3910                  switch (errno) {
3916 3911  
3917 3912                  case ENOENT:
3918 3913                          /*
3919 3914                           * The parent doesn't exist.  We should have caught this
3920 3915                           * above, but there may a race condition that has since
3921 3916                           * destroyed the parent.
3922 3917                           *
3923 3918                           * At this point, we don't know whether it's the source
3924 3919                           * that doesn't exist anymore, or whether the target
3925 3920                           * dataset doesn't exist.
3926 3921                           */
3927 3922                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3928 3923                              "no such parent '%s'"), parent);
3929 3924                          return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
3930 3925  
3931 3926                  case EXDEV:
3932 3927                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3933 3928                              "source and target pools differ"));
3934 3929                          return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
3935 3930                              errbuf));
3936 3931  
3937 3932                  default:
3938 3933                          return (zfs_standard_error(zhp->zfs_hdl, errno,
3939 3934                              errbuf));
3940 3935                  }
3941 3936          }
3942 3937  
3943 3938          return (ret);
3944 3939  }
3945 3940  
3946 3941  /*
3947 3942   * Promotes the given clone fs to be the clone parent.
3948 3943   */
3949 3944  int
3950 3945  zfs_promote(zfs_handle_t *zhp)
3951 3946  {
3952 3947          libzfs_handle_t *hdl = zhp->zfs_hdl;
3953 3948          char snapname[ZFS_MAX_DATASET_NAME_LEN];
3954 3949          int ret;
3955 3950          char errbuf[1024];
3956 3951  
3957 3952          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3958 3953              "cannot promote '%s'"), zhp->zfs_name);
3959 3954  
3960 3955          if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3961 3956                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3962 3957                      "snapshots can not be promoted"));
3963 3958                  return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3964 3959          }
3965 3960  
3966 3961          if (zhp->zfs_dmustats.dds_origin[0] == '\0') {
3967 3962                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3968 3963                      "not a cloned filesystem"));
3969 3964                  return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3970 3965          }
3971 3966  
3972 3967          if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
3973 3968                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3974 3969  
3975 3970          ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname));
3976 3971  
3977 3972          if (ret != 0) {
3978 3973                  switch (ret) {
3979 3974                  case EEXIST:
3980 3975                          /* There is a conflicting snapshot name. */
3981 3976                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3982 3977                              "conflicting snapshot '%s' from parent '%s'"),
3983 3978                              snapname, zhp->zfs_dmustats.dds_origin);
3984 3979                          return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3985 3980  
3986 3981                  default:
3987 3982                          return (zfs_standard_error(hdl, ret, errbuf));
3988 3983                  }
3989 3984          }
3990 3985          return (ret);
3991 3986  }
3992 3987  
3993 3988  typedef struct snapdata {
3994 3989          nvlist_t *sd_nvl;
3995 3990          const char *sd_snapname;
3996 3991  } snapdata_t;
3997 3992  
3998 3993  static int
3999 3994  zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
4000 3995  {
4001 3996          snapdata_t *sd = arg;
4002 3997          char name[ZFS_MAX_DATASET_NAME_LEN];
4003 3998          int rv = 0;
4004 3999  
4005 4000          if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
4006 4001                  (void) snprintf(name, sizeof (name),
4007 4002                      "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
4008 4003  
4009 4004                  fnvlist_add_boolean(sd->sd_nvl, name);
4010 4005  
4011 4006                  rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
4012 4007          }
4013 4008          zfs_close(zhp);
4014 4009  
4015 4010          return (rv);
4016 4011  }
4017 4012  
4018 4013  int
4019 4014  zfs_remap_indirects(libzfs_handle_t *hdl, const char *fs)
4020 4015  {
4021 4016          int err;
4022 4017          char errbuf[1024];
4023 4018  
4024 4019          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4025 4020              "cannot remap dataset '%s'"), fs);
4026 4021  
4027 4022          err = lzc_remap(fs);
4028 4023  
4029 4024          if (err != 0) {
4030 4025                  switch (err) {
4031 4026                  case ENOTSUP:
4032 4027                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4033 4028                              "pool must be upgraded"));
4034 4029                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4035 4030                          break;
4036 4031                  case EINVAL:
4037 4032                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4038 4033                          break;
4039 4034                  default:
4040 4035                          (void) zfs_standard_error(hdl, err, errbuf);
4041 4036                          break;
4042 4037                  }
4043 4038          }
4044 4039  
4045 4040          return (err);
4046 4041  }
4047 4042  
4048 4043  /*
4049 4044   * Creates snapshots.  The keys in the snaps nvlist are the snapshots to be
4050 4045   * created.
4051 4046   */
4052 4047  int
4053 4048  zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
4054 4049  {
4055 4050          int ret;
4056 4051          char errbuf[1024];
4057 4052          nvpair_t *elem;
4058 4053          nvlist_t *errors;
4059 4054  
4060 4055          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4061 4056              "cannot create snapshots "));
4062 4057  
4063 4058          elem = NULL;
4064 4059          while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
4065 4060                  const char *snapname = nvpair_name(elem);
4066 4061  
4067 4062                  /* validate the target name */
4068 4063                  if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
4069 4064                      B_TRUE)) {
4070 4065                          (void) snprintf(errbuf, sizeof (errbuf),
4071 4066                              dgettext(TEXT_DOMAIN,
4072 4067                              "cannot create snapshot '%s'"), snapname);
4073 4068                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4074 4069                  }
4075 4070          }
4076 4071  
4077 4072          /*
4078 4073           * get pool handle for prop validation. assumes all snaps are in the
4079 4074           * same pool, as does lzc_snapshot (below).
4080 4075           */
4081 4076          char pool[ZFS_MAX_DATASET_NAME_LEN];
4082 4077          elem = nvlist_next_nvpair(snaps, NULL);
4083 4078          (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
4084 4079          pool[strcspn(pool, "/@")] = '\0';
4085 4080          zpool_handle_t *zpool_hdl = zpool_open(hdl, pool);
4086 4081  
4087 4082          if (props != NULL &&
4088 4083              (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
4089 4084              props, B_FALSE, NULL, zpool_hdl, B_FALSE, errbuf)) == NULL) {
4090 4085                  zpool_close(zpool_hdl);
4091 4086                  return (-1);
4092 4087          }
4093 4088          zpool_close(zpool_hdl);
4094 4089  
4095 4090          ret = lzc_snapshot(snaps, props, &errors);
4096 4091  
4097 4092          if (ret != 0) {
4098 4093                  boolean_t printed = B_FALSE;
4099 4094                  for (elem = nvlist_next_nvpair(errors, NULL);
4100 4095                      elem != NULL;
4101 4096                      elem = nvlist_next_nvpair(errors, elem)) {
4102 4097                          (void) snprintf(errbuf, sizeof (errbuf),
4103 4098                              dgettext(TEXT_DOMAIN,
4104 4099                              "cannot create snapshot '%s'"), nvpair_name(elem));
4105 4100                          (void) zfs_standard_error(hdl,
4106 4101                              fnvpair_value_int32(elem), errbuf);
4107 4102                          printed = B_TRUE;
4108 4103                  }
4109 4104                  if (!printed) {
4110 4105                          switch (ret) {
4111 4106                          case EXDEV:
4112 4107                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4113 4108                                      "multiple snapshots of same "
4114 4109                                      "fs not allowed"));
4115 4110                                  (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
4116 4111  
4117 4112                                  break;
4118 4113                          default:
4119 4114                                  (void) zfs_standard_error(hdl, ret, errbuf);
4120 4115                          }
4121 4116                  }
4122 4117          }
4123 4118  
4124 4119          nvlist_free(props);
4125 4120          nvlist_free(errors);
4126 4121          return (ret);
4127 4122  }
4128 4123  
4129 4124  int
4130 4125  zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
4131 4126      nvlist_t *props)
4132 4127  {
4133 4128          int ret;
4134 4129          snapdata_t sd = { 0 };
4135 4130          char fsname[ZFS_MAX_DATASET_NAME_LEN];
4136 4131          char *cp;
4137 4132          zfs_handle_t *zhp;
4138 4133          char errbuf[1024];
4139 4134  
4140 4135          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4141 4136              "cannot snapshot %s"), path);
4142 4137  
4143 4138          if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
4144 4139                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4145 4140  
4146 4141          (void) strlcpy(fsname, path, sizeof (fsname));
4147 4142          cp = strchr(fsname, '@');
4148 4143          *cp = '\0';
4149 4144          sd.sd_snapname = cp + 1;
4150 4145  
4151 4146          if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
4152 4147              ZFS_TYPE_VOLUME)) == NULL) {
4153 4148                  return (-1);
4154 4149          }
4155 4150  
4156 4151          verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
4157 4152          if (recursive) {
4158 4153                  (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
4159 4154          } else {
4160 4155                  fnvlist_add_boolean(sd.sd_nvl, path);
4161 4156          }
4162 4157  
4163 4158          ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
4164 4159          nvlist_free(sd.sd_nvl);
4165 4160          zfs_close(zhp);
4166 4161          return (ret);
4167 4162  }
4168 4163  
4169 4164  /*
4170 4165   * Destroy any more recent snapshots.  We invoke this callback on any dependents
4171 4166   * of the snapshot first.  If the 'cb_dependent' member is non-zero, then this
4172 4167   * is a dependent and we should just destroy it without checking the transaction
4173 4168   * group.
4174 4169   */
4175 4170  typedef struct rollback_data {
4176 4171          const char      *cb_target;             /* the snapshot */
4177 4172          uint64_t        cb_create;              /* creation time reference */
4178 4173          boolean_t       cb_error;
4179 4174          boolean_t       cb_force;
4180 4175  } rollback_data_t;
4181 4176  
4182 4177  static int
4183 4178  rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
4184 4179  {
4185 4180          rollback_data_t *cbp = data;
4186 4181          prop_changelist_t *clp;
4187 4182  
4188 4183          /* We must destroy this clone; first unmount it */
4189 4184          clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
4190 4185              cbp->cb_force ? MS_FORCE: 0);
4191 4186          if (clp == NULL || changelist_prefix(clp) != 0) {
4192 4187                  cbp->cb_error = B_TRUE;
4193 4188                  zfs_close(zhp);
4194 4189                  return (0);
4195 4190          }
4196 4191          if (zfs_destroy(zhp, B_FALSE) != 0)
4197 4192                  cbp->cb_error = B_TRUE;
4198 4193          else
4199 4194                  changelist_remove(clp, zhp->zfs_name);
4200 4195          (void) changelist_postfix(clp);
4201 4196          changelist_free(clp);
4202 4197  
4203 4198          zfs_close(zhp);
4204 4199          return (0);
4205 4200  }
4206 4201  
4207 4202  static int
4208 4203  rollback_destroy(zfs_handle_t *zhp, void *data)
4209 4204  {
4210 4205          rollback_data_t *cbp = data;
4211 4206  
4212 4207          if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
4213 4208                  cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
4214 4209                      rollback_destroy_dependent, cbp);
4215 4210  
4216 4211                  cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
4217 4212          }
4218 4213  
4219 4214          zfs_close(zhp);
4220 4215          return (0);
4221 4216  }
4222 4217  
4223 4218  /*
4224 4219   * Given a dataset, rollback to a specific snapshot, discarding any
4225 4220   * data changes since then and making it the active dataset.
4226 4221   *
4227 4222   * Any snapshots and bookmarks more recent than the target are
4228 4223   * destroyed, along with their dependents (i.e. clones).
4229 4224   */
4230 4225  int
4231 4226  zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
4232 4227  {
4233 4228          rollback_data_t cb = { 0 };
4234 4229          int err;
4235 4230          boolean_t restore_resv = 0;
4236 4231          uint64_t old_volsize = 0, new_volsize;
4237 4232          zfs_prop_t resv_prop;
4238 4233  
4239 4234          assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
4240 4235              zhp->zfs_type == ZFS_TYPE_VOLUME);
4241 4236  
4242 4237          /*
4243 4238           * Destroy all recent snapshots and their dependents.
4244 4239           */
4245 4240          cb.cb_force = force;
4246 4241          cb.cb_target = snap->zfs_name;
4247 4242          cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
4248 4243          (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb);
4249 4244          (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
4250 4245  
4251 4246          if (cb.cb_error)
4252 4247                  return (-1);
4253 4248  
4254 4249          /*
4255 4250           * Now that we have verified that the snapshot is the latest,
4256 4251           * rollback to the given snapshot.
4257 4252           */
4258 4253  
4259 4254          if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
4260 4255                  if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
4261 4256                          return (-1);
4262 4257                  old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
4263 4258                  restore_resv =
4264 4259                      (old_volsize == zfs_prop_get_int(zhp, resv_prop));
4265 4260          }
4266 4261  
4267 4262          /*
4268 4263           * Pass both the filesystem and the wanted snapshot names,
4269 4264           * we would get an error back if the snapshot is destroyed or
4270 4265           * a new snapshot is created before this request is processed.
4271 4266           */
4272 4267          err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name);
4273 4268          if (err != 0) {
4274 4269                  char errbuf[1024];
4275 4270  
4276 4271                  (void) snprintf(errbuf, sizeof (errbuf),
4277 4272                      dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
4278 4273                      zhp->zfs_name);
4279 4274                  switch (err) {
4280 4275                  case EEXIST:
4281 4276                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
4282 4277                              "there is a snapshot or bookmark more recent "
4283 4278                              "than '%s'"), snap->zfs_name);
4284 4279                          (void) zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf);
4285 4280                          break;
4286 4281                  case ESRCH:
4287 4282                          zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
4288 4283                              "'%s' is not found among snapshots of '%s'"),
4289 4284                              snap->zfs_name, zhp->zfs_name);
4290 4285                          (void) zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf);
4291 4286                          break;
4292 4287                  case EINVAL:
4293 4288                          (void) zfs_error(zhp->zfs_hdl, EZFS_BADTYPE, errbuf);
4294 4289                          break;
4295 4290                  default:
4296 4291                          (void) zfs_standard_error(zhp->zfs_hdl, err, errbuf);
4297 4292                  }
4298 4293                  return (err);
4299 4294          }
4300 4295  
4301 4296          /*
4302 4297           * For volumes, if the pre-rollback volsize matched the pre-
4303 4298           * rollback reservation and the volsize has changed then set
4304 4299           * the reservation property to the post-rollback volsize.
4305 4300           * Make a new handle since the rollback closed the dataset.
4306 4301           */
4307 4302          if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
4308 4303              (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
4309 4304                  if (restore_resv) {
4310 4305                          new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
4311 4306                          if (old_volsize != new_volsize)
4312 4307                                  err = zfs_prop_set_int(zhp, resv_prop,
4313 4308                                      new_volsize);
4314 4309                  }
4315 4310                  zfs_close(zhp);
4316 4311          }
4317 4312          return (err);
4318 4313  }
4319 4314  
4320 4315  /*
4321 4316   * Renames the given dataset.
4322 4317   */
4323 4318  int
4324 4319  zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
4325 4320      boolean_t force_unmount)
4326 4321  {
4327 4322          int ret = 0;
4328 4323          zfs_cmd_t zc = { 0 };
4329 4324          char *delim;
4330 4325          prop_changelist_t *cl = NULL;
4331 4326          zfs_handle_t *zhrp = NULL;
4332 4327          char *parentname = NULL;
4333 4328          char parent[ZFS_MAX_DATASET_NAME_LEN];
4334 4329          libzfs_handle_t *hdl = zhp->zfs_hdl;
4335 4330          char errbuf[1024];
4336 4331  
4337 4332          /* if we have the same exact name, just return success */
4338 4333          if (strcmp(zhp->zfs_name, target) == 0)
4339 4334                  return (0);
4340 4335  
4341 4336          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4342 4337              "cannot rename to '%s'"), target);
4343 4338  
4344 4339          /* make sure source name is valid */
4345 4340          if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
4346 4341                  return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4347 4342  
4348 4343          /*
4349 4344           * Make sure the target name is valid
4350 4345           */
4351 4346          if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
4352 4347                  if ((strchr(target, '@') == NULL) ||
4353 4348                      *target == '@') {
4354 4349                          /*
4355 4350                           * Snapshot target name is abbreviated,
4356 4351                           * reconstruct full dataset name
4357 4352                           */
4358 4353                          (void) strlcpy(parent, zhp->zfs_name,
4359 4354                              sizeof (parent));
4360 4355                          delim = strchr(parent, '@');
4361 4356                          if (strchr(target, '@') == NULL)
4362 4357                                  *(++delim) = '\0';
4363 4358                          else
4364 4359                                  *delim = '\0';
4365 4360                          (void) strlcat(parent, target, sizeof (parent));
4366 4361                          target = parent;
4367 4362                  } else {
4368 4363                          /*
4369 4364                           * Make sure we're renaming within the same dataset.
4370 4365                           */
4371 4366                          delim = strchr(target, '@');
4372 4367                          if (strncmp(zhp->zfs_name, target, delim - target)
4373 4368                              != 0 || zhp->zfs_name[delim - target] != '@') {
4374 4369                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4375 4370                                      "snapshots must be part of same "
4376 4371                                      "dataset"));
4377 4372                                  return (zfs_error(hdl, EZFS_CROSSTARGET,
4378 4373                                      errbuf));
4379 4374                          }
4380 4375                  }
4381 4376  
4382 4377                  if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
4383 4378                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4384 4379          } else {
4385 4380                  if (recursive) {
4386 4381                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4387 4382                              "recursive rename must be a snapshot"));
4388 4383                          return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
4389 4384                  }
4390 4385  
4391 4386                  if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
4392 4387                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4393 4388  
4394 4389                  /* validate parents */
4395 4390                  if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
4396 4391                          return (-1);
4397 4392  
4398 4393                  /* make sure we're in the same pool */
4399 4394                  verify((delim = strchr(target, '/')) != NULL);
4400 4395                  if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
4401 4396                      zhp->zfs_name[delim - target] != '/') {
4402 4397                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4403 4398                              "datasets must be within same pool"));
4404 4399                          return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
4405 4400                  }
4406 4401  
4407 4402                  /* new name cannot be a child of the current dataset name */
4408 4403                  if (is_descendant(zhp->zfs_name, target)) {
4409 4404                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4410 4405                              "New dataset name cannot be a descendant of "
4411 4406                              "current dataset name"));
4412 4407                          return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4413 4408                  }
4414 4409          }
4415 4410  
4416 4411          (void) snprintf(errbuf, sizeof (errbuf),
4417 4412              dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
4418 4413  
4419 4414          if (getzoneid() == GLOBAL_ZONEID &&
4420 4415              zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
4421 4416                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4422 4417                      "dataset is used in a non-global zone"));
4423 4418                  return (zfs_error(hdl, EZFS_ZONED, errbuf));
4424 4419          }
4425 4420  
4426 4421          if (recursive) {
4427 4422                  parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
4428 4423                  if (parentname == NULL) {
4429 4424                          ret = -1;
4430 4425                          goto error;
4431 4426                  }
4432 4427                  delim = strchr(parentname, '@');
4433 4428                  *delim = '\0';
4434 4429                  zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
4435 4430                  if (zhrp == NULL) {
4436 4431                          ret = -1;
4437 4432                          goto error;
4438 4433                  }
4439 4434          } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) {
4440 4435                  if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
4441 4436                      force_unmount ? MS_FORCE : 0)) == NULL)
4442 4437                          return (-1);
4443 4438  
4444 4439                  if (changelist_haszonedchild(cl)) {
4445 4440                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4446 4441                              "child dataset with inherited mountpoint is used "
4447 4442                              "in a non-global zone"));
4448 4443                          (void) zfs_error(hdl, EZFS_ZONED, errbuf);
4449 4444                          ret = -1;
4450 4445                          goto error;
4451 4446                  }
4452 4447  
4453 4448                  if ((ret = changelist_prefix(cl)) != 0)
4454 4449                          goto error;
4455 4450          }
4456 4451  
4457 4452          if (ZFS_IS_VOLUME(zhp))
4458 4453                  zc.zc_objset_type = DMU_OST_ZVOL;
4459 4454          else
4460 4455                  zc.zc_objset_type = DMU_OST_ZFS;
4461 4456  
4462 4457          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4463 4458          (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
4464 4459  
4465 4460          zc.zc_cookie = recursive;
4466 4461  
4467 4462          if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
4468 4463                  /*
4469 4464                   * if it was recursive, the one that actually failed will
4470 4465                   * be in zc.zc_name
4471 4466                   */
4472 4467                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4473 4468                      "cannot rename '%s'"), zc.zc_name);
4474 4469  
4475 4470                  if (recursive && errno == EEXIST) {
4476 4471                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4477 4472                              "a child dataset already has a snapshot "
4478 4473                              "with the new name"));
4479 4474                          (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
4480 4475                  } else if (errno == EACCES) {
4481 4476                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4482 4477                              "cannot move encrypted child outside of "
4483 4478                              "its encryption root"));
4484 4479                          (void) zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf);
4485 4480                  } else {
4486 4481                          (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
4487 4482                  }
4488 4483  
4489 4484                  /*
4490 4485                   * On failure, we still want to remount any filesystems that
4491 4486                   * were previously mounted, so we don't alter the system state.
4492 4487                   */
4493 4488                  if (cl != NULL)
4494 4489                          (void) changelist_postfix(cl);
4495 4490          } else {
4496 4491                  if (cl != NULL) {
4497 4492                          changelist_rename(cl, zfs_get_name(zhp), target);
4498 4493                          ret = changelist_postfix(cl);
4499 4494                  }
4500 4495          }
4501 4496  
4502 4497  error:
4503 4498          if (parentname != NULL) {
4504 4499                  free(parentname);
4505 4500          }
4506 4501          if (zhrp != NULL) {
4507 4502                  zfs_close(zhrp);
4508 4503          }
4509 4504          if (cl != NULL) {
4510 4505                  changelist_free(cl);
4511 4506          }
4512 4507          return (ret);
4513 4508  }
4514 4509  
4515 4510  nvlist_t *
4516 4511  zfs_get_user_props(zfs_handle_t *zhp)
4517 4512  {
4518 4513          return (zhp->zfs_user_props);
4519 4514  }
4520 4515  
4521 4516  nvlist_t *
4522 4517  zfs_get_recvd_props(zfs_handle_t *zhp)
4523 4518  {
4524 4519          if (zhp->zfs_recvd_props == NULL)
4525 4520                  if (get_recvd_props_ioctl(zhp) != 0)
4526 4521                          return (NULL);
4527 4522          return (zhp->zfs_recvd_props);
4528 4523  }
4529 4524  
4530 4525  /*
4531 4526   * This function is used by 'zfs list' to determine the exact set of columns to
4532 4527   * display, and their maximum widths.  This does two main things:
4533 4528   *
4534 4529   *      - If this is a list of all properties, then expand the list to include
4535 4530   *        all native properties, and set a flag so that for each dataset we look
4536 4531   *        for new unique user properties and add them to the list.
4537 4532   *
4538 4533   *      - For non fixed-width properties, keep track of the maximum width seen
4539 4534   *        so that we can size the column appropriately. If the user has
4540 4535   *        requested received property values, we also need to compute the width
4541 4536   *        of the RECEIVED column.
4542 4537   */
4543 4538  int
4544 4539  zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
4545 4540      boolean_t literal)
4546 4541  {
4547 4542          libzfs_handle_t *hdl = zhp->zfs_hdl;
4548 4543          zprop_list_t *entry;
4549 4544          zprop_list_t **last, **start;
4550 4545          nvlist_t *userprops, *propval;
4551 4546          nvpair_t *elem;
4552 4547          char *strval;
4553 4548          char buf[ZFS_MAXPROPLEN];
4554 4549  
4555 4550          if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
4556 4551                  return (-1);
4557 4552  
4558 4553          userprops = zfs_get_user_props(zhp);
4559 4554  
4560 4555          entry = *plp;
4561 4556          if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
4562 4557                  /*
4563 4558                   * Go through and add any user properties as necessary.  We
4564 4559                   * start by incrementing our list pointer to the first
4565 4560                   * non-native property.
4566 4561                   */
4567 4562                  start = plp;
4568 4563                  while (*start != NULL) {
4569 4564                          if ((*start)->pl_prop == ZPROP_INVAL)
4570 4565                                  break;
4571 4566                          start = &(*start)->pl_next;
4572 4567                  }
4573 4568  
4574 4569                  elem = NULL;
4575 4570                  while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
4576 4571                          /*
4577 4572                           * See if we've already found this property in our list.
4578 4573                           */
4579 4574                          for (last = start; *last != NULL;
4580 4575                              last = &(*last)->pl_next) {
4581 4576                                  if (strcmp((*last)->pl_user_prop,
4582 4577                                      nvpair_name(elem)) == 0)
4583 4578                                          break;
4584 4579                          }
4585 4580  
4586 4581                          if (*last == NULL) {
4587 4582                                  if ((entry = zfs_alloc(hdl,
4588 4583                                      sizeof (zprop_list_t))) == NULL ||
4589 4584                                      ((entry->pl_user_prop = zfs_strdup(hdl,
4590 4585                                      nvpair_name(elem)))) == NULL) {
4591 4586                                          free(entry);
4592 4587                                          return (-1);
4593 4588                                  }
4594 4589  
4595 4590                                  entry->pl_prop = ZPROP_INVAL;
4596 4591                                  entry->pl_width = strlen(nvpair_name(elem));
4597 4592                                  entry->pl_all = B_TRUE;
4598 4593                                  *last = entry;
4599 4594                          }
4600 4595                  }
4601 4596          }
4602 4597  
4603 4598          /*
4604 4599           * Now go through and check the width of any non-fixed columns
4605 4600           */
4606 4601          for (entry = *plp; entry != NULL; entry = entry->pl_next) {
4607 4602                  if (entry->pl_fixed && !literal)
4608 4603                          continue;
4609 4604  
4610 4605                  if (entry->pl_prop != ZPROP_INVAL) {
4611 4606                          if (zfs_prop_get(zhp, entry->pl_prop,
4612 4607                              buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
4613 4608                                  if (strlen(buf) > entry->pl_width)
4614 4609                                          entry->pl_width = strlen(buf);
4615 4610                          }
4616 4611                          if (received && zfs_prop_get_recvd(zhp,
4617 4612                              zfs_prop_to_name(entry->pl_prop),
4618 4613                              buf, sizeof (buf), literal) == 0)
4619 4614                                  if (strlen(buf) > entry->pl_recvd_width)
4620 4615                                          entry->pl_recvd_width = strlen(buf);
4621 4616                  } else {
4622 4617                          if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
4623 4618                              &propval) == 0) {
4624 4619                                  verify(nvlist_lookup_string(propval,
4625 4620                                      ZPROP_VALUE, &strval) == 0);
4626 4621                                  if (strlen(strval) > entry->pl_width)
4627 4622                                          entry->pl_width = strlen(strval);
4628 4623                          }
4629 4624                          if (received && zfs_prop_get_recvd(zhp,
4630 4625                              entry->pl_user_prop,
4631 4626                              buf, sizeof (buf), literal) == 0)
4632 4627                                  if (strlen(buf) > entry->pl_recvd_width)
4633 4628                                          entry->pl_recvd_width = strlen(buf);
4634 4629                  }
4635 4630          }
4636 4631  
4637 4632          return (0);
4638 4633  }
4639 4634  
4640 4635  int
4641 4636  zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
4642 4637      char *resource, void *export, void *sharetab,
4643 4638      int sharemax, zfs_share_op_t operation)
4644 4639  {
4645 4640          zfs_cmd_t zc = { 0 };
4646 4641          int error;
4647 4642  
4648 4643          (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4649 4644          (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4650 4645          if (resource)
4651 4646                  (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
4652 4647          zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
4653 4648          zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
4654 4649          zc.zc_share.z_sharetype = operation;
4655 4650          zc.zc_share.z_sharemax = sharemax;
4656 4651          error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
4657 4652          return (error);
4658 4653  }
4659 4654  
4660 4655  void
4661 4656  zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
4662 4657  {
4663 4658          nvpair_t *curr;
4664 4659  
4665 4660          /*
4666 4661           * Keep a reference to the props-table against which we prune the
4667 4662           * properties.
4668 4663           */
4669 4664          zhp->zfs_props_table = props;
4670 4665  
4671 4666          curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
4672 4667  
4673 4668          while (curr) {
4674 4669                  zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
4675 4670                  nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
4676 4671  
4677 4672                  /*
4678 4673                   * User properties will result in ZPROP_INVAL, and since we
4679 4674                   * only know how to prune standard ZFS properties, we always
4680 4675                   * leave these in the list.  This can also happen if we
4681 4676                   * encounter an unknown DSL property (when running older
4682 4677                   * software, for example).
4683 4678                   */
4684 4679                  if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
4685 4680                          (void) nvlist_remove(zhp->zfs_props,
4686 4681                              nvpair_name(curr), nvpair_type(curr));
4687 4682                  curr = next;
4688 4683          }
4689 4684  }
4690 4685  
4691 4686  static int
4692 4687  zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
4693 4688      zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
4694 4689  {
4695 4690          zfs_cmd_t zc = { 0 };
4696 4691          nvlist_t *nvlist = NULL;
4697 4692          int error;
4698 4693  
4699 4694          (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4700 4695          (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4701 4696          zc.zc_cookie = (uint64_t)cmd;
4702 4697  
4703 4698          if (cmd == ZFS_SMB_ACL_RENAME) {
4704 4699                  if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
4705 4700                          (void) no_memory(hdl);
4706 4701                          return (0);
4707 4702                  }
4708 4703          }
4709 4704  
4710 4705          switch (cmd) {
4711 4706          case ZFS_SMB_ACL_ADD:
4712 4707          case ZFS_SMB_ACL_REMOVE:
4713 4708                  (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
4714 4709                  break;
4715 4710          case ZFS_SMB_ACL_RENAME:
4716 4711                  if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
4717 4712                      resource1) != 0) {
4718 4713                                  (void) no_memory(hdl);
4719 4714                                  return (-1);
4720 4715                  }
4721 4716                  if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
4722 4717                      resource2) != 0) {
4723 4718                                  (void) no_memory(hdl);
4724 4719                                  return (-1);
4725 4720                  }
4726 4721                  if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
4727 4722                          nvlist_free(nvlist);
4728 4723                          return (-1);
4729 4724                  }
4730 4725                  break;
4731 4726          case ZFS_SMB_ACL_PURGE:
4732 4727                  break;
4733 4728          default:
4734 4729                  return (-1);
4735 4730          }
4736 4731          error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
4737 4732          nvlist_free(nvlist);
4738 4733          return (error);
4739 4734  }
4740 4735  
4741 4736  int
4742 4737  zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
4743 4738      char *path, char *resource)
4744 4739  {
4745 4740          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
4746 4741              resource, NULL));
4747 4742  }
4748 4743  
4749 4744  int
4750 4745  zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
4751 4746      char *path, char *resource)
4752 4747  {
4753 4748          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
4754 4749              resource, NULL));
4755 4750  }
4756 4751  
4757 4752  int
4758 4753  zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
4759 4754  {
4760 4755          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
4761 4756              NULL, NULL));
4762 4757  }
4763 4758  
4764 4759  int
4765 4760  zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
4766 4761      char *oldname, char *newname)
4767 4762  {
4768 4763          return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
4769 4764              oldname, newname));
4770 4765  }
4771 4766  
4772 4767  int
4773 4768  zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
4774 4769      zfs_userspace_cb_t func, void *arg)
4775 4770  {
4776 4771          zfs_cmd_t zc = { 0 };
4777 4772          zfs_useracct_t buf[100];
4778 4773          libzfs_handle_t *hdl = zhp->zfs_hdl;
4779 4774          int ret;
4780 4775  
4781 4776          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4782 4777  
4783 4778          zc.zc_objset_type = type;
4784 4779          zc.zc_nvlist_dst = (uintptr_t)buf;
4785 4780  
4786 4781          for (;;) {
4787 4782                  zfs_useracct_t *zua = buf;
4788 4783  
4789 4784                  zc.zc_nvlist_dst_size = sizeof (buf);
4790 4785                  if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
4791 4786                          char errbuf[1024];
4792 4787  
4793 4788                          if ((errno == ENOTSUP &&
4794 4789                              (type == ZFS_PROP_USEROBJUSED ||
4795 4790                              type == ZFS_PROP_GROUPOBJUSED ||
4796 4791                              type == ZFS_PROP_USEROBJQUOTA ||
4797 4792                              type == ZFS_PROP_GROUPOBJQUOTA ||
4798 4793                              type == ZFS_PROP_PROJECTOBJUSED ||
4799 4794                              type == ZFS_PROP_PROJECTOBJQUOTA ||
4800 4795                              type == ZFS_PROP_PROJECTUSED ||
4801 4796                              type == ZFS_PROP_PROJECTQUOTA)))
4802 4797                                  break;
4803 4798  
4804 4799                          (void) snprintf(errbuf, sizeof (errbuf),
4805 4800                              dgettext(TEXT_DOMAIN,
4806 4801                              "cannot get used/quota for %s"), zc.zc_name);
4807 4802                          return (zfs_standard_error_fmt(hdl, errno, errbuf));
4808 4803                  }
4809 4804                  if (zc.zc_nvlist_dst_size == 0)
4810 4805                          break;
4811 4806  
4812 4807                  while (zc.zc_nvlist_dst_size > 0) {
4813 4808                          if ((ret = func(arg, zua->zu_domain, zua->zu_rid,
4814 4809                              zua->zu_space)) != 0)
4815 4810                                  return (ret);
4816 4811                          zua++;
4817 4812                          zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4818 4813                  }
4819 4814          }
4820 4815  
4821 4816          return (0);
4822 4817  }
4823 4818  
4824 4819  struct holdarg {
4825 4820          nvlist_t *nvl;
4826 4821          const char *snapname;
4827 4822          const char *tag;
4828 4823          boolean_t recursive;
4829 4824          int error;
4830 4825  };
4831 4826  
4832 4827  static int
4833 4828  zfs_hold_one(zfs_handle_t *zhp, void *arg)
4834 4829  {
4835 4830          struct holdarg *ha = arg;
4836 4831          char name[ZFS_MAX_DATASET_NAME_LEN];
4837 4832          int rv = 0;
4838 4833  
4839 4834          (void) snprintf(name, sizeof (name),
4840 4835              "%s@%s", zhp->zfs_name, ha->snapname);
4841 4836  
4842 4837          if (lzc_exists(name))
4843 4838                  fnvlist_add_string(ha->nvl, name, ha->tag);
4844 4839  
4845 4840          if (ha->recursive)
4846 4841                  rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4847 4842          zfs_close(zhp);
4848 4843          return (rv);
4849 4844  }
4850 4845  
4851 4846  int
4852 4847  zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4853 4848      boolean_t recursive, int cleanup_fd)
4854 4849  {
4855 4850          int ret;
4856 4851          struct holdarg ha;
4857 4852  
4858 4853          ha.nvl = fnvlist_alloc();
4859 4854          ha.snapname = snapname;
4860 4855          ha.tag = tag;
4861 4856          ha.recursive = recursive;
4862 4857          (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4863 4858  
4864 4859          if (nvlist_empty(ha.nvl)) {
4865 4860                  char errbuf[1024];
4866 4861  
4867 4862                  fnvlist_free(ha.nvl);
4868 4863                  ret = ENOENT;
4869 4864                  (void) snprintf(errbuf, sizeof (errbuf),
4870 4865                      dgettext(TEXT_DOMAIN,
4871 4866                      "cannot hold snapshot '%s@%s'"),
4872 4867                      zhp->zfs_name, snapname);
4873 4868                  (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
4874 4869                  return (ret);
4875 4870          }
4876 4871  
4877 4872          ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4878 4873          fnvlist_free(ha.nvl);
4879 4874  
4880 4875          return (ret);
4881 4876  }
4882 4877  
4883 4878  int
4884 4879  zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
4885 4880  {
4886 4881          int ret;
4887 4882          nvlist_t *errors;
4888 4883          libzfs_handle_t *hdl = zhp->zfs_hdl;
4889 4884          char errbuf[1024];
4890 4885          nvpair_t *elem;
4891 4886  
4892 4887          errors = NULL;
4893 4888          ret = lzc_hold(holds, cleanup_fd, &errors);
4894 4889  
4895 4890          if (ret == 0) {
4896 4891                  /* There may be errors even in the success case. */
4897 4892                  fnvlist_free(errors);
4898 4893                  return (0);
4899 4894          }
4900 4895  
4901 4896          if (nvlist_empty(errors)) {
4902 4897                  /* no hold-specific errors */
4903 4898                  (void) snprintf(errbuf, sizeof (errbuf),
4904 4899                      dgettext(TEXT_DOMAIN, "cannot hold"));
4905 4900                  switch (ret) {
4906 4901                  case ENOTSUP:
4907 4902                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4908 4903                              "pool must be upgraded"));
4909 4904                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4910 4905                          break;
4911 4906                  case EINVAL:
4912 4907                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4913 4908                          break;
4914 4909                  default:
4915 4910                          (void) zfs_standard_error(hdl, ret, errbuf);
4916 4911                  }
4917 4912          }
4918 4913  
4919 4914          for (elem = nvlist_next_nvpair(errors, NULL);
4920 4915              elem != NULL;
4921 4916              elem = nvlist_next_nvpair(errors, elem)) {
4922 4917                  (void) snprintf(errbuf, sizeof (errbuf),
4923 4918                      dgettext(TEXT_DOMAIN,
4924 4919                      "cannot hold snapshot '%s'"), nvpair_name(elem));
4925 4920                  switch (fnvpair_value_int32(elem)) {
4926 4921                  case E2BIG:
4927 4922                          /*
4928 4923                           * Temporary tags wind up having the ds object id
4929 4924                           * prepended. So even if we passed the length check
4930 4925                           * above, it's still possible for the tag to wind
4931 4926                           * up being slightly too long.
4932 4927                           */
4933 4928                          (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4934 4929                          break;
4935 4930                  case EINVAL:
4936 4931                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4937 4932                          break;
4938 4933                  case EEXIST:
4939 4934                          (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4940 4935                          break;
4941 4936                  default:
4942 4937                          (void) zfs_standard_error(hdl,
4943 4938                              fnvpair_value_int32(elem), errbuf);
4944 4939                  }
4945 4940          }
4946 4941  
4947 4942          fnvlist_free(errors);
4948 4943          return (ret);
4949 4944  }
4950 4945  
4951 4946  static int
4952 4947  zfs_release_one(zfs_handle_t *zhp, void *arg)
4953 4948  {
4954 4949          struct holdarg *ha = arg;
4955 4950          char name[ZFS_MAX_DATASET_NAME_LEN];
4956 4951          int rv = 0;
4957 4952          nvlist_t *existing_holds;
4958 4953  
4959 4954          (void) snprintf(name, sizeof (name),
4960 4955              "%s@%s", zhp->zfs_name, ha->snapname);
4961 4956  
4962 4957          if (lzc_get_holds(name, &existing_holds) != 0) {
4963 4958                  ha->error = ENOENT;
4964 4959          } else if (!nvlist_exists(existing_holds, ha->tag)) {
4965 4960                  ha->error = ESRCH;
4966 4961          } else {
4967 4962                  nvlist_t *torelease = fnvlist_alloc();
4968 4963                  fnvlist_add_boolean(torelease, ha->tag);
4969 4964                  fnvlist_add_nvlist(ha->nvl, name, torelease);
4970 4965                  fnvlist_free(torelease);
4971 4966          }
4972 4967  
4973 4968          if (ha->recursive)
4974 4969                  rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4975 4970          zfs_close(zhp);
4976 4971          return (rv);
4977 4972  }
4978 4973  
4979 4974  int
4980 4975  zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4981 4976      boolean_t recursive)
4982 4977  {
4983 4978          int ret;
4984 4979          struct holdarg ha;
4985 4980          nvlist_t *errors = NULL;
4986 4981          nvpair_t *elem;
4987 4982          libzfs_handle_t *hdl = zhp->zfs_hdl;
4988 4983          char errbuf[1024];
4989 4984  
4990 4985          ha.nvl = fnvlist_alloc();
4991 4986          ha.snapname = snapname;
4992 4987          ha.tag = tag;
4993 4988          ha.recursive = recursive;
4994 4989          ha.error = 0;
4995 4990          (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
4996 4991  
4997 4992          if (nvlist_empty(ha.nvl)) {
4998 4993                  fnvlist_free(ha.nvl);
4999 4994                  ret = ha.error;
5000 4995                  (void) snprintf(errbuf, sizeof (errbuf),
5001 4996                      dgettext(TEXT_DOMAIN,
5002 4997                      "cannot release hold from snapshot '%s@%s'"),
5003 4998                      zhp->zfs_name, snapname);
5004 4999                  if (ret == ESRCH) {
5005 5000                          (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
5006 5001                  } else {
5007 5002                          (void) zfs_standard_error(hdl, ret, errbuf);
5008 5003                  }
5009 5004                  return (ret);
5010 5005          }
5011 5006  
5012 5007          ret = lzc_release(ha.nvl, &errors);
5013 5008          fnvlist_free(ha.nvl);
5014 5009  
5015 5010          if (ret == 0) {
5016 5011                  /* There may be errors even in the success case. */
5017 5012                  fnvlist_free(errors);
5018 5013                  return (0);
5019 5014          }
5020 5015  
5021 5016          if (nvlist_empty(errors)) {
5022 5017                  /* no hold-specific errors */
5023 5018                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
5024 5019                      "cannot release"));
5025 5020                  switch (errno) {
5026 5021                  case ENOTSUP:
5027 5022                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5028 5023                              "pool must be upgraded"));
5029 5024                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
5030 5025                          break;
5031 5026                  default:
5032 5027                          (void) zfs_standard_error_fmt(hdl, errno, errbuf);
5033 5028                  }
5034 5029          }
5035 5030  
5036 5031          for (elem = nvlist_next_nvpair(errors, NULL);
5037 5032              elem != NULL;
5038 5033              elem = nvlist_next_nvpair(errors, elem)) {
5039 5034                  (void) snprintf(errbuf, sizeof (errbuf),
5040 5035                      dgettext(TEXT_DOMAIN,
5041 5036                      "cannot release hold from snapshot '%s'"),
5042 5037                      nvpair_name(elem));
5043 5038                  switch (fnvpair_value_int32(elem)) {
5044 5039                  case ESRCH:
5045 5040                          (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
5046 5041                          break;
5047 5042                  case EINVAL:
5048 5043                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
5049 5044                          break;
5050 5045                  default:
5051 5046                          (void) zfs_standard_error_fmt(hdl,
5052 5047                              fnvpair_value_int32(elem), errbuf);
5053 5048                  }
5054 5049          }
5055 5050  
5056 5051          fnvlist_free(errors);
5057 5052          return (ret);
5058 5053  }
5059 5054  
5060 5055  int
5061 5056  zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
5062 5057  {
5063 5058          zfs_cmd_t zc = { 0 };
5064 5059          libzfs_handle_t *hdl = zhp->zfs_hdl;
5065 5060          int nvsz = 2048;
5066 5061          void *nvbuf;
5067 5062          int err = 0;
5068 5063          char errbuf[1024];
5069 5064  
5070 5065          assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
5071 5066              zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
5072 5067  
5073 5068  tryagain:
5074 5069  
5075 5070          nvbuf = malloc(nvsz);
5076 5071          if (nvbuf == NULL) {
5077 5072                  err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
5078 5073                  goto out;
5079 5074          }
5080 5075  
5081 5076          zc.zc_nvlist_dst_size = nvsz;
5082 5077          zc.zc_nvlist_dst = (uintptr_t)nvbuf;
5083 5078  
5084 5079          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
5085 5080  
5086 5081          if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
5087 5082                  (void) snprintf(errbuf, sizeof (errbuf),
5088 5083                      dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
5089 5084                      zc.zc_name);
5090 5085                  switch (errno) {
5091 5086                  case ENOMEM:
5092 5087                          free(nvbuf);
5093 5088                          nvsz = zc.zc_nvlist_dst_size;
5094 5089                          goto tryagain;
5095 5090  
5096 5091                  case ENOTSUP:
5097 5092                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5098 5093                              "pool must be upgraded"));
5099 5094                          err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
5100 5095                          break;
5101 5096                  case EINVAL:
5102 5097                          err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
5103 5098                          break;
5104 5099                  case ENOENT:
5105 5100                          err = zfs_error(hdl, EZFS_NOENT, errbuf);
5106 5101                          break;
5107 5102                  default:
5108 5103                          err = zfs_standard_error_fmt(hdl, errno, errbuf);
5109 5104                          break;
5110 5105                  }
5111 5106          } else {
5112 5107                  /* success */
5113 5108                  int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
5114 5109                  if (rc) {
5115 5110                          (void) snprintf(errbuf, sizeof (errbuf), dgettext(
5116 5111                              TEXT_DOMAIN, "cannot get permissions on '%s'"),
5117 5112                              zc.zc_name);
5118 5113                          err = zfs_standard_error_fmt(hdl, rc, errbuf);
5119 5114                  }
5120 5115          }
5121 5116  
5122 5117          free(nvbuf);
5123 5118  out:
5124 5119          return (err);
5125 5120  }
5126 5121  
5127 5122  int
5128 5123  zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
5129 5124  {
5130 5125          zfs_cmd_t zc = { 0 };
5131 5126          libzfs_handle_t *hdl = zhp->zfs_hdl;
5132 5127          char *nvbuf;
5133 5128          char errbuf[1024];
5134 5129          size_t nvsz;
5135 5130          int err;
5136 5131  
5137 5132          assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
5138 5133              zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
5139 5134  
5140 5135          err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
5141 5136          assert(err == 0);
5142 5137  
5143 5138          nvbuf = malloc(nvsz);
5144 5139  
5145 5140          err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
5146 5141          assert(err == 0);
5147 5142  
5148 5143          zc.zc_nvlist_src_size = nvsz;
5149 5144          zc.zc_nvlist_src = (uintptr_t)nvbuf;
5150 5145          zc.zc_perm_action = un;
5151 5146  
5152 5147          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
5153 5148  
5154 5149          if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
5155 5150                  (void) snprintf(errbuf, sizeof (errbuf),
5156 5151                      dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
5157 5152                      zc.zc_name);
5158 5153                  switch (errno) {
5159 5154                  case ENOTSUP:
5160 5155                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5161 5156                              "pool must be upgraded"));
5162 5157                          err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
5163 5158                          break;
5164 5159                  case EINVAL:
5165 5160                          err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
5166 5161                          break;
5167 5162                  case ENOENT:
5168 5163                          err = zfs_error(hdl, EZFS_NOENT, errbuf);
5169 5164                          break;
5170 5165                  default:
5171 5166                          err = zfs_standard_error_fmt(hdl, errno, errbuf);
5172 5167                          break;
5173 5168                  }
5174 5169          }
5175 5170  
5176 5171          free(nvbuf);
5177 5172  
5178 5173          return (err);
5179 5174  }
5180 5175  
5181 5176  int
5182 5177  zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
5183 5178  {
5184 5179          int err;
5185 5180          char errbuf[1024];
5186 5181  
5187 5182          err = lzc_get_holds(zhp->zfs_name, nvl);
5188 5183  
5189 5184          if (err != 0) {
5190 5185                  libzfs_handle_t *hdl = zhp->zfs_hdl;
5191 5186  
5192 5187                  (void) snprintf(errbuf, sizeof (errbuf),
5193 5188                      dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
5194 5189                      zhp->zfs_name);
5195 5190                  switch (err) {
5196 5191                  case ENOTSUP:
5197 5192                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5198 5193                              "pool must be upgraded"));
5199 5194                          err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
5200 5195                          break;
5201 5196                  case EINVAL:
5202 5197                          err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
5203 5198                          break;
5204 5199                  case ENOENT:
5205 5200                          err = zfs_error(hdl, EZFS_NOENT, errbuf);
5206 5201                          break;
5207 5202                  default:
5208 5203                          err = zfs_standard_error_fmt(hdl, errno, errbuf);
5209 5204                          break;
5210 5205                  }
5211 5206          }
5212 5207  
5213 5208          return (err);
5214 5209  }
5215 5210  
5216 5211  /*
5217 5212   * The theory of raidz space accounting
5218 5213   *
5219 5214   * The "referenced" property of RAIDZ vdevs is scaled such that a 128KB block
5220 5215   * will "reference" 128KB, even though it allocates more than that, to store the
5221 5216   * parity information (and perhaps skip sectors). This concept of the
5222 5217   * "referenced" (and other DMU space accounting) being lower than the allocated
5223 5218   * space by a constant factor is called "raidz deflation."
5224 5219   *
5225 5220   * As mentioned above, the constant factor for raidz deflation assumes a 128KB
5226 5221   * block size. However, zvols typically have a much smaller block size (default
5227 5222   * 8KB). These smaller blocks may require proportionally much more parity
5228 5223   * information (and perhaps skip sectors). In this case, the change to the
5229 5224   * "referenced" property may be much more than the logical block size.
5230 5225   *
5231 5226   * Suppose a raidz vdev has 5 disks with ashift=12.  A 128k block may be written
5232 5227   * as follows.
5233 5228   *
5234 5229   * +-------+-------+-------+-------+-------+
5235 5230   * | disk1 | disk2 | disk3 | disk4 | disk5 |
5236 5231   * +-------+-------+-------+-------+-------+
5237 5232   * |  P0   |  D0   |  D8   |  D16  |  D24  |
5238 5233   * |  P1   |  D1   |  D9   |  D17  |  D25  |
5239 5234   * |  P2   |  D2   |  D10  |  D18  |  D26  |
5240 5235   * |  P3   |  D3   |  D11  |  D19  |  D27  |
5241 5236   * |  P4   |  D4   |  D12  |  D20  |  D28  |
5242 5237   * |  P5   |  D5   |  D13  |  D21  |  D29  |
5243 5238   * |  P6   |  D6   |  D14  |  D22  |  D30  |
5244 5239   * |  P7   |  D7   |  D15  |  D23  |  D31  |
5245 5240   * +-------+-------+-------+-------+-------+
5246 5241   *
5247 5242   * Above, notice that 160k was allocated: 8 x 4k parity sectors + 32 x 4k data
5248 5243   * sectors.  The dataset's referenced will increase by 128k and the pool's
5249 5244   * allocated and free properties will be adjusted by 160k.
5250 5245   *
5251 5246   * A 4k block written to the same raidz vdev will require two 4k sectors.  The
5252 5247   * blank cells represent unallocated space.
5253 5248   *
5254 5249   * +-------+-------+-------+-------+-------+
5255 5250   * | disk1 | disk2 | disk3 | disk4 | disk5 |
5256 5251   * +-------+-------+-------+-------+-------+
5257 5252   * |  P0   |  D0   |       |       |       |
5258 5253   * +-------+-------+-------+-------+-------+
5259 5254   *
5260 5255   * Above, notice that the 4k block required one sector for parity and another
5261 5256   * for data.  vdev_raidz_asize() will return 8k and as such the pool's allocated
5262 5257   * and free properties will be adjusted by 8k.  The dataset will not be charged
5263 5258   * 8k.  Rather, it will be charged a value that is scaled according to the
5264 5259   * overhead of the 128k block on the same vdev.  This 8k allocation will be
5265 5260   * charged 8k * 128k / 160k.  128k is from SPA_OLD_MAXBLOCKSIZE and 160k is as
5266 5261   * calculated in the 128k block example above.
5267 5262   *
5268 5263   * Every raidz allocation is sized to be a multiple of nparity+1 sectors.  That
5269 5264   * is, every raidz1 allocation will be a multiple of 2 sectors, raidz2
5270 5265   * allocations are a multiple of 3 sectors, and raidz3 allocations are a
5271 5266   * multiple of of 4 sectors.  When a block does not fill the required number of
5272 5267   * sectors, skip blocks (sectors) are used.
5273 5268   *
5274 5269   * An 8k block being written to a raidz vdev may be written as follows:
5275 5270   *
5276 5271   * +-------+-------+-------+-------+-------+
5277 5272   * | disk1 | disk2 | disk3 | disk4 | disk5 |
5278 5273   * +-------+-------+-------+-------+-------+
5279 5274   * |  P0   |  D0   |  D1   |  S0   |       |
5280 5275   * +-------+-------+-------+-------+-------+
5281 5276   *
5282 5277   * In order to maintain the nparity+1 allocation size, a skip block (S0) was
5283 5278   * added.  For this 8k block, the pool's allocated and free properties are
5284 5279   * adjusted by 16k and the dataset's referenced is increased by 16k * 128k /
5285 5280   * 160k.  Again, 128k is from SPA_OLD_MAXBLOCKSIZE and 160k is as calculated in
5286 5281   * the 128k block example above.
5287 5282   *
5288 5283   * Compression may lead to a variety of block sizes being written for the same
5289 5284   * volume or file.  There is no clear way to reserve just the amount of space
5290 5285   * that will be required, so the worst case (no compression) is assumed.
5291 5286   * Note that metadata blocks will typically be compressed, so the reservation
5292 5287   * size returned by zvol_volsize_to_reservation() will generally be slightly
5293 5288   * larger than the maximum that the volume can reference.
5294 5289   */
5295 5290  
5296 5291  /*
5297 5292   * Derived from function of same name in uts/common/fs/zfs/vdev_raidz.c.
5298 5293   * Returns the amount of space (in bytes) that will be allocated for the
5299 5294   * specified block size. Note that the "referenced" space accounted will be less
5300 5295   * than this, but not necessarily equal to "blksize", due to RAIDZ deflation.
5301 5296   */
5302 5297  static uint64_t
5303 5298  vdev_raidz_asize(uint64_t ndisks, uint64_t nparity, uint64_t ashift,
5304 5299      uint64_t blksize)
5305 5300  {
5306 5301          uint64_t asize, ndata;
5307 5302  
5308 5303          ASSERT3U(ndisks, >, nparity);
5309 5304          ndata = ndisks - nparity;
5310 5305          asize = ((blksize - 1) >> ashift) + 1;
5311 5306          asize += nparity * ((asize + ndata - 1) / ndata);
5312 5307          asize = roundup(asize, nparity + 1) << ashift;
5313 5308  
5314 5309          return (asize);
5315 5310  }
5316 5311  
5317 5312  /*
5318 5313   * Determine how much space will be allocated if it lands on the most space-
5319 5314   * inefficient top-level vdev.  Returns the size in bytes required to store one
5320 5315   * copy of the volume data.  See theory comment above.
5321 5316   */
5322 5317  static uint64_t
5323 5318  volsize_from_vdevs(zpool_handle_t *zhp, uint64_t nblocks, uint64_t blksize)
5324 5319  {
5325 5320          nvlist_t *config, *tree, **vdevs;
5326 5321          uint_t nvdevs, v;
5327 5322          uint64_t ret = 0;
5328 5323  
5329 5324          config = zpool_get_config(zhp, NULL);
5330 5325          if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) != 0 ||
5331 5326              nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN,
5332 5327              &vdevs, &nvdevs) != 0) {
5333 5328                  return (nblocks * blksize);
5334 5329          }
5335 5330  
5336 5331          for (v = 0; v < nvdevs; v++) {
5337 5332                  char *type;
5338 5333                  uint64_t nparity, ashift, asize, tsize;
5339 5334                  nvlist_t **disks;
5340 5335                  uint_t ndisks;
5341 5336                  uint64_t volsize;
5342 5337  
5343 5338                  if (nvlist_lookup_string(vdevs[v], ZPOOL_CONFIG_TYPE,
5344 5339                      &type) != 0 || strcmp(type, VDEV_TYPE_RAIDZ) != 0 ||
5345 5340                      nvlist_lookup_uint64(vdevs[v], ZPOOL_CONFIG_NPARITY,
5346 5341                      &nparity) != 0 ||
5347 5342                      nvlist_lookup_uint64(vdevs[v], ZPOOL_CONFIG_ASHIFT,
5348 5343                      &ashift) != 0 ||
5349 5344                      nvlist_lookup_nvlist_array(vdevs[v], ZPOOL_CONFIG_CHILDREN,
5350 5345                      &disks, &ndisks) != 0) {
5351 5346                          continue;
5352 5347                  }
5353 5348  
5354 5349                  /* allocation size for the "typical" 128k block */
5355 5350                  tsize = vdev_raidz_asize(ndisks, nparity, ashift,
5356 5351                      SPA_OLD_MAXBLOCKSIZE);
5357 5352                  /* allocation size for the blksize block */
5358 5353                  asize = vdev_raidz_asize(ndisks, nparity, ashift, blksize);
5359 5354  
5360 5355                  /*
5361 5356                   * Scale this size down as a ratio of 128k / tsize.  See theory
5362 5357                   * statement above.
5363 5358                   */
5364 5359                  volsize = nblocks * asize * SPA_OLD_MAXBLOCKSIZE / tsize;
5365 5360                  if (volsize > ret) {
5366 5361                          ret = volsize;
5367 5362                  }
5368 5363          }
5369 5364  
5370 5365          if (ret == 0) {
5371 5366                  ret = nblocks * blksize;
5372 5367          }
5373 5368  
5374 5369          return (ret);
5375 5370  }
5376 5371  
5377 5372  /*
5378 5373   * Convert the zvol's volume size to an appropriate reservation.  See theory
5379 5374   * comment above.
5380 5375   *
5381 5376   * Note: If this routine is updated, it is necessary to update the ZFS test
5382 5377   * suite's shell version in reservation.shlib.
5383 5378   */
5384 5379  uint64_t
5385 5380  zvol_volsize_to_reservation(zpool_handle_t *zph, uint64_t volsize,
5386 5381      nvlist_t *props)
5387 5382  {
5388 5383          uint64_t numdb;
5389 5384          uint64_t nblocks, volblocksize;
5390 5385          int ncopies;
5391 5386          char *strval;
5392 5387  
5393 5388          if (nvlist_lookup_string(props,
5394 5389              zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
5395 5390                  ncopies = atoi(strval);
5396 5391          else
5397 5392                  ncopies = 1;
5398 5393          if (nvlist_lookup_uint64(props,
5399 5394              zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
5400 5395              &volblocksize) != 0)
5401 5396                  volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
5402 5397  
5403 5398          nblocks = volsize / volblocksize;
5404 5399          /*
5405 5400           * Metadata defaults to using 128k blocks, not volblocksize blocks.  For
5406 5401           * this reason, only the data blocks are scaled based on vdev config.
5407 5402           */
5408 5403          volsize = volsize_from_vdevs(zph, nblocks, volblocksize);
5409 5404  
5410 5405          /* start with metadnode L0-L6 */
5411 5406          numdb = 7;
5412 5407          /* calculate number of indirects */
5413 5408          while (nblocks > 1) {
5414 5409                  nblocks += DNODES_PER_LEVEL - 1;
5415 5410                  nblocks /= DNODES_PER_LEVEL;
5416 5411                  numdb += nblocks;
5417 5412          }
5418 5413          numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
5419 5414          volsize *= ncopies;
5420 5415          /*
5421 5416           * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
5422 5417           * compressed, but in practice they compress down to about
5423 5418           * 1100 bytes
5424 5419           */
5425 5420          numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
5426 5421          volsize += numdb;
5427 5422          return (volsize);
5428 5423  }
  
    | 
      ↓ open down ↓ | 
    4082 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX