1236884Smm/* 2236884Smm * CDDL HEADER START 3236884Smm * 4236884Smm * The contents of this file are subject to the terms of the 5236884Smm * Common Development and Distribution License (the "License"). 6236884Smm * You may not use this file except in compliance with the License. 7236884Smm * 8236884Smm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9236884Smm * or http://www.opensolaris.org/os/licensing. 10236884Smm * See the License for the specific language governing permissions 11236884Smm * and limitations under the License. 12236884Smm * 13236884Smm * When distributing Covered Code, include this CDDL HEADER in each 14236884Smm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15236884Smm * If applicable, add the following below this CDDL HEADER, with the 16236884Smm * fields enclosed by brackets "[]" replaced with your own identifying 17236884Smm * information: Portions Copyright [yyyy] [name of copyright owner] 18236884Smm * 19236884Smm * CDDL HEADER END 20236884Smm */ 21236884Smm 22236884Smm/* 23249195Smm * Copyright (c) 2013 by Delphix. All rights reserved. 24236884Smm */ 25236884Smm 26236884Smm#include <sys/zfs_context.h> 27236884Smm#include <sys/zfeature.h> 28236884Smm#include <sys/dmu.h> 29236884Smm#include <sys/nvpair.h> 30236884Smm#include <sys/zap.h> 31236884Smm#include <sys/dmu_tx.h> 32236884Smm#include "zfeature_common.h" 33236884Smm#include <sys/spa_impl.h> 34236884Smm 35236884Smm/* 36236884Smm * ZFS Feature Flags 37236884Smm * ----------------- 38236884Smm * 39236884Smm * ZFS feature flags are used to provide fine-grained versioning to the ZFS 40236884Smm * on-disk format. Once enabled on a pool feature flags replace the old 41236884Smm * spa_version() number. 42236884Smm * 43236884Smm * Each new on-disk format change will be given a uniquely identifying string 44236884Smm * guid rather than a version number. This avoids the problem of different 45236884Smm * organizations creating new on-disk formats with the same version number. To 46236884Smm * keep feature guids unique they should consist of the reverse dns name of the 47236884Smm * organization which implemented the feature and a short name for the feature, 48236884Smm * separated by a colon (e.g. com.delphix:async_destroy). 49236884Smm * 50236884Smm * Reference Counts 51236884Smm * ---------------- 52236884Smm * 53236884Smm * Within each pool features can be in one of three states: disabled, enabled, 54236884Smm * or active. These states are differentiated by a reference count stored on 55236884Smm * disk for each feature: 56236884Smm * 57236884Smm * 1) If there is no reference count stored on disk the feature is disabled. 58236884Smm * 2) If the reference count is 0 a system administrator has enabled the 59236884Smm * feature, but the feature has not been used yet, so no on-disk 60236884Smm * format changes have been made. 61236884Smm * 3) If the reference count is greater than 0 the feature is active. 62236884Smm * The format changes required by the feature are currently on disk. 63236884Smm * Note that if the feature's format changes are reversed the feature 64236884Smm * may choose to set its reference count back to 0. 65236884Smm * 66236884Smm * Feature flags makes no differentiation between non-zero reference counts 67236884Smm * for an active feature (e.g. a reference count of 1 means the same thing as a 68236884Smm * reference count of 27834721), but feature implementations may choose to use 69236884Smm * the reference count to store meaningful information. For example, a new RAID 70236884Smm * implementation might set the reference count to the number of vdevs using 71236884Smm * it. If all those disks are removed from the pool the feature goes back to 72236884Smm * having a reference count of 0. 73236884Smm * 74236884Smm * It is the responsibility of the individual features to maintain a non-zero 75236884Smm * reference count as long as the feature's format changes are present on disk. 76236884Smm * 77236884Smm * Dependencies 78236884Smm * ------------ 79236884Smm * 80236884Smm * Each feature may depend on other features. The only effect of this 81236884Smm * relationship is that when a feature is enabled all of its dependencies are 82236884Smm * automatically enabled as well. Any future work to support disabling of 83236884Smm * features would need to ensure that features cannot be disabled if other 84236884Smm * enabled features depend on them. 85236884Smm * 86236884Smm * On-disk Format 87236884Smm * -------------- 88236884Smm * 89236884Smm * When feature flags are enabled spa_version() is set to SPA_VERSION_FEATURES 90236884Smm * (5000). In order for this to work the pool is automatically upgraded to 91236884Smm * SPA_VERSION_BEFORE_FEATURES (28) first, so all pre-feature flags on disk 92236884Smm * format changes will be in use. 93236884Smm * 94236884Smm * Information about features is stored in 3 ZAP objects in the pool's MOS. 95236884Smm * These objects are linked to by the following names in the pool directory 96236884Smm * object: 97236884Smm * 98236884Smm * 1) features_for_read: feature guid -> reference count 99236884Smm * Features needed to open the pool for reading. 100236884Smm * 2) features_for_write: feature guid -> reference count 101236884Smm * Features needed to open the pool for writing. 102236884Smm * 3) feature_descriptions: feature guid -> descriptive string 103236884Smm * A human readable string. 104236884Smm * 105236884Smm * All enabled features appear in either features_for_read or 106236884Smm * features_for_write, but not both. 107236884Smm * 108236884Smm * To open a pool in read-only mode only the features listed in 109236884Smm * features_for_read need to be supported. 110236884Smm * 111236884Smm * To open the pool in read-write mode features in both features_for_read and 112236884Smm * features_for_write need to be supported. 113236884Smm * 114236884Smm * Some features may be required to read the ZAP objects containing feature 115236884Smm * information. To allow software to check for compatibility with these features 116236884Smm * before the pool is opened their names must be stored in the label in a 117236884Smm * new "features_for_read" entry (note that features that are only required 118236884Smm * to write to a pool never need to be stored in the label since the 119236884Smm * features_for_write ZAP object can be read before the pool is written to). 120236884Smm * To save space in the label features must be explicitly marked as needing to 121236884Smm * be written to the label. Also, reference counts are not stored in the label, 122236884Smm * instead any feature whose reference count drops to 0 is removed from the 123236884Smm * label. 124236884Smm * 125236884Smm * Adding New Features 126236884Smm * ------------------- 127236884Smm * 128236884Smm * Features must be registered in zpool_feature_init() function in 129236884Smm * zfeature_common.c using the zfeature_register() function. This function 130236884Smm * has arguments to specify if the feature should be stored in the 131236884Smm * features_for_read or features_for_write ZAP object and if it needs to be 132236884Smm * written to the label when active. 133236884Smm * 134236884Smm * Once a feature is registered it will appear as a "feature@<feature name>" 135236884Smm * property which can be set by an administrator. Feature implementors should 136236884Smm * use the spa_feature_is_enabled() and spa_feature_is_active() functions to 137236884Smm * query the state of a feature and the spa_feature_incr() and 138236884Smm * spa_feature_decr() functions to change an enabled feature's reference count. 139236884Smm * Reference counts may only be updated in the syncing context. 140236884Smm * 141236884Smm * Features may not perform enable-time initialization. Instead, any such 142236884Smm * initialization should occur when the feature is first used. This design 143236884Smm * enforces that on-disk changes be made only when features are used. Code 144236884Smm * should only check if a feature is enabled using spa_feature_is_enabled(), 145236884Smm * not by relying on any feature specific metadata existing. If a feature is 146236884Smm * enabled, but the feature's metadata is not on disk yet then it should be 147236884Smm * created as needed. 148236884Smm * 149236884Smm * As an example, consider the com.delphix:async_destroy feature. This feature 150236884Smm * relies on the existence of a bptree in the MOS that store blocks for 151236884Smm * asynchronous freeing. This bptree is not created when async_destroy is 152236884Smm * enabled. Instead, when a dataset is destroyed spa_feature_is_enabled() is 153236884Smm * called to check if async_destroy is enabled. If it is and the bptree object 154236884Smm * does not exist yet, the bptree object is created as part of the dataset 155236884Smm * destroy and async_destroy's reference count is incremented to indicate it 156236884Smm * has made an on-disk format change. Later, after the destroyed dataset's 157236884Smm * blocks have all been asynchronously freed there is no longer any use for the 158236884Smm * bptree object, so it is destroyed and async_destroy's reference count is 159236884Smm * decremented back to 0 to indicate that it has undone its on-disk format 160236884Smm * changes. 161236884Smm */ 162236884Smm 163236884Smmtypedef enum { 164236884Smm FEATURE_ACTION_INCR, 165236884Smm FEATURE_ACTION_DECR, 166236884Smm} feature_action_t; 167236884Smm 168236884Smm/* 169263390Sdelphij * Checks that the active features in the pool are supported by 170236884Smm * this software. Adds each unsupported feature (name -> description) to 171236884Smm * the supplied nvlist. 172236884Smm */ 173236884Smmboolean_t 174263390Sdelphijspa_features_check(spa_t *spa, boolean_t for_write, 175238926Smm nvlist_t *unsup_feat, nvlist_t *enabled_feat) 176236884Smm{ 177263390Sdelphij objset_t *os = spa->spa_meta_objset; 178236884Smm boolean_t supported; 179236884Smm zap_cursor_t zc; 180236884Smm zap_attribute_t za; 181263390Sdelphij uint64_t obj = for_write ? 182263390Sdelphij spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; 183236884Smm 184236884Smm supported = B_TRUE; 185236884Smm for (zap_cursor_init(&zc, os, obj); 186236884Smm zap_cursor_retrieve(&zc, &za) == 0; 187236884Smm zap_cursor_advance(&zc)) { 188236884Smm ASSERT(za.za_integer_length == sizeof (uint64_t) && 189236884Smm za.za_num_integers == 1); 190236884Smm 191238926Smm if (NULL != enabled_feat) { 192238926Smm fnvlist_add_uint64(enabled_feat, za.za_name, 193238926Smm za.za_first_integer); 194238926Smm } 195238926Smm 196236884Smm if (za.za_first_integer != 0 && 197236884Smm !zfeature_is_supported(za.za_name)) { 198236884Smm supported = B_FALSE; 199236884Smm 200238926Smm if (NULL != unsup_feat) { 201236884Smm char *desc = ""; 202236884Smm char buf[MAXPATHLEN]; 203236884Smm 204263390Sdelphij if (zap_lookup(os, spa->spa_feat_desc_obj, 205263390Sdelphij za.za_name, 1, sizeof (buf), buf) == 0) 206236884Smm desc = buf; 207236884Smm 208236884Smm VERIFY(nvlist_add_string(unsup_feat, za.za_name, 209236884Smm desc) == 0); 210236884Smm } 211236884Smm } 212236884Smm } 213236884Smm zap_cursor_fini(&zc); 214236884Smm 215236884Smm return (supported); 216236884Smm} 217236884Smm 218263390Sdelphij/* 219263397Sdelphij * Use an in-memory cache of feature refcounts for quick retrieval. 220263397Sdelphij * 221263390Sdelphij * Note: well-designed features will not need to use this; they should 222263390Sdelphij * use spa_feature_is_enabled() and spa_feature_is_active() instead. 223263390Sdelphij * However, this is non-static for zdb and zhack. 224263390Sdelphij */ 225263390Sdelphijint 226263390Sdelphijfeature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res) 227236884Smm{ 228263397Sdelphij ASSERT(VALID_FEATURE_FID(feature->fi_feature)); 229263397Sdelphij if (spa->spa_feat_refcount_cache[feature->fi_feature] == 230263397Sdelphij SPA_FEATURE_DISABLED) { 231263397Sdelphij return (SET_ERROR(ENOTSUP)); 232263397Sdelphij } 233263397Sdelphij *res = spa->spa_feat_refcount_cache[feature->fi_feature]; 234263397Sdelphij return (0); 235263397Sdelphij} 236263397Sdelphij 237263397Sdelphij/* 238263397Sdelphij * Note: well-designed features will not need to use this; they should 239263397Sdelphij * use spa_feature_is_enabled() and spa_feature_is_active() instead. 240263397Sdelphij * However, this is non-static for zdb and zhack. 241263397Sdelphij */ 242263397Sdelphijint 243263397Sdelphijfeature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature, 244263397Sdelphij uint64_t *res) 245263397Sdelphij{ 246236884Smm int err; 247236884Smm uint64_t refcount; 248263390Sdelphij uint64_t zapobj = feature->fi_can_readonly ? 249263390Sdelphij spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; 250236884Smm 251239774Smm /* 252239774Smm * If the pool is currently being created, the feature objects may not 253239774Smm * have been allocated yet. Act as though all features are disabled. 254239774Smm */ 255239774Smm if (zapobj == 0) 256249195Smm return (SET_ERROR(ENOTSUP)); 257236884Smm 258263390Sdelphij err = zap_lookup(spa->spa_meta_objset, zapobj, 259263390Sdelphij feature->fi_guid, sizeof (uint64_t), 1, &refcount); 260236884Smm if (err != 0) { 261236884Smm if (err == ENOENT) 262249195Smm return (SET_ERROR(ENOTSUP)); 263236884Smm else 264236884Smm return (err); 265236884Smm } 266236884Smm *res = refcount; 267236884Smm return (0); 268236884Smm} 269236884Smm 270263397Sdelphij 271263397Sdelphijstatic int 272263397Sdelphijfeature_get_enabled_txg(spa_t *spa, zfeature_info_t *feature, uint64_t *res) { 273263397Sdelphij uint64_t enabled_txg_obj = spa->spa_feat_enabled_txg_obj; 274263397Sdelphij 275263397Sdelphij ASSERT(zfeature_depends_on(feature->fi_feature, 276263397Sdelphij SPA_FEATURE_ENABLED_TXG)); 277263397Sdelphij 278263397Sdelphij if (!spa_feature_is_enabled(spa, feature->fi_feature)) { 279263397Sdelphij return (SET_ERROR(ENOTSUP)); 280263397Sdelphij } 281263397Sdelphij 282263397Sdelphij ASSERT(enabled_txg_obj != 0); 283263397Sdelphij 284263397Sdelphij VERIFY0(zap_lookup(spa->spa_meta_objset, spa->spa_feat_enabled_txg_obj, 285263397Sdelphij feature->fi_guid, sizeof (uint64_t), 1, res)); 286263397Sdelphij 287263397Sdelphij return (0); 288263397Sdelphij} 289263397Sdelphij 290263390Sdelphij/* 291263390Sdelphij * This function is non-static for zhack; it should otherwise not be used 292263390Sdelphij * outside this file. 293263390Sdelphij */ 294263390Sdelphijvoid 295263390Sdelphijfeature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount, 296236884Smm dmu_tx_t *tx) 297236884Smm{ 298263397Sdelphij ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature)); 299263390Sdelphij uint64_t zapobj = feature->fi_can_readonly ? 300263390Sdelphij spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; 301236884Smm 302263390Sdelphij VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid, 303263390Sdelphij sizeof (uint64_t), 1, &refcount, tx)); 304263390Sdelphij 305263397Sdelphij /* 306263397Sdelphij * feature_sync is called directly from zhack, allowing the 307263397Sdelphij * creation of arbitrary features whose fi_feature field may 308263397Sdelphij * be greater than SPA_FEATURES. When called from zhack, the 309263397Sdelphij * zfeature_info_t object's fi_feature field will be set to 310263397Sdelphij * SPA_FEATURE_NONE. 311263397Sdelphij */ 312263397Sdelphij if (feature->fi_feature != SPA_FEATURE_NONE) { 313263397Sdelphij uint64_t *refcount_cache = 314263397Sdelphij &spa->spa_feat_refcount_cache[feature->fi_feature]; 315263401Sdelphij#ifdef atomic_swap_64 316263397Sdelphij VERIFY3U(*refcount_cache, ==, 317263397Sdelphij atomic_swap_64(refcount_cache, refcount)); 318263401Sdelphij#else 319263401Sdelphij *refcount_cache = refcount; 320263401Sdelphij#endif 321263397Sdelphij } 322263397Sdelphij 323263390Sdelphij if (refcount == 0) 324263390Sdelphij spa_deactivate_mos_feature(spa, feature->fi_guid); 325263390Sdelphij else if (feature->fi_mos) 326263397Sdelphij spa_activate_mos_feature(spa, feature->fi_guid, tx); 327263390Sdelphij} 328263390Sdelphij 329263390Sdelphij/* 330263390Sdelphij * This function is non-static for zhack; it should otherwise not be used 331263390Sdelphij * outside this file. 332263390Sdelphij */ 333263390Sdelphijvoid 334263390Sdelphijfeature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx) 335263390Sdelphij{ 336263397Sdelphij uint64_t initial_refcount = feature->fi_activate_on_enable ? 1 : 0; 337263390Sdelphij uint64_t zapobj = feature->fi_can_readonly ? 338263390Sdelphij spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; 339263390Sdelphij 340236884Smm ASSERT(0 != zapobj); 341236884Smm ASSERT(zfeature_is_valid_guid(feature->fi_guid)); 342263390Sdelphij ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES); 343236884Smm 344236884Smm /* 345263390Sdelphij * If the feature is already enabled, ignore the request. 346236884Smm */ 347263390Sdelphij if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0) 348263390Sdelphij return; 349236884Smm 350263390Sdelphij for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) 351263390Sdelphij spa_feature_enable(spa, feature->fi_depends[i], tx); 352263390Sdelphij 353263390Sdelphij VERIFY0(zap_update(spa->spa_meta_objset, spa->spa_feat_desc_obj, 354263390Sdelphij feature->fi_guid, 1, strlen(feature->fi_desc) + 1, 355263390Sdelphij feature->fi_desc, tx)); 356263397Sdelphij 357263397Sdelphij feature_sync(spa, feature, initial_refcount, tx); 358263397Sdelphij 359263397Sdelphij if (spa_feature_is_enabled(spa, SPA_FEATURE_ENABLED_TXG)) { 360263397Sdelphij uint64_t enabling_txg = dmu_tx_get_txg(tx); 361263397Sdelphij 362263397Sdelphij if (spa->spa_feat_enabled_txg_obj == 0ULL) { 363263397Sdelphij spa->spa_feat_enabled_txg_obj = 364263397Sdelphij zap_create_link(spa->spa_meta_objset, 365263397Sdelphij DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT, 366263397Sdelphij DMU_POOL_FEATURE_ENABLED_TXG, tx); 367263397Sdelphij } 368263397Sdelphij spa_feature_incr(spa, SPA_FEATURE_ENABLED_TXG, tx); 369263397Sdelphij 370263397Sdelphij VERIFY0(zap_add(spa->spa_meta_objset, 371263397Sdelphij spa->spa_feat_enabled_txg_obj, feature->fi_guid, 372263397Sdelphij sizeof (uint64_t), 1, &enabling_txg, tx)); 373263397Sdelphij } 374263390Sdelphij} 375263390Sdelphij 376263390Sdelphijstatic void 377263390Sdelphijfeature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action, 378263390Sdelphij dmu_tx_t *tx) 379263390Sdelphij{ 380263390Sdelphij uint64_t refcount; 381263390Sdelphij zfeature_info_t *feature = &spa_feature_table[fid]; 382263390Sdelphij uint64_t zapobj = feature->fi_can_readonly ? 383263390Sdelphij spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj; 384263390Sdelphij 385263397Sdelphij ASSERT(VALID_FEATURE_FID(fid)); 386263390Sdelphij ASSERT(0 != zapobj); 387263390Sdelphij ASSERT(zfeature_is_valid_guid(feature->fi_guid)); 388263390Sdelphij 389263390Sdelphij ASSERT(dmu_tx_is_syncing(tx)); 390263390Sdelphij ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES); 391263390Sdelphij 392263397Sdelphij VERIFY3U(feature_get_refcount(spa, feature, &refcount), !=, ENOTSUP); 393263390Sdelphij 394236884Smm switch (action) { 395236884Smm case FEATURE_ACTION_INCR: 396263390Sdelphij VERIFY3U(refcount, !=, UINT64_MAX); 397236884Smm refcount++; 398236884Smm break; 399236884Smm case FEATURE_ACTION_DECR: 400263390Sdelphij VERIFY3U(refcount, !=, 0); 401236884Smm refcount--; 402236884Smm break; 403236884Smm default: 404236884Smm ASSERT(0); 405236884Smm break; 406236884Smm } 407236884Smm 408263390Sdelphij feature_sync(spa, feature, refcount, tx); 409236884Smm} 410236884Smm 411236884Smmvoid 412236884Smmspa_feature_create_zap_objects(spa_t *spa, dmu_tx_t *tx) 413236884Smm{ 414236884Smm /* 415236884Smm * We create feature flags ZAP objects in two instances: during pool 416236884Smm * creation and during pool upgrade. 417236884Smm */ 418236884Smm ASSERT(dsl_pool_sync_context(spa_get_dsl(spa)) || (!spa->spa_sync_on && 419236884Smm tx->tx_txg == TXG_INITIAL)); 420236884Smm 421236884Smm spa->spa_feat_for_read_obj = zap_create_link(spa->spa_meta_objset, 422236884Smm DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT, 423236884Smm DMU_POOL_FEATURES_FOR_READ, tx); 424236884Smm spa->spa_feat_for_write_obj = zap_create_link(spa->spa_meta_objset, 425236884Smm DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT, 426236884Smm DMU_POOL_FEATURES_FOR_WRITE, tx); 427236884Smm spa->spa_feat_desc_obj = zap_create_link(spa->spa_meta_objset, 428236884Smm DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT, 429236884Smm DMU_POOL_FEATURE_DESCRIPTIONS, tx); 430236884Smm} 431236884Smm 432236884Smm/* 433236884Smm * Enable any required dependencies, then enable the requested feature. 434236884Smm */ 435236884Smmvoid 436263390Sdelphijspa_feature_enable(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx) 437236884Smm{ 438236884Smm ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES); 439263397Sdelphij ASSERT(VALID_FEATURE_FID(fid)); 440263390Sdelphij feature_enable_sync(spa, &spa_feature_table[fid], tx); 441236884Smm} 442236884Smm 443236884Smmvoid 444263390Sdelphijspa_feature_incr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx) 445236884Smm{ 446263390Sdelphij feature_do_action(spa, fid, FEATURE_ACTION_INCR, tx); 447236884Smm} 448236884Smm 449236884Smmvoid 450263390Sdelphijspa_feature_decr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx) 451236884Smm{ 452263390Sdelphij feature_do_action(spa, fid, FEATURE_ACTION_DECR, tx); 453236884Smm} 454236884Smm 455236884Smmboolean_t 456263390Sdelphijspa_feature_is_enabled(spa_t *spa, spa_feature_t fid) 457236884Smm{ 458236884Smm int err; 459236884Smm uint64_t refcount; 460236884Smm 461263397Sdelphij ASSERT(VALID_FEATURE_FID(fid)); 462236884Smm if (spa_version(spa) < SPA_VERSION_FEATURES) 463236884Smm return (B_FALSE); 464236884Smm 465263390Sdelphij err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount); 466236884Smm ASSERT(err == 0 || err == ENOTSUP); 467236884Smm return (err == 0); 468236884Smm} 469236884Smm 470236884Smmboolean_t 471263390Sdelphijspa_feature_is_active(spa_t *spa, spa_feature_t fid) 472236884Smm{ 473236884Smm int err; 474236884Smm uint64_t refcount; 475236884Smm 476263397Sdelphij ASSERT(VALID_FEATURE_FID(fid)); 477236884Smm if (spa_version(spa) < SPA_VERSION_FEATURES) 478236884Smm return (B_FALSE); 479236884Smm 480263390Sdelphij err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount); 481236884Smm ASSERT(err == 0 || err == ENOTSUP); 482236884Smm return (err == 0 && refcount > 0); 483236884Smm} 484263397Sdelphij 485263397Sdelphij/* 486263397Sdelphij * For the feature specified by fid (which must depend on 487263397Sdelphij * SPA_FEATURE_ENABLED_TXG), return the TXG at which it was enabled in the 488263397Sdelphij * OUT txg argument. 489263397Sdelphij * 490263397Sdelphij * Returns B_TRUE if the feature is enabled, in which case txg will be filled 491263397Sdelphij * with the transaction group in which the specified feature was enabled. 492263397Sdelphij * Returns B_FALSE otherwise (i.e. if the feature is not enabled). 493263397Sdelphij */ 494263397Sdelphijboolean_t 495263397Sdelphijspa_feature_enabled_txg(spa_t *spa, spa_feature_t fid, uint64_t *txg) { 496263397Sdelphij int err; 497263397Sdelphij 498263397Sdelphij ASSERT(VALID_FEATURE_FID(fid)); 499263397Sdelphij if (spa_version(spa) < SPA_VERSION_FEATURES) 500263397Sdelphij return (B_FALSE); 501263397Sdelphij 502263397Sdelphij err = feature_get_enabled_txg(spa, &spa_feature_table[fid], txg); 503263397Sdelphij ASSERT(err == 0 || err == ENOTSUP); 504263397Sdelphij 505263397Sdelphij return (err == 0); 506263397Sdelphij} 507