mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 03:09:34 +03:00
Illumos 5959 - clean up per-dataset feature count code
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> References: https://www.illumos.org/issues/5959 https://github.com/illumos/illumos-gate/commit/ca0cc39 Porting notes: illumos code doesn't check for feature_get_refcount() returning ENOTSUP (which means feature is disabled) in zdb. zfsonlinux added a check in https://github.com/zfsonlinux/zfs/commit/784652c due to #3468. The check was reintroduced here. Ported-by: Witaut Bajaryn <vitaut.bayaryn@gmail.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #3965
This commit is contained in:
parent
072484504f
commit
241b541574
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* 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) 2015, Intel Corporation.
|
* Copyright (c) 2015, Intel Corporation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -2274,7 +2274,7 @@ dump_label(const char *dev)
|
|||||||
(void) close(fd);
|
(void) close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t num_large_blocks;
|
static uint64_t dataset_feature_count[SPA_FEATURES];
|
||||||
|
|
||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static int
|
static int
|
||||||
@ -2282,14 +2282,22 @@ dump_one_dir(const char *dsname, void *arg)
|
|||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
objset_t *os;
|
objset_t *os;
|
||||||
|
spa_feature_t f;
|
||||||
|
|
||||||
error = dmu_objset_own(dsname, DMU_OST_ANY, B_TRUE, FTAG, &os);
|
error = dmu_objset_own(dsname, DMU_OST_ANY, B_TRUE, FTAG, &os);
|
||||||
if (error) {
|
if (error) {
|
||||||
(void) printf("Could not open %s, error %d\n", dsname, error);
|
(void) printf("Could not open %s, error %d\n", dsname, error);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (dmu_objset_ds(os)->ds_large_blocks)
|
|
||||||
num_large_blocks++;
|
for (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);
|
dump_dir(os);
|
||||||
dmu_objset_disown(os, FTAG);
|
dmu_objset_disown(os, FTAG);
|
||||||
fuid_table_destroy();
|
fuid_table_destroy();
|
||||||
@ -3094,7 +3102,7 @@ dump_zpool(spa_t *spa)
|
|||||||
dump_metaslab_groups(spa);
|
dump_metaslab_groups(spa);
|
||||||
|
|
||||||
if (dump_opt['d'] || dump_opt['i']) {
|
if (dump_opt['d'] || dump_opt['i']) {
|
||||||
uint64_t refcount;
|
spa_feature_t f;
|
||||||
|
|
||||||
dump_dir(dp->dp_meta_objset);
|
dump_dir(dp->dp_meta_objset);
|
||||||
if (dump_opt['d'] >= 3) {
|
if (dump_opt['d'] >= 3) {
|
||||||
@ -3117,18 +3125,28 @@ dump_zpool(spa_t *spa)
|
|||||||
(void) dmu_objset_find(spa_name(spa), dump_one_dir,
|
(void) dmu_objset_find(spa_name(spa), dump_one_dir,
|
||||||
NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
|
NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
|
||||||
|
|
||||||
if (feature_get_refcount(spa,
|
for (f = 0; f < SPA_FEATURES; f++) {
|
||||||
&spa_feature_table[SPA_FEATURE_LARGE_BLOCKS],
|
uint64_t refcount;
|
||||||
&refcount) != ENOTSUP) {
|
|
||||||
if (num_large_blocks != refcount) {
|
if (!(spa_feature_table[f].fi_flags &
|
||||||
(void) printf("large_blocks feature refcount "
|
ZFEATURE_FLAG_PER_DATASET)) {
|
||||||
"mismatch: expected %lld != actual %lld\n",
|
ASSERT0(dataset_feature_count[f]);
|
||||||
(longlong_t)num_large_blocks,
|
continue;
|
||||||
|
}
|
||||||
|
if (feature_get_refcount(spa, &spa_feature_table[f],
|
||||||
|
&refcount) == ENOTSUP)
|
||||||
|
continue;
|
||||||
|
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);
|
(longlong_t)refcount);
|
||||||
rc = 2;
|
rc = 2;
|
||||||
} else {
|
} else {
|
||||||
(void) printf("Verified large_blocks feature "
|
(void) printf("Verified %s feature refcount "
|
||||||
"refcount is correct (%llu)\n",
|
"of %llu is correct\n",
|
||||||
|
spa_feature_table[f].fi_uname,
|
||||||
(longlong_t)refcount);
|
(longlong_t)refcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* 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);
|
feature_enable_sync(spa, feature, tx);
|
||||||
|
|
||||||
spa_history_log_internal(spa, "zhack enable feature", tx,
|
spa_history_log_internal(spa, "zhack enable feature", tx,
|
||||||
"name=%s can_readonly=%u",
|
"name=%s flags=%u",
|
||||||
feature->fi_guid, feature->fi_can_readonly);
|
feature->fi_guid, feature->fi_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -314,9 +314,7 @@ zhack_do_feature_enable(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
desc = NULL;
|
desc = NULL;
|
||||||
feature.fi_uname = "zhack";
|
feature.fi_uname = "zhack";
|
||||||
feature.fi_mos = B_FALSE;
|
feature.fi_flags = 0;
|
||||||
feature.fi_can_readonly = B_FALSE;
|
|
||||||
feature.fi_activate_on_enable = B_FALSE;
|
|
||||||
feature.fi_depends = nodeps;
|
feature.fi_depends = nodeps;
|
||||||
feature.fi_feature = SPA_FEATURE_NONE;
|
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) {
|
while ((c = getopt(argc, argv, "rmd:")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'r':
|
case 'r':
|
||||||
feature.fi_can_readonly = B_TRUE;
|
feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
desc = strdup(optarg);
|
desc = strdup(optarg);
|
||||||
@ -413,7 +411,7 @@ zhack_do_feature_ref(int argc, char **argv)
|
|||||||
* disk later.
|
* disk later.
|
||||||
*/
|
*/
|
||||||
feature.fi_uname = "zhack";
|
feature.fi_uname = "zhack";
|
||||||
feature.fi_mos = B_FALSE;
|
feature.fi_flags = 0;
|
||||||
feature.fi_desc = NULL;
|
feature.fi_desc = NULL;
|
||||||
feature.fi_depends = nodeps;
|
feature.fi_depends = nodeps;
|
||||||
feature.fi_feature = SPA_FEATURE_NONE;
|
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) {
|
while ((c = getopt(argc, argv, "md")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'm':
|
case 'm':
|
||||||
feature.fi_mos = B_TRUE;
|
feature.fi_flags |= ZFEATURE_FLAG_MOS;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
decr = B_TRUE;
|
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,
|
if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
|
||||||
feature.fi_guid)) {
|
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,
|
} else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
|
||||||
feature.fi_guid)) {
|
feature.fi_guid)) {
|
||||||
feature.fi_can_readonly = B_TRUE;
|
feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
|
||||||
} else {
|
} else {
|
||||||
fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
|
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2011 Nexenta Systems, Inc. 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 by Frederik Wessels. All rights reserved.
|
||||||
* Copyright (c) 2012 by Cyril Plisko. All rights reserved.
|
* Copyright (c) 2012 by Cyril Plisko. All rights reserved.
|
||||||
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
|
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
|
||||||
@ -5105,7 +5105,8 @@ zpool_do_upgrade(int argc, char **argv)
|
|||||||
"---------------\n");
|
"---------------\n");
|
||||||
for (i = 0; i < SPA_FEATURES; i++) {
|
for (i = 0; i < SPA_FEATURES; i++) {
|
||||||
zfeature_info_t *fi = &spa_feature_table[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)" : "";
|
" (read-only compatible)" : "";
|
||||||
|
|
||||||
(void) printf("%-37s%s\n", fi->fi_uname, ro);
|
(void) printf("%-37s%s\n", fi->fi_uname, ro);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2013 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, Joyent, Inc. All rights reserved.
|
||||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||||
@ -38,6 +38,7 @@
|
|||||||
#include <sys/zfs_context.h>
|
#include <sys/zfs_context.h>
|
||||||
#include <sys/dsl_deadlist.h>
|
#include <sys/dsl_deadlist.h>
|
||||||
#include <sys/refcount.h>
|
#include <sys/refcount.h>
|
||||||
|
#include <zfeature_common.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -145,8 +146,6 @@ typedef struct dsl_dataset {
|
|||||||
/* only used in syncing context, only valid for non-snapshots: */
|
/* only used in syncing context, only valid for non-snapshots: */
|
||||||
struct dsl_dataset *ds_prev;
|
struct dsl_dataset *ds_prev;
|
||||||
uint64_t ds_bookmarks; /* DMU_OTN_ZAP_METADATA */
|
uint64_t ds_bookmarks; /* DMU_OTN_ZAP_METADATA */
|
||||||
boolean_t ds_large_blocks;
|
|
||||||
boolean_t ds_need_large_blocks;
|
|
||||||
|
|
||||||
/* has internal locking: */
|
/* has internal locking: */
|
||||||
dsl_deadlist_t ds_deadlist;
|
dsl_deadlist_t ds_deadlist;
|
||||||
@ -185,6 +184,18 @@ typedef struct dsl_dataset {
|
|||||||
kmutex_t ds_sendstream_lock;
|
kmutex_t ds_sendstream_lock;
|
||||||
list_t ds_sendstreams;
|
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 */
|
/* Protected by ds_lock; keep at end of struct for better locality */
|
||||||
char ds_snapname[MAXNAMELEN];
|
char ds_snapname[MAXNAMELEN];
|
||||||
} dsl_dataset_t;
|
} 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,
|
int dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, dsl_dataset_t *last,
|
||||||
uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
|
uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
|
||||||
boolean_t dsl_dataset_is_dirty(dsl_dataset_t *ds);
|
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);
|
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);
|
void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx);
|
||||||
int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result);
|
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
|
#ifdef ZFS_DEBUG
|
||||||
#define dprintf_ds(ds, fmt, ...) do { \
|
#define dprintf_ds(ds, fmt, ...) do { \
|
||||||
if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
|
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.
|
||||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -55,15 +55,23 @@ typedef enum spa_feature {
|
|||||||
|
|
||||||
#define SPA_FEATURE_DISABLED (-1ULL)
|
#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 {
|
typedef struct zfeature_info {
|
||||||
spa_feature_t fi_feature;
|
spa_feature_t fi_feature;
|
||||||
const char *fi_uname; /* User-facing feature name */
|
const char *fi_uname; /* User-facing feature name */
|
||||||
const char *fi_guid; /* On-disk feature identifier */
|
const char *fi_guid; /* On-disk feature identifier */
|
||||||
const char *fi_desc; /* Feature description */
|
const char *fi_desc; /* Feature description */
|
||||||
boolean_t fi_can_readonly; /* Can open pool readonly w/o support? */
|
zfeature_flags_t fi_flags;
|
||||||
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;
|
|
||||||
/* array of dependencies, terminated by SPA_FEATURE_NONE */
|
/* array of dependencies, terminated by SPA_FEATURE_NONE */
|
||||||
const spa_feature_t *fi_depends;
|
const spa_feature_t *fi_depends;
|
||||||
} zfeature_info_t;
|
} zfeature_info_t;
|
||||||
|
@ -1615,6 +1615,11 @@ dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
|
|||||||
struct dirty_leaf *dl;
|
struct dirty_leaf *dl;
|
||||||
dmu_object_type_t type;
|
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);
|
DB_DNODE_ENTER(db);
|
||||||
type = DB_DNODE(db)->dn_type;
|
type = DB_DNODE(db)->dn_type;
|
||||||
DB_DNODE_EXIT(db);
|
DB_DNODE_EXIT(db);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||||
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
|
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
|
||||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||||
@ -611,7 +611,7 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (large_block_ok && ds->ds_large_blocks)
|
if (large_block_ok && ds->ds_feature_inuse[SPA_FEATURE_LARGE_BLOCKS])
|
||||||
featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
|
featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
|
||||||
if (embedok &&
|
if (embedok &&
|
||||||
spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) {
|
spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) {
|
||||||
@ -1226,13 +1226,6 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
|
|||||||
}
|
}
|
||||||
VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds));
|
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);
|
dmu_buf_will_dirty(newds->ds_dbuf, tx);
|
||||||
dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
|
dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2013 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, Joyent, Inc. All rights reserved.
|
||||||
* Copyright (c) 2014 RackTop Systems.
|
* Copyright (c) 2014 RackTop Systems.
|
||||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||||
@ -126,8 +126,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_compressed_bytes += compressed;
|
||||||
dsl_dataset_phys(ds)->ds_uncompressed_bytes += uncompressed;
|
dsl_dataset_phys(ds)->ds_uncompressed_bytes += uncompressed;
|
||||||
dsl_dataset_phys(ds)->ds_unique_bytes += used;
|
dsl_dataset_phys(ds)->ds_unique_bytes += used;
|
||||||
if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE)
|
if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE) {
|
||||||
ds->ds_need_large_blocks = B_TRUE;
|
ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_BLOCKS] =
|
||||||
|
B_TRUE;
|
||||||
|
}
|
||||||
mutex_exit(&ds->ds_lock);
|
mutex_exit(&ds->ds_lock);
|
||||||
dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
|
dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
|
||||||
compressed, uncompressed, tx);
|
compressed, uncompressed, tx);
|
||||||
@ -432,19 +434,25 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
|
|||||||
offsetof(dmu_sendarg_t, dsa_link));
|
offsetof(dmu_sendarg_t, dsa_link));
|
||||||
|
|
||||||
if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
|
if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
|
||||||
int zaperr = zap_contains(mos, dsobj,
|
spa_feature_t f;
|
||||||
DS_FIELD_LARGE_BLOCKS);
|
|
||||||
if (zaperr != ENOENT) {
|
for (f = 0; f < SPA_FEATURES; f++) {
|
||||||
VERIFY0(zaperr);
|
if (!(spa_feature_table[f].fi_flags &
|
||||||
ds->ds_large_blocks = B_TRUE;
|
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,
|
||||||
err = dsl_dir_hold_obj(dp,
|
dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds, &ds->ds_dir);
|
||||||
dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds,
|
|
||||||
&ds->ds_dir);
|
|
||||||
}
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
mutex_destroy(&ds->ds_lock);
|
mutex_destroy(&ds->ds_lock);
|
||||||
mutex_destroy(&ds->ds_opening_lock);
|
mutex_destroy(&ds->ds_opening_lock);
|
||||||
@ -698,6 +706,34 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
|
|||||||
return (gotit);
|
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
|
uint64_t
|
||||||
dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
|
dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
|
||||||
uint64_t flags, dmu_tx_t *tx)
|
uint64_t flags, dmu_tx_t *tx)
|
||||||
@ -736,6 +772,7 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
|
|||||||
if (origin == NULL) {
|
if (origin == NULL) {
|
||||||
dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx);
|
dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx);
|
||||||
} else {
|
} else {
|
||||||
|
spa_feature_t f;
|
||||||
dsl_dataset_t *ohds; /* head of the origin snapshot */
|
dsl_dataset_t *ohds; /* head of the origin snapshot */
|
||||||
|
|
||||||
dsphys->ds_prev_snap_obj = origin->ds_object;
|
dsphys->ds_prev_snap_obj = origin->ds_object;
|
||||||
@ -756,8 +793,10 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
|
|||||||
dsphys->ds_flags |= dsl_dataset_phys(origin)->ds_flags &
|
dsphys->ds_flags |= dsl_dataset_phys(origin)->ds_flags &
|
||||||
(DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
|
(DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
|
||||||
|
|
||||||
if (origin->ds_large_blocks)
|
for (f = 0; f < SPA_FEATURES; f++) {
|
||||||
dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
|
if (origin->ds_feature_inuse[f])
|
||||||
|
dsl_dataset_activate_feature(dsobj, f, tx);
|
||||||
|
}
|
||||||
|
|
||||||
dmu_buf_will_dirty(origin->ds_dbuf, tx);
|
dmu_buf_will_dirty(origin->ds_dbuf, tx);
|
||||||
dsl_dataset_phys(origin)->ds_num_children++;
|
dsl_dataset_phys(origin)->ds_num_children++;
|
||||||
@ -1233,6 +1272,7 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
|
|||||||
dsl_dataset_phys_t *dsphys;
|
dsl_dataset_phys_t *dsphys;
|
||||||
uint64_t dsobj, crtxg;
|
uint64_t dsobj, crtxg;
|
||||||
objset_t *mos = dp->dp_meta_objset;
|
objset_t *mos = dp->dp_meta_objset;
|
||||||
|
spa_feature_t f;
|
||||||
ASSERTV(static zil_header_t zero_zil);
|
ASSERTV(static zil_header_t zero_zil);
|
||||||
ASSERTV(objset_t *os);
|
ASSERTV(objset_t *os);
|
||||||
|
|
||||||
@ -1282,8 +1322,10 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
|
|||||||
dsphys->ds_bp = dsl_dataset_phys(ds)->ds_bp;
|
dsphys->ds_bp = dsl_dataset_phys(ds)->ds_bp;
|
||||||
dmu_buf_rele(dbuf, FTAG);
|
dmu_buf_rele(dbuf, FTAG);
|
||||||
|
|
||||||
if (ds->ds_large_blocks)
|
for (f = 0; f < SPA_FEATURES; f++) {
|
||||||
dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
|
if (ds->ds_feature_inuse[f])
|
||||||
|
dsl_dataset_activate_feature(dsobj, f, tx);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT3U(ds->ds_prev != 0, ==,
|
ASSERT3U(ds->ds_prev != 0, ==,
|
||||||
dsl_dataset_phys(ds)->ds_prev_snap_obj != 0);
|
dsl_dataset_phys(ds)->ds_prev_snap_obj != 0);
|
||||||
@ -1561,6 +1603,8 @@ dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname,
|
|||||||
void
|
void
|
||||||
dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
|
dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
|
||||||
{
|
{
|
||||||
|
spa_feature_t f;
|
||||||
|
|
||||||
ASSERT(dmu_tx_is_syncing(tx));
|
ASSERT(dmu_tx_is_syncing(tx));
|
||||||
ASSERT(ds->ds_objset != NULL);
|
ASSERT(ds->ds_objset != NULL);
|
||||||
ASSERT(dsl_dataset_phys(ds)->ds_next_snap_obj == 0);
|
ASSERT(dsl_dataset_phys(ds)->ds_next_snap_obj == 0);
|
||||||
@ -1574,9 +1618,13 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
|
|||||||
|
|
||||||
dmu_objset_sync(ds->ds_objset, zio, tx);
|
dmu_objset_sync(ds->ds_objset, zio, tx);
|
||||||
|
|
||||||
if (ds->ds_need_large_blocks && !ds->ds_large_blocks) {
|
for (f = 0; f < SPA_FEATURES; f++) {
|
||||||
dsl_dataset_activate_large_blocks_sync_impl(ds->ds_object, tx);
|
if (ds->ds_feature_activation_needed[f]) {
|
||||||
ds->ds_large_blocks = B_TRUE;
|
if (ds->ds_feature_inuse[f])
|
||||||
|
continue;
|
||||||
|
dsl_dataset_activate_feature(ds->ds_object, f, tx);
|
||||||
|
ds->ds_feature_inuse[f] = B_TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2703,6 +2751,7 @@ void
|
|||||||
dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
|
dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
|
||||||
dsl_dataset_t *origin_head, dmu_tx_t *tx)
|
dsl_dataset_t *origin_head, dmu_tx_t *tx)
|
||||||
{
|
{
|
||||||
|
spa_feature_t f;
|
||||||
dsl_pool_t *dp = dmu_tx_pool(tx);
|
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||||
int64_t unused_refres_delta;
|
int64_t unused_refres_delta;
|
||||||
|
|
||||||
@ -2711,6 +2760,43 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
|
|||||||
dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
|
dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
|
||||||
ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
|
ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Swap per-dataset feature flags.
|
||||||
|
*/
|
||||||
|
for (f = 0; f < SPA_FEATURES; f++) {
|
||||||
|
boolean_t clone_inuse;
|
||||||
|
boolean_t origin_head_inuse;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone_inuse = clone->ds_feature_inuse[f];
|
||||||
|
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(clone->ds_dbuf, tx);
|
||||||
dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
|
dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
|
||||||
|
|
||||||
@ -3265,77 +3351,6 @@ dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
|
|||||||
return (err);
|
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.
|
* Return TRUE if 'earlier' is an earlier snapshot in 'later's timeline.
|
||||||
* For example, they could both be snapshots of the same filesystem, and
|
* For example, they could both be snapshots of the same filesystem, and
|
||||||
@ -3380,7 +3395,6 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier,
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
|
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) 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 Steven Hartland. All rights reserved.
|
||||||
* Copyright (c) 2013 by Joyent, Inc. All rights reserved.
|
* Copyright (c) 2013 by Joyent, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
@ -246,6 +246,7 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
|
|||||||
#ifdef ZFS_DEBUG
|
#ifdef ZFS_DEBUG
|
||||||
int err;
|
int err;
|
||||||
#endif
|
#endif
|
||||||
|
spa_feature_t f;
|
||||||
int after_branch_point = FALSE;
|
int after_branch_point = FALSE;
|
||||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||||
objset_t *mos = dp->dp_meta_objset;
|
objset_t *mos = dp->dp_meta_objset;
|
||||||
@ -277,9 +278,11 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
|
|||||||
|
|
||||||
obj = ds->ds_object;
|
obj = ds->ds_object;
|
||||||
|
|
||||||
if (ds->ds_large_blocks) {
|
for (f = 0; f < SPA_FEATURES; f++) {
|
||||||
ASSERT0(zap_contains(mos, obj, DS_FIELD_LARGE_BLOCKS));
|
if (ds->ds_feature_inuse[f]) {
|
||||||
spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
|
dsl_dataset_deactivate_feature(obj, f, tx);
|
||||||
|
ds->ds_feature_inuse[f] = B_FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
|
if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
|
||||||
ASSERT3P(ds->ds_prev, ==, NULL);
|
ASSERT3P(ds->ds_prev, ==, NULL);
|
||||||
@ -715,6 +718,7 @@ void
|
|||||||
dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
|
dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||||
{
|
{
|
||||||
dsl_pool_t *dp = dmu_tx_pool(tx);
|
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||||
|
spa_feature_t f;
|
||||||
objset_t *mos = dp->dp_meta_objset;
|
objset_t *mos = dp->dp_meta_objset;
|
||||||
uint64_t obj, ddobj, prevobj = 0;
|
uint64_t obj, ddobj, prevobj = 0;
|
||||||
boolean_t rmorigin;
|
boolean_t rmorigin;
|
||||||
@ -742,13 +746,17 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
|
|||||||
ASSERT0(ds->ds_reserved);
|
ASSERT0(ds->ds_reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ds->ds_large_blocks)
|
obj = ds->ds_object;
|
||||||
spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
|
|
||||||
|
for (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);
|
dsl_scan_ds_destroyed(ds, tx);
|
||||||
|
|
||||||
obj = ds->ds_object;
|
|
||||||
|
|
||||||
if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
|
if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
|
||||||
/* This is a clone */
|
/* This is a clone */
|
||||||
ASSERT(ds->ds_prev != NULL);
|
ASSERT(ds->ds_prev != NULL);
|
||||||
|
@ -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>
|
#include <sys/zfs_context.h>
|
||||||
@ -253,7 +253,7 @@ feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
uint64_t refcount;
|
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;
|
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -306,7 +306,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
|
|||||||
uint64_t zapobj;
|
uint64_t zapobj;
|
||||||
|
|
||||||
ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature));
|
ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature));
|
||||||
zapobj = feature->fi_can_readonly ?
|
zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||||
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
||||||
VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid,
|
VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid,
|
||||||
sizeof (uint64_t), 1, &refcount, tx));
|
sizeof (uint64_t), 1, &refcount, tx));
|
||||||
@ -327,7 +327,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
|
|||||||
|
|
||||||
if (refcount == 0)
|
if (refcount == 0)
|
||||||
spa_deactivate_mos_feature(spa, feature->fi_guid);
|
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);
|
spa_activate_mos_feature(spa, feature->fi_guid, tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,8 +338,9 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
|
|||||||
void
|
void
|
||||||
feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
|
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 initial_refcount =
|
||||||
uint64_t zapobj = feature->fi_can_readonly ?
|
(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;
|
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -385,7 +386,8 @@ feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
|
|||||||
{
|
{
|
||||||
uint64_t refcount = 0;
|
uint64_t refcount = 0;
|
||||||
zfeature_info_t *feature = &spa_feature_table[fid];
|
zfeature_info_t *feature = &spa_feature_table[fid];
|
||||||
ASSERTV(uint64_t zapobj = feature->fi_can_readonly ?
|
ASSERTV(uint64_t zapobj =
|
||||||
|
(feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||||
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj);
|
spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj);
|
||||||
|
|
||||||
ASSERT(VALID_FEATURE_FID(fid));
|
ASSERT(VALID_FEATURE_FID(fid));
|
||||||
|
@ -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 by Saso Kiselkov. All rights reserved.
|
||||||
* Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
|
* Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
@ -135,15 +135,15 @@ zfeature_depends_on(spa_feature_t fid, spa_feature_t check) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
|
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
|
||||||
const char *desc, boolean_t readonly, boolean_t mos,
|
const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
|
||||||
boolean_t activate_on_enable, const spa_feature_t *deps)
|
|
||||||
{
|
{
|
||||||
zfeature_info_t *feature = &spa_feature_table[fid];
|
zfeature_info_t *feature = &spa_feature_table[fid];
|
||||||
static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
|
static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
|
||||||
|
|
||||||
ASSERT(name != NULL);
|
ASSERT(name != NULL);
|
||||||
ASSERT(desc != NULL);
|
ASSERT(desc != NULL);
|
||||||
ASSERT(!readonly || !mos);
|
ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
|
||||||
|
(flags & ZFEATURE_FLAG_MOS) == 0);
|
||||||
ASSERT3U(fid, <, SPA_FEATURES);
|
ASSERT3U(fid, <, SPA_FEATURES);
|
||||||
ASSERT(zfeature_is_valid_guid(guid));
|
ASSERT(zfeature_is_valid_guid(guid));
|
||||||
|
|
||||||
@ -154,9 +154,7 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
|
|||||||
feature->fi_guid = guid;
|
feature->fi_guid = guid;
|
||||||
feature->fi_uname = name;
|
feature->fi_uname = name;
|
||||||
feature->fi_desc = desc;
|
feature->fi_desc = desc;
|
||||||
feature->fi_can_readonly = readonly;
|
feature->fi_flags = flags;
|
||||||
feature->fi_mos = mos;
|
|
||||||
feature->fi_activate_on_enable = activate_on_enable;
|
|
||||||
feature->fi_depends = deps;
|
feature->fi_depends = deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,28 +163,28 @@ zpool_feature_init(void)
|
|||||||
{
|
{
|
||||||
zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
|
zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
|
||||||
"com.delphix:async_destroy", "async_destroy",
|
"com.delphix:async_destroy", "async_destroy",
|
||||||
"Destroy filesystems asynchronously.", B_TRUE, B_FALSE,
|
"Destroy filesystems asynchronously.",
|
||||||
B_FALSE, NULL);
|
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||||
|
|
||||||
zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
|
zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
|
||||||
"com.delphix:empty_bpobj", "empty_bpobj",
|
"com.delphix:empty_bpobj", "empty_bpobj",
|
||||||
"Snapshots use less space.", B_TRUE, B_FALSE,
|
"Snapshots use less space.",
|
||||||
B_FALSE, NULL);
|
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||||
|
|
||||||
zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
|
zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
|
||||||
"org.illumos:lz4_compress", "lz4_compress",
|
"org.illumos:lz4_compress", "lz4_compress",
|
||||||
"LZ4 compression algorithm support.", B_FALSE, B_FALSE,
|
"LZ4 compression algorithm support.",
|
||||||
B_TRUE, NULL);
|
ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
|
||||||
|
|
||||||
zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
|
zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
|
||||||
"com.delphix:spacemap_histogram", "spacemap_histogram",
|
"com.delphix:spacemap_histogram", "spacemap_histogram",
|
||||||
"Spacemaps maintain space histograms.", B_TRUE, B_FALSE,
|
"Spacemaps maintain space histograms.",
|
||||||
B_FALSE, NULL);
|
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||||
|
|
||||||
zfeature_register(SPA_FEATURE_ENABLED_TXG,
|
zfeature_register(SPA_FEATURE_ENABLED_TXG,
|
||||||
"com.delphix:enabled_txg", "enabled_txg",
|
"com.delphix:enabled_txg", "enabled_txg",
|
||||||
"Record txg at which a feature is enabled", B_TRUE, B_FALSE,
|
"Record txg at which a feature is enabled",
|
||||||
B_FALSE, NULL);
|
ZFEATURE_FLAG_READONLY_COMPAT, NULL);
|
||||||
|
|
||||||
{
|
{
|
||||||
static const spa_feature_t hole_birth_deps[] = {
|
static const spa_feature_t hole_birth_deps[] = {
|
||||||
@ -196,13 +194,14 @@ zpool_feature_init(void)
|
|||||||
zfeature_register(SPA_FEATURE_HOLE_BIRTH,
|
zfeature_register(SPA_FEATURE_HOLE_BIRTH,
|
||||||
"com.delphix:hole_birth", "hole_birth",
|
"com.delphix:hole_birth", "hole_birth",
|
||||||
"Retain hole birth txg for more precise zfs send",
|
"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,
|
zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||||
"com.delphix:extensible_dataset", "extensible_dataset",
|
"com.delphix:extensible_dataset", "extensible_dataset",
|
||||||
"Enhanced dataset functionality, used by other features.",
|
"Enhanced dataset functionality, used by other features.",
|
||||||
B_FALSE, B_FALSE, B_FALSE, NULL);
|
0, NULL);
|
||||||
|
|
||||||
{
|
{
|
||||||
static const spa_feature_t bookmarks_deps[] = {
|
static const spa_feature_t bookmarks_deps[] = {
|
||||||
@ -213,7 +212,7 @@ zpool_feature_init(void)
|
|||||||
zfeature_register(SPA_FEATURE_BOOKMARKS,
|
zfeature_register(SPA_FEATURE_BOOKMARKS,
|
||||||
"com.delphix:bookmarks", "bookmarks",
|
"com.delphix:bookmarks", "bookmarks",
|
||||||
"\"zfs bookmark\" command",
|
"\"zfs bookmark\" command",
|
||||||
B_TRUE, B_FALSE, B_FALSE, bookmarks_deps);
|
ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -223,14 +222,15 @@ zpool_feature_init(void)
|
|||||||
};
|
};
|
||||||
zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
|
zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
|
||||||
"com.joyent:filesystem_limits", "filesystem_limits",
|
"com.joyent:filesystem_limits", "filesystem_limits",
|
||||||
"Filesystem and snapshot limits.", B_TRUE, B_FALSE, B_FALSE,
|
"Filesystem and snapshot limits.",
|
||||||
filesystem_limits_deps);
|
ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
|
zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
|
||||||
"com.delphix:embedded_data", "embedded_data",
|
"com.delphix:embedded_data", "embedded_data",
|
||||||
"Blocks which compress very well use even less space.",
|
"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[] = {
|
static const spa_feature_t large_blocks_deps[] = {
|
||||||
@ -239,7 +239,7 @@ zpool_feature_init(void)
|
|||||||
};
|
};
|
||||||
zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
|
zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
|
||||||
"org.open-zfs:large_blocks", "large_blocks",
|
"org.open-zfs:large_blocks", "large_blocks",
|
||||||
"Support for blocks larger than 128KB.", B_FALSE, B_FALSE, B_FALSE,
|
"Support for blocks larger than 128KB.",
|
||||||
large_blocks_deps);
|
ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user