/* * shutdown_state_check -- compares and fixes shutdown state */ int shutdown_state_check(struct shutdown_state *curr_sds, struct shutdown_state *pool_sds, struct pool_replica *rep) { LOG(3, "curr_sds %p, pool_sds %p", curr_sds, pool_sds); if (util_is_zeroed(pool_sds, sizeof(*pool_sds)) && !util_is_zeroed(curr_sds, sizeof(*curr_sds))) { shutdown_state_reinit(curr_sds, pool_sds, rep); return 0; } bool is_uuid_usc_correct = le64toh(pool_sds->usc) == le64toh(curr_sds->usc) && le64toh(pool_sds->uuid) == le64toh(curr_sds->uuid); bool is_checksum_correct = util_checksum(pool_sds, sizeof(*pool_sds), &pool_sds->checksum, 0, 0); int dirty = pool_sds->dirty; if (!is_checksum_correct) { /* the program was killed during opening or closing the pool */ LOG(2, "incorrect checksum - SDS will be reinitialized"); shutdown_state_reinit(curr_sds, pool_sds, rep); return 0; } if (is_uuid_usc_correct) { if (dirty == 0) return 0; /* * the program was killed when the pool was opened * but there wasn't an ADR failure */ LOG(2, "the pool was not closed - SDS will be reinitialized"); shutdown_state_reinit(curr_sds, pool_sds, rep); return 0; } if (dirty == 0) { /* an ADR failure but the pool was closed */ LOG(2, "an ADR failure was detected but the pool was closed - SDS will be reinitialized"); shutdown_state_reinit(curr_sds, pool_sds, rep); return 0; } /* an ADR failure - the pool might be corrupted */ ERR("an ADR failure was detected, the pool might be corrupted"); return 1; }
/* * sds_check_replica -- (internal) check if replica is healthy */ static int sds_check_replica(location *loc) { LOG(3, NULL); struct pool_replica *rep = REP(loc->set, loc->replica); if (rep->remote) return 0; /* make a copy of sds as we shouldn't modify a pool */ struct shutdown_state old_sds = loc->hdr.sds; struct shutdown_state curr_sds; if (IGNORE_SDS(&loc->hdr)) return util_is_zeroed(&old_sds, sizeof(old_sds)) ? 0 : -1; shutdown_state_init(&curr_sds, NULL); /* get current shutdown state */ for (unsigned p = 0; p < rep->nparts; ++p) { if (shutdown_state_add_part(&curr_sds, PART(rep, p)->path, NULL)) return -1; } /* compare current and old shutdown state */ return shutdown_state_check(&curr_sds, &old_sds, NULL); }
/* * check_checksums -- (internal) check if checksums are correct for parts in * a given replica */ static int check_checksums(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) { struct pool_replica *rep = REP(set, r); struct replica_health_status *rep_hs = REP(set_hs, r); if (rep->remote) continue; for (unsigned p = 0; p < rep->nparts; ++p) { /* skip broken parts */ if (replica_is_part_broken(r, p, set_hs)) continue; /* check part's checksum */ LOG(4, "checking checksum for part %u, replica %u", p, r); struct pool_hdr *hdrp = HDR(rep, p); if (!util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 0)) {; ERR("invalid checksum of pool header"); rep_hs->part[p] |= IS_BROKEN; } else if (util_is_zeroed(hdrp, sizeof(*hdrp))) { rep_hs->part[p] |= IS_BROKEN; } } } return 0; }
/* * pool_hdr_valid -- (internal) return true if pool header is valid */ static int pool_hdr_valid(struct pool_hdr *hdrp) { return !util_is_zeroed((void *)hdrp, sizeof(*hdrp)) && util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 0, POOL_HDR_CSUM_END_OFF); }
/* * util_compare_arch_flags -- compare architecture flags */ int util_compare_arch_flags(const struct arch_flags *arch_flags, const struct arch_flags *comp_flags) { int ret = 0; if (!util_is_zeroed(&arch_flags->reserved, sizeof(arch_flags->reserved))) { ERR("invalid reserved values"); ret = -1; } if (arch_flags->e_machine != comp_flags->e_machine) { ERR("invalid e_machine value"); ret = -1; } if (arch_flags->ei_data != comp_flags->ei_data) { ERR("invalid ei_data value"); ret = -1; } if (arch_flags->ei_class != comp_flags->ei_class) { ERR("invalid ei_class value"); ret = -1; } if (arch_flags->alignment_desc != comp_flags->alignment_desc) { ERR("invalid alignment_desc value"); ret = -1; } return ret; }
/* * 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; }
/* * pool_hdr_default_check -- (internal) check some default values in pool header */ static int pool_hdr_default_check(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); ASSERT(CHECK_IS(ppc, REPAIR)); struct pool_hdr def_hdr; pool_hdr_default(ppc->pool->params.type, &def_hdr); if (memcmp(loc->hdr.signature, def_hdr.signature, POOL_HDR_SIG_LEN)) { CHECK_ASK(ppc, Q_DEFAULT_SIGNATURE, "%spool_hdr.signature is not valid.|Do you want to set " "it to %.8s?", loc->prefix, def_hdr.signature); } if (loc->hdr.major != def_hdr.major) { CHECK_ASK(ppc, Q_DEFAULT_MAJOR, "%spool_hdr.major is not valid.|Do you want to set it " "to default value 0x%x?", loc->prefix, def_hdr.major); } if (loc->hdr.compat_features != def_hdr.compat_features) { CHECK_ASK(ppc, Q_DEFAULT_COMPAT_FEATURES, "%spool_hdr.compat_features is not valid.|Do you want " "to set it to default value 0x%x?", loc->prefix, def_hdr.compat_features); } if (loc->hdr.incompat_features != def_hdr.incompat_features) { CHECK_ASK(ppc, Q_DEFAULT_INCOMPAT_FEATURES, "%spool_hdr.incompat_features is not valid.|Do you " "want to set it to default value 0x%x?", loc->prefix, def_hdr.incompat_features); } if (loc->hdr.ro_compat_features != def_hdr.ro_compat_features) { CHECK_ASK(ppc, Q_DEFAULT_RO_COMPAT_FEATURES, "%spool_hdr.ro_compat_features is not valid.|Do you " "want to set it to default value 0x%x?", loc->prefix, def_hdr.ro_compat_features); } if (!util_is_zeroed(loc->hdr.unused, sizeof(loc->hdr.unused))) { CHECK_ASK(ppc, Q_ZERO_UNUSED_AREA, "%sunused area is not filled by zeros.|Do you want to " "fill it up?", loc->prefix); } return check_questions_sequence_validate(ppc); }
/* * pvector_push_back -- bumps the number of values in the vector and returns * the pointer to the value position to which the caller must set the * value. Calling this method without actually setting the value will * result in an inconsistent vector state. */ uint64_t * pvector_push_back(struct pvector_context *ctx) { uint64_t idx = ctx->nvalues; struct array_spec s = pvector_get_array_spec(idx); if (s.idx >= PVECTOR_MAX_ARRAYS) { ERR("Exceeded maximum number of entries in persistent vector"); return NULL; } PMEMobjpool *pop = ctx->pop; /* * If the destination array does not exist, calculate its size * and allocate it. */ if (ctx->vec->arrays[s.idx] == 0) { if (s.idx == 0) { /* * In the case the vector is completely empty the * initial embedded array must be assigned as the first * element of the sequence. */ ASSERTeq(util_is_zeroed(ctx->vec, sizeof(*ctx->vec)), 1); ctx->vec->arrays[0] = OBJ_PTR_TO_OFF(pop, &ctx->vec->embedded); pmemops_persist(&pop->p_ops, &ctx->vec->arrays[0], sizeof(ctx->vec->arrays[0])); } else { size_t arr_size = sizeof(uint64_t) * (1ULL << (s.idx + PVECTOR_INIT_SHIFT)); if (pmalloc_construct(pop, &ctx->vec->arrays[s.idx], arr_size, pvector_array_constr, NULL, 0, OBJ_INTERNAL_OBJECT_MASK, 0) != 0) return NULL; } } ctx->nvalues++; uint64_t *arrp = OBJ_OFF_TO_PTR(pop, ctx->vec->arrays[s.idx]); return &arrp[s.pos]; }
/* * pool_get_first_valid_btt -- return offset to first valid BTT Info * * - Return offset to valid BTT Info header in pool file. * - Start looking from given offset. * - Convert BTT Info header to host endianness. * - Return the BTT Info header by pointer. * - If zeroed pointer provided would check if all checked BTT Info are zeroed * which is useful for BLK pools */ uint64_t pool_get_first_valid_btt(struct pool_data *pool, struct btt_info *infop, uint64_t offset, bool *zeroed) { /* if we have valid arena get BTT Info header from it */ if (pool->narenas != 0) { struct arena *arenap = TAILQ_FIRST(&pool->arenas); memcpy(infop, &arenap->btt_info, sizeof(*infop)); return arenap->offset; } const size_t info_size = sizeof(*infop); /* theoretical offsets to BTT Info header and backup */ uint64_t offsets[2] = {offset, 0}; while (offsets[0] < pool->set_file->size) { /* calculate backup offset */ offsets[1] = pool_next_arena_offset(pool, offsets[0]) - info_size; /* check both offsets: header and backup */ for (int i = 0; i < 2; ++i) { if (pool_read(pool, infop, info_size, offsets[i])) continue; /* check if all possible BTT Info are zeroed */ if (zeroed) *zeroed &= util_is_zeroed((const void *)infop, info_size); /* check if read BTT Info is valid */ if (pool_btt_info_valid(infop)) { btt_info_convert2h(infop); return offsets[i]; } } /* jump to next arena */ offsets[0] += BTT_MAX_ARENA; } return 0; }
int main(int argc, char *argv[]) { START(argc, argv, "obj_redo_log"); util_init(); if (argc < 4) FATAL_USAGE(); PMEMobjpool *pop = pmemobj_open_mock(argv[1]); UT_ASSERTne(pop, NULL); UT_ASSERTeq(util_is_zeroed((char *)pop->addr + PMEMOBJ_POOL_HDR_SIZE, pop->size - PMEMOBJ_POOL_HDR_SIZE), 1); char *end = NULL; errno = 0; size_t redo_size = strtoul(argv[2], &end, 0); if (errno || !end || *end != '\0') FATAL_USAGE(); UT_ASSERT(pop->size >= redo_size * sizeof(struct redo_log)); struct redo_log *redo = (struct redo_log *)pop->addr; uint64_t offset; uint64_t value; int i; int ret; size_t index; for (i = 3; i < argc; i++) { char *arg = argv[i]; UT_ASSERTne(arg, NULL); switch (arg[0]) { case 's': if (sscanf(arg, "s:%ld:0x%lx:0x%lx", &index, &offset, &value) != 3) FATAL_USAGE(); UT_OUT("s:%ld:0x%08lx:0x%08lx", index, offset, value); redo_log_store(pop, redo, index, offset, value); break; case 'f': if (sscanf(arg, "f:%ld:0x%lx:0x%lx", &index, &offset, &value) != 3) FATAL_USAGE(); UT_OUT("f:%ld:0x%08lx:0x%08lx", index, offset, value); redo_log_store_last(pop, redo, index, offset, value); break; case 'F': if (sscanf(arg, "F:%ld", &index) != 1) FATAL_USAGE(); UT_OUT("F:%ld", index); redo_log_set_last(pop, redo, index); break; case 'r': if (sscanf(arg, "r:0x%lx", &offset) != 1) FATAL_USAGE(); uint64_t *valp = (uint64_t *)((uintptr_t)pop->addr + offset); UT_OUT("r:0x%08lx:0x%08lx", offset, *valp); break; case 'e': if (sscanf(arg, "e:%ld", &index) != 1) FATAL_USAGE(); struct redo_log *entry = redo + index; int flag = (entry->offset & REDO_FINISH_FLAG) ? 1 : 0; offset = entry->offset & REDO_FLAG_MASK; value = entry->value; UT_OUT("e:%ld:0x%08lx:%d:0x%08lx", index, offset, flag, value); break; case 'P': redo_log_process(pop, redo, redo_size); UT_OUT("P"); break; case 'R': redo_log_recover(pop, redo, redo_size); UT_OUT("R"); break; case 'C': ret = redo_log_check(pop, redo, redo_size); UT_OUT("C:%d", ret); break; default: FATAL_USAGE(); } } pmemobj_close_mock(pop); DONE(NULL); }
/* * util_header_create -- (internal) create header of a single pool set file */ static int util_header_create(struct pool_set *set, unsigned repidx, unsigned partidx, size_t hdrsize, const char *sig, uint32_t major, uint32_t compat, uint32_t incompat, uint32_t ro_compat) { LOG(3, "set %p repidx %u partidx %u hdrsize %zu sig %s major %u " "compat %#x incompat %#x ro_comapt %#x", set, repidx, partidx, hdrsize, sig, major, compat, incompat, ro_compat); struct pool_replica *rep = set->replica[repidx]; /* opaque info lives at the beginning of mapped memory pool */ struct pool_hdr *hdrp = rep->part[partidx].hdr; /* check if the pool header is all zeros */ if (!util_is_zeroed(hdrp, sizeof (*hdrp))) { ERR("Non-empty file detected"); errno = EINVAL; return -1; } /* * Zero out the pool descriptor - just in case we fail right after * header checksum is stored. */ void *descp = (void *)((uintptr_t)hdrp + sizeof (*hdrp)); memset(descp, 0, hdrsize - sizeof (*hdrp)); pmem_msync(descp, hdrsize - sizeof (*hdrp)); /* create pool's header */ strncpy(hdrp->signature, sig, POOL_HDR_SIG_LEN); hdrp->major = htole32(major); hdrp->compat_features = htole32(compat); hdrp->incompat_features = htole32(incompat); hdrp->ro_compat_features = htole32(ro_compat); memcpy(hdrp->poolset_uuid, set->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->uuid, PART(rep, partidx).uuid, POOL_HDR_UUID_LEN); /* link parts */ memcpy(hdrp->prev_part_uuid, PART(rep, partidx - 1).uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_part_uuid, PART(rep, partidx + 1).uuid, POOL_HDR_UUID_LEN); /* link replicas */ memcpy(hdrp->prev_repl_uuid, PART(REP(set, repidx - 1), 0).uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_repl_uuid, PART(REP(set, repidx + 1), 0).uuid, POOL_HDR_UUID_LEN); hdrp->crtime = htole64((uint64_t)time(NULL)); if (util_get_arch_flags(&hdrp->arch_flags)) { ERR("Reading architecture flags failed\n"); errno = EINVAL; return -1; } hdrp->arch_flags.alignment_desc = htole64(hdrp->arch_flags.alignment_desc); hdrp->arch_flags.e_machine = htole16(hdrp->arch_flags.e_machine); util_checksum(hdrp, sizeof (*hdrp), &hdrp->checksum, 1); /* store pool's header */ pmem_msync(hdrp, sizeof (*hdrp)); return 0; }
/* * pmemlog_map_common -- (internal) map a log memory pool * * This routine does all the work, but takes a rdonly flag so internal * calls can map a read-only pool if required. * * If empty flag is set, the file is assumed to be a new memory pool, and * a new pool header is created. Otherwise, a valid header must exist. */ static PMEMlogpool * pmemlog_map_common(int fd, size_t poolsize, int rdonly, int empty) { LOG(3, "fd %d poolsize %zu rdonly %d empty %d", fd, poolsize, rdonly, empty); void *addr; if ((addr = util_map(fd, poolsize, rdonly)) == NULL) { (void) close(fd); return NULL; /* util_map() set errno, called LOG */ } VALGRIND_REGISTER_PMEM_MAPPING(addr, poolsize); VALGRIND_REGISTER_PMEM_FILE(fd, addr, poolsize, 0); (void) close(fd); /* check if the mapped region is located in persistent memory */ int is_pmem = pmem_is_pmem(addr, poolsize); /* opaque info lives at the beginning of mapped memory pool */ struct pmemlog *plp = addr; if (!empty) { struct pool_hdr hdr; memcpy(&hdr, &plp->hdr, sizeof (hdr)); if (!util_convert_hdr(&hdr)) { errno = EINVAL; goto err; } /* * valid header found */ if (strncmp(hdr.signature, LOG_HDR_SIG, POOL_HDR_SIG_LEN)) { ERR("wrong pool type: \"%s\"", hdr.signature); errno = EINVAL; goto err; } if (hdr.major != LOG_FORMAT_MAJOR) { ERR("log pool version %d (library expects %d)", hdr.major, LOG_FORMAT_MAJOR); errno = EINVAL; goto err; } /* XXX - pools sets / replicas */ if (memcmp(hdr.uuid, hdr.prev_part_uuid, POOL_HDR_UUID_LEN) || memcmp(hdr.uuid, hdr.next_part_uuid, POOL_HDR_UUID_LEN) || memcmp(hdr.uuid, hdr.prev_repl_uuid, POOL_HDR_UUID_LEN) || memcmp(hdr.uuid, hdr.next_repl_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong UUID"); errno = EINVAL; goto err; } uint64_t hdr_start = le64toh(plp->start_offset); uint64_t hdr_end = le64toh(plp->end_offset); uint64_t hdr_write = le64toh(plp->write_offset); if ((hdr_start != roundup(sizeof (*plp), LOG_FORMAT_DATA_ALIGN)) || (hdr_end != poolsize) || (hdr_start > hdr_end)) { ERR("wrong start/end offsets (start: %ju end: %ju), " "pool size %zu", hdr_start, hdr_end, poolsize); errno = EINVAL; goto err; } if ((hdr_write > hdr_end) || (hdr_write < hdr_start)) { ERR("wrong write offset " "(start: %ju end: %ju write: %ju)", hdr_start, hdr_end, hdr_write); errno = EINVAL; goto err; } LOG(3, "start: %ju, end: %ju, write: %ju", hdr_start, hdr_end, hdr_write); int retval = util_feature_check(&hdr, LOG_FORMAT_INCOMPAT, LOG_FORMAT_RO_COMPAT, LOG_FORMAT_COMPAT); if (retval < 0) goto err; else if (retval == 0) rdonly = 1; } else { LOG(3, "creating new log memory pool"); ASSERTeq(rdonly, 0); struct pool_hdr *hdrp = &plp->hdr; /* check if the pool header is all zero */ if (!util_is_zeroed(hdrp, sizeof (*hdrp))) { ERR("Non-empty file detected"); errno = EINVAL; goto err; } /* create required metadata first */ plp->start_offset = htole64(roundup(sizeof (*plp), LOG_FORMAT_DATA_ALIGN)); plp->end_offset = htole64(poolsize); plp->write_offset = plp->start_offset; /* store non-volatile part of pool's descriptor */ pmem_msync(&plp->start_offset, 3 * sizeof (uint64_t)); /* create pool header */ strncpy(hdrp->signature, LOG_HDR_SIG, POOL_HDR_SIG_LEN); hdrp->major = htole32(LOG_FORMAT_MAJOR); hdrp->compat_features = htole32(LOG_FORMAT_COMPAT); hdrp->incompat_features = htole32(LOG_FORMAT_INCOMPAT); hdrp->ro_compat_features = htole32(LOG_FORMAT_RO_COMPAT); uuid_generate(hdrp->uuid); /* XXX - pools sets / replicas */ uuid_generate(hdrp->poolset_uuid); memcpy(hdrp->prev_part_uuid, hdrp->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_part_uuid, hdrp->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->prev_repl_uuid, hdrp->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_repl_uuid, hdrp->uuid, POOL_HDR_UUID_LEN); hdrp->crtime = htole64((uint64_t)time(NULL)); if (util_get_arch_flags(&hdrp->arch_flags)) { ERR("Reading architecture flags failed\n"); errno = EINVAL; goto err; } hdrp->arch_flags.alignment_desc = htole64(hdrp->arch_flags.alignment_desc); hdrp->arch_flags.e_machine = htole16(hdrp->arch_flags.e_machine); util_checksum(hdrp, sizeof (*hdrp), &hdrp->checksum, 1); /* store pool's header */ pmem_msync(hdrp, sizeof (*hdrp)); } /* remove volatile part of header */ VALGRIND_REMOVE_PMEM_MAPPING(&plp->addr, sizeof (struct pmemlog) - sizeof (struct pool_hdr) - 3 * sizeof (uint64_t)); /* * Use some of the memory pool area for run-time info. This * run-time state is never loaded from the file, it is always * created here, so no need to worry about byte-order. */ plp->addr = addr; plp->size = poolsize; plp->rdonly = rdonly; plp->is_pmem = is_pmem; if ((plp->rwlockp = Malloc(sizeof (*plp->rwlockp))) == NULL) { ERR("!Malloc for a RW lock"); goto err; } if ((errno = pthread_rwlock_init(plp->rwlockp, NULL))) { ERR("!pthread_rwlock_init"); goto err_free; } /* * If possible, turn off all permissions on the pool header page. * * The prototype PMFS doesn't allow this when large pages are in * use. It is not considered an error if this fails. */ util_range_none(addr, sizeof (struct pool_hdr)); /* the rest should be kept read-only (debug version only) */ RANGE_RO(addr + sizeof (struct pool_hdr), poolsize - sizeof (struct pool_hdr)); LOG(3, "plp %p", plp); return plp; err_free: Free((void *)plp->rwlockp); err: LOG(4, "error clean up"); int oerrno = errno; VALGRIND_REMOVE_PMEM_MAPPING(addr, poolsize); util_unmap(addr, poolsize); errno = oerrno; return NULL; }
/* * util_header_create -- (internal) create header of a single pool set file */ static int util_header_create(struct pool_set *set, unsigned repidx, unsigned partidx, const char *sig, uint32_t major, uint32_t compat, uint32_t incompat, uint32_t ro_compat, const unsigned char *prev_repl_uuid, const unsigned char *next_repl_uuid, const unsigned char *arch_flags) { LOG(3, "set %p repidx %u partidx %u sig %.8s major %u " "compat %#x incompat %#x ro_comapt %#x" "prev_repl_uuid %p next_repl_uuid %p arch_flags %p", set, repidx, partidx, sig, major, compat, incompat, ro_compat, prev_repl_uuid, next_repl_uuid, arch_flags); struct pool_replica *rep = set->replica[repidx]; /* opaque info lives at the beginning of mapped memory pool */ struct pool_hdr *hdrp = rep->part[partidx].hdr; /* check if the pool header is all zeros */ if (!util_is_zeroed(hdrp, sizeof(*hdrp))) { ERR("Non-empty file detected"); errno = EEXIST; return -1; } /* * Zero out the pool descriptor - just in case we fail right after * header checksum is stored. */ void *descp = (void *)((uintptr_t)hdrp + sizeof(*hdrp)); memset(descp, 0, POOL_HDR_SIZE - sizeof(*hdrp)); pmem_msync(descp, POOL_HDR_SIZE - sizeof(*hdrp)); /* create pool's header */ memcpy(hdrp->signature, sig, POOL_HDR_SIG_LEN); hdrp->major = major; hdrp->compat_features = compat; hdrp->incompat_features = incompat; hdrp->ro_compat_features = ro_compat; memcpy(hdrp->poolset_uuid, set->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->uuid, PART(rep, partidx).uuid, POOL_HDR_UUID_LEN); /* link parts */ memcpy(hdrp->prev_part_uuid, PART(rep, partidx - 1).uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_part_uuid, PART(rep, partidx + 1).uuid, POOL_HDR_UUID_LEN); /* link replicas */ if (prev_repl_uuid) { memcpy(hdrp->prev_repl_uuid, prev_repl_uuid, POOL_HDR_UUID_LEN); } else { memcpy(hdrp->prev_repl_uuid, PART(REP(set, repidx - 1), 0).uuid, POOL_HDR_UUID_LEN); } if (next_repl_uuid) { memcpy(hdrp->next_repl_uuid, next_repl_uuid, POOL_HDR_UUID_LEN); } else { memcpy(hdrp->next_repl_uuid, PART(REP(set, repidx + 1), 0).uuid, POOL_HDR_UUID_LEN); } hdrp->crtime = (uint64_t)time(NULL); if (!arch_flags) { if (util_get_arch_flags(&hdrp->arch_flags)) { ERR("Reading architecture flags failed"); errno = EINVAL; return -1; } } util_convert2le_hdr(hdrp); if (arch_flags) { memcpy(&hdrp->arch_flags, arch_flags, sizeof(struct arch_flags)); } util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 1); /* store pool's header */ pmem_msync(hdrp, sizeof(*hdrp)); return 0; }