Changeset View
Changeset View
Standalone View
Standalone View
sys/contrib/openzfs/module/zfs/vdev_label.c
Show First 20 Lines • Show All 748 Lines • ▼ Show 20 Lines | |||||
* find the most up-to-date label that does not exceed the specified | * find the most up-to-date label that does not exceed the specified | ||||
* 'txg' value. | * 'txg' value. | ||||
*/ | */ | ||||
nvlist_t * | nvlist_t * | ||||
vdev_label_read_config(vdev_t *vd, uint64_t txg) | vdev_label_read_config(vdev_t *vd, uint64_t txg) | ||||
{ | { | ||||
spa_t *spa = vd->vdev_spa; | spa_t *spa = vd->vdev_spa; | ||||
nvlist_t *config = NULL; | nvlist_t *config = NULL; | ||||
vdev_phys_t *vp; | vdev_phys_t *vp[VDEV_LABELS]; | ||||
abd_t *vp_abd; | abd_t *vp_abd[VDEV_LABELS]; | ||||
zio_t *zio; | zio_t *zio[VDEV_LABELS]; | ||||
uint64_t best_txg = 0; | uint64_t best_txg = 0; | ||||
uint64_t label_txg = 0; | uint64_t label_txg = 0; | ||||
int error = 0; | int error = 0; | ||||
int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | | int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | | ||||
ZIO_FLAG_SPECULATIVE; | ZIO_FLAG_SPECULATIVE; | ||||
ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL); | ASSERT(vd->vdev_validate_thread == curthread || | ||||
spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL); | |||||
if (!vdev_readable(vd)) | if (!vdev_readable(vd)) | ||||
return (NULL); | return (NULL); | ||||
/* | /* | ||||
* The label for a dRAID distributed spare is not stored on disk. | * The label for a dRAID distributed spare is not stored on disk. | ||||
* Instead it is generated when needed which allows us to bypass | * Instead it is generated when needed which allows us to bypass | ||||
* the pipeline when reading the config from the label. | * the pipeline when reading the config from the label. | ||||
*/ | */ | ||||
if (vd->vdev_ops == &vdev_draid_spare_ops) | if (vd->vdev_ops == &vdev_draid_spare_ops) | ||||
return (vdev_draid_read_config_spare(vd)); | return (vdev_draid_read_config_spare(vd)); | ||||
vp_abd = abd_alloc_linear(sizeof (vdev_phys_t), B_TRUE); | for (int l = 0; l < VDEV_LABELS; l++) { | ||||
vp = abd_to_buf(vp_abd); | vp_abd[l] = abd_alloc_linear(sizeof (vdev_phys_t), B_TRUE); | ||||
vp[l] = abd_to_buf(vp_abd[l]); | |||||
} | |||||
retry: | retry: | ||||
for (int l = 0; l < VDEV_LABELS; l++) { | for (int l = 0; l < VDEV_LABELS; l++) { | ||||
zio[l] = zio_root(spa, NULL, NULL, flags); | |||||
vdev_label_read(zio[l], vd, l, vp_abd[l], | |||||
offsetof(vdev_label_t, vl_vdev_phys), sizeof (vdev_phys_t), | |||||
NULL, NULL, flags); | |||||
} | |||||
for (int l = 0; l < VDEV_LABELS; l++) { | |||||
nvlist_t *label = NULL; | nvlist_t *label = NULL; | ||||
zio = zio_root(spa, NULL, NULL, flags); | if (zio_wait(zio[l]) == 0 && | ||||
nvlist_unpack(vp[l]->vp_nvlist, sizeof (vp[l]->vp_nvlist), | |||||
vdev_label_read(zio, vd, l, vp_abd, | |||||
offsetof(vdev_label_t, vl_vdev_phys), | |||||
sizeof (vdev_phys_t), NULL, NULL, flags); | |||||
if (zio_wait(zio) == 0 && | |||||
nvlist_unpack(vp->vp_nvlist, sizeof (vp->vp_nvlist), | |||||
&label, 0) == 0) { | &label, 0) == 0) { | ||||
/* | /* | ||||
* Auxiliary vdevs won't have txg values in their | * Auxiliary vdevs won't have txg values in their | ||||
* labels and newly added vdevs may not have been | * labels and newly added vdevs may not have been | ||||
* completely initialized so just return the | * completely initialized so just return the | ||||
* configuration from the first valid label we | * configuration from the first valid label we | ||||
* encounter. | * encounter. | ||||
*/ | */ | ||||
error = nvlist_lookup_uint64(label, | error = nvlist_lookup_uint64(label, | ||||
ZPOOL_CONFIG_POOL_TXG, &label_txg); | ZPOOL_CONFIG_POOL_TXG, &label_txg); | ||||
if ((error || label_txg == 0) && !config) { | if ((error || label_txg == 0) && !config) { | ||||
config = label; | config = label; | ||||
for (l++; l < VDEV_LABELS; l++) | |||||
zio_wait(zio[l]); | |||||
break; | break; | ||||
} else if (label_txg <= txg && label_txg > best_txg) { | } else if (label_txg <= txg && label_txg > best_txg) { | ||||
best_txg = label_txg; | best_txg = label_txg; | ||||
nvlist_free(config); | nvlist_free(config); | ||||
config = fnvlist_dup(label); | config = fnvlist_dup(label); | ||||
} | } | ||||
} | } | ||||
Show All 12 Lines | retry: | ||||
* We found a valid label but it didn't pass txg restrictions. | * We found a valid label but it didn't pass txg restrictions. | ||||
*/ | */ | ||||
if (config == NULL && label_txg != 0) { | if (config == NULL && label_txg != 0) { | ||||
vdev_dbgmsg(vd, "label discarded as txg is too large " | vdev_dbgmsg(vd, "label discarded as txg is too large " | ||||
"(%llu > %llu)", (u_longlong_t)label_txg, | "(%llu > %llu)", (u_longlong_t)label_txg, | ||||
(u_longlong_t)txg); | (u_longlong_t)txg); | ||||
} | } | ||||
abd_free(vp_abd); | for (int l = 0; l < VDEV_LABELS; l++) { | ||||
abd_free(vp_abd[l]); | |||||
} | |||||
return (config); | return (config); | ||||
} | } | ||||
/* | /* | ||||
* Determine if a device is in use. The 'spare_guid' parameter will be filled | * Determine if a device is in use. The 'spare_guid' parameter will be filled | ||||
* in with the device guid if this spare is active elsewhere on the system. | * in with the device guid if this spare is active elsewhere on the system. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 1,142 Lines • Show Last 20 Lines |