diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index f050f36e21..6b5ec42019 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -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. * Copyright (c) 2015, Intel Corporation. */ @@ -2274,7 +2274,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 @@ -2282,14 +2282,22 @@ dump_one_dir(const char *dsname, void *arg) { int error; objset_t *os; + spa_feature_t f; error = dmu_objset_own(dsname, DMU_OST_ANY, B_TRUE, FTAG, &os); if (error) { (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 (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(); @@ -3094,7 +3102,7 @@ dump_zpool(spa_t *spa) dump_metaslab_groups(spa); if (dump_opt['d'] || dump_opt['i']) { - uint64_t refcount; + spa_feature_t f; dump_dir(dp->dp_meta_objset); if (dump_opt['d'] >= 3) { @@ -3117,18 +3125,28 @@ dump_zpool(spa_t *spa) (void) dmu_objset_find(spa_name(spa), dump_one_dir, NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN); - if (feature_get_refcount(spa, - &spa_feature_table[SPA_FEATURE_LARGE_BLOCKS], - &refcount) != ENOTSUP) { - if (num_large_blocks != refcount) { - (void) printf("large_blocks feature refcount " - "mismatch: expected %lld != actual %lld\n", - (longlong_t)num_large_blocks, + for (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; + } + 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); rc = 2; } else { - (void) printf("Verified large_blocks feature " - "refcount is correct (%llu)\n", + (void) printf("Verified %s feature refcount " + "of %llu is correct\n", + spa_feature_table[f].fi_uname, (longlong_t)refcount); } } diff --git a/cmd/zhack/zhack.c b/cmd/zhack/zhack.c index 3f86714fe3..a7da371c8a 100644 --- a/cmd/zhack/zhack.c +++ b/cmd/zhack/zhack.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); + "name=%s flags=%u", + 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); } diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index f32efcef27..8cb9c861cb 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -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 by Cyril Plisko. 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"); 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); diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index d6da5dcfdb..25622263e6 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) 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 Steven Hartland. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. @@ -38,6 +38,7 @@ #include #include #include +#include #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) { \ diff --git a/include/zfeature_common.h b/include/zfeature_common.h index e383c4ff78..d481a28a8f 100644 --- a/include/zfeature_common.h +++ b/include/zfeature_common.h @@ -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. */ @@ -55,15 +55,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; diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index d340da821f..31242d6015 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -1615,6 +1615,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); diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index b2d844eb42..8e79dc70db 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -20,7 +20,7 @@ */ /* * 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 (c) 2014, Joyent, Inc. 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 - 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; if (embedok && 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)); - 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; diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 2168f28941..829452b1d2 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -20,7 +20,7 @@ */ /* * 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 RackTop Systems. * 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_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); @@ -432,19 +434,25 @@ 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; + spa_feature_t f; + + for (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); @@ -698,6 +706,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) @@ -736,6 +772,7 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, if (origin == NULL) { dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx); } else { + spa_feature_t f; dsl_dataset_t *ohds; /* head of the origin snapshot */ 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 & (DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET); - if (origin->ds_large_blocks) - dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx); + for (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++; @@ -1233,6 +1272,7 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname, dsl_dataset_phys_t *dsphys; uint64_t dsobj, crtxg; objset_t *mos = dp->dp_meta_objset; + spa_feature_t f; ASSERTV(static zil_header_t zero_zil); 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; dmu_buf_rele(dbuf, FTAG); - if (ds->ds_large_blocks) - dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx); + for (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); @@ -1561,6 +1603,8 @@ dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname, void 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(ds->ds_objset != NULL); 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); - 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 (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; + } } } @@ -2703,6 +2751,7 @@ void dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone, dsl_dataset_t *origin_head, dmu_tx_t *tx) { + spa_feature_t f; dsl_pool_t *dp = dmu_tx_pool(tx); 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); 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(origin_head->ds_dbuf, tx); @@ -3265,77 +3351,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 @@ -3380,7 +3395,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) { diff --git a/module/zfs/dsl_destroy.c b/module/zfs/dsl_destroy.c index 0e2238f99e..e45f46d8da 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, 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. */ @@ -246,6 +246,7 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx) #ifdef ZFS_DEBUG int err; #endif + spa_feature_t f; int after_branch_point = FALSE; dsl_pool_t *dp = ds->ds_dir->dd_pool; 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; - 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 (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); @@ -715,6 +718,7 @@ void dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx) { dsl_pool_t *dp = dmu_tx_pool(tx); + spa_feature_t f; objset_t *mos = dp->dp_meta_objset; uint64_t obj, ddobj, prevobj = 0; boolean_t rmorigin; @@ -742,13 +746,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 (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); diff --git a/module/zfs/zfeature.c b/module/zfs/zfeature.c index 352376f22b..bda9548293 100644 --- a/module/zfs/zfeature.c +++ b/module/zfs/zfeature.c @@ -20,7 +20,7 @@ */ /* - * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2011, 2015 by Delphix. All rights reserved. */ #include @@ -253,7 +253,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; /* @@ -306,7 +306,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount, uint64_t zapobj; 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; VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid, 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) 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); } @@ -338,8 +338,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; int i; @@ -385,7 +386,8 @@ feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action, { uint64_t refcount = 0; 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); ASSERT(VALID_FEATURE_FID(fid)); diff --git a/module/zfs/zfeature_common.c b/module/zfs/zfeature_common.c index 609a72ab30..f57e5489ca 100644 --- a/module/zfs/zfeature_common.c +++ b/module/zfs/zfeature_common.c @@ -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) 2014, Nexenta Systems, Inc. All rights reserved. */ @@ -135,15 +135,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)); @@ -154,9 +154,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; } @@ -165,28 +163,28 @@ 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_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 const spa_feature_t hole_birth_deps[] = { @@ -196,13 +194,14 @@ zpool_feature_init(void) 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[] = { @@ -213,7 +212,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); } { @@ -223,14 +222,15 @@ 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[] = { @@ -239,7 +239,7 @@ 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); } }