mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-24 18:39:34 +03:00
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:
parent
62b6939308
commit
fa86b5dbb6
@ -565,16 +565,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);
|
||||
@ -676,8 +680,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).
|
||||
@ -2515,8 +2518,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));
|
||||
@ -2832,7 +2834,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");
|
||||
|
@ -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))
|
||||
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));
|
||||
|
@ -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 by Cyril Plisko. All rights reserved.
|
||||
*/
|
||||
@ -1030,7 +1030,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];
|
||||
|
@ -273,6 +273,9 @@ 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
|
||||
}
|
||||
#endif
|
||||
|
@ -200,6 +200,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];
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -37,34 +37,37 @@ 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_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
|
||||
|
||||
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 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);
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@ -459,10 +459,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,
|
||||
@ -877,14 +876,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)
|
||||
|
@ -251,5 +251,27 @@ an existing space map is upgraded to the new format. Once the feature is
|
||||
|
||||
.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"
|
||||
\fBzpool\fR(8)
|
||||
|
@ -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--) {
|
||||
|
@ -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,
|
||||
@ -196,10 +198,63 @@ 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));
|
||||
}
|
||||
|
||||
#if defined(_KERNEL) && defined(HAVE_SPL)
|
||||
EXPORT_SYMBOL(dmu_object_alloc);
|
||||
EXPORT_SYMBOL(dmu_object_claim);
|
||||
EXPORT_SYMBOL(dmu_object_reclaim);
|
||||
EXPORT_SYMBOL(dmu_object_free);
|
||||
EXPORT_SYMBOL(dmu_object_next);
|
||||
EXPORT_SYMBOL(dmu_object_zapify);
|
||||
EXPORT_SYMBOL(dmu_object_free_zapified);
|
||||
#endif
|
||||
|
@ -619,7 +619,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;
|
||||
|
||||
|
@ -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>
|
||||
@ -578,7 +578,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]) ||
|
||||
@ -591,7 +596,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
|
||||
@ -600,7 +605,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;
|
||||
@ -618,7 +623,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;
|
||||
|
@ -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));
|
||||
}
|
||||
@ -3005,6 +3005,14 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
|
||||
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)
|
||||
EXPORT_SYMBOL(dsl_dataset_hold);
|
||||
EXPORT_SYMBOL(dsl_dataset_hold_obj);
|
||||
|
@ -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;
|
||||
@ -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));
|
||||
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
|
||||
@ -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));
|
||||
|
||||
dsl_dir_rele(dd, FTAG);
|
||||
VERIFY0(dmu_object_free(mos, ddobj, tx));
|
||||
dmu_object_free_zapified(mos, ddobj, tx);
|
||||
}
|
||||
|
||||
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;
|
||||
uint64_t obj, ddobj, prevobj = 0;
|
||||
boolean_t rmorigin;
|
||||
zfeature_info_t *async_destroy;
|
||||
objset_t *os;
|
||||
|
||||
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--;
|
||||
}
|
||||
|
||||
async_destroy =
|
||||
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY];
|
||||
|
||||
/*
|
||||
* Destroy the deadlist. Unless it's a clone, the
|
||||
* 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));
|
||||
|
||||
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 {
|
||||
/*
|
||||
@ -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);
|
||||
|
||||
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,
|
||||
@ -823,7 +821,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);
|
||||
|
||||
@ -879,8 +877,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;
|
||||
|
@ -32,6 +32,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>
|
||||
@ -89,7 +90,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
|
||||
@ -1372,6 +1373,13 @@ dsl_dir_snap_cmtime_update(dsl_dir_t *dd)
|
||||
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)
|
||||
EXPORT_SYMBOL(dsl_dir_set_quota);
|
||||
EXPORT_SYMBOL(dsl_dir_set_reservation);
|
||||
|
@ -245,8 +245,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);
|
||||
@ -254,8 +253,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);
|
||||
|
@ -98,7 +98,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);
|
||||
@ -1415,7 +1415,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);
|
||||
@ -1474,7 +1473,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,
|
||||
@ -1485,11 +1484,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));
|
||||
|
@ -2347,14 +2347,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;
|
||||
}
|
||||
@ -5957,7 +5955,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;
|
||||
|
||||
prop = zpool_name_to_prop(nvpair_name(elem));
|
||||
switch ((int)prop) {
|
||||
@ -5968,9 +5966,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;
|
||||
|
@ -1096,14 +1096,16 @@ 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);
|
||||
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);
|
||||
if (nvlist_remove_all(spa->spa_label_features, feature) == 0)
|
||||
vdev_config_dirty(spa->spa_root_vdev);
|
||||
}
|
||||
|
||||
|
@ -482,8 +482,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;
|
||||
|
||||
@ -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));
|
||||
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 {
|
||||
@ -533,13 +531,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 {
|
||||
@ -557,20 +553,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -572,7 +572,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)
|
||||
{
|
||||
@ -862,8 +862,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);
|
||||
|
@ -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;
|
||||
char *buf;
|
||||
|
||||
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) {
|
||||
char *desc = "";
|
||||
|
||||
if (zap_lookup(os, desc_obj, za->za_name,
|
||||
1, MAXPATHLEN, buf) == 0)
|
||||
if (zap_lookup(os, spa->spa_feat_desc_obj,
|
||||
za->za_name, 1, MAXPATHLEN, buf) == 0)
|
||||
desc = buf;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
@ -236,8 +243,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));
|
||||
@ -248,49 +255,82 @@ 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;
|
||||
int i;
|
||||
|
||||
ASSERT(0 != zapobj);
|
||||
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 (error == 0)
|
||||
return (0);
|
||||
refcount = 0;
|
||||
break;
|
||||
if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
|
||||
return;
|
||||
|
||||
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:
|
||||
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:
|
||||
@ -298,42 +338,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
|
||||
@ -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.
|
||||
*/
|
||||
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 = 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);
|
||||
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 = 0;
|
||||
|
||||
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 = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -88,39 +88,30 @@ zfeature_is_valid_guid(const char *name)
|
||||
boolean_t
|
||||
zfeature_is_supported(const char *guid)
|
||||
{
|
||||
spa_feature_t i;
|
||||
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (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)
|
||||
{
|
||||
int i;
|
||||
spa_feature_t i;
|
||||
|
||||
for (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);
|
||||
}
|
||||
}
|
||||
@ -129,11 +120,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);
|
||||
@ -144,6 +136,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;
|
||||
@ -167,4 +160,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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
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
|
||||
history_str_free(char *buf)
|
||||
@ -2347,8 +2347,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)
|
||||
@ -2358,9 +2356,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);
|
||||
}
|
||||
@ -3631,15 +3630,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));
|
||||
}
|
||||
@ -3699,9 +3696,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));
|
||||
@ -3715,9 +3712,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3726,14 +3723,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);
|
||||
|
Loading…
Reference in New Issue
Block a user