/* * check_uuids_between_replicas -- (internal) check if uuids between internally * consistent adjacent replicas are consistent */ static int check_uuids_between_replicas(struct pool_set *set, struct poolset_health_status *set_hs) { for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip comparing inconsistent pairs of replicas */ if (!replica_is_replica_consistent(r, set_hs) || !replica_is_replica_consistent(r + 1, set_hs)) continue; struct pool_replica *rep = REP(set, r); struct pool_replica *rep_n = REP(set, r + 1); struct replica_health_status *rep_hs = REP(set_hs, r); struct replica_health_status *rep_n_hs = REP(set_hs, r + 1); /* check adjacent replica uuids for yet unbroken parts */ unsigned p = replica_find_unbroken_part(r, set_hs); unsigned p_n = replica_find_unbroken_part(r + 1, set_hs); /* if the first part is broken, cannot compare replica uuids */ if (p > 0) { rep_hs->flags |= IS_BROKEN; continue; } /* if the first part is broken, cannot compare replica uuids */ if (p_n > 0) { rep_n_hs->flags |= IS_BROKEN; continue; } /* check if replica uuids are consistent between replicas */ if (uuidcmp(HDR(rep_n, p_n)->prev_repl_uuid, HDR(rep, p)->uuid) || uuidcmp( HDR(rep, p)->next_repl_uuid, HDR(rep_n, p_n)->uuid)) { if (set->nreplicas == 1) { rep_hs->flags |= IS_INCONSISTENT; } else { if (replica_is_replica_broken(r, set_hs)) { rep_hs->flags |= IS_BROKEN; continue; } if (replica_is_replica_broken(r + 1, set_hs)) { rep_n_hs->flags |= IS_BROKEN; continue; } // two unbroken and internally consistent // adjacent replicas have different adjacent // replica uuids - mark one as inconsistent rep_n_hs->flags |= IS_INCONSISTENT; continue; } } } return 0; }
/* * pool_params_from_header -- parse pool params from pool header */ void pool_params_from_header(struct pool_params *params, const struct pool_hdr *hdr) { memcpy(params->signature, hdr->signature, sizeof(params->signature)); /* * Check if file is a part of pool set by comparing the UUID with the * next part UUID. If it is the same it means the pool consist of a * single file. */ int uuid_eq_next = uuidcmp(hdr->uuid, hdr->next_part_uuid); int uuid_eq_prev = uuidcmp(hdr->uuid, hdr->prev_part_uuid); params->is_part = !params->is_poolset && (uuid_eq_next || uuid_eq_prev); params->type = pool_hdr_get_type(hdr); }
/* * check_replica_cycles -- (internal) check if healthy replicas form cycles * shorter than the number of all replicas */ static int check_replica_cycles(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); unsigned first_healthy; unsigned count_healthy = 0; for (unsigned r = 0; r < set->nreplicas; ++r) { if (!replica_is_replica_healthy(r, set_hs)) { count_healthy = 0; continue; } if (count_healthy == 0) first_healthy = r; ++count_healthy; struct pool_hdr *hdrh = PART(REP(set, first_healthy), 0).hdr; struct pool_hdr *hdr = PART(REP(set, r), 0).hdr; if (uuidcmp(hdrh->uuid, hdr->next_repl_uuid) == 0 && count_healthy < set->nreplicas) { /* * healthy replicas form a cycle shorter than * the number of all replicas; for the user it * means that: */ ERR("there exist healthy replicas which come" " from a different poolset file"); return -1; } } return 0; }
/* * check_replica_poolset_uuids - (internal) check if poolset_uuid fields are * consistent among all parts of a replica; * the replica is initially considered as * consistent */ static int check_replica_poolset_uuids(struct pool_set *set, unsigned repn, uuid_t poolset_uuid, struct poolset_health_status *set_hs) { LOG(3, "set %p, repn %u, poolset_uuid %p, set_hs %p", set, repn, poolset_uuid, set_hs); struct pool_replica *rep = REP(set, repn); for (unsigned p = 0; p < rep->nhdrs; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (uuidcmp(HDR(rep, p)->poolset_uuid, poolset_uuid)) { /* * two internally consistent replicas have * different poolset_uuid */ return -1; } else { /* * it is sufficient to check only one part * from internally consistent replica */ break; } } return 0; }
/* * is_uuid_already_used -- (internal) check if given uuid is assigned to * any of the earlier replicas */ static int is_uuid_already_used(uuid_t uuid, struct pool_set *set, unsigned repn) { for (unsigned r = 0; r < repn; ++r) { if (uuidcmp(uuid, PART(REP(set, r), 0).uuid) == 0) return 1; } return 0; }
/* * pool_hdr_uuid_links -- (internal) check UUID links values */ static int pool_hdr_uuid_links(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 links are also valid. */ if (loc->hdr_valid && loc->single_repl && loc->single_part) return 0; uuid_t *links[] = { &loc->hdr.next_part_uuid, &loc->hdr.prev_part_uuid, &loc->hdr.next_repl_uuid, &loc->hdr.prev_repl_uuid}; uuid_t *uuids[] = { &loc->next_part_hdrp->uuid, &loc->prev_part_hdrp->uuid, &loc->next_repl_hdrp->uuid, &loc->prev_repl_hdrp->uuid }; uint32_t questions[] = { Q_NEXT_PART_UUID_SET, Q_PREV_PART_UUID_SET, Q_NEXT_REPL_UUID_SET, Q_PREV_REPL_UUID_SET }; const char *fields[] = { "pool_hdr.next_part_uuid", "pool_hdr.prev_part_uuid", "pool_hdr.next_repl_uuid", "pool_hdr.prev_repl_uuid" }; COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(uuids)); COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(questions)); COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(fields)); for (uint64_t i = 0; i < ARRAY_SIZE(links); ++i) { if (uuidcmp(*links[i], *uuids[i]) == 0) continue; if (CHECK_IS(ppc, REPAIR)) { CHECK_ASK(ppc, questions[i], "%sinvalid %s.|Do you want to set it to a " "valid value?", loc->prefix, fields[i]); } else { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sinvalid %s", loc->prefix, fields[i]); } } return check_questions_sequence_validate(ppc); }
static bool do_list(void) { struct dsp_ndb_props props; unsigned num = 0, i; void *proc_handle; struct node_info *node_table; void **tmp_table; unsigned node_count = 0, allocated_count = 0; if (!dsp_enum(dsp_handle, 0, &props, sizeof(props), &num)) { pr_err("failed to enumerate nodes"); return false; } if (!dsp_attach(dsp_handle, 0, NULL, &proc_handle)) { pr_err("dsp attach failed"); return false; } node_table = calloc(num, sizeof(*node_table)); for (i = 0; i < num; i++) { if (dsp_enum(dsp_handle, i, &props, sizeof(props), &num)) { memcpy(&node_table[i].id, &props.node_id, sizeof(props.node_id)); memcpy(&node_table[i].name, props.ac_name, sizeof(props.ac_name)); node_table[i].type = props.ntype; node_table[i].state = -1; } } tmp_table = calloc(num, sizeof(*tmp_table)); if (dsp_enum_nodes(dsp_handle, proc_handle, tmp_table, num, &node_count, &allocated_count)) { for (i = 0; i < node_count; i++) { struct dsp_node_attr attr; struct dsp_node node = { .handle = tmp_table[i] }; if (dsp_node_get_attr(dsp_handle, &node, &attr, sizeof(attr))) { unsigned j; for (j = 0; j < num; j++) { if (uuidcmp(&node_table[j].id, &attr.info.props.node_id)) { node_table[j].state = attr.info.state; break; } } } } } else {
/* * check_replica_poolset_uuids - (internal) check if poolset_uuid fields are * consistent among all parts of a replica; * the replica is initially considered as * consistent */ static int check_replica_poolset_uuids(struct pool_set *set, unsigned repn, uuid_t poolset_uuid, struct poolset_health_status *set_hs) { LOG(3, "set %p, repn %u, poolset_uuid %p, set_hs %p", set, repn, poolset_uuid, set_hs); struct pool_replica *rep = REP(set, repn); for (unsigned p = 0; p < rep->nparts; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (!uuidcmp(HDR(rep, p)->poolset_uuid, poolset_uuid)) { /* * two internally consistent replicas have * different poolset_uuid */ if (replica_is_replica_broken(repn, set_hs)) { /* mark broken replica as inconsistent */ REP(set_hs, repn)->flags |= IS_INCONSISTENT; } else { /* * two consistent unbroken replicas * - cannot synchronize */ ERR("inconsistent poolset_uuid values"); return -1; } } else { /* * it is sufficient to check only one part * from internally consistent replica */ break; } } return 0; }
int main (int argc, const char *argv[]) { const char *tstr = NULL; var *env = var_alloc(); var *env_collector = var_get_dict_forkey (env, "collector"); var *env_colors = var_get_array_forkey (env, "colors"); var_set_int_forkey (env_collector, "listenport", 3333); var_set_str_forkey (env_collector, "address", "127.0.0.1"); var_set_str_forkey (env_collector, "key", "secret"); var_clear_array (env_colors); var_add_str (env_colors, "red"); var_add_str (env_colors, "green"); var_add_str (env_colors, "blue"); assert (var_get_int_forkey (env_collector, "listenport") == 3333); assert (tstr = var_get_str_forkey (env_collector, "address")); assert (strcmp (tstr, "127.0.0.1") == 0); assert (tstr = var_get_str_forkey (env_collector, "key")); assert (strcmp (tstr, "secret") == 0); assert (var_get_count (env_collector) == 3); assert (tstr = var_get_str_atindex (env_colors, 0)); assert (strcmp (tstr, "red") == 0); assert (tstr = var_get_str_atindex (env_colors, 1)); assert (strcmp (tstr, "green") == 0); assert (tstr = var_get_str_atindex (env_colors, 2)); assert (strcmp (tstr, "blue") == 0); time_t tnow = time (NULL); var_set_time_forkey (env, "nowtime", tnow); assert (var_get_time_forkey (env, "nowtime") == tnow); var_set_unixtime_forkey (env, "unixtime", tnow); assert (var_get_time_forkey (env, "unixtime") == tnow); uuid uuid_in = uuidgen(); var_set_uuid_forkey (env, "myuuid", uuid_in); uuid uuid_out = var_get_uuid_forkey (env, "myuuid"); assert (uuidcmp (uuid_in, uuid_out)); var_new_generation (env); var_set_int_forkey (env_collector, "listenport", 3333); var_set_str_forkey (env_collector, "address", "192.168.1.1"); var_clear_array (env_colors); var_add_str (env_colors, "red"); var_add_str (env_colors, "green"); var_add_str (env_colors, "blue"); var *lport, *addr, *key; lport = var_find_key (env_collector, "listenport"); addr = var_find_key (env_collector, "address"); key = var_find_key (env_collector, "key"); assert (lport); assert (addr); assert (key); /* collector.listenport should be unchanged from first generation */ assert (lport->generation == env->generation); assert (lport->lastmodified < env->generation); assert (lport->firstseen == lport->lastmodified); /* collector.addr should be changed this generation */ assert (addr->generation == env->generation); assert (addr->lastmodified == env->generation); assert (addr->firstseen == env->firstseen); /* colors should be changed this generation */ assert (env_colors->generation == env->generation); assert (env_colors->lastmodified == env->generation); assert (env_colors->firstseen == env->firstseen); /* collector.key should be stale */ assert (key->generation < env->generation); var_clean_generation (env); /* collector.key should now be deleted */ key = var_find_key (env_collector, "key"); assert (key == NULL); return 0; }
/* * check_uuids_between_parts -- (internal) check if uuids between adjacent * parts are consistent for a given replica */ static void check_uuids_between_parts(struct pool_set *set, unsigned repn, struct poolset_health_status *set_hs) { LOG(3, "set %p, repn %u, set_hs %p", set, repn, set_hs); struct pool_replica *rep = REP(set, repn); struct replica_health_status *rep_hs = REP(set_hs, repn); /* check parts linkage */ LOG(4, "checking parts linkage in replica %u", repn); for (unsigned p = 0; p < rep->nparts; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; struct pool_hdr *hdrp = HDR(rep, p); struct pool_hdr *next_hdrp = HDR(rep, p + 1); int next_is_broken = replica_is_part_broken(repn, p + 1, set_hs); if (!next_is_broken) { int next_decoupled = uuidcmp(next_hdrp->prev_part_uuid, hdrp->uuid) || uuidcmp(hdrp->next_part_uuid, next_hdrp->uuid); if (next_decoupled) { rep_hs->flags |= IS_INCONSISTENT; /* skip further checking */ return; } } } /* check if all uuids for adjacent replicas are the same across parts */ LOG(4, "checking consistency of adjacent replicas' uuids in replica %u", repn); unsigned unbroken_p = UNDEF_PART; for (unsigned p = 0; p < rep->nparts; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (unbroken_p == UNDEF_PART) { unbroken_p = p; continue; } struct pool_hdr *hdrp = HDR(rep, p); int prev_differ = uuidcmp(HDR(rep, unbroken_p)->prev_repl_uuid, hdrp->prev_repl_uuid); int next_differ = uuidcmp(HDR(rep, unbroken_p)->next_repl_uuid, hdrp->next_repl_uuid); if (prev_differ || next_differ) { ERR("different adjacent replica UUID between parts"); rep_hs->flags |= IS_INCONSISTENT; /* skip further checking */ return; } } /* check poolset_uuid consistency between replica's parts */ LOG(4, "checking consistency of poolset uuid in replica %u", repn); uuid_t poolset_uuid; int uuid_stored = 0; for (unsigned p = 0; p < rep->nparts; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (!uuid_stored) { memcpy(poolset_uuid, HDR(rep, p)->poolset_uuid, POOL_HDR_UUID_LEN); uuid_stored = 1; continue; } if (uuidcmp(HDR(rep, p)->poolset_uuid, poolset_uuid)) { rep_hs->flags |= IS_INCONSISTENT; /* skip further checking */ return; } } }
/* * check_uuids_between_replicas -- (internal) check if uuids between internally * consistent adjacent replicas are consistent */ static int check_uuids_between_replicas(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip comparing inconsistent pairs of replicas */ if (!replica_is_replica_consistent(r, set_hs) || !replica_is_replica_consistent(r + 1, set_hs)) continue; struct pool_replica *rep = REP(set, r); struct pool_replica *rep_n = REPN(set, r); /* get uuids of the two adjacent replicas */ uuid_t *rep_uuidp = NULL; uuid_t *rep_n_uuidp = NULL; unsigned r_n = REPNidx(set_hs, r); if (get_replica_uuid(rep, r, set_hs, &rep_uuidp)) LOG(2, "cannot get replica uuid, replica %u", r); if (get_replica_uuid(rep_n, r_n, set_hs, &rep_n_uuidp)) LOG(2, "cannot get replica uuid, replica %u", r_n); /* * check if replica uuids are consistent between two adjacent * replicas */ unsigned p = replica_find_unbroken_part(r, set_hs); unsigned p_n = replica_find_unbroken_part(r_n, set_hs); if (p_n != UNDEF_PART && rep_uuidp != NULL && uuidcmp(*rep_uuidp, HDR(rep_n, p_n)->prev_repl_uuid)) { ERR( "inconsistent replica uuids between replicas %u and %u", r, r_n); return -1; } if (p != UNDEF_PART && rep_n_uuidp != NULL && uuidcmp(*rep_n_uuidp, HDR(rep, p)->next_repl_uuid)) { ERR( "inconsistent replica uuids between replicas %u and %u", r, r_n); return -1; } /* * check if replica uuids on borders of a broken replica are * consistent */ unsigned r_nn = REPNidx(set_hs, r_n); if (set->nreplicas > 1 && p != UNDEF_PART && replica_is_replica_broken(r_n, set_hs) && replica_is_replica_consistent(r_nn, set_hs)) { unsigned p_nn = replica_find_unbroken_part(r_nn, set_hs); if (p_nn == UNDEF_PART) { LOG(2, "cannot compare uuids on borders of replica %u", r); continue; } struct pool_replica *rep_nn = REP(set, r_nn); if (uuidcmp(HDR(rep, p)->next_repl_uuid, HDR(rep_nn, p_nn)->prev_repl_uuid)) { ERR( "inconsistent replica uuids on borders of replica %u", r); return -1; } } } return 0; }
/* * check_uuids_between_parts -- (internal) check if uuids between adjacent * parts are consistent for a given replica */ static int check_uuids_between_parts(struct pool_set *set, unsigned repn, struct poolset_health_status *set_hs) { LOG(3, "set %p, repn %u, set_hs %p", set, repn, set_hs); struct pool_replica *rep = REP(set, repn); /* check poolset_uuid consistency between replica's parts */ LOG(4, "checking consistency of poolset uuid in replica %u", repn); uuid_t poolset_uuid; int uuid_stored = 0; unsigned part_stored = UNDEF_PART; for (unsigned p = 0; p < rep->nhdrs; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (!uuid_stored) { memcpy(poolset_uuid, HDR(rep, p)->poolset_uuid, POOL_HDR_UUID_LEN); uuid_stored = 1; part_stored = p; continue; } if (uuidcmp(HDR(rep, p)->poolset_uuid, poolset_uuid)) { ERR("different poolset uuids in parts from the same" " replica (repn %u, parts %u and %u); cannot" " synchronize", repn, part_stored, p); errno = EINVAL; return -1; } } /* check if all uuids for adjacent replicas are the same across parts */ LOG(4, "checking consistency of adjacent replicas' uuids in replica %u", repn); unsigned unbroken_p = UNDEF_PART; for (unsigned p = 0; p < rep->nhdrs; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (unbroken_p == UNDEF_PART) { unbroken_p = p; continue; } struct pool_hdr *hdrp = HDR(rep, p); int prev_differ = uuidcmp(HDR(rep, unbroken_p)->prev_repl_uuid, hdrp->prev_repl_uuid); int next_differ = uuidcmp(HDR(rep, unbroken_p)->next_repl_uuid, hdrp->next_repl_uuid); if (prev_differ || next_differ) { ERR("different adjacent replica UUID between parts" " (repn %u, parts %u and %u);" " cannot synchronize", repn, unbroken_p, p); errno = EINVAL; return -1; } } /* check parts linkage */ LOG(4, "checking parts linkage in replica %u", repn); for (unsigned p = 0; p < rep->nhdrs; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; struct pool_hdr *hdrp = HDR(rep, p); struct pool_hdr *next_hdrp = HDRN(rep, p); int next_is_broken = replica_is_part_broken(repn, p + 1, set_hs); if (!next_is_broken) { int next_decoupled = uuidcmp(next_hdrp->prev_part_uuid, hdrp->uuid) || uuidcmp(hdrp->next_part_uuid, next_hdrp->uuid); if (next_decoupled) { ERR("two consecutive unbroken parts are not" " linked to each other (repn %u, parts" " %u and %u); cannot synchronize", repn, p, p + 1); errno = EINVAL; return -1; } } } return 0; }
/* * 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); }
int GptAllocFileCopy(HGPT hGPT, char *pszFileName, EFI_PARTITION_ENTRY *pNewEntry) { int i; int iPartition; QWORD qwLBA; int iErr; // To be cleaned up before return char *pSect = (char *)NULL; // End of clean-up zone int nSect; FILE *hf = NULL; // Compute the number of partition entries per sector. // int iEntryPerSect = hGPT->iSectorSize / sizeof(EFI_PARTITION_ENTRY); // Allocate a buffer to access drive data. pSect = (char *)malloc(hGPT->iSectorSize); if (!pSect) GptAllocFileCopyFail(-4); // Open the partition image file hf = fopen(pszFileName, "rb"); if (!hf) GptAllocFileCopyFail(-10); // Compute the number of sectors necessary. nSect = (int)((_filelength(_fileno(hf)) + hGPT->iSectorSize - 1) / hGPT->iSectorSize); // Search the smallest contiguous block of free sectors large enough. pNewEntry->EndingLBA = nSect; iPartition = GptAllocSectors(hGPT, pNewEntry); // Side effect: pNewEntry->PartitionTypeGUID = 0; if (iPartition < 0) GptAllocFileCopyFail(iPartition); #ifdef _DEBUG if (iVerbose) { printf("Allocating partition entry #%d for copying from file %s\n", iPartition, pszFileName); } #endif // Write the partition contents for (i=0, qwLBA=pNewEntry->StartingLBA; i<nSect; i++, qwLBA++) { size_t stRead; stRead = fread(pSect, 1, hGPT->iSectorSize, hf); if (stRead < (size_t)(hGPT->iSectorSize)) memset(pSect+stRead, 0, hGPT->iSectorSize-stRead); // ~~jfl 2001/12/19 Use the partition type GUID specified in the file, if any. if (i==0) { EFI_BOOT_PROGRAM_HEADER *pHdr = (EFI_BOOT_PROGRAM_HEADER *)pSect; if (CheckCrc(hGPT->iSectorSize, &(pHdr->Header))) { if (!memcmp(((char *)&(pHdr->Header.Signature))+3, "MBR32", 5)) { pNewEntry->PartitionTypeGUID = guidMbrBackup; // If it's inside the GPT, then it's the backup! } else // Assume it's a relay or a boot program (Including the boot menu). { // Both have a partition entry behind the header. pNewEntry->PartitionTypeGUID = pHdr->Partition.PartitionTypeGUID; } } else if ( (!memcmp(((char *)&(pHdr->Header.Signature))+3, "Relay", 5)) && (!uuidcmp(&(pHdr->Partition.PartitionTypeGUID), &guidRelay)) ) // It's a relay, but with the header incomplete (CRC not set yet). { pNewEntry->PartitionTypeGUID = guidRelay; // ~~jfl 2002/01/03 Update the partition header while we have it. uuid_create((uuid_t *)&(pHdr->Partition.UniquePartitionGUID)); // Generate a new GUID SetCrc(&(pHdr->Header)); } else if (IsMBR(pSect)) // Master Boot Record. Assume it's a hard disk. { pNewEntry->PartitionTypeGUID = guidHardDiskImage; } if (IsNullUuid((uuid_t*)&(pNewEntry->PartitionTypeGUID))) // Assume anything else is a floppy. { pNewEntry->PartitionTypeGUID = guidFloppyImage; } } iErr = GptBlockWrite(hGPT, qwLBA, 1, pSect); if (iErr) GptAllocFileCopyFail(-3); } copy_return: // Cleanup fclose(hf); free(pSect); return iPartition; }