mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-13 10:02:38 +00:00
MFV 286707: 5959 clean up per-dataset feature count code
Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: George Wilson <george@delphix.com> Reviewed by: Alex Reece <alex@delphix.com> Approved by: Richard Lowe <richlowe@richlowe.net> Author: Matthew Ahrens <mahrens@delphix.com> illumos/illumos-gate@ca0cc3918a A ZFS feature flags (large blocks) tracks its refcounts as the number of datasets that have ever used the feature. Several features of this type are planned to be added (new checksum functions). This code should be made common infrastructure rather than duplicating the code for each feature.
This commit is contained in:
commit
0d0def87fe
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=286708
@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -2221,7 +2221,7 @@ dump_label(const char *dev)
|
||||
(void) close(fd);
|
||||
}
|
||||
|
||||
static uint64_t num_large_blocks;
|
||||
static uint64_t dataset_feature_count[SPA_FEATURES];
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
@ -2235,8 +2235,15 @@ dump_one_dir(const char *dsname, void *arg)
|
||||
(void) printf("Could not open %s, error %d\n", dsname, error);
|
||||
return (0);
|
||||
}
|
||||
if (dmu_objset_ds(os)->ds_large_blocks)
|
||||
num_large_blocks++;
|
||||
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (!dmu_objset_ds(os)->ds_feature_inuse[f])
|
||||
continue;
|
||||
ASSERT(spa_feature_table[f].fi_flags &
|
||||
ZFEATURE_FLAG_PER_DATASET);
|
||||
dataset_feature_count[f]++;
|
||||
}
|
||||
|
||||
dump_dir(os);
|
||||
dmu_objset_disown(os, FTAG);
|
||||
fuid_table_destroy();
|
||||
@ -3035,7 +3042,6 @@ dump_zpool(spa_t *spa)
|
||||
dump_metaslab_groups(spa);
|
||||
|
||||
if (dump_opt['d'] || dump_opt['i']) {
|
||||
uint64_t refcount;
|
||||
dump_dir(dp->dp_meta_objset);
|
||||
if (dump_opt['d'] >= 3) {
|
||||
dump_full_bpobj(&spa->spa_deferred_bpobj,
|
||||
@ -3057,17 +3063,29 @@ dump_zpool(spa_t *spa)
|
||||
(void) dmu_objset_find(spa_name(spa), dump_one_dir,
|
||||
NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
|
||||
|
||||
(void) feature_get_refcount(spa,
|
||||
&spa_feature_table[SPA_FEATURE_LARGE_BLOCKS], &refcount);
|
||||
if (num_large_blocks != refcount) {
|
||||
(void) printf("large_blocks feature refcount mismatch: "
|
||||
"expected %lld != actual %lld\n",
|
||||
(longlong_t)num_large_blocks,
|
||||
(longlong_t)refcount);
|
||||
rc = 2;
|
||||
} else {
|
||||
(void) printf("Verified large_blocks feature refcount "
|
||||
"is correct (%llu)\n", (longlong_t)refcount);
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
uint64_t refcount;
|
||||
|
||||
if (!(spa_feature_table[f].fi_flags &
|
||||
ZFEATURE_FLAG_PER_DATASET)) {
|
||||
ASSERT0(dataset_feature_count[f]);
|
||||
continue;
|
||||
}
|
||||
(void) feature_get_refcount(spa,
|
||||
&spa_feature_table[f], &refcount);
|
||||
if (dataset_feature_count[f] != refcount) {
|
||||
(void) printf("%s feature refcount mismatch: "
|
||||
"%lld datasets != %lld refcount\n",
|
||||
spa_feature_table[f].fi_uname,
|
||||
(longlong_t)dataset_feature_count[f],
|
||||
(longlong_t)refcount);
|
||||
rc = 2;
|
||||
} else {
|
||||
(void) printf("Verified %s feature refcount "
|
||||
"of %llu is correct\n",
|
||||
spa_feature_table[f].fi_uname,
|
||||
(longlong_t)refcount);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rc == 0 && (dump_opt['b'] || dump_opt['c']))
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -294,8 +294,8 @@ zhack_feature_enable_sync(void *arg, dmu_tx_t *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);
|
||||
"guid=%s flags=%x",
|
||||
feature->fi_guid, feature->fi_flags);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -314,9 +314,7 @@ zhack_do_feature_enable(int argc, char **argv)
|
||||
*/
|
||||
desc = NULL;
|
||||
feature.fi_uname = "zhack";
|
||||
feature.fi_mos = B_FALSE;
|
||||
feature.fi_can_readonly = B_FALSE;
|
||||
feature.fi_activate_on_enable = B_FALSE;
|
||||
feature.fi_flags = 0;
|
||||
feature.fi_depends = nodeps;
|
||||
feature.fi_feature = SPA_FEATURE_NONE;
|
||||
|
||||
@ -324,7 +322,7 @@ zhack_do_feature_enable(int argc, char **argv)
|
||||
while ((c = getopt(argc, argv, "rmd:")) != -1) {
|
||||
switch (c) {
|
||||
case 'r':
|
||||
feature.fi_can_readonly = B_TRUE;
|
||||
feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
|
||||
break;
|
||||
case 'd':
|
||||
desc = strdup(optarg);
|
||||
@ -413,7 +411,7 @@ zhack_do_feature_ref(int argc, char **argv)
|
||||
* disk later.
|
||||
*/
|
||||
feature.fi_uname = "zhack";
|
||||
feature.fi_mos = B_FALSE;
|
||||
feature.fi_flags = 0;
|
||||
feature.fi_desc = NULL;
|
||||
feature.fi_depends = nodeps;
|
||||
feature.fi_feature = SPA_FEATURE_NONE;
|
||||
@ -422,7 +420,7 @@ zhack_do_feature_ref(int argc, char **argv)
|
||||
while ((c = getopt(argc, argv, "md")) != -1) {
|
||||
switch (c) {
|
||||
case 'm':
|
||||
feature.fi_mos = B_TRUE;
|
||||
feature.fi_flags |= ZFEATURE_FLAG_MOS;
|
||||
break;
|
||||
case 'd':
|
||||
decr = B_TRUE;
|
||||
@ -455,10 +453,10 @@ zhack_do_feature_ref(int argc, char **argv)
|
||||
|
||||
if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
|
||||
feature.fi_guid)) {
|
||||
feature.fi_can_readonly = B_FALSE;
|
||||
feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT;
|
||||
} else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
|
||||
feature.fi_guid)) {
|
||||
feature.fi_can_readonly = B_TRUE;
|
||||
feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
|
||||
} else {
|
||||
fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
|
||||
}
|
||||
|
@ -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) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
|
||||
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
|
||||
@ -4986,7 +4986,8 @@ zpool_do_upgrade(int argc, char **argv)
|
||||
"---------------\n");
|
||||
for (i = 0; i < SPA_FEATURES; i++) {
|
||||
zfeature_info_t *fi = &spa_feature_table[i];
|
||||
const char *ro = fi->fi_can_readonly ?
|
||||
const char *ro =
|
||||
(fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||
" (read-only compatible)" : "";
|
||||
|
||||
(void) printf("%-37s%s\n", fi->fi_uname, ro);
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 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, Nexenta Systems, Inc. All rights reserved.
|
||||
@ -129,15 +129,15 @@ zfeature_depends_on(spa_feature_t fid, spa_feature_t check) {
|
||||
|
||||
static void
|
||||
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
|
||||
const char *desc, boolean_t readonly, boolean_t mos,
|
||||
boolean_t activate_on_enable, const spa_feature_t *deps)
|
||||
const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
|
||||
{
|
||||
zfeature_info_t *feature = &spa_feature_table[fid];
|
||||
static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
|
||||
|
||||
ASSERT(name != NULL);
|
||||
ASSERT(desc != NULL);
|
||||
ASSERT(!readonly || !mos);
|
||||
ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
|
||||
(flags & ZFEATURE_FLAG_MOS) == 0);
|
||||
ASSERT3U(fid, <, SPA_FEATURES);
|
||||
ASSERT(zfeature_is_valid_guid(guid));
|
||||
|
||||
@ -148,9 +148,7 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
|
||||
feature->fi_guid = guid;
|
||||
feature->fi_uname = name;
|
||||
feature->fi_desc = desc;
|
||||
feature->fi_can_readonly = readonly;
|
||||
feature->fi_mos = mos;
|
||||
feature->fi_activate_on_enable = activate_on_enable;
|
||||
feature->fi_flags = flags;
|
||||
feature->fi_depends = deps;
|
||||
}
|
||||
|
||||
@ -159,45 +157,46 @@ zpool_feature_init(void)
|
||||
{
|
||||
zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
|
||||
"com.delphix:async_destroy", "async_destroy",
|
||||
"Destroy filesystems asynchronously.", B_TRUE, B_FALSE,
|
||||
B_FALSE, NULL);
|
||||
"Destroy filesystems asynchronously.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
|
||||
"com.delphix:empty_bpobj", "empty_bpobj",
|
||||
"Snapshots use less space.", B_TRUE, B_FALSE,
|
||||
B_FALSE, NULL);
|
||||
"Snapshots use less space.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
|
||||
"org.illumos:lz4_compress", "lz4_compress",
|
||||
"LZ4 compression algorithm support.", B_FALSE, B_FALSE,
|
||||
B_TRUE, NULL);
|
||||
"LZ4 compression algorithm support.",
|
||||
ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, 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.", B_FALSE, B_FALSE,
|
||||
B_FALSE, NULL);
|
||||
"Crash dumps to multiple vdev pools.",
|
||||
0, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
|
||||
"com.delphix:spacemap_histogram", "spacemap_histogram",
|
||||
"Spacemaps maintain space histograms.", B_TRUE, B_FALSE,
|
||||
B_FALSE, NULL);
|
||||
"Spacemaps maintain space histograms.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
|
||||
zfeature_register(SPA_FEATURE_ENABLED_TXG,
|
||||
"com.delphix:enabled_txg", "enabled_txg",
|
||||
"Record txg at which a feature is enabled", B_TRUE, B_FALSE,
|
||||
B_FALSE, NULL);
|
||||
"Record txg at which a feature is enabled",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||
|
||||
static spa_feature_t hole_birth_deps[] = { SPA_FEATURE_ENABLED_TXG,
|
||||
SPA_FEATURE_NONE };
|
||||
zfeature_register(SPA_FEATURE_HOLE_BIRTH,
|
||||
"com.delphix:hole_birth", "hole_birth",
|
||||
"Retain hole birth txg for more precise zfs send",
|
||||
B_FALSE, B_TRUE, B_TRUE, hole_birth_deps);
|
||||
ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
|
||||
hole_birth_deps);
|
||||
|
||||
zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
"com.delphix:extensible_dataset", "extensible_dataset",
|
||||
"Enhanced dataset functionality, used by other features.",
|
||||
B_FALSE, B_FALSE, B_FALSE, NULL);
|
||||
0, NULL);
|
||||
|
||||
static const spa_feature_t bookmarks_deps[] = {
|
||||
SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
@ -206,7 +205,7 @@ zpool_feature_init(void)
|
||||
zfeature_register(SPA_FEATURE_BOOKMARKS,
|
||||
"com.delphix:bookmarks", "bookmarks",
|
||||
"\"zfs bookmark\" command",
|
||||
B_TRUE, B_FALSE, B_FALSE, bookmarks_deps);
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
|
||||
|
||||
static const spa_feature_t filesystem_limits_deps[] = {
|
||||
SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
@ -214,13 +213,14 @@ zpool_feature_init(void)
|
||||
};
|
||||
zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
|
||||
"com.joyent:filesystem_limits", "filesystem_limits",
|
||||
"Filesystem and snapshot limits.", B_TRUE, B_FALSE, B_FALSE,
|
||||
filesystem_limits_deps);
|
||||
"Filesystem and snapshot limits.",
|
||||
ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
|
||||
|
||||
zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
|
||||
"com.delphix:embedded_data", "embedded_data",
|
||||
"Blocks which compress very well use even less space.",
|
||||
B_FALSE, B_TRUE, B_TRUE, NULL);
|
||||
ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
|
||||
NULL);
|
||||
|
||||
static const spa_feature_t large_blocks_deps[] = {
|
||||
SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||
@ -228,6 +228,6 @@ zpool_feature_init(void)
|
||||
};
|
||||
zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
|
||||
"org.open-zfs:large_blocks", "large_blocks",
|
||||
"Support for blocks larger than 128KB.", B_FALSE, B_FALSE, B_FALSE,
|
||||
large_blocks_deps);
|
||||
"Support for blocks larger than 128KB.",
|
||||
ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
@ -56,15 +56,23 @@ typedef enum spa_feature {
|
||||
|
||||
#define SPA_FEATURE_DISABLED (-1ULL)
|
||||
|
||||
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? */
|
||||
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 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? */
|
||||
/* Activate this feature at the same time it is enabled */
|
||||
boolean_t fi_activate_on_enable;
|
||||
zfeature_flags_t fi_flags;
|
||||
/* array of dependencies, terminated by SPA_FEATURE_NONE */
|
||||
const spa_feature_t *fi_depends;
|
||||
} zfeature_info_t;
|
||||
|
@ -1573,6 +1573,11 @@ dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
|
||||
struct dirty_leaf *dl;
|
||||
dmu_object_type_t type;
|
||||
|
||||
if (etype == BP_EMBEDDED_TYPE_DATA) {
|
||||
ASSERT(spa_feature_is_active(dmu_objset_spa(db->db_objset),
|
||||
SPA_FEATURE_EMBEDDED_DATA));
|
||||
}
|
||||
|
||||
DB_DNODE_ENTER(db);
|
||||
type = DB_DNODE(db)->dn_type;
|
||||
DB_DNODE_EXIT(db);
|
||||
|
@ -21,7 +21,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
* Copyright 2014 HybridCluster. All rights reserved.
|
||||
@ -721,7 +721,7 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (large_block_ok && to_ds->ds_large_blocks)
|
||||
if (large_block_ok && to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_BLOCKS])
|
||||
featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
|
||||
if (embedok &&
|
||||
spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) {
|
||||
@ -1379,13 +1379,6 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
|
||||
}
|
||||
VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds));
|
||||
|
||||
if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
|
||||
DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
|
||||
!newds->ds_large_blocks) {
|
||||
dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
|
||||
newds->ds_large_blocks = B_TRUE;
|
||||
}
|
||||
|
||||
dmu_buf_will_dirty(newds->ds_dbuf, tx);
|
||||
dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Portions Copyright (c) 2011 Martin Matuska <mm@FreeBSD.org>
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 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.
|
||||
@ -130,8 +130,10 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
|
||||
dsl_dataset_phys(ds)->ds_compressed_bytes += compressed;
|
||||
dsl_dataset_phys(ds)->ds_uncompressed_bytes += uncompressed;
|
||||
dsl_dataset_phys(ds)->ds_unique_bytes += used;
|
||||
if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE)
|
||||
ds->ds_need_large_blocks = B_TRUE;
|
||||
if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE) {
|
||||
ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_BLOCKS] =
|
||||
B_TRUE;
|
||||
}
|
||||
mutex_exit(&ds->ds_lock);
|
||||
dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
|
||||
compressed, uncompressed, tx);
|
||||
@ -433,19 +435,23 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
|
||||
offsetof(dmu_sendarg_t, dsa_link));
|
||||
|
||||
if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
|
||||
int zaperr = zap_contains(mos, dsobj,
|
||||
DS_FIELD_LARGE_BLOCKS);
|
||||
if (zaperr != ENOENT) {
|
||||
VERIFY0(zaperr);
|
||||
ds->ds_large_blocks = B_TRUE;
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
err = dsl_dir_hold_obj(dp,
|
||||
dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds,
|
||||
&ds->ds_dir);
|
||||
}
|
||||
err = dsl_dir_hold_obj(dp,
|
||||
dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds, &ds->ds_dir);
|
||||
if (err != 0) {
|
||||
mutex_destroy(&ds->ds_lock);
|
||||
mutex_destroy(&ds->ds_opening_lock);
|
||||
@ -701,6 +707,34 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
|
||||
return (gotit);
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dataset_activate_feature(uint64_t dsobj, 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 zero = 0;
|
||||
|
||||
VERIFY(spa_feature_table[f].fi_flags & ZFEATURE_FLAG_PER_DATASET);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_deactivate_feature(uint64_t dsobj, 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
|
||||
uint64_t flags, dmu_tx_t *tx)
|
||||
@ -761,8 +795,10 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
|
||||
dsphys->ds_flags |= dsl_dataset_phys(origin)->ds_flags &
|
||||
(DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
|
||||
|
||||
if (origin->ds_large_blocks)
|
||||
dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (origin->ds_feature_inuse[f])
|
||||
dsl_dataset_activate_feature(dsobj, f, tx);
|
||||
}
|
||||
|
||||
dmu_buf_will_dirty(origin->ds_dbuf, tx);
|
||||
dsl_dataset_phys(origin)->ds_num_children++;
|
||||
@ -1324,8 +1360,10 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
|
||||
dsphys->ds_bp = dsl_dataset_phys(ds)->ds_bp;
|
||||
dmu_buf_rele(dbuf, FTAG);
|
||||
|
||||
if (ds->ds_large_blocks)
|
||||
dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (ds->ds_feature_inuse[f])
|
||||
dsl_dataset_activate_feature(dsobj, f, tx);
|
||||
}
|
||||
|
||||
ASSERT3U(ds->ds_prev != 0, ==,
|
||||
dsl_dataset_phys(ds)->ds_prev_snap_obj != 0);
|
||||
@ -1617,9 +1655,13 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
|
||||
|
||||
dmu_objset_sync(ds->ds_objset, zio, tx);
|
||||
|
||||
if (ds->ds_need_large_blocks && !ds->ds_large_blocks) {
|
||||
dsl_dataset_activate_large_blocks_sync_impl(ds->ds_object, tx);
|
||||
ds->ds_large_blocks = B_TRUE;
|
||||
for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
|
||||
if (ds->ds_feature_activation_needed[f]) {
|
||||
if (ds->ds_feature_inuse[f])
|
||||
continue;
|
||||
dsl_dataset_activate_feature(ds->ds_object, f, tx);
|
||||
ds->ds_feature_inuse[f] = B_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2783,6 +2825,40 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
|
||||
dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
|
||||
ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
|
||||
|
||||
/*
|
||||
* Swap per-dataset feature flags.
|
||||
*/
|
||||
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]);
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean_t clone_inuse = clone->ds_feature_inuse[f];
|
||||
boolean_t origin_head_inuse = origin_head->ds_feature_inuse[f];
|
||||
|
||||
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;
|
||||
}
|
||||
if (origin_head_inuse) {
|
||||
dsl_dataset_activate_feature(clone->ds_object, f, tx);
|
||||
clone->ds_feature_inuse[f] = B_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
dmu_buf_will_dirty(clone->ds_dbuf, tx);
|
||||
dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
|
||||
|
||||
@ -3337,77 +3413,6 @@ dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
dsl_dataset_activate_large_blocks_check(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
const char *dsname = arg;
|
||||
dsl_dataset_t *ds;
|
||||
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||
int error = 0;
|
||||
|
||||
if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
ASSERT(spa_feature_is_enabled(dp->dp_spa,
|
||||
SPA_FEATURE_EXTENSIBLE_DATASET));
|
||||
|
||||
error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
if (ds->ds_large_blocks)
|
||||
error = EALREADY;
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_activate_large_blocks_sync_impl(uint64_t dsobj, 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 zero = 0;
|
||||
|
||||
spa_feature_incr(spa, SPA_FEATURE_LARGE_BLOCKS, tx);
|
||||
dmu_object_zapify(mos, dsobj, DMU_OT_DSL_DATASET, tx);
|
||||
|
||||
VERIFY0(zap_add(mos, dsobj, DS_FIELD_LARGE_BLOCKS,
|
||||
sizeof (zero), 1, &zero, tx));
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dataset_activate_large_blocks_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
const char *dsname = arg;
|
||||
dsl_dataset_t *ds;
|
||||
|
||||
VERIFY0(dsl_dataset_hold(dmu_tx_pool(tx), dsname, FTAG, &ds));
|
||||
|
||||
dsl_dataset_activate_large_blocks_sync_impl(ds->ds_object, tx);
|
||||
ASSERT(!ds->ds_large_blocks);
|
||||
ds->ds_large_blocks = B_TRUE;
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
}
|
||||
|
||||
int
|
||||
dsl_dataset_activate_large_blocks(const char *dsname)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = dsl_sync_task(dsname,
|
||||
dsl_dataset_activate_large_blocks_check,
|
||||
dsl_dataset_activate_large_blocks_sync, (void *)dsname,
|
||||
1, ZFS_SPACE_CHECK_RESERVED);
|
||||
|
||||
/*
|
||||
* EALREADY indicates that this dataset already supports large blocks.
|
||||
*/
|
||||
if (error == EALREADY)
|
||||
error = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if 'earlier' is an earlier snapshot in 'later's timeline.
|
||||
* For example, they could both be snapshots of the same filesystem, and
|
||||
@ -3452,7 +3457,6 @@ 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)
|
||||
{
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright (c) 2013 by Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
@ -267,9 +267,11 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
|
||||
|
||||
obj = ds->ds_object;
|
||||
|
||||
if (ds->ds_large_blocks) {
|
||||
ASSERT0(zap_contains(mos, obj, DS_FIELD_LARGE_BLOCKS));
|
||||
spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
|
||||
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_phys(ds)->ds_prev_snap_obj != 0) {
|
||||
ASSERT3P(ds->ds_prev, ==, NULL);
|
||||
@ -736,13 +738,17 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
ASSERT0(ds->ds_reserved);
|
||||
}
|
||||
|
||||
if (ds->ds_large_blocks)
|
||||
spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, 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;
|
||||
}
|
||||
}
|
||||
|
||||
dsl_scan_ds_destroyed(ds, tx);
|
||||
|
||||
obj = ds->ds_object;
|
||||
|
||||
if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
|
||||
/* This is a clone */
|
||||
ASSERT(ds->ds_prev != NULL);
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
@ -38,6 +38,7 @@
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/dsl_deadlist.h>
|
||||
#include <sys/refcount.h>
|
||||
#include <zfeature_common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -145,8 +146,6 @@ typedef struct dsl_dataset {
|
||||
/* only used in syncing context, only valid for non-snapshots: */
|
||||
struct dsl_dataset *ds_prev;
|
||||
uint64_t ds_bookmarks; /* DMU_OTN_ZAP_METADATA */
|
||||
boolean_t ds_large_blocks;
|
||||
boolean_t ds_need_large_blocks;
|
||||
|
||||
/* has internal locking: */
|
||||
dsl_deadlist_t ds_deadlist;
|
||||
@ -185,6 +184,18 @@ typedef struct dsl_dataset {
|
||||
kmutex_t ds_sendstream_lock;
|
||||
list_t ds_sendstreams;
|
||||
|
||||
/*
|
||||
* For ZFEATURE_FLAG_PER_DATASET features, set if this dataset
|
||||
* uses this feature.
|
||||
*/
|
||||
uint8_t ds_feature_inuse[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];
|
||||
|
||||
/* Protected by ds_lock; keep at end of struct for better locality */
|
||||
char ds_snapname[MAXNAMELEN];
|
||||
} dsl_dataset_t;
|
||||
@ -264,8 +275,6 @@ int dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
|
||||
int dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, dsl_dataset_t *last,
|
||||
uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
|
||||
boolean_t dsl_dataset_is_dirty(dsl_dataset_t *ds);
|
||||
int dsl_dataset_activate_large_blocks(const char *dsname);
|
||||
void dsl_dataset_activate_large_blocks_sync_impl(uint64_t dsobj, dmu_tx_t *tx);
|
||||
|
||||
int dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf);
|
||||
|
||||
@ -305,6 +314,9 @@ void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds,
|
||||
void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx);
|
||||
int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result);
|
||||
|
||||
void dsl_dataset_deactivate_feature(uint64_t dsobj,
|
||||
spa_feature_t f, dmu_tx_t *tx);
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
#define dprintf_ds(ds, fmt, ...) do { \
|
||||
if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
@ -245,7 +245,7 @@ feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
|
||||
{
|
||||
int err;
|
||||
uint64_t refcount;
|
||||
uint64_t zapobj = feature->fi_can_readonly ?
|
||||
uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
||||
|
||||
/*
|
||||
@ -296,7 +296,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
|
||||
dmu_tx_t *tx)
|
||||
{
|
||||
ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature));
|
||||
uint64_t zapobj = feature->fi_can_readonly ?
|
||||
uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
||||
|
||||
VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid,
|
||||
@ -322,7 +322,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
|
||||
|
||||
if (refcount == 0)
|
||||
spa_deactivate_mos_feature(spa, feature->fi_guid);
|
||||
else if (feature->fi_mos)
|
||||
else if (feature->fi_flags & ZFEATURE_FLAG_MOS)
|
||||
spa_activate_mos_feature(spa, feature->fi_guid, tx);
|
||||
}
|
||||
|
||||
@ -333,8 +333,9 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
|
||||
void
|
||||
feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
|
||||
{
|
||||
uint64_t initial_refcount = feature->fi_activate_on_enable ? 1 : 0;
|
||||
uint64_t zapobj = feature->fi_can_readonly ?
|
||||
uint64_t initial_refcount =
|
||||
(feature->fi_flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE) ? 1 : 0;
|
||||
uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
||||
|
||||
ASSERT(0 != zapobj);
|
||||
@ -379,7 +380,7 @@ feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
|
||||
{
|
||||
uint64_t refcount;
|
||||
zfeature_info_t *feature = &spa_feature_table[fid];
|
||||
uint64_t zapobj = feature->fi_can_readonly ?
|
||||
uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
||||
|
||||
ASSERT(VALID_FEATURE_FID(fid));
|
||||
|
Loading…
Reference in New Issue
Block a user