Print this page
NEX-16623 Ability to set properties for multiple datasets/snapshots during single sync-round
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-7822 40Gb Intel XL710 NIC performance data
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-8827 AUTOSNAP: can't register recursive zone when there is a child under autosnappool/volumegrou
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5987 need to change ssm wearout threshold to 90%
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5925 KRRP: Incorrect collecting of snap-props causes errors during recv
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alexey Komarov <alexey.komarov@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5795 Rename 'wrc' as 'wbc' in the source and in the tech docs
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-5341 Race condition causes wrc_004_pos to panic the system
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5319 Panic trying to rename zvol used as COMSTAR lu
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5060 WBC: Writecache and deduplication should not be used together
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4934 Add capability to remove special vdev
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-4830 writecache=off leaks data on special vdev (the data will never migrate)
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4608 WRC: Possible deadlock during the disabling of WRC for a dataset
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
6160 /usr/lib/fs/zfs/bootinstall should use bootadm
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
Reviewed by: Adam Števko <adam.stevko@gmail.com>
Reviewed by: Josef Sipek <jeffpc@josefsipek.net>
Approved by: Richard Lowe <richlowe@richlowe.net>
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R (NULL is not an int)
6171 dsl_prop_unregister() slows down dataset eviction.
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Approved by: Dan McDonald <danmcd@omniti.com>
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Revert "NEX-4476 WRC: Allow to use write back cache per tree of datasets"
This reverts commit fe97b74444278a6f36fec93179133641296312da.
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Remaining fixes for the illumos merge
re #12619 rb4429 More dp->dp_config_rwlock holds
re #13253 rb4328 ssh: openssl version checking needs updating
re #11441 rb4292 panic in apic_record_rdt_entry on VMware hardware version 9
re #12619, rb4287 Deadlocked zfs txg processing in dsl_sync_task_group_sync()
@@ -21,10 +21,11 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2013 Martin Matuska. All rights reserved.
* Copyright 2015, Joyent, Inc.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/zfs_context.h>
#include <sys/dmu.h>
#include <sys/dmu_objset.h>
@@ -31,19 +32,19 @@
#include <sys/dmu_tx.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_dir.h>
#include <sys/dsl_prop.h>
#include <sys/dsl_synctask.h>
+#include <sys/zfeature.h>
#include <sys/spa.h>
#include <sys/zap.h>
#include <sys/fs/zfs.h>
+#include <sys/wbc.h>
#include "zfs_prop.h"
+#include "zfs_errno.h"
-#define ZPROP_INHERIT_SUFFIX "$inherit"
-#define ZPROP_RECVD_SUFFIX "$recvd"
-
static int
dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
{
/*
* The setonce properties are read-only, BUT they still
@@ -285,11 +286,20 @@
dsl_prop_cb_record_t *cbr;
int err;
ASSERT(dsl_pool_config_held(dp));
+ if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
+ wbc_mode_prop_val_t val;
+
+ err = dsl_prop_get_ds(ds, propname, 8,
+ WBC_MODE_PROP_VAL_SZ, &val, NULL);
+ if (err == 0)
+ value = (uintptr_t)((void *)&val);
+ } else
err = dsl_prop_get_int_ds(ds, propname, &value);
+
if (err != 0)
return (err);
cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
cbr->cbr_ds = ds;
@@ -475,10 +485,11 @@
for (pr = list_head(&dd->dd_props);
pr; pr = list_next(&dd->dd_props, pr)) {
for (cbr = list_head(&pr->pr_cbs); cbr;
cbr = list_next(&pr->pr_cbs, cbr)) {
uint64_t value;
+ const char *propname;
/*
* Callback entries do not have holds on their
* datasets so that datasets with registered
* callbacks are still eligible for eviction.
@@ -502,14 +513,23 @@
*/
if (ds != cbr->cbr_ds &&
!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
continue;
- if (dsl_prop_get_ds(cbr->cbr_ds,
- cbr->cbr_pr->pr_propname, sizeof (value), 1,
- &value, NULL) == 0)
+ propname = cbr->cbr_pr->pr_propname;
+ if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
+ wbc_mode_prop_val_t val;
+
+ if (dsl_prop_get_ds(cbr->cbr_ds, propname, 8,
+ WBC_MODE_PROP_VAL_SZ, &val, NULL) == 0) {
+ value = (uintptr_t)((void *)&val);
cbr->cbr_func(cbr->cbr_arg, value);
+ }
+ } else if (dsl_prop_get_ds(cbr->cbr_ds, propname,
+ sizeof (value), 1, &value, NULL) == 0) {
+ cbr->cbr_func(cbr->cbr_arg, value);
+ }
if (ds != cbr->cbr_ds)
dsl_dataset_rele(cbr->cbr_ds, FTAG);
}
}
@@ -618,11 +638,12 @@
const char *valstr = NULL;
char *inheritstr;
char *recvdstr;
char *tbuf = NULL;
int err;
- uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
+ spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
+ uint64_t version = spa_version(spa);
isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
if (ds->ds_is_snapshot) {
ASSERT(version >= SPA_VERSION_SNAP_PROPS);
@@ -716,11 +737,51 @@
}
strfree(inheritstr);
strfree(recvdstr);
- if (isint) {
+ if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
+ wbc_mode_prop_val_t val;
+
+ VERIFY0(dsl_prop_get_ds(ds, propname, 8,
+ WBC_MODE_PROP_VAL_SZ, &val, NULL));
+
+ dsl_prop_changed_notify(ds->ds_dir->dd_pool,
+ ds->ds_dir->dd_object, propname,
+ (uintptr_t)((void *)&val), TRUE);
+
+ /*
+ * Flow diagram of ZFS_PROP_WBC_MODE states
+ *
+ * off (root_ds_object == 0, txg_off == 0)
+ * (user sees wbc_mode=off, source=default)
+ *
+ * user operation "set on" ==>>
+ *
+ * on (root_ds_object != 0, txg_off == 0)
+ * (user sees wbc_mode=on, source=local)
+ *
+ * user operation "set off" ==>>
+ *
+ * off_delayed (root_ds_object != 0, txg_off != 0)
+ * (user sees wbc_mode=off, source=local)
+ *
+ * internal operation "inherit" ==>>
+ *
+ * off (root_ds_object == 0, txg_off == 0)
+ * (user sees wbc_mode=off, source=default)
+ */
+ if (val.root_ds_object == 0)
+ spa_feature_decr(spa, SPA_FEATURE_WBC, tx);
+ else if (val.txg_off == 0)
+ spa_feature_incr(spa, SPA_FEATURE_WBC, tx);
+
+ (void) snprintf(valbuf, sizeof (valbuf),
+ "%s", (val.root_ds_object != 0 &&
+ val.txg_off == 0) ? "on" : "off");
+ valstr = valbuf;
+ } else if (isint) {
VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
if (ds->ds_is_snapshot) {
dsl_prop_cb_record_t *cbr;
/*
@@ -800,10 +861,79 @@
error = dsl_props_set(dsname, source, nvl);
fnvlist_free(nvl);
return (error);
}
+/* ARGSUSED */
+static int
+dsl_prop_wbc_mode_check_child_cb(dsl_pool_t *dp,
+ dsl_dataset_t *ds, void *arg)
+{
+ int err;
+ zfs_prop_t *prop = arg;
+ objset_t *os = NULL;
+
+ err = dmu_objset_from_ds(ds, &os);
+ if (err != 0)
+ return (err);
+
+ if (*prop == ZFS_PROP_DEDUP) {
+ /*
+ * User tries to set ZFS_PROP_DEDUP.
+ * In this case we just check that
+ * the target DS and its children
+ * do not use writecache
+ */
+ if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
+ return (SET_ERROR(EKZFS_WBCCONFLICT));
+ } else {
+ ASSERT3U(*prop, ==, ZFS_PROP_WBC_MODE);
+
+ /*
+ * User tries to set ZFS_PROP_WBC_MODE.
+ * In this case we need check that
+ * the target DS and its children
+ * do not use writecache and dedup
+ */
+ if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
+ return (SET_ERROR(EKZFS_WBCCHILD));
+
+ if (os->os_dedup_checksum != ZIO_CHECKSUM_OFF)
+ return (SET_ERROR(EKZFS_WBCCONFLICT));
+ }
+
+ return (0);
+}
+
+static int
+dsl_prop_wbc_mode_check(dsl_dataset_t *ds, objset_t *os)
+{
+ int err = 0;
+ zfs_prop_t prop = ZFS_PROP_WBC_MODE;
+
+ if (os->os_wbc_mode != ZFS_WBC_MODE_OFF) {
+ /*
+ * ZFS_PROP_WBC_MODE cannot be set for
+ * a child DS if the prop was set for
+ * the parent
+ */
+ if (os->os_wbc_root_ds_obj != ds->ds_object)
+ return (SET_ERROR(EKZFS_WBCPARENT));
+ } else {
+ /*
+ * Is not allowed to change wbc_mode for parent
+ * if its children already have the changed prop
+ */
+ err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
+ ds->ds_dir->dd_object,
+ dsl_prop_wbc_mode_check_child_cb, &prop,
+ DS_FIND_CHILDREN);
+ }
+
+ return (err);
+}
+
typedef struct dsl_props_set_arg {
const char *dpsa_dsname;
zprop_source_t dpsa_source;
nvlist_t *dpsa_props;
} dsl_props_set_arg_t;
@@ -812,33 +942,120 @@
dsl_props_set_check(void *arg, dmu_tx_t *tx)
{
dsl_props_set_arg_t *dpsa = arg;
dsl_pool_t *dp = dmu_tx_pool(tx);
dsl_dataset_t *ds;
+ objset_t *os = NULL;
uint64_t version;
nvpair_t *elem = NULL;
int err;
err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
if (err != 0)
return (err);
+ err = dmu_objset_from_ds(ds, &os);
+ if (err != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (err);
+ }
+
version = spa_version(ds->ds_dir->dd_pool->dp_spa);
while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
- if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
+ const char *prop_name = nvpair_name(elem);
+ zfs_prop_t prop = zfs_name_to_prop(prop_name);
+
+ if (strlen(prop_name) >= ZAP_MAXNAMELEN) {
dsl_dataset_rele(ds, FTAG);
return (SET_ERROR(ENAMETOOLONG));
}
+
+ /*
+ * Deduplication and WBC cannot be used together
+ * This code returns error also for case when
+ * WBC is ON, DEDUP is off and a user tries
+ * to do DEDUP=off, because in this case the code
+ * will be more complex, but benefit is too small
+ */
+ if (prop == ZFS_PROP_DEDUP) {
+ if (os->os_wbc_root_ds_obj != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EKZFS_WBCCONFLICT));
+ }
+
+ /*
+ * Need to be sure that children DS
+ * do not use writecache
+ */
+ err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
+ ds->ds_dir->dd_object,
+ dsl_prop_wbc_mode_check_child_cb, &prop,
+ DS_FIND_CHILDREN);
+ if (err != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (err);
+ }
+ }
+
+ if (prop == ZFS_PROP_WBC_MODE) {
+ uint64_t wbc_mode_new = 0;
+ data_type_t elem_type = nvpair_type(elem);
+
+ if (elem_type == DATA_TYPE_UINT64)
+ wbc_mode_new = fnvpair_value_uint64(elem);
+
+ if (os->os_wbc_root_ds_obj == ds->ds_object &&
+ elem_type == DATA_TYPE_UINT64) {
+
+ /*
+ * ZFS_WBC_MODE_OFF_DELAYED means that
+ * the coresponding wbc_instance is in
+ * transition state: from ON to OFF
+ * so ON/OFF is not permitted
+ */
+ if (os->os_wbc_mode ==
+ ZFS_WBC_MODE_OFF_DELAYED) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINPROGRESS));
+ }
+
+ ASSERT3U(os->os_wbc_mode, ==, ZFS_WBC_MODE_ON);
+
+ /* Check for double ON */
+ if (wbc_mode_new == ZFS_WBC_MODE_ON) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EALREADY));
+ }
+ }
+
+ err = dsl_prop_wbc_mode_check(ds, os);
+ if (err != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (err);
+ }
+
+ /* Check for double OFF */
+ if (os->os_wbc_root_ds_obj == 0 &&
+ elem_type == DATA_TYPE_UINT64 &&
+ wbc_mode_new == ZFS_WBC_MODE_OFF) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EALREADY));
+ }
+
+ continue;
+ }
+
if (nvpair_type(elem) == DATA_TYPE_STRING) {
char *valstr = fnvpair_value_string(elem);
if (strlen(valstr) >= (version <
SPA_VERSION_STMF_PROP ?
ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
dsl_dataset_rele(ds, FTAG);
- return (E2BIG);
+ return (SET_ERROR(E2BIG));
}
}
+
}
if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
dsl_dataset_rele(ds, FTAG);
return (SET_ERROR(ENOTSUP));
@@ -853,34 +1070,56 @@
{
nvpair_t *elem = NULL;
while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
nvpair_t *pair = elem;
- const char *name = nvpair_name(pair);
if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
/*
- * This usually happens when we reuse the nvlist_t data
- * returned by the counterpart dsl_prop_get_all_impl().
- * For instance we do this to restore the original
- * received properties when an error occurs in the
- * zfs_ioc_recv() codepath.
+ * dsl_prop_get_all_impl() returns properties in this
+ * format.
*/
nvlist_t *attrs = fnvpair_value_nvlist(pair);
pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
}
if (nvpair_type(pair) == DATA_TYPE_STRING) {
const char *value = fnvpair_value_string(pair);
- dsl_prop_set_sync_impl(ds, name,
+ dsl_prop_set_sync_impl(ds, nvpair_name(pair),
source, 1, strlen(value) + 1, value, tx);
} else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
+ const char *propname = nvpair_name(pair);
+ zfs_prop_t prop = zfs_name_to_prop(propname);
uint64_t intval = fnvpair_value_uint64(pair);
- dsl_prop_set_sync_impl(ds, name,
+
+ if (prop == ZFS_PROP_WBC_MODE) {
+ wbc_mode_prop_val_t val;
+
+ /*
+ * Disabling WBC involves the following:
+ * 1) all the subsequent data writes will
+ * stop using special vdev
+ * 2) already WriteBackCached data blocks
+ * (with TXG <= txg_off below) will gradually
+ * migrated from special vdev
+ *
+ * To handle this need to remember TXG.
+ * WBC will be completely disabled for this DS,
+ * after WBC-window cross this TXG
+ */
+ val.txg_off = (intval == 0) ? tx->tx_txg : 0;
+ val.root_ds_object = ds->ds_object;
+ val.flags = 0;
+
+ dsl_prop_set_sync_impl(ds, nvpair_name(pair),
+ source, 8, WBC_MODE_PROP_VAL_SZ, &val, tx);
+ } else {
+ dsl_prop_set_sync_impl(ds, nvpair_name(pair),
source, sizeof (intval), 1, &intval, tx);
+ }
} else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
- dsl_prop_set_sync_impl(ds, name,
+ dsl_prop_set_sync_impl(ds, nvpair_name(pair),
source, 0, 0, NULL, tx);
} else {
panic("invalid nvpair type");
}
}
@@ -890,12 +1129,23 @@
dsl_props_set_sync(void *arg, dmu_tx_t *tx)
{
dsl_props_set_arg_t *dpsa = arg;
dsl_pool_t *dp = dmu_tx_pool(tx);
dsl_dataset_t *ds;
+ objset_t *os = NULL;
VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
+ /*
+ * Need to initialize os, to be sure that non-mounted datasets and
+ * non-exposed zvols will receive notification about modified
+ * properties.
+ * During the initialization a property can register its callback
+ * that will be called if the property is changed.
+ * dsl_props_set_sync_impl() calls dsl_prop_changed_notify()
+ * that calls the required callback if it exists.
+ */
+ VERIFY0(dmu_objset_from_ds(ds, &os));
dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
dsl_dataset_rele(ds, FTAG);
}
/*
@@ -920,10 +1170,97 @@
return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
&dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
}
+static void
+dsl_props_mds_set_sync(void *arg, dmu_tx_t *tx)
+{
+ dsl_props_set_arg_t *top_dpsa = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ nvlist_t *dss_props = top_dpsa->dpsa_props;
+ nvpair_t *pair = NULL;
+
+ while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
+ dsl_props_set_arg_t dpsa;
+ dsl_dataset_t *ds = NULL;
+ const char *ds_name;
+
+ ds_name = nvpair_name(pair);
+ VERIFY0(dsl_dataset_hold(dp, ds_name, FTAG, &ds));
+
+ dpsa.dpsa_dsname = ds_name;
+ dpsa.dpsa_source = ZPROP_SRC_LOCAL;
+ dpsa.dpsa_props = fnvpair_value_nvlist(pair);
+
+ dsl_props_set_sync(&dpsa, tx);
+ dsl_dataset_rele(ds, FTAG);
+ }
+}
+
+static int
+dsl_props_mds_set_check(void *arg, dmu_tx_t *tx)
+{
+ dsl_props_set_arg_t *top_dpsa = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ nvlist_t *dss_props = top_dpsa->dpsa_props;
+ nvpair_t *pair = NULL;
+
+ while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
+ dsl_props_set_arg_t dpsa;
+ dsl_dataset_t *ds = NULL;
+ const char *ds_name;
+ int err;
+
+ ds_name = nvpair_name(pair);
+ err = dsl_dataset_hold(dp, ds_name, FTAG, &ds);
+ if (err != 0)
+ return (err);
+
+ if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+
+ dpsa.dpsa_dsname = ds_name;
+ dpsa.dpsa_source = ZPROP_SRC_LOCAL;
+ dpsa.dpsa_props = fnvpair_value_nvlist(pair);
+
+ err = dsl_props_set_check(&dpsa, tx);
+ dsl_dataset_rele(ds, FTAG);
+ if (err != 0)
+ return (err);
+ }
+
+ return (0);
+}
+
+
+/*
+ * The given 'dss_props' nvlist represents the following struct:
+ * ds1 -> prop1:value
+ * -> prop3:value
+ * ds2 -> prop1:value
+ * -> prop2:value
+ *
+ * All-or-nothing: if any prop can't be set, nothing will be modified.
+ */
+int
+dsl_props_set_mds(const char *pool_name, nvlist_t *dss_props,
+ size_t num_props)
+{
+ dsl_props_set_arg_t dpsa;
+
+ dpsa.dpsa_dsname = pool_name;
+ dpsa.dpsa_source = ZPROP_SRC_LOCAL;
+ dpsa.dpsa_props = dss_props;
+
+ return (dsl_sync_task(pool_name, dsl_props_mds_set_check,
+ dsl_props_mds_set_sync, &dpsa, 2 * num_props,
+ ZFS_SPACE_CHECK_RESERVED));
+}
+
typedef enum dsl_prop_getflags {
DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */
DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */
DSL_PROP_GET_LOCAL = 0x4, /* local properties */
DSL_PROP_GET_RECEIVED = 0x8 /* received properties */
@@ -1027,18 +1364,38 @@
za.za_name, 1, za.za_num_integers, tmp);
if (err != 0) {
kmem_free(tmp, za.za_num_integers);
break;
}
+
VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
tmp) == 0);
kmem_free(tmp, za.za_num_integers);
} else {
/*
* Integer property
*/
ASSERT(za.za_integer_length == 8);
+
+ if (prop == ZFS_PROP_WBC_MODE) {
+ wbc_mode_prop_val_t val;
+
+ ASSERT(za.za_num_integers ==
+ WBC_MODE_PROP_VAL_SZ);
+
+ err = zap_lookup(mos, propobj,
+ za.za_name, 8, za.za_num_integers, &val);
+ if (err != 0)
+ break;
+
+ if (val.root_ds_object != 0 &&
+ val.txg_off == 0)
+ za.za_first_integer = ZFS_WBC_MODE_ON;
+ else
+ za.za_first_integer = ZFS_WBC_MODE_OFF;
+ }
+
(void) nvlist_add_uint64(propval, ZPROP_VALUE,
za.za_first_integer);
}
VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);