The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/zfs/dsl_prop.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 503d66faec62bf641f156401c874d29e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.