Fix zdb pool/ with -k

When examining the root dataset with zdb -k, we get into a mismatched
state. main() knows we are not examining the whole pool, but it strips
off the trailing slash. import_checkpointed_state() then thinks we are
examining the whole pool, and does not update the target path
appropriately. The fix is to directly inform import_checkpointed_state
that we are examining a filesystem, and not the whole pool.

Sponsored-by: Klara, Inc.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Rob Norris <rob.norris@klarasystems.com>
Signed-off-by: Paul Dagnelie <paul.dagnelie@klarasystems.com>
Co-authored-by: Paul Dagnelie <paul.dagnelie@klarasystems.com>
Closes #17536
This commit is contained in:
Paul Dagnelie 2025-07-15 17:01:49 -07:00 committed by Brian Behlendorf
parent 8c4f625c12
commit 6af1f61ad4
2 changed files with 13 additions and 9 deletions

View File

@ -7708,7 +7708,8 @@ zdb_set_skip_mmp(char *target)
* applies to the new_path parameter if allocated.
*/
static char *
import_checkpointed_state(char *target, nvlist_t *cfg, char **new_path)
import_checkpointed_state(char *target, nvlist_t *cfg, boolean_t target_is_spa,
char **new_path)
{
int error = 0;
char *poolname, *bogus_name = NULL;
@ -7716,11 +7717,11 @@ import_checkpointed_state(char *target, nvlist_t *cfg, char **new_path)
/* If the target is not a pool, the extract the pool name */
char *path_start = strchr(target, '/');
if (path_start != NULL) {
if (target_is_spa || path_start == NULL) {
poolname = target;
} else {
size_t poolname_len = path_start - target;
poolname = strndup(target, poolname_len);
} else {
poolname = target;
}
if (cfg == NULL) {
@ -7751,10 +7752,11 @@ import_checkpointed_state(char *target, nvlist_t *cfg, char **new_path)
"with error %d\n", bogus_name, error);
}
if (new_path != NULL && path_start != NULL) {
if (asprintf(new_path, "%s%s", bogus_name, path_start) == -1) {
if (new_path != NULL && !target_is_spa) {
if (asprintf(new_path, "%s%s", bogus_name,
path_start != NULL ? path_start : "") == -1) {
free(bogus_name);
if (path_start != NULL)
if (!target_is_spa && path_start != NULL)
free(poolname);
return (NULL);
}
@ -7983,7 +7985,7 @@ verify_checkpoint_blocks(spa_t *spa)
* name) so we can do verification on it against the current state
* of the pool.
*/
checkpoint_pool = import_checkpointed_state(spa->spa_name, NULL,
checkpoint_pool = import_checkpointed_state(spa->spa_name, NULL, B_TRUE,
NULL);
ASSERT(strcmp(spa->spa_name, checkpoint_pool) != 0);
@ -9700,7 +9702,7 @@ main(int argc, char **argv)
char *checkpoint_target = NULL;
if (dump_opt['k']) {
checkpoint_pool = import_checkpointed_state(target, cfg,
&checkpoint_target);
target_is_spa, &checkpoint_target);
if (checkpoint_target != NULL)
target = checkpoint_target;

View File

@ -63,6 +63,7 @@ log_must eval "zdb $TESTPOOL | grep -q \"Checkpointed uberblock found\""
log_mustnot eval "zdb -k $TESTPOOL | grep -q \"Checkpointed uberblock found\""
log_mustnot eval "zdb $TESTPOOL | grep \"Dataset $FS1\""
log_must eval "zdb -k $TESTPOOL | grep \"Dataset $CHECKPOINTED_FS1\""
log_must eval "zdb -k $TESTPOOL/ | grep \"$TESTPOOL$BOGUS_SUFFIX\""
log_must zpool export $TESTPOOL
@ -70,6 +71,7 @@ log_must eval "zdb -e $TESTPOOL | grep \"Checkpointed uberblock found\""
log_mustnot eval "zdb -k -e $TESTPOOL | grep \"Checkpointed uberblock found\""
log_mustnot eval "zdb -e $TESTPOOL | grep \"Dataset $FS1\""
log_must eval "zdb -k -e $TESTPOOL | grep \"Dataset $CHECKPOINTED_FS1\""
log_must eval "zdb -k -e $TESTPOOL/ | grep \"$TESTPOOL$BOGUS_SUFFIX\""
log_must zpool import $TESTPOOL