Skip to content

Commit

Permalink
Add types to featureflags in zfs
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Paul Dagnelie <[email protected]>
Closes openzfs#7981
  • Loading branch information
pcd1193182 authored and Gregor Kopka committed Jan 7, 2019
1 parent aeb45f9 commit 13c32f8
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 104 deletions.
2 changes: 1 addition & 1 deletion cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 10 additions & 7 deletions include/sys/dsl_dataset.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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 { \
Expand Down
14 changes: 12 additions & 2 deletions include/zfeature_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -73,21 +73,31 @@ 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),
/* Each dataset has a field set if it has ever used this feature. */
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 */
const char *fi_guid; /* On-disk feature identifier */
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;
Expand Down
65 changes: 40 additions & 25 deletions module/zcommon/zfeature_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand All @@ -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);
}
Expand All @@ -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[] = {
Expand All @@ -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[] = {
Expand All @@ -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);
}

{
Expand All @@ -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[] = {
Expand All @@ -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);
}

{
Expand All @@ -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);
}

{
Expand All @@ -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,
Expand All @@ -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);
}

{
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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);
}

{
Expand All @@ -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);
}

{
Expand All @@ -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);
}
}

Expand Down
3 changes: 2 additions & 1 deletion module/zfs/dmu_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 9 additions & 9 deletions module/zfs/dmu_objset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions module/zfs/dmu_send.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
4 changes: 2 additions & 2 deletions module/zfs/dnode_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Loading

0 comments on commit 13c32f8

Please sign in to comment.