diff options
-rw-r--r-- | cmd/zdb/zdb.c | 2 | ||||
-rw-r--r-- | include/sys/dsl_dataset.h | 17 | ||||
-rw-r--r-- | include/zfeature_common.h | 14 | ||||
-rw-r--r-- | module/zcommon/zfeature_common.c | 65 | ||||
-rw-r--r-- | module/zfs/dmu_object.c | 3 | ||||
-rw-r--r-- | module/zfs/dmu_objset.c | 18 | ||||
-rw-r--r-- | module/zfs/dmu_send.c | 4 | ||||
-rw-r--r-- | module/zfs/dnode_sync.c | 4 | ||||
-rw-r--r-- | module/zfs/dsl_crypt.c | 8 | ||||
-rw-r--r-- | module/zfs/dsl_dataset.c | 231 | ||||
-rw-r--r-- | module/zfs/dsl_destroy.c | 14 |
11 files changed, 276 insertions, 104 deletions
diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 6072783c3..ad4ebe00a 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -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); diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index 7eded35a1..47a46f07d 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -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 { \ diff --git a/include/zfeature_common.h b/include/zfeature_common.h index 84bc7f816..3804d7b1a 100644 --- a/include/zfeature_common.h +++ b/include/zfeature_common.h @@ -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; diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c index e630481cb..a0ad108c5 100644 --- a/module/zcommon/zfeature_common.c +++ b/module/zcommon/zfeature_common.c @@ -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); } } diff --git a/module/zfs/dmu_object.c b/module/zfs/dmu_object.c index afee869b6..9b5cf125f 100644 --- a/module/zfs/dmu_object.c +++ b/module/zfs/dmu_object.c @@ -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; diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 7ad1d618a..a8304c18d 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -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) diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 24f663d3f..9c0ad406b 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -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 */ diff --git a/module/zfs/dnode_sync.c b/module/zfs/dnode_sync.c index e42f337ed..c4062beb3 100644 --- a/module/zfs/dnode_sync.c +++ b/module/zfs/dnode_sync.c @@ -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); } diff --git a/module/zfs/dsl_crypt.c b/module/zfs/dsl_crypt.c index 0eeb260c3..d2545c6fa 100644 --- a/module/zfs/dsl_crypt.c +++ b/module/zfs/dsl_crypt.c @@ -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, diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 5d98f460a..168aea861 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -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; - } - 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; + 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_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; } } diff --git a/module/zfs/dsl_destroy.c b/module/zfs/dsl_destroy.c index b80d34672..97d7befbd 100644 --- a/module/zfs/dsl_destroy.c +++ b/module/zfs/dsl_destroy.c @@ -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); |