FreeBSD ZFS
The Zettabyte File System

dsl_prop.c

Go to the documentation of this file.
00001 /*
00002  * CDDL HEADER START
00003  *
00004  * The contents of this file are subject to the terms of the
00005  * Common Development and Distribution License (the "License").
00006  * You may not use this file except in compliance with the License.
00007  *
00008  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
00009  * or http://www.opensolaris.org/os/licensing.
00010  * See the License for the specific language governing permissions
00011  * and limitations under the License.
00012  *
00013  * When distributing Covered Code, include this CDDL HEADER in each
00014  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
00015  * If applicable, add the following below this CDDL HEADER, with the
00016  * fields enclosed by brackets "[]" replaced with your own identifying
00017  * information: Portions Copyright [yyyy] [name of copyright owner]
00018  *
00019  * CDDL HEADER END
00020  */
00021 /*
00022  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
00023  */
00024 
00025 #include <sys/zfs_context.h>
00026 #include <sys/dmu.h>
00027 #include <sys/dmu_objset.h>
00028 #include <sys/dmu_tx.h>
00029 #include <sys/dsl_dataset.h>
00030 #include <sys/dsl_dir.h>
00031 #include <sys/dsl_prop.h>
00032 #include <sys/dsl_synctask.h>
00033 #include <sys/spa.h>
00034 #include <sys/zap.h>
00035 #include <sys/fs/zfs.h>
00036 
00037 #include "zfs_prop.h"
00038 
00039 #define ZPROP_INHERIT_SUFFIX "$inherit"
00040 #define ZPROP_RECVD_SUFFIX "$recvd"
00041 
00042 static int
00043 dodefault(const char *propname, int intsz, int numints, void *buf)
00044 {
00045         zfs_prop_t prop;
00046 
00047         /*
00048          * The setonce properties are read-only, BUT they still
00049          * have a default value that can be used as the initial
00050          * value.
00051          */
00052         if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL ||
00053             (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
00054                 return (ENOENT);
00055 
00056         if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
00057                 if (intsz != 1)
00058                         return (EOVERFLOW);
00059                 (void) strncpy(buf, zfs_prop_default_string(prop),
00060                     numints);
00061         } else {
00062                 if (intsz != 8 || numints < 1)
00063                         return (EOVERFLOW);
00064 
00065                 *(uint64_t *)buf = zfs_prop_default_numeric(prop);
00066         }
00067 
00068         return (0);
00069 }
00070 
00071 int
00072 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
00073     int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
00074 {
00075         int err = ENOENT;
00076         dsl_dir_t *target = dd;
00077         objset_t *mos = dd->dd_pool->dp_meta_objset;
00078         zfs_prop_t prop;
00079         boolean_t inheritable;
00080         boolean_t inheriting = B_FALSE;
00081         char *inheritstr;
00082         char *recvdstr;
00083 
00084         ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock));
00085 
00086         if (setpoint)
00087                 setpoint[0] = '\0';
00088 
00089         prop = zfs_name_to_prop(propname);
00090         inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
00091         inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
00092         recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
00093 
00094         /*
00095          * Note: dd may become NULL, therefore we shouldn't dereference it
00096          * after this loop.
00097          */
00098         for (; dd != NULL; dd = dd->dd_parent) {
00099                 ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock));
00100 
00101                 if (dd != target || snapshot) {
00102                         if (!inheritable)
00103                                 break;
00104                         inheriting = B_TRUE;
00105                 }
00106 
00107                 /* Check for a local value. */
00108                 err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname,
00109                     intsz, numints, buf);
00110                 if (err != ENOENT) {
00111                         if (setpoint != NULL && err == 0)
00112                                 dsl_dir_name(dd, setpoint);
00113                         break;
00114                 }
00115 
00116                 /*
00117                  * Skip the check for a received value if there is an explicit
00118                  * inheritance entry.
00119                  */
00120                 err = zap_contains(mos, dd->dd_phys->dd_props_zapobj,
00121                     inheritstr);
00122                 if (err != 0 && err != ENOENT)
00123                         break;
00124 
00125                 if (err == ENOENT) {
00126                         /* Check for a received value. */
00127                         err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj,
00128                             recvdstr, intsz, numints, buf);
00129                         if (err != ENOENT) {
00130                                 if (setpoint != NULL && err == 0) {
00131                                         if (inheriting) {
00132                                                 dsl_dir_name(dd, setpoint);
00133                                         } else {
00134                                                 (void) strcpy(setpoint,
00135                                                     ZPROP_SOURCE_VAL_RECVD);
00136                                         }
00137                                 }
00138                                 break;
00139                         }
00140                 }
00141 
00142                 /*
00143                  * If we found an explicit inheritance entry, err is zero even
00144                  * though we haven't yet found the value, so reinitializing err
00145                  * at the end of the loop (instead of at the beginning) ensures
00146                  * that err has a valid post-loop value.
00147                  */
00148                 err = ENOENT;
00149         }
00150 
00151         if (err == ENOENT)
00152                 err = dodefault(propname, intsz, numints, buf);
00153 
00154         strfree(inheritstr);
00155         strfree(recvdstr);
00156 
00157         return (err);
00158 }
00159 
00160 int
00161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
00162     int intsz, int numints, void *buf, char *setpoint)
00163 {
00164         zfs_prop_t prop = zfs_name_to_prop(propname);
00165         boolean_t inheritable;
00166         boolean_t snapshot;
00167         uint64_t zapobj;
00168 
00169         ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock));
00170         inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
00171         snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds));
00172         zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj);
00173 
00174         if (zapobj != 0) {
00175                 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
00176                 int err;
00177 
00178                 ASSERT(snapshot);
00179 
00180                 /* Check for a local value. */
00181                 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
00182                 if (err != ENOENT) {
00183                         if (setpoint != NULL && err == 0)
00184                                 dsl_dataset_name(ds, setpoint);
00185                         return (err);
00186                 }
00187 
00188                 /*
00189                  * Skip the check for a received value if there is an explicit
00190                  * inheritance entry.
00191                  */
00192                 if (inheritable) {
00193                         char *inheritstr = kmem_asprintf("%s%s", propname,
00194                             ZPROP_INHERIT_SUFFIX);
00195                         err = zap_contains(mos, zapobj, inheritstr);
00196                         strfree(inheritstr);
00197                         if (err != 0 && err != ENOENT)
00198                                 return (err);
00199                 }
00200 
00201                 if (err == ENOENT) {
00202                         /* Check for a received value. */
00203                         char *recvdstr = kmem_asprintf("%s%s", propname,
00204                             ZPROP_RECVD_SUFFIX);
00205                         err = zap_lookup(mos, zapobj, recvdstr,
00206                             intsz, numints, buf);
00207                         strfree(recvdstr);
00208                         if (err != ENOENT) {
00209                                 if (setpoint != NULL && err == 0)
00210                                         (void) strcpy(setpoint,
00211                                             ZPROP_SOURCE_VAL_RECVD);
00212                                 return (err);
00213                         }
00214                 }
00215         }
00216 
00217         return (dsl_prop_get_dd(ds->ds_dir, propname,
00218             intsz, numints, buf, setpoint, snapshot));
00219 }
00220 
00228 int
00229 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
00230     dsl_prop_changed_cb_t *callback, void *cbarg)
00231 {
00232         dsl_dir_t *dd = ds->ds_dir;
00233         dsl_pool_t *dp = dd->dd_pool;
00234         uint64_t value;
00235         dsl_prop_cb_record_t *cbr;
00236         int err;
00237         int need_rwlock;
00238 
00239         need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock);
00240         if (need_rwlock)
00241                 rw_enter(&dp->dp_config_rwlock, RW_READER);
00242 
00243         err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL);
00244         if (err != 0) {
00245                 if (need_rwlock)
00246                         rw_exit(&dp->dp_config_rwlock);
00247                 return (err);
00248         }
00249 
00250         cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
00251         cbr->cbr_ds = ds;
00252         cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP);
00253         (void) strcpy((char *)cbr->cbr_propname, propname);
00254         cbr->cbr_func = callback;
00255         cbr->cbr_arg = cbarg;
00256         mutex_enter(&dd->dd_lock);
00257         list_insert_head(&dd->dd_prop_cbs, cbr);
00258         mutex_exit(&dd->dd_lock);
00259 
00260         cbr->cbr_func(cbr->cbr_arg, value);
00261 
00262         if (need_rwlock)
00263                 rw_exit(&dp->dp_config_rwlock);
00264         return (0);
00265 }
00266 
00267 int
00268 dsl_prop_get(const char *dsname, const char *propname,
00269     int intsz, int numints, void *buf, char *setpoint)
00270 {
00271         dsl_dataset_t *ds;
00272         int err;
00273 
00274         err = dsl_dataset_hold(dsname, FTAG, &ds);
00275         if (err)
00276                 return (err);
00277 
00278         rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
00279         err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint);
00280         rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
00281 
00282         dsl_dataset_rele(ds, FTAG);
00283         return (err);
00284 }
00285 
00294 int
00295 dsl_prop_get_integer(const char *ddname, const char *propname,
00296     uint64_t *valuep, char *setpoint)
00297 {
00298         return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
00299 }
00300 
00301 void
00302 dsl_prop_setarg_init_uint64(dsl_prop_setarg_t *psa, const char *propname,
00303     zprop_source_t source, uint64_t *value)
00304 {
00305         psa->psa_name = propname;
00306         psa->psa_source = source;
00307         psa->psa_intsz = 8;
00308         psa->psa_numints = 1;
00309         psa->psa_value = value;
00310 
00311         psa->psa_effective_value = -1ULL;
00312 }
00313 
00324 int
00325 dsl_prop_predict_sync(dsl_dir_t *dd, dsl_prop_setarg_t *psa)
00326 {
00327         const char *propname = psa->psa_name;
00328         zfs_prop_t prop = zfs_name_to_prop(propname);
00329         zprop_source_t source = psa->psa_source;
00330         objset_t *mos;
00331         uint64_t zapobj;
00332         uint64_t version;
00333         char *recvdstr;
00334         int err = 0;
00335 
00336         switch (prop) {
00337         case ZFS_PROP_QUOTA:
00338         case ZFS_PROP_RESERVATION:
00339         case ZFS_PROP_REFQUOTA:
00340         case ZFS_PROP_REFRESERVATION:
00341                 break;
00342         default:
00343                 return (-1);
00344         }
00345 
00346         mos = dd->dd_pool->dp_meta_objset;
00347         zapobj = dd->dd_phys->dd_props_zapobj;
00348         recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
00349 
00350         version = spa_version(dd->dd_pool->dp_spa);
00351         if (version < SPA_VERSION_RECVD_PROPS) {
00352                 if (source & ZPROP_SRC_NONE)
00353                         source = ZPROP_SRC_NONE;
00354                 else if (source & ZPROP_SRC_RECEIVED)
00355                         source = ZPROP_SRC_LOCAL;
00356         }
00357 
00358         switch (source) {
00359         case ZPROP_SRC_NONE:
00360                 /* Revert to the received value, if any. */
00361                 err = zap_lookup(mos, zapobj, recvdstr, 8, 1,
00362                     &psa->psa_effective_value);
00363                 if (err == ENOENT)
00364                         psa->psa_effective_value = 0;
00365                 break;
00366         case ZPROP_SRC_LOCAL:
00367                 psa->psa_effective_value = *(uint64_t *)psa->psa_value;
00368                 break;
00369         case ZPROP_SRC_RECEIVED:
00370                 /*
00371                  * If there's no local setting, then the new received value will
00372                  * be the effective value.
00373                  */
00374                 err = zap_lookup(mos, zapobj, propname, 8, 1,
00375                     &psa->psa_effective_value);
00376                 if (err == ENOENT)
00377                         psa->psa_effective_value = *(uint64_t *)psa->psa_value;
00378                 break;
00379         case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
00380                 /*
00381                  * We're clearing the received value, so the local setting (if
00382                  * it exists) remains the effective value.
00383                  */
00384                 err = zap_lookup(mos, zapobj, propname, 8, 1,
00385                     &psa->psa_effective_value);
00386                 if (err == ENOENT)
00387                         psa->psa_effective_value = 0;
00388                 break;
00389         default:
00390                 cmn_err(CE_PANIC, "unexpected property source: %d", source);
00391         }
00392 
00393         strfree(recvdstr);
00394 
00395         if (err == ENOENT)
00396                 return (0);
00397 
00398         return (err);
00399 }
00400 
00401 #ifdef  ZFS_DEBUG
00402 void
00403 dsl_prop_check_prediction(dsl_dir_t *dd, dsl_prop_setarg_t *psa)
00404 {
00405         zfs_prop_t prop = zfs_name_to_prop(psa->psa_name);
00406         uint64_t intval;
00407         char setpoint[MAXNAMELEN];
00408         uint64_t version = spa_version(dd->dd_pool->dp_spa);
00409         int err;
00410 
00411         if (version < SPA_VERSION_RECVD_PROPS) {
00412                 switch (prop) {
00413                 case ZFS_PROP_QUOTA:
00414                 case ZFS_PROP_RESERVATION:
00415                         return;
00416                 }
00417         }
00418 
00419         err = dsl_prop_get_dd(dd, psa->psa_name, 8, 1, &intval,
00420             setpoint, B_FALSE);
00421         if (err == 0 && intval != psa->psa_effective_value) {
00422                 cmn_err(CE_PANIC, "%s property, source: %x, "
00423                     "predicted effective value: %llu, "
00424                     "actual effective value: %llu (setpoint: %s)",
00425                     psa->psa_name, psa->psa_source,
00426                     (unsigned long long)psa->psa_effective_value,
00427                     (unsigned long long)intval, setpoint);
00428         }
00429 }
00430 #endif
00431 
00438 int
00439 dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
00440     dsl_prop_changed_cb_t *callback, void *cbarg)
00441 {
00442         dsl_dir_t *dd = ds->ds_dir;
00443         dsl_prop_cb_record_t *cbr;
00444 
00445         mutex_enter(&dd->dd_lock);
00446         for (cbr = list_head(&dd->dd_prop_cbs);
00447             cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
00448                 if (cbr->cbr_ds == ds &&
00449                     cbr->cbr_func == callback &&
00450                     cbr->cbr_arg == cbarg &&
00451                     strcmp(cbr->cbr_propname, propname) == 0)
00452                         break;
00453         }
00454 
00455         if (cbr == NULL) {
00456                 mutex_exit(&dd->dd_lock);
00457                 return (ENOMSG);
00458         }
00459 
00460         list_remove(&dd->dd_prop_cbs, cbr);
00461         mutex_exit(&dd->dd_lock);
00462         kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1);
00463         kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
00464 
00465         return (0);
00466 }
00467 
00471 int
00472 dsl_prop_numcb(dsl_dataset_t *ds)
00473 {
00474         dsl_dir_t *dd = ds->ds_dir;
00475         dsl_prop_cb_record_t *cbr;
00476         int num = 0;
00477 
00478         mutex_enter(&dd->dd_lock);
00479         for (cbr = list_head(&dd->dd_prop_cbs);
00480             cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
00481                 if (cbr->cbr_ds == ds)
00482                         num++;
00483         }
00484         mutex_exit(&dd->dd_lock);
00485 
00486         return (num);
00487 }
00488 
00489 static void
00490 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
00491     const char *propname, uint64_t value, int first)
00492 {
00493         dsl_dir_t *dd;
00494         dsl_prop_cb_record_t *cbr;
00495         objset_t *mos = dp->dp_meta_objset;
00496         zap_cursor_t zc;
00497         zap_attribute_t *za;
00498         int err;
00499 
00500         ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock));
00501         err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd);
00502         if (err)
00503                 return;
00504 
00505         if (!first) {
00506                 /*
00507                  * If the prop is set here, then this change is not
00508                  * being inherited here or below; stop the recursion.
00509                  */
00510                 err = zap_contains(mos, dd->dd_phys->dd_props_zapobj, propname);
00511                 if (err == 0) {
00512                         dsl_dir_close(dd, FTAG);
00513                         return;
00514                 }
00515                 ASSERT3U(err, ==, ENOENT);
00516         }
00517 
00518         mutex_enter(&dd->dd_lock);
00519         for (cbr = list_head(&dd->dd_prop_cbs); cbr;
00520             cbr = list_next(&dd->dd_prop_cbs, cbr)) {
00521                 uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj;
00522 
00523                 if (strcmp(cbr->cbr_propname, propname) != 0)
00524                         continue;
00525 
00526                 /*
00527                  * If the property is set on this ds, then it is not
00528                  * inherited here; don't call the callback.
00529                  */
00530                 if (propobj && 0 == zap_contains(mos, propobj, propname))
00531                         continue;
00532 
00533                 cbr->cbr_func(cbr->cbr_arg, value);
00534         }
00535         mutex_exit(&dd->dd_lock);
00536 
00537         za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
00538         for (zap_cursor_init(&zc, mos,
00539             dd->dd_phys->dd_child_dir_zapobj);
00540             zap_cursor_retrieve(&zc, za) == 0;
00541             zap_cursor_advance(&zc)) {
00542                 dsl_prop_changed_notify(dp, za->za_first_integer,
00543                     propname, value, FALSE);
00544         }
00545         kmem_free(za, sizeof (zap_attribute_t));
00546         zap_cursor_fini(&zc);
00547         dsl_dir_close(dd, FTAG);
00548 }
00549 
00550 void
00551 dsl_prop_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
00552 {
00553         dsl_dataset_t *ds = arg1;
00554         dsl_prop_setarg_t *psa = arg2;
00555         objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
00556         uint64_t zapobj, intval, dummy;
00557         int isint;
00558         char valbuf[32];
00559         char *valstr = NULL;
00560         char *inheritstr;
00561         char *recvdstr;
00562         char *tbuf = NULL;
00563         int err;
00564         uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
00565         const char *propname = psa->psa_name;
00566         zprop_source_t source = psa->psa_source;
00567 
00568         isint = (dodefault(propname, 8, 1, &intval) == 0);
00569 
00570         if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
00571                 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
00572                 if (ds->ds_phys->ds_props_obj == 0) {
00573                         dmu_buf_will_dirty(ds->ds_dbuf, tx);
00574                         ds->ds_phys->ds_props_obj =
00575                             zap_create(mos,
00576                             DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
00577                 }
00578                 zapobj = ds->ds_phys->ds_props_obj;
00579         } else {
00580                 zapobj = ds->ds_dir->dd_phys->dd_props_zapobj;
00581         }
00582 
00583         if (version < SPA_VERSION_RECVD_PROPS) {
00584                 zfs_prop_t prop = zfs_name_to_prop(propname);
00585                 if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION)
00586                         return;
00587 
00588                 if (source & ZPROP_SRC_NONE)
00589                         source = ZPROP_SRC_NONE;
00590                 else if (source & ZPROP_SRC_RECEIVED)
00591                         source = ZPROP_SRC_LOCAL;
00592         }
00593 
00594         inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
00595         recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
00596 
00597         switch (source) {
00598         case ZPROP_SRC_NONE:
00599                 /*
00600                  * revert to received value, if any (inherit -S)
00601                  * - remove propname
00602                  * - remove propname$inherit
00603                  */
00604                 err = zap_remove(mos, zapobj, propname, tx);
00605                 ASSERT(err == 0 || err == ENOENT);
00606                 err = zap_remove(mos, zapobj, inheritstr, tx);
00607                 ASSERT(err == 0 || err == ENOENT);
00608                 break;
00609         case ZPROP_SRC_LOCAL:
00610                 /*
00611                  * remove propname$inherit
00612                  * set propname -> value
00613                  */
00614                 err = zap_remove(mos, zapobj, inheritstr, tx);
00615                 ASSERT(err == 0 || err == ENOENT);
00616                 VERIFY(0 == zap_update(mos, zapobj, propname,
00617                     psa->psa_intsz, psa->psa_numints, psa->psa_value, tx));
00618                 break;
00619         case ZPROP_SRC_INHERITED:
00620                 /*
00621                  * explicitly inherit
00622                  * - remove propname
00623                  * - set propname$inherit
00624                  */
00625                 err = zap_remove(mos, zapobj, propname, tx);
00626                 ASSERT(err == 0 || err == ENOENT);
00627                 if (version >= SPA_VERSION_RECVD_PROPS &&
00628                     dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy,
00629                     NULL) == 0) {
00630                         dummy = 0;
00631                         err = zap_update(mos, zapobj, inheritstr,
00632                             8, 1, &dummy, tx);
00633                         ASSERT(err == 0);
00634                 }
00635                 break;
00636         case ZPROP_SRC_RECEIVED:
00637                 /*
00638                  * set propname$recvd -> value
00639                  */
00640                 err = zap_update(mos, zapobj, recvdstr,
00641                     psa->psa_intsz, psa->psa_numints, psa->psa_value, tx);
00642                 ASSERT(err == 0);
00643                 break;
00644         case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
00645                 /*
00646                  * clear local and received settings
00647                  * - remove propname
00648                  * - remove propname$inherit
00649                  * - remove propname$recvd
00650                  */
00651                 err = zap_remove(mos, zapobj, propname, tx);
00652                 ASSERT(err == 0 || err == ENOENT);
00653                 err = zap_remove(mos, zapobj, inheritstr, tx);
00654                 ASSERT(err == 0 || err == ENOENT);
00655                 /* FALLTHRU */
00656         case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
00657                 /*
00658                  * remove propname$recvd
00659                  */
00660                 err = zap_remove(mos, zapobj, recvdstr, tx);
00661                 ASSERT(err == 0 || err == ENOENT);
00662                 break;
00663         default:
00664                 cmn_err(CE_PANIC, "unexpected property source: %d", source);
00665         }
00666 
00667         strfree(inheritstr);
00668         strfree(recvdstr);
00669 
00670         if (isint) {
00671                 VERIFY(0 == dsl_prop_get_ds(ds, propname, 8, 1, &intval, NULL));
00672 
00673                 if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
00674                         dsl_prop_cb_record_t *cbr;
00675                         /*
00676                          * It's a snapshot; nothing can inherit this
00677                          * property, so just look for callbacks on this
00678                          * ds here.
00679                          */
00680                         mutex_enter(&ds->ds_dir->dd_lock);
00681                         for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
00682                             cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
00683                                 if (cbr->cbr_ds == ds &&
00684                                     strcmp(cbr->cbr_propname, propname) == 0)
00685                                         cbr->cbr_func(cbr->cbr_arg, intval);
00686                         }
00687                         mutex_exit(&ds->ds_dir->dd_lock);
00688                 } else {
00689                         dsl_prop_changed_notify(ds->ds_dir->dd_pool,
00690                             ds->ds_dir->dd_object, propname, intval, TRUE);
00691                 }
00692 
00693                 (void) snprintf(valbuf, sizeof (valbuf),
00694                     "%lld", (longlong_t)intval);
00695                 valstr = valbuf;
00696         } else {
00697                 if (source == ZPROP_SRC_LOCAL) {
00698                         valstr = (char *)psa->psa_value;
00699                 } else {
00700                         tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
00701                         if (dsl_prop_get_ds(ds, propname, 1,
00702                             ZAP_MAXVALUELEN, tbuf, NULL) == 0)
00703                                 valstr = tbuf;
00704                 }
00705         }
00706 
00707         spa_history_log_internal((source == ZPROP_SRC_NONE ||
00708             source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT :
00709             LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx,
00710             "%s=%s dataset = %llu", propname,
00711             (valstr == NULL ? "" : valstr), ds->ds_object);
00712 
00713         if (tbuf != NULL)
00714                 kmem_free(tbuf, ZAP_MAXVALUELEN);
00715 }
00716 
00717 void
00718 dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
00719 {
00720         dsl_dataset_t *ds = arg1;
00721         dsl_props_arg_t *pa = arg2;
00722         nvlist_t *props = pa->pa_props;
00723         dsl_prop_setarg_t psa;
00724         nvpair_t *elem = NULL;
00725 
00726         psa.psa_source = pa->pa_source;
00727 
00728         while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
00729                 nvpair_t *pair = elem;
00730 
00731                 psa.psa_name = nvpair_name(pair);
00732 
00733                 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
00734                         /*
00735                          * dsl_prop_get_all_impl() returns properties in this
00736                          * format.
00737                          */
00738                         nvlist_t *attrs;
00739                         VERIFY(nvpair_value_nvlist(pair, &attrs) == 0);
00740                         VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
00741                             &pair) == 0);
00742                 }
00743 
00744                 if (nvpair_type(pair) == DATA_TYPE_STRING) {
00745                         VERIFY(nvpair_value_string(pair,
00746                             (char **)&psa.psa_value) == 0);
00747                         psa.psa_intsz = 1;
00748                         psa.psa_numints = strlen(psa.psa_value) + 1;
00749                 } else {
00750                         uint64_t intval;
00751                         VERIFY(nvpair_value_uint64(pair, &intval) == 0);
00752                         psa.psa_intsz = sizeof (intval);
00753                         psa.psa_numints = 1;
00754                         psa.psa_value = &intval;
00755                 }
00756                 dsl_prop_set_sync(ds, &psa, tx);
00757         }
00758 }
00759 
00760 void
00761 dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val,
00762     dmu_tx_t *tx)
00763 {
00764         objset_t *mos = dd->dd_pool->dp_meta_objset;
00765         uint64_t zapobj = dd->dd_phys->dd_props_zapobj;
00766 
00767         ASSERT(dmu_tx_is_syncing(tx));
00768 
00769         VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx));
00770 
00771         dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE);
00772 
00773         spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx,
00774             "%s=%llu dataset = %llu", name, (u_longlong_t)val,
00775             dd->dd_phys->dd_head_dataset_obj);
00776 }
00777 
00778 int
00779 dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source,
00780     int intsz, int numints, const void *buf)
00781 {
00782         dsl_dataset_t *ds;
00783         uint64_t version;
00784         int err;
00785         dsl_prop_setarg_t psa;
00786 
00787         /*
00788          * We must do these checks before we get to the syncfunc, since
00789          * it can't fail.
00790          */
00791         if (strlen(propname) >= ZAP_MAXNAMELEN)
00792                 return (ENAMETOOLONG);
00793 
00794         err = dsl_dataset_hold(dsname, FTAG, &ds);
00795         if (err)
00796                 return (err);
00797 
00798         version = spa_version(ds->ds_dir->dd_pool->dp_spa);
00799         if (intsz * numints >= (version < SPA_VERSION_STMF_PROP ?
00800             ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
00801                 dsl_dataset_rele(ds, FTAG);
00802                 return (E2BIG);
00803         }
00804         if (dsl_dataset_is_snapshot(ds) &&
00805             version < SPA_VERSION_SNAP_PROPS) {
00806                 dsl_dataset_rele(ds, FTAG);
00807                 return (ENOTSUP);
00808         }
00809 
00810         psa.psa_name = propname;
00811         psa.psa_source = source;
00812         psa.psa_intsz = intsz;
00813         psa.psa_numints = numints;
00814         psa.psa_value = buf;
00815         psa.psa_effective_value = -1ULL;
00816 
00817         err = dsl_sync_task_do(ds->ds_dir->dd_pool,
00818             NULL, dsl_prop_set_sync, ds, &psa, 2);
00819 
00820         dsl_dataset_rele(ds, FTAG);
00821         return (err);
00822 }
00823 
00824 int
00825 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
00826 {
00827         dsl_dataset_t *ds;
00828         uint64_t version;
00829         nvpair_t *elem = NULL;
00830         dsl_props_arg_t pa;
00831         int err;
00832 
00833         if (err = dsl_dataset_hold(dsname, FTAG, &ds))
00834                 return (err);
00835         /*
00836          * Do these checks before the syncfunc, since it can't fail.
00837          */
00838         version = spa_version(ds->ds_dir->dd_pool->dp_spa);
00839         while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
00840                 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
00841                         dsl_dataset_rele(ds, FTAG);
00842                         return (ENAMETOOLONG);
00843                 }
00844                 if (nvpair_type(elem) == DATA_TYPE_STRING) {
00845                         char *valstr;
00846                         VERIFY(nvpair_value_string(elem, &valstr) == 0);
00847                         if (strlen(valstr) >= (version <
00848                             SPA_VERSION_STMF_PROP ?
00849                             ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
00850                                 dsl_dataset_rele(ds, FTAG);
00851                                 return (E2BIG);
00852                         }
00853                 }
00854         }
00855 
00856         if (dsl_dataset_is_snapshot(ds) &&
00857             version < SPA_VERSION_SNAP_PROPS) {
00858                 dsl_dataset_rele(ds, FTAG);
00859                 return (ENOTSUP);
00860         }
00861 
00862         pa.pa_props = props;
00863         pa.pa_source = source;
00864 
00865         err = dsl_sync_task_do(ds->ds_dir->dd_pool,
00866             NULL, dsl_props_set_sync, ds, &pa, 2);
00867 
00868         dsl_dataset_rele(ds, FTAG);
00869         return (err);
00870 }
00871 
00872 typedef enum dsl_prop_getflags {
00873         DSL_PROP_GET_INHERITING = 0x1,  /* searching parent of target ds */
00874         DSL_PROP_GET_SNAPSHOT = 0x2,    /* snapshot dataset */
00875         DSL_PROP_GET_LOCAL = 0x4,       /* local properties */
00876         DSL_PROP_GET_RECEIVED = 0x8     /* received properties */
00877 } dsl_prop_getflags_t;
00878 
00879 static int
00880 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
00881     const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
00882 {
00883         zap_cursor_t zc;
00884         zap_attribute_t za;
00885         int err = 0;
00886 
00887         for (zap_cursor_init(&zc, mos, propobj);
00888             (err = zap_cursor_retrieve(&zc, &za)) == 0;
00889             zap_cursor_advance(&zc)) {
00890                 nvlist_t *propval;
00891                 zfs_prop_t prop;
00892                 char buf[ZAP_MAXNAMELEN];
00893                 char *valstr;
00894                 const char *suffix;
00895                 const char *propname;
00896                 const char *source;
00897 
00898                 suffix = strchr(za.za_name, '$');
00899 
00900                 if (suffix == NULL) {
00901                         /*
00902                          * Skip local properties if we only want received
00903                          * properties.
00904                          */
00905                         if (flags & DSL_PROP_GET_RECEIVED)
00906                                 continue;
00907 
00908                         propname = za.za_name;
00909                         source = setpoint;
00910                 } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
00911                         /* Skip explicitly inherited entries. */
00912                         continue;
00913                 } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
00914                         if (flags & DSL_PROP_GET_LOCAL)
00915                                 continue;
00916 
00917                         (void) strncpy(buf, za.za_name, (suffix - za.za_name));
00918                         buf[suffix - za.za_name] = '\0';
00919                         propname = buf;
00920 
00921                         if (!(flags & DSL_PROP_GET_RECEIVED)) {
00922                                 /* Skip if locally overridden. */
00923                                 err = zap_contains(mos, propobj, propname);
00924                                 if (err == 0)
00925                                         continue;
00926                                 if (err != ENOENT)
00927                                         break;
00928 
00929                                 /* Skip if explicitly inherited. */
00930                                 valstr = kmem_asprintf("%s%s", propname,
00931                                     ZPROP_INHERIT_SUFFIX);
00932                                 err = zap_contains(mos, propobj, valstr);
00933                                 strfree(valstr);
00934                                 if (err == 0)
00935                                         continue;
00936                                 if (err != ENOENT)
00937                                         break;
00938                         }
00939 
00940                         source = ((flags & DSL_PROP_GET_INHERITING) ?
00941                             setpoint : ZPROP_SOURCE_VAL_RECVD);
00942                 } else {
00943                         /*
00944                          * For backward compatibility, skip suffixes we don't
00945                          * recognize.
00946                          */
00947                         continue;
00948                 }
00949 
00950                 prop = zfs_name_to_prop(propname);
00951 
00952                 /* Skip non-inheritable properties. */
00953                 if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
00954                     !zfs_prop_inheritable(prop))
00955                         continue;
00956 
00957                 /* Skip properties not valid for this type. */
00958                 if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
00959                     !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
00960                         continue;
00961 
00962                 /* Skip properties already defined. */
00963                 if (nvlist_exists(nv, propname))
00964                         continue;
00965 
00966                 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
00967                 if (za.za_integer_length == 1) {
00968                         /*
00969                          * String property
00970                          */
00971                         char *tmp = kmem_alloc(za.za_num_integers,
00972                             KM_SLEEP);
00973                         err = zap_lookup(mos, propobj,
00974                             za.za_name, 1, za.za_num_integers, tmp);
00975                         if (err != 0) {
00976                                 kmem_free(tmp, za.za_num_integers);
00977                                 break;
00978                         }
00979                         VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
00980                             tmp) == 0);
00981                         kmem_free(tmp, za.za_num_integers);
00982                 } else {
00983                         /*
00984                          * Integer property
00985                          */
00986                         ASSERT(za.za_integer_length == 8);
00987                         (void) nvlist_add_uint64(propval, ZPROP_VALUE,
00988                             za.za_first_integer);
00989                 }
00990 
00991                 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
00992                 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
00993                 nvlist_free(propval);
00994         }
00995         zap_cursor_fini(&zc);
00996         if (err == ENOENT)
00997                 err = 0;
00998         return (err);
00999 }
01000 
01004 static int
01005 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
01006     dsl_prop_getflags_t flags)
01007 {
01008         dsl_dir_t *dd = ds->ds_dir;
01009         dsl_pool_t *dp = dd->dd_pool;
01010         objset_t *mos = dp->dp_meta_objset;
01011         int err = 0;
01012         char setpoint[MAXNAMELEN];
01013 
01014         VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
01015 
01016         if (dsl_dataset_is_snapshot(ds))
01017                 flags |= DSL_PROP_GET_SNAPSHOT;
01018 
01019         rw_enter(&dp->dp_config_rwlock, RW_READER);
01020 
01021         if (ds->ds_phys->ds_props_obj != 0) {
01022                 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
01023                 dsl_dataset_name(ds, setpoint);
01024                 err = dsl_prop_get_all_impl(mos, ds->ds_phys->ds_props_obj,
01025                     setpoint, flags, *nvp);
01026                 if (err)
01027                         goto out;
01028         }
01029 
01030         for (; dd != NULL; dd = dd->dd_parent) {
01031                 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
01032                         if (flags & (DSL_PROP_GET_LOCAL |
01033                             DSL_PROP_GET_RECEIVED))
01034                                 break;
01035                         flags |= DSL_PROP_GET_INHERITING;
01036                 }
01037                 dsl_dir_name(dd, setpoint);
01038                 err = dsl_prop_get_all_impl(mos, dd->dd_phys->dd_props_zapobj,
01039                     setpoint, flags, *nvp);
01040                 if (err)
01041                         break;
01042         }
01043 out:
01044         rw_exit(&dp->dp_config_rwlock);
01045         return (err);
01046 }
01047 
01048 boolean_t
01049 dsl_prop_get_hasrecvd(objset_t *os)
01050 {
01051         dsl_dataset_t *ds = os->os_dsl_dataset;
01052         int rc;
01053         uint64_t dummy;
01054 
01055         rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
01056         rc = dsl_prop_get_ds(ds, ZPROP_HAS_RECVD, 8, 1, &dummy, NULL);
01057         rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
01058         ASSERT(rc != 0 || spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
01059         return (rc == 0);
01060 }
01061 
01062 static void
01063 dsl_prop_set_hasrecvd_impl(objset_t *os, zprop_source_t source)
01064 {
01065         dsl_dataset_t *ds = os->os_dsl_dataset;
01066         uint64_t dummy = 0;
01067         dsl_prop_setarg_t psa;
01068 
01069         if (spa_version(os->os_spa) < SPA_VERSION_RECVD_PROPS)
01070                 return;
01071 
01072         dsl_prop_setarg_init_uint64(&psa, ZPROP_HAS_RECVD, source, &dummy);
01073 
01074         (void) dsl_sync_task_do(ds->ds_dir->dd_pool, NULL,
01075             dsl_prop_set_sync, ds, &psa, 2);
01076 }
01077 
01082 void
01083 dsl_prop_set_hasrecvd(objset_t *os)
01084 {
01085         if (dsl_prop_get_hasrecvd(os)) {
01086                 ASSERT(spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS);
01087                 return;
01088         }
01089         dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_LOCAL);
01090 }
01091 
01092 void
01093 dsl_prop_unset_hasrecvd(objset_t *os)
01094 {
01095         dsl_prop_set_hasrecvd_impl(os, ZPROP_SRC_NONE);
01096 }
01097 
01098 int
01099 dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
01100 {
01101         return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
01102 }
01103 
01104 int
01105 dsl_prop_get_received(objset_t *os, nvlist_t **nvp)
01106 {
01107         /*
01108          * Received properties are not distinguishable from local properties
01109          * until the dataset has received properties on or after
01110          * SPA_VERSION_RECVD_PROPS.
01111          */
01112         dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(os) ?
01113             DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
01114         return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags));
01115 }
01116 
01117 void
01118 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
01119 {
01120         nvlist_t *propval;
01121         const char *propname = zfs_prop_to_name(prop);
01122         uint64_t default_value;
01123 
01124         if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
01125                 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
01126                 return;
01127         }
01128 
01129         VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
01130         VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
01131         /* Indicate the default source if we can. */
01132         if (dodefault(propname, 8, 1, &default_value) == 0 &&
01133             value == default_value) {
01134                 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
01135         }
01136         VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
01137         nvlist_free(propval);
01138 }
01139 
01140 void
01141 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
01142 {
01143         nvlist_t *propval;
01144         const char *propname = zfs_prop_to_name(prop);
01145 
01146         if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
01147                 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
01148                 return;
01149         }
01150 
01151         VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
01152         VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
01153         VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
01154         nvlist_free(propval);
01155 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines