diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index ed85554d4..60cd81222 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -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"); diff --git a/cmd/zhack/zhack.c b/cmd/zhack/zhack.c index ab84046a1..9abfc0ed4 100644 --- a/cmd/zhack/zhack.c +++ b/cmd/zhack/zhack.c @@ -283,12 +283,13 @@ zhack_do_feature_stat(int argc, char **argv) } static void -feature_enable_sync(void *arg, dmu_tx_t *tx) +zhack_feature_enable_sync(void *arg, dmu_tx_t *tx) { spa_t *spa = dmu_tx_pool(tx)->dp_spa; zfeature_info_t *feature = arg; - spa_feature_enable(spa, feature, tx); + feature_enable_sync(spa, feature, tx); + spa_history_log_internal(spa, "zhack enable feature", tx, "name=%s can_readonly=%u", feature->fi_guid, feature->fi_can_readonly); @@ -302,7 +303,7 @@ zhack_do_feature_enable(int argc, char **argv) spa_t *spa; objset_t *mos; zfeature_info_t feature; - zfeature_info_t *nodeps[] = { NULL }; + spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; /* * Features are not added to the pool's label until their refcounts @@ -349,14 +350,14 @@ zhack_do_feature_enable(int argc, char **argv) zhack_spa_open(target, B_FALSE, FTAG, &spa); mos = spa->spa_meta_objset; - if (0 == zfeature_lookup_guid(feature.fi_guid, NULL)) + if (zfeature_is_supported(feature.fi_guid)) fatal(spa, FTAG, "'%s' is a real feature, will not enable"); if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid)) fatal(spa, FTAG, "feature already enabled: %s", feature.fi_guid); VERIFY0(dsl_sync_task(spa_name(spa), NULL, - feature_enable_sync, &feature, 5)); + zhack_feature_enable_sync, &feature, 5)); spa_close(spa, FTAG); @@ -368,8 +369,10 @@ feature_incr_sync(void *arg, dmu_tx_t *tx) { spa_t *spa = dmu_tx_pool(tx)->dp_spa; zfeature_info_t *feature = arg; + uint64_t refcount; - spa_feature_incr(spa, feature, tx); + VERIFY0(feature_get_refcount(spa, feature, &refcount)); + feature_sync(spa, feature, refcount + 1, tx); spa_history_log_internal(spa, "zhack feature incr", tx, "name=%s", feature->fi_guid); } @@ -379,8 +382,10 @@ feature_decr_sync(void *arg, dmu_tx_t *tx) { spa_t *spa = dmu_tx_pool(tx)->dp_spa; zfeature_info_t *feature = arg; + uint64_t refcount; - spa_feature_decr(spa, feature, tx); + VERIFY0(feature_get_refcount(spa, feature, &refcount)); + feature_sync(spa, feature, refcount - 1, tx); spa_history_log_internal(spa, "zhack feature decr", tx, "name=%s", feature->fi_guid); } @@ -394,7 +399,7 @@ zhack_do_feature_ref(int argc, char **argv) spa_t *spa; objset_t *mos; zfeature_info_t feature; - zfeature_info_t *nodeps[] = { NULL }; + spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; /* * fi_desc does not matter here because it was written to disk @@ -437,9 +442,10 @@ zhack_do_feature_ref(int argc, char **argv) zhack_spa_open(target, B_FALSE, FTAG, &spa); mos = spa->spa_meta_objset; - if (0 == zfeature_lookup_guid(feature.fi_guid, NULL)) - fatal(spa, FTAG, "'%s' is a real feature, will not change " - "refcount"); + if (zfeature_is_supported(feature.fi_guid)) { + fatal(spa, FTAG, + "'%s' is a real feature, will not change refcount"); + } if (0 == zap_contains(mos, spa->spa_feat_for_read_obj, feature.fi_guid)) { @@ -451,9 +457,14 @@ zhack_do_feature_ref(int argc, char **argv) fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid); } - if (decr && !spa_feature_is_active(spa, &feature)) - fatal(spa, FTAG, "feature refcount already 0: %s", - feature.fi_guid); + if (decr) { + uint64_t count; + if (feature_get_refcount(spa, &feature, &count) == 0 && + count != 0) { + fatal(spa, FTAG, "feature refcount already 0: %s", + feature.fi_guid); + } + } VERIFY0(dsl_sync_task(spa_name(spa), NULL, decr ? feature_decr_sync : feature_incr_sync, &feature, 5)); diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 77c68d74d..89073c0e1 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -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]; diff --git a/include/sys/dmu_impl.h b/include/sys/dmu_impl.h index bbff15df9..cb4afbaae 100644 --- a/include/sys/dmu_impl.h +++ b/include/sys/dmu_impl.h @@ -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 diff --git a/include/sys/dnode.h b/include/sys/dnode.h index fa0aa4bb7..4ca2a8a13 100644 --- a/include/sys/dnode.h +++ b/include/sys/dnode.h @@ -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]; diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index f6449c687..27ef405e0 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -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 :. + */ + /* * DS_FLAG_CI_DATASET is set if the dataset contains a file system whose * name lookups should be performed case-insensitively. diff --git a/include/sys/zap.h b/include/sys/zap.h index aabfca7ba..fbd513098 100644 --- a/include/sys/zap.h +++ b/include/sys/zap.h @@ -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. diff --git a/include/sys/zfeature.h b/include/sys/zfeature.h index 9df7e4973..c2ca63f7c 100644 --- a/include/sys/zfeature.h +++ b/include/sys/zfeature.h @@ -27,6 +27,7 @@ #define _SYS_ZFEATURE_H #include +#include #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 } diff --git a/include/zfeature_common.h b/include/zfeature_common.h index f4c1088db..084153cb0 100644 --- a/include/zfeature_common.h +++ b/include/zfeature_common.h @@ -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); diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 9d0366711..a5d2c28af 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -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 @@ -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) diff --git a/man/man5/zpool-features.5 b/man/man5/zpool-features.5 index 57d6120bf..b37bf98d8 100644 --- a/man/man5/zpool-features.5 +++ b/man/man5/zpool-features.5 @@ -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) diff --git a/module/zfs/bpobj.c b/module/zfs/bpobj.c index 5787a6fb4..eb3233b10 100644 --- a/module/zfs/bpobj.c +++ b/module/zfs/bpobj.c @@ -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--) { diff --git a/module/zfs/dmu_object.c b/module/zfs/dmu_object.c index b6b82a24b..375439ed7 100644 --- a/module/zfs/dmu_object.c +++ b/module/zfs/dmu_object.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include 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 diff --git a/module/zfs/dmu_traverse.c b/module/zfs/dmu_traverse.c index bd291c6a8..27f9eb332 100644 --- a/module/zfs/dmu_traverse.c +++ b/module/zfs/dmu_traverse.c @@ -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; diff --git a/module/zfs/dnode_sync.c b/module/zfs/dnode_sync.c index 0ff25d2af..78bccdfc6 100644 --- a/module/zfs/dnode_sync.c +++ b/module/zfs/dnode_sync.c @@ -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 @@ -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; diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 5eb8c0199..cbdf393c0 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -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); diff --git a/module/zfs/dsl_destroy.c b/module/zfs/dsl_destroy.c index 351165dbf..11038b1f9 100644 --- a/module/zfs/dsl_destroy.c +++ b/module/zfs/dsl_destroy.c @@ -38,6 +38,7 @@ #include #include #include +#include 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; diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index fb7cd2cd6..7eafdfd2e 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/module/zfs/dsl_pool.c b/module/zfs/dsl_pool.c index 0ef50717c..91476cc0b 100644 --- a/module/zfs/dsl_pool.c +++ b/module/zfs/dsl_pool.c @@ -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); diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index 7807f8485..22b68d685 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -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)); diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 397e9e627..fabf16169 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -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; diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index ef59d2255..50c3b9afd 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -1096,15 +1096,17 @@ spa_vdev_state_exit(spa_t *spa, vdev_t *vd, int error) void spa_activate_mos_feature(spa_t *spa, const char *feature) { - (void) nvlist_add_boolean(spa->spa_label_features, feature); - vdev_config_dirty(spa->spa_root_vdev); + if (!nvlist_exists(spa->spa_label_features, feature)) { + fnvlist_add_boolean(spa->spa_label_features, feature); + vdev_config_dirty(spa->spa_root_vdev); + } } void spa_deactivate_mos_feature(spa_t *spa, const char *feature) { - (void) nvlist_remove_all(spa->spa_label_features, feature); - vdev_config_dirty(spa->spa_root_vdev); + if (nvlist_remove_all(spa->spa_label_features, feature) == 0) + vdev_config_dirty(spa->spa_root_vdev); } /* diff --git a/module/zfs/space_map.c b/module/zfs/space_map.c index bbc926d4d..645a81387 100644 --- a/module/zfs/space_map.c +++ b/module/zfs/space_map.c @@ -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); } } diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c index 555d52f4c..73d84b554 100644 --- a/module/zfs/zap_micro.c +++ b/module/zfs/zap_micro.c @@ -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); diff --git a/module/zfs/zfeature.c b/module/zfs/zfeature.c index cdb9d6dce..89d4b43f0 100644 --- a/module/zfs/zfeature.c +++ b/module/zfs/zfeature.c @@ -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)); - - error = zap_lookup(os, zapobj, feature->fi_guid, - sizeof (uint64_t), 1, &refcount); + ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES); /* - * If we can't ascertain the status of the specified feature, an I/O - * error occurred. + * If the feature is already enabled, ignore the request. */ - if (error != 0 && error != ENOENT) - return (error); + if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0) + return; + + for (i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) + spa_feature_enable(spa, feature->fi_depends[i], tx); + + VERIFY0(zap_update(spa->spa_meta_objset, spa->spa_feat_desc_obj, + feature->fi_guid, 1, strlen(feature->fi_desc) + 1, + feature->fi_desc, tx)); + feature_sync(spa, feature, 0, tx); +} + +static void +feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action, + dmu_tx_t *tx) +{ + uint64_t refcount; + zfeature_info_t *feature = &spa_feature_table[fid]; + uint64_t zapobj = feature->fi_can_readonly ? + spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; + + ASSERT3U(fid, <, SPA_FEATURES); + ASSERT(0 != zapobj); + ASSERT(zfeature_is_valid_guid(feature->fi_guid)); + + ASSERT(dmu_tx_is_syncing(tx)); + ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES); + + VERIFY0(zap_lookup(spa->spa_meta_objset, zapobj, feature->fi_guid, + sizeof (uint64_t), 1, &refcount)); switch (action) { - case FEATURE_ACTION_ENABLE: - /* - * If the feature is already enabled, ignore the request. - */ - if (error == 0) - return (0); - refcount = 0; - break; case FEATURE_ACTION_INCR: - if (error == ENOENT) - return (SET_ERROR(ENOTSUP)); - if (refcount == UINT64_MAX) - return (SET_ERROR(EOVERFLOW)); + VERIFY3U(refcount, !=, UINT64_MAX); refcount++; break; case FEATURE_ACTION_DECR: - if (error == ENOENT) - return (SET_ERROR(ENOTSUP)); - if (refcount == 0) - return (SET_ERROR(EOVERFLOW)); + VERIFY3U(refcount, !=, 0); refcount--; break; default: @@ -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); } diff --git a/module/zfs/zfeature_common.c b/module/zfs/zfeature_common.c index cee544880..5bcc08ade 100644 --- a/module/zfs/zfeature_common.c +++ b/module/zfs/zfeature_common.c @@ -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); } diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index db7683ad9..453571598 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -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);