/* * pool_hdr_uuid_fix -- (internal) fix UUID value */ static int pool_hdr_uuid_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *context) { LOG(3, NULL); ASSERTne(loc, NULL); switch (question) { case Q_UUID_SET: CHECK_INFO(ppc, "%ssetting pool_hdr.uuid to %s", loc->prefix, check_get_uuid_str(*loc->valid_uuid)); memcpy(loc->hdr.uuid, loc->valid_uuid, POOL_HDR_UUID_LEN); break; case Q_UUID_REGENERATE: if (util_uuid_generate(loc->hdr.uuid) != 0) { ppc->result = CHECK_RESULT_INTERNAL_ERROR; return CHECK_ERR(ppc, "%suuid generation failed", loc->prefix); } CHECK_INFO(ppc, "%ssetting pool_hdr.uuid to %s", loc->prefix, check_get_uuid_str(loc->hdr.uuid)); break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * pool_hdr_nondefault_fix -- (internal) fix custom value fields */ static int pool_hdr_nondefault_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *context) { LOG(3, NULL); ASSERTne(loc, NULL); uint64_t *flags = NULL; switch (question) { case Q_CRTIME: CHECK_INFO(ppc, "%ssetting pool_hdr.crtime to file's modtime: " "%s", loc->prefix, check_get_time_str(ppc->pool->set_file->mtime)); util_convert2h_hdr_nocheck(&loc->hdr); loc->hdr.crtime = (uint64_t)ppc->pool->set_file->mtime; util_convert2le_hdr(&loc->hdr); break; case Q_ARCH_FLAGS: flags = (uint64_t *)&loc->valid_part_hdrp->arch_flags; CHECK_INFO(ppc, "%ssetting pool_hdr.arch_flags to 0x%08" PRIx64 "%08" PRIx64, loc->prefix, flags[0], flags[1]); util_convert2h_hdr_nocheck(&loc->hdr); memcpy(&loc->hdr.arch_flags, &loc->valid_part_hdrp->arch_flags, sizeof(struct arch_flags)); util_convert2le_hdr(&loc->hdr); break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * sds_check -- (internal) check shutdown_state */ static int sds_check(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); CHECK_INFO(ppc, "%s" SDS_CHECK_STR, loc->prefix); /* shutdown state is valid */ if (!sds_check_replica(loc)) { CHECK_INFO(ppc, "%s" SDS_OK_STR, loc->prefix); loc->step = CHECK_STEP_COMPLETE; return 0; } /* shutdown state is NOT valid and can NOT be repaired */ if (CHECK_IS_NOT(ppc, REPAIR)) { check_end(ppc->data); ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%s%s", loc->prefix, SDS_FAIL_MSG(&loc->hdr)); } /* shutdown state is NOT valid but can be repaired */ CHECK_ASK(ppc, Q_RESET_SDS, "%s%s", loc->prefix, SDS_REPAIR_MSG(&loc->hdr)); return check_questions_sequence_validate(ppc); }
/* * cto_hdr_fix -- (internal) fix pmemcto header */ static int cto_hdr_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *ctx) { LOG(3, NULL); switch (question) { case Q_CTO_CONSISTENT: CHECK_INFO(ppc, "setting pmemcto.consistent flag"); ppc->pool->hdr.cto.consistent = 1; break; case Q_CTO_ADDR: CHECK_INFO(ppc, "recovering pmemcto.addr"); ppc->pool->hdr.cto.addr = 0; break; case Q_CTO_SIZE: CHECK_INFO(ppc, "setting pmemcto.size to the actual pool size %zu", ppc->pool->params.size); ppc->pool->hdr.cto.size = ppc->pool->params.size; break; case Q_CTO_ROOT: CHECK_INFO(ppc, "recovering pmemcto.root pointer"); ppc->pool->hdr.cto.root = 0; break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * pool_hdr_preliminary_check -- (internal) check pool header checksum and pool * parameters */ static int pool_hdr_preliminary_check(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); CHECK_INFO(ppc, "%schecking pool header", loc->prefix); if (util_is_zeroed((void *)&loc->hdr, sizeof(loc->hdr))) { if (CHECK_IS_NOT(ppc, REPAIR)) { check_end(ppc->data); ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sempty pool hdr", loc->prefix); } } else if (loc->hdr_valid) { enum pool_type type = pool_hdr_get_type(&loc->hdr); if (type == POOL_TYPE_UNKNOWN) { if (CHECK_IS_NOT(ppc, REPAIR)) { check_end(ppc->data); ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sinvalid signature", loc->prefix); } CHECK_INFO(ppc, "%sinvalid signature", loc->prefix); } else { /* valid check sum */ CHECK_INFO(ppc, "%spool header correct", loc->prefix); loc->step = CHECK_STEP_COMPLETE; return 0; } } else if (CHECK_IS_NOT(ppc, REPAIR)) { check_end(ppc->data); ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sincorrect pool header", loc->prefix); } else { CHECK_INFO(ppc, "%sincorrect pool header", loc->prefix); } ASSERT(CHECK_IS(ppc, REPAIR)); if (ppc->pool->params.type == POOL_TYPE_UNKNOWN) { ppc->pool->params.type = pool_hdr_possible_type(ppc); if (ppc->pool->params.type == POOL_TYPE_UNKNOWN) { ppc->result = CHECK_RESULT_CANNOT_REPAIR; return CHECK_ERR(ppc, "cannot determine pool type"); } } if (!pool_supported(ppc->pool->params.type)) { ppc->result = CHECK_RESULT_CANNOT_REPAIR; return CHECK_ERR(ppc, "the repair of %s pools is not supported", pool_get_pool_type_str(ppc->pool->params.type)); } return 0; }
/* * check_push_answer -- process answer and push it to answers queue */ int check_push_answer(PMEMpoolcheck *ppc) { if (ppc->data->check_status_cache == NULL) return 0; /* check if answer is "yes" or "no" */ struct check_status *status = ppc->data->check_status_cache; if (status->status.str.answer != NULL) { if (strcmp(status->status.str.answer, CHECK_ANSWER_YES) == 0) status->answer = PMEMPOOL_CHECK_ANSWER_YES; else if (strcmp(status->status.str.answer, CHECK_ANSWER_NO) == 0) status->answer = PMEMPOOL_CHECK_ANSWER_NO; } if (status->answer == PMEMPOOL_CHECK_ANSWER_EMPTY) { /* invalid answer provided */ status_answer_push(ppc->data, ppc->data->check_status_cache); ppc->data->check_status_cache = NULL; CHECK_INFO(ppc, "Answer must be either %s or %s", CHECK_ANSWER_YES, CHECK_ANSWER_NO); return -1; } /* push answer */ TAILQ_INSERT_TAIL(&ppc->data->answers, ppc->data->check_status_cache, next); ppc->data->check_status_cache = NULL; return 0; }
/* * pool_hdr_uuid_links_fix -- (internal) fix UUID links values */ static int pool_hdr_uuid_links_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *context) { LOG(3, NULL); ASSERTne(loc, NULL); switch (question) { case Q_NEXT_PART_UUID_SET: CHECK_INFO(ppc, "%ssetting pool_hdr.next_part_uuid to %s", loc->prefix, check_get_uuid_str(loc->next_part_hdrp->uuid)); memcpy(loc->hdr.next_part_uuid, loc->next_part_hdrp->uuid, POOL_HDR_UUID_LEN); break; case Q_PREV_PART_UUID_SET: CHECK_INFO(ppc, "%ssetting pool_hdr.prev_part_uuid to %s", loc->prefix, check_get_uuid_str(loc->prev_part_hdrp->uuid)); memcpy(loc->hdr.prev_part_uuid, loc->prev_part_hdrp->uuid, POOL_HDR_UUID_LEN); break; case Q_NEXT_REPL_UUID_SET: CHECK_INFO(ppc, "%ssetting pool_hdr.next_repl_uuid to %s", loc->prefix, check_get_uuid_str(loc->next_repl_hdrp->uuid)); memcpy(loc->hdr.next_repl_uuid, loc->next_repl_hdrp->uuid, POOL_HDR_UUID_LEN); break; case Q_PREV_REPL_UUID_SET: CHECK_INFO(ppc, "%ssetting pool_hdr.prev_repl_uuid to %s", loc->prefix, check_get_uuid_str(loc->prev_repl_hdrp->uuid)); memcpy(loc->hdr.prev_repl_uuid, loc->prev_repl_hdrp->uuid, POOL_HDR_UUID_LEN); break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * backup_poolset -- (internal) backup the poolset */ static int backup_poolset(PMEMpoolcheck *ppc, location *loc, int overwrite) { struct pool_replica *srep = ppc->pool->set_file->poolset->replica[0]; struct pool_replica *drep = loc->set->replica[0]; for (unsigned p = 0; p < srep->nparts; p++) { if (overwrite == 0) { CHECK_INFO(ppc, "creating backup file: %s", drep->part[p].path); } if (pool_set_part_copy(&drep->part[p], &srep->part[p], overwrite)) { location_release(loc); ppc->result = CHECK_RESULT_ERROR; CHECK_INFO(ppc, "unable to create backup file"); return CHECK_ERR(ppc, "unable to backup poolset"); } } return 0; }
/* * backup_nonpoolset_create -- (internal) create backup */ static int backup_nonpoolset_create(PMEMpoolcheck *ppc, location *loc) { CHECK_INFO(ppc, "creating backup file: %s", ppc->backup_path); if (pool_copy(ppc->pool, ppc->backup_path, 0)) { location_release(loc); ppc->result = CHECK_RESULT_ERROR; return CHECK_ERR(ppc, "cannot perform backup"); } location_release(loc); loc->step = CHECK_STEP_COMPLETE; return 0; }
/* * sds_fix -- (internal) fix shutdown state */ static int sds_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *context) { LOG(3, NULL); switch (question) { case Q_RESET_SDS: CHECK_INFO(ppc, "%sresetting pool_hdr.sds", loc->prefix); memset(&loc->hdr.sds, 0, sizeof(loc->hdr.sds)); ++loc->healthy_replicas; break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * pool_hdr_checksum_fix -- (internal) fix checksum */ static int pool_hdr_checksum_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *context) { LOG(3, NULL); ASSERTne(loc, NULL); switch (question) { case Q_CHECKSUM: util_checksum(&loc->hdr, sizeof(loc->hdr), &loc->hdr.checksum, 1, POOL_HDR_CSUM_END_OFF); CHECK_INFO(ppc, "%ssetting pool_hdr.checksum to 0x%jx", loc->prefix, le64toh(loc->hdr.checksum)); break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * pool_hdr_checksum -- (internal) validate checksum */ static int pool_hdr_checksum(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); if (loc->hdr_valid) return 0; if (CHECK_IS_NOT(ppc, REPAIR)) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, INVALID_CHECKSUM, loc->prefix); } else if (CHECK_IS_NOT(ppc, ADVANCED)) { ppc->result = CHECK_RESULT_CANNOT_REPAIR; CHECK_INFO(ppc, "%s" REQUIRE_ADVANCED, loc->prefix); return CHECK_ERR(ppc, INVALID_CHECKSUM, loc->prefix); } CHECK_ASK(ppc, Q_CHECKSUM, INVALID_CHECKSUM ".|Do you want to " "regenerate checksum?", loc->prefix); return check_questions_sequence_validate(ppc); }
/* * pool_hdr_default_fix -- (internal) fix some default values in pool header */ static int pool_hdr_default_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *context) { LOG(3, NULL); ASSERTne(loc, NULL); struct pool_hdr def_hdr; pool_hdr_default(ppc->pool->params.type, &def_hdr); switch (question) { case Q_DEFAULT_SIGNATURE: CHECK_INFO(ppc, "%ssetting pool_hdr.signature to %.8s", loc->prefix, def_hdr.signature); memcpy(&loc->hdr.signature, &def_hdr.signature, POOL_HDR_SIG_LEN); break; case Q_DEFAULT_MAJOR: CHECK_INFO(ppc, "%ssetting pool_hdr.major to 0x%x", loc->prefix, def_hdr.major); loc->hdr.major = def_hdr.major; break; case Q_DEFAULT_COMPAT_FEATURES: CHECK_INFO(ppc, "%ssetting pool_hdr.compat_features to 0x%x", loc->prefix, def_hdr.compat_features); loc->hdr.compat_features = def_hdr.compat_features; break; case Q_DEFAULT_INCOMPAT_FEATURES: CHECK_INFO(ppc, "%ssetting pool_hdr.incompat_features to 0x%x", loc->prefix, def_hdr.incompat_features); loc->hdr.incompat_features = def_hdr.incompat_features; break; case Q_DEFAULT_RO_COMPAT_FEATURES: CHECK_INFO(ppc, "%ssetting pool_hdr.ro_compat_features to 0x%x", loc->prefix, def_hdr.ro_compat_features); loc->hdr.ro_compat_features = def_hdr.ro_compat_features; break; case Q_ZERO_UNUSED_AREA: CHECK_INFO(ppc, "%ssetting pool_hdr.unused to zeros", loc->prefix); memset(loc->hdr.unused, 0, sizeof(loc->hdr.unused)); break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * pool_hdr_nondefault -- (internal) validate custom value fields */ static int pool_hdr_nondefault(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); if (loc->hdr.crtime > (uint64_t)ppc->pool->set_file->mtime) { const char *error = "%spool_hdr.crtime is not valid"; if (CHECK_IS_NOT(ppc, REPAIR)) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, error, loc->prefix); } else if (CHECK_IS_NOT(ppc, ADVANCED)) { ppc->result = CHECK_RESULT_CANNOT_REPAIR; CHECK_INFO(ppc, "%s" REQUIRE_ADVANCED, loc->prefix); return CHECK_ERR(ppc, error, loc->prefix); } CHECK_ASK(ppc, Q_CRTIME, "%spool_hdr.crtime is not valid.|Do you want to set it " "to file's modtime [%s]?", loc->prefix, check_get_time_str(ppc->pool->set_file->mtime)); } if (loc->valid_part_hdrp && memcmp(&loc->valid_part_hdrp->arch_flags, &loc->hdr.arch_flags, sizeof(struct arch_flags)) != 0) { const char *error = "%spool_hdr.arch_flags is not valid"; if (CHECK_IS_NOT(ppc, REPAIR)) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, error, loc->prefix); } CHECK_ASK(ppc, Q_ARCH_FLAGS, "%spool_hdr.arch_flags is not valid.|Do you want to " "copy it from a valid part?", loc->prefix); } return check_questions_sequence_validate(ppc); }
/* * backup_poolset_requirements -- (internal) check backup requirements */ static int backup_poolset_requirements(PMEMpoolcheck *ppc, location *loc) { LOG(3, "backup_path %s", ppc->backup_path); if (ppc->pool->set_file->poolset->nreplicas > 1) { CHECK_INFO(ppc, "backup of a poolset with multiple replicas is not supported"); goto err; } if (pool_set_parse(&loc->set, ppc->backup_path)) { CHECK_INFO(ppc, "invalid poolset backup file: %s", ppc->backup_path); goto err; } if (loc->set->nreplicas > 1) { CHECK_INFO(ppc, "backup to a poolset with multiple replicas is not supported"); goto err_poolset; } ASSERTeq(loc->set->nreplicas, 1); struct pool_replica *srep = ppc->pool->set_file->poolset->replica[0]; struct pool_replica *drep = loc->set->replica[0]; if (srep->nparts != drep->nparts) { CHECK_INFO(ppc, "number of part files in the backup poolset must match number of part files in the source poolset"); goto err_poolset; } int overwrite_required = 0; for (unsigned p = 0; p < srep->nparts; p++) { if (srep->part[p].filesize != drep->part[p].filesize) { CHECK_INFO(ppc, "size of the part %u of the backup poolset does not match source poolset", p); goto err_poolset; } if (os_access(drep->part[p].path, F_OK)) { if (errno == ENOENT) { errno = 0; continue; } else { CHECK_INFO(ppc, "unable to access the part of the destination poolset: %s", ppc->backup_path); goto err_poolset; } } overwrite_required = true; if ((size_t)util_file_get_size(drep->part[p].path) != srep->part[p].filesize) { CHECK_INFO(ppc, "destination of the backup part does not match size of the source part file: %s", drep->part[p].path); goto err_poolset; } } if (CHECK_WITHOUT_FIXING(ppc)) { location_release(loc); loc->step = CHECK_STEP_COMPLETE; return 0; } if (overwrite_required) { CHECK_ASK(ppc, Q_OVERWRITE_EXISTING_PARTS, "part files of the destination poolset of the backup already exist.|" "Do you want to overwrite them?"); } return check_questions_sequence_validate(ppc); err_poolset: location_release(loc); err: ppc->result = CHECK_RESULT_ERROR; return CHECK_ERR(ppc, "unable to backup poolset"); }
/* * cto_hdr_check -- (internal) check pmemcto header */ static int cto_hdr_check(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); CHECK_INFO(ppc, "checking pmemcto header"); if (cto_read(ppc)) { ppc->result = CHECK_RESULT_ERROR; return -1; } if (ppc->pool->hdr.cto.consistent == 0) { if (CHECK_ASK(ppc, Q_CTO_CONSISTENT, "pmemcto.consistent flag is not set.|Do you want to set pmemcto.consistent flag?")) goto error; } if ((void *)ppc->pool->hdr.cto.addr == NULL) { if (CHECK_ASK(ppc, Q_CTO_ADDR, "invalid pmemcto.addr: %p.|Do you want to recover pmemcto.addr?", (void *)ppc->pool->hdr.cto.addr)) goto error; } if (ppc->pool->hdr.cto.size < PMEMCTO_MIN_POOL) { CHECK_INFO(ppc, "pmemcto.size is less than minimum: %zu < %zu.", ppc->pool->hdr.cto.size, PMEMCTO_MIN_POOL); } if (ppc->pool->hdr.cto.size != ppc->pool->params.size) { if (CHECK_ASK(ppc, Q_CTO_SIZE, "pmemcto.size is different than pool size: %zu != %zu.|Do you want to set pmemlog.size to the actual pool size?", ppc->pool->hdr.cto.size, ppc->pool->params.size)) goto error; } char *valid_addr_begin = (char *)ppc->pool->hdr.cto.addr + CTO_DSC_SIZE_ALIGNED; char *valid_addr_end = (char *)ppc->pool->hdr.cto.addr + ppc->pool->hdr.cto.size; if ((void *)ppc->pool->hdr.cto.root != NULL && ((char *)ppc->pool->hdr.cto.root < valid_addr_begin || (char *)ppc->pool->hdr.cto.root >= valid_addr_end)) { if (CHECK_ASK(ppc, Q_CTO_ROOT, "invalid pmemcto.root: %p.|Do you want to recover pmemcto.root?", (void *)ppc->pool->hdr.cto.root)) goto error; } if (ppc->result == CHECK_RESULT_CONSISTENT || ppc->result == CHECK_RESULT_REPAIRED) CHECK_INFO(ppc, "pmemcto header correct"); return check_questions_sequence_validate(ppc); error: ppc->result = CHECK_RESULT_NOT_CONSISTENT; check_end(ppc->data); return -1; }
/* * pool_hdr_uuid_find -- (internal) check UUID value */ static int pool_hdr_uuid_find(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); /* * If the pool header is valid and there is not other parts or replicas * in the poolset its uuid is also valid. */ if (loc->hdr_valid && loc->single_repl && loc->single_part) return 0; int hdrs_valid[] = { loc->next_part_hdr_valid, loc->prev_part_hdr_valid, loc->next_repl_hdr_valid, loc->prev_repl_hdr_valid}; uuid_t *uuids[] = { &loc->next_part_hdrp->prev_part_uuid, &loc->prev_part_hdrp->next_part_uuid, &loc->next_repl_hdrp->prev_repl_uuid, &loc->prev_repl_hdrp->next_repl_uuid }; /* * if all valid poolset part files have the same uuid links to this part * file it is valid uuid * if all links have the same uuid and it is single file pool it is also * the valid uuid */ loc->valid_uuid = NULL; if (loc->hdr_valid) loc->valid_uuid = &loc->hdr.uuid; uuid_t *common_uuid = uuids[0]; COMPILE_ERROR_ON(ARRAY_SIZE(uuids) != ARRAY_SIZE(hdrs_valid)); COMPILE_ERROR_ON(COMPARE_TO_FIRST_PART_ONLY >= ARRAY_SIZE(uuids)); for (unsigned i = 0; i < ARRAY_SIZE(uuids); ++i) { if (i > 0 && common_uuid != NULL) { if (uuidcmp(*common_uuid, *uuids[i]) != 0) { common_uuid = NULL; } } if (i >= COMPARE_TO_FIRST_PART_ONLY && loc->part != 0) continue; if (!hdrs_valid[i]) continue; if (!loc->valid_uuid) { loc->valid_uuid = uuids[i]; } else if (uuidcmp(*loc->valid_uuid, *uuids[i]) != 0) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sambiguous pool_hdr.uuid", loc->prefix); } } if (!loc->valid_uuid && common_uuid) loc->valid_uuid = common_uuid; if (loc->valid_uuid != NULL) { if (uuidcmp(*loc->valid_uuid, loc->hdr.uuid) != 0) { CHECK_ASK(ppc, Q_UUID_SET, INVALID_UUID ".|Do you want " "to set it to %s from a valid part file?", loc->prefix, check_get_uuid_str(*loc->valid_uuid)); } } else if (CHECK_IS(ppc, ADVANCED)) { CHECK_ASK(ppc, Q_UUID_REGENERATE, INVALID_UUID ".|Do you want " "to regenerate it?", loc->prefix); } else if (CHECK_IS(ppc, REPAIR)) { ppc->result = CHECK_RESULT_CANNOT_REPAIR; CHECK_INFO(ppc, "%s" REQUIRE_ADVANCED, loc->prefix); return CHECK_ERR(ppc, INVALID_UUID, loc->prefix); } else { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, INVALID_UUID, loc->prefix); } return check_questions_sequence_validate(ppc); }
/* * pool_hdr_poolset_uuid -- (internal) check poolset_uuid field */ static int pool_hdr_poolset_uuid_find(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); /* * If the pool header is valid and there is not other parts or replicas * in the poolset its poolset_uuid is also valid. */ if (loc->hdr_valid && loc->single_repl && loc->single_part) return 0; if (loc->replica != 0 || loc->part != 0) goto after_lookup; /* for blk pool we can take the UUID from BTT Info header */ if (ppc->pool->params.type == POOL_TYPE_BLK && ppc->pool->bttc.valid) { loc->valid_puuid = &ppc->pool->bttc.btt_info.parent_uuid; if (uuidcmp(loc->hdr.poolset_uuid, *loc->valid_puuid) != 0) { CHECK_ASK(ppc, Q_POOLSET_UUID_FROM_BTT_INFO, "%sinvalid pool_hdr.poolset_uuid.|Do you want " "to set it to %s from BTT Info?", loc->prefix, check_get_uuid_str(*loc->valid_puuid)); goto exit_question; } } if (loc->single_part && loc->single_repl) { /* * If the pool is not blk pool or BTT Info header is invalid * there is no other way to validate poolset uuid. */ return 0; } /* * if all valid poolset part files have the same poolset uuid it is * the valid poolset uuid * if all part files have the same poolset uuid it is valid poolset uuid */ struct pool_set *poolset = ppc->pool->set_file->poolset; unsigned nreplicas = poolset->nreplicas; uuid_t *common_puuid = loc->valid_puuid; for (unsigned r = 0; r < nreplicas; r++) { struct pool_replica *rep = REP(poolset, r); for (unsigned p = 0; p < rep->nhdrs; p++) { struct pool_hdr *hdr = HDR(rep, p); /* * find poolset uuid if it is the same for all part * files */ if (common_puuid == NULL) { if (r == 0 && p == 0) { common_puuid = &hdr->poolset_uuid; } } else if (uuidcmp(*common_puuid, hdr->poolset_uuid) != 0) { common_puuid = NULL; } if (!pool_hdr_valid(hdr)) continue; /* * find poolset uuid if it is the same for all valid * part files */ if (loc->valid_puuid == NULL) { loc->valid_puuid = &hdr->poolset_uuid; } else if (uuidcmp(*loc->valid_puuid, hdr->poolset_uuid) != 0) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "the poolset contains " "part files from various poolsets"); } } } if (!loc->valid_puuid && common_puuid) loc->valid_puuid = common_puuid; if (loc->valid_puuid) goto after_lookup; if (CHECK_IS_NOT(ppc, REPAIR)) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, NO_COMMON_POOLSET_UUID, loc->prefix); } else if (CHECK_IS_NOT(ppc, ADVANCED)) { ppc->result = CHECK_RESULT_CANNOT_REPAIR; CHECK_INFO(ppc, "%s" REQUIRE_ADVANCED, loc->prefix); return CHECK_ERR(ppc, NO_COMMON_POOLSET_UUID, loc->prefix); } else { CHECK_ASK(ppc, Q_POOLSET_UUID_REGENERATE, NO_COMMON_POOLSET_UUID ".|Do you want to regenerate pool_hdr.poolset_uuid?", loc->prefix); goto exit_question; } after_lookup: if (loc->valid_puuid) { if (uuidcmp(*loc->valid_puuid, loc->hdr.poolset_uuid) != 0) { if (CHECK_IS_NOT(ppc, REPAIR)) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sinvalid " "pool_hdr.poolset_uuid", loc->prefix); } CHECK_ASK(ppc, Q_POOLSET_UUID_SET, "%sinvalid " "pool_hdr.poolset_uuid.|Do you want to set " "it to %s from a valid part file?", loc->prefix, check_get_uuid_str(*loc->valid_puuid)); } } exit_question: return check_questions_sequence_validate(ppc); }