MFV r258374:

4171 clean up spa_feature_*() interfaces

4172 implement extensible_dataset feature for use by other zpool
features

illumos/illumos-gate@2acef22db7

MFC after:	2 weeks
This commit is contained in:
Xin LI 2013-12-24 07:14:25 +00:00
commit 1aaa945f67
28 changed files with 366 additions and 284 deletions

View File

@ -559,16 +559,20 @@ get_metaslab_refcount(vdev_t *vd)
static int
verify_spacemap_refcounts(spa_t *spa)
{
int expected_refcount, actual_refcount;
uint64_t expected_refcount = 0;
uint64_t actual_refcount;
expected_refcount = spa_feature_get_refcount(spa,
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM]);
(void) feature_get_refcount(spa,
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM],
&expected_refcount);
actual_refcount = get_dtl_refcount(spa->spa_root_vdev);
actual_refcount += get_metaslab_refcount(spa->spa_root_vdev);
if (expected_refcount != actual_refcount) {
(void) printf("space map refcount mismatch: expected %d != "
"actual %d\n", expected_refcount, actual_refcount);
(void) printf("space map refcount mismatch: expected %lld != "
"actual %lld\n",
(longlong_t)expected_refcount,
(longlong_t)actual_refcount);
return (2);
}
return (0);
@ -670,8 +674,7 @@ dump_metaslab(metaslab_t *msp)
}
if (dump_opt['m'] > 1 && sm != NULL &&
spa_feature_is_active(spa,
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM])) {
spa_feature_is_active(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
/*
* The space map histogram represents free space in chunks
* of sm_shift (i.e. bucket 0 refers to 2^sm_shift).
@ -2417,8 +2420,7 @@ dump_block_stats(spa_t *spa)
(void) bpobj_iterate_nofree(&spa->spa_dsl_pool->dp_free_bpobj,
count_block_cb, &zcb, NULL);
}
if (spa_feature_is_active(spa,
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
if (spa_feature_is_active(spa, SPA_FEATURE_ASYNC_DESTROY)) {
VERIFY3U(0, ==, bptree_iterate(spa->spa_meta_objset,
spa->spa_dsl_pool->dp_bptree_obj, B_FALSE, count_block_cb,
&zcb, NULL));
@ -2719,7 +2721,7 @@ dump_zpool(spa_t *spa)
}
if (spa_feature_is_active(spa,
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
SPA_FEATURE_ASYNC_DESTROY)) {
dump_bptree(spa->spa_meta_objset,
spa->spa_dsl_pool->dp_bptree_obj,
"Pool dataset frees");

View File

@ -283,12 +283,13 @@ zhack_do_feature_stat(int argc, char **argv)
}
static void
feature_enable_sync(void *arg, dmu_tx_t *tx)
zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
spa_feature_enable(spa, feature, tx);
feature_enable_sync(spa, feature, tx);
spa_history_log_internal(spa, "zhack enable feature", tx,
"name=%s can_readonly=%u",
feature->fi_guid, feature->fi_can_readonly);
@ -302,7 +303,7 @@ zhack_do_feature_enable(int argc, char **argv)
spa_t *spa;
objset_t *mos;
zfeature_info_t feature;
zfeature_info_t *nodeps[] = { NULL };
spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
/*
* Features are not added to the pool's label until their refcounts
@ -349,14 +350,14 @@ zhack_do_feature_enable(int argc, char **argv)
zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset;
if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
if (zfeature_is_supported(feature.fi_guid))
fatal(spa, FTAG, "'%s' is a real feature, will not enable");
if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
fatal(spa, FTAG, "feature already enabled: %s",
feature.fi_guid);
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
feature_enable_sync, &feature, 5));
zhack_feature_enable_sync, &feature, 5));
spa_close(spa, FTAG);
@ -368,8 +369,10 @@ feature_incr_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
uint64_t refcount;
spa_feature_incr(spa, feature, tx);
VERIFY0(feature_get_refcount(spa, feature, &refcount));
feature_sync(spa, feature, refcount + 1, tx);
spa_history_log_internal(spa, "zhack feature incr", tx,
"name=%s", feature->fi_guid);
}
@ -379,8 +382,10 @@ feature_decr_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
uint64_t refcount;
spa_feature_decr(spa, feature, tx);
VERIFY0(feature_get_refcount(spa, feature, &refcount));
feature_sync(spa, feature, refcount - 1, tx);
spa_history_log_internal(spa, "zhack feature decr", tx,
"name=%s", feature->fi_guid);
}
@ -394,7 +399,7 @@ zhack_do_feature_ref(int argc, char **argv)
spa_t *spa;
objset_t *mos;
zfeature_info_t feature;
zfeature_info_t *nodeps[] = { NULL };
spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
/*
* fi_desc does not matter here because it was written to disk
@ -437,9 +442,10 @@ zhack_do_feature_ref(int argc, char **argv)
zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset;
if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
fatal(spa, FTAG, "'%s' is a real feature, will not change "
"refcount");
if (zfeature_is_supported(feature.fi_guid)) {
fatal(spa, FTAG,
"'%s' is a real feature, will not change refcount");
}
if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
feature.fi_guid)) {
@ -451,9 +457,14 @@ zhack_do_feature_ref(int argc, char **argv)
fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
}
if (decr && !spa_feature_is_active(spa, &feature))
fatal(spa, FTAG, "feature refcount already 0: %s",
feature.fi_guid);
if (decr) {
uint64_t count;
if (feature_get_refcount(spa, &feature, &count) == 0 &&
count != 0) {
fatal(spa, FTAG, "feature refcount already 0: %s",
feature.fi_guid);
}
}
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
decr ? feature_decr_sync : feature_incr_sync, &feature, 5));

View File

@ -270,6 +270,23 @@ Once the feature is
.Sy active ,
it will remain in that state until the pool is destroyed.
.El
.It Sy extensible_dataset
.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:extensible_dataset"
.It GUID Ta com.delphix:extensible_dataset
.It READ\-ONLY COMPATIBLE Ta no
.It DEPENDENCIES Ta none
.El
.Pp
This feature allows more flexible use of internal ZFS data structures,
and exists for other features to depend on.
.Pp
This feature will be
.Sy active
when the first dependent feature uses it,
and will be returned to the
.Sy enabled
state when all datasets that use
this feature are destroyed.
.Sh SEE ALSO
.Xr zpool 8
.Sh AUTHORS

View File

@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
@ -1004,7 +1004,7 @@ zpool_do_create(int argc, char **argv)
* Hand off to libzfs.
*/
if (enable_all_pool_feat) {
int i;
spa_feature_t i;
for (i = 0; i < SPA_FEATURES; i++) {
char propname[MAXPATHLEN];
zfeature_info_t *feat = &spa_feature_table[i];

View File

@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@ -443,10 +443,9 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
prop = zpool_name_to_prop(propname);
if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
int err;
zfeature_info_t *feature;
char *fname = strchr(propname, '@') + 1;
err = zfeature_lookup_name(fname, &feature);
err = zfeature_lookup_name(fname, NULL);
if (err != 0) {
ASSERT3U(err, ==, ENOENT);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@ -839,14 +838,14 @@ zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
*/
if (supported) {
int ret;
zfeature_info_t *fi;
spa_feature_t fid;
ret = zfeature_lookup_name(feature, &fi);
ret = zfeature_lookup_name(feature, &fid);
if (ret != 0) {
(void) strlcpy(buf, "-", len);
return (ENOTSUP);
}
feature = fi->fi_guid;
feature = spa_feature_table[fid].fi_guid;
}
if (nvlist_lookup_uint64(features, feature, &refcount) == 0)

View File

@ -91,32 +91,22 @@ zfeature_is_supported(const char *guid)
if (zfeature_checks_disable)
return (B_TRUE);
return (0 == zfeature_lookup_guid(guid, NULL));
}
int
zfeature_lookup_guid(const char *guid, zfeature_info_t **res)
{
for (int i = 0; i < SPA_FEATURES; i++) {
for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
zfeature_info_t *feature = &spa_feature_table[i];
if (strcmp(guid, feature->fi_guid) == 0) {
if (res != NULL)
*res = feature;
return (0);
}
if (strcmp(guid, feature->fi_guid) == 0)
return (B_TRUE);
}
return (ENOENT);
return (B_FALSE);
}
int
zfeature_lookup_name(const char *name, zfeature_info_t **res)
zfeature_lookup_name(const char *name, spa_feature_t *res)
{
for (int i = 0; i < SPA_FEATURES; i++) {
for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
zfeature_info_t *feature = &spa_feature_table[i];
if (strcmp(name, feature->fi_uname) == 0) {
if (res != NULL)
*res = feature;
*res = i;
return (0);
}
}
@ -125,11 +115,12 @@ zfeature_lookup_name(const char *name, zfeature_info_t **res)
}
static void
zfeature_register(int fid, const char *guid, const char *name, const char *desc,
boolean_t readonly, boolean_t mos, zfeature_info_t **deps)
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
const char *desc, boolean_t readonly, boolean_t mos,
const spa_feature_t *deps)
{
zfeature_info_t *feature = &spa_feature_table[fid];
static zfeature_info_t *nodeps[] = { NULL };
static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
ASSERT(name != NULL);
ASSERT(desc != NULL);
@ -140,6 +131,7 @@ zfeature_register(int fid, const char *guid, const char *name, const char *desc,
if (deps == NULL)
deps = nodeps;
feature->fi_feature = fid;
feature->fi_guid = guid;
feature->fi_uname = name;
feature->fi_desc = desc;
@ -166,4 +158,8 @@ zpool_feature_init(void)
zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
"com.delphix:spacemap_histogram", "spacemap_histogram",
"Spacemaps maintain space histograms.", B_TRUE, B_FALSE, NULL);
zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
"com.delphix:extensible_dataset", "extensible_dataset",
"Enhanced dataset functionality, used by other features.",
B_FALSE, B_FALSE, NULL);
}

View File

@ -37,35 +37,38 @@ extern "C" {
struct zfeature_info;
typedef enum spa_feature {
SPA_FEATURE_NONE = -1,
SPA_FEATURE_ASYNC_DESTROY,
SPA_FEATURE_EMPTY_BPOBJ,
SPA_FEATURE_LZ4_COMPRESS,
SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
SPA_FEATURE_SPACEMAP_HISTOGRAM,
SPA_FEATURE_EXTENSIBLE_DATASET,
SPA_FEATURES
} spa_feature_t;
typedef struct zfeature_info {
spa_feature_t fi_feature;
const char *fi_uname; /* User-facing feature name */
const char *fi_guid; /* On-disk feature identifier */
const char *fi_desc; /* Feature description */
boolean_t fi_can_readonly; /* Can open pool readonly w/o support? */
boolean_t fi_mos; /* Is the feature necessary to read the MOS? */
struct zfeature_info **fi_depends; /* array; null terminated */
/* array of dependencies, terminated by SPA_FEATURE_NONE */
const spa_feature_t *fi_depends;
} zfeature_info_t;
typedef int (zfeature_func_t)(zfeature_info_t *fi, void *arg);
#define ZFS_FEATURE_DEBUG
static enum spa_feature {
SPA_FEATURE_ASYNC_DESTROY,
SPA_FEATURE_EMPTY_BPOBJ,
SPA_FEATURE_LZ4_COMPRESS,
SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
SPA_FEATURE_SPACEMAP_HISTOGRAM,
SPA_FEATURES
} spa_feature_t;
extern zfeature_info_t spa_feature_table[SPA_FEATURES];
extern boolean_t zfeature_is_valid_guid(const char *);
extern boolean_t zfeature_is_supported(const char *);
extern int zfeature_lookup_guid(const char *, zfeature_info_t **res);
extern int zfeature_lookup_name(const char *, zfeature_info_t **res);
extern int zfeature_lookup_name(const char *name, spa_feature_t *res);
extern void zpool_feature_init(void);

View File

@ -36,13 +36,11 @@
uint64_t
bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx)
{
zfeature_info_t *empty_bpobj_feat =
&spa_feature_table[SPA_FEATURE_EMPTY_BPOBJ];
spa_t *spa = dmu_objset_spa(os);
dsl_pool_t *dp = dmu_objset_pool(os);
if (spa_feature_is_enabled(spa, empty_bpobj_feat)) {
if (!spa_feature_is_active(spa, empty_bpobj_feat)) {
if (spa_feature_is_enabled(spa, SPA_FEATURE_EMPTY_BPOBJ)) {
if (!spa_feature_is_active(spa, SPA_FEATURE_EMPTY_BPOBJ)) {
ASSERT0(dp->dp_empty_bpobj);
dp->dp_empty_bpobj =
bpobj_alloc(os, SPA_MAXBLOCKSIZE, tx);
@ -51,7 +49,7 @@ bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx)
DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
&dp->dp_empty_bpobj, tx) == 0);
}
spa_feature_incr(spa, empty_bpobj_feat, tx);
spa_feature_incr(spa, SPA_FEATURE_EMPTY_BPOBJ, tx);
ASSERT(dp->dp_empty_bpobj != 0);
return (dp->dp_empty_bpobj);
} else {
@ -62,12 +60,11 @@ bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx)
void
bpobj_decr_empty(objset_t *os, dmu_tx_t *tx)
{
zfeature_info_t *empty_bpobj_feat =
&spa_feature_table[SPA_FEATURE_EMPTY_BPOBJ];
dsl_pool_t *dp = dmu_objset_pool(os);
spa_feature_decr(dmu_objset_spa(os), empty_bpobj_feat, tx);
if (!spa_feature_is_active(dmu_objset_spa(os), empty_bpobj_feat)) {
spa_feature_decr(dmu_objset_spa(os), SPA_FEATURE_EMPTY_BPOBJ, tx);
if (!spa_feature_is_active(dmu_objset_spa(os),
SPA_FEATURE_EMPTY_BPOBJ)) {
VERIFY3U(0, ==, zap_remove(dp->dp_meta_objset,
DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_EMPTY_BPOBJ, tx));
@ -265,6 +262,7 @@ bpobj_iterate_impl(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx,
mutex_exit(&bpo->bpo_lock);
return (err);
}
ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ_SUBOBJ);
epb = doi.doi_data_block_size / sizeof (uint64_t);
for (i = bpo->bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) {

View File

@ -27,6 +27,8 @@
#include <sys/dmu_objset.h>
#include <sys/dmu_tx.h>
#include <sys/dnode.h>
#include <sys/zap.h>
#include <sys/zfeature.h>
uint64_t
dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
@ -195,3 +197,54 @@ dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
return (error);
}
/*
* Turn this object from old_type into DMU_OTN_ZAP_METADATA, and bump the
* refcount on SPA_FEATURE_EXTENSIBLE_DATASET.
*
* Only for use from syncing context, on MOS objects.
*/
void
dmu_object_zapify(objset_t *mos, uint64_t object, dmu_object_type_t old_type,
dmu_tx_t *tx)
{
dnode_t *dn;
ASSERT(dmu_tx_is_syncing(tx));
VERIFY0(dnode_hold(mos, object, FTAG, &dn));
if (dn->dn_type == DMU_OTN_ZAP_METADATA) {
dnode_rele(dn, FTAG);
return;
}
ASSERT3U(dn->dn_type, ==, old_type);
ASSERT0(dn->dn_maxblkid);
dn->dn_next_type[tx->tx_txg & TXG_MASK] = dn->dn_type =
DMU_OTN_ZAP_METADATA;
dnode_setdirty(dn, tx);
dnode_rele(dn, FTAG);
mzap_create_impl(mos, object, 0, 0, tx);
spa_feature_incr(dmu_objset_spa(mos),
SPA_FEATURE_EXTENSIBLE_DATASET, tx);
}
void
dmu_object_free_zapified(objset_t *mos, uint64_t object, dmu_tx_t *tx)
{
dnode_t *dn;
dmu_object_type_t t;
ASSERT(dmu_tx_is_syncing(tx));
VERIFY0(dnode_hold(mos, object, FTAG, &dn));
t = dn->dn_type;
dnode_rele(dn, FTAG);
if (t == DMU_OTN_ZAP_METADATA) {
spa_feature_decr(dmu_objset_spa(mos),
SPA_FEATURE_EXTENSIBLE_DATASET, tx);
}
VERIFY0(dmu_object_free(mos, object, tx));
}

View File

@ -605,7 +605,7 @@ traverse_pool(spa_t *spa, uint64_t txg_start, int flags,
continue;
}
if (doi.doi_type == DMU_OT_DSL_DATASET) {
if (doi.doi_bonus_type == DMU_OT_DSL_DATASET) {
dsl_dataset_t *ds;
uint64_t txg = txg_start;

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#include <sys/zfs_context.h>
@ -577,7 +577,12 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
BP_GET_LSIZE(&dnp->dn_blkptr[0]) ==
dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
if (dn->dn_next_blksz[txgoff]) {
if (dn->dn_next_type[txgoff] != 0) {
dnp->dn_type = dn->dn_type;
dn->dn_next_type[txgoff] = 0;
}
if (dn->dn_next_blksz[txgoff] != 0) {
ASSERT(P2PHASE(dn->dn_next_blksz[txgoff],
SPA_MINBLOCKSIZE) == 0);
ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[0]) ||
@ -590,7 +595,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dn->dn_next_blksz[txgoff] = 0;
}
if (dn->dn_next_bonuslen[txgoff]) {
if (dn->dn_next_bonuslen[txgoff] != 0) {
if (dn->dn_next_bonuslen[txgoff] == DN_ZERO_BONUSLEN)
dnp->dn_bonuslen = 0;
else
@ -599,7 +604,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dn->dn_next_bonuslen[txgoff] = 0;
}
if (dn->dn_next_bonustype[txgoff]) {
if (dn->dn_next_bonustype[txgoff] != 0) {
ASSERT(DMU_OT_IS_VALID(dn->dn_next_bonustype[txgoff]));
dnp->dn_bonustype = dn->dn_next_bonustype[txgoff];
dn->dn_next_bonustype[txgoff] = 0;
@ -617,7 +622,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dn->dn_rm_spillblk[txgoff] = 0;
}
if (dn->dn_next_indblkshift[txgoff]) {
if (dn->dn_next_indblkshift[txgoff] != 0) {
ASSERT(dnp->dn_nlevels == 1);
dnp->dn_indblkshift = dn->dn_next_indblkshift[txgoff];
dn->dn_next_indblkshift[txgoff] = 0;

View File

@ -357,7 +357,7 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
/* Make sure dsobj has the correct object type. */
dmu_object_info_from_db(dbuf, &doi);
if (doi.doi_type != DMU_OT_DSL_DATASET) {
if (doi.doi_bonus_type != DMU_OT_DSL_DATASET) {
dmu_buf_rele(dbuf, tag);
return (SET_ERROR(EINVAL));
}
@ -3052,3 +3052,11 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
dsl_dataset_rele(origin, FTAG);
return (ret);
}
void
dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
{
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
dmu_object_zapify(mos, ds->ds_object, DMU_OT_DSL_DATASET, tx);
}

View File

@ -38,6 +38,7 @@
#include <sys/zfeature.h>
#include <sys/zfs_ioctl.h>
#include <sys/dsl_deleg.h>
#include <sys/dmu_impl.h>
typedef struct dmu_snapshots_destroy_arg {
nvlist_t *dsda_snaps;
@ -448,7 +449,7 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
VERIFY0(zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx));
dsl_dir_rele(ds->ds_dir, ds);
ds->ds_dir = NULL;
VERIFY0(dmu_object_free(mos, obj, tx));
dmu_object_free_zapified(mos, obj, tx);
}
static void
@ -671,7 +672,7 @@ dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx)
dd->dd_parent->dd_phys->dd_child_dir_zapobj, dd->dd_myname, tx));
dsl_dir_rele(dd, FTAG);
VERIFY0(dmu_object_free(mos, ddobj, tx));
dmu_object_free_zapified(mos, ddobj, tx);
}
void
@ -724,10 +725,6 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
ds->ds_prev->ds_phys->ds_num_children--;
}
zfeature_info_t *async_destroy =
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY];
objset_t *os;
/*
* Destroy the deadlist. Unless it's a clone, the
* deadlist should be empty. (If it's a clone, it's
@ -738,9 +735,10 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_phys->ds_deadlist_obj = 0;
objset_t *os;
VERIFY0(dmu_objset_from_ds(ds, &os));
if (!spa_feature_is_enabled(dp->dp_spa, async_destroy)) {
if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) {
old_synchronous_dataset_destroy(ds, tx);
} else {
/*
@ -751,10 +749,11 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
zil_destroy_sync(dmu_objset_zil(os), tx);
if (!spa_feature_is_active(dp->dp_spa, async_destroy)) {
if (!spa_feature_is_active(dp->dp_spa,
SPA_FEATURE_ASYNC_DESTROY)) {
dsl_scan_t *scn = dp->dp_scan;
spa_feature_incr(dp->dp_spa, async_destroy, tx);
spa_feature_incr(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY,
tx);
dp->dp_bptree_obj = bptree_alloc(mos, tx);
VERIFY0(zap_add(mos,
DMU_POOL_DIRECTORY_OBJECT,
@ -814,7 +813,7 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
ASSERT0(ds->ds_phys->ds_userrefs_obj);
dsl_dir_rele(ds->ds_dir, ds);
ds->ds_dir = NULL;
VERIFY0(dmu_object_free(mos, obj, tx));
dmu_object_free_zapified(mos, obj, tx);
dsl_dir_destroy_sync(ddobj, tx);
@ -870,8 +869,7 @@ dsl_destroy_head(const char *name)
error = spa_open(name, &spa, FTAG);
if (error != 0)
return (error);
isenabled = spa_feature_is_enabled(spa,
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY]);
isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY);
spa_close(spa, FTAG);
ddha.ddha_name = name;

View File

@ -33,6 +33,7 @@
#include <sys/dsl_prop.h>
#include <sys/dsl_synctask.h>
#include <sys/dsl_deleg.h>
#include <sys/dmu_impl.h>
#include <sys/spa.h>
#include <sys/metaslab.h>
#include <sys/zap.h>
@ -93,7 +94,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
{
dmu_object_info_t doi;
dmu_object_info_from_db(dbuf, &doi);
ASSERT3U(doi.doi_type, ==, DMU_OT_DSL_DIR);
ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_DSL_DIR);
ASSERT3U(doi.doi_bonus_size, >=, sizeof (dsl_dir_phys_t));
}
#endif
@ -1363,3 +1364,10 @@ dsl_dir_snap_cmtime_update(dsl_dir_t *dd)
dd->dd_snap_cmtime = t;
mutex_exit(&dd->dd_lock);
}
void
dsl_dir_zapify(dsl_dir_t *dd, dmu_tx_t *tx)
{
objset_t *mos = dd->dd_pool->dp_meta_objset;
dmu_object_zapify(mos, dd->dd_object, DMU_OT_DSL_DIR, tx);
}

View File

@ -278,8 +278,7 @@ dsl_pool_open(dsl_pool_t *dp)
dp->dp_meta_objset, obj));
}
if (spa_feature_is_active(dp->dp_spa,
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) {
err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1,
&dp->dp_bptree_obj);
@ -287,8 +286,7 @@ dsl_pool_open(dsl_pool_t *dp)
goto out;
}
if (spa_feature_is_active(dp->dp_spa,
&spa_feature_table[SPA_FEATURE_EMPTY_BPOBJ])) {
if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMPTY_BPOBJ)) {
err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
&dp->dp_empty_bpobj);

View File

@ -132,7 +132,7 @@ dsl_scan_init(dsl_pool_t *dp, uint64_t txg)
*/
ASSERT(!scn->scn_async_destroying);
scn->scn_async_destroying = spa_feature_is_active(dp->dp_spa,
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY]);
SPA_FEATURE_ASYNC_DESTROY);
err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
"scrub_func", sizeof (uint64_t), 1, &f);
@ -1384,7 +1384,6 @@ dsl_scan_active(dsl_scan_t *scn)
return (B_FALSE);
if (spa_shutting_down(spa))
return (B_FALSE);
if (scn->scn_phys.scn_state == DSS_SCANNING ||
scn->scn_async_destroying)
return (B_TRUE);
@ -1443,7 +1442,7 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
VERIFY3U(0, ==, zio_wait(scn->scn_zio_root));
if (err == 0 && spa_feature_is_active(spa,
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
SPA_FEATURE_ASYNC_DESTROY)) {
ASSERT(scn->scn_async_destroying);
scn->scn_is_bptree = B_TRUE;
scn->scn_zio_root = zio_root(dp->dp_spa, NULL,
@ -1454,11 +1453,11 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
VERIFY0(zio_wait(scn->scn_zio_root));
if (err == 0) {
zfeature_info_t *feat = &spa_feature_table
[SPA_FEATURE_ASYNC_DESTROY];
/* finished; deactivate async destroy feature */
spa_feature_decr(spa, feat, tx);
ASSERT(!spa_feature_is_active(spa, feat));
spa_feature_decr(spa, SPA_FEATURE_ASYNC_DESTROY,
tx);
ASSERT(!spa_feature_is_active(spa,
SPA_FEATURE_ASYNC_DESTROY));
VERIFY0(zap_remove(dp->dp_meta_objset,
DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_BPTREE_OBJ, tx));

View File

@ -2350,14 +2350,12 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
enabled_feat = fnvlist_alloc();
unsup_feat = fnvlist_alloc();
if (!feature_is_supported(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_desc_obj,
if (!spa_features_check(spa, B_FALSE,
unsup_feat, enabled_feat))
missing_feat_read = B_TRUE;
if (spa_writeable(spa) || state == SPA_LOAD_TRYIMPORT) {
if (!feature_is_supported(spa->spa_meta_objset,
spa->spa_feat_for_write_obj, spa->spa_feat_desc_obj,
if (!spa_features_check(spa, B_TRUE,
unsup_feat, enabled_feat)) {
missing_feat_write = B_TRUE;
}
@ -6231,7 +6229,7 @@ spa_sync_props(void *arg, dmu_tx_t *tx)
zpool_prop_t prop;
const char *propname;
zprop_type_t proptype;
zfeature_info_t *feature;
spa_feature_t fid;
switch (prop = zpool_name_to_prop(nvpair_name(elem))) {
case ZPROP_INVAL:
@ -6241,9 +6239,9 @@ spa_sync_props(void *arg, dmu_tx_t *tx)
ASSERT(zpool_prop_feature(nvpair_name(elem)));
fname = strchr(nvpair_name(elem), '@') + 1;
VERIFY0(zfeature_lookup_name(fname, &feature));
VERIFY0(zfeature_lookup_name(fname, &fid));
spa_feature_enable(spa, feature, tx);
spa_feature_enable(spa, fid, tx);
spa_history_log_internal(spa, "set", tx,
"%s=enabled", nvpair_name(elem));
break;

View File

@ -1193,15 +1193,17 @@ spa_vdev_state_exit(spa_t *spa, vdev_t *vd, int error)
void
spa_activate_mos_feature(spa_t *spa, const char *feature)
{
(void) nvlist_add_boolean(spa->spa_label_features, feature);
vdev_config_dirty(spa->spa_root_vdev);
if (!nvlist_exists(spa->spa_label_features, feature)) {
fnvlist_add_boolean(spa->spa_label_features, feature);
vdev_config_dirty(spa->spa_root_vdev);
}
}
void
spa_deactivate_mos_feature(spa_t *spa, const char *feature)
{
(void) nvlist_remove_all(spa->spa_label_features, feature);
vdev_config_dirty(spa->spa_root_vdev);
if (nvlist_remove_all(spa->spa_label_features, feature) == 0)
vdev_config_dirty(spa->spa_root_vdev);
}
/*

View File

@ -474,8 +474,6 @@ space_map_truncate(space_map_t *sm, dmu_tx_t *tx)
{
objset_t *os = sm->sm_os;
spa_t *spa = dmu_objset_spa(os);
zfeature_info_t *space_map_histogram =
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM];
dmu_object_info_t doi;
int bonuslen;
@ -485,7 +483,7 @@ space_map_truncate(space_map_t *sm, dmu_tx_t *tx)
VERIFY0(dmu_free_range(os, space_map_object(sm), 0, -1ULL, tx));
dmu_object_info_from_db(sm->sm_dbuf, &doi);
if (spa_feature_is_enabled(spa, space_map_histogram)) {
if (spa_feature_is_enabled(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
bonuslen = sizeof (space_map_phys_t);
ASSERT3U(bonuslen, <=, dmu_bonus_max());
} else {
@ -525,13 +523,11 @@ uint64_t
space_map_alloc(objset_t *os, dmu_tx_t *tx)
{
spa_t *spa = dmu_objset_spa(os);
zfeature_info_t *space_map_histogram =
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM];
uint64_t object;
int bonuslen;
if (spa_feature_is_enabled(spa, space_map_histogram)) {
spa_feature_incr(spa, space_map_histogram, tx);
if (spa_feature_is_enabled(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
spa_feature_incr(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM, tx);
bonuslen = sizeof (space_map_phys_t);
ASSERT3U(bonuslen, <=, dmu_bonus_max());
} else {
@ -549,20 +545,20 @@ void
space_map_free(space_map_t *sm, dmu_tx_t *tx)
{
spa_t *spa;
zfeature_info_t *space_map_histogram =
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM];
if (sm == NULL)
return;
spa = dmu_objset_spa(sm->sm_os);
if (spa_feature_is_enabled(spa, space_map_histogram)) {
if (spa_feature_is_enabled(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
dmu_object_info_t doi;
dmu_object_info_from_db(sm->sm_dbuf, &doi);
if (doi.doi_bonus_size != SPACE_MAP_SIZE_V0) {
VERIFY(spa_feature_is_active(spa, space_map_histogram));
spa_feature_decr(spa, space_map_histogram, tx);
VERIFY(spa_feature_is_active(spa,
SPA_FEATURE_SPACEMAP_HISTOGRAM));
spa_feature_decr(spa,
SPA_FEATURE_SPACEMAP_HISTOGRAM, tx);
}
}

View File

@ -301,6 +301,8 @@ typedef struct dmu_sendarg {
uint64_t dsa_last_data_offset;
} dmu_sendarg_t;
void dmu_object_zapify(objset_t *, uint64_t, dmu_object_type_t, dmu_tx_t *);
void dmu_object_free_zapified(objset_t *, uint64_t, dmu_tx_t *);
#ifdef __cplusplus
}

View File

@ -178,6 +178,7 @@ typedef struct dnode {
uint16_t dn_datablkszsec; /* in 512b sectors */
uint32_t dn_datablksz; /* in bytes */
uint64_t dn_maxblkid;
uint8_t dn_next_type[TXG_SIZE];
uint8_t dn_next_nblkptr[TXG_SIZE];
uint8_t dn_next_nlevels[TXG_SIZE];
uint8_t dn_next_indblkshift[TXG_SIZE];

View File

@ -49,9 +49,9 @@ struct dsl_pool;
#define DS_FLAG_INCONSISTENT (1ULL<<0)
#define DS_IS_INCONSISTENT(ds) \
((ds)->ds_phys->ds_flags & DS_FLAG_INCONSISTENT)
/*
* Note: nopromote can not yet be set, but we want support for it in this
* on-disk version, so that we don't need to upgrade for it later.
* Do not allow this dataset to be promoted.
*/
#define DS_FLAG_NOPROMOTE (1ULL<<1)
@ -70,6 +70,11 @@ struct dsl_pool;
#define DS_IS_DEFER_DESTROY(ds) \
((ds)->ds_phys->ds_flags & DS_FLAG_DEFER_DESTROY)
/*
* DS_FIELD_* are strings that are used in the "extensified" dataset zap object.
* They should be of the format <reverse-dns>:<field>.
*/
/*
* DS_FLAG_CI_DATASET is set if the dataset contains a file system whose
* name lookups should be performed case-insensitively.

View File

@ -140,6 +140,12 @@ uint64_t zap_create_flags(objset_t *os, int normflags, zap_flags_t flags,
uint64_t zap_create_link(objset_t *os, dmu_object_type_t ot,
uint64_t parent_obj, const char *name, dmu_tx_t *tx);
/*
* Initialize an already-allocated object.
*/
void mzap_create_impl(objset_t *os, uint64_t obj, int normflags,
zap_flags_t flags, dmu_tx_t *tx);
/*
* Create a new zapobj with no attributes from the given (unallocated)
* object number.

View File

@ -27,6 +27,7 @@
#define _SYS_ZFEATURE_H
#include <sys/nvpair.h>
#include <sys/txg.h>
#include "zfeature_common.h"
#ifdef __cplusplus
@ -37,17 +38,25 @@ struct spa;
struct dmu_tx;
struct objset;
extern boolean_t feature_is_supported(struct objset *os, uint64_t obj,
uint64_t desc_obj, nvlist_t *unsup_feat, nvlist_t *enabled_feat);
extern void spa_feature_create_zap_objects(struct spa *, struct dmu_tx *);
extern void spa_feature_enable(struct spa *, zfeature_info_t *,
extern void spa_feature_enable(struct spa *, spa_feature_t,
struct dmu_tx *);
extern void spa_feature_incr(struct spa *, spa_feature_t, struct dmu_tx *);
extern void spa_feature_decr(struct spa *, spa_feature_t, struct dmu_tx *);
extern boolean_t spa_feature_is_enabled(struct spa *, spa_feature_t);
extern boolean_t spa_feature_is_active(struct spa *, spa_feature_t);
extern uint64_t spa_feature_refcount(spa_t *, spa_feature_t, uint64_t);
extern boolean_t spa_features_check(spa_t *, boolean_t, nvlist_t *, nvlist_t *);
/*
* These functions are only exported for zhack and zdb; normal callers should
* use the above interfaces.
*/
extern int feature_get_refcount(struct spa *, zfeature_info_t *, uint64_t *);
extern void feature_enable_sync(struct spa *, zfeature_info_t *,
struct dmu_tx *);
extern void feature_sync(struct spa *, zfeature_info_t *, uint64_t,
struct dmu_tx *);
extern void spa_feature_incr(struct spa *, zfeature_info_t *, struct dmu_tx *);
extern void spa_feature_decr(struct spa *, zfeature_info_t *, struct dmu_tx *);
extern boolean_t spa_feature_is_enabled(struct spa *, zfeature_info_t *);
extern boolean_t spa_feature_is_active(struct spa *, zfeature_info_t *);
extern int spa_feature_get_refcount(struct spa *, zfeature_info_t *);
#ifdef __cplusplus
}

View File

@ -583,7 +583,7 @@ mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags)
return (err);
}
static void
void
mzap_create_impl(objset_t *os, uint64_t obj, int normflags, zap_flags_t flags,
dmu_tx_t *tx)
{
@ -873,8 +873,8 @@ zap_lookup_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
int
zap_contains(objset_t *os, uint64_t zapobj, const char *name)
{
int err = (zap_lookup_norm(os, zapobj, name, 0,
0, NULL, MT_EXACT, NULL, 0, NULL));
int err = zap_lookup_norm(os, zapobj, name, 0,
0, NULL, MT_EXACT, NULL, 0, NULL);
if (err == EOVERFLOW || err == EINVAL)
err = 0; /* found, but skipped reading the value */
return (err);

View File

@ -161,23 +161,25 @@
*/
typedef enum {
FEATURE_ACTION_ENABLE,
FEATURE_ACTION_INCR,
FEATURE_ACTION_DECR,
} feature_action_t;
/*
* Checks that the features active in the specified object are supported by
* Checks that the active features in the pool are supported by
* this software. Adds each unsupported feature (name -> description) to
* the supplied nvlist.
*/
boolean_t
feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
spa_features_check(spa_t *spa, boolean_t for_write,
nvlist_t *unsup_feat, nvlist_t *enabled_feat)
{
objset_t *os = spa->spa_meta_objset;
boolean_t supported;
zap_cursor_t zc;
zap_attribute_t za;
uint64_t obj = for_write ?
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
supported = B_TRUE;
for (zap_cursor_init(&zc, os, obj);
@ -199,8 +201,8 @@ feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
char *desc = "";
char buf[MAXPATHLEN];
if (zap_lookup(os, desc_obj, za.za_name,
1, sizeof (buf), buf) == 0)
if (zap_lookup(os, spa->spa_feat_desc_obj,
za.za_name, 1, sizeof (buf), buf) == 0)
desc = buf;
VERIFY(nvlist_add_string(unsup_feat, za.za_name,
@ -213,13 +215,18 @@ feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
return (supported);
}
static int
feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj,
zfeature_info_t *feature, uint64_t *res)
/*
* Note: well-designed features will not need to use this; they should
* use spa_feature_is_enabled() and spa_feature_is_active() instead.
* However, this is non-static for zdb and zhack.
*/
int
feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res)
{
int err;
uint64_t refcount;
uint64_t zapobj = feature->fi_can_readonly ? write_obj : read_obj;
uint64_t zapobj = feature->fi_can_readonly ?
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
/*
* If the pool is currently being created, the feature objects may not
@ -228,8 +235,8 @@ feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj,
if (zapobj == 0)
return (SET_ERROR(ENOTSUP));
err = zap_lookup(os, zapobj, feature->fi_guid, sizeof (uint64_t), 1,
&refcount);
err = zap_lookup(spa->spa_meta_objset, zapobj,
feature->fi_guid, sizeof (uint64_t), 1, &refcount);
if (err != 0) {
if (err == ENOENT)
return (SET_ERROR(ENOTSUP));
@ -240,49 +247,81 @@ feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj,
return (0);
}
static int
feature_do_action(objset_t *os, uint64_t read_obj, uint64_t write_obj,
uint64_t desc_obj, zfeature_info_t *feature, feature_action_t action,
/*
* This function is non-static for zhack; it should otherwise not be used
* outside this file.
*/
void
feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
dmu_tx_t *tx)
{
int error;
uint64_t refcount;
uint64_t zapobj = feature->fi_can_readonly ? write_obj : read_obj;
uint64_t zapobj = feature->fi_can_readonly ?
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid,
sizeof (uint64_t), 1, &refcount, tx));
if (refcount == 0)
spa_deactivate_mos_feature(spa, feature->fi_guid);
else if (feature->fi_mos)
spa_activate_mos_feature(spa, feature->fi_guid);
}
/*
* This function is non-static for zhack; it should otherwise not be used
* outside this file.
*/
void
feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
{
uint64_t zapobj = feature->fi_can_readonly ?
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
ASSERT(0 != zapobj);
ASSERT(zfeature_is_valid_guid(feature->fi_guid));
error = zap_lookup(os, zapobj, feature->fi_guid,
sizeof (uint64_t), 1, &refcount);
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
/*
* If we can't ascertain the status of the specified feature, an I/O
* error occurred.
* If the feature is already enabled, ignore the request.
*/
if (error != 0 && error != ENOENT)
return (error);
if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
return;
for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++)
spa_feature_enable(spa, feature->fi_depends[i], tx);
VERIFY0(zap_update(spa->spa_meta_objset, spa->spa_feat_desc_obj,
feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
feature->fi_desc, tx));
feature_sync(spa, feature, 0, tx);
}
static void
feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
dmu_tx_t *tx)
{
uint64_t refcount;
zfeature_info_t *feature = &spa_feature_table[fid];
uint64_t zapobj = feature->fi_can_readonly ?
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
ASSERT3U(fid, <, SPA_FEATURES);
ASSERT(0 != zapobj);
ASSERT(zfeature_is_valid_guid(feature->fi_guid));
ASSERT(dmu_tx_is_syncing(tx));
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
VERIFY0(zap_lookup(spa->spa_meta_objset, zapobj, feature->fi_guid,
sizeof (uint64_t), 1, &refcount));
switch (action) {
case FEATURE_ACTION_ENABLE:
/*
* If the feature is already enabled, ignore the request.
*/
if (error == 0)
return (0);
refcount = 0;
break;
case FEATURE_ACTION_INCR:
if (error == ENOENT)
return (SET_ERROR(ENOTSUP));
if (refcount == UINT64_MAX)
return (SET_ERROR(EOVERFLOW));
VERIFY3U(refcount, !=, UINT64_MAX);
refcount++;
break;
case FEATURE_ACTION_DECR:
if (error == ENOENT)
return (SET_ERROR(ENOTSUP));
if (refcount == 0)
return (SET_ERROR(EOVERFLOW));
VERIFY3U(refcount, !=, 0);
refcount--;
break;
default:
@ -290,42 +329,7 @@ feature_do_action(objset_t *os, uint64_t read_obj, uint64_t write_obj,
break;
}
if (action == FEATURE_ACTION_ENABLE) {
int i;
for (i = 0; feature->fi_depends[i] != NULL; i++) {
zfeature_info_t *dep = feature->fi_depends[i];
error = feature_do_action(os, read_obj, write_obj,
desc_obj, dep, FEATURE_ACTION_ENABLE, tx);
if (error != 0)
return (error);
}
}
error = zap_update(os, zapobj, feature->fi_guid,
sizeof (uint64_t), 1, &refcount, tx);
if (error != 0)
return (error);
if (action == FEATURE_ACTION_ENABLE) {
error = zap_update(os, desc_obj,
feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
feature->fi_desc, tx);
if (error != 0)
return (error);
}
if (action == FEATURE_ACTION_INCR && refcount == 1 && feature->fi_mos) {
spa_activate_mos_feature(dmu_objset_spa(os), feature->fi_guid);
}
if (action == FEATURE_ACTION_DECR && refcount == 0) {
spa_deactivate_mos_feature(dmu_objset_spa(os),
feature->fi_guid);
}
return (0);
feature_sync(spa, feature, refcount, tx);
}
void
@ -353,82 +357,51 @@ spa_feature_create_zap_objects(spa_t *spa, dmu_tx_t *tx)
* Enable any required dependencies, then enable the requested feature.
*/
void
spa_feature_enable(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
spa_feature_enable(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
{
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
spa->spa_feat_desc_obj, feature, FEATURE_ACTION_ENABLE, tx));
ASSERT3U(fid, <, SPA_FEATURES);
feature_enable_sync(spa, &spa_feature_table[fid], tx);
}
void
spa_feature_incr(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
spa_feature_incr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
{
ASSERT(dmu_tx_is_syncing(tx));
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
spa->spa_feat_desc_obj, feature, FEATURE_ACTION_INCR, tx));
feature_do_action(spa, fid, FEATURE_ACTION_INCR, tx);
}
void
spa_feature_decr(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
spa_feature_decr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
{
ASSERT(dmu_tx_is_syncing(tx));
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
spa->spa_feat_desc_obj, feature, FEATURE_ACTION_DECR, tx));
}
/*
* This interface is for debugging only. Normal consumers should use
* spa_feature_is_enabled/spa_feature_is_active.
*/
int
spa_feature_get_refcount(spa_t *spa, zfeature_info_t *feature)
{
int err;
uint64_t refcount;
if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE);
err = feature_get_refcount(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
feature, &refcount);
ASSERT(err == 0 || err == ENOTSUP);
return (err == 0 ? refcount : 0);
feature_do_action(spa, fid, FEATURE_ACTION_DECR, tx);
}
boolean_t
spa_feature_is_enabled(spa_t *spa, zfeature_info_t *feature)
spa_feature_is_enabled(spa_t *spa, spa_feature_t fid)
{
int err;
uint64_t refcount;
ASSERT3U(fid, <, SPA_FEATURES);
if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE);
err = feature_get_refcount(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
feature, &refcount);
err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
ASSERT(err == 0 || err == ENOTSUP);
return (err == 0);
}
boolean_t
spa_feature_is_active(spa_t *spa, zfeature_info_t *feature)
spa_feature_is_active(spa_t *spa, spa_feature_t fid)
{
int err;
uint64_t refcount;
ASSERT3U(fid, <, SPA_FEATURES);
if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE);
err = feature_get_refcount(spa->spa_meta_objset,
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
feature, &refcount);
err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
ASSERT(err == 0 || err == ENOTSUP);
return (err == 0 && refcount > 0);
}

View File

@ -254,7 +254,7 @@ static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp);
static void zfsdev_close(void *data);
static int zfs_prop_activate_feature(spa_t *spa, zfeature_info_t *feature);
static int zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature);
/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
void
@ -2433,8 +2433,6 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
case ZFS_PROP_COMPRESSION:
{
if (intval == ZIO_COMPRESS_LZ4) {
zfeature_info_t *feature =
&spa_feature_table[SPA_FEATURE_LZ4_COMPRESS];
spa_t *spa;
if ((err = spa_open(dsname, &spa, FTAG)) != 0)
@ -2444,9 +2442,10 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
* Setting the LZ4 compression algorithm activates
* the feature.
*/
if (!spa_feature_is_active(spa, feature)) {
if (!spa_feature_is_active(spa,
SPA_FEATURE_LZ4_COMPRESS)) {
if ((err = zfs_prop_activate_feature(spa,
feature)) != 0) {
SPA_FEATURE_LZ4_COMPRESS)) != 0) {
spa_close(spa, FTAG);
return (err);
}
@ -3731,15 +3730,13 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
return (SET_ERROR(ENOTSUP));
if (intval == ZIO_COMPRESS_LZ4) {
zfeature_info_t *feature =
&spa_feature_table[
SPA_FEATURE_LZ4_COMPRESS];
spa_t *spa;
if ((err = spa_open(dsname, &spa, FTAG)) != 0)
return (err);
if (!spa_feature_is_enabled(spa, feature)) {
if (!spa_feature_is_enabled(spa,
SPA_FEATURE_LZ4_COMPRESS)) {
spa_close(spa, FTAG);
return (SET_ERROR(ENOTSUP));
}
@ -3797,9 +3794,9 @@ static int
zfs_prop_activate_feature_check(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
spa_feature_t *featurep = arg;
if (!spa_feature_is_active(spa, feature))
if (!spa_feature_is_active(spa, *featurep))
return (0);
else
return (SET_ERROR(EBUSY));
@ -3813,9 +3810,9 @@ static void
zfs_prop_activate_feature_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
spa_feature_t *featurep = arg;
spa_feature_incr(spa, feature, tx);
spa_feature_incr(spa, *featurep, tx);
}
/*
@ -3824,14 +3821,14 @@ zfs_prop_activate_feature_sync(void *arg, dmu_tx_t *tx)
* as being active.
*/
static int
zfs_prop_activate_feature(spa_t *spa, zfeature_info_t *feature)
zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature)
{
int err;
/* EBUSY here indicates that the feature is already active */
err = dsl_sync_task(spa_name(spa),
zfs_prop_activate_feature_check, zfs_prop_activate_feature_sync,
feature, 2);
&feature, 2);
if (err != 0 && err != EBUSY)
return (err);

View File

@ -1861,8 +1861,7 @@ zfs_mvdev_dump_feature_check(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
if (spa_feature_is_active(spa,
&spa_feature_table[SPA_FEATURE_MULTI_VDEV_CRASH_DUMP]))
if (spa_feature_is_active(spa, SPA_FEATURE_MULTI_VDEV_CRASH_DUMP))
return (1);
return (0);
}
@ -1873,8 +1872,7 @@ zfs_mvdev_dump_activate_feature_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
spa_feature_incr(spa,
&spa_feature_table[SPA_FEATURE_MULTI_VDEV_CRASH_DUMP], tx);
spa_feature_incr(spa, SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, tx);
}
static int
@ -1909,7 +1907,7 @@ zvol_dump_init(zvol_state_t *zv, boolean_t resize)
*/
if (vd->vdev_children > 1 || vd->vdev_ops == &vdev_raidz_ops) {
if (!spa_feature_is_enabled(spa,
&spa_feature_table[SPA_FEATURE_MULTI_VDEV_CRASH_DUMP]))
SPA_FEATURE_MULTI_VDEV_CRASH_DUMP))
return (SET_ERROR(ENOTSUP));
(void) dsl_sync_task(spa_name(spa),
zfs_mvdev_dump_feature_check,
@ -1930,8 +1928,8 @@ zvol_dump_init(zvol_state_t *zv, boolean_t resize)
* function. Otherwise, use the old default -- OFF.
*/
checksum = spa_feature_is_active(spa,
&spa_feature_table[SPA_FEATURE_MULTI_VDEV_CRASH_DUMP]) ?
ZIO_CHECKSUM_NOPARITY : ZIO_CHECKSUM_OFF;
SPA_FEATURE_MULTI_VDEV_CRASH_DUMP) ? ZIO_CHECKSUM_NOPARITY :
ZIO_CHECKSUM_OFF;
/*
* If we are resizing the dump device then we only need to