Print this page
    
NEX-16623 Ability to set properties for multiple datasets/snapshots during single sync-round
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-7822 40Gb Intel XL710 NIC performance data
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-8827 AUTOSNAP: can't register recursive zone when there is a child under autosnappool/volumegrou
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5987 need to change ssm wearout threshold to 90%
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5925 KRRP: Incorrect collecting of snap-props causes errors during recv
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alexey Komarov <alexey.komarov@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5795 Rename 'wrc' as 'wbc' in the source and in the tech docs
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-5341 Race condition causes wrc_004_pos to panic the system
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5319 Panic trying to rename zvol used as COMSTAR lu
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5060 WBC: Writecache and deduplication should not be used together
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4934 Add capability to remove special vdev
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-4830 writecache=off leaks data on special vdev (the data will never migrate)
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4608 WRC: Possible deadlock during the disabling of WRC for a dataset
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
6160 /usr/lib/fs/zfs/bootinstall should use bootadm
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
Reviewed by: Adam Števko <adam.stevko@gmail.com>
Reviewed by: Josef Sipek <jeffpc@josefsipek.net>
Approved by: Richard Lowe <richlowe@richlowe.net>
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R (NULL is not an int)
6171 dsl_prop_unregister() slows down dataset eviction.
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Approved by: Dan McDonald <danmcd@omniti.com>
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Revert "NEX-4476 WRC: Allow to use write back cache per tree of datasets"
This reverts commit fe97b74444278a6f36fec93179133641296312da.
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Remaining fixes for the illumos merge
re #12619 rb4429 More dp->dp_config_rwlock holds
re #13253 rb4328 ssh: openssl version checking needs updating
re #11441 rb4292 panic in apic_record_rdt_entry on VMware hardware version 9
re #12619, rb4287 Deadlocked zfs txg processing in dsl_sync_task_group_sync()
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/zfs/dsl_prop.c
          +++ new/usr/src/uts/common/fs/zfs/dsl_prop.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  
    | 
      ↓ open down ↓ | 
    15 lines elided | 
    
      ↑ open up ↑ | 
  
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  24   24   * Copyright (c) 2013 Martin Matuska. All rights reserved.
  25   25   * Copyright 2015, Joyent, Inc.
       26 + * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  26   27   */
  27   28  
  28   29  #include <sys/zfs_context.h>
  29   30  #include <sys/dmu.h>
  30   31  #include <sys/dmu_objset.h>
  31   32  #include <sys/dmu_tx.h>
  32   33  #include <sys/dsl_dataset.h>
  33   34  #include <sys/dsl_dir.h>
  34   35  #include <sys/dsl_prop.h>
  35   36  #include <sys/dsl_synctask.h>
       37 +#include <sys/zfeature.h>
  36   38  #include <sys/spa.h>
  37   39  #include <sys/zap.h>
  38   40  #include <sys/fs/zfs.h>
       41 +#include <sys/wbc.h>
  39   42  
  40   43  #include "zfs_prop.h"
       44 +#include "zfs_errno.h"
  41   45  
  42      -#define ZPROP_INHERIT_SUFFIX "$inherit"
  43      -#define ZPROP_RECVD_SUFFIX "$recvd"
  44      -
  45   46  static int
  46   47  dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
  47   48  {
  48   49          /*
  49   50           * The setonce properties are read-only, BUT they still
  50   51           * have a default value that can be used as the initial
  51   52           * value.
  52   53           */
  53   54          if (prop == ZPROP_INVAL ||
  54   55              (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
  55   56                  return (SET_ERROR(ENOENT));
  56   57  
  57   58          if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
  58   59                  if (intsz != 1)
  59   60                          return (SET_ERROR(EOVERFLOW));
  60   61                  (void) strncpy(buf, zfs_prop_default_string(prop),
  61   62                      numints);
  62   63          } else {
  63   64                  if (intsz != 8 || numints < 1)
  64   65                          return (SET_ERROR(EOVERFLOW));
  65   66  
  66   67                  *(uint64_t *)buf = zfs_prop_default_numeric(prop);
  67   68          }
  68   69  
  69   70          return (0);
  70   71  }
  71   72  
  72   73  int
  73   74  dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
  74   75      int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
  75   76  {
  76   77          int err = ENOENT;
  77   78          dsl_dir_t *target = dd;
  78   79          objset_t *mos = dd->dd_pool->dp_meta_objset;
  79   80          zfs_prop_t prop;
  80   81          boolean_t inheritable;
  81   82          boolean_t inheriting = B_FALSE;
  82   83          char *inheritstr;
  83   84          char *recvdstr;
  84   85  
  85   86          ASSERT(dsl_pool_config_held(dd->dd_pool));
  86   87  
  87   88          if (setpoint)
  88   89                  setpoint[0] = '\0';
  89   90  
  90   91          prop = zfs_name_to_prop(propname);
  91   92          inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
  92   93          inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
  93   94          recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
  94   95  
  95   96          /*
  96   97           * Note: dd may become NULL, therefore we shouldn't dereference it
  97   98           * after this loop.
  98   99           */
  99  100          for (; dd != NULL; dd = dd->dd_parent) {
 100  101                  if (dd != target || snapshot) {
 101  102                          if (!inheritable)
 102  103                                  break;
 103  104                          inheriting = B_TRUE;
 104  105                  }
 105  106  
 106  107                  /* Check for a local value. */
 107  108                  err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 108  109                      propname, intsz, numints, buf);
 109  110                  if (err != ENOENT) {
 110  111                          if (setpoint != NULL && err == 0)
 111  112                                  dsl_dir_name(dd, setpoint);
 112  113                          break;
 113  114                  }
 114  115  
 115  116                  /*
 116  117                   * Skip the check for a received value if there is an explicit
 117  118                   * inheritance entry.
 118  119                   */
 119  120                  err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 120  121                      inheritstr);
 121  122                  if (err != 0 && err != ENOENT)
 122  123                          break;
 123  124  
 124  125                  if (err == ENOENT) {
 125  126                          /* Check for a received value. */
 126  127                          err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 127  128                              recvdstr, intsz, numints, buf);
 128  129                          if (err != ENOENT) {
 129  130                                  if (setpoint != NULL && err == 0) {
 130  131                                          if (inheriting) {
 131  132                                                  dsl_dir_name(dd, setpoint);
 132  133                                          } else {
 133  134                                                  (void) strcpy(setpoint,
 134  135                                                      ZPROP_SOURCE_VAL_RECVD);
 135  136                                          }
 136  137                                  }
 137  138                                  break;
 138  139                          }
 139  140                  }
 140  141  
 141  142                  /*
 142  143                   * If we found an explicit inheritance entry, err is zero even
 143  144                   * though we haven't yet found the value, so reinitializing err
 144  145                   * at the end of the loop (instead of at the beginning) ensures
 145  146                   * that err has a valid post-loop value.
 146  147                   */
 147  148                  err = SET_ERROR(ENOENT);
 148  149          }
 149  150  
 150  151          if (err == ENOENT)
 151  152                  err = dodefault(prop, intsz, numints, buf);
 152  153  
 153  154          strfree(inheritstr);
 154  155          strfree(recvdstr);
 155  156  
 156  157          return (err);
 157  158  }
 158  159  
 159  160  int
 160  161  dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
 161  162      int intsz, int numints, void *buf, char *setpoint)
 162  163  {
 163  164          zfs_prop_t prop = zfs_name_to_prop(propname);
 164  165          boolean_t inheritable;
 165  166          uint64_t zapobj;
 166  167  
 167  168          ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 168  169          inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
 169  170          zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 170  171  
 171  172          if (zapobj != 0) {
 172  173                  objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 173  174                  int err;
 174  175  
 175  176                  ASSERT(ds->ds_is_snapshot);
 176  177  
 177  178                  /* Check for a local value. */
 178  179                  err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
 179  180                  if (err != ENOENT) {
 180  181                          if (setpoint != NULL && err == 0)
 181  182                                  dsl_dataset_name(ds, setpoint);
 182  183                          return (err);
 183  184                  }
 184  185  
 185  186                  /*
 186  187                   * Skip the check for a received value if there is an explicit
 187  188                   * inheritance entry.
 188  189                   */
 189  190                  if (inheritable) {
 190  191                          char *inheritstr = kmem_asprintf("%s%s", propname,
 191  192                              ZPROP_INHERIT_SUFFIX);
 192  193                          err = zap_contains(mos, zapobj, inheritstr);
 193  194                          strfree(inheritstr);
 194  195                          if (err != 0 && err != ENOENT)
 195  196                                  return (err);
 196  197                  }
 197  198  
 198  199                  if (err == ENOENT) {
 199  200                          /* Check for a received value. */
 200  201                          char *recvdstr = kmem_asprintf("%s%s", propname,
 201  202                              ZPROP_RECVD_SUFFIX);
 202  203                          err = zap_lookup(mos, zapobj, recvdstr,
 203  204                              intsz, numints, buf);
 204  205                          strfree(recvdstr);
 205  206                          if (err != ENOENT) {
 206  207                                  if (setpoint != NULL && err == 0)
 207  208                                          (void) strcpy(setpoint,
 208  209                                              ZPROP_SOURCE_VAL_RECVD);
 209  210                                  return (err);
 210  211                          }
 211  212                  }
 212  213          }
 213  214  
 214  215          return (dsl_prop_get_dd(ds->ds_dir, propname,
 215  216              intsz, numints, buf, setpoint, ds->ds_is_snapshot));
 216  217  }
 217  218  
 218  219  static dsl_prop_record_t *
 219  220  dsl_prop_record_find(dsl_dir_t *dd, const char *propname)
 220  221  {
 221  222          dsl_prop_record_t *pr = NULL;
 222  223  
 223  224          ASSERT(MUTEX_HELD(&dd->dd_lock));
 224  225  
 225  226          for (pr = list_head(&dd->dd_props);
 226  227              pr != NULL; pr = list_next(&dd->dd_props, pr)) {
 227  228                  if (strcmp(pr->pr_propname, propname) == 0)
 228  229                          break;
 229  230          }
 230  231  
 231  232          return (pr);
 232  233  }
 233  234  
 234  235  static dsl_prop_record_t *
 235  236  dsl_prop_record_create(dsl_dir_t *dd, const char *propname)
 236  237  {
 237  238          dsl_prop_record_t *pr;
 238  239  
 239  240          ASSERT(MUTEX_HELD(&dd->dd_lock));
 240  241  
 241  242          pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP);
 242  243          pr->pr_propname = spa_strdup(propname);
 243  244          list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t),
 244  245              offsetof(dsl_prop_cb_record_t, cbr_pr_node));
 245  246          list_insert_head(&dd->dd_props, pr);
 246  247  
 247  248          return (pr);
 248  249  }
 249  250  
 250  251  void
 251  252  dsl_prop_init(dsl_dir_t *dd)
 252  253  {
 253  254          list_create(&dd->dd_props, sizeof (dsl_prop_record_t),
 254  255              offsetof(dsl_prop_record_t, pr_node));
 255  256  }
 256  257  
 257  258  void
 258  259  dsl_prop_fini(dsl_dir_t *dd)
 259  260  {
 260  261          dsl_prop_record_t *pr;
 261  262  
 262  263          while ((pr = list_remove_head(&dd->dd_props)) != NULL) {
 263  264                  list_destroy(&pr->pr_cbs);
 264  265                  strfree((char *)pr->pr_propname);
 265  266                  kmem_free(pr, sizeof (dsl_prop_record_t));
 266  267          }
 267  268          list_destroy(&dd->dd_props);
 268  269  }
 269  270  
 270  271  /*
 271  272   * Register interest in the named property.  We'll call the callback
 272  273   * once to notify it of the current property value, and again each time
 273  274   * the property changes, until this callback is unregistered.
 274  275   *
 275  276   * Return 0 on success, errno if the prop is not an integer value.
 276  277   */
 277  278  int
 278  279  dsl_prop_register(dsl_dataset_t *ds, const char *propname,
 279  280      dsl_prop_changed_cb_t *callback, void *cbarg)
  
    | 
      ↓ open down ↓ | 
    225 lines elided | 
    
      ↑ open up ↑ | 
  
 280  281  {
 281  282          dsl_dir_t *dd = ds->ds_dir;
 282  283          dsl_pool_t *dp = dd->dd_pool;
 283  284          uint64_t value;
 284  285          dsl_prop_record_t *pr;
 285  286          dsl_prop_cb_record_t *cbr;
 286  287          int err;
 287  288  
 288  289          ASSERT(dsl_pool_config_held(dp));
 289  290  
 290      -        err = dsl_prop_get_int_ds(ds, propname, &value);
      291 +        if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
      292 +                wbc_mode_prop_val_t val;
      293 +
      294 +                err = dsl_prop_get_ds(ds, propname, 8,
      295 +                    WBC_MODE_PROP_VAL_SZ, &val, NULL);
      296 +                if (err == 0)
      297 +                        value = (uintptr_t)((void *)&val);
      298 +        } else
      299 +                err = dsl_prop_get_int_ds(ds, propname, &value);
      300 +
 291  301          if (err != 0)
 292  302                  return (err);
 293  303  
 294  304          cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
 295  305          cbr->cbr_ds = ds;
 296  306          cbr->cbr_func = callback;
 297  307          cbr->cbr_arg = cbarg;
 298  308  
 299  309          mutex_enter(&dd->dd_lock);
 300  310          pr = dsl_prop_record_find(dd, propname);
 301  311          if (pr == NULL)
 302  312                  pr = dsl_prop_record_create(dd, propname);
 303  313          cbr->cbr_pr = pr;
 304  314          list_insert_head(&pr->pr_cbs, cbr);
 305  315          list_insert_head(&ds->ds_prop_cbs, cbr);
 306  316          mutex_exit(&dd->dd_lock);
 307  317  
 308  318          cbr->cbr_func(cbr->cbr_arg, value);
 309  319          return (0);
 310  320  }
 311  321  
 312  322  int
 313  323  dsl_prop_get(const char *dsname, const char *propname,
 314  324      int intsz, int numints, void *buf, char *setpoint)
 315  325  {
 316  326          objset_t *os;
 317  327          int error;
 318  328  
 319  329          error = dmu_objset_hold(dsname, FTAG, &os);
 320  330          if (error != 0)
 321  331                  return (error);
 322  332  
 323  333          error = dsl_prop_get_ds(dmu_objset_ds(os), propname,
 324  334              intsz, numints, buf, setpoint);
 325  335  
 326  336          dmu_objset_rele(os, FTAG);
 327  337          return (error);
 328  338  }
 329  339  
 330  340  /*
 331  341   * Get the current property value.  It may have changed by the time this
 332  342   * function returns, so it is NOT safe to follow up with
 333  343   * dsl_prop_register() and assume that the value has not changed in
 334  344   * between.
 335  345   *
 336  346   * Return 0 on success, ENOENT if ddname is invalid.
 337  347   */
 338  348  int
 339  349  dsl_prop_get_integer(const char *ddname, const char *propname,
 340  350      uint64_t *valuep, char *setpoint)
 341  351  {
 342  352          return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
 343  353  }
 344  354  
 345  355  int
 346  356  dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname,
 347  357      uint64_t *valuep)
 348  358  {
 349  359          return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL));
 350  360  }
 351  361  
 352  362  /*
 353  363   * Predict the effective value of the given special property if it were set with
 354  364   * the given value and source. This is not a general purpose function. It exists
 355  365   * only to handle the special requirements of the quota and reservation
 356  366   * properties. The fact that these properties are non-inheritable greatly
 357  367   * simplifies the prediction logic.
 358  368   *
 359  369   * Returns 0 on success, a positive error code on failure, or -1 if called with
 360  370   * a property not handled by this function.
 361  371   */
 362  372  int
 363  373  dsl_prop_predict(dsl_dir_t *dd, const char *propname,
 364  374      zprop_source_t source, uint64_t value, uint64_t *newvalp)
 365  375  {
 366  376          zfs_prop_t prop = zfs_name_to_prop(propname);
 367  377          objset_t *mos;
 368  378          uint64_t zapobj;
 369  379          uint64_t version;
 370  380          char *recvdstr;
 371  381          int err = 0;
 372  382  
 373  383          switch (prop) {
 374  384          case ZFS_PROP_QUOTA:
 375  385          case ZFS_PROP_RESERVATION:
 376  386          case ZFS_PROP_REFQUOTA:
 377  387          case ZFS_PROP_REFRESERVATION:
 378  388                  break;
 379  389          default:
 380  390                  return (-1);
 381  391          }
 382  392  
 383  393          mos = dd->dd_pool->dp_meta_objset;
 384  394          zapobj = dsl_dir_phys(dd)->dd_props_zapobj;
 385  395          recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
 386  396  
 387  397          version = spa_version(dd->dd_pool->dp_spa);
 388  398          if (version < SPA_VERSION_RECVD_PROPS) {
 389  399                  if (source & ZPROP_SRC_NONE)
 390  400                          source = ZPROP_SRC_NONE;
 391  401                  else if (source & ZPROP_SRC_RECEIVED)
 392  402                          source = ZPROP_SRC_LOCAL;
 393  403          }
 394  404  
 395  405          switch (source) {
 396  406          case ZPROP_SRC_NONE:
 397  407                  /* Revert to the received value, if any. */
 398  408                  err = zap_lookup(mos, zapobj, recvdstr, 8, 1, newvalp);
 399  409                  if (err == ENOENT)
 400  410                          *newvalp = 0;
 401  411                  break;
 402  412          case ZPROP_SRC_LOCAL:
 403  413                  *newvalp = value;
 404  414                  break;
 405  415          case ZPROP_SRC_RECEIVED:
 406  416                  /*
 407  417                   * If there's no local setting, then the new received value will
 408  418                   * be the effective value.
 409  419                   */
 410  420                  err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
 411  421                  if (err == ENOENT)
 412  422                          *newvalp = value;
 413  423                  break;
 414  424          case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
 415  425                  /*
 416  426                   * We're clearing the received value, so the local setting (if
 417  427                   * it exists) remains the effective value.
 418  428                   */
 419  429                  err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
 420  430                  if (err == ENOENT)
 421  431                          *newvalp = 0;
 422  432                  break;
 423  433          default:
 424  434                  panic("unexpected property source: %d", source);
 425  435          }
 426  436  
 427  437          strfree(recvdstr);
 428  438  
 429  439          if (err == ENOENT)
 430  440                  return (0);
 431  441  
 432  442          return (err);
 433  443  }
 434  444  
 435  445  /*
 436  446   * Unregister all callbacks that are registered with the
 437  447   * given callback argument.
 438  448   */
 439  449  void
 440  450  dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg)
 441  451  {
 442  452          dsl_prop_cb_record_t *cbr, *next_cbr;
 443  453  
 444  454          dsl_dir_t *dd = ds->ds_dir;
 445  455  
 446  456          mutex_enter(&dd->dd_lock);
 447  457          next_cbr = list_head(&ds->ds_prop_cbs);
 448  458          while (next_cbr != NULL) {
 449  459                  cbr = next_cbr;
 450  460                  next_cbr = list_next(&ds->ds_prop_cbs, cbr);
 451  461                  if (cbr->cbr_arg == cbarg) {
 452  462                          list_remove(&ds->ds_prop_cbs, cbr);
 453  463                          list_remove(&cbr->cbr_pr->pr_cbs, cbr);
 454  464                          kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
 455  465                  }
 456  466          }
 457  467          mutex_exit(&dd->dd_lock);
 458  468  }
 459  469  
 460  470  boolean_t
 461  471  dsl_prop_hascb(dsl_dataset_t *ds)
 462  472  {
 463  473          return (!list_is_empty(&ds->ds_prop_cbs));
 464  474  }
 465  475  
 466  476  /* ARGSUSED */
 467  477  static int
 468  478  dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
 469  479  {
  
    | 
      ↓ open down ↓ | 
    169 lines elided | 
    
      ↑ open up ↑ | 
  
 470  480          dsl_dir_t *dd = ds->ds_dir;
 471  481          dsl_prop_record_t *pr;
 472  482          dsl_prop_cb_record_t *cbr;
 473  483  
 474  484          mutex_enter(&dd->dd_lock);
 475  485          for (pr = list_head(&dd->dd_props);
 476  486              pr; pr = list_next(&dd->dd_props, pr)) {
 477  487                  for (cbr = list_head(&pr->pr_cbs); cbr;
 478  488                      cbr = list_next(&pr->pr_cbs, cbr)) {
 479  489                          uint64_t value;
      490 +                        const char *propname;
 480  491  
 481  492                          /*
 482  493                           * Callback entries do not have holds on their
 483  494                           * datasets so that datasets with registered
 484  495                           * callbacks are still eligible for eviction.
 485  496                           * Unlike operations to update properties on a
 486  497                           * single dataset, we are performing a recursive
 487  498                           * descent of related head datasets.  The caller
 488  499                           * of this function only has a dataset hold on
 489  500                           * the passed in head dataset, not the snapshots
 490  501                           * associated with this dataset.  Without a hold,
 491  502                           * the dataset pointer within callback records
 492  503                           * for snapshots can be invalidated by eviction
 493  504                           * at any time.
 494  505                           *
 495  506                           * Use dsl_dataset_try_add_ref() to verify
 496  507                           * that the dataset for a snapshot has not
  
    | 
      ↓ open down ↓ | 
    7 lines elided | 
    
      ↑ open up ↑ | 
  
 497  508                           * begun eviction processing and to prevent
 498  509                           * eviction from occurring for the duration of
 499  510                           * the callback.  If the hold attempt fails,
 500  511                           * this object is already being evicted and the
 501  512                           * callback can be safely ignored.
 502  513                           */
 503  514                          if (ds != cbr->cbr_ds &&
 504  515                              !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
 505  516                                  continue;
 506  517  
 507      -                        if (dsl_prop_get_ds(cbr->cbr_ds,
 508      -                            cbr->cbr_pr->pr_propname, sizeof (value), 1,
 509      -                            &value, NULL) == 0)
      518 +                        propname = cbr->cbr_pr->pr_propname;
      519 +                        if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
      520 +                                wbc_mode_prop_val_t val;
      521 +
      522 +                                if (dsl_prop_get_ds(cbr->cbr_ds, propname, 8,
      523 +                                    WBC_MODE_PROP_VAL_SZ, &val, NULL) == 0) {
      524 +                                        value = (uintptr_t)((void *)&val);
      525 +                                        cbr->cbr_func(cbr->cbr_arg, value);
      526 +                                }
      527 +                        } else if (dsl_prop_get_ds(cbr->cbr_ds, propname,
      528 +                            sizeof (value), 1, &value, NULL) == 0) {
 510  529                                  cbr->cbr_func(cbr->cbr_arg, value);
      530 +                        }
 511  531  
 512  532                          if (ds != cbr->cbr_ds)
 513  533                                  dsl_dataset_rele(cbr->cbr_ds, FTAG);
 514  534                  }
 515  535          }
 516  536          mutex_exit(&dd->dd_lock);
 517  537  
 518  538          return (0);
 519  539  }
 520  540  
 521  541  /*
 522  542   * Update all property values for ddobj & its descendants.  This is used
 523  543   * when renaming the dir.
 524  544   */
 525  545  void
 526  546  dsl_prop_notify_all(dsl_dir_t *dd)
 527  547  {
 528  548          dsl_pool_t *dp = dd->dd_pool;
 529  549          ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
 530  550          (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
 531  551              NULL, DS_FIND_CHILDREN);
 532  552  }
 533  553  
 534  554  static void
 535  555  dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
 536  556      const char *propname, uint64_t value, int first)
 537  557  {
 538  558          dsl_dir_t *dd;
 539  559          dsl_prop_record_t *pr;
 540  560          dsl_prop_cb_record_t *cbr;
 541  561          objset_t *mos = dp->dp_meta_objset;
 542  562          zap_cursor_t zc;
 543  563          zap_attribute_t *za;
 544  564          int err;
 545  565  
 546  566          ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
 547  567          err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd);
 548  568          if (err)
 549  569                  return;
 550  570  
 551  571          if (!first) {
 552  572                  /*
 553  573                   * If the prop is set here, then this change is not
 554  574                   * being inherited here or below; stop the recursion.
 555  575                   */
 556  576                  err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 557  577                      propname);
 558  578                  if (err == 0) {
 559  579                          dsl_dir_rele(dd, FTAG);
 560  580                          return;
 561  581                  }
 562  582                  ASSERT3U(err, ==, ENOENT);
 563  583          }
 564  584  
 565  585          mutex_enter(&dd->dd_lock);
 566  586          pr = dsl_prop_record_find(dd, propname);
 567  587          if (pr != NULL) {
 568  588                  for (cbr = list_head(&pr->pr_cbs); cbr;
 569  589                      cbr = list_next(&pr->pr_cbs, cbr)) {
 570  590                          uint64_t propobj;
 571  591  
 572  592                          /*
 573  593                           * cbr->cbr_ds may be invalidated due to eviction,
 574  594                           * requiring the use of dsl_dataset_try_add_ref().
 575  595                           * See comment block in dsl_prop_notify_all_cb()
 576  596                           * for details.
 577  597                           */
 578  598                          if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
 579  599                                  continue;
 580  600  
 581  601                          propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
 582  602  
 583  603                          /*
 584  604                           * If the property is not set on this ds, then it is
 585  605                           * inherited here; call the callback.
 586  606                           */
 587  607                          if (propobj == 0 ||
 588  608                              zap_contains(mos, propobj, propname) != 0)
 589  609                                  cbr->cbr_func(cbr->cbr_arg, value);
 590  610  
 591  611                          dsl_dataset_rele(cbr->cbr_ds, FTAG);
 592  612                  }
 593  613          }
 594  614          mutex_exit(&dd->dd_lock);
 595  615  
 596  616          za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
 597  617          for (zap_cursor_init(&zc, mos,
 598  618              dsl_dir_phys(dd)->dd_child_dir_zapobj);
 599  619              zap_cursor_retrieve(&zc, za) == 0;
 600  620              zap_cursor_advance(&zc)) {
 601  621                  dsl_prop_changed_notify(dp, za->za_first_integer,
 602  622                      propname, value, FALSE);
 603  623          }
 604  624          kmem_free(za, sizeof (zap_attribute_t));
 605  625          zap_cursor_fini(&zc);
 606  626          dsl_dir_rele(dd, FTAG);
 607  627  }
 608  628  
 609  629  void
 610  630  dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
 611  631      zprop_source_t source, int intsz, int numints, const void *value,
 612  632      dmu_tx_t *tx)
  
    | 
      ↓ open down ↓ | 
    92 lines elided | 
    
      ↑ open up ↑ | 
  
 613  633  {
 614  634          objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 615  635          uint64_t zapobj, intval, dummy;
 616  636          int isint;
 617  637          char valbuf[32];
 618  638          const char *valstr = NULL;
 619  639          char *inheritstr;
 620  640          char *recvdstr;
 621  641          char *tbuf = NULL;
 622  642          int err;
 623      -        uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
      643 +        spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
      644 +        uint64_t version = spa_version(spa);
 624  645  
 625  646          isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
 626  647  
 627  648          if (ds->ds_is_snapshot) {
 628  649                  ASSERT(version >= SPA_VERSION_SNAP_PROPS);
 629  650                  if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
 630  651                          dmu_buf_will_dirty(ds->ds_dbuf, tx);
 631  652                          dsl_dataset_phys(ds)->ds_props_obj =
 632  653                              zap_create(mos,
 633  654                              DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
 634  655                  }
 635  656                  zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 636  657          } else {
 637  658                  zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
 638  659          }
 639  660  
 640  661          if (version < SPA_VERSION_RECVD_PROPS) {
 641  662                  if (source & ZPROP_SRC_NONE)
 642  663                          source = ZPROP_SRC_NONE;
 643  664                  else if (source & ZPROP_SRC_RECEIVED)
 644  665                          source = ZPROP_SRC_LOCAL;
 645  666          }
 646  667  
 647  668          inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
 648  669          recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
 649  670  
 650  671          switch (source) {
 651  672          case ZPROP_SRC_NONE:
 652  673                  /*
 653  674                   * revert to received value, if any (inherit -S)
 654  675                   * - remove propname
 655  676                   * - remove propname$inherit
 656  677                   */
 657  678                  err = zap_remove(mos, zapobj, propname, tx);
 658  679                  ASSERT(err == 0 || err == ENOENT);
 659  680                  err = zap_remove(mos, zapobj, inheritstr, tx);
 660  681                  ASSERT(err == 0 || err == ENOENT);
 661  682                  break;
 662  683          case ZPROP_SRC_LOCAL:
 663  684                  /*
 664  685                   * remove propname$inherit
 665  686                   * set propname -> value
 666  687                   */
 667  688                  err = zap_remove(mos, zapobj, inheritstr, tx);
 668  689                  ASSERT(err == 0 || err == ENOENT);
 669  690                  VERIFY0(zap_update(mos, zapobj, propname,
 670  691                      intsz, numints, value, tx));
 671  692                  break;
 672  693          case ZPROP_SRC_INHERITED:
 673  694                  /*
 674  695                   * explicitly inherit
 675  696                   * - remove propname
 676  697                   * - set propname$inherit
 677  698                   */
 678  699                  err = zap_remove(mos, zapobj, propname, tx);
 679  700                  ASSERT(err == 0 || err == ENOENT);
 680  701                  if (version >= SPA_VERSION_RECVD_PROPS &&
 681  702                      dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) {
 682  703                          dummy = 0;
 683  704                          VERIFY0(zap_update(mos, zapobj, inheritstr,
 684  705                              8, 1, &dummy, tx));
 685  706                  }
 686  707                  break;
 687  708          case ZPROP_SRC_RECEIVED:
 688  709                  /*
 689  710                   * set propname$recvd -> value
 690  711                   */
 691  712                  err = zap_update(mos, zapobj, recvdstr,
 692  713                      intsz, numints, value, tx);
 693  714                  ASSERT(err == 0);
 694  715                  break;
 695  716          case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
 696  717                  /*
 697  718                   * clear local and received settings
 698  719                   * - remove propname
 699  720                   * - remove propname$inherit
 700  721                   * - remove propname$recvd
 701  722                   */
 702  723                  err = zap_remove(mos, zapobj, propname, tx);
 703  724                  ASSERT(err == 0 || err == ENOENT);
 704  725                  err = zap_remove(mos, zapobj, inheritstr, tx);
 705  726                  ASSERT(err == 0 || err == ENOENT);
 706  727                  /* FALLTHRU */
 707  728          case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
 708  729                  /*
 709  730                   * remove propname$recvd
 710  731                   */
  
    | 
      ↓ open down ↓ | 
    77 lines elided | 
    
      ↑ open up ↑ | 
  
 711  732                  err = zap_remove(mos, zapobj, recvdstr, tx);
 712  733                  ASSERT(err == 0 || err == ENOENT);
 713  734                  break;
 714  735          default:
 715  736                  cmn_err(CE_PANIC, "unexpected property source: %d", source);
 716  737          }
 717  738  
 718  739          strfree(inheritstr);
 719  740          strfree(recvdstr);
 720  741  
 721      -        if (isint) {
      742 +        if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
      743 +                wbc_mode_prop_val_t val;
      744 +
      745 +                VERIFY0(dsl_prop_get_ds(ds, propname, 8,
      746 +                    WBC_MODE_PROP_VAL_SZ, &val, NULL));
      747 +
      748 +                dsl_prop_changed_notify(ds->ds_dir->dd_pool,
      749 +                    ds->ds_dir->dd_object, propname,
      750 +                    (uintptr_t)((void *)&val), TRUE);
      751 +
      752 +                /*
      753 +                 * Flow diagram of ZFS_PROP_WBC_MODE states
      754 +                 *
      755 +                 * off (root_ds_object == 0, txg_off == 0)
      756 +                 *      (user sees wbc_mode=off, source=default)
      757 +                 *
      758 +                 *      user operation "set on" ==>>
      759 +                 *
      760 +                 * on (root_ds_object != 0, txg_off == 0)
      761 +                 *      (user sees wbc_mode=on, source=local)
      762 +                 *
      763 +                 *      user operation "set off" ==>>
      764 +                 *
      765 +                 * off_delayed (root_ds_object != 0, txg_off != 0)
      766 +                 *      (user sees wbc_mode=off, source=local)
      767 +                 *
      768 +                 *      internal operation "inherit" ==>>
      769 +                 *
      770 +                 * off (root_ds_object == 0, txg_off == 0)
      771 +                 *      (user sees wbc_mode=off, source=default)
      772 +                 */
      773 +                if (val.root_ds_object == 0)
      774 +                        spa_feature_decr(spa, SPA_FEATURE_WBC, tx);
      775 +                else if (val.txg_off == 0)
      776 +                        spa_feature_incr(spa, SPA_FEATURE_WBC, tx);
      777 +
      778 +                (void) snprintf(valbuf, sizeof (valbuf),
      779 +                    "%s", (val.root_ds_object != 0 &&
      780 +                    val.txg_off == 0) ? "on" : "off");
      781 +                valstr = valbuf;
      782 +        } else if (isint) {
 722  783                  VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
 723  784  
 724  785                  if (ds->ds_is_snapshot) {
 725  786                          dsl_prop_cb_record_t *cbr;
 726  787                          /*
 727  788                           * It's a snapshot; nothing can inherit this
 728  789                           * property, so just look for callbacks on this
 729  790                           * ds here.
 730  791                           */
 731  792                          mutex_enter(&ds->ds_dir->dd_lock);
 732  793                          for (cbr = list_head(&ds->ds_prop_cbs); cbr;
 733  794                              cbr = list_next(&ds->ds_prop_cbs, cbr)) {
 734  795                                  if (strcmp(cbr->cbr_pr->pr_propname,
 735  796                                      propname) == 0)
 736  797                                          cbr->cbr_func(cbr->cbr_arg, intval);
 737  798                          }
 738  799                          mutex_exit(&ds->ds_dir->dd_lock);
 739  800                  } else {
 740  801                          dsl_prop_changed_notify(ds->ds_dir->dd_pool,
 741  802                              ds->ds_dir->dd_object, propname, intval, TRUE);
 742  803                  }
 743  804  
 744  805                  (void) snprintf(valbuf, sizeof (valbuf),
 745  806                      "%lld", (longlong_t)intval);
 746  807                  valstr = valbuf;
 747  808          } else {
 748  809                  if (source == ZPROP_SRC_LOCAL) {
 749  810                          valstr = value;
 750  811                  } else {
 751  812                          tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
 752  813                          if (dsl_prop_get_ds(ds, propname, 1,
 753  814                              ZAP_MAXVALUELEN, tbuf, NULL) == 0)
 754  815                                  valstr = tbuf;
 755  816                  }
 756  817          }
 757  818  
 758  819          spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE ||
 759  820              source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx,
 760  821              "%s=%s", propname, (valstr == NULL ? "" : valstr));
 761  822  
 762  823          if (tbuf != NULL)
 763  824                  kmem_free(tbuf, ZAP_MAXVALUELEN);
 764  825  }
 765  826  
 766  827  int
 767  828  dsl_prop_set_int(const char *dsname, const char *propname,
 768  829      zprop_source_t source, uint64_t value)
 769  830  {
 770  831          nvlist_t *nvl = fnvlist_alloc();
 771  832          int error;
 772  833  
 773  834          fnvlist_add_uint64(nvl, propname, value);
 774  835          error = dsl_props_set(dsname, source, nvl);
 775  836          fnvlist_free(nvl);
 776  837          return (error);
 777  838  }
 778  839  
 779  840  int
 780  841  dsl_prop_set_string(const char *dsname, const char *propname,
 781  842      zprop_source_t source, const char *value)
 782  843  {
 783  844          nvlist_t *nvl = fnvlist_alloc();
 784  845          int error;
 785  846  
 786  847          fnvlist_add_string(nvl, propname, value);
 787  848          error = dsl_props_set(dsname, source, nvl);
 788  849          fnvlist_free(nvl);
 789  850          return (error);
 790  851  }
 791  852  
 792  853  int
 793  854  dsl_prop_inherit(const char *dsname, const char *propname,
 794  855      zprop_source_t source)
  
    | 
      ↓ open down ↓ | 
    63 lines elided | 
    
      ↑ open up ↑ | 
  
 795  856  {
 796  857          nvlist_t *nvl = fnvlist_alloc();
 797  858          int error;
 798  859  
 799  860          fnvlist_add_boolean(nvl, propname);
 800  861          error = dsl_props_set(dsname, source, nvl);
 801  862          fnvlist_free(nvl);
 802  863          return (error);
 803  864  }
 804  865  
      866 +/* ARGSUSED */
      867 +static int
      868 +dsl_prop_wbc_mode_check_child_cb(dsl_pool_t *dp,
      869 +    dsl_dataset_t *ds, void *arg)
      870 +{
      871 +        int err;
      872 +        zfs_prop_t *prop = arg;
      873 +        objset_t *os = NULL;
      874 +
      875 +        err = dmu_objset_from_ds(ds, &os);
      876 +        if (err != 0)
      877 +                return (err);
      878 +
      879 +        if (*prop == ZFS_PROP_DEDUP) {
      880 +                /*
      881 +                 * User tries to set ZFS_PROP_DEDUP.
      882 +                 * In this case we just check that
      883 +                 * the target DS and its children
      884 +                 * do not use writecache
      885 +                 */
      886 +                if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
      887 +                        return (SET_ERROR(EKZFS_WBCCONFLICT));
      888 +        } else {
      889 +                ASSERT3U(*prop, ==, ZFS_PROP_WBC_MODE);
      890 +
      891 +                /*
      892 +                 * User tries to set ZFS_PROP_WBC_MODE.
      893 +                 * In this case we need check that
      894 +                 * the target DS and its children
      895 +                 * do not use writecache and dedup
      896 +                 */
      897 +                if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
      898 +                        return (SET_ERROR(EKZFS_WBCCHILD));
      899 +
      900 +                if (os->os_dedup_checksum != ZIO_CHECKSUM_OFF)
      901 +                        return (SET_ERROR(EKZFS_WBCCONFLICT));
      902 +        }
      903 +
      904 +        return (0);
      905 +}
      906 +
      907 +static int
      908 +dsl_prop_wbc_mode_check(dsl_dataset_t *ds, objset_t *os)
      909 +{
      910 +        int err = 0;
      911 +        zfs_prop_t prop = ZFS_PROP_WBC_MODE;
      912 +
      913 +        if (os->os_wbc_mode != ZFS_WBC_MODE_OFF) {
      914 +                /*
      915 +                 * ZFS_PROP_WBC_MODE cannot be set for
      916 +                 * a child DS if the prop was set for
      917 +                 * the parent
      918 +                 */
      919 +                if (os->os_wbc_root_ds_obj != ds->ds_object)
      920 +                        return (SET_ERROR(EKZFS_WBCPARENT));
      921 +        } else {
      922 +                /*
      923 +                 * Is not allowed to change wbc_mode for parent
      924 +                 * if its children already have the changed prop
      925 +                 */
      926 +                err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
      927 +                    ds->ds_dir->dd_object,
      928 +                    dsl_prop_wbc_mode_check_child_cb, &prop,
      929 +                    DS_FIND_CHILDREN);
      930 +        }
      931 +
      932 +        return (err);
      933 +}
      934 +
 805  935  typedef struct dsl_props_set_arg {
 806  936          const char *dpsa_dsname;
 807  937          zprop_source_t dpsa_source;
 808  938          nvlist_t *dpsa_props;
 809  939  } dsl_props_set_arg_t;
 810  940  
 811  941  static int
 812  942  dsl_props_set_check(void *arg, dmu_tx_t *tx)
 813  943  {
 814  944          dsl_props_set_arg_t *dpsa = arg;
 815  945          dsl_pool_t *dp = dmu_tx_pool(tx);
 816  946          dsl_dataset_t *ds;
      947 +        objset_t *os = NULL;
 817  948          uint64_t version;
 818  949          nvpair_t *elem = NULL;
 819  950          int err;
 820  951  
 821  952          err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
 822  953          if (err != 0)
 823  954                  return (err);
 824  955  
      956 +        err = dmu_objset_from_ds(ds, &os);
      957 +        if (err != 0) {
      958 +                dsl_dataset_rele(ds, FTAG);
      959 +                return (err);
      960 +        }
      961 +
 825  962          version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 826  963          while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
 827      -                if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
      964 +                const char *prop_name = nvpair_name(elem);
      965 +                zfs_prop_t prop = zfs_name_to_prop(prop_name);
      966 +
      967 +                if (strlen(prop_name) >= ZAP_MAXNAMELEN) {
 828  968                          dsl_dataset_rele(ds, FTAG);
 829  969                          return (SET_ERROR(ENAMETOOLONG));
 830  970                  }
      971 +
      972 +                /*
      973 +                 * Deduplication and WBC cannot be used together
      974 +                 * This code returns error also for case when
      975 +                 * WBC is ON, DEDUP is off and a user tries
      976 +                 * to do DEDUP=off, because in this case the code
      977 +                 * will be more complex, but benefit is too small
      978 +                 */
      979 +                if (prop == ZFS_PROP_DEDUP) {
      980 +                        if (os->os_wbc_root_ds_obj != 0) {
      981 +                                dsl_dataset_rele(ds, FTAG);
      982 +                                return (SET_ERROR(EKZFS_WBCCONFLICT));
      983 +                        }
      984 +
      985 +                        /*
      986 +                         * Need to be sure that children DS
      987 +                         * do not use writecache
      988 +                         */
      989 +                        err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
      990 +                            ds->ds_dir->dd_object,
      991 +                            dsl_prop_wbc_mode_check_child_cb, &prop,
      992 +                            DS_FIND_CHILDREN);
      993 +                        if (err != 0) {
      994 +                                dsl_dataset_rele(ds, FTAG);
      995 +                                return (err);
      996 +                        }
      997 +                }
      998 +
      999 +                if (prop == ZFS_PROP_WBC_MODE) {
     1000 +                        uint64_t wbc_mode_new = 0;
     1001 +                        data_type_t elem_type = nvpair_type(elem);
     1002 +
     1003 +                        if (elem_type == DATA_TYPE_UINT64)
     1004 +                                wbc_mode_new = fnvpair_value_uint64(elem);
     1005 +
     1006 +                        if (os->os_wbc_root_ds_obj == ds->ds_object &&
     1007 +                            elem_type == DATA_TYPE_UINT64) {
     1008 +
     1009 +                                /*
     1010 +                                 * ZFS_WBC_MODE_OFF_DELAYED means that
     1011 +                                 * the coresponding wbc_instance is in
     1012 +                                 * transition state: from ON to OFF
     1013 +                                 * so ON/OFF is not permitted
     1014 +                                 */
     1015 +                                if (os->os_wbc_mode ==
     1016 +                                    ZFS_WBC_MODE_OFF_DELAYED) {
     1017 +                                        dsl_dataset_rele(ds, FTAG);
     1018 +                                        return (SET_ERROR(EINPROGRESS));
     1019 +                                }
     1020 +
     1021 +                                ASSERT3U(os->os_wbc_mode, ==, ZFS_WBC_MODE_ON);
     1022 +
     1023 +                                /* Check for double ON */
     1024 +                                if (wbc_mode_new == ZFS_WBC_MODE_ON) {
     1025 +                                        dsl_dataset_rele(ds, FTAG);
     1026 +                                        return (SET_ERROR(EALREADY));
     1027 +                                }
     1028 +                        }
     1029 +
     1030 +                        err = dsl_prop_wbc_mode_check(ds, os);
     1031 +                        if (err != 0) {
     1032 +                                dsl_dataset_rele(ds, FTAG);
     1033 +                                return (err);
     1034 +                        }
     1035 +
     1036 +                        /* Check for double OFF */
     1037 +                        if (os->os_wbc_root_ds_obj == 0 &&
     1038 +                            elem_type == DATA_TYPE_UINT64 &&
     1039 +                            wbc_mode_new == ZFS_WBC_MODE_OFF) {
     1040 +                                dsl_dataset_rele(ds, FTAG);
     1041 +                                return (SET_ERROR(EALREADY));
     1042 +                        }
     1043 +
     1044 +                        continue;
     1045 +                }
     1046 +
 831 1047                  if (nvpair_type(elem) == DATA_TYPE_STRING) {
 832 1048                          char *valstr = fnvpair_value_string(elem);
 833 1049                          if (strlen(valstr) >= (version <
 834 1050                              SPA_VERSION_STMF_PROP ?
 835 1051                              ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
 836 1052                                  dsl_dataset_rele(ds, FTAG);
 837      -                                return (E2BIG);
     1053 +                                return (SET_ERROR(E2BIG));
 838 1054                          }
 839 1055                  }
     1056 +
 840 1057          }
 841 1058  
 842 1059          if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
 843 1060                  dsl_dataset_rele(ds, FTAG);
 844 1061                  return (SET_ERROR(ENOTSUP));
 845 1062          }
 846 1063          dsl_dataset_rele(ds, FTAG);
 847 1064          return (0);
 848 1065  }
 849 1066  
 850 1067  void
 851 1068  dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
 852 1069      nvlist_t *props, dmu_tx_t *tx)
 853 1070  {
 854 1071          nvpair_t *elem = NULL;
 855 1072  
 856 1073          while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 857 1074                  nvpair_t *pair = elem;
 858      -                const char *name = nvpair_name(pair);
 859 1075  
 860 1076                  if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
 861 1077                          /*
 862      -                         * This usually happens when we reuse the nvlist_t data
 863      -                         * returned by the counterpart dsl_prop_get_all_impl().
 864      -                         * For instance we do this to restore the original
 865      -                         * received properties when an error occurs in the
 866      -                         * zfs_ioc_recv() codepath.
     1078 +                         * dsl_prop_get_all_impl() returns properties in this
     1079 +                         * format.
 867 1080                           */
 868 1081                          nvlist_t *attrs = fnvpair_value_nvlist(pair);
 869 1082                          pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
 870 1083                  }
 871 1084  
 872 1085                  if (nvpair_type(pair) == DATA_TYPE_STRING) {
 873 1086                          const char *value = fnvpair_value_string(pair);
 874      -                        dsl_prop_set_sync_impl(ds, name,
     1087 +                        dsl_prop_set_sync_impl(ds, nvpair_name(pair),
 875 1088                              source, 1, strlen(value) + 1, value, tx);
 876 1089                  } else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
     1090 +                        const char *propname = nvpair_name(pair);
     1091 +                        zfs_prop_t prop = zfs_name_to_prop(propname);
 877 1092                          uint64_t intval = fnvpair_value_uint64(pair);
 878      -                        dsl_prop_set_sync_impl(ds, name,
 879      -                            source, sizeof (intval), 1, &intval, tx);
     1093 +
     1094 +                        if (prop == ZFS_PROP_WBC_MODE) {
     1095 +                                wbc_mode_prop_val_t val;
     1096 +
     1097 +                                /*
     1098 +                                 * Disabling WBC involves the following:
     1099 +                                 * 1) all the subsequent data writes will
     1100 +                                 * stop using special vdev
     1101 +                                 * 2) already WriteBackCached data blocks
     1102 +                                 * (with TXG <= txg_off below) will gradually
     1103 +                                 * migrated from special vdev
     1104 +                                 *
     1105 +                                 * To handle this need to remember TXG.
     1106 +                                 * WBC will be completely disabled for this DS,
     1107 +                                 * after WBC-window cross this TXG
     1108 +                                 */
     1109 +                                val.txg_off = (intval == 0) ? tx->tx_txg : 0;
     1110 +                                val.root_ds_object = ds->ds_object;
     1111 +                                val.flags = 0;
     1112 +
     1113 +                                dsl_prop_set_sync_impl(ds, nvpair_name(pair),
     1114 +                                    source, 8, WBC_MODE_PROP_VAL_SZ, &val, tx);
     1115 +                        } else {
     1116 +                                dsl_prop_set_sync_impl(ds, nvpair_name(pair),
     1117 +                                    source, sizeof (intval), 1, &intval, tx);
     1118 +                        }
 880 1119                  } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
 881      -                        dsl_prop_set_sync_impl(ds, name,
     1120 +                        dsl_prop_set_sync_impl(ds, nvpair_name(pair),
 882 1121                              source, 0, 0, NULL, tx);
 883 1122                  } else {
 884 1123                          panic("invalid nvpair type");
 885 1124                  }
 886 1125          }
 887 1126  }
 888 1127  
 889 1128  static void
 890 1129  dsl_props_set_sync(void *arg, dmu_tx_t *tx)
 891 1130  {
 892 1131          dsl_props_set_arg_t *dpsa = arg;
 893 1132          dsl_pool_t *dp = dmu_tx_pool(tx);
 894 1133          dsl_dataset_t *ds;
     1134 +        objset_t *os = NULL;
 895 1135  
 896 1136          VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
     1137 +        /*
     1138 +         * Need to initialize os, to be sure that non-mounted datasets and
     1139 +         * non-exposed zvols will receive notification about modified
     1140 +         * properties.
     1141 +         * During the initialization a property can register its callback
     1142 +         * that will be called if the property is changed.
     1143 +         * dsl_props_set_sync_impl() calls dsl_prop_changed_notify()
     1144 +         * that calls the required callback if it exists.
     1145 +         */
     1146 +        VERIFY0(dmu_objset_from_ds(ds, &os));
 897 1147          dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
 898 1148          dsl_dataset_rele(ds, FTAG);
 899 1149  }
 900 1150  
 901 1151  /*
 902 1152   * All-or-nothing; if any prop can't be set, nothing will be modified.
 903 1153   */
 904 1154  int
 905 1155  dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
 906 1156  {
 907 1157          dsl_props_set_arg_t dpsa;
 908 1158          int nblks = 0;
 909 1159  
 910 1160          dpsa.dpsa_dsname = dsname;
 911 1161          dpsa.dpsa_source = source;
 912 1162          dpsa.dpsa_props = props;
 913 1163  
 914 1164          /*
  
    | 
      ↓ open down ↓ | 
    8 lines elided | 
    
      ↑ open up ↑ | 
  
 915 1165           * If the source includes NONE, then we will only be removing entries
 916 1166           * from the ZAP object.  In that case don't check for ENOSPC.
 917 1167           */
 918 1168          if ((source & ZPROP_SRC_NONE) == 0)
 919 1169                  nblks = 2 * fnvlist_num_pairs(props);
 920 1170  
 921 1171          return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
 922 1172              &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
 923 1173  }
 924 1174  
     1175 +static void
     1176 +dsl_props_mds_set_sync(void *arg, dmu_tx_t *tx)
     1177 +{
     1178 +        dsl_props_set_arg_t *top_dpsa = arg;
     1179 +        dsl_pool_t *dp = dmu_tx_pool(tx);
     1180 +        nvlist_t *dss_props = top_dpsa->dpsa_props;
     1181 +        nvpair_t *pair = NULL;
     1182 +
     1183 +        while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
     1184 +                dsl_props_set_arg_t dpsa;
     1185 +                dsl_dataset_t *ds = NULL;
     1186 +                const char *ds_name;
     1187 +
     1188 +                ds_name = nvpair_name(pair);
     1189 +                VERIFY0(dsl_dataset_hold(dp, ds_name, FTAG, &ds));
     1190 +
     1191 +                dpsa.dpsa_dsname = ds_name;
     1192 +                dpsa.dpsa_source = ZPROP_SRC_LOCAL;
     1193 +                dpsa.dpsa_props = fnvpair_value_nvlist(pair);
     1194 +
     1195 +                dsl_props_set_sync(&dpsa, tx);
     1196 +                dsl_dataset_rele(ds, FTAG);
     1197 +        }
     1198 +}
     1199 +
     1200 +static int
     1201 +dsl_props_mds_set_check(void *arg, dmu_tx_t *tx)
     1202 +{
     1203 +        dsl_props_set_arg_t *top_dpsa = arg;
     1204 +        dsl_pool_t *dp = dmu_tx_pool(tx);
     1205 +        nvlist_t *dss_props = top_dpsa->dpsa_props;
     1206 +        nvpair_t *pair = NULL;
     1207 +
     1208 +        while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
     1209 +                dsl_props_set_arg_t dpsa;
     1210 +                dsl_dataset_t *ds = NULL;
     1211 +                const char *ds_name;
     1212 +                int err;
     1213 +
     1214 +                ds_name = nvpair_name(pair);
     1215 +                err = dsl_dataset_hold(dp, ds_name, FTAG, &ds);
     1216 +                if (err != 0)
     1217 +                        return (err);
     1218 +
     1219 +                if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
     1220 +                        dsl_dataset_rele(ds, FTAG);
     1221 +                        return (SET_ERROR(EINVAL));
     1222 +                }
     1223 +
     1224 +                dpsa.dpsa_dsname = ds_name;
     1225 +                dpsa.dpsa_source = ZPROP_SRC_LOCAL;
     1226 +                dpsa.dpsa_props = fnvpair_value_nvlist(pair);
     1227 +
     1228 +                err = dsl_props_set_check(&dpsa, tx);
     1229 +                dsl_dataset_rele(ds, FTAG);
     1230 +                if (err != 0)
     1231 +                        return (err);
     1232 +        }
     1233 +
     1234 +        return (0);
     1235 +}
     1236 +
     1237 +
     1238 +/*
     1239 + * The given 'dss_props' nvlist represents the following struct:
     1240 + *  ds1 -> prop1:value
     1241 + *      -> prop3:value
     1242 + *  ds2 -> prop1:value
     1243 + *      -> prop2:value
     1244 + *
     1245 + * All-or-nothing: if any prop can't be set, nothing will be modified.
     1246 + */
     1247 +int
     1248 +dsl_props_set_mds(const char *pool_name, nvlist_t *dss_props,
     1249 +    size_t num_props)
     1250 +{
     1251 +        dsl_props_set_arg_t dpsa;
     1252 +
     1253 +        dpsa.dpsa_dsname = pool_name;
     1254 +        dpsa.dpsa_source = ZPROP_SRC_LOCAL;
     1255 +        dpsa.dpsa_props = dss_props;
     1256 +
     1257 +        return (dsl_sync_task(pool_name, dsl_props_mds_set_check,
     1258 +            dsl_props_mds_set_sync, &dpsa, 2 * num_props,
     1259 +            ZFS_SPACE_CHECK_RESERVED));
     1260 +}
     1261 +
 925 1262  typedef enum dsl_prop_getflags {
 926 1263          DSL_PROP_GET_INHERITING = 0x1,  /* searching parent of target ds */
 927 1264          DSL_PROP_GET_SNAPSHOT = 0x2,    /* snapshot dataset */
 928 1265          DSL_PROP_GET_LOCAL = 0x4,       /* local properties */
 929 1266          DSL_PROP_GET_RECEIVED = 0x8     /* received properties */
 930 1267  } dsl_prop_getflags_t;
 931 1268  
 932 1269  static int
 933 1270  dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
 934 1271      const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
 935 1272  {
 936 1273          zap_cursor_t zc;
 937 1274          zap_attribute_t za;
 938 1275          int err = 0;
 939 1276  
 940 1277          for (zap_cursor_init(&zc, mos, propobj);
 941 1278              (err = zap_cursor_retrieve(&zc, &za)) == 0;
 942 1279              zap_cursor_advance(&zc)) {
 943 1280                  nvlist_t *propval;
 944 1281                  zfs_prop_t prop;
 945 1282                  char buf[ZAP_MAXNAMELEN];
 946 1283                  char *valstr;
 947 1284                  const char *suffix;
 948 1285                  const char *propname;
 949 1286                  const char *source;
 950 1287  
 951 1288                  suffix = strchr(za.za_name, '$');
 952 1289  
 953 1290                  if (suffix == NULL) {
 954 1291                          /*
 955 1292                           * Skip local properties if we only want received
 956 1293                           * properties.
 957 1294                           */
 958 1295                          if (flags & DSL_PROP_GET_RECEIVED)
 959 1296                                  continue;
 960 1297  
 961 1298                          propname = za.za_name;
 962 1299                          source = setpoint;
 963 1300                  } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
 964 1301                          /* Skip explicitly inherited entries. */
 965 1302                          continue;
 966 1303                  } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
 967 1304                          if (flags & DSL_PROP_GET_LOCAL)
 968 1305                                  continue;
 969 1306  
 970 1307                          (void) strncpy(buf, za.za_name, (suffix - za.za_name));
 971 1308                          buf[suffix - za.za_name] = '\0';
 972 1309                          propname = buf;
 973 1310  
 974 1311                          if (!(flags & DSL_PROP_GET_RECEIVED)) {
 975 1312                                  /* Skip if locally overridden. */
 976 1313                                  err = zap_contains(mos, propobj, propname);
 977 1314                                  if (err == 0)
 978 1315                                          continue;
 979 1316                                  if (err != ENOENT)
 980 1317                                          break;
 981 1318  
 982 1319                                  /* Skip if explicitly inherited. */
 983 1320                                  valstr = kmem_asprintf("%s%s", propname,
 984 1321                                      ZPROP_INHERIT_SUFFIX);
 985 1322                                  err = zap_contains(mos, propobj, valstr);
 986 1323                                  strfree(valstr);
 987 1324                                  if (err == 0)
 988 1325                                          continue;
 989 1326                                  if (err != ENOENT)
 990 1327                                          break;
 991 1328                          }
 992 1329  
 993 1330                          source = ((flags & DSL_PROP_GET_INHERITING) ?
 994 1331                              setpoint : ZPROP_SOURCE_VAL_RECVD);
 995 1332                  } else {
 996 1333                          /*
 997 1334                           * For backward compatibility, skip suffixes we don't
 998 1335                           * recognize.
 999 1336                           */
1000 1337                          continue;
1001 1338                  }
1002 1339  
1003 1340                  prop = zfs_name_to_prop(propname);
1004 1341  
1005 1342                  /* Skip non-inheritable properties. */
1006 1343                  if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
1007 1344                      !zfs_prop_inheritable(prop))
1008 1345                          continue;
1009 1346  
1010 1347                  /* Skip properties not valid for this type. */
1011 1348                  if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
1012 1349                      !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
1013 1350                          continue;
1014 1351  
1015 1352                  /* Skip properties already defined. */
1016 1353                  if (nvlist_exists(nv, propname))
1017 1354                          continue;
1018 1355  
1019 1356                  VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1020 1357                  if (za.za_integer_length == 1) {
1021 1358                          /*
  
    | 
      ↓ open down ↓ | 
    87 lines elided | 
    
      ↑ open up ↑ | 
  
1022 1359                           * String property
1023 1360                           */
1024 1361                          char *tmp = kmem_alloc(za.za_num_integers,
1025 1362                              KM_SLEEP);
1026 1363                          err = zap_lookup(mos, propobj,
1027 1364                              za.za_name, 1, za.za_num_integers, tmp);
1028 1365                          if (err != 0) {
1029 1366                                  kmem_free(tmp, za.za_num_integers);
1030 1367                                  break;
1031 1368                          }
     1369 +
1032 1370                          VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
1033 1371                              tmp) == 0);
1034 1372                          kmem_free(tmp, za.za_num_integers);
1035 1373                  } else {
1036 1374                          /*
1037 1375                           * Integer property
1038 1376                           */
1039 1377                          ASSERT(za.za_integer_length == 8);
     1378 +
     1379 +                        if (prop == ZFS_PROP_WBC_MODE) {
     1380 +                                wbc_mode_prop_val_t val;
     1381 +
     1382 +                                ASSERT(za.za_num_integers ==
     1383 +                                    WBC_MODE_PROP_VAL_SZ);
     1384 +
     1385 +                                err = zap_lookup(mos, propobj,
     1386 +                                    za.za_name, 8, za.za_num_integers, &val);
     1387 +                                if (err != 0)
     1388 +                                        break;
     1389 +
     1390 +                                if (val.root_ds_object != 0 &&
     1391 +                                    val.txg_off == 0)
     1392 +                                        za.za_first_integer = ZFS_WBC_MODE_ON;
     1393 +                                else
     1394 +                                        za.za_first_integer = ZFS_WBC_MODE_OFF;
     1395 +                        }
     1396 +
1040 1397                          (void) nvlist_add_uint64(propval, ZPROP_VALUE,
1041 1398                              za.za_first_integer);
1042 1399                  }
1043 1400  
1044 1401                  VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
1045 1402                  VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1046 1403                  nvlist_free(propval);
1047 1404          }
1048 1405          zap_cursor_fini(&zc);
1049 1406          if (err == ENOENT)
1050 1407                  err = 0;
1051 1408          return (err);
1052 1409  }
1053 1410  
1054 1411  /*
1055 1412   * Iterate over all properties for this dataset and return them in an nvlist.
1056 1413   */
1057 1414  static int
1058 1415  dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1059 1416      dsl_prop_getflags_t flags)
1060 1417  {
1061 1418          dsl_dir_t *dd = ds->ds_dir;
1062 1419          dsl_pool_t *dp = dd->dd_pool;
1063 1420          objset_t *mos = dp->dp_meta_objset;
1064 1421          int err = 0;
1065 1422          char setpoint[ZFS_MAX_DATASET_NAME_LEN];
1066 1423  
1067 1424          VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1068 1425  
1069 1426          if (ds->ds_is_snapshot)
1070 1427                  flags |= DSL_PROP_GET_SNAPSHOT;
1071 1428  
1072 1429          ASSERT(dsl_pool_config_held(dp));
1073 1430  
1074 1431          if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
1075 1432                  ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
1076 1433                  dsl_dataset_name(ds, setpoint);
1077 1434                  err = dsl_prop_get_all_impl(mos,
1078 1435                      dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
1079 1436                  if (err)
1080 1437                          goto out;
1081 1438          }
1082 1439  
1083 1440          for (; dd != NULL; dd = dd->dd_parent) {
1084 1441                  if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1085 1442                          if (flags & (DSL_PROP_GET_LOCAL |
1086 1443                              DSL_PROP_GET_RECEIVED))
1087 1444                                  break;
1088 1445                          flags |= DSL_PROP_GET_INHERITING;
1089 1446                  }
1090 1447                  dsl_dir_name(dd, setpoint);
1091 1448                  err = dsl_prop_get_all_impl(mos,
1092 1449                      dsl_dir_phys(dd)->dd_props_zapobj, setpoint, flags, *nvp);
1093 1450                  if (err)
1094 1451                          break;
1095 1452          }
1096 1453  out:
1097 1454          return (err);
1098 1455  }
1099 1456  
1100 1457  boolean_t
1101 1458  dsl_prop_get_hasrecvd(const char *dsname)
1102 1459  {
1103 1460          uint64_t dummy;
1104 1461  
1105 1462          return (0 ==
1106 1463              dsl_prop_get_integer(dsname, ZPROP_HAS_RECVD, &dummy, NULL));
1107 1464  }
1108 1465  
1109 1466  static int
1110 1467  dsl_prop_set_hasrecvd_impl(const char *dsname, zprop_source_t source)
1111 1468  {
1112 1469          uint64_t version;
1113 1470          spa_t *spa;
1114 1471          int error = 0;
1115 1472  
1116 1473          VERIFY0(spa_open(dsname, &spa, FTAG));
1117 1474          version = spa_version(spa);
1118 1475          spa_close(spa, FTAG);
1119 1476  
1120 1477          if (version >= SPA_VERSION_RECVD_PROPS)
1121 1478                  error = dsl_prop_set_int(dsname, ZPROP_HAS_RECVD, source, 0);
1122 1479          return (error);
1123 1480  }
1124 1481  
1125 1482  /*
1126 1483   * Call after successfully receiving properties to ensure that only the first
1127 1484   * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1128 1485   */
1129 1486  int
1130 1487  dsl_prop_set_hasrecvd(const char *dsname)
1131 1488  {
1132 1489          int error = 0;
1133 1490          if (!dsl_prop_get_hasrecvd(dsname))
1134 1491                  error = dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_LOCAL);
1135 1492          return (error);
1136 1493  }
1137 1494  
1138 1495  void
1139 1496  dsl_prop_unset_hasrecvd(const char *dsname)
1140 1497  {
1141 1498          VERIFY0(dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_NONE));
1142 1499  }
1143 1500  
1144 1501  int
1145 1502  dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
1146 1503  {
1147 1504          return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
1148 1505  }
1149 1506  
1150 1507  int
1151 1508  dsl_prop_get_received(const char *dsname, nvlist_t **nvp)
1152 1509  {
1153 1510          objset_t *os;
1154 1511          int error;
1155 1512  
1156 1513          /*
1157 1514           * Received properties are not distinguishable from local properties
1158 1515           * until the dataset has received properties on or after
1159 1516           * SPA_VERSION_RECVD_PROPS.
1160 1517           */
1161 1518          dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(dsname) ?
1162 1519              DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
1163 1520  
1164 1521          error = dmu_objset_hold(dsname, FTAG, &os);
1165 1522          if (error != 0)
1166 1523                  return (error);
1167 1524          error = dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags);
1168 1525          dmu_objset_rele(os, FTAG);
1169 1526          return (error);
1170 1527  }
1171 1528  
1172 1529  void
1173 1530  dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
1174 1531  {
1175 1532          nvlist_t *propval;
1176 1533          const char *propname = zfs_prop_to_name(prop);
1177 1534          uint64_t default_value;
1178 1535  
1179 1536          if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1180 1537                  VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1181 1538                  return;
1182 1539          }
1183 1540  
1184 1541          VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1185 1542          VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1186 1543          /* Indicate the default source if we can. */
1187 1544          if (dodefault(prop, 8, 1, &default_value) == 0 &&
1188 1545              value == default_value) {
1189 1546                  VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
1190 1547          }
1191 1548          VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1192 1549          nvlist_free(propval);
1193 1550  }
1194 1551  
1195 1552  void
1196 1553  dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
1197 1554  {
1198 1555          nvlist_t *propval;
1199 1556          const char *propname = zfs_prop_to_name(prop);
1200 1557  
1201 1558          if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1202 1559                  VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1203 1560                  return;
1204 1561          }
1205 1562  
1206 1563          VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1207 1564          VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1208 1565          VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1209 1566          nvlist_free(propval);
1210 1567  }
  
    | 
      ↓ open down ↓ | 
    161 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX