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()


   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));


 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 }


 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,


 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)


 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);


 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;


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)




   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  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  27  */
  28 
  29 #include <sys/zfs_context.h>
  30 #include <sys/dmu.h>
  31 #include <sys/dmu_objset.h>
  32 #include <sys/dmu_tx.h>
  33 #include <sys/dsl_dataset.h>
  34 #include <sys/dsl_dir.h>
  35 #include <sys/dsl_prop.h>
  36 #include <sys/dsl_synctask.h>
  37 #include <sys/zfeature.h>
  38 #include <sys/spa.h>
  39 #include <sys/zap.h>
  40 #include <sys/fs/zfs.h>
  41 #include <sys/wbc.h>
  42 
  43 #include "zfs_prop.h"
  44 #include "zfs_errno.h"
  45 



  46 static int
  47 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
  48 {
  49         /*
  50          * The setonce properties are read-only, BUT they still
  51          * have a default value that can be used as the initial
  52          * value.
  53          */
  54         if (prop == ZPROP_INVAL ||
  55             (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
  56                 return (SET_ERROR(ENOENT));
  57 
  58         if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
  59                 if (intsz != 1)
  60                         return (SET_ERROR(EOVERFLOW));
  61                 (void) strncpy(buf, zfs_prop_default_string(prop),
  62                     numints);
  63         } else {
  64                 if (intsz != 8 || numints < 1)
  65                         return (SET_ERROR(EOVERFLOW));


 271 /*
 272  * Register interest in the named property.  We'll call the callback
 273  * once to notify it of the current property value, and again each time
 274  * the property changes, until this callback is unregistered.
 275  *
 276  * Return 0 on success, errno if the prop is not an integer value.
 277  */
 278 int
 279 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
 280     dsl_prop_changed_cb_t *callback, void *cbarg)
 281 {
 282         dsl_dir_t *dd = ds->ds_dir;
 283         dsl_pool_t *dp = dd->dd_pool;
 284         uint64_t value;
 285         dsl_prop_record_t *pr;
 286         dsl_prop_cb_record_t *cbr;
 287         int err;
 288 
 289         ASSERT(dsl_pool_config_held(dp));
 290 
 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 
 301         if (err != 0)
 302                 return (err);
 303 
 304         cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
 305         cbr->cbr_ds = ds;
 306         cbr->cbr_func = callback;
 307         cbr->cbr_arg = cbarg;
 308 
 309         mutex_enter(&dd->dd_lock);
 310         pr = dsl_prop_record_find(dd, propname);
 311         if (pr == NULL)
 312                 pr = dsl_prop_record_create(dd, propname);
 313         cbr->cbr_pr = pr;
 314         list_insert_head(&pr->pr_cbs, cbr);
 315         list_insert_head(&ds->ds_prop_cbs, cbr);
 316         mutex_exit(&dd->dd_lock);
 317 
 318         cbr->cbr_func(cbr->cbr_arg, value);
 319         return (0);
 320 }


 470 boolean_t
 471 dsl_prop_hascb(dsl_dataset_t *ds)
 472 {
 473         return (!list_is_empty(&ds->ds_prop_cbs));
 474 }
 475 
 476 /* ARGSUSED */
 477 static int
 478 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
 479 {
 480         dsl_dir_t *dd = ds->ds_dir;
 481         dsl_prop_record_t *pr;
 482         dsl_prop_cb_record_t *cbr;
 483 
 484         mutex_enter(&dd->dd_lock);
 485         for (pr = list_head(&dd->dd_props);
 486             pr; pr = list_next(&dd->dd_props, pr)) {
 487                 for (cbr = list_head(&pr->pr_cbs); cbr;
 488                     cbr = list_next(&pr->pr_cbs, cbr)) {
 489                         uint64_t value;
 490                         const char *propname;
 491 
 492                         /*
 493                          * Callback entries do not have holds on their
 494                          * datasets so that datasets with registered
 495                          * callbacks are still eligible for eviction.
 496                          * Unlike operations to update properties on a
 497                          * single dataset, we are performing a recursive
 498                          * descent of related head datasets.  The caller
 499                          * of this function only has a dataset hold on
 500                          * the passed in head dataset, not the snapshots
 501                          * associated with this dataset.  Without a hold,
 502                          * the dataset pointer within callback records
 503                          * for snapshots can be invalidated by eviction
 504                          * at any time.
 505                          *
 506                          * Use dsl_dataset_try_add_ref() to verify
 507                          * that the dataset for a snapshot has not
 508                          * begun eviction processing and to prevent
 509                          * eviction from occurring for the duration of
 510                          * the callback.  If the hold attempt fails,
 511                          * this object is already being evicted and the
 512                          * callback can be safely ignored.
 513                          */
 514                         if (ds != cbr->cbr_ds &&
 515                             !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
 516                                 continue;
 517 
 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) {
 529                                 cbr->cbr_func(cbr->cbr_arg, value);
 530                         }
 531 
 532                         if (ds != cbr->cbr_ds)
 533                                 dsl_dataset_rele(cbr->cbr_ds, FTAG);
 534                 }
 535         }
 536         mutex_exit(&dd->dd_lock);
 537 
 538         return (0);
 539 }
 540 
 541 /*
 542  * Update all property values for ddobj & its descendants.  This is used
 543  * when renaming the dir.
 544  */
 545 void
 546 dsl_prop_notify_all(dsl_dir_t *dd)
 547 {
 548         dsl_pool_t *dp = dd->dd_pool;
 549         ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
 550         (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,


 623         }
 624         kmem_free(za, sizeof (zap_attribute_t));
 625         zap_cursor_fini(&zc);
 626         dsl_dir_rele(dd, FTAG);
 627 }
 628 
 629 void
 630 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
 631     zprop_source_t source, int intsz, int numints, const void *value,
 632     dmu_tx_t *tx)
 633 {
 634         objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 635         uint64_t zapobj, intval, dummy;
 636         int isint;
 637         char valbuf[32];
 638         const char *valstr = NULL;
 639         char *inheritstr;
 640         char *recvdstr;
 641         char *tbuf = NULL;
 642         int err;
 643         spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
 644         uint64_t version = spa_version(spa);
 645 
 646         isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
 647 
 648         if (ds->ds_is_snapshot) {
 649                 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
 650                 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
 651                         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 652                         dsl_dataset_phys(ds)->ds_props_obj =
 653                             zap_create(mos,
 654                             DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
 655                 }
 656                 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
 657         } else {
 658                 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
 659         }
 660 
 661         if (version < SPA_VERSION_RECVD_PROPS) {
 662                 if (source & ZPROP_SRC_NONE)
 663                         source = ZPROP_SRC_NONE;
 664                 else if (source & ZPROP_SRC_RECEIVED)


 722                  */
 723                 err = zap_remove(mos, zapobj, propname, tx);
 724                 ASSERT(err == 0 || err == ENOENT);
 725                 err = zap_remove(mos, zapobj, inheritstr, tx);
 726                 ASSERT(err == 0 || err == ENOENT);
 727                 /* FALLTHRU */
 728         case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
 729                 /*
 730                  * remove propname$recvd
 731                  */
 732                 err = zap_remove(mos, zapobj, recvdstr, tx);
 733                 ASSERT(err == 0 || err == ENOENT);
 734                 break;
 735         default:
 736                 cmn_err(CE_PANIC, "unexpected property source: %d", source);
 737         }
 738 
 739         strfree(inheritstr);
 740         strfree(recvdstr);
 741 
 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) {
 783                 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
 784 
 785                 if (ds->ds_is_snapshot) {
 786                         dsl_prop_cb_record_t *cbr;
 787                         /*
 788                          * It's a snapshot; nothing can inherit this
 789                          * property, so just look for callbacks on this
 790                          * ds here.
 791                          */
 792                         mutex_enter(&ds->ds_dir->dd_lock);
 793                         for (cbr = list_head(&ds->ds_prop_cbs); cbr;
 794                             cbr = list_next(&ds->ds_prop_cbs, cbr)) {
 795                                 if (strcmp(cbr->cbr_pr->pr_propname,
 796                                     propname) == 0)
 797                                         cbr->cbr_func(cbr->cbr_arg, intval);
 798                         }
 799                         mutex_exit(&ds->ds_dir->dd_lock);
 800                 } else {
 801                         dsl_prop_changed_notify(ds->ds_dir->dd_pool,
 802                             ds->ds_dir->dd_object, propname, intval, TRUE);


 846 
 847         fnvlist_add_string(nvl, propname, value);
 848         error = dsl_props_set(dsname, source, nvl);
 849         fnvlist_free(nvl);
 850         return (error);
 851 }
 852 
 853 int
 854 dsl_prop_inherit(const char *dsname, const char *propname,
 855     zprop_source_t source)
 856 {
 857         nvlist_t *nvl = fnvlist_alloc();
 858         int error;
 859 
 860         fnvlist_add_boolean(nvl, propname);
 861         error = dsl_props_set(dsname, source, nvl);
 862         fnvlist_free(nvl);
 863         return (error);
 864 }
 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 
 935 typedef struct dsl_props_set_arg {
 936         const char *dpsa_dsname;
 937         zprop_source_t dpsa_source;
 938         nvlist_t *dpsa_props;
 939 } dsl_props_set_arg_t;
 940 
 941 static int
 942 dsl_props_set_check(void *arg, dmu_tx_t *tx)
 943 {
 944         dsl_props_set_arg_t *dpsa = arg;
 945         dsl_pool_t *dp = dmu_tx_pool(tx);
 946         dsl_dataset_t *ds;
 947         objset_t *os = NULL;
 948         uint64_t version;
 949         nvpair_t *elem = NULL;
 950         int err;
 951 
 952         err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
 953         if (err != 0)
 954                 return (err);
 955 
 956         err = dmu_objset_from_ds(ds, &os);
 957         if (err != 0) {
 958                 dsl_dataset_rele(ds, FTAG);
 959                 return (err);
 960         }
 961 
 962         version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 963         while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
 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) {
 968                         dsl_dataset_rele(ds, FTAG);
 969                         return (SET_ERROR(ENAMETOOLONG));
 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 
1047                 if (nvpair_type(elem) == DATA_TYPE_STRING) {
1048                         char *valstr = fnvpair_value_string(elem);
1049                         if (strlen(valstr) >= (version <
1050                             SPA_VERSION_STMF_PROP ?
1051                             ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
1052                                 dsl_dataset_rele(ds, FTAG);
1053                                 return (SET_ERROR(E2BIG));
1054                         }
1055                 }
1056 
1057         }
1058 
1059         if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
1060                 dsl_dataset_rele(ds, FTAG);
1061                 return (SET_ERROR(ENOTSUP));
1062         }
1063         dsl_dataset_rele(ds, FTAG);
1064         return (0);
1065 }
1066 
1067 void
1068 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
1069     nvlist_t *props, dmu_tx_t *tx)
1070 {
1071         nvpair_t *elem = NULL;
1072 
1073         while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
1074                 nvpair_t *pair = elem;

1075 
1076                 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
1077                         /*
1078                          * dsl_prop_get_all_impl() returns properties in this
1079                          * format.



1080                          */
1081                         nvlist_t *attrs = fnvpair_value_nvlist(pair);
1082                         pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
1083                 }
1084 
1085                 if (nvpair_type(pair) == DATA_TYPE_STRING) {
1086                         const char *value = fnvpair_value_string(pair);
1087                         dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1088                             source, 1, strlen(value) + 1, value, tx);
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);
1092                         uint64_t intval = fnvpair_value_uint64(pair);
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                         }
1119                 } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
1120                         dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1121                             source, 0, 0, NULL, tx);
1122                 } else {
1123                         panic("invalid nvpair type");
1124                 }
1125         }
1126 }
1127 
1128 static void
1129 dsl_props_set_sync(void *arg, dmu_tx_t *tx)
1130 {
1131         dsl_props_set_arg_t *dpsa = arg;
1132         dsl_pool_t *dp = dmu_tx_pool(tx);
1133         dsl_dataset_t *ds;
1134         objset_t *os = NULL;
1135 
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));
1147         dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
1148         dsl_dataset_rele(ds, FTAG);
1149 }
1150 
1151 /*
1152  * All-or-nothing; if any prop can't be set, nothing will be modified.
1153  */
1154 int
1155 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
1156 {
1157         dsl_props_set_arg_t dpsa;
1158         int nblks = 0;
1159 
1160         dpsa.dpsa_dsname = dsname;
1161         dpsa.dpsa_source = source;
1162         dpsa.dpsa_props = props;
1163 
1164         /*
1165          * If the source includes NONE, then we will only be removing entries
1166          * from the ZAP object.  In that case don't check for ENOSPC.
1167          */
1168         if ((source & ZPROP_SRC_NONE) == 0)
1169                 nblks = 2 * fnvlist_num_pairs(props);
1170 
1171         return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
1172             &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
1173 }
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 
1262 typedef enum dsl_prop_getflags {
1263         DSL_PROP_GET_INHERITING = 0x1,  /* searching parent of target ds */
1264         DSL_PROP_GET_SNAPSHOT = 0x2,    /* snapshot dataset */
1265         DSL_PROP_GET_LOCAL = 0x4,       /* local properties */
1266         DSL_PROP_GET_RECEIVED = 0x8     /* received properties */
1267 } dsl_prop_getflags_t;
1268 
1269 static int
1270 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
1271     const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
1272 {
1273         zap_cursor_t zc;
1274         zap_attribute_t za;
1275         int err = 0;
1276 
1277         for (zap_cursor_init(&zc, mos, propobj);
1278             (err = zap_cursor_retrieve(&zc, &za)) == 0;
1279             zap_cursor_advance(&zc)) {
1280                 nvlist_t *propval;
1281                 zfs_prop_t prop;


1349                     !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
1350                         continue;
1351 
1352                 /* Skip properties already defined. */
1353                 if (nvlist_exists(nv, propname))
1354                         continue;
1355 
1356                 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1357                 if (za.za_integer_length == 1) {
1358                         /*
1359                          * String property
1360                          */
1361                         char *tmp = kmem_alloc(za.za_num_integers,
1362                             KM_SLEEP);
1363                         err = zap_lookup(mos, propobj,
1364                             za.za_name, 1, za.za_num_integers, tmp);
1365                         if (err != 0) {
1366                                 kmem_free(tmp, za.za_num_integers);
1367                                 break;
1368                         }
1369 
1370                         VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
1371                             tmp) == 0);
1372                         kmem_free(tmp, za.za_num_integers);
1373                 } else {
1374                         /*
1375                          * Integer property
1376                          */
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 
1397                         (void) nvlist_add_uint64(propval, ZPROP_VALUE,
1398                             za.za_first_integer);
1399                 }
1400 
1401                 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
1402                 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1403                 nvlist_free(propval);
1404         }
1405         zap_cursor_fini(&zc);
1406         if (err == ENOENT)
1407                 err = 0;
1408         return (err);
1409 }
1410 
1411 /*
1412  * Iterate over all properties for this dataset and return them in an nvlist.
1413  */
1414 static int
1415 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1416     dsl_prop_getflags_t flags)