Print this page
4171 clean up spa_feature_*() interfaces
4172 implement extensible_dataset feature for use by other zpool features
Reviewed by: Max Grossman <max.grossman@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
*** 159,185 ****
* decremented back to 0 to indicate that it has undone its on-disk format
* changes.
*/
typedef enum {
- FEATURE_ACTION_ENABLE,
FEATURE_ACTION_INCR,
FEATURE_ACTION_DECR,
} feature_action_t;
/*
! * Checks that the features active in the specified object are supported by
* this software. Adds each unsupported feature (name -> description) to
* the supplied nvlist.
*/
boolean_t
! feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
nvlist_t *unsup_feat, nvlist_t *enabled_feat)
{
boolean_t supported;
zap_cursor_t zc;
zap_attribute_t za;
supported = B_TRUE;
for (zap_cursor_init(&zc, os, obj);
zap_cursor_retrieve(&zc, &za) == 0;
zap_cursor_advance(&zc)) {
--- 159,187 ----
* decremented back to 0 to indicate that it has undone its on-disk format
* changes.
*/
typedef enum {
FEATURE_ACTION_INCR,
FEATURE_ACTION_DECR,
} feature_action_t;
/*
! * Checks that the active features in the pool are supported by
* this software. Adds each unsupported feature (name -> description) to
* the supplied nvlist.
*/
boolean_t
! spa_features_check(spa_t *spa, boolean_t for_write,
nvlist_t *unsup_feat, nvlist_t *enabled_feat)
{
+ objset_t *os = spa->spa_meta_objset;
boolean_t supported;
zap_cursor_t zc;
zap_attribute_t za;
+ uint64_t obj = for_write ?
+ spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
supported = B_TRUE;
for (zap_cursor_init(&zc, os, obj);
zap_cursor_retrieve(&zc, &za) == 0;
zap_cursor_advance(&zc)) {
*** 197,208 ****
if (NULL != unsup_feat) {
char *desc = "";
char buf[MAXPATHLEN];
! if (zap_lookup(os, desc_obj, za.za_name,
! 1, sizeof (buf), buf) == 0)
desc = buf;
VERIFY(nvlist_add_string(unsup_feat, za.za_name,
desc) == 0);
}
--- 199,210 ----
if (NULL != unsup_feat) {
char *desc = "";
char buf[MAXPATHLEN];
! if (zap_lookup(os, spa->spa_feat_desc_obj,
! za.za_name, 1, sizeof (buf), buf) == 0)
desc = buf;
VERIFY(nvlist_add_string(unsup_feat, za.za_name,
desc) == 0);
}
*** 211,237 ****
zap_cursor_fini(&zc);
return (supported);
}
! static int
! feature_get_refcount(objset_t *os, uint64_t read_obj, uint64_t write_obj,
! zfeature_info_t *feature, uint64_t *res)
{
int err;
uint64_t refcount;
! uint64_t zapobj = feature->fi_can_readonly ? write_obj : read_obj;
/*
* If the pool is currently being created, the feature objects may not
* have been allocated yet. Act as though all features are disabled.
*/
if (zapobj == 0)
return (SET_ERROR(ENOTSUP));
! err = zap_lookup(os, zapobj, feature->fi_guid, sizeof (uint64_t), 1,
! &refcount);
if (err != 0) {
if (err == ENOENT)
return (SET_ERROR(ENOTSUP));
else
return (err);
--- 213,244 ----
zap_cursor_fini(&zc);
return (supported);
}
! /*
! * Note: well-designed features will not need to use this; they should
! * use spa_feature_is_enabled() and spa_feature_is_active() instead.
! * However, this is non-static for zdb and zhack.
! */
! int
! feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res)
{
int err;
uint64_t refcount;
! uint64_t zapobj = feature->fi_can_readonly ?
! spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
/*
* If the pool is currently being created, the feature objects may not
* have been allocated yet. Act as though all features are disabled.
*/
if (zapobj == 0)
return (SET_ERROR(ENOTSUP));
! err = zap_lookup(spa->spa_meta_objset, zapobj,
! feature->fi_guid, sizeof (uint64_t), 1, &refcount);
if (err != 0) {
if (err == ENOENT)
return (SET_ERROR(ENOTSUP));
else
return (err);
*** 238,333 ****
}
*res = refcount;
return (0);
}
! static int
! feature_do_action(objset_t *os, uint64_t read_obj, uint64_t write_obj,
! uint64_t desc_obj, zfeature_info_t *feature, feature_action_t action,
dmu_tx_t *tx)
{
! int error;
! uint64_t refcount;
! uint64_t zapobj = feature->fi_can_readonly ? write_obj : read_obj;
! ASSERT(0 != zapobj);
! ASSERT(zfeature_is_valid_guid(feature->fi_guid));
! error = zap_lookup(os, zapobj, feature->fi_guid,
! sizeof (uint64_t), 1, &refcount);
! /*
! * If we can't ascertain the status of the specified feature, an I/O
! * error occurred.
*/
! if (error != 0 && error != ENOENT)
! return (error);
! switch (action) {
! case FEATURE_ACTION_ENABLE:
/*
* If the feature is already enabled, ignore the request.
*/
! if (error == 0)
! return (0);
! refcount = 0;
! break;
case FEATURE_ACTION_INCR:
! if (error == ENOENT)
! return (SET_ERROR(ENOTSUP));
! if (refcount == UINT64_MAX)
! return (SET_ERROR(EOVERFLOW));
refcount++;
break;
case FEATURE_ACTION_DECR:
! if (error == ENOENT)
! return (SET_ERROR(ENOTSUP));
! if (refcount == 0)
! return (SET_ERROR(EOVERFLOW));
refcount--;
break;
default:
ASSERT(0);
break;
}
! if (action == FEATURE_ACTION_ENABLE) {
! int i;
!
! for (i = 0; feature->fi_depends[i] != NULL; i++) {
! zfeature_info_t *dep = feature->fi_depends[i];
!
! error = feature_do_action(os, read_obj, write_obj,
! desc_obj, dep, FEATURE_ACTION_ENABLE, tx);
! if (error != 0)
! return (error);
! }
! }
!
! error = zap_update(os, zapobj, feature->fi_guid,
! sizeof (uint64_t), 1, &refcount, tx);
! if (error != 0)
! return (error);
!
! if (action == FEATURE_ACTION_ENABLE) {
! error = zap_update(os, desc_obj,
! feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
! feature->fi_desc, tx);
! if (error != 0)
! return (error);
! }
!
! if (action == FEATURE_ACTION_INCR && refcount == 1 && feature->fi_mos) {
! spa_activate_mos_feature(dmu_objset_spa(os), feature->fi_guid);
! }
!
! if (action == FEATURE_ACTION_DECR && refcount == 0) {
! spa_deactivate_mos_feature(dmu_objset_spa(os),
! feature->fi_guid);
! }
!
! return (0);
}
void
spa_feature_create_zap_objects(spa_t *spa, dmu_tx_t *tx)
{
--- 245,337 ----
}
*res = refcount;
return (0);
}
! /*
! * This function is non-static for zhack; it should otherwise not be used
! * outside this file.
! */
! void
! feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
dmu_tx_t *tx)
{
! uint64_t zapobj = feature->fi_can_readonly ?
! 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));
! if (refcount == 0)
! spa_deactivate_mos_feature(spa, feature->fi_guid);
! else if (feature->fi_mos)
! spa_activate_mos_feature(spa, feature->fi_guid);
! }
! /*
! * This function is non-static for zhack; it should otherwise not be used
! * outside this file.
*/
! void
! feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
! {
! uint64_t zapobj = feature->fi_can_readonly ?
! spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
! ASSERT(0 != zapobj);
! ASSERT(zfeature_is_valid_guid(feature->fi_guid));
! ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
!
/*
* If the feature is already enabled, ignore the request.
*/
! if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
! return;
!
! for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++)
! spa_feature_enable(spa, feature->fi_depends[i], tx);
!
! VERIFY0(zap_update(spa->spa_meta_objset, spa->spa_feat_desc_obj,
! feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
! feature->fi_desc, tx));
! feature_sync(spa, feature, 0, tx);
! }
!
! static void
! feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
! dmu_tx_t *tx)
! {
! uint64_t refcount;
! zfeature_info_t *feature = &spa_feature_table[fid];
! uint64_t zapobj = feature->fi_can_readonly ?
! spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
!
! ASSERT3U(fid, <, SPA_FEATURES);
! ASSERT(0 != zapobj);
! ASSERT(zfeature_is_valid_guid(feature->fi_guid));
!
! ASSERT(dmu_tx_is_syncing(tx));
! ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
!
! VERIFY0(zap_lookup(spa->spa_meta_objset, zapobj, feature->fi_guid,
! sizeof (uint64_t), 1, &refcount));
!
! switch (action) {
case FEATURE_ACTION_INCR:
! VERIFY3U(refcount, !=, UINT64_MAX);
refcount++;
break;
case FEATURE_ACTION_DECR:
! VERIFY3U(refcount, !=, 0);
refcount--;
break;
default:
ASSERT(0);
break;
}
! feature_sync(spa, feature, refcount, tx);
}
void
spa_feature_create_zap_objects(spa_t *spa, dmu_tx_t *tx)
{
*** 351,434 ****
/*
* Enable any required dependencies, then enable the requested feature.
*/
void
! spa_feature_enable(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
{
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
! VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
! spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
! spa->spa_feat_desc_obj, feature, FEATURE_ACTION_ENABLE, tx));
}
void
! spa_feature_incr(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
{
! ASSERT(dmu_tx_is_syncing(tx));
! ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
! VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
! spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
! spa->spa_feat_desc_obj, feature, FEATURE_ACTION_INCR, tx));
}
void
! spa_feature_decr(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
{
! ASSERT(dmu_tx_is_syncing(tx));
! ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
! VERIFY3U(0, ==, feature_do_action(spa->spa_meta_objset,
! spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
! spa->spa_feat_desc_obj, feature, FEATURE_ACTION_DECR, tx));
}
- /*
- * This interface is for debugging only. Normal consumers should use
- * spa_feature_is_enabled/spa_feature_is_active.
- */
- int
- spa_feature_get_refcount(spa_t *spa, zfeature_info_t *feature)
- {
- int err;
- uint64_t refcount;
-
- if (spa_version(spa) < SPA_VERSION_FEATURES)
- return (B_FALSE);
-
- err = feature_get_refcount(spa->spa_meta_objset,
- spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
- feature, &refcount);
- ASSERT(err == 0 || err == ENOTSUP);
- return (err == 0 ? refcount : 0);
- }
-
boolean_t
! spa_feature_is_enabled(spa_t *spa, zfeature_info_t *feature)
{
int err;
uint64_t refcount;
if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE);
! err = feature_get_refcount(spa->spa_meta_objset,
! spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
! feature, &refcount);
ASSERT(err == 0 || err == ENOTSUP);
return (err == 0);
}
boolean_t
! spa_feature_is_active(spa_t *spa, zfeature_info_t *feature)
{
int err;
uint64_t refcount;
if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE);
! err = feature_get_refcount(spa->spa_meta_objset,
! spa->spa_feat_for_read_obj, spa->spa_feat_for_write_obj,
! feature, &refcount);
ASSERT(err == 0 || err == ENOTSUP);
return (err == 0 && refcount > 0);
}
--- 355,407 ----
/*
* Enable any required dependencies, then enable the requested feature.
*/
void
! spa_feature_enable(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
{
ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
! ASSERT3U(fid, <, SPA_FEATURES);
! feature_enable_sync(spa, &spa_feature_table[fid], tx);
}
void
! spa_feature_incr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
{
! feature_do_action(spa, fid, FEATURE_ACTION_INCR, tx);
}
void
! spa_feature_decr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
{
! feature_do_action(spa, fid, FEATURE_ACTION_DECR, tx);
}
boolean_t
! spa_feature_is_enabled(spa_t *spa, spa_feature_t fid)
{
int err;
uint64_t refcount;
+ ASSERT3U(fid, <, SPA_FEATURES);
if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE);
! err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
ASSERT(err == 0 || err == ENOTSUP);
return (err == 0);
}
boolean_t
! spa_feature_is_active(spa_t *spa, spa_feature_t fid)
{
int err;
uint64_t refcount;
+ ASSERT3U(fid, <, SPA_FEATURES);
if (spa_version(spa) < SPA_VERSION_FEATURES)
return (B_FALSE);
! err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
ASSERT(err == 0 || err == ENOTSUP);
return (err == 0 && refcount > 0);
}