Add types to featureflags in zfs
The boolean featureflags in use thus far in ZFS are extremely useful, but because they take advantage of the zap layer, more interesting data than just a true/false value can be stored in a featureflag. In redacted send/receive, this is used to store the list of redaction snapshots for a redacted dataset. This change adds the ability for ZFS to store types other than a boolean in a featureflag. The only other implemented type is a uint64_t array. It also modifies the interfaces around dataset features to accomodate the new capabilities, and adds a few new functions to increase encapsulation. This functionality will be used by the Redacted Send/Receive feature. Reviewed-by: Matthew Ahrens <mahrens@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Paul Dagnelie <pcd@delphix.com> Closes #7981
This commit is contained in:
parent
779a6c0bf6
commit
d52d80b700
|
@ -3219,7 +3219,7 @@ dump_one_dir(const char *dsname, void *arg)
|
|||
return (0);
|
||||
|
||||
for (f = 0; f < SPA_FEATURES; f++) {
|
||||
if (!dmu_objset_ds(os)->ds_feature_inuse[f])
|
||||
if (!dsl_dataset_feature_is_active(dmu_objset_ds(os), f))
|
||||
continue;
|
||||
ASSERT(spa_feature_table[f].fi_flags &
|
||||
ZFEATURE_FLAG_PER_DATASET);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
*/
|
||||
|
@ -242,13 +242,13 @@ typedef struct dsl_dataset {
|
|||
* For ZFEATURE_FLAG_PER_DATASET features, set if this dataset
|
||||
* uses this feature.
|
||||
*/
|
||||
uint8_t ds_feature_inuse[SPA_FEATURES];
|
||||
void *ds_feature[SPA_FEATURES];
|
||||
|
||||
/*
|
||||
* Set if we need to activate the feature on this dataset this txg
|
||||
* (used only in syncing context).
|
||||
*/
|
||||
uint8_t ds_feature_activation_needed[SPA_FEATURES];
|
||||
void *ds_feature_activation[SPA_FEATURES];
|
||||
|
||||
/* Protected by ds_lock; keep at end of struct for better locality */
|
||||
char ds_snapname[ZFS_MAX_DATASET_NAME_LEN];
|
||||
|
@ -449,10 +449,13 @@ void dsl_dataset_create_remap_deadlist(dsl_dataset_t *ds, dmu_tx_t *tx);
|
|||
boolean_t dsl_dataset_remap_deadlist_exists(dsl_dataset_t *ds);
|
||||
void dsl_dataset_destroy_remap_deadlist(dsl_dataset_t *ds, dmu_tx_t *tx);
|
||||
|
||||
void dsl_dataset_activate_feature(uint64_t dsobj,
|
||||
spa_feature_t f, dmu_tx_t *tx);
|
||||
void dsl_dataset_deactivate_feature(uint64_t dsobj,
|
||||
spa_feature_t f, dmu_tx_t *tx);
|
||||
void dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, void *arg,
|
||||
dmu_tx_t *tx);
|
||||
void dsl_dataset_deactivate_feature(dsl_dataset_t *ds, spa_feature_t f,
|
||||
dmu_tx_t *tx);
|
||||
boolean_t dsl_dataset_feature_is_active(dsl_dataset_t *ds, spa_feature_t f);
|
||||
boolean_t dsl_dataset_get_uint64_array_feature(dsl_dataset_t *ds,
|
||||
spa_feature_t f, uint64_t *outlength, uint64_t **outp);
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
#define dprintf_ds(ds, fmt, ...) do { \
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2017, Intel Corporation.
|
||||
|
@ -73,7 +73,10 @@ typedef enum spa_feature {
|
|||
typedef enum zfeature_flags {
|
||||
/* Can open pool readonly even if this feature is not supported. */
|
||||
ZFEATURE_FLAG_READONLY_COMPAT = (1 << 0),
|
||||
/* Is this feature necessary to read the MOS? */
|
||||
/*
|
||||
* Is this feature necessary to load the pool? i.e. do we need this
|
||||
* feature to read the full feature list out of the MOS?
|
||||
*/
|
||||
ZFEATURE_FLAG_MOS = (1 << 1),
|
||||
/* Activate this feature at the same time it is enabled. */
|
||||
ZFEATURE_FLAG_ACTIVATE_ON_ENABLE = (1 << 2),
|
||||
|
@ -81,6 +84,12 @@ typedef enum zfeature_flags {
|
|||
ZFEATURE_FLAG_PER_DATASET = (1 << 3)
|
||||
} zfeature_flags_t;
|
||||
|
||||
typedef enum zfeature_type {
|
||||
ZFEATURE_TYPE_BOOLEAN,
|
||||
ZFEATURE_TYPE_UINT64_ARRAY,
|
||||
ZFEATURE_NUM_TYPES
|
||||
} zfeature_type_t;
|
||||
|
||||
typedef struct zfeature_info {
|
||||
spa_feature_t fi_feature;
|
||||
const char *fi_uname; /* User-facing feature name */
|
||||
|
@ -88,6 +97,7 @@ typedef struct zfeature_info {
|
|||
const char *fi_desc; /* Feature description */
|
||||
zfeature_flags_t fi_flags;
|
||||
boolean_t fi_zfs_mod_supported; /* supported by running zfs module */
|
||||
zfeature_type_t fi_type; /* Only relevant for PER_DATASET features */
|
||||
/* array of dependencies, terminated by SPA_FEATURE_NONE */
|
||||
const spa_feature_t *fi_depends;
|
||||
} zfeature_info_t;
|
||||
|
|
|
@ -203,7 +203,8 @@ zfs_mod_supported_feature(const char *name)
|
|||
|
||||
static void
|
||||
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
|
||||
const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
|
||||
const char *desc, zfeature_flags_t flags, zfeature_type_t type,
|
||||
const spa_feature_t *deps)
|
||||
{
|
||||
zfeature_info_t *feature = &spa_feature_table[fid];
|
||||
static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
|
||||
|
@ -226,6 +227,7 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
|
|||
feature->fi_uname = name;
|
||||
feature->fi_desc = desc;
|
||||
feature->fi_flags = flags;
|
||||
feature->fi_type = type;
|
||||
feature->fi_depends = deps;
|
||||
feature->fi_zfs_mod_supported = zfs_mod_supported_feature(guid);
|
||||
}
|
||||
|
@ -236,32 +238,32 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
|
||||
"com.delphix:async_destroy", "async_destroy",
|
||||
"Destroy filesystems asynchronously.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
|
||||
"com.delphix:empty_bpobj", "empty_bpobj",
|
||||
"Snapshots use less space.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
|
||||
"org.illumos:lz4_compress", "lz4_compress",
|
||||
"LZ4 compression algorithm support.",
|
||||
ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
|
||||
ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
|
||||
"com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
|
||||
"Crash dumps to multiple vdev pools.",
|
||||
0, NULL);
|
||||
0, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
|
||||
"com.delphix:spacemap_histogram", "spacemap_histogram",
|
||||
"Spacemaps maintain space histograms.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_ENABLED_TXG,
|
||||
"com.delphix:enabled_txg", "enabled_txg",
|
||||
"Record txg at which a feature is enabled",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
{
|
||||
static const spa_feature_t hole_birth_deps[] = {
|
||||
|
@ -272,24 +274,24 @@ zpool_feature_init(void)
|
|||
"com.delphix:hole_birth", "hole_birth",
|
||||
"Retain hole birth txg for more precise zfs send",
|
||||
ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
|
||||
hole_birth_deps);
|
||||
ZFEATURE_TYPE_BOOLEAN, hole_birth_deps);
|
||||
}
|
||||
|
||||
zfeature_register(SPA_FEATURE_POOL_CHECKPOINT,
|
||||
"com.delphix:zpool_checkpoint", "zpool_checkpoint",
|
||||
"Pool state can be checkpointed, allowing rewind later.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_SPACEMAP_V2,
|
||||
"com.delphix:spacemap_v2", "spacemap_v2",
|
||||
"Space maps representing large segments are more efficient.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
|
||||
NULL);
|
||||
ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
"com.delphix:extensible_dataset", "extensible_dataset",
|
||||
"Enhanced dataset functionality, used by other features.",
|
||||
0, NULL);
|
||||
0, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
{
|
||||
static const spa_feature_t bookmarks_deps[] = {
|
||||
|
@ -300,7 +302,8 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_BOOKMARKS,
|
||||
"com.delphix:bookmarks", "bookmarks",
|
||||
"\"zfs bookmark\" command",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
|
||||
bookmarks_deps);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -311,14 +314,15 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
|
||||
"com.joyent:filesystem_limits", "filesystem_limits",
|
||||
"Filesystem and snapshot limits.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
|
||||
filesystem_limits_deps);
|
||||
}
|
||||
|
||||
zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
|
||||
"com.delphix:embedded_data", "embedded_data",
|
||||
"Blocks which compress very well use even less space.",
|
||||
ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
|
||||
NULL);
|
||||
ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
{
|
||||
static const spa_feature_t large_blocks_deps[] = {
|
||||
|
@ -328,7 +332,8 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
|
||||
"org.open-zfs:large_blocks", "large_blocks",
|
||||
"Support for blocks larger than 128KB.",
|
||||
ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
|
||||
ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
|
||||
large_blocks_deps);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -339,7 +344,8 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_LARGE_DNODE,
|
||||
"org.zfsonlinux:large_dnode", "large_dnode",
|
||||
"Variable on-disk size of dnodes.",
|
||||
ZFEATURE_FLAG_PER_DATASET, large_dnode_deps);
|
||||
ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
|
||||
large_dnode_deps);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -350,8 +356,10 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_SHA512,
|
||||
"org.illumos:sha512", "sha512",
|
||||
"SHA-512/256 hash algorithm.",
|
||||
ZFEATURE_FLAG_PER_DATASET, sha512_deps);
|
||||
ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
|
||||
sha512_deps);
|
||||
}
|
||||
|
||||
{
|
||||
static const spa_feature_t skein_deps[] = {
|
||||
SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
|
@ -360,7 +368,8 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_SKEIN,
|
||||
"org.illumos:skein", "skein",
|
||||
"Skein hash algorithm.",
|
||||
ZFEATURE_FLAG_PER_DATASET, skein_deps);
|
||||
ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
|
||||
skein_deps);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -371,12 +380,15 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_EDONR,
|
||||
"org.illumos:edonr", "edonr",
|
||||
"Edon-R hash algorithm.",
|
||||
ZFEATURE_FLAG_PER_DATASET, edonr_deps);
|
||||
ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
|
||||
edonr_deps);
|
||||
}
|
||||
|
||||
zfeature_register(SPA_FEATURE_DEVICE_REMOVAL,
|
||||
"com.delphix:device_removal", "device_removal",
|
||||
"Top-level vdevs can be removed, reducing logical pool size.",
|
||||
ZFEATURE_FLAG_MOS, NULL);
|
||||
ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
|
||||
{
|
||||
static const spa_feature_t obsolete_counts_deps[] = {
|
||||
SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
|
@ -387,8 +399,10 @@ zpool_feature_init(void)
|
|||
"com.delphix:obsolete_counts", "obsolete_counts",
|
||||
"Reduce memory used by removed devices when their blocks are "
|
||||
"freed or remapped.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, obsolete_counts_deps);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
|
||||
obsolete_counts_deps);
|
||||
}
|
||||
|
||||
{
|
||||
static const spa_feature_t userobj_accounting_deps[] = {
|
||||
SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
|
@ -398,7 +412,7 @@ zpool_feature_init(void)
|
|||
"org.zfsonlinux:userobj_accounting", "userobj_accounting",
|
||||
"User/Group object accounting.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
|
||||
userobj_accounting_deps);
|
||||
ZFEATURE_TYPE_BOOLEAN, userobj_accounting_deps);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -409,7 +423,8 @@ zpool_feature_init(void)
|
|||
zfeature_register(SPA_FEATURE_ENCRYPTION,
|
||||
"com.datto:encryption", "encryption",
|
||||
"Support for dataset level encryption",
|
||||
ZFEATURE_FLAG_PER_DATASET, encryption_deps);
|
||||
ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
|
||||
encryption_deps);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -421,14 +436,14 @@ zpool_feature_init(void)
|
|||
"org.zfsonlinux:project_quota", "project_quota",
|
||||
"space/object accounting based on project ID.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
|
||||
project_quota_deps);
|
||||
ZFEATURE_TYPE_BOOLEAN, project_quota_deps);
|
||||
}
|
||||
|
||||
{
|
||||
zfeature_register(SPA_FEATURE_ALLOCATION_CLASSES,
|
||||
"org.zfsonlinux:allocation_classes", "allocation_classes",
|
||||
"Support for separate allocation classes.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -337,7 +337,8 @@ dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
|
|||
|
||||
if (*objectp == 0) {
|
||||
start_obj = 1;
|
||||
} else if (ds && ds->ds_feature_inuse[SPA_FEATURE_LARGE_DNODE]) {
|
||||
} else if (ds && dsl_dataset_feature_is_active(ds,
|
||||
SPA_FEATURE_LARGE_DNODE)) {
|
||||
uint64_t i = *objectp + 1;
|
||||
uint64_t last_obj = *objectp | (DNODES_PER_BLOCK - 1);
|
||||
dmu_object_info_t doi;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
|
@ -1073,14 +1073,14 @@ dmu_objset_create_impl_dnstats(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
|
|||
(!os->os_encrypted || !dmu_objset_is_receiving(os))) {
|
||||
os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
|
||||
if (dmu_objset_userobjused_enabled(os)) {
|
||||
ds->ds_feature_activation_needed[
|
||||
SPA_FEATURE_USEROBJ_ACCOUNTING] = B_TRUE;
|
||||
ds->ds_feature_activation[
|
||||
SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
|
||||
os->os_phys->os_flags |=
|
||||
OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
|
||||
}
|
||||
if (dmu_objset_projectquota_enabled(os)) {
|
||||
ds->ds_feature_activation_needed[
|
||||
SPA_FEATURE_PROJECT_QUOTA] = B_TRUE;
|
||||
ds->ds_feature_activation[
|
||||
SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE;
|
||||
os->os_phys->os_flags |=
|
||||
OBJSET_FLAG_PROJECTQUOTA_COMPLETE;
|
||||
}
|
||||
|
@ -2377,11 +2377,11 @@ dmu_objset_id_quota_upgrade_cb(objset_t *os)
|
|||
dmu_objset_userobjspace_present(os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
dmu_objset_ds(os)->ds_feature_activation_needed[
|
||||
SPA_FEATURE_USEROBJ_ACCOUNTING] = B_TRUE;
|
||||
dmu_objset_ds(os)->ds_feature_activation[
|
||||
SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
|
||||
if (dmu_objset_projectquota_enabled(os))
|
||||
dmu_objset_ds(os)->ds_feature_activation_needed[
|
||||
SPA_FEATURE_PROJECT_QUOTA] = B_TRUE;
|
||||
dmu_objset_ds(os)->ds_feature_activation[
|
||||
SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE;
|
||||
|
||||
err = dmu_objset_space_upgrade(os);
|
||||
if (err)
|
||||
|
|
|
@ -1022,9 +1022,9 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds,
|
|||
|
||||
/* raw sends imply large_block_ok */
|
||||
if ((large_block_ok || rawok) &&
|
||||
to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_BLOCKS])
|
||||
dsl_dataset_feature_is_active(to_ds, SPA_FEATURE_LARGE_BLOCKS))
|
||||
featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
|
||||
if (to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_DNODE])
|
||||
if (dsl_dataset_feature_is_active(to_ds, SPA_FEATURE_LARGE_DNODE))
|
||||
featureflags |= DMU_BACKUP_FEATURE_LARGE_DNODE;
|
||||
|
||||
/* encrypted datasets will not have embedded blocks */
|
||||
|
|
|
@ -753,8 +753,8 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
|
|||
if (dn->dn_num_slots > DNODE_MIN_SLOTS) {
|
||||
dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
|
||||
mutex_enter(&ds->ds_lock);
|
||||
ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_DNODE] =
|
||||
B_TRUE;
|
||||
ds->ds_feature_activation[SPA_FEATURE_LARGE_DNODE] =
|
||||
(void *)B_TRUE;
|
||||
mutex_exit(&ds->ds_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2017, Datto, Inc. All rights reserved.
|
||||
* Copyright (c) 2018 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/dsl_crypt.h>
|
||||
|
@ -1938,7 +1939,8 @@ dsl_dataset_create_crypt_sync(uint64_t dsobj, dsl_dir_t *dd,
|
|||
VERIFY0(zap_add(dp->dp_meta_objset, dd->dd_object,
|
||||
DD_FIELD_CRYPTO_KEY_OBJ, sizeof (uint64_t), 1, &dd->dd_crypto_obj,
|
||||
tx));
|
||||
dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION, tx);
|
||||
dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION,
|
||||
(void *)B_TRUE, tx);
|
||||
|
||||
/*
|
||||
* If we inherited the wrapping key we release our reference now.
|
||||
|
@ -2249,8 +2251,8 @@ dsl_crypto_recv_raw_key_sync(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
|
|||
sizeof (uint64_t), 1, &version, tx));
|
||||
|
||||
dsl_dataset_activate_feature(ds->ds_object,
|
||||
SPA_FEATURE_ENCRYPTION, tx);
|
||||
ds->ds_feature_inuse[SPA_FEATURE_ENCRYPTION] = B_TRUE;
|
||||
SPA_FEATURE_ENCRYPTION, (void *)B_TRUE, tx);
|
||||
ds->ds_feature[SPA_FEATURE_ENCRYPTION] = (void *)B_TRUE;
|
||||
|
||||
/* save the dd_crypto_obj on disk */
|
||||
VERIFY0(zap_add(mos, dd->dd_object, DD_FIELD_CRYPTO_KEY_OBJ,
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 RackTop Systems.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
|
@ -89,6 +89,8 @@ static void dsl_dataset_set_remap_deadlist_object(dsl_dataset_t *ds,
|
|||
static void dsl_dataset_unset_remap_deadlist_object(dsl_dataset_t *ds,
|
||||
dmu_tx_t *tx);
|
||||
|
||||
static void unload_zfeature(dsl_dataset_t *ds, spa_feature_t f);
|
||||
|
||||
extern int spa_asize_inflation;
|
||||
|
||||
static zil_header_t zero_zil;
|
||||
|
@ -149,13 +151,16 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
|
|||
dsl_dataset_phys(ds)->ds_unique_bytes += used;
|
||||
|
||||
if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE) {
|
||||
ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_BLOCKS] =
|
||||
B_TRUE;
|
||||
ds->ds_feature_activation[SPA_FEATURE_LARGE_BLOCKS] =
|
||||
(void *)B_TRUE;
|
||||
}
|
||||
|
||||
spa_feature_t f = zio_checksum_to_feature(BP_GET_CHECKSUM(bp));
|
||||
if (f != SPA_FEATURE_NONE)
|
||||
ds->ds_feature_activation_needed[f] = B_TRUE;
|
||||
if (f != SPA_FEATURE_NONE) {
|
||||
ASSERT3S(spa_feature_table[f].fi_type, ==,
|
||||
ZFEATURE_TYPE_BOOLEAN);
|
||||
ds->ds_feature_activation[f] = (void *)B_TRUE;
|
||||
}
|
||||
|
||||
mutex_exit(&ds->ds_lock);
|
||||
dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
|
||||
|
@ -291,6 +296,72 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
|
|||
return (used);
|
||||
}
|
||||
|
||||
struct feature_type_uint64_array_arg {
|
||||
uint64_t length;
|
||||
uint64_t *array;
|
||||
};
|
||||
|
||||
static void
|
||||
unload_zfeature(dsl_dataset_t *ds, spa_feature_t f)
|
||||
{
|
||||
switch (spa_feature_table[f].fi_type) {
|
||||
case ZFEATURE_TYPE_BOOLEAN:
|
||||
break;
|
||||
case ZFEATURE_TYPE_UINT64_ARRAY:
|
||||
{
|
||||
struct feature_type_uint64_array_arg *ftuaa = ds->ds_feature[f];
|
||||
kmem_free(ftuaa->array, ftuaa->length * sizeof (uint64_t));
|
||||
kmem_free(ftuaa, sizeof (*ftuaa));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
load_zfeature(objset_t *mos, dsl_dataset_t *ds, spa_feature_t f)
|
||||
{
|
||||
int err = 0;
|
||||
switch (spa_feature_table[f].fi_type) {
|
||||
case ZFEATURE_TYPE_BOOLEAN:
|
||||
err = zap_contains(mos, ds->ds_object,
|
||||
spa_feature_table[f].fi_guid);
|
||||
if (err == 0) {
|
||||
ds->ds_feature[f] = (void *)B_TRUE;
|
||||
} else {
|
||||
ASSERT3U(err, ==, ENOENT);
|
||||
err = 0;
|
||||
}
|
||||
break;
|
||||
case ZFEATURE_TYPE_UINT64_ARRAY:
|
||||
{
|
||||
uint64_t int_size, num_int;
|
||||
uint64_t *data;
|
||||
err = zap_length(mos, ds->ds_object,
|
||||
spa_feature_table[f].fi_guid, &int_size, &num_int);
|
||||
if (err != 0) {
|
||||
ASSERT3U(err, ==, ENOENT);
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
ASSERT3U(int_size, ==, sizeof (uint64_t));
|
||||
data = kmem_alloc(int_size * num_int, KM_SLEEP);
|
||||
VERIFY0(zap_lookup(mos, ds->ds_object,
|
||||
spa_feature_table[f].fi_guid, int_size, num_int, data));
|
||||
struct feature_type_uint64_array_arg *ftuaa =
|
||||
kmem_alloc(sizeof (*ftuaa), KM_SLEEP);
|
||||
ftuaa->length = num_int;
|
||||
ftuaa->array = data;
|
||||
ds->ds_feature[f] = ftuaa;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to release the fsid syncronously or we risk that a subsequent
|
||||
* mount of the same dataset will fail to unique_insert the fsid. This
|
||||
|
@ -334,6 +405,11 @@ dsl_dataset_evict_async(void *dbu)
|
|||
|
||||
ASSERT(!list_link_active(&ds->ds_synced_link));
|
||||
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (dsl_dataset_feature_is_active(ds, f))
|
||||
unload_zfeature(ds, f);
|
||||
}
|
||||
|
||||
list_destroy(&ds->ds_prop_cbs);
|
||||
mutex_destroy(&ds->ds_lock);
|
||||
mutex_destroy(&ds->ds_opening_lock);
|
||||
|
@ -501,14 +577,7 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
|
|||
if (!(spa_feature_table[f].fi_flags &
|
||||
ZFEATURE_FLAG_PER_DATASET))
|
||||
continue;
|
||||
err = zap_contains(mos, dsobj,
|
||||
spa_feature_table[f].fi_guid);
|
||||
if (err == 0) {
|
||||
ds->ds_feature_inuse[f] = B_TRUE;
|
||||
} else {
|
||||
ASSERT3U(err, ==, ENOENT);
|
||||
err = 0;
|
||||
}
|
||||
err = load_zfeature(mos, ds, f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -872,8 +941,55 @@ dsl_dataset_has_owner(dsl_dataset_t *ds)
|
|||
return (rv);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
zfeature_active(spa_feature_t f, void *arg)
|
||||
{
|
||||
switch (spa_feature_table[f].fi_type) {
|
||||
case ZFEATURE_TYPE_BOOLEAN: {
|
||||
boolean_t val = (boolean_t)arg;
|
||||
ASSERT(val == B_FALSE || val == B_TRUE);
|
||||
return (val);
|
||||
}
|
||||
case ZFEATURE_TYPE_UINT64_ARRAY:
|
||||
/*
|
||||
* In this case, arg is a uint64_t array. The feature is active
|
||||
* if the array is non-null.
|
||||
*/
|
||||
return (arg != NULL);
|
||||
default:
|
||||
panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
|
||||
return (B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
boolean_t
|
||||
dsl_dataset_feature_is_active(dsl_dataset_t *ds, spa_feature_t f)
|
||||
{
|
||||
return (zfeature_active(f, ds->ds_feature[f]));
|
||||
}
|
||||
|
||||
/*
|
||||
* The buffers passed out by this function are references to internal buffers;
|
||||
* they should not be freed by callers of this function, and they should not be
|
||||
* used after the dataset has been released.
|
||||
*/
|
||||
boolean_t
|
||||
dsl_dataset_get_uint64_array_feature(dsl_dataset_t *ds, spa_feature_t f,
|
||||
uint64_t *outlength, uint64_t **outp)
|
||||
{
|
||||
VERIFY(spa_feature_table[f].fi_type & ZFEATURE_TYPE_UINT64_ARRAY);
|
||||
if (!dsl_dataset_feature_is_active(ds, f)) {
|
||||
return (B_FALSE);
|
||||
}
|
||||
struct feature_type_uint64_array_arg *ftuaa = ds->ds_feature[f];
|
||||
*outp = ftuaa->array;
|
||||
*outlength = ftuaa->length;
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
|
||||
dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, void *arg,
|
||||
dmu_tx_t *tx)
|
||||
{
|
||||
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
|
||||
objset_t *mos = dmu_tx_pool(tx)->dp_meta_objset;
|
||||
|
@ -884,20 +1000,44 @@ dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
|
|||
spa_feature_incr(spa, f, tx);
|
||||
dmu_object_zapify(mos, dsobj, DMU_OT_DSL_DATASET, tx);
|
||||
|
||||
VERIFY0(zap_add(mos, dsobj, spa_feature_table[f].fi_guid,
|
||||
sizeof (zero), 1, &zero, tx));
|
||||
switch (spa_feature_table[f].fi_type) {
|
||||
case ZFEATURE_TYPE_BOOLEAN:
|
||||
ASSERT3S((boolean_t)arg, ==, B_TRUE);
|
||||
VERIFY0(zap_add(mos, dsobj, spa_feature_table[f].fi_guid,
|
||||
sizeof (zero), 1, &zero, tx));
|
||||
break;
|
||||
case ZFEATURE_TYPE_UINT64_ARRAY:
|
||||
{
|
||||
struct feature_type_uint64_array_arg *ftuaa = arg;
|
||||
VERIFY0(zap_add(mos, dsobj, spa_feature_table[f].fi_guid,
|
||||
sizeof (uint64_t), ftuaa->length, ftuaa->array, tx));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Invalid zfeature type %d", spa_feature_table[f].fi_type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_deactivate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
|
||||
dsl_dataset_deactivate_feature_impl(dsl_dataset_t *ds, spa_feature_t f,
|
||||
dmu_tx_t *tx)
|
||||
{
|
||||
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
|
||||
objset_t *mos = dmu_tx_pool(tx)->dp_meta_objset;
|
||||
uint64_t dsobj = ds->ds_object;
|
||||
|
||||
VERIFY(spa_feature_table[f].fi_flags & ZFEATURE_FLAG_PER_DATASET);
|
||||
|
||||
VERIFY0(zap_remove(mos, dsobj, spa_feature_table[f].fi_guid, tx));
|
||||
spa_feature_decr(spa, f, tx);
|
||||
ds->ds_feature[f] = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_deactivate_feature(dsl_dataset_t *ds, spa_feature_t f, dmu_tx_t *tx)
|
||||
{
|
||||
unload_zfeature(ds, f);
|
||||
dsl_dataset_deactivate_feature_impl(ds, f, tx);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -961,8 +1101,10 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
|
|||
(DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
|
||||
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (origin->ds_feature_inuse[f])
|
||||
dsl_dataset_activate_feature(dsobj, f, tx);
|
||||
if (zfeature_active(f, origin->ds_feature[f])) {
|
||||
dsl_dataset_activate_feature(dsobj, f,
|
||||
origin->ds_feature[f], tx);
|
||||
}
|
||||
}
|
||||
|
||||
dmu_buf_will_dirty(origin->ds_dbuf, tx);
|
||||
|
@ -1492,8 +1634,10 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
|
|||
dmu_buf_rele(dbuf, FTAG);
|
||||
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (ds->ds_feature_inuse[f])
|
||||
dsl_dataset_activate_feature(dsobj, f, tx);
|
||||
if (zfeature_active(f, ds->ds_feature[f])) {
|
||||
dsl_dataset_activate_feature(dsobj, f,
|
||||
ds->ds_feature[f], tx);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT3U(ds->ds_prev != 0, ==,
|
||||
|
@ -1808,11 +1952,12 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
|
|||
dmu_objset_sync(ds->ds_objset, zio, tx);
|
||||
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (ds->ds_feature_activation_needed[f]) {
|
||||
if (ds->ds_feature_inuse[f])
|
||||
if (zfeature_active(f, ds->ds_feature_activation[f])) {
|
||||
if (zfeature_active(f, ds->ds_feature[f]))
|
||||
continue;
|
||||
dsl_dataset_activate_feature(ds->ds_object, f, tx);
|
||||
ds->ds_feature_inuse[f] = B_TRUE;
|
||||
dsl_dataset_activate_feature(ds->ds_object, f,
|
||||
ds->ds_feature_activation[f], tx);
|
||||
ds->ds_feature[f] = ds->ds_feature_activation[f];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3530,31 +3675,31 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
|
|||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (!(spa_feature_table[f].fi_flags &
|
||||
ZFEATURE_FLAG_PER_DATASET)) {
|
||||
ASSERT(!clone->ds_feature_inuse[f]);
|
||||
ASSERT(!origin_head->ds_feature_inuse[f]);
|
||||
ASSERT(!dsl_dataset_feature_is_active(clone, f));
|
||||
ASSERT(!dsl_dataset_feature_is_active(origin_head, f));
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean_t clone_inuse = clone->ds_feature_inuse[f];
|
||||
boolean_t origin_head_inuse = origin_head->ds_feature_inuse[f];
|
||||
boolean_t clone_inuse = dsl_dataset_feature_is_active(clone, f);
|
||||
void *clone_feature = clone->ds_feature[f];
|
||||
boolean_t origin_head_inuse =
|
||||
dsl_dataset_feature_is_active(origin_head, f);
|
||||
void *origin_head_feature = origin_head->ds_feature[f];
|
||||
|
||||
if (clone_inuse)
|
||||
dsl_dataset_deactivate_feature_impl(clone, f, tx);
|
||||
if (origin_head_inuse)
|
||||
dsl_dataset_deactivate_feature_impl(origin_head, f, tx);
|
||||
|
||||
if (clone_inuse) {
|
||||
dsl_dataset_deactivate_feature(clone->ds_object, f, tx);
|
||||
clone->ds_feature_inuse[f] = B_FALSE;
|
||||
dsl_dataset_activate_feature(origin_head->ds_object, f,
|
||||
clone_feature, tx);
|
||||
origin_head->ds_feature[f] = clone_feature;
|
||||
}
|
||||
if (origin_head_inuse) {
|
||||
dsl_dataset_deactivate_feature(origin_head->ds_object,
|
||||
f, tx);
|
||||
origin_head->ds_feature_inuse[f] = B_FALSE;
|
||||
}
|
||||
if (clone_inuse) {
|
||||
dsl_dataset_activate_feature(origin_head->ds_object,
|
||||
f, tx);
|
||||
origin_head->ds_feature_inuse[f] = B_TRUE;
|
||||
}
|
||||
if (origin_head_inuse) {
|
||||
dsl_dataset_activate_feature(clone->ds_object, f, tx);
|
||||
clone->ds_feature_inuse[f] = B_TRUE;
|
||||
dsl_dataset_activate_feature(clone->ds_object, f,
|
||||
origin_head_feature, tx);
|
||||
clone->ds_feature[f] = origin_head_feature;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright (c) 2013 by Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
|
||||
|
@ -315,10 +315,8 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
|
|||
obj = ds->ds_object;
|
||||
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (ds->ds_feature_inuse[f]) {
|
||||
dsl_dataset_deactivate_feature(obj, f, tx);
|
||||
ds->ds_feature_inuse[f] = B_FALSE;
|
||||
}
|
||||
if (dsl_dataset_feature_is_active(ds, f))
|
||||
dsl_dataset_deactivate_feature(ds, f, tx);
|
||||
}
|
||||
if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
|
||||
ASSERT3P(ds->ds_prev, ==, NULL);
|
||||
|
@ -869,10 +867,8 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
|
|||
obj = ds->ds_object;
|
||||
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (ds->ds_feature_inuse[f]) {
|
||||
dsl_dataset_deactivate_feature(obj, f, tx);
|
||||
ds->ds_feature_inuse[f] = B_FALSE;
|
||||
}
|
||||
if (dsl_dataset_feature_is_active(ds, f))
|
||||
dsl_dataset_deactivate_feature(ds, f, tx);
|
||||
}
|
||||
|
||||
dsl_scan_ds_destroyed(ds, tx);
|
||||
|
|
Loading…
Reference in New Issue