OpenZFS 6736 - ZFS per-vdev ZAPs
6736 ZFS per-vdev ZAPs Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: John Kennedy <john.kennedy@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Don Brady <don.brady@intel.com> Reviewed by: Dan McDonald <danmcd@omniti.com> References: https://www.illumos.org/issues/6736 https://github.com/openzfs/openzfs/commit/215198a Ported-by: Don Brady <don.brady@intel.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #4515
This commit is contained in:
parent
4cd77889b6
commit
e0ab3ab553
|
@ -266,6 +266,7 @@ AC_CONFIG_FILES([
|
||||||
tests/zfs-tests/tests/functional/threadsappend/Makefile
|
tests/zfs-tests/tests/functional/threadsappend/Makefile
|
||||||
tests/zfs-tests/tests/functional/truncate/Makefile
|
tests/zfs-tests/tests/functional/truncate/Makefile
|
||||||
tests/zfs-tests/tests/functional/userquota/Makefile
|
tests/zfs-tests/tests/functional/userquota/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/vdev_zaps/Makefile
|
||||||
tests/zfs-tests/tests/functional/write_dirs/Makefile
|
tests/zfs-tests/tests/functional/write_dirs/Makefile
|
||||||
tests/zfs-tests/tests/functional/xattr/Makefile
|
tests/zfs-tests/tests/functional/xattr/Makefile
|
||||||
tests/zfs-tests/tests/functional/zvol/Makefile
|
tests/zfs-tests/tests/functional/zvol/Makefile
|
||||||
|
|
|
@ -315,6 +315,7 @@ typedef struct dmu_buf {
|
||||||
#define DMU_POOL_FREE_BPOBJ "free_bpobj"
|
#define DMU_POOL_FREE_BPOBJ "free_bpobj"
|
||||||
#define DMU_POOL_BPTREE_OBJ "bptree_obj"
|
#define DMU_POOL_BPTREE_OBJ "bptree_obj"
|
||||||
#define DMU_POOL_EMPTY_BPOBJ "empty_bpobj"
|
#define DMU_POOL_EMPTY_BPOBJ "empty_bpobj"
|
||||||
|
#define DMU_POOL_VDEV_ZAP_MAP "com.delphix:vdev_zap_map"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate an object from this objset. The range of object numbers
|
* Allocate an object from this objset. The range of object numbers
|
||||||
|
|
|
@ -566,6 +566,9 @@ typedef struct zpool_rewind_policy {
|
||||||
#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read"
|
#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read"
|
||||||
#define ZPOOL_CONFIG_FEATURE_STATS "feature_stats" /* not stored on disk */
|
#define ZPOOL_CONFIG_FEATURE_STATS "feature_stats" /* not stored on disk */
|
||||||
#define ZPOOL_CONFIG_ERRATA "errata" /* not stored on disk */
|
#define ZPOOL_CONFIG_ERRATA "errata" /* not stored on disk */
|
||||||
|
#define ZPOOL_CONFIG_VDEV_TOP_ZAP "com.delphix:vdev_zap_top"
|
||||||
|
#define ZPOOL_CONFIG_VDEV_LEAF_ZAP "com.delphix:vdev_zap_leaf"
|
||||||
|
#define ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS "com.delphix:has_per_vdev_zaps"
|
||||||
/*
|
/*
|
||||||
* The persistent vdev state is stored as separate values rather than a single
|
* The persistent vdev state is stored as separate values rather than a single
|
||||||
* 'vdev_state' entry. This is because a device can be in multiple states, such
|
* 'vdev_state' entry. This is because a device can be in multiple states, such
|
||||||
|
|
|
@ -116,6 +116,12 @@ typedef struct spa_taskqs {
|
||||||
taskq_t **stqs_taskq;
|
taskq_t **stqs_taskq;
|
||||||
} spa_taskqs_t;
|
} spa_taskqs_t;
|
||||||
|
|
||||||
|
typedef enum spa_all_vdev_zap_action {
|
||||||
|
AVZ_ACTION_NONE = 0,
|
||||||
|
AVZ_ACTION_DESTROY, /* Destroy all per-vdev ZAPs and the AVZ. */
|
||||||
|
AVZ_ACTION_REBUILD /* Populate the new AVZ, see spa_avz_rebuild */
|
||||||
|
} spa_avz_action_t;
|
||||||
|
|
||||||
struct spa {
|
struct spa {
|
||||||
/*
|
/*
|
||||||
* Fields protected by spa_namespace_lock.
|
* Fields protected by spa_namespace_lock.
|
||||||
|
@ -251,6 +257,8 @@ struct spa {
|
||||||
uint64_t spa_deadman_calls; /* number of deadman calls */
|
uint64_t spa_deadman_calls; /* number of deadman calls */
|
||||||
hrtime_t spa_sync_starttime; /* starting time of spa_sync */
|
hrtime_t spa_sync_starttime; /* starting time of spa_sync */
|
||||||
uint64_t spa_deadman_synctime; /* deadman expiration timer */
|
uint64_t spa_deadman_synctime; /* deadman expiration timer */
|
||||||
|
uint64_t spa_all_vdev_zaps; /* ZAP of per-vd ZAP obj #s */
|
||||||
|
spa_avz_action_t spa_avz_action; /* destroy/rebuild AVZ? */
|
||||||
uint64_t spa_errata; /* errata issues detected */
|
uint64_t spa_errata; /* errata issues detected */
|
||||||
spa_stats_t spa_stats; /* assorted spa statistics */
|
spa_stats_t spa_stats; /* assorted spa statistics */
|
||||||
hrtime_t spa_ccw_fail_time; /* Conf cache write fail time */
|
hrtime_t spa_ccw_fail_time; /* Conf cache write fail time */
|
||||||
|
|
|
@ -70,6 +70,10 @@ extern void vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg,
|
||||||
extern boolean_t vdev_dtl_required(vdev_t *vd);
|
extern boolean_t vdev_dtl_required(vdev_t *vd);
|
||||||
extern boolean_t vdev_resilver_needed(vdev_t *vd,
|
extern boolean_t vdev_resilver_needed(vdev_t *vd,
|
||||||
uint64_t *minp, uint64_t *maxp);
|
uint64_t *minp, uint64_t *maxp);
|
||||||
|
extern void vdev_destroy_unlink_zap(vdev_t *vd, uint64_t zapobj,
|
||||||
|
dmu_tx_t *tx);
|
||||||
|
extern uint64_t vdev_create_link_zap(vdev_t *vd, dmu_tx_t *tx);
|
||||||
|
extern void vdev_construct_zaps(vdev_t *vd, dmu_tx_t *tx);
|
||||||
|
|
||||||
extern void vdev_hold(vdev_t *);
|
extern void vdev_hold(vdev_t *);
|
||||||
extern void vdev_rele(vdev_t *);
|
extern void vdev_rele(vdev_t *);
|
||||||
|
@ -133,7 +137,8 @@ extern void vdev_state_clean(vdev_t *vd);
|
||||||
typedef enum vdev_config_flag {
|
typedef enum vdev_config_flag {
|
||||||
VDEV_CONFIG_SPARE = 1 << 0,
|
VDEV_CONFIG_SPARE = 1 << 0,
|
||||||
VDEV_CONFIG_L2CACHE = 1 << 1,
|
VDEV_CONFIG_L2CACHE = 1 << 1,
|
||||||
VDEV_CONFIG_REMOVING = 1 << 2
|
VDEV_CONFIG_REMOVING = 1 << 2,
|
||||||
|
VDEV_CONFIG_MOS = 1 << 3
|
||||||
} vdev_config_flag_t;
|
} vdev_config_flag_t;
|
||||||
|
|
||||||
extern void vdev_top_config_generate(spa_t *spa, nvlist_t *config);
|
extern void vdev_top_config_generate(spa_t *spa, nvlist_t *config);
|
||||||
|
|
|
@ -177,6 +177,7 @@ struct vdev {
|
||||||
uint64_t vdev_islog; /* is an intent log device */
|
uint64_t vdev_islog; /* is an intent log device */
|
||||||
uint64_t vdev_removing; /* device is being removed? */
|
uint64_t vdev_removing; /* device is being removed? */
|
||||||
boolean_t vdev_ishole; /* is a hole in the namespace */
|
boolean_t vdev_ishole; /* is a hole in the namespace */
|
||||||
|
uint64_t vdev_top_zap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Leaf vdev state.
|
* Leaf vdev state.
|
||||||
|
@ -215,6 +216,7 @@ struct vdev {
|
||||||
spa_aux_vdev_t *vdev_aux; /* for l2cache and spares vdevs */
|
spa_aux_vdev_t *vdev_aux; /* for l2cache and spares vdevs */
|
||||||
zio_t *vdev_probe_zio; /* root of current probe */
|
zio_t *vdev_probe_zio; /* root of current probe */
|
||||||
vdev_aux_t vdev_label_aux; /* on-disk aux state */
|
vdev_aux_t vdev_label_aux; /* on-disk aux state */
|
||||||
|
uint64_t vdev_leaf_zap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For DTrace to work in userland (libzpool) context, these fields must
|
* For DTrace to work in userland (libzpool) context, these fields must
|
||||||
|
|
234
module/zfs/spa.c
234
module/zfs/spa.c
|
@ -1674,6 +1674,21 @@ spa_check_removed(vdev_t *vd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spa_config_valid_zaps(vdev_t *vd, vdev_t *mvd)
|
||||||
|
{
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
ASSERT3U(vd->vdev_children, ==, mvd->vdev_children);
|
||||||
|
|
||||||
|
vd->vdev_top_zap = mvd->vdev_top_zap;
|
||||||
|
vd->vdev_leaf_zap = mvd->vdev_leaf_zap;
|
||||||
|
|
||||||
|
for (i = 0; i < vd->vdev_children; i++) {
|
||||||
|
spa_config_valid_zaps(vd->vdev_child[i], mvd->vdev_child[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate the current config against the MOS config
|
* Validate the current config against the MOS config
|
||||||
*/
|
*/
|
||||||
|
@ -1778,16 +1793,25 @@ spa_config_valid(spa_t *spa, nvlist_t *config)
|
||||||
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
|
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
|
||||||
|
|
||||||
vdev_reopen(rvd);
|
vdev_reopen(rvd);
|
||||||
} else if (mtvd->vdev_islog) {
|
} else {
|
||||||
|
if (mtvd->vdev_islog) {
|
||||||
|
/*
|
||||||
|
* Load the slog device's state from the MOS
|
||||||
|
* config since it's possible that the label
|
||||||
|
* does not contain the most up-to-date
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
|
vdev_load_log_state(tvd, mtvd);
|
||||||
|
vdev_reopen(tvd);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load the slog device's state from the MOS config
|
* Per-vdev ZAP info is stored exclusively in the MOS.
|
||||||
* since it's possible that the label does not
|
|
||||||
* contain the most up-to-date information.
|
|
||||||
*/
|
*/
|
||||||
vdev_load_log_state(tvd, mtvd);
|
spa_config_valid_zaps(tvd, mtvd);
|
||||||
vdev_reopen(tvd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vdev_free(mrvd);
|
vdev_free(mrvd);
|
||||||
spa_config_exit(spa, SCL_ALL, FTAG);
|
spa_config_exit(spa, SCL_ALL, FTAG);
|
||||||
|
|
||||||
|
@ -2214,6 +2238,36 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type,
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count the number of per-vdev ZAPs associated with all of the vdevs in the
|
||||||
|
* vdev tree rooted in the given vd, and ensure that each ZAP is present in the
|
||||||
|
* spa's per-vdev ZAP list.
|
||||||
|
*/
|
||||||
|
static uint64_t
|
||||||
|
vdev_count_verify_zaps(vdev_t *vd)
|
||||||
|
{
|
||||||
|
spa_t *spa = vd->vdev_spa;
|
||||||
|
uint64_t total = 0;
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
if (vd->vdev_top_zap != 0) {
|
||||||
|
total++;
|
||||||
|
ASSERT0(zap_lookup_int(spa->spa_meta_objset,
|
||||||
|
spa->spa_all_vdev_zaps, vd->vdev_top_zap));
|
||||||
|
}
|
||||||
|
if (vd->vdev_leaf_zap != 0) {
|
||||||
|
total++;
|
||||||
|
ASSERT0(zap_lookup_int(spa->spa_meta_objset,
|
||||||
|
spa->spa_all_vdev_zaps, vd->vdev_leaf_zap));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < vd->vdev_children; i++) {
|
||||||
|
total += vdev_count_verify_zaps(vd->vdev_child[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load an existing storage pool, using the pool's builtin spa_config as a
|
* Load an existing storage pool, using the pool's builtin spa_config as a
|
||||||
* source of configuration information.
|
* source of configuration information.
|
||||||
|
@ -2234,6 +2288,7 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
|
||||||
int parse, i;
|
int parse, i;
|
||||||
uint64_t obj;
|
uint64_t obj;
|
||||||
boolean_t missing_feat_write = B_FALSE;
|
boolean_t missing_feat_write = B_FALSE;
|
||||||
|
nvlist_t *mos_config;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is an untrusted config, access the pool in read-only mode.
|
* If this is an untrusted config, access the pool in read-only mode.
|
||||||
|
@ -2632,6 +2687,38 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
|
||||||
if (error != 0 && error != ENOENT)
|
if (error != 0 && error != ENOENT)
|
||||||
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
|
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the per-vdev ZAP map. If we have an older pool, this will not
|
||||||
|
* be present; in this case, defer its creation to a later time to
|
||||||
|
* avoid dirtying the MOS this early / out of sync context. See
|
||||||
|
* spa_sync_config_object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The sentinel is only available in the MOS config. */
|
||||||
|
if (load_nvlist(spa, spa->spa_config_object, &mos_config) != 0)
|
||||||
|
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
|
||||||
|
|
||||||
|
error = spa_dir_prop(spa, DMU_POOL_VDEV_ZAP_MAP,
|
||||||
|
&spa->spa_all_vdev_zaps);
|
||||||
|
|
||||||
|
if (error != ENOENT && error != 0) {
|
||||||
|
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
|
||||||
|
} else if (error == 0 && !nvlist_exists(mos_config,
|
||||||
|
ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS)) {
|
||||||
|
/*
|
||||||
|
* An older version of ZFS overwrote the sentinel value, so
|
||||||
|
* we have orphaned per-vdev ZAPs in the MOS. Defer their
|
||||||
|
* destruction to later; see spa_sync_config_object.
|
||||||
|
*/
|
||||||
|
spa->spa_avz_action = AVZ_ACTION_DESTROY;
|
||||||
|
/*
|
||||||
|
* We're assuming that no vdevs have had their ZAPs created
|
||||||
|
* before this. Better be sure of it.
|
||||||
|
*/
|
||||||
|
ASSERT0(vdev_count_verify_zaps(spa->spa_root_vdev));
|
||||||
|
}
|
||||||
|
nvlist_free(mos_config);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're assembling the pool from the split-off vdevs of
|
* If we're assembling the pool from the split-off vdevs of
|
||||||
* an existing pool, we don't want to attach the spares & cache
|
* an existing pool, we don't want to attach the spares & cache
|
||||||
|
@ -5170,6 +5257,16 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
|
||||||
vml[c]->vdev_top->vdev_asize) == 0);
|
vml[c]->vdev_top->vdev_asize) == 0);
|
||||||
VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_ASHIFT,
|
VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_ASHIFT,
|
||||||
vml[c]->vdev_top->vdev_ashift) == 0);
|
vml[c]->vdev_top->vdev_ashift) == 0);
|
||||||
|
|
||||||
|
/* transfer per-vdev ZAPs */
|
||||||
|
ASSERT3U(vml[c]->vdev_leaf_zap, !=, 0);
|
||||||
|
VERIFY0(nvlist_add_uint64(child[c],
|
||||||
|
ZPOOL_CONFIG_VDEV_LEAF_ZAP, vml[c]->vdev_leaf_zap));
|
||||||
|
|
||||||
|
ASSERT3U(vml[c]->vdev_top->vdev_top_zap, !=, 0);
|
||||||
|
VERIFY0(nvlist_add_uint64(child[c],
|
||||||
|
ZPOOL_CONFIG_VDEV_TOP_ZAP,
|
||||||
|
vml[c]->vdev_parent->vdev_top_zap));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
@ -5211,11 +5308,13 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
|
||||||
spa->spa_config_txg) == 0);
|
spa->spa_config_txg) == 0);
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
||||||
spa_generate_guid(NULL)) == 0);
|
spa_generate_guid(NULL)) == 0);
|
||||||
|
VERIFY0(nvlist_add_boolean(config, ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS));
|
||||||
(void) nvlist_lookup_string(props,
|
(void) nvlist_lookup_string(props,
|
||||||
zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
|
zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
|
||||||
|
|
||||||
/* add the new pool to the namespace */
|
/* add the new pool to the namespace */
|
||||||
newspa = spa_add(newname, config, altroot);
|
newspa = spa_add(newname, config, altroot);
|
||||||
|
newspa->spa_avz_action = AVZ_ACTION_REBUILD;
|
||||||
newspa->spa_config_txg = spa->spa_config_txg;
|
newspa->spa_config_txg = spa->spa_config_txg;
|
||||||
spa_set_log_state(newspa, SPA_LOG_CLEAR);
|
spa_set_log_state(newspa, SPA_LOG_CLEAR);
|
||||||
|
|
||||||
|
@ -5273,9 +5372,11 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
spa_history_log_internal(spa, "detach", tx,
|
spa_history_log_internal(spa, "detach", tx,
|
||||||
"vdev=%s", vml[c]->vdev_path);
|
"vdev=%s", vml[c]->vdev_path);
|
||||||
|
|
||||||
vdev_free(vml[c]);
|
vdev_free(vml[c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spa->spa_avz_action = AVZ_ACTION_REBUILD;
|
||||||
vdev_config_dirty(spa->spa_root_vdev);
|
vdev_config_dirty(spa->spa_root_vdev);
|
||||||
spa->spa_config_splitting = NULL;
|
spa->spa_config_splitting = NULL;
|
||||||
nvlist_free(nvl);
|
nvlist_free(nvl);
|
||||||
|
@ -6109,16 +6210,120 @@ spa_sync_aux_dev(spa_t *spa, spa_aux_vdev_t *sav, dmu_tx_t *tx,
|
||||||
sav->sav_sync = B_FALSE;
|
sav->sav_sync = B_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rebuild spa's all-vdev ZAP from the vdev ZAPs indicated in each vdev_t.
|
||||||
|
* The all-vdev ZAP must be empty.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
spa_avz_build(vdev_t *vd, uint64_t avz, dmu_tx_t *tx)
|
||||||
|
{
|
||||||
|
spa_t *spa = vd->vdev_spa;
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
if (vd->vdev_top_zap != 0) {
|
||||||
|
VERIFY0(zap_add_int(spa->spa_meta_objset, avz,
|
||||||
|
vd->vdev_top_zap, tx));
|
||||||
|
}
|
||||||
|
if (vd->vdev_leaf_zap != 0) {
|
||||||
|
VERIFY0(zap_add_int(spa->spa_meta_objset, avz,
|
||||||
|
vd->vdev_leaf_zap, tx));
|
||||||
|
}
|
||||||
|
for (i = 0; i < vd->vdev_children; i++) {
|
||||||
|
spa_avz_build(vd->vdev_child[i], avz, tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
spa_sync_config_object(spa_t *spa, dmu_tx_t *tx)
|
spa_sync_config_object(spa_t *spa, dmu_tx_t *tx)
|
||||||
{
|
{
|
||||||
nvlist_t *config;
|
nvlist_t *config;
|
||||||
|
|
||||||
if (list_is_empty(&spa->spa_config_dirty_list))
|
/*
|
||||||
|
* If the pool is being imported from a pre-per-vdev-ZAP version of ZFS,
|
||||||
|
* its config may not be dirty but we still need to build per-vdev ZAPs.
|
||||||
|
* Similarly, if the pool is being assembled (e.g. after a split), we
|
||||||
|
* need to rebuild the AVZ although the config may not be dirty.
|
||||||
|
*/
|
||||||
|
if (list_is_empty(&spa->spa_config_dirty_list) &&
|
||||||
|
spa->spa_avz_action == AVZ_ACTION_NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
|
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
|
||||||
|
|
||||||
|
ASSERT(spa->spa_avz_action == AVZ_ACTION_NONE ||
|
||||||
|
spa->spa_all_vdev_zaps != 0);
|
||||||
|
|
||||||
|
if (spa->spa_avz_action == AVZ_ACTION_REBUILD) {
|
||||||
|
zap_cursor_t zc;
|
||||||
|
zap_attribute_t za;
|
||||||
|
|
||||||
|
/* Make and build the new AVZ */
|
||||||
|
uint64_t new_avz = zap_create(spa->spa_meta_objset,
|
||||||
|
DMU_OTN_ZAP_METADATA, DMU_OT_NONE, 0, tx);
|
||||||
|
spa_avz_build(spa->spa_root_vdev, new_avz, tx);
|
||||||
|
|
||||||
|
/* Diff old AVZ with new one */
|
||||||
|
for (zap_cursor_init(&zc, spa->spa_meta_objset,
|
||||||
|
spa->spa_all_vdev_zaps);
|
||||||
|
zap_cursor_retrieve(&zc, &za) == 0;
|
||||||
|
zap_cursor_advance(&zc)) {
|
||||||
|
uint64_t vdzap = za.za_first_integer;
|
||||||
|
if (zap_lookup_int(spa->spa_meta_objset, new_avz,
|
||||||
|
vdzap) == ENOENT) {
|
||||||
|
/*
|
||||||
|
* ZAP is listed in old AVZ but not in new one;
|
||||||
|
* destroy it
|
||||||
|
*/
|
||||||
|
VERIFY0(zap_destroy(spa->spa_meta_objset, vdzap,
|
||||||
|
tx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zap_cursor_fini(&zc);
|
||||||
|
|
||||||
|
/* Destroy the old AVZ */
|
||||||
|
VERIFY0(zap_destroy(spa->spa_meta_objset,
|
||||||
|
spa->spa_all_vdev_zaps, tx));
|
||||||
|
|
||||||
|
/* Replace the old AVZ in the dir obj with the new one */
|
||||||
|
VERIFY0(zap_update(spa->spa_meta_objset,
|
||||||
|
DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_VDEV_ZAP_MAP,
|
||||||
|
sizeof (new_avz), 1, &new_avz, tx));
|
||||||
|
|
||||||
|
spa->spa_all_vdev_zaps = new_avz;
|
||||||
|
} else if (spa->spa_avz_action == AVZ_ACTION_DESTROY) {
|
||||||
|
zap_cursor_t zc;
|
||||||
|
zap_attribute_t za;
|
||||||
|
|
||||||
|
/* Walk through the AVZ and destroy all listed ZAPs */
|
||||||
|
for (zap_cursor_init(&zc, spa->spa_meta_objset,
|
||||||
|
spa->spa_all_vdev_zaps);
|
||||||
|
zap_cursor_retrieve(&zc, &za) == 0;
|
||||||
|
zap_cursor_advance(&zc)) {
|
||||||
|
uint64_t zap = za.za_first_integer;
|
||||||
|
VERIFY0(zap_destroy(spa->spa_meta_objset, zap, tx));
|
||||||
|
}
|
||||||
|
|
||||||
|
zap_cursor_fini(&zc);
|
||||||
|
|
||||||
|
/* Destroy and unlink the AVZ itself */
|
||||||
|
VERIFY0(zap_destroy(spa->spa_meta_objset,
|
||||||
|
spa->spa_all_vdev_zaps, tx));
|
||||||
|
VERIFY0(zap_remove(spa->spa_meta_objset,
|
||||||
|
DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_VDEV_ZAP_MAP, tx));
|
||||||
|
spa->spa_all_vdev_zaps = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spa->spa_all_vdev_zaps == 0) {
|
||||||
|
spa->spa_all_vdev_zaps = zap_create_link(spa->spa_meta_objset,
|
||||||
|
DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT,
|
||||||
|
DMU_POOL_VDEV_ZAP_MAP, tx);
|
||||||
|
}
|
||||||
|
spa->spa_avz_action = AVZ_ACTION_NONE;
|
||||||
|
|
||||||
|
/* Create ZAPs for vdevs that don't have them. */
|
||||||
|
vdev_construct_zaps(spa->spa_root_vdev, tx);
|
||||||
|
|
||||||
config = spa_config_generate(spa, spa->spa_root_vdev,
|
config = spa_config_generate(spa, spa->spa_root_vdev,
|
||||||
dmu_tx_get_txg(tx), B_FALSE);
|
dmu_tx_get_txg(tx), B_FALSE);
|
||||||
|
|
||||||
|
@ -6509,6 +6714,21 @@ spa_sync(spa_t *spa, uint64_t txg)
|
||||||
|
|
||||||
} while (dmu_objset_is_dirty(mos, txg));
|
} while (dmu_objset_is_dirty(mos, txg));
|
||||||
|
|
||||||
|
if (!list_is_empty(&spa->spa_config_dirty_list)) {
|
||||||
|
/*
|
||||||
|
* Make sure that the number of ZAPs for all the vdevs matches
|
||||||
|
* the number of ZAPs in the per-vdev ZAP list. This only gets
|
||||||
|
* called if the config is dirty; otherwise there may be
|
||||||
|
* outstanding AVZ operations that weren't completed in
|
||||||
|
* spa_sync_config_object.
|
||||||
|
*/
|
||||||
|
uint64_t all_vdev_zap_entry_count;
|
||||||
|
ASSERT0(zap_count(spa->spa_meta_objset,
|
||||||
|
spa->spa_all_vdev_zaps, &all_vdev_zap_entry_count));
|
||||||
|
ASSERT3U(vdev_count_verify_zaps(spa->spa_root_vdev), ==,
|
||||||
|
all_vdev_zap_entry_count);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rewrite the vdev configuration (which includes the uberblock)
|
* Rewrite the vdev configuration (which includes the uberblock)
|
||||||
* to commit the transaction group.
|
* to commit the transaction group.
|
||||||
|
|
|
@ -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) 2013 by Delphix. All rights reserved.
|
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/spa.h>
|
#include <sys/spa.h>
|
||||||
|
@ -129,7 +129,7 @@ spa_config_load(void)
|
||||||
if (nvpair_type(nvpair) != DATA_TYPE_NVLIST)
|
if (nvpair_type(nvpair) != DATA_TYPE_NVLIST)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
VERIFY(nvpair_value_nvlist(nvpair, &child) == 0);
|
child = fnvpair_value_nvlist(nvpair);
|
||||||
|
|
||||||
if (spa_lookup(nvpair_name(nvpair)) != NULL)
|
if (spa_lookup(nvpair_name(nvpair)) != NULL)
|
||||||
continue;
|
continue;
|
||||||
|
@ -167,14 +167,9 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
|
||||||
/*
|
/*
|
||||||
* Pack the configuration into a buffer.
|
* Pack the configuration into a buffer.
|
||||||
*/
|
*/
|
||||||
VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);
|
buf = fnvlist_pack(nvl, &buflen);
|
||||||
|
|
||||||
buf = vmem_alloc(buflen, KM_SLEEP);
|
|
||||||
temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
|
temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
|
||||||
|
|
||||||
VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR,
|
|
||||||
KM_SLEEP) == 0);
|
|
||||||
|
|
||||||
#if defined(__linux__) && defined(_KERNEL)
|
#if defined(__linux__) && defined(_KERNEL)
|
||||||
/*
|
/*
|
||||||
* Write the configuration to disk. Due to the complexity involved
|
* Write the configuration to disk. Due to the complexity involved
|
||||||
|
@ -216,7 +211,7 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
|
||||||
(void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
|
(void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vmem_free(buf, buflen);
|
fnvlist_pack_free(buf, buflen);
|
||||||
kmem_free(temp, MAXPATHLEN);
|
kmem_free(temp, MAXPATHLEN);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
@ -282,17 +277,15 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nvl == NULL)
|
if (nvl == NULL)
|
||||||
VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME,
|
nvl = fnvlist_alloc();
|
||||||
KM_SLEEP) == 0);
|
|
||||||
|
|
||||||
if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
|
if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME)
|
||||||
VERIFY0(nvlist_lookup_string(spa->spa_config,
|
pool_name = fnvlist_lookup_string(
|
||||||
ZPOOL_CONFIG_POOL_NAME, &pool_name));
|
spa->spa_config, ZPOOL_CONFIG_POOL_NAME);
|
||||||
} else
|
else
|
||||||
pool_name = spa_name(spa);
|
pool_name = spa_name(spa);
|
||||||
|
|
||||||
VERIFY(nvlist_add_nvlist(nvl, pool_name,
|
fnvlist_add_nvlist(nvl, pool_name, spa->spa_config);
|
||||||
spa->spa_config) == 0);
|
|
||||||
mutex_exit(&spa->spa_props_lock);
|
mutex_exit(&spa->spa_props_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,15 +347,15 @@ spa_all_configs(uint64_t *generation)
|
||||||
if (*generation == spa_config_generation)
|
if (*generation == spa_config_generation)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
VERIFY(nvlist_alloc(&pools, NV_UNIQUE_NAME, KM_SLEEP) == 0);
|
pools = fnvlist_alloc();
|
||||||
|
|
||||||
mutex_enter(&spa_namespace_lock);
|
mutex_enter(&spa_namespace_lock);
|
||||||
while ((spa = spa_next(spa)) != NULL) {
|
while ((spa = spa_next(spa)) != NULL) {
|
||||||
if (INGLOBALZONE(curproc) ||
|
if (INGLOBALZONE(curproc) ||
|
||||||
zone_dataset_visible(spa_name(spa), NULL)) {
|
zone_dataset_visible(spa_name(spa), NULL)) {
|
||||||
mutex_enter(&spa->spa_props_lock);
|
mutex_enter(&spa->spa_props_lock);
|
||||||
VERIFY(nvlist_add_nvlist(pools, spa_name(spa),
|
fnvlist_add_nvlist(pools, spa_name(spa),
|
||||||
spa->spa_config) == 0);
|
spa->spa_config);
|
||||||
mutex_exit(&spa->spa_props_lock);
|
mutex_exit(&spa->spa_props_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,6 +389,7 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
|
||||||
boolean_t locked = B_FALSE;
|
boolean_t locked = B_FALSE;
|
||||||
uint64_t split_guid;
|
uint64_t split_guid;
|
||||||
char *pool_name;
|
char *pool_name;
|
||||||
|
int config_gen_flags = 0;
|
||||||
|
|
||||||
if (vd == NULL) {
|
if (vd == NULL) {
|
||||||
vd = rvd;
|
vd = rvd;
|
||||||
|
@ -428,23 +422,17 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
|
||||||
} else
|
} else
|
||||||
pool_name = spa_name(spa);
|
pool_name = spa_name(spa);
|
||||||
|
|
||||||
VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0);
|
config = fnvlist_alloc();
|
||||||
|
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
|
|
||||||
spa_version(spa)) == 0);
|
|
||||||
VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME,
|
|
||||||
pool_name) == 0);
|
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE,
|
|
||||||
spa_state(spa)) == 0);
|
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG,
|
|
||||||
txg) == 0);
|
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
|
||||||
spa_guid(spa)) == 0);
|
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA,
|
|
||||||
spa->spa_errata) == 0);
|
|
||||||
VERIFY(spa->spa_comment == NULL || nvlist_add_string(config,
|
|
||||||
ZPOOL_CONFIG_COMMENT, spa->spa_comment) == 0);
|
|
||||||
|
|
||||||
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_VERSION, spa_version(spa));
|
||||||
|
fnvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, spa_name(spa));
|
||||||
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE, spa_state(spa));
|
||||||
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, txg);
|
||||||
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID, spa_guid(spa));
|
||||||
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA, spa->spa_errata);
|
||||||
|
if (spa->spa_comment != NULL)
|
||||||
|
fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT,
|
||||||
|
spa->spa_comment);
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
hostid = zone_get_hostid(NULL);
|
hostid = zone_get_hostid(NULL);
|
||||||
|
@ -455,24 +443,21 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
|
||||||
*/
|
*/
|
||||||
(void) ddi_strtoul(hw_serial, NULL, 10, &hostid);
|
(void) ddi_strtoul(hw_serial, NULL, 10, &hostid);
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
if (hostid != 0) {
|
if (hostid != 0)
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID,
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID, hostid);
|
||||||
hostid) == 0);
|
fnvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME, utsname()->nodename);
|
||||||
}
|
|
||||||
VERIFY0(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME,
|
|
||||||
utsname()->nodename));
|
|
||||||
|
|
||||||
if (vd != rvd) {
|
if (vd != rvd) {
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID,
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID,
|
||||||
vd->vdev_top->vdev_guid) == 0);
|
vd->vdev_top->vdev_guid);
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_GUID,
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_GUID,
|
||||||
vd->vdev_guid) == 0);
|
vd->vdev_guid);
|
||||||
if (vd->vdev_isspare)
|
if (vd->vdev_isspare)
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_SPARE,
|
fnvlist_add_uint64(config,
|
||||||
1ULL) == 0);
|
ZPOOL_CONFIG_IS_SPARE, 1ULL);
|
||||||
if (vd->vdev_islog)
|
if (vd->vdev_islog)
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_LOG,
|
fnvlist_add_uint64(config,
|
||||||
1ULL) == 0);
|
ZPOOL_CONFIG_IS_LOG, 1ULL);
|
||||||
vd = vd->vdev_top; /* label contains top config */
|
vd = vd->vdev_top; /* label contains top config */
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
@ -480,8 +465,12 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
|
||||||
* in the mos config, and not in the vdev labels
|
* in the mos config, and not in the vdev labels
|
||||||
*/
|
*/
|
||||||
if (spa->spa_config_splitting != NULL)
|
if (spa->spa_config_splitting != NULL)
|
||||||
VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_SPLIT,
|
fnvlist_add_nvlist(config, ZPOOL_CONFIG_SPLIT,
|
||||||
spa->spa_config_splitting) == 0);
|
spa->spa_config_splitting);
|
||||||
|
|
||||||
|
fnvlist_add_boolean(config, ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS);
|
||||||
|
|
||||||
|
config_gen_flags |= VDEV_CONFIG_MOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -496,19 +485,18 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
|
||||||
if (spa->spa_config_splitting != NULL &&
|
if (spa->spa_config_splitting != NULL &&
|
||||||
nvlist_lookup_uint64(spa->spa_config_splitting,
|
nvlist_lookup_uint64(spa->spa_config_splitting,
|
||||||
ZPOOL_CONFIG_SPLIT_GUID, &split_guid) == 0) {
|
ZPOOL_CONFIG_SPLIT_GUID, &split_guid) == 0) {
|
||||||
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_SPLIT_GUID,
|
fnvlist_add_uint64(config, ZPOOL_CONFIG_SPLIT_GUID, split_guid);
|
||||||
split_guid) == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nvroot = vdev_config_generate(spa, vd, getstats, 0);
|
nvroot = vdev_config_generate(spa, vd, getstats, config_gen_flags);
|
||||||
VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0);
|
fnvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot);
|
||||||
nvlist_free(nvroot);
|
nvlist_free(nvroot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store what's necessary for reading the MOS in the label.
|
* Store what's necessary for reading the MOS in the label.
|
||||||
*/
|
*/
|
||||||
VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
|
fnvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
|
||||||
spa->spa_label_features) == 0);
|
spa->spa_label_features);
|
||||||
|
|
||||||
if (getstats && spa_load_state(spa) == SPA_LOAD_NONE) {
|
if (getstats && spa_load_state(spa) == SPA_LOAD_NONE) {
|
||||||
ddt_histogram_t *ddh;
|
ddt_histogram_t *ddh;
|
||||||
|
@ -517,23 +505,23 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
|
||||||
|
|
||||||
ddh = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
|
ddh = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
|
||||||
ddt_get_dedup_histogram(spa, ddh);
|
ddt_get_dedup_histogram(spa, ddh);
|
||||||
VERIFY(nvlist_add_uint64_array(config,
|
fnvlist_add_uint64_array(config,
|
||||||
ZPOOL_CONFIG_DDT_HISTOGRAM,
|
ZPOOL_CONFIG_DDT_HISTOGRAM,
|
||||||
(uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t)) == 0);
|
(uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t));
|
||||||
kmem_free(ddh, sizeof (ddt_histogram_t));
|
kmem_free(ddh, sizeof (ddt_histogram_t));
|
||||||
|
|
||||||
ddo = kmem_zalloc(sizeof (ddt_object_t), KM_SLEEP);
|
ddo = kmem_zalloc(sizeof (ddt_object_t), KM_SLEEP);
|
||||||
ddt_get_dedup_object_stats(spa, ddo);
|
ddt_get_dedup_object_stats(spa, ddo);
|
||||||
VERIFY(nvlist_add_uint64_array(config,
|
fnvlist_add_uint64_array(config,
|
||||||
ZPOOL_CONFIG_DDT_OBJ_STATS,
|
ZPOOL_CONFIG_DDT_OBJ_STATS,
|
||||||
(uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t)) == 0);
|
(uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t));
|
||||||
kmem_free(ddo, sizeof (ddt_object_t));
|
kmem_free(ddo, sizeof (ddt_object_t));
|
||||||
|
|
||||||
dds = kmem_zalloc(sizeof (ddt_stat_t), KM_SLEEP);
|
dds = kmem_zalloc(sizeof (ddt_stat_t), KM_SLEEP);
|
||||||
ddt_get_dedup_stats(spa, dds);
|
ddt_get_dedup_stats(spa, dds);
|
||||||
VERIFY(nvlist_add_uint64_array(config,
|
fnvlist_add_uint64_array(config,
|
||||||
ZPOOL_CONFIG_DDT_STATS,
|
ZPOOL_CONFIG_DDT_STATS,
|
||||||
(uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t)) == 0);
|
(uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t));
|
||||||
kmem_free(dds, sizeof (ddt_stat_t));
|
kmem_free(dds, sizeof (ddt_stat_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -519,6 +519,10 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
|
||||||
&vd->vdev_asize);
|
&vd->vdev_asize);
|
||||||
(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVING,
|
(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVING,
|
||||||
&vd->vdev_removing);
|
&vd->vdev_removing);
|
||||||
|
(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_VDEV_TOP_ZAP,
|
||||||
|
&vd->vdev_top_zap);
|
||||||
|
} else {
|
||||||
|
ASSERT0(vd->vdev_top_zap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent && !parent->vdev_parent && alloctype != VDEV_ALLOC_ATTACH) {
|
if (parent && !parent->vdev_parent && alloctype != VDEV_ALLOC_ATTACH) {
|
||||||
|
@ -530,9 +534,18 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
|
||||||
spa_log_class(spa) : spa_normal_class(spa), vd);
|
spa_log_class(spa) : spa_normal_class(spa), vd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vd->vdev_ops->vdev_op_leaf &&
|
||||||
|
(alloctype == VDEV_ALLOC_LOAD || alloctype == VDEV_ALLOC_SPLIT)) {
|
||||||
|
(void) nvlist_lookup_uint64(nv,
|
||||||
|
ZPOOL_CONFIG_VDEV_LEAF_ZAP, &vd->vdev_leaf_zap);
|
||||||
|
} else {
|
||||||
|
ASSERT0(vd->vdev_leaf_zap);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're a leaf vdev, try to load the DTL object and other state.
|
* If we're a leaf vdev, try to load the DTL object and other state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (vd->vdev_ops->vdev_op_leaf &&
|
if (vd->vdev_ops->vdev_op_leaf &&
|
||||||
(alloctype == VDEV_ALLOC_LOAD || alloctype == VDEV_ALLOC_L2CACHE ||
|
(alloctype == VDEV_ALLOC_LOAD || alloctype == VDEV_ALLOC_L2CACHE ||
|
||||||
alloctype == VDEV_ALLOC_ROOTPOOL)) {
|
alloctype == VDEV_ALLOC_ROOTPOOL)) {
|
||||||
|
@ -694,10 +707,12 @@ vdev_top_transfer(vdev_t *svd, vdev_t *tvd)
|
||||||
tvd->vdev_ms_array = svd->vdev_ms_array;
|
tvd->vdev_ms_array = svd->vdev_ms_array;
|
||||||
tvd->vdev_ms_shift = svd->vdev_ms_shift;
|
tvd->vdev_ms_shift = svd->vdev_ms_shift;
|
||||||
tvd->vdev_ms_count = svd->vdev_ms_count;
|
tvd->vdev_ms_count = svd->vdev_ms_count;
|
||||||
|
tvd->vdev_top_zap = svd->vdev_top_zap;
|
||||||
|
|
||||||
svd->vdev_ms_array = 0;
|
svd->vdev_ms_array = 0;
|
||||||
svd->vdev_ms_shift = 0;
|
svd->vdev_ms_shift = 0;
|
||||||
svd->vdev_ms_count = 0;
|
svd->vdev_ms_count = 0;
|
||||||
|
svd->vdev_top_zap = 0;
|
||||||
|
|
||||||
if (tvd->vdev_mg)
|
if (tvd->vdev_mg)
|
||||||
ASSERT3P(tvd->vdev_mg, ==, svd->vdev_mg);
|
ASSERT3P(tvd->vdev_mg, ==, svd->vdev_mg);
|
||||||
|
@ -1976,6 +1991,51 @@ vdev_dtl_load(vdev_t *vd)
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vdev_destroy_unlink_zap(vdev_t *vd, uint64_t zapobj, dmu_tx_t *tx)
|
||||||
|
{
|
||||||
|
spa_t *spa = vd->vdev_spa;
|
||||||
|
|
||||||
|
VERIFY0(zap_destroy(spa->spa_meta_objset, zapobj, tx));
|
||||||
|
VERIFY0(zap_remove_int(spa->spa_meta_objset, spa->spa_all_vdev_zaps,
|
||||||
|
zapobj, tx));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
vdev_create_link_zap(vdev_t *vd, dmu_tx_t *tx)
|
||||||
|
{
|
||||||
|
spa_t *spa = vd->vdev_spa;
|
||||||
|
uint64_t zap = zap_create(spa->spa_meta_objset, DMU_OTN_ZAP_METADATA,
|
||||||
|
DMU_OT_NONE, 0, tx);
|
||||||
|
|
||||||
|
ASSERT(zap != 0);
|
||||||
|
VERIFY0(zap_add_int(spa->spa_meta_objset, spa->spa_all_vdev_zaps,
|
||||||
|
zap, tx));
|
||||||
|
|
||||||
|
return (zap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vdev_construct_zaps(vdev_t *vd, dmu_tx_t *tx)
|
||||||
|
{
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
if (vd->vdev_ops != &vdev_hole_ops &&
|
||||||
|
vd->vdev_ops != &vdev_missing_ops &&
|
||||||
|
vd->vdev_ops != &vdev_root_ops &&
|
||||||
|
!vd->vdev_top->vdev_removing) {
|
||||||
|
if (vd->vdev_ops->vdev_op_leaf && vd->vdev_leaf_zap == 0) {
|
||||||
|
vd->vdev_leaf_zap = vdev_create_link_zap(vd, tx);
|
||||||
|
}
|
||||||
|
if (vd == vd->vdev_top && vd->vdev_top_zap == 0) {
|
||||||
|
vd->vdev_top_zap = vdev_create_link_zap(vd, tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < vd->vdev_children; i++) {
|
||||||
|
vdev_construct_zaps(vd->vdev_child[i], tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
vdev_dtl_sync(vdev_t *vd, uint64_t txg)
|
vdev_dtl_sync(vdev_t *vd, uint64_t txg)
|
||||||
{
|
{
|
||||||
|
@ -1998,6 +2058,18 @@ vdev_dtl_sync(vdev_t *vd, uint64_t txg)
|
||||||
space_map_close(vd->vdev_dtl_sm);
|
space_map_close(vd->vdev_dtl_sm);
|
||||||
vd->vdev_dtl_sm = NULL;
|
vd->vdev_dtl_sm = NULL;
|
||||||
mutex_exit(&vd->vdev_dtl_lock);
|
mutex_exit(&vd->vdev_dtl_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only destroy the leaf ZAP for detached leaves or for
|
||||||
|
* removed log devices. Removed data devices handle leaf ZAP
|
||||||
|
* cleanup later, once cancellation is no longer possible.
|
||||||
|
*/
|
||||||
|
if (vd->vdev_leaf_zap != 0 && (vd->vdev_detached ||
|
||||||
|
vd->vdev_top->vdev_islog)) {
|
||||||
|
vdev_destroy_unlink_zap(vd, vd->vdev_leaf_zap, tx);
|
||||||
|
vd->vdev_leaf_zap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
dmu_tx_commit(tx);
|
dmu_tx_commit(tx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2204,6 +2276,8 @@ vdev_remove(vdev_t *vd, uint64_t txg)
|
||||||
int m, i;
|
int m, i;
|
||||||
|
|
||||||
tx = dmu_tx_create_assigned(spa_get_dsl(spa), txg);
|
tx = dmu_tx_create_assigned(spa_get_dsl(spa), txg);
|
||||||
|
ASSERT(vd == vd->vdev_top);
|
||||||
|
ASSERT3U(txg, ==, spa_syncing_txg(spa));
|
||||||
|
|
||||||
if (vd->vdev_ms != NULL) {
|
if (vd->vdev_ms != NULL) {
|
||||||
metaslab_group_t *mg = vd->vdev_mg;
|
metaslab_group_t *mg = vd->vdev_mg;
|
||||||
|
@ -2245,6 +2319,11 @@ vdev_remove(vdev_t *vd, uint64_t txg)
|
||||||
(void) dmu_object_free(mos, vd->vdev_ms_array, tx);
|
(void) dmu_object_free(mos, vd->vdev_ms_array, tx);
|
||||||
vd->vdev_ms_array = 0;
|
vd->vdev_ms_array = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vd->vdev_islog && vd->vdev_top_zap != 0) {
|
||||||
|
vdev_destroy_unlink_zap(vd, vd->vdev_top_zap, tx);
|
||||||
|
vd->vdev_top_zap = 0;
|
||||||
|
}
|
||||||
dmu_tx_commit(tx);
|
dmu_tx_commit(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,6 +291,20 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats,
|
||||||
if (vd->vdev_crtxg)
|
if (vd->vdev_crtxg)
|
||||||
fnvlist_add_uint64(nv, ZPOOL_CONFIG_CREATE_TXG, vd->vdev_crtxg);
|
fnvlist_add_uint64(nv, ZPOOL_CONFIG_CREATE_TXG, vd->vdev_crtxg);
|
||||||
|
|
||||||
|
if (flags & VDEV_CONFIG_MOS) {
|
||||||
|
if (vd->vdev_leaf_zap != 0) {
|
||||||
|
ASSERT(vd->vdev_ops->vdev_op_leaf);
|
||||||
|
fnvlist_add_uint64(nv, ZPOOL_CONFIG_VDEV_LEAF_ZAP,
|
||||||
|
vd->vdev_leaf_zap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vd->vdev_top_zap != 0) {
|
||||||
|
ASSERT(vd == vd->vdev_top);
|
||||||
|
fnvlist_add_uint64(nv, ZPOOL_CONFIG_VDEV_TOP_ZAP,
|
||||||
|
vd->vdev_top_zap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (getstats) {
|
if (getstats) {
|
||||||
vdev_stat_t vs;
|
vdev_stat_t vs;
|
||||||
pool_scan_stat_t ps;
|
pool_scan_stat_t ps;
|
||||||
|
|
|
@ -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) 2014 Spectra Logic Corporation, All rights reserved.
|
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -965,8 +965,8 @@ zap_create_link(objset_t *os, dmu_object_type_t ot, uint64_t parent_obj,
|
||||||
uint64_t new_obj;
|
uint64_t new_obj;
|
||||||
|
|
||||||
VERIFY((new_obj = zap_create(os, ot, DMU_OT_NONE, 0, tx)) > 0);
|
VERIFY((new_obj = zap_create(os, ot, DMU_OT_NONE, 0, tx)) > 0);
|
||||||
VERIFY(zap_add(os, parent_obj, name, sizeof (uint64_t), 1, &new_obj,
|
VERIFY0(zap_add(os, parent_obj, name, sizeof (uint64_t), 1, &new_obj,
|
||||||
tx) == 0);
|
tx));
|
||||||
|
|
||||||
return (new_obj);
|
return (new_obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -614,6 +614,13 @@ tests = [
|
||||||
'userquota_008_pos', 'userquota_009_pos',
|
'userquota_008_pos', 'userquota_009_pos',
|
||||||
'userquota_011_pos', 'userquota_012_neg']
|
'userquota_011_pos', 'userquota_012_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# vdev_zaps_007_pos -- fails due to a pre-existing issue with zpool split
|
||||||
|
#
|
||||||
|
[tests/functional/vdev_zaps]
|
||||||
|
tests = ['vdev_zaps_001_pos', 'vdev_zaps_002_pos', 'vdev_zaps_003_pos',
|
||||||
|
'vdev_zaps_004_pos', 'vdev_zaps_005_pos', 'vdev_zaps_006_pos']
|
||||||
|
|
||||||
# DISABLED:
|
# DISABLED:
|
||||||
# write_dirs_002_pos - needs investigation
|
# write_dirs_002_pos - needs investigation
|
||||||
[tests/functional/write_dirs]
|
[tests/functional/write_dirs]
|
||||||
|
|
|
@ -50,6 +50,7 @@ SUBDIRS = \
|
||||||
threadsappend \
|
threadsappend \
|
||||||
truncate \
|
truncate \
|
||||||
userquota \
|
userquota \
|
||||||
|
vdev_zaps \
|
||||||
write_dirs \
|
write_dirs \
|
||||||
xattr \
|
xattr \
|
||||||
zvol
|
zvol
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/vdev_zaps
|
||||||
|
dist_pkgdata_SCRIPTS = \
|
||||||
|
setup.ksh \
|
||||||
|
cleanup.ksh \
|
||||||
|
vdev_zaps_001_pos.ksh \
|
||||||
|
vdev_zaps_002_pos.ksh \
|
||||||
|
vdev_zaps_003_pos.ksh \
|
||||||
|
vdev_zaps_004_pos.ksh \
|
||||||
|
vdev_zaps_005_pos.ksh \
|
||||||
|
vdev_zaps_006_pos.ksh \
|
||||||
|
vdev_zaps_007_pos.ksh \
|
||||||
|
vdev_zaps.kshlib
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
default_cleanup
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
rm -rf $TESTDIR || log_fail Could not remove $TESTDIR
|
||||||
|
mkdir -p $TESTDIR || log_fail Could not create $TESTDIR
|
|
@ -0,0 +1,114 @@
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
function get_conf_section # regex conf
|
||||||
|
{
|
||||||
|
typeset dsk_line next_vd_line conf section
|
||||||
|
typeset regex="$1"
|
||||||
|
typeset conf="$2"
|
||||||
|
|
||||||
|
dsk_line=$(grep -n "$regex" "$conf" | awk -F: '{print $1}')
|
||||||
|
if [[ -z "$dsk_line" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
next_vd_line=$(tail -n +$dsk_line "$conf" | \
|
||||||
|
grep -n "children\[" | awk -F: '{print $1}' | head -n 1)
|
||||||
|
|
||||||
|
if [[ -n "$next_vd_line" ]]; then
|
||||||
|
section=$(cat "$conf" | sed "1,${dsk_line}d" | head -n \
|
||||||
|
$(($next_vd_line - 2)))
|
||||||
|
|
||||||
|
else
|
||||||
|
section=$(tail -n +$dsk_line "$conf")
|
||||||
|
fi
|
||||||
|
echo "$section"
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_leaf_vd_zap # dsk conf
|
||||||
|
{
|
||||||
|
typeset section=$(get_conf_section "$1" "$2")
|
||||||
|
echo "$section" | egrep \
|
||||||
|
"com.delphix:vdev_zap_leaf: [0-9]+" | awk '{print $2}'
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_top_vd_zap # dsk conf
|
||||||
|
{
|
||||||
|
typeset section=$(get_conf_section "$1" "$2")
|
||||||
|
echo "$section" | egrep \
|
||||||
|
"com.delphix:vdev_zap_top: [0-9]+" | awk '{print $2}'
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_has_sentinel # conf
|
||||||
|
{
|
||||||
|
res=$(grep "com.delphix:has_per_vdev_zaps" "$1")
|
||||||
|
[[ -z "$res" ]] && log_fail "Pool missing ZAP feature sentinel value"
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_zap_common # pool vd lvl zapobj
|
||||||
|
{
|
||||||
|
typeset pool=$1
|
||||||
|
typeset vd="$2"
|
||||||
|
typeset lvl=$3
|
||||||
|
typeset zapobj=$4
|
||||||
|
|
||||||
|
if [[ -z "$zapobj" ]]; then
|
||||||
|
log_fail "$vd on $pool has no $lvl ZAP in config"
|
||||||
|
elif [[ -z "$(zdb -d $pool $zapobj | grep 'zap')" ]]; then
|
||||||
|
log_fail "$vd on $pool has no $lvl ZAP in MOS"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_top_zap # pool vd conf
|
||||||
|
{
|
||||||
|
typeset pool=$1
|
||||||
|
typeset vd="$2"
|
||||||
|
typeset conf=$3
|
||||||
|
|
||||||
|
top_zap=$(get_top_vd_zap "$vd" $conf)
|
||||||
|
assert_zap_common $pool "$vd" "top" $top_zap
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_leaf_zap # pool vd conf
|
||||||
|
{
|
||||||
|
typeset pool=$1
|
||||||
|
typeset vd="$2"
|
||||||
|
typeset conf=$3
|
||||||
|
|
||||||
|
leaf_zap=$(get_leaf_vd_zap "$vd" $conf)
|
||||||
|
assert_zap_common $pool "$vd" "leaf" $leaf_zap
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Code common to setup/teardown for each test.
|
||||||
|
#
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
if datasetexists $TESTPOOL ; then
|
||||||
|
log_must zpool destroy -f $TESTPOOL
|
||||||
|
fi
|
||||||
|
if [[ -e $conf ]]; then
|
||||||
|
log_must $RM -f "$conf"
|
||||||
|
fi
|
||||||
|
if [[ -e $POOL2 ]]; then
|
||||||
|
log_must zpool destroy -f $POOL2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
|
@ -0,0 +1,42 @@
|
||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Verify that per-vdev ZAPs are created with one vdev.
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool with one disk.
|
||||||
|
# 2. Verify that the disk has a top and leaf ZAP in its config and the MOS.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs are created on pool creation with one disk."
|
||||||
|
|
||||||
|
DISK=${DISKS%% *}
|
||||||
|
|
||||||
|
log_must zpool create -f $TESTPOOL $DISK
|
||||||
|
conf="$TESTDIR/vz001"
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
assert_top_zap $TESTPOOL $DISK "$conf"
|
||||||
|
assert_leaf_zap $TESTPOOL $DISK "$conf"
|
||||||
|
assert_has_sentinel "$conf"
|
||||||
|
|
||||||
|
log_pass "Per-vdev ZAPs are created in a one-disk pool."
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Verify that per-vdev ZAPs are created with multiple vdevs.
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool with multiple disks.
|
||||||
|
# 2. Verify that each has both a top and leaf zap.
|
||||||
|
# 3. Verify that each of those ZAPs exists in the MOS.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs are created on pool creation with many disks."
|
||||||
|
|
||||||
|
log_must zpool create -f $TESTPOOL $DISKS
|
||||||
|
|
||||||
|
conf="$TESTDIR/vz002"
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
assert_has_sentinel "$conf"
|
||||||
|
for DISK in $DISKS; do
|
||||||
|
assert_top_zap $TESTPOOL $DISK "$conf"
|
||||||
|
assert_leaf_zap $TESTPOOL $DISK "$conf"
|
||||||
|
done
|
||||||
|
|
||||||
|
log_pass
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Verify that per-vdev ZAPs are created with multi-level vdev tree.
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool with a multi-disk mirror.
|
||||||
|
# 2. Verify that mirror has top ZAP but no leaf ZAP.
|
||||||
|
# 3. Verify that each disk has a leaf ZAP but no top ZAP.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs are created on pool creation with multi-level vdev "\
|
||||||
|
"trees."
|
||||||
|
|
||||||
|
log_must zpool create -f $TESTPOOL mirror $DISKS
|
||||||
|
|
||||||
|
conf="$TESTDIR/vz003"
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
assert_has_sentinel "$conf"
|
||||||
|
assert_top_zap $TESTPOOL "type: 'mirror'" "$conf"
|
||||||
|
for DISK in $DISKS; do
|
||||||
|
assert_leaf_zap $TESTPOOL $DISK "$conf"
|
||||||
|
top_zap=$(get_top_vd_zap $DISK "$conf")
|
||||||
|
[[ -n "$top_zap" ]] && log_fail "Leaf vdev $DISK has top-level ZAP."
|
||||||
|
done
|
||||||
|
|
||||||
|
log_pass
|
|
@ -0,0 +1,94 @@
|
||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Verify that per-vdev ZAPs are properly transferred on attach/detach.
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool with one disk. Verify that it has a top and leaf ZAP.
|
||||||
|
# 2. Attach a disk.
|
||||||
|
# 3. Verify that top-level and leaf-level ZAPs were transferred properly.
|
||||||
|
# 4. Verify that the newly-attached disk has a leaf ZAP.
|
||||||
|
# 5. Detach the original disk.
|
||||||
|
# 6. Verify that top-level and leaf-level ZAPs were transferred properly.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs are transferred properly on attach/detach"
|
||||||
|
|
||||||
|
DISK=${DISKS%% *}
|
||||||
|
log_must zpool create -f $TESTPOOL $DISK
|
||||||
|
|
||||||
|
# Make the pool.
|
||||||
|
conf="$TESTDIR/vz004"
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
assert_has_sentinel "$conf"
|
||||||
|
orig_top=$(get_top_vd_zap $DISK $conf)
|
||||||
|
orig_leaf=$(get_leaf_vd_zap $DISK $conf)
|
||||||
|
assert_zap_common $TESTPOOL $DISK "top" $orig_top
|
||||||
|
|
||||||
|
#
|
||||||
|
# Attach a disk.
|
||||||
|
#
|
||||||
|
|
||||||
|
disk2=$(echo $DISKS | awk '{print $2}')
|
||||||
|
log_must zpool attach $TESTPOOL $DISK $disk2
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
# Ensure top-level ZAP was transferred successfully.
|
||||||
|
new_top=$(get_top_vd_zap "type: 'mirror'" $conf)
|
||||||
|
if [[ "$new_top" -ne "$orig_top" ]]; then
|
||||||
|
log_fail "Top-level ZAP wasn't transferred successfully on attach."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure leaf ZAP of original disk was transferred successfully.
|
||||||
|
new_leaf=$(get_leaf_vd_zap $DISK $conf)
|
||||||
|
if [[ "$new_leaf" -ne "$orig_leaf" ]]; then
|
||||||
|
log_fail "$DISK used to have leaf-level ZAP $orig_leaf, now has "\
|
||||||
|
"$new_leaf"
|
||||||
|
fi
|
||||||
|
# Ensure original disk no longer has top-level ZAP.
|
||||||
|
dsk1_top=$(get_top_vd_zap $DISK $conf)
|
||||||
|
[[ -n "$dsk1_top" ]] && log_fail "$DISK has top-level ZAP, but is only leaf."
|
||||||
|
|
||||||
|
# Ensure attached disk got a leaf-level ZAP but not a top-level ZAP.
|
||||||
|
dsk2_top=$(get_top_vd_zap $disk2 $conf)
|
||||||
|
dsk2_leaf=$(get_leaf_vd_zap $disk2 $conf)
|
||||||
|
[[ -n "$dsk2_top" ]] && log_fail "Attached disk $disk2 has top ZAP."
|
||||||
|
[[ -z "$dsk2_leaf" ]] && log_fail "Attached disk $disk2 has no leaf ZAP."
|
||||||
|
|
||||||
|
#
|
||||||
|
# Detach original disk.
|
||||||
|
#
|
||||||
|
|
||||||
|
log_must zpool detach $TESTPOOL $DISK
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
final_top=$(get_top_vd_zap $disk2 $conf)
|
||||||
|
final_leaf=$(get_leaf_vd_zap $disk2 $conf)
|
||||||
|
# Make sure top ZAP was successfully transferred.
|
||||||
|
[[ "$final_top" -ne "$orig_top" ]] && log_fail "Lost top-level ZAP when "\
|
||||||
|
"promoting $disk2 (expected $orig_top, found $final_top)"
|
||||||
|
|
||||||
|
# Make sure leaf ZAP was successfully transferred.
|
||||||
|
[[ "$final_leaf" -ne "$dsk2_leaf" ]] && log_fail "$disk2 lost its leaf ZAP "\
|
||||||
|
"on promotion (expected $dsk2_leaf, got $final_leaf)"
|
||||||
|
|
||||||
|
log_pass
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Verify that per-vdev ZAPs persist when the pool is exported and imported.
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool with a disk.
|
||||||
|
# 2. Export the pool and re-import it.
|
||||||
|
# 3. Verify that the ZAPs aren't different.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs persist across export/import."
|
||||||
|
|
||||||
|
DISK=${DISKS%% *}
|
||||||
|
log_must zpool create -f $TESTPOOL $DISK
|
||||||
|
|
||||||
|
# Make the pool.
|
||||||
|
conf="$TESTDIR/vz005"
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
assert_has_sentinel "$conf"
|
||||||
|
orig_top=$(get_top_vd_zap $DISK $conf)
|
||||||
|
orig_leaf=$(get_leaf_vd_zap $DISK $conf)
|
||||||
|
assert_zap_common $TESTPOOL $DISK "top" $orig_top
|
||||||
|
assert_zap_common $TESTPOOL $DISK "leaf" $orig_leaf
|
||||||
|
|
||||||
|
# Export the pool.
|
||||||
|
log_must zpool export $TESTPOOL
|
||||||
|
|
||||||
|
# Import the pool.
|
||||||
|
log_must zpool import $TESTPOOL
|
||||||
|
|
||||||
|
# Verify that ZAPs persisted.
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
new_top=$(get_top_vd_zap $DISK $conf)
|
||||||
|
new_leaf=$(get_leaf_vd_zap $DISK $conf)
|
||||||
|
|
||||||
|
[[ "$new_top" -ne "$orig_top" ]] && log_fail "Top ZAP ($new_top) after "\
|
||||||
|
"import does not match top ZAP before export ($orig_top)"
|
||||||
|
[[ "$new_leaf" -ne "$orig_leaf" ]] && log_fail "Leaf ZAP ($new_leaf) after "\
|
||||||
|
"import does not match leaf ZAP before export ($orig_leaf)"
|
||||||
|
|
||||||
|
log_pass
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015, 2016 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Verify that top-level per-vdev ZAPs are created for added devices
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool with one disk.
|
||||||
|
# 2. Add a disk.
|
||||||
|
# 3. Verify its ZAPs were created.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
|
||||||
|
|
||||||
|
DISK_ARR=($DISKS)
|
||||||
|
DISK=${DISK_ARR[0]}
|
||||||
|
log_must zpool create -f $TESTPOOL $DISK
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs are created for added vdevs."
|
||||||
|
|
||||||
|
log_must zpool add -f $TESTPOOL ${DISK_ARR[1]}
|
||||||
|
conf="$TESTDIR/vz006"
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
assert_has_sentinel "$conf"
|
||||||
|
orig_top=$(get_top_vd_zap ${DISK_ARR[1]} $conf)
|
||||||
|
assert_zap_common $TESTPOOL ${DISK_ARR[1]} "top" $orig_top
|
||||||
|
assert_leaf_zap $TESTPOOL ${DISK_ARR[1]} "$conf"
|
||||||
|
|
||||||
|
log_pass
|
|
@ -0,0 +1,74 @@
|
||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Verify that ZAPs are handled properly during mirror pool splitting.
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool with a two-way mirror.
|
||||||
|
# 2. Split the pool.
|
||||||
|
# 3. Verify that the ZAPs in the old pool persisted.
|
||||||
|
# 4. Import the new pool.
|
||||||
|
# 5. Verify that the ZAPs in the new pool persisted.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
|
||||||
|
|
||||||
|
DISK_ARR=($DISKS)
|
||||||
|
POOL2=${TESTPOOL}2
|
||||||
|
log_must zpool create -f $TESTPOOL mirror ${DISK_ARR[0]} ${DISK_ARR[1]}
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs persist correctly on the original pool after split."
|
||||||
|
conf="$TESTDIR/vz007"
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
assert_has_sentinel "$conf"
|
||||||
|
orig_top=$(get_top_vd_zap "type: 'mirror'" $conf)
|
||||||
|
orig_leaf0=$(get_leaf_vd_zap ${DISK_ARR[0]} $conf)
|
||||||
|
orig_leaf1=$(get_leaf_vd_zap ${DISK_ARR[1]} $conf)
|
||||||
|
assert_zap_common $TESTPOOL "type: 'mirror'" "top" $orig_top
|
||||||
|
assert_zap_common $TESTPOOL ${DISK_ARR[0]} "leaf" $orig_leaf0
|
||||||
|
assert_zap_common $TESTPOOL ${DISK_ARR[1]} "leaf" $orig_leaf1
|
||||||
|
|
||||||
|
log_must zpool split $TESTPOOL $POOL2 ${DISK_ARR[1]}
|
||||||
|
|
||||||
|
# Make sure old pool's ZAPs are consistent.
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
new_leaf0=$(get_leaf_vd_zap ${DISK_ARR[0]} $conf)
|
||||||
|
new_top_s0=$(get_top_vd_zap ${DISK_ARR[0]} $conf)
|
||||||
|
|
||||||
|
[[ "$new_leaf0" -ne "$orig_leaf0" ]] && log_fail "Leaf ZAP in original pool "\
|
||||||
|
"didn't persist (expected $orig_leaf0, got $new_leaf0)"
|
||||||
|
[[ "$new_top_s0" -ne "$orig_top" ]] && log_fail "Top ZAP in original pool "\
|
||||||
|
"didn't persist (expected $orig_top, got $new_top_s0)"
|
||||||
|
|
||||||
|
log_assert "Per-vdev ZAPs persist on the new pool after import."
|
||||||
|
|
||||||
|
# Import the split pool.
|
||||||
|
log_must zpool import $POOL2
|
||||||
|
log_must zdb -PC $TESTPOOL > $conf
|
||||||
|
|
||||||
|
new_leaf1=$(get_leaf_vd_zap ${DISK_ARR[1]} $conf)
|
||||||
|
new_top_s1=$(get_top_vd_zap ${DISK_ARR[1]} $conf)
|
||||||
|
[[ "$new_leaf1" -ne "$orig_leaf1" ]] && log_fail "Leaf ZAP in new pool "\
|
||||||
|
"didn't persist (expected $orig_leaf1, got $new_leaf1)"
|
||||||
|
[[ "$new_top_s1" -ne "$orig_top" ]] && log_fail "Top ZAP in new pool "\
|
||||||
|
"didn't persist (expected $orig_top, got $new_top_s1)"
|
||||||
|
|
||||||
|
log_pass
|
Loading…
Reference in New Issue