Illumos 4171, 4172

4171 clean up spa_feature_*() interfaces
4172 implement extensible_dataset feature for use by other zpool features

Reviewed by: Max Grossman <max.grossman@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Approved by: Garrett D'Amore <garrett@damore.org>a

References:
  https://www.illumos.org/issues/4171
  https://www.illumos.org/issues/4172
  https://github.com/illumos/illumos-gate/commit/2acef22

Ported-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2528
This commit is contained in:
Matthew Ahrens 2013-10-08 09:13:05 -08:00 committed by Brian Behlendorf
parent 62b6939308
commit fa86b5dbb6
27 changed files with 369 additions and 276 deletions

View File

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

View File

@ -283,12 +283,13 @@ zhack_do_feature_stat(int argc, char **argv)
} }
static void 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; spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg; 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, spa_history_log_internal(spa, "zhack enable feature", tx,
"name=%s can_readonly=%u", "name=%s can_readonly=%u",
feature->fi_guid, feature->fi_can_readonly); feature->fi_guid, feature->fi_can_readonly);
@ -302,7 +303,7 @@ zhack_do_feature_enable(int argc, char **argv)
spa_t *spa; spa_t *spa;
objset_t *mos; objset_t *mos;
zfeature_info_t feature; 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 * 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); zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset; 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"); fatal(spa, FTAG, "'%s' is a real feature, will not enable");
if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid)) if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
fatal(spa, FTAG, "feature already enabled: %s", fatal(spa, FTAG, "feature already enabled: %s",
feature.fi_guid); feature.fi_guid);
VERIFY0(dsl_sync_task(spa_name(spa), NULL, VERIFY0(dsl_sync_task(spa_name(spa), NULL,
feature_enable_sync, &feature, 5)); zhack_feature_enable_sync, &feature, 5));
spa_close(spa, FTAG); 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; spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg; 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, spa_history_log_internal(spa, "zhack feature incr", tx,
"name=%s", feature->fi_guid); "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; spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg; 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, spa_history_log_internal(spa, "zhack feature decr", tx,
"name=%s", feature->fi_guid); "name=%s", feature->fi_guid);
} }
@ -394,7 +399,7 @@ zhack_do_feature_ref(int argc, char **argv)
spa_t *spa; spa_t *spa;
objset_t *mos; objset_t *mos;
zfeature_info_t feature; 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 * 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); zhack_spa_open(target, B_FALSE, FTAG, &spa);
mos = spa->spa_meta_objset; 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 change " fatal(spa, FTAG,
"refcount"); "'%s' is a real feature, will not change refcount");
}
if (0 == zap_contains(mos, spa->spa_feat_for_read_obj, if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
feature.fi_guid)) { 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); fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
} }
if (decr && !spa_feature_is_active(spa, &feature)) if (decr) {
uint64_t count;
if (feature_get_refcount(spa, &feature, &count) == 0 &&
count != 0) {
fatal(spa, FTAG, "feature refcount already 0: %s", fatal(spa, FTAG, "feature refcount already 0: %s",
feature.fi_guid); feature.fi_guid);
}
}
VERIFY0(dsl_sync_task(spa_name(spa), NULL, VERIFY0(dsl_sync_task(spa_name(spa), NULL,
decr ? feature_decr_sync : feature_incr_sync, &feature, 5)); decr ? feature_decr_sync : feature_incr_sync, &feature, 5));

View File

@ -22,7 +22,7 @@
/* /*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. 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 by Frederik Wessels. All rights reserved.
* Copyright (c) 2012 by Cyril Plisko. All rights reserved. * Copyright (c) 2012 by Cyril Plisko. All rights reserved.
*/ */
@ -1030,7 +1030,7 @@ zpool_do_create(int argc, char **argv)
* Hand off to libzfs. * Hand off to libzfs.
*/ */
if (enable_all_pool_feat) { if (enable_all_pool_feat) {
int i; spa_feature_t i;
for (i = 0; i < SPA_FEATURES; i++) { for (i = 0; i < SPA_FEATURES; i++) {
char propname[MAXPATHLEN]; char propname[MAXPATHLEN];
zfeature_info_t *feat = &spa_feature_table[i]; zfeature_info_t *feat = &spa_feature_table[i];

View File

@ -273,6 +273,9 @@ typedef struct dmu_sendarg {
uint64_t dsa_last_data_offset; uint64_t dsa_last_data_offset;
} dmu_sendarg_t; } 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -200,6 +200,7 @@ typedef struct dnode {
uint16_t dn_datablkszsec; /* in 512b sectors */ uint16_t dn_datablkszsec; /* in 512b sectors */
uint32_t dn_datablksz; /* in bytes */ uint32_t dn_datablksz; /* in bytes */
uint64_t dn_maxblkid; uint64_t dn_maxblkid;
uint8_t dn_next_type[TXG_SIZE];
uint8_t dn_next_nblkptr[TXG_SIZE]; uint8_t dn_next_nblkptr[TXG_SIZE];
uint8_t dn_next_nlevels[TXG_SIZE]; uint8_t dn_next_nlevels[TXG_SIZE];
uint8_t dn_next_indblkshift[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_FLAG_INCONSISTENT (1ULL<<0)
#define DS_IS_INCONSISTENT(ds) \ #define DS_IS_INCONSISTENT(ds) \
((ds)->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) ((ds)->ds_phys->ds_flags & DS_FLAG_INCONSISTENT)
/* /*
* Note: nopromote can not yet be set, but we want support for it in this * Do not allow this dataset to be promoted.
* on-disk version, so that we don't need to upgrade for it later.
*/ */
#define DS_FLAG_NOPROMOTE (1ULL<<1) #define DS_FLAG_NOPROMOTE (1ULL<<1)
@ -70,6 +70,11 @@ struct dsl_pool;
#define DS_IS_DEFER_DESTROY(ds) \ #define DS_IS_DEFER_DESTROY(ds) \
((ds)->ds_phys->ds_flags & DS_FLAG_DEFER_DESTROY) ((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 * DS_FLAG_CI_DATASET is set if the dataset contains a file system whose
* name lookups should be performed case-insensitively. * 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 zap_create_link(objset_t *os, dmu_object_type_t ot,
uint64_t parent_obj, const char *name, dmu_tx_t *tx); 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) * Create a new zapobj with no attributes from the given (unallocated)
* object number. * object number.

View File

@ -27,6 +27,7 @@
#define _SYS_ZFEATURE_H #define _SYS_ZFEATURE_H
#include <sys/nvpair.h> #include <sys/nvpair.h>
#include <sys/txg.h>
#include "zfeature_common.h" #include "zfeature_common.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -37,17 +38,25 @@ struct spa;
struct dmu_tx; struct dmu_tx;
struct objset; 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_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 *); 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 #ifdef __cplusplus
} }

View File

@ -37,34 +37,37 @@ extern "C" {
struct zfeature_info; 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_SPACEMAP_HISTOGRAM,
SPA_FEATURE_EXTENSIBLE_DATASET,
SPA_FEATURES
} spa_feature_t;
typedef struct zfeature_info { typedef struct zfeature_info {
spa_feature_t fi_feature;
const char *fi_uname; /* User-facing feature name */ const char *fi_uname; /* User-facing feature name */
const char *fi_guid; /* On-disk feature identifier */ const char *fi_guid; /* On-disk feature identifier */
const char *fi_desc; /* Feature description */ const char *fi_desc; /* Feature description */
boolean_t fi_can_readonly; /* Can open pool readonly w/o support? */ boolean_t fi_can_readonly; /* Can open pool readonly w/o support? */
boolean_t fi_mos; /* Is the feature necessary to read the MOS? */ 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; } zfeature_info_t;
typedef int (zfeature_func_t)(zfeature_info_t *fi, void *arg); typedef int (zfeature_func_t)(zfeature_info_t *fi, void *arg);
#define ZFS_FEATURE_DEBUG #define ZFS_FEATURE_DEBUG
typedef enum spa_feature {
SPA_FEATURE_ASYNC_DESTROY,
SPA_FEATURE_EMPTY_BPOBJ,
SPA_FEATURE_LZ4_COMPRESS,
SPA_FEATURE_SPACEMAP_HISTOGRAM,
SPA_FEATURES
} spa_feature_t;
extern zfeature_info_t spa_feature_table[SPA_FEATURES]; extern zfeature_info_t spa_feature_table[SPA_FEATURES];
extern boolean_t zfeature_is_valid_guid(const char *); extern boolean_t zfeature_is_valid_guid(const char *);
extern boolean_t zfeature_is_supported(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 *name, spa_feature_t *res);
extern int zfeature_lookup_name(const char *, zfeature_info_t **res);
extern void zpool_feature_init(void); extern void zpool_feature_init(void);

View File

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

View File

@ -251,5 +251,27 @@ an existing space map is upgraded to the new format. Once the feature is
.RE .RE
.sp
.ne 2
.na
\fB\fBextensible_dataset\fR\fR
.ad
.RS 4n
.TS
l l .
GUID com.delphix:extensible_dataset
READ\-ONLY COMPATIBLE no
DEPENDENCIES none
.TE
This feature allows more flexible use of internal ZFS data structures,
and exists for other features to depend on.
This feature will be \fBactive\fR when the first dependent feature uses it,
and will be returned to the \fBenabled\fR state when all datasets that use
this feature are destroyed.
.RE
.SH "SEE ALSO" .SH "SEE ALSO"
\fBzpool\fR(8) \fBzpool\fR(8)

View File

@ -36,13 +36,11 @@
uint64_t uint64_t
bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx) 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); spa_t *spa = dmu_objset_spa(os);
dsl_pool_t *dp = dmu_objset_pool(os); dsl_pool_t *dp = dmu_objset_pool(os);
if (spa_feature_is_enabled(spa, empty_bpobj_feat)) { if (spa_feature_is_enabled(spa, SPA_FEATURE_EMPTY_BPOBJ)) {
if (!spa_feature_is_active(spa, empty_bpobj_feat)) { if (!spa_feature_is_active(spa, SPA_FEATURE_EMPTY_BPOBJ)) {
ASSERT0(dp->dp_empty_bpobj); ASSERT0(dp->dp_empty_bpobj);
dp->dp_empty_bpobj = dp->dp_empty_bpobj =
bpobj_alloc(os, SPA_MAXBLOCKSIZE, tx); 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, DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
&dp->dp_empty_bpobj, tx) == 0); &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); ASSERT(dp->dp_empty_bpobj != 0);
return (dp->dp_empty_bpobj); return (dp->dp_empty_bpobj);
} else { } else {
@ -62,12 +60,11 @@ bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx)
void void
bpobj_decr_empty(objset_t *os, dmu_tx_t *tx) 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); dsl_pool_t *dp = dmu_objset_pool(os);
spa_feature_decr(dmu_objset_spa(os), empty_bpobj_feat, tx); spa_feature_decr(dmu_objset_spa(os), SPA_FEATURE_EMPTY_BPOBJ, tx);
if (!spa_feature_is_active(dmu_objset_spa(os), empty_bpobj_feat)) { if (!spa_feature_is_active(dmu_objset_spa(os),
SPA_FEATURE_EMPTY_BPOBJ)) {
VERIFY3U(0, ==, zap_remove(dp->dp_meta_objset, VERIFY3U(0, ==, zap_remove(dp->dp_meta_objset,
DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_EMPTY_BPOBJ, tx)); 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); mutex_exit(&bpo->bpo_lock);
return (err); return (err);
} }
ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ_SUBOBJ);
epb = doi.doi_data_block_size / sizeof (uint64_t); epb = doi.doi_data_block_size / sizeof (uint64_t);
for (i = bpo->bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) { 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_objset.h>
#include <sys/dmu_tx.h> #include <sys/dmu_tx.h>
#include <sys/dnode.h> #include <sys/dnode.h>
#include <sys/zap.h>
#include <sys/zfeature.h>
uint64_t uint64_t
dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize, dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
@ -196,10 +198,63 @@ dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
return (error); 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));
}
#if defined(_KERNEL) && defined(HAVE_SPL) #if defined(_KERNEL) && defined(HAVE_SPL)
EXPORT_SYMBOL(dmu_object_alloc); EXPORT_SYMBOL(dmu_object_alloc);
EXPORT_SYMBOL(dmu_object_claim); EXPORT_SYMBOL(dmu_object_claim);
EXPORT_SYMBOL(dmu_object_reclaim); EXPORT_SYMBOL(dmu_object_reclaim);
EXPORT_SYMBOL(dmu_object_free); EXPORT_SYMBOL(dmu_object_free);
EXPORT_SYMBOL(dmu_object_next); EXPORT_SYMBOL(dmu_object_next);
EXPORT_SYMBOL(dmu_object_zapify);
EXPORT_SYMBOL(dmu_object_free_zapified);
#endif #endif

View File

@ -619,7 +619,7 @@ traverse_pool(spa_t *spa, uint64_t txg_start, int flags,
continue; continue;
} }
if (doi.doi_type == DMU_OT_DSL_DATASET) { if (doi.doi_bonus_type == DMU_OT_DSL_DATASET) {
dsl_dataset_t *ds; dsl_dataset_t *ds;
uint64_t txg = txg_start; 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) 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> #include <sys/zfs_context.h>
@ -578,7 +578,12 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
BP_GET_LSIZE(&dnp->dn_blkptr[0]) == BP_GET_LSIZE(&dnp->dn_blkptr[0]) ==
dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT); 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], ASSERT(P2PHASE(dn->dn_next_blksz[txgoff],
SPA_MINBLOCKSIZE) == 0); SPA_MINBLOCKSIZE) == 0);
ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[0]) || ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[0]) ||
@ -591,7 +596,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dn->dn_next_blksz[txgoff] = 0; 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) if (dn->dn_next_bonuslen[txgoff] == DN_ZERO_BONUSLEN)
dnp->dn_bonuslen = 0; dnp->dn_bonuslen = 0;
else else
@ -600,7 +605,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dn->dn_next_bonuslen[txgoff] = 0; 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])); ASSERT(DMU_OT_IS_VALID(dn->dn_next_bonustype[txgoff]));
dnp->dn_bonustype = dn->dn_next_bonustype[txgoff]; dnp->dn_bonustype = dn->dn_next_bonustype[txgoff];
dn->dn_next_bonustype[txgoff] = 0; dn->dn_next_bonustype[txgoff] = 0;
@ -618,7 +623,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dn->dn_rm_spillblk[txgoff] = 0; dn->dn_rm_spillblk[txgoff] = 0;
} }
if (dn->dn_next_indblkshift[txgoff]) { if (dn->dn_next_indblkshift[txgoff] != 0) {
ASSERT(dnp->dn_nlevels == 1); ASSERT(dnp->dn_nlevels == 1);
dnp->dn_indblkshift = dn->dn_next_indblkshift[txgoff]; dnp->dn_indblkshift = dn->dn_next_indblkshift[txgoff];
dn->dn_next_indblkshift[txgoff] = 0; 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. */ /* Make sure dsobj has the correct object type. */
dmu_object_info_from_db(dbuf, &doi); 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); dmu_buf_rele(dbuf, tag);
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
} }
@ -3005,6 +3005,14 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
return (ret); 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);
}
#if defined(_KERNEL) && defined(HAVE_SPL) #if defined(_KERNEL) && defined(HAVE_SPL)
EXPORT_SYMBOL(dsl_dataset_hold); EXPORT_SYMBOL(dsl_dataset_hold);
EXPORT_SYMBOL(dsl_dataset_hold_obj); EXPORT_SYMBOL(dsl_dataset_hold_obj);

View File

@ -38,6 +38,7 @@
#include <sys/zfeature.h> #include <sys/zfeature.h>
#include <sys/zfs_ioctl.h> #include <sys/zfs_ioctl.h>
#include <sys/dsl_deleg.h> #include <sys/dsl_deleg.h>
#include <sys/dmu_impl.h>
typedef struct dmu_snapshots_destroy_arg { typedef struct dmu_snapshots_destroy_arg {
nvlist_t *dsda_snaps; nvlist_t *dsda_snaps;
@ -452,7 +453,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)); VERIFY0(zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx));
dsl_dir_rele(ds->ds_dir, ds); dsl_dir_rele(ds->ds_dir, ds);
ds->ds_dir = NULL; ds->ds_dir = NULL;
VERIFY0(dmu_object_free(mos, obj, tx)); dmu_object_free_zapified(mos, obj, tx);
} }
static void static void
@ -679,7 +680,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)); dd->dd_parent->dd_phys->dd_child_dir_zapobj, dd->dd_myname, tx));
dsl_dir_rele(dd, FTAG); dsl_dir_rele(dd, FTAG);
VERIFY0(dmu_object_free(mos, ddobj, tx)); dmu_object_free_zapified(mos, ddobj, tx);
} }
void void
@ -689,7 +690,6 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
objset_t *mos = dp->dp_meta_objset; objset_t *mos = dp->dp_meta_objset;
uint64_t obj, ddobj, prevobj = 0; uint64_t obj, ddobj, prevobj = 0;
boolean_t rmorigin; boolean_t rmorigin;
zfeature_info_t *async_destroy;
objset_t *os; objset_t *os;
ASSERT3U(ds->ds_phys->ds_num_children, <=, 1); ASSERT3U(ds->ds_phys->ds_num_children, <=, 1);
@ -734,9 +734,6 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
ds->ds_prev->ds_phys->ds_num_children--; ds->ds_prev->ds_phys->ds_num_children--;
} }
async_destroy =
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY];
/* /*
* Destroy the deadlist. Unless it's a clone, the * Destroy the deadlist. Unless it's a clone, the
* deadlist should be empty. (If it's a clone, it's * deadlist should be empty. (If it's a clone, it's
@ -749,7 +746,7 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
VERIFY0(dmu_objset_from_ds(ds, &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); old_synchronous_dataset_destroy(ds, tx);
} else { } else {
/* /*
@ -760,10 +757,11 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
zil_destroy_sync(dmu_objset_zil(os), 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; dsl_scan_t *scn = dp->dp_scan;
spa_feature_incr(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY,
spa_feature_incr(dp->dp_spa, async_destroy, tx); tx);
dp->dp_bptree_obj = bptree_alloc(mos, tx); dp->dp_bptree_obj = bptree_alloc(mos, tx);
VERIFY0(zap_add(mos, VERIFY0(zap_add(mos,
DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_DIRECTORY_OBJECT,
@ -823,7 +821,7 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
ASSERT0(ds->ds_phys->ds_userrefs_obj); ASSERT0(ds->ds_phys->ds_userrefs_obj);
dsl_dir_rele(ds->ds_dir, ds); dsl_dir_rele(ds->ds_dir, ds);
ds->ds_dir = NULL; ds->ds_dir = NULL;
VERIFY0(dmu_object_free(mos, obj, tx)); dmu_object_free_zapified(mos, obj, tx);
dsl_dir_destroy_sync(ddobj, tx); dsl_dir_destroy_sync(ddobj, tx);
@ -879,8 +877,7 @@ dsl_destroy_head(const char *name)
error = spa_open(name, &spa, FTAG); error = spa_open(name, &spa, FTAG);
if (error != 0) if (error != 0)
return (error); return (error);
isenabled = spa_feature_is_enabled(spa, isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY);
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY]);
spa_close(spa, FTAG); spa_close(spa, FTAG);
ddha.ddha_name = name; ddha.ddha_name = name;

View File

@ -32,6 +32,7 @@
#include <sys/dsl_prop.h> #include <sys/dsl_prop.h>
#include <sys/dsl_synctask.h> #include <sys/dsl_synctask.h>
#include <sys/dsl_deleg.h> #include <sys/dsl_deleg.h>
#include <sys/dmu_impl.h>
#include <sys/spa.h> #include <sys/spa.h>
#include <sys/metaslab.h> #include <sys/metaslab.h>
#include <sys/zap.h> #include <sys/zap.h>
@ -89,7 +90,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
{ {
dmu_object_info_t doi; dmu_object_info_t doi;
dmu_object_info_from_db(dbuf, &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)); ASSERT3U(doi.doi_bonus_size, >=, sizeof (dsl_dir_phys_t));
} }
#endif #endif
@ -1372,6 +1373,13 @@ dsl_dir_snap_cmtime_update(dsl_dir_t *dd)
mutex_exit(&dd->dd_lock); 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);
}
#if defined(_KERNEL) && defined(HAVE_SPL) #if defined(_KERNEL) && defined(HAVE_SPL)
EXPORT_SYMBOL(dsl_dir_set_quota); EXPORT_SYMBOL(dsl_dir_set_quota);
EXPORT_SYMBOL(dsl_dir_set_reservation); EXPORT_SYMBOL(dsl_dir_set_reservation);

View File

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

View File

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

View File

@ -2347,14 +2347,12 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
enabled_feat = fnvlist_alloc(); enabled_feat = fnvlist_alloc();
unsup_feat = fnvlist_alloc(); unsup_feat = fnvlist_alloc();
if (!feature_is_supported(spa->spa_meta_objset, if (!spa_features_check(spa, B_FALSE,
spa->spa_feat_for_read_obj, spa->spa_feat_desc_obj,
unsup_feat, enabled_feat)) unsup_feat, enabled_feat))
missing_feat_read = B_TRUE; missing_feat_read = B_TRUE;
if (spa_writeable(spa) || state == SPA_LOAD_TRYIMPORT) { if (spa_writeable(spa) || state == SPA_LOAD_TRYIMPORT) {
if (!feature_is_supported(spa->spa_meta_objset, if (!spa_features_check(spa, B_TRUE,
spa->spa_feat_for_write_obj, spa->spa_feat_desc_obj,
unsup_feat, enabled_feat)) { unsup_feat, enabled_feat)) {
missing_feat_write = B_TRUE; missing_feat_write = B_TRUE;
} }
@ -5957,7 +5955,7 @@ spa_sync_props(void *arg, dmu_tx_t *tx)
zpool_prop_t prop; zpool_prop_t prop;
const char *propname; const char *propname;
zprop_type_t proptype; zprop_type_t proptype;
zfeature_info_t *feature; spa_feature_t fid;
prop = zpool_name_to_prop(nvpair_name(elem)); prop = zpool_name_to_prop(nvpair_name(elem));
switch ((int)prop) { switch ((int)prop) {
@ -5968,9 +5966,9 @@ spa_sync_props(void *arg, dmu_tx_t *tx)
ASSERT(zpool_prop_feature(nvpair_name(elem))); ASSERT(zpool_prop_feature(nvpair_name(elem)));
fname = strchr(nvpair_name(elem), '@') + 1; 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, spa_history_log_internal(spa, "set", tx,
"%s=enabled", nvpair_name(elem)); "%s=enabled", nvpair_name(elem));
break; break;

View File

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

View File

@ -482,8 +482,6 @@ space_map_truncate(space_map_t *sm, dmu_tx_t *tx)
{ {
objset_t *os = sm->sm_os; objset_t *os = sm->sm_os;
spa_t *spa = dmu_objset_spa(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; dmu_object_info_t doi;
int bonuslen; int bonuslen;
@ -493,7 +491,7 @@ space_map_truncate(space_map_t *sm, dmu_tx_t *tx)
VERIFY0(dmu_free_range(os, space_map_object(sm), 0, -1ULL, tx)); VERIFY0(dmu_free_range(os, space_map_object(sm), 0, -1ULL, tx));
dmu_object_info_from_db(sm->sm_dbuf, &doi); 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); bonuslen = sizeof (space_map_phys_t);
ASSERT3U(bonuslen, <=, dmu_bonus_max()); ASSERT3U(bonuslen, <=, dmu_bonus_max());
} else { } else {
@ -533,13 +531,11 @@ uint64_t
space_map_alloc(objset_t *os, dmu_tx_t *tx) space_map_alloc(objset_t *os, dmu_tx_t *tx)
{ {
spa_t *spa = dmu_objset_spa(os); spa_t *spa = dmu_objset_spa(os);
zfeature_info_t *space_map_histogram =
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM];
uint64_t object; uint64_t object;
int bonuslen; int bonuslen;
if (spa_feature_is_enabled(spa, space_map_histogram)) { if (spa_feature_is_enabled(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
spa_feature_incr(spa, space_map_histogram, tx); spa_feature_incr(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM, tx);
bonuslen = sizeof (space_map_phys_t); bonuslen = sizeof (space_map_phys_t);
ASSERT3U(bonuslen, <=, dmu_bonus_max()); ASSERT3U(bonuslen, <=, dmu_bonus_max());
} else { } else {
@ -557,20 +553,20 @@ void
space_map_free(space_map_t *sm, dmu_tx_t *tx) space_map_free(space_map_t *sm, dmu_tx_t *tx)
{ {
spa_t *spa; spa_t *spa;
zfeature_info_t *space_map_histogram =
&spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM];
if (sm == NULL) if (sm == NULL)
return; return;
spa = dmu_objset_spa(sm->sm_os); 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_t doi;
dmu_object_info_from_db(sm->sm_dbuf, &doi); dmu_object_info_from_db(sm->sm_dbuf, &doi);
if (doi.doi_bonus_size != SPACE_MAP_SIZE_V0) { if (doi.doi_bonus_size != SPACE_MAP_SIZE_V0) {
VERIFY(spa_feature_is_active(spa, space_map_histogram)); VERIFY(spa_feature_is_active(spa,
spa_feature_decr(spa, space_map_histogram, tx); SPA_FEATURE_SPACEMAP_HISTOGRAM));
spa_feature_decr(spa,
SPA_FEATURE_SPACEMAP_HISTOGRAM, tx);
} }
} }

View File

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

View File

@ -161,23 +161,25 @@
*/ */
typedef enum { typedef enum {
FEATURE_ACTION_ENABLE,
FEATURE_ACTION_INCR, FEATURE_ACTION_INCR,
FEATURE_ACTION_DECR, FEATURE_ACTION_DECR,
} feature_action_t; } 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 * this software. Adds each unsupported feature (name -> description) to
* the supplied nvlist. * the supplied nvlist.
*/ */
boolean_t 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) nvlist_t *unsup_feat, nvlist_t *enabled_feat)
{ {
objset_t *os = spa->spa_meta_objset;
boolean_t supported; boolean_t supported;
zap_cursor_t *zc; zap_cursor_t *zc;
zap_attribute_t *za; zap_attribute_t *za;
uint64_t obj = for_write ?
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
char *buf; char *buf;
zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP); zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
@ -203,8 +205,8 @@ feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
if (NULL != unsup_feat) { if (NULL != unsup_feat) {
char *desc = ""; char *desc = "";
if (zap_lookup(os, desc_obj, za->za_name, if (zap_lookup(os, spa->spa_feat_desc_obj,
1, MAXPATHLEN, buf) == 0) za->za_name, 1, MAXPATHLEN, buf) == 0)
desc = buf; desc = buf;
VERIFY(nvlist_add_string(unsup_feat, VERIFY(nvlist_add_string(unsup_feat,
@ -221,13 +223,18 @@ feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
return (supported); return (supported);
} }
static int /*
feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj, * Note: well-designed features will not need to use this; they should
zfeature_info_t *feature, uint64_t *res) * 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; int err;
uint64_t refcount; 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 * If the pool is currently being created, the feature objects may not
@ -236,8 +243,8 @@ feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj,
if (zapobj == 0) if (zapobj == 0)
return (SET_ERROR(ENOTSUP)); return (SET_ERROR(ENOTSUP));
err = zap_lookup(os, zapobj, feature->fi_guid, sizeof (uint64_t), 1, err = zap_lookup(spa->spa_meta_objset, zapobj,
&refcount); feature->fi_guid, sizeof (uint64_t), 1, &refcount);
if (err != 0) { if (err != 0) {
if (err == ENOENT) if (err == ENOENT)
return (SET_ERROR(ENOTSUP)); return (SET_ERROR(ENOTSUP));
@ -248,49 +255,82 @@ feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj,
return (0); return (0);
} }
static int /*
feature_do_action(objset_t *os, uint64_t read_obj, uint64_t write_obj, * This function is non-static for zhack; it should otherwise not be used
uint64_t desc_obj, zfeature_info_t *feature, feature_action_t action, * outside this file.
*/
void
feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
dmu_tx_t *tx) dmu_tx_t *tx)
{ {
int error; uint64_t zapobj = feature->fi_can_readonly ?
uint64_t refcount; spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
uint64_t zapobj = feature->fi_can_readonly ? write_obj : 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;
int i;
ASSERT(0 != zapobj); ASSERT(0 != zapobj);
ASSERT(zfeature_is_valid_guid(feature->fi_guid)); ASSERT(zfeature_is_valid_guid(feature->fi_guid));
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
error = zap_lookup(os, zapobj, feature->fi_guid,
sizeof (uint64_t), 1, &refcount);
/*
* If we can't ascertain the status of the specified feature, an I/O
* error occurred.
*/
if (error != 0 && error != ENOENT)
return (error);
switch (action) {
case FEATURE_ACTION_ENABLE:
/* /*
* If the feature is already enabled, ignore the request. * If the feature is already enabled, ignore the request.
*/ */
if (error == 0) if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
return (0); return;
refcount = 0;
break; for (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_INCR: case FEATURE_ACTION_INCR:
if (error == ENOENT) VERIFY3U(refcount, !=, UINT64_MAX);
return (SET_ERROR(ENOTSUP));
if (refcount == UINT64_MAX)
return (SET_ERROR(EOVERFLOW));
refcount++; refcount++;
break; break;
case FEATURE_ACTION_DECR: case FEATURE_ACTION_DECR:
if (error == ENOENT) VERIFY3U(refcount, !=, 0);
return (SET_ERROR(ENOTSUP));
if (refcount == 0)
return (SET_ERROR(EOVERFLOW));
refcount--; refcount--;
break; break;
default: default:
@ -298,42 +338,7 @@ feature_do_action(objset_t *os, uint64_t read_obj, uint64_t write_obj,
break; break;
} }
if (action == FEATURE_ACTION_ENABLE) { feature_sync(spa, feature, refcount, tx);
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);
} }
void void
@ -361,82 +366,51 @@ spa_feature_create_zap_objects(spa_t *spa, dmu_tx_t *tx)
* Enable any required dependencies, then enable the requested feature. * Enable any required dependencies, then enable the requested feature.
*/ */
void 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); ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset, ASSERT3U(fid, <, SPA_FEATURES);
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj, feature_enable_sync(spa, &spa_feature_table[fid], tx);
spa->spa_feat_desc_obj, feature, FEATURE_ACTION_ENABLE, tx));
} }
void 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)); feature_do_action(spa, fid, FEATURE_ACTION_INCR, 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));
} }
void 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)); feature_do_action(spa, fid, FEATURE_ACTION_DECR, 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 = 0;
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);
} }
boolean_t 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; int err;
uint64_t refcount = 0; uint64_t refcount = 0;
ASSERT3U(fid, <, SPA_FEATURES);
if (spa_version(spa) < SPA_VERSION_FEATURES) if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE); return (B_FALSE);
err = feature_get_refcount(spa->spa_meta_objset, err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
feature, &refcount);
ASSERT(err == 0 || err == ENOTSUP); ASSERT(err == 0 || err == ENOTSUP);
return (err == 0); return (err == 0);
} }
boolean_t 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; int err;
uint64_t refcount = 0; uint64_t refcount = 0;
ASSERT3U(fid, <, SPA_FEATURES);
if (spa_version(spa) < SPA_VERSION_FEATURES) if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE); return (B_FALSE);
err = feature_get_refcount(spa->spa_meta_objset, err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
feature, &refcount);
ASSERT(err == 0 || err == ENOTSUP); ASSERT(err == 0 || err == ENOTSUP);
return (err == 0 && refcount > 0); return (err == 0 && refcount > 0);
} }

View File

@ -88,39 +88,30 @@ zfeature_is_valid_guid(const char *name)
boolean_t boolean_t
zfeature_is_supported(const char *guid) zfeature_is_supported(const char *guid)
{ {
spa_feature_t i;
if (zfeature_checks_disable) if (zfeature_checks_disable)
return (B_TRUE); return (B_TRUE);
return (0 == zfeature_lookup_guid(guid, NULL));
}
int
zfeature_lookup_guid(const char *guid, zfeature_info_t **res)
{
int i;
for (i = 0; i < SPA_FEATURES; i++) { for (i = 0; i < SPA_FEATURES; i++) {
zfeature_info_t *feature = &spa_feature_table[i]; zfeature_info_t *feature = &spa_feature_table[i];
if (strcmp(guid, feature->fi_guid) == 0) { if (strcmp(guid, feature->fi_guid) == 0)
if (res != NULL) return (B_TRUE);
*res = feature;
return (0);
}
} }
return (ENOENT); return (B_FALSE);
} }
int int
zfeature_lookup_name(const char *name, zfeature_info_t **res) zfeature_lookup_name(const char *name, spa_feature_t *res)
{ {
int i; spa_feature_t i;
for (i = 0; i < SPA_FEATURES; i++) { for (i = 0; i < SPA_FEATURES; i++) {
zfeature_info_t *feature = &spa_feature_table[i]; zfeature_info_t *feature = &spa_feature_table[i];
if (strcmp(name, feature->fi_uname) == 0) { if (strcmp(name, feature->fi_uname) == 0) {
if (res != NULL) if (res != NULL)
*res = feature; *res = i;
return (0); return (0);
} }
} }
@ -129,11 +120,12 @@ zfeature_lookup_name(const char *name, zfeature_info_t **res)
} }
static void static void
zfeature_register(int fid, const char *guid, const char *name, const char *desc, zfeature_register(spa_feature_t fid, const char *guid, const char *name,
boolean_t readonly, boolean_t mos, zfeature_info_t **deps) const char *desc, boolean_t readonly, boolean_t mos,
const spa_feature_t *deps)
{ {
zfeature_info_t *feature = &spa_feature_table[fid]; 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(name != NULL);
ASSERT(desc != NULL); ASSERT(desc != NULL);
@ -144,6 +136,7 @@ zfeature_register(int fid, const char *guid, const char *name, const char *desc,
if (deps == NULL) if (deps == NULL)
deps = nodeps; deps = nodeps;
feature->fi_feature = fid;
feature->fi_guid = guid; feature->fi_guid = guid;
feature->fi_uname = name; feature->fi_uname = name;
feature->fi_desc = desc; feature->fi_desc = desc;
@ -167,4 +160,8 @@ zpool_feature_init(void)
zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM, zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
"com.delphix:spacemap_histogram", "spacemap_histogram", "com.delphix:spacemap_histogram", "spacemap_histogram",
"Spacemaps maintain space histograms.", B_TRUE, B_FALSE, NULL); "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

@ -245,7 +245,7 @@ static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *,
int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *); int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *);
static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp); static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp);
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);
static void static void
history_str_free(char *buf) history_str_free(char *buf)
@ -2347,8 +2347,6 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
case ZFS_PROP_COMPRESSION: case ZFS_PROP_COMPRESSION:
{ {
if (intval == ZIO_COMPRESS_LZ4) { if (intval == ZIO_COMPRESS_LZ4) {
zfeature_info_t *feature =
&spa_feature_table[SPA_FEATURE_LZ4_COMPRESS];
spa_t *spa; spa_t *spa;
if ((err = spa_open(dsname, &spa, FTAG)) != 0) if ((err = spa_open(dsname, &spa, FTAG)) != 0)
@ -2358,9 +2356,10 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
* Setting the LZ4 compression algorithm activates * Setting the LZ4 compression algorithm activates
* the feature. * 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, if ((err = zfs_prop_activate_feature(spa,
feature)) != 0) { SPA_FEATURE_LZ4_COMPRESS)) != 0) {
spa_close(spa, FTAG); spa_close(spa, FTAG);
return (err); return (err);
} }
@ -3631,15 +3630,13 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
return (SET_ERROR(ENOTSUP)); return (SET_ERROR(ENOTSUP));
if (intval == ZIO_COMPRESS_LZ4) { if (intval == ZIO_COMPRESS_LZ4) {
zfeature_info_t *feature =
&spa_feature_table[
SPA_FEATURE_LZ4_COMPRESS];
spa_t *spa; spa_t *spa;
if ((err = spa_open(dsname, &spa, FTAG)) != 0) if ((err = spa_open(dsname, &spa, FTAG)) != 0)
return (err); return (err);
if (!spa_feature_is_enabled(spa, feature)) { if (!spa_feature_is_enabled(spa,
SPA_FEATURE_LZ4_COMPRESS)) {
spa_close(spa, FTAG); spa_close(spa, FTAG);
return (SET_ERROR(ENOTSUP)); return (SET_ERROR(ENOTSUP));
} }
@ -3699,9 +3696,9 @@ static int
zfs_prop_activate_feature_check(void *arg, dmu_tx_t *tx) zfs_prop_activate_feature_check(void *arg, dmu_tx_t *tx)
{ {
spa_t *spa = dmu_tx_pool(tx)->dp_spa; 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); return (0);
else else
return (SET_ERROR(EBUSY)); return (SET_ERROR(EBUSY));
@ -3715,9 +3712,9 @@ static void
zfs_prop_activate_feature_sync(void *arg, dmu_tx_t *tx) zfs_prop_activate_feature_sync(void *arg, dmu_tx_t *tx)
{ {
spa_t *spa = dmu_tx_pool(tx)->dp_spa; 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);
} }
/* /*
@ -3726,14 +3723,14 @@ zfs_prop_activate_feature_sync(void *arg, dmu_tx_t *tx)
* as being active. * as being active.
*/ */
static int 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; int err;
/* EBUSY here indicates that the feature is already active */ /* EBUSY here indicates that the feature is already active */
err = dsl_sync_task(spa_name(spa), err = dsl_sync_task(spa_name(spa),
zfs_prop_activate_feature_check, zfs_prop_activate_feature_sync, zfs_prop_activate_feature_check, zfs_prop_activate_feature_sync,
feature, 2); &feature, 2);
if (err != 0 && err != EBUSY) if (err != 0 && err != EBUSY)
return (err); return (err);