1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  24  * Copyright (c) 2013 Martin Matuska. All rights reserved.
  25  * Copyright 2015, Joyent, Inc.
  26  */
  27 
  28 #include <sys/zfs_context.h>
  29 #include <sys/dmu.h>
  30 #include <sys/dmu_objset.h>
  31 #include <sys/dmu_tx.h>
  32 #include <sys/dsl_dataset.h>
  33 #include <sys/dsl_dir.h>
  34 #include <sys/dsl_prop.h>
  35 #include <sys/dsl_synctask.h>
  36 #include <sys/spa.h>
  37 #include <sys/zap.h>
  38 #include <sys/fs/zfs.h>
  39 
  40 #include "zfs_prop.h"
  41 
  42 #define ZPROP_INHERIT_SUFFIX "$inherit"
  43 #define ZPROP_RECVD_SUFFIX "$recvd"
  44 
  45 static int
  46 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
  47 {
  48         /*
  49          * The setonce properties are read-only, BUT they still
  50          * have a default value that can be used as the initial
  51          * value.
  52          */
  53         if (prop == ZPROP_INVAL ||
  54             (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
  55                 return (SET_ERROR(ENOENT));
  56 
  57         if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
  58                 if (intsz != 1)
  59                         return (SET_ERROR(EOVERFLOW));
  60                 (void) strncpy(buf, zfs_prop_default_string(prop),
  61                     numints);
  62         } else {
  63                 if (intsz != 8 || numints < 1)
  64                         return (SET_ERROR(EOVERFLOW));
  65 
  66                 *(uint64_t *)buf = zfs_prop_default_numeric(prop);
  67         }
  68 
  69         return (0);
  70 }
  71 
  72 int
  73 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
  74     int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
  75 {
  76         int err = ENOENT;
  77         dsl_dir_t *target = dd;
  78         objset_t *mos = dd->dd_pool->dp_meta_objset;
  79         zfs_prop_t prop;
  80         boolean_t inheritable;
  81         boolean_t inheriting = B_FALSE;
  82         char *inheritstr;
  83         char *recvdstr;
  84 
  85         ASSERT(dsl_pool_config_held(dd->dd_pool));
  86 
  87         if (setpoint)
  88                 setpoint[0] = '\0';
  89 
  90         prop = zfs_name_to_prop(propname);
  91         inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
  92         inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
  93         recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
  94 
  95         /*
  96          * Note: dd may become NULL, therefore we shouldn't dereference it
  97          * after this loop.
  98          */
  99         for (; dd != NULL; dd = dd->dd_parent) {
 100                 if (dd != target || snapshot) {
 101                         if (!inheritable)
 102                                 break;
 103                         inheriting = B_TRUE;
 104                 }
 105 
 106                 /* Check for a local value. */
 107                 err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 108                     propname, intsz, numints, buf);
 109                 if (err != ENOENT) {
 110                         if (setpoint != NULL && err == 0)
 111                                 dsl_dir_name(dd, setpoint);
 112                         break;
 113                 }
 114 
 115                 /*
 116                  * Skip the check for a received value if there is an explicit
 117                  * inheritance entry.
 118                  */
 119                 err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 120                     inheritstr);
 121                 if (err != 0 && err != ENOENT)
 122                         break;
 123 
 124                 if (err == ENOENT) {
 125                         /* Check for a received value. */
 126                         err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 127                             recvdstr, intsz, numints, buf);
 128                         if (err != ENOENT) {
 129                                 if (setpoint != NULL && err == 0) {
 130                                         if (inheriting) {
 131                                                 dsl_dir_name(dd, setpoint);
 132                                         } else {
 133                                                 (void) strcpy(setpoint,
 134                                                     ZPROP_SOURCE_VAL_RECVD);
 135                                         }
 136                                 }
 137                                 break;
 138                         }
 139                 }
 140 
 141                 /*
 142                  * If we found an explicit inheritance entry, err is zero even
 143                  * though we haven't yet found the value, so reinitializing err
 144                  * at the end of the loop (instead of at the beginning) ensures
 145                  * that err has a valid post-loop value.
 146                  */
 147                 err = SET_ERROR(ENOENT);
 148         }
 149 
 150         if (err == ENOENT)
 151                 err = dodefault(prop, intsz, numints, buf);
 152 
 153         strfree(inheritstr);
 154         strfree(recvdstr);
 155 
 156         return (err);
 157 }
 158 
 159 int
 160 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
 161     int intsz, int numints, void *buf, char *setpoint)
 162 {
 163         zfs_prop_t prop = zfs_name_to_prop(propname);
 164         boolean_t inheritable;
 165         uint64_t zapobj;
 166 
 167         ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 168         inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
 169         zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 170 
 171         if (zapobj != 0) {
 172                 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 173                 int err;
 174 
 175                 ASSERT(ds->ds_is_snapshot);
 176 
 177                 /* Check for a local value. */
 178                 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
 179                 if (err != ENOENT) {
 180                         if (setpoint != NULL && err == 0)
 181                                 dsl_dataset_name(ds, setpoint);
 182                         return (err);
 183                 }
 184 
 185                 /*
 186                  * Skip the check for a received value if there is an explicit
 187                  * inheritance entry.
 188                  */
 189                 if (inheritable) {
 190                         char *inheritstr = kmem_asprintf("%s%s", propname,
 191                             ZPROP_INHERIT_SUFFIX);
 192                         err = zap_contains(mos, zapobj, inheritstr);
 193                         strfree(inheritstr);
 194                         if (err != 0 && err != ENOENT)
 195                                 return (err);
 196                 }
 197 
 198                 if (err == ENOENT) {
 199                         /* Check for a received value. */
 200                         char *recvdstr = kmem_asprintf("%s%s", propname,
 201                             ZPROP_RECVD_SUFFIX);
 202                         err = zap_lookup(mos, zapobj, recvdstr,
 203                             intsz, numints, buf);
 204                         strfree(recvdstr);
 205                         if (err != ENOENT) {
 206                                 if (setpoint != NULL && err == 0)
 207                                         (void) strcpy(setpoint,
 208                                             ZPROP_SOURCE_VAL_RECVD);
 209                                 return (err);
 210                         }
 211                 }
 212         }
 213 
 214         return (dsl_prop_get_dd(ds->ds_dir, propname,
 215             intsz, numints, buf, setpoint, ds->ds_is_snapshot));
 216 }
 217 
 218 static dsl_prop_record_t *
 219 dsl_prop_record_find(dsl_dir_t *dd, const char *propname)
 220 {
 221         dsl_prop_record_t *pr = NULL;
 222 
 223         ASSERT(MUTEX_HELD(&dd->dd_lock));
 224 
 225         for (pr = list_head(&dd->dd_props);
 226             pr != NULL; pr = list_next(&dd->dd_props, pr)) {
 227                 if (strcmp(pr->pr_propname, propname) == 0)
 228                         break;
 229         }
 230 
 231         return (pr);
 232 }
 233 
 234 static dsl_prop_record_t *
 235 dsl_prop_record_create(dsl_dir_t *dd, const char *propname)
 236 {
 237         dsl_prop_record_t *pr;
 238 
 239         ASSERT(MUTEX_HELD(&dd->dd_lock));
 240 
 241         pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP);
 242         pr->pr_propname = spa_strdup(propname);
 243         list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t),
 244             offsetof(dsl_prop_cb_record_t, cbr_pr_node));
 245         list_insert_head(&dd->dd_props, pr);
 246 
 247         return (pr);
 248 }
 249 
 250 void
 251 dsl_prop_init(dsl_dir_t *dd)
 252 {
 253         list_create(&dd->dd_props, sizeof (dsl_prop_record_t),
 254             offsetof(dsl_prop_record_t, pr_node));
 255 }
 256 
 257 void
 258 dsl_prop_fini(dsl_dir_t *dd)
 259 {
 260         dsl_prop_record_t *pr;
 261 
 262         while ((pr = list_remove_head(&dd->dd_props)) != NULL) {
 263                 list_destroy(&pr->pr_cbs);
 264                 strfree((char *)pr->pr_propname);
 265                 kmem_free(pr, sizeof (dsl_prop_record_t));
 266         }
 267         list_destroy(&dd->dd_props);
 268 }
 269 
 270 /*
 271  * Register interest in the named property.  We'll call the callback
 272  * once to notify it of the current property value, and again each time
 273  * the property changes, until this callback is unregistered.
 274  *
 275  * Return 0 on success, errno if the prop is not an integer value.
 276  */
 277 int
 278 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
 279     dsl_prop_changed_cb_t *callback, void *cbarg)
 280 {
 281         dsl_dir_t *dd = ds->ds_dir;
 282         dsl_pool_t *dp = dd->dd_pool;
 283         uint64_t value;
 284         dsl_prop_record_t *pr;
 285         dsl_prop_cb_record_t *cbr;
 286         int err;
 287 
 288         ASSERT(dsl_pool_config_held(dp));
 289 
 290         err = dsl_prop_get_int_ds(ds, propname, &value);
 291         if (err != 0)
 292                 return (err);
 293 
 294         cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
 295         cbr->cbr_ds = ds;
 296         cbr->cbr_func = callback;
 297         cbr->cbr_arg = cbarg;
 298 
 299         mutex_enter(&dd->dd_lock);
 300         pr = dsl_prop_record_find(dd, propname);
 301         if (pr == NULL)
 302                 pr = dsl_prop_record_create(dd, propname);
 303         cbr->cbr_pr = pr;
 304         list_insert_head(&pr->pr_cbs, cbr);
 305         list_insert_head(&ds->ds_prop_cbs, cbr);
 306         mutex_exit(&dd->dd_lock);
 307 
 308         cbr->cbr_func(cbr->cbr_arg, value);
 309         return (0);
 310 }
 311 
 312 int
 313 dsl_prop_get(const char *dsname, const char *propname,
 314     int intsz, int numints, void *buf, char *setpoint)
 315 {
 316         objset_t *os;
 317         int error;
 318 
 319         error = dmu_objset_hold(dsname, FTAG, &os);
 320         if (error != 0)
 321                 return (error);
 322 
 323         error = dsl_prop_get_ds(dmu_objset_ds(os), propname,
 324             intsz, numints, buf, setpoint);
 325 
 326         dmu_objset_rele(os, FTAG);
 327         return (error);
 328 }
 329 
 330 /*
 331  * Get the current property value.  It may have changed by the time this
 332  * function returns, so it is NOT safe to follow up with
 333  * dsl_prop_register() and assume that the value has not changed in
 334  * between.
 335  *
 336  * Return 0 on success, ENOENT if ddname is invalid.
 337  */
 338 int
 339 dsl_prop_get_integer(const char *ddname, const char *propname,
 340     uint64_t *valuep, char *setpoint)
 341 {
 342         return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
 343 }
 344 
 345 int
 346 dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname,
 347     uint64_t *valuep)
 348 {
 349         return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL));
 350 }
 351 
 352 /*
 353  * Predict the effective value of the given special property if it were set with
 354  * the given value and source. This is not a general purpose function. It exists
 355  * only to handle the special requirements of the quota and reservation
 356  * properties. The fact that these properties are non-inheritable greatly
 357  * simplifies the prediction logic.
 358  *
 359  * Returns 0 on success, a positive error code on failure, or -1 if called with
 360  * a property not handled by this function.
 361  */
 362 int
 363 dsl_prop_predict(dsl_dir_t *dd, const char *propname,
 364     zprop_source_t source, uint64_t value, uint64_t *newvalp)
 365 {
 366         zfs_prop_t prop = zfs_name_to_prop(propname);
 367         objset_t *mos;
 368         uint64_t zapobj;
 369         uint64_t version;
 370         char *recvdstr;
 371         int err = 0;
 372 
 373         switch (prop) {
 374         case ZFS_PROP_QUOTA:
 375         case ZFS_PROP_RESERVATION:
 376         case ZFS_PROP_REFQUOTA:
 377         case ZFS_PROP_REFRESERVATION:
 378                 break;
 379         default:
 380                 return (-1);
 381         }
 382 
 383         mos = dd->dd_pool->dp_meta_objset;
 384         zapobj = dsl_dir_phys(dd)->dd_props_zapobj;
 385         recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
 386 
 387         version = spa_version(dd->dd_pool->dp_spa);
 388         if (version < SPA_VERSION_RECVD_PROPS) {
 389                 if (source & ZPROP_SRC_NONE)
 390                         source = ZPROP_SRC_NONE;
 391                 else if (source & ZPROP_SRC_RECEIVED)
 392                         source = ZPROP_SRC_LOCAL;
 393         }
 394 
 395         switch (source) {
 396         case ZPROP_SRC_NONE:
 397                 /* Revert to the received value, if any. */
 398                 err = zap_lookup(mos, zapobj, recvdstr, 8, 1, newvalp);
 399                 if (err == ENOENT)
 400                         *newvalp = 0;
 401                 break;
 402         case ZPROP_SRC_LOCAL:
 403                 *newvalp = value;
 404                 break;
 405         case ZPROP_SRC_RECEIVED:
 406                 /*
 407                  * If there's no local setting, then the new received value will
 408                  * be the effective value.
 409                  */
 410                 err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
 411                 if (err == ENOENT)
 412                         *newvalp = value;
 413                 break;
 414         case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
 415                 /*
 416                  * We're clearing the received value, so the local setting (if
 417                  * it exists) remains the effective value.
 418                  */
 419                 err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
 420                 if (err == ENOENT)
 421                         *newvalp = 0;
 422                 break;
 423         default:
 424                 panic("unexpected property source: %d", source);
 425         }
 426 
 427         strfree(recvdstr);
 428 
 429         if (err == ENOENT)
 430                 return (0);
 431 
 432         return (err);
 433 }
 434 
 435 /*
 436  * Unregister all callbacks that are registered with the
 437  * given callback argument.
 438  */
 439 void
 440 dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg)
 441 {
 442         dsl_prop_cb_record_t *cbr, *next_cbr;
 443 
 444         dsl_dir_t *dd = ds->ds_dir;
 445 
 446         mutex_enter(&dd->dd_lock);
 447         next_cbr = list_head(&ds->ds_prop_cbs);
 448         while (next_cbr != NULL) {
 449                 cbr = next_cbr;
 450                 next_cbr = list_next(&ds->ds_prop_cbs, cbr);
 451                 if (cbr->cbr_arg == cbarg) {
 452                         list_remove(&ds->ds_prop_cbs, cbr);
 453                         list_remove(&cbr->cbr_pr->pr_cbs, cbr);
 454                         kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
 455                 }
 456         }
 457         mutex_exit(&dd->dd_lock);
 458 }
 459 
 460 boolean_t
 461 dsl_prop_hascb(dsl_dataset_t *ds)
 462 {
 463         return (!list_is_empty(&ds->ds_prop_cbs));
 464 }
 465 
 466 /* ARGSUSED */
 467 static int
 468 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
 469 {
 470         dsl_dir_t *dd = ds->ds_dir;
 471         dsl_prop_record_t *pr;
 472         dsl_prop_cb_record_t *cbr;
 473 
 474         mutex_enter(&dd->dd_lock);
 475         for (pr = list_head(&dd->dd_props);
 476             pr; pr = list_next(&dd->dd_props, pr)) {
 477                 for (cbr = list_head(&pr->pr_cbs); cbr;
 478                     cbr = list_next(&pr->pr_cbs, cbr)) {
 479                         uint64_t value;
 480 
 481                         /*
 482                          * Callback entries do not have holds on their
 483                          * datasets so that datasets with registered
 484                          * callbacks are still eligible for eviction.
 485                          * Unlike operations to update properties on a
 486                          * single dataset, we are performing a recursive
 487                          * descent of related head datasets.  The caller
 488                          * of this function only has a dataset hold on
 489                          * the passed in head dataset, not the snapshots
 490                          * associated with this dataset.  Without a hold,
 491                          * the dataset pointer within callback records
 492                          * for snapshots can be invalidated by eviction
 493                          * at any time.
 494                          *
 495                          * Use dsl_dataset_try_add_ref() to verify
 496                          * that the dataset for a snapshot has not
 497                          * begun eviction processing and to prevent
 498                          * eviction from occurring for the duration of
 499                          * the callback.  If the hold attempt fails,
 500                          * this object is already being evicted and the
 501                          * callback can be safely ignored.
 502                          */
 503                         if (ds != cbr->cbr_ds &&
 504                             !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
 505                                 continue;
 506 
 507                         if (dsl_prop_get_ds(cbr->cbr_ds,
 508                             cbr->cbr_pr->pr_propname, sizeof (value), 1,
 509                             &value, NULL) == 0)
 510                                 cbr->cbr_func(cbr->cbr_arg, value);
 511 
 512                         if (ds != cbr->cbr_ds)
 513                                 dsl_dataset_rele(cbr->cbr_ds, FTAG);
 514                 }
 515         }
 516         mutex_exit(&dd->dd_lock);
 517 
 518         return (0);
 519 }
 520 
 521 /*
 522  * Update all property values for ddobj & its descendants.  This is used
 523  * when renaming the dir.
 524  */
 525 void
 526 dsl_prop_notify_all(dsl_dir_t *dd)
 527 {
 528         dsl_pool_t *dp = dd->dd_pool;
 529         ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
 530         (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
 531             NULL, DS_FIND_CHILDREN);
 532 }
 533 
 534 static void
 535 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
 536     const char *propname, uint64_t value, int first)
 537 {
 538         dsl_dir_t *dd;
 539         dsl_prop_record_t *pr;
 540         dsl_prop_cb_record_t *cbr;
 541         objset_t *mos = dp->dp_meta_objset;
 542         zap_cursor_t zc;
 543         zap_attribute_t *za;
 544         int err;
 545 
 546         ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
 547         err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd);
 548         if (err)
 549                 return;
 550 
 551         if (!first) {
 552                 /*
 553                  * If the prop is set here, then this change is not
 554                  * being inherited here or below; stop the recursion.
 555                  */
 556                 err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
 557                     propname);
 558                 if (err == 0) {
 559                         dsl_dir_rele(dd, FTAG);
 560                         return;
 561                 }
 562                 ASSERT3U(err, ==, ENOENT);
 563         }
 564 
 565         mutex_enter(&dd->dd_lock);
 566         pr = dsl_prop_record_find(dd, propname);
 567         if (pr != NULL) {
 568                 for (cbr = list_head(&pr->pr_cbs); cbr;
 569                     cbr = list_next(&pr->pr_cbs, cbr)) {
 570                         uint64_t propobj;
 571 
 572                         /*
 573                          * cbr->cbr_ds may be invalidated due to eviction,
 574                          * requiring the use of dsl_dataset_try_add_ref().
 575                          * See comment block in dsl_prop_notify_all_cb()
 576                          * for details.
 577                          */
 578                         if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
 579                                 continue;
 580 
 581                         propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
 582 
 583                         /*
 584                          * If the property is not set on this ds, then it is
 585                          * inherited here; call the callback.
 586                          */
 587                         if (propobj == 0 ||
 588                             zap_contains(mos, propobj, propname) != 0)
 589                                 cbr->cbr_func(cbr->cbr_arg, value);
 590 
 591                         dsl_dataset_rele(cbr->cbr_ds, FTAG);
 592                 }
 593         }
 594         mutex_exit(&dd->dd_lock);
 595 
 596         za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
 597         for (zap_cursor_init(&zc, mos,
 598             dsl_dir_phys(dd)->dd_child_dir_zapobj);
 599             zap_cursor_retrieve(&zc, za) == 0;
 600             zap_cursor_advance(&zc)) {
 601                 dsl_prop_changed_notify(dp, za->za_first_integer,
 602                     propname, value, FALSE);
 603         }
 604         kmem_free(za, sizeof (zap_attribute_t));
 605         zap_cursor_fini(&zc);
 606         dsl_dir_rele(dd, FTAG);
 607 }
 608 
 609 void
 610 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
 611     zprop_source_t source, int intsz, int numints, const void *value,
 612     dmu_tx_t *tx)
 613 {
 614         objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 615         uint64_t zapobj, intval, dummy;
 616         int isint;
 617         char valbuf[32];
 618         const char *valstr = NULL;
 619         char *inheritstr;
 620         char *recvdstr;
 621         char *tbuf = NULL;
 622         int err;
 623         uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 624 
 625         isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
 626 
 627         if (ds->ds_is_snapshot) {
 628                 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
 629                 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
 630                         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 631                         dsl_dataset_phys(ds)->ds_props_obj =
 632                             zap_create(mos,
 633                             DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
 634                 }
 635                 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 636         } else {
 637                 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
 638         }
 639 
 640         if (version < SPA_VERSION_RECVD_PROPS) {
 641                 if (source & ZPROP_SRC_NONE)
 642                         source = ZPROP_SRC_NONE;
 643                 else if (source & ZPROP_SRC_RECEIVED)
 644                         source = ZPROP_SRC_LOCAL;
 645         }
 646 
 647         inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
 648         recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
 649 
 650         switch (source) {
 651         case ZPROP_SRC_NONE:
 652                 /*
 653                  * revert to received value, if any (inherit -S)
 654                  * - remove propname
 655                  * - remove propname$inherit
 656                  */
 657                 err = zap_remove(mos, zapobj, propname, tx);
 658                 ASSERT(err == 0 || err == ENOENT);
 659                 err = zap_remove(mos, zapobj, inheritstr, tx);
 660                 ASSERT(err == 0 || err == ENOENT);
 661                 break;
 662         case ZPROP_SRC_LOCAL:
 663                 /*
 664                  * remove propname$inherit
 665                  * set propname -> value
 666                  */
 667                 err = zap_remove(mos, zapobj, inheritstr, tx);
 668                 ASSERT(err == 0 || err == ENOENT);
 669                 VERIFY0(zap_update(mos, zapobj, propname,
 670                     intsz, numints, value, tx));
 671                 break;
 672         case ZPROP_SRC_INHERITED:
 673                 /*
 674                  * explicitly inherit
 675                  * - remove propname
 676                  * - set propname$inherit
 677                  */
 678                 err = zap_remove(mos, zapobj, propname, tx);
 679                 ASSERT(err == 0 || err == ENOENT);
 680                 if (version >= SPA_VERSION_RECVD_PROPS &&
 681                     dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) {
 682                         dummy = 0;
 683                         VERIFY0(zap_update(mos, zapobj, inheritstr,
 684                             8, 1, &dummy, tx));
 685                 }
 686                 break;
 687         case ZPROP_SRC_RECEIVED:
 688                 /*
 689                  * set propname$recvd -> value
 690                  */
 691                 err = zap_update(mos, zapobj, recvdstr,
 692                     intsz, numints, value, tx);
 693                 ASSERT(err == 0);
 694                 break;
 695         case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
 696                 /*
 697                  * clear local and received settings
 698                  * - remove propname
 699                  * - remove propname$inherit
 700                  * - remove propname$recvd
 701                  */
 702                 err = zap_remove(mos, zapobj, propname, tx);
 703                 ASSERT(err == 0 || err == ENOENT);
 704                 err = zap_remove(mos, zapobj, inheritstr, tx);
 705                 ASSERT(err == 0 || err == ENOENT);
 706                 /* FALLTHRU */
 707         case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
 708                 /*
 709                  * remove propname$recvd
 710                  */
 711                 err = zap_remove(mos, zapobj, recvdstr, tx);
 712                 ASSERT(err == 0 || err == ENOENT);
 713                 break;
 714         default:
 715                 cmn_err(CE_PANIC, "unexpected property source: %d", source);
 716         }
 717 
 718         strfree(inheritstr);
 719         strfree(recvdstr);
 720 
 721         if (isint) {
 722                 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
 723 
 724                 if (ds->ds_is_snapshot) {
 725                         dsl_prop_cb_record_t *cbr;
 726                         /*
 727                          * It's a snapshot; nothing can inherit this
 728                          * property, so just look for callbacks on this
 729                          * ds here.
 730                          */
 731                         mutex_enter(&ds->ds_dir->dd_lock);
 732                         for (cbr = list_head(&ds->ds_prop_cbs); cbr;
 733                             cbr = list_next(&ds->ds_prop_cbs, cbr)) {
 734                                 if (strcmp(cbr->cbr_pr->pr_propname,
 735                                     propname) == 0)
 736                                         cbr->cbr_func(cbr->cbr_arg, intval);
 737                         }
 738                         mutex_exit(&ds->ds_dir->dd_lock);
 739                 } else {
 740                         dsl_prop_changed_notify(ds->ds_dir->dd_pool,
 741                             ds->ds_dir->dd_object, propname, intval, TRUE);
 742                 }
 743 
 744                 (void) snprintf(valbuf, sizeof (valbuf),
 745                     "%lld", (longlong_t)intval);
 746                 valstr = valbuf;
 747         } else {
 748                 if (source == ZPROP_SRC_LOCAL) {
 749                         valstr = value;
 750                 } else {
 751                         tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
 752                         if (dsl_prop_get_ds(ds, propname, 1,
 753                             ZAP_MAXVALUELEN, tbuf, NULL) == 0)
 754                                 valstr = tbuf;
 755                 }
 756         }
 757 
 758         spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE ||
 759             source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx,
 760             "%s=%s", propname, (valstr == NULL ? "" : valstr));
 761 
 762         if (tbuf != NULL)
 763                 kmem_free(tbuf, ZAP_MAXVALUELEN);
 764 }
 765 
 766 int
 767 dsl_prop_set_int(const char *dsname, const char *propname,
 768     zprop_source_t source, uint64_t value)
 769 {
 770         nvlist_t *nvl = fnvlist_alloc();
 771         int error;
 772 
 773         fnvlist_add_uint64(nvl, propname, value);
 774         error = dsl_props_set(dsname, source, nvl);
 775         fnvlist_free(nvl);
 776         return (error);
 777 }
 778 
 779 int
 780 dsl_prop_set_string(const char *dsname, const char *propname,
 781     zprop_source_t source, const char *value)
 782 {
 783         nvlist_t *nvl = fnvlist_alloc();
 784         int error;
 785 
 786         fnvlist_add_string(nvl, propname, value);
 787         error = dsl_props_set(dsname, source, nvl);
 788         fnvlist_free(nvl);
 789         return (error);
 790 }
 791 
 792 int
 793 dsl_prop_inherit(const char *dsname, const char *propname,
 794     zprop_source_t source)
 795 {
 796         nvlist_t *nvl = fnvlist_alloc();
 797         int error;
 798 
 799         fnvlist_add_boolean(nvl, propname);
 800         error = dsl_props_set(dsname, source, nvl);
 801         fnvlist_free(nvl);
 802         return (error);
 803 }
 804 
 805 typedef struct dsl_props_set_arg {
 806         const char *dpsa_dsname;
 807         zprop_source_t dpsa_source;
 808         nvlist_t *dpsa_props;
 809 } dsl_props_set_arg_t;
 810 
 811 static int
 812 dsl_props_set_check(void *arg, dmu_tx_t *tx)
 813 {
 814         dsl_props_set_arg_t *dpsa = arg;
 815         dsl_pool_t *dp = dmu_tx_pool(tx);
 816         dsl_dataset_t *ds;
 817         uint64_t version;
 818         nvpair_t *elem = NULL;
 819         int err;
 820 
 821         err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
 822         if (err != 0)
 823                 return (err);
 824 
 825         version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 826         while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
 827                 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
 828                         dsl_dataset_rele(ds, FTAG);
 829                         return (SET_ERROR(ENAMETOOLONG));
 830                 }
 831                 if (nvpair_type(elem) == DATA_TYPE_STRING) {
 832                         char *valstr = fnvpair_value_string(elem);
 833                         if (strlen(valstr) >= (version <
 834                             SPA_VERSION_STMF_PROP ?
 835                             ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
 836                                 dsl_dataset_rele(ds, FTAG);
 837                                 return (E2BIG);
 838                         }
 839                 }
 840         }
 841 
 842         if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
 843                 dsl_dataset_rele(ds, FTAG);
 844                 return (SET_ERROR(ENOTSUP));
 845         }
 846         dsl_dataset_rele(ds, FTAG);
 847         return (0);
 848 }
 849 
 850 void
 851 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
 852     nvlist_t *props, dmu_tx_t *tx)
 853 {
 854         nvpair_t *elem = NULL;
 855 
 856         while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 857                 nvpair_t *pair = elem;
 858                 const char *name = nvpair_name(pair);
 859 
 860                 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
 861                         /*
 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.
 867                          */
 868                         nvlist_t *attrs = fnvpair_value_nvlist(pair);
 869                         pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
 870                 }
 871 
 872                 if (nvpair_type(pair) == DATA_TYPE_STRING) {
 873                         const char *value = fnvpair_value_string(pair);
 874                         dsl_prop_set_sync_impl(ds, name,
 875                             source, 1, strlen(value) + 1, value, tx);
 876                 } else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
 877                         uint64_t intval = fnvpair_value_uint64(pair);
 878                         dsl_prop_set_sync_impl(ds, name,
 879                             source, sizeof (intval), 1, &intval, tx);
 880                 } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
 881                         dsl_prop_set_sync_impl(ds, name,
 882                             source, 0, 0, NULL, tx);
 883                 } else {
 884                         panic("invalid nvpair type");
 885                 }
 886         }
 887 }
 888 
 889 static void
 890 dsl_props_set_sync(void *arg, dmu_tx_t *tx)
 891 {
 892         dsl_props_set_arg_t *dpsa = arg;
 893         dsl_pool_t *dp = dmu_tx_pool(tx);
 894         dsl_dataset_t *ds;
 895 
 896         VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
 897         dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
 898         dsl_dataset_rele(ds, FTAG);
 899 }
 900 
 901 /*
 902  * All-or-nothing; if any prop can't be set, nothing will be modified.
 903  */
 904 int
 905 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
 906 {
 907         dsl_props_set_arg_t dpsa;
 908         int nblks = 0;
 909 
 910         dpsa.dpsa_dsname = dsname;
 911         dpsa.dpsa_source = source;
 912         dpsa.dpsa_props = props;
 913 
 914         /*
 915          * If the source includes NONE, then we will only be removing entries
 916          * from the ZAP object.  In that case don't check for ENOSPC.
 917          */
 918         if ((source & ZPROP_SRC_NONE) == 0)
 919                 nblks = 2 * fnvlist_num_pairs(props);
 920 
 921         return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
 922             &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
 923 }
 924 
 925 typedef enum dsl_prop_getflags {
 926         DSL_PROP_GET_INHERITING = 0x1,  /* searching parent of target ds */
 927         DSL_PROP_GET_SNAPSHOT = 0x2,    /* snapshot dataset */
 928         DSL_PROP_GET_LOCAL = 0x4,       /* local properties */
 929         DSL_PROP_GET_RECEIVED = 0x8     /* received properties */
 930 } dsl_prop_getflags_t;
 931 
 932 static int
 933 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
 934     const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
 935 {
 936         zap_cursor_t zc;
 937         zap_attribute_t za;
 938         int err = 0;
 939 
 940         for (zap_cursor_init(&zc, mos, propobj);
 941             (err = zap_cursor_retrieve(&zc, &za)) == 0;
 942             zap_cursor_advance(&zc)) {
 943                 nvlist_t *propval;
 944                 zfs_prop_t prop;
 945                 char buf[ZAP_MAXNAMELEN];
 946                 char *valstr;
 947                 const char *suffix;
 948                 const char *propname;
 949                 const char *source;
 950 
 951                 suffix = strchr(za.za_name, '$');
 952 
 953                 if (suffix == NULL) {
 954                         /*
 955                          * Skip local properties if we only want received
 956                          * properties.
 957                          */
 958                         if (flags & DSL_PROP_GET_RECEIVED)
 959                                 continue;
 960 
 961                         propname = za.za_name;
 962                         source = setpoint;
 963                 } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
 964                         /* Skip explicitly inherited entries. */
 965                         continue;
 966                 } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
 967                         if (flags & DSL_PROP_GET_LOCAL)
 968                                 continue;
 969 
 970                         (void) strncpy(buf, za.za_name, (suffix - za.za_name));
 971                         buf[suffix - za.za_name] = '\0';
 972                         propname = buf;
 973 
 974                         if (!(flags & DSL_PROP_GET_RECEIVED)) {
 975                                 /* Skip if locally overridden. */
 976                                 err = zap_contains(mos, propobj, propname);
 977                                 if (err == 0)
 978                                         continue;
 979                                 if (err != ENOENT)
 980                                         break;
 981 
 982                                 /* Skip if explicitly inherited. */
 983                                 valstr = kmem_asprintf("%s%s", propname,
 984                                     ZPROP_INHERIT_SUFFIX);
 985                                 err = zap_contains(mos, propobj, valstr);
 986                                 strfree(valstr);
 987                                 if (err == 0)
 988                                         continue;
 989                                 if (err != ENOENT)
 990                                         break;
 991                         }
 992 
 993                         source = ((flags & DSL_PROP_GET_INHERITING) ?
 994                             setpoint : ZPROP_SOURCE_VAL_RECVD);
 995                 } else {
 996                         /*
 997                          * For backward compatibility, skip suffixes we don't
 998                          * recognize.
 999                          */
1000                         continue;
1001                 }
1002 
1003                 prop = zfs_name_to_prop(propname);
1004 
1005                 /* Skip non-inheritable properties. */
1006                 if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
1007                     !zfs_prop_inheritable(prop))
1008                         continue;
1009 
1010                 /* Skip properties not valid for this type. */
1011                 if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
1012                     !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
1013                         continue;
1014 
1015                 /* Skip properties already defined. */
1016                 if (nvlist_exists(nv, propname))
1017                         continue;
1018 
1019                 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1020                 if (za.za_integer_length == 1) {
1021                         /*
1022                          * String property
1023                          */
1024                         char *tmp = kmem_alloc(za.za_num_integers,
1025                             KM_SLEEP);
1026                         err = zap_lookup(mos, propobj,
1027                             za.za_name, 1, za.za_num_integers, tmp);
1028                         if (err != 0) {
1029                                 kmem_free(tmp, za.za_num_integers);
1030                                 break;
1031                         }
1032                         VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
1033                             tmp) == 0);
1034                         kmem_free(tmp, za.za_num_integers);
1035                 } else {
1036                         /*
1037                          * Integer property
1038                          */
1039                         ASSERT(za.za_integer_length == 8);
1040                         (void) nvlist_add_uint64(propval, ZPROP_VALUE,
1041                             za.za_first_integer);
1042                 }
1043 
1044                 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
1045                 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1046                 nvlist_free(propval);
1047         }
1048         zap_cursor_fini(&zc);
1049         if (err == ENOENT)
1050                 err = 0;
1051         return (err);
1052 }
1053 
1054 /*
1055  * Iterate over all properties for this dataset and return them in an nvlist.
1056  */
1057 static int
1058 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1059     dsl_prop_getflags_t flags)
1060 {
1061         dsl_dir_t *dd = ds->ds_dir;
1062         dsl_pool_t *dp = dd->dd_pool;
1063         objset_t *mos = dp->dp_meta_objset;
1064         int err = 0;
1065         char setpoint[ZFS_MAX_DATASET_NAME_LEN];
1066 
1067         VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1068 
1069         if (ds->ds_is_snapshot)
1070                 flags |= DSL_PROP_GET_SNAPSHOT;
1071 
1072         ASSERT(dsl_pool_config_held(dp));
1073 
1074         if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
1075                 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
1076                 dsl_dataset_name(ds, setpoint);
1077                 err = dsl_prop_get_all_impl(mos,
1078                     dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
1079                 if (err)
1080                         goto out;
1081         }
1082 
1083         for (; dd != NULL; dd = dd->dd_parent) {
1084                 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1085                         if (flags & (DSL_PROP_GET_LOCAL |
1086                             DSL_PROP_GET_RECEIVED))
1087                                 break;
1088                         flags |= DSL_PROP_GET_INHERITING;
1089                 }
1090                 dsl_dir_name(dd, setpoint);
1091                 err = dsl_prop_get_all_impl(mos,
1092                     dsl_dir_phys(dd)->dd_props_zapobj, setpoint, flags, *nvp);
1093                 if (err)
1094                         break;
1095         }
1096 out:
1097         return (err);
1098 }
1099 
1100 boolean_t
1101 dsl_prop_get_hasrecvd(const char *dsname)
1102 {
1103         uint64_t dummy;
1104 
1105         return (0 ==
1106             dsl_prop_get_integer(dsname, ZPROP_HAS_RECVD, &dummy, NULL));
1107 }
1108 
1109 static int
1110 dsl_prop_set_hasrecvd_impl(const char *dsname, zprop_source_t source)
1111 {
1112         uint64_t version;
1113         spa_t *spa;
1114         int error = 0;
1115 
1116         VERIFY0(spa_open(dsname, &spa, FTAG));
1117         version = spa_version(spa);
1118         spa_close(spa, FTAG);
1119 
1120         if (version >= SPA_VERSION_RECVD_PROPS)
1121                 error = dsl_prop_set_int(dsname, ZPROP_HAS_RECVD, source, 0);
1122         return (error);
1123 }
1124 
1125 /*
1126  * Call after successfully receiving properties to ensure that only the first
1127  * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1128  */
1129 int
1130 dsl_prop_set_hasrecvd(const char *dsname)
1131 {
1132         int error = 0;
1133         if (!dsl_prop_get_hasrecvd(dsname))
1134                 error = dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_LOCAL);
1135         return (error);
1136 }
1137 
1138 void
1139 dsl_prop_unset_hasrecvd(const char *dsname)
1140 {
1141         VERIFY0(dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_NONE));
1142 }
1143 
1144 int
1145 dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
1146 {
1147         return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
1148 }
1149 
1150 int
1151 dsl_prop_get_received(const char *dsname, nvlist_t **nvp)
1152 {
1153         objset_t *os;
1154         int error;
1155 
1156         /*
1157          * Received properties are not distinguishable from local properties
1158          * until the dataset has received properties on or after
1159          * SPA_VERSION_RECVD_PROPS.
1160          */
1161         dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(dsname) ?
1162             DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
1163 
1164         error = dmu_objset_hold(dsname, FTAG, &os);
1165         if (error != 0)
1166                 return (error);
1167         error = dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags);
1168         dmu_objset_rele(os, FTAG);
1169         return (error);
1170 }
1171 
1172 void
1173 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
1174 {
1175         nvlist_t *propval;
1176         const char *propname = zfs_prop_to_name(prop);
1177         uint64_t default_value;
1178 
1179         if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1180                 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1181                 return;
1182         }
1183 
1184         VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1185         VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1186         /* Indicate the default source if we can. */
1187         if (dodefault(prop, 8, 1, &default_value) == 0 &&
1188             value == default_value) {
1189                 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
1190         }
1191         VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1192         nvlist_free(propval);
1193 }
1194 
1195 void
1196 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
1197 {
1198         nvlist_t *propval;
1199         const char *propname = zfs_prop_to_name(prop);
1200 
1201         if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1202                 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1203                 return;
1204         }
1205 
1206         VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1207         VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1208         VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1209         nvlist_free(propval);
1210 }