Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Uberblock Label and Path Handling Issues related to AUX vdevs #15737

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions include/sys/spa_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ struct spa {

spa_aux_vdev_t spa_spares; /* hot spares */
spa_aux_vdev_t spa_l2cache; /* L2ARC cache devices */
boolean_t spa_aux_sync_uber; /* need to sync aux uber */
nvlist_t *spa_label_features; /* Features for reading MOS */
uint64_t spa_config_object; /* MOS object for pool config */
uint64_t spa_config_generation; /* config generation number */
Expand Down
17 changes: 15 additions & 2 deletions lib/libzutil/zutil_import.c
Original file line number Diff line number Diff line change
Expand Up @@ -1210,13 +1210,26 @@ label_paths(libpc_handle_t *hdl, nvlist_t *label, const char **path,
nvlist_t *nvroot;
uint64_t pool_guid;
uint64_t vdev_guid;
uint64_t state;

*path = NULL;
*devid = NULL;
if (nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &vdev_guid) != 0)
return (ENOENT);

/*
* In case of spare or l2cache, we directly return path/devid from the
* label.
*/
if (!(nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_STATE, &state)) &&
(state == POOL_STATE_SPARE || state == POOL_STATE_L2CACHE)) {
(void) nvlist_lookup_string(label, ZPOOL_CONFIG_PATH, path);
(void) nvlist_lookup_string(label, ZPOOL_CONFIG_DEVID, devid);
return (0);
}

if (nvlist_lookup_nvlist(label, ZPOOL_CONFIG_VDEV_TREE, &nvroot) ||
nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_GUID, &pool_guid) ||
nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &vdev_guid))
nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_GUID, &pool_guid))
return (ENOENT);

return (label_paths_impl(hdl, nvroot, pool_guid, vdev_guid, path,
Expand Down
85 changes: 62 additions & 23 deletions module/zfs/vdev_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,10 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason)
int error;
uint64_t spare_guid = 0, l2cache_guid = 0;
int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL;
boolean_t reason_spare = (reason == VDEV_LABEL_SPARE || (reason ==
VDEV_LABEL_REMOVE && vd->vdev_isspare));
boolean_t reason_l2cache = (reason == VDEV_LABEL_L2CACHE || (reason ==
VDEV_LABEL_REMOVE && vd->vdev_isl2cache));

ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);

Expand Down Expand Up @@ -1116,34 +1120,20 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason)
* really part of an active pool just yet. The labels will
* be written again with a meaningful txg by spa_sync().
*/
if (reason == VDEV_LABEL_SPARE ||
(reason == VDEV_LABEL_REMOVE && vd->vdev_isspare)) {
if (reason_spare || reason_l2cache) {
/*
* For inactive hot spares, we generate a special label that
* identifies as a mutually shared hot spare. We write the
* label if we are adding a hot spare, or if we are removing an
* active hot spare (in which case we want to revert the
* labels).
* For inactive hot spares and level 2 ARC devices, we generate
* a special label that identifies as a mutually shared hot
* spare or l2cache device. We write the label in case of
* addition or removal of hot spare or l2cache vdev (in which
* case we want to revert the labels).
*/
VERIFY(nvlist_alloc(&label, NV_UNIQUE_NAME, KM_SLEEP) == 0);

VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_VERSION,
spa_version(spa)) == 0);
VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_POOL_STATE,
POOL_STATE_SPARE) == 0);
VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_GUID,
vd->vdev_guid) == 0);
} else if (reason == VDEV_LABEL_L2CACHE ||
(reason == VDEV_LABEL_REMOVE && vd->vdev_isl2cache)) {
/*
* For level 2 ARC devices, add a special label.
*/
VERIFY(nvlist_alloc(&label, NV_UNIQUE_NAME, KM_SLEEP) == 0);

VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_VERSION,
spa_version(spa)) == 0);
VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_POOL_STATE,
POOL_STATE_L2CACHE) == 0);
reason_spare ? POOL_STATE_SPARE : POOL_STATE_L2CACHE) == 0);
VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_GUID,
vd->vdev_guid) == 0);

Expand All @@ -1154,8 +1144,34 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason)
* spa->spa_l2cache->sav_config (populated in
* spa_ld_open_aux_vdevs()).
*/
VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_ASHIFT,
vd->vdev_ashift) == 0);
if (reason_l2cache) {
VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_ASHIFT,
vd->vdev_ashift) == 0);
}

/*
* Add path information to help find it during pool import
*/
if (vd->vdev_path != NULL) {
VERIFY(nvlist_add_string(label, ZPOOL_CONFIG_PATH,
vd->vdev_path) == 0);
}
if (vd->vdev_devid != NULL) {
VERIFY(nvlist_add_string(label, ZPOOL_CONFIG_DEVID,
vd->vdev_devid) == 0);
}
if (vd->vdev_physpath != NULL) {
VERIFY(nvlist_add_string(label, ZPOOL_CONFIG_PHYS_PATH,
vd->vdev_physpath) == 0);
}

/*
* When spare or l2cache (aux) vdev is added during pool
* creation, spa->spa_uberblock is not written until this
* point. Write it on next config sync.
*/
if (uberblock_verify(&spa->spa_uberblock))
spa->spa_aux_sync_uber = B_TRUE;
} else {
uint64_t txg = 0ULL;

Expand Down Expand Up @@ -1794,6 +1810,16 @@ vdev_uberblock_sync_list(vdev_t **svd, int svdcount, uberblock_t *ub, int flags)
for (int v = 0; v < svdcount; v++)
vdev_uberblock_sync(zio, &good_writes, ub, svd[v], flags);

if (spa->spa_aux_sync_uber) {
for (int v = 0; v < spa->spa_spares.sav_count; v++) {
vdev_uberblock_sync(zio, &good_writes, ub,
spa->spa_spares.sav_vdevs[v], flags);
}
for (int v = 0; v < spa->spa_l2cache.sav_count; v++) {
vdev_uberblock_sync(zio, &good_writes, ub,
spa->spa_l2cache.sav_vdevs[v], flags);
}
}
(void) zio_wait(zio);

/*
Expand All @@ -1808,6 +1834,19 @@ vdev_uberblock_sync_list(vdev_t **svd, int svdcount, uberblock_t *ub, int flags)
zio_flush(zio, svd[v]);
}
}
if (spa->spa_aux_sync_uber) {
spa->spa_aux_sync_uber = B_FALSE;
for (int v = 0; v < spa->spa_spares.sav_count; v++) {
if (vdev_writeable(spa->spa_spares.sav_vdevs[v])) {
zio_flush(zio, spa->spa_spares.sav_vdevs[v]);
}
}
for (int v = 0; v < spa->spa_l2cache.sav_count; v++) {
if (vdev_writeable(spa->spa_l2cache.sav_vdevs[v])) {
zio_flush(zio, spa->spa_l2cache.sav_vdevs[v]);
}
}
}

(void) zio_wait(zio);

Expand Down