/* * map_all_unbroken_headers -- (internal) map all headers in a poolset, * skipping those marked as broken in a helping * structure */ static int map_all_unbroken_headers(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 = set->replica[r]; struct replica_health_status *rep_hs = set_hs->replica[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; LOG(4, "mapping header for part %u, replica %u", p, r); if (util_map_hdr(&rep->part[p], MAP_SHARED, 0) != 0) { LOG(1, "header mapping failed - part #%d", p); rep_hs->part[p] |= IS_BROKEN; } } } return 0; }
/* * pool_set_file_map_headers -- map headers of each pool set part file */ int pool_set_file_map_headers(struct pool_set_file *file, int rdonly, int prv) { if (!file->poolset) return -1; for (unsigned r = 0; r < file->poolset->nreplicas; r++) { struct pool_replica *rep = file->poolset->replica[r]; for (unsigned p = 0; p < rep->nparts; p++) { struct pool_set_part *part = &rep->part[p]; if (util_map_hdr(part, prv ? MAP_PRIVATE : MAP_SHARED, rdonly)) { part->hdr = NULL; goto err; } } } return 0; err: pool_set_file_unmap_headers(file); return -1; }
/* * pmempool_convert_func -- main function for convert command */ int pmempool_convert_func(char *appname, int argc, char *argv[]) { if (argc != 2) { print_usage(appname); return -1; } int ret = 0; const char *f = argv[1]; struct pmem_pool_params params; if (pmem_pool_parse_params(f, ¶ms, 1)) { fprintf(stderr, "Cannot determine type of pool.\n"); return -1; } if (params.is_part) { fprintf(stderr, "Conversion cannot be performed on " "a poolset part.\n"); return -1; } if (params.type != PMEM_POOL_TYPE_OBJ) { fprintf(stderr, "Conversion is currently supported only for " "pmemobj pools.\n"); return -1; } struct pool_set_file *psf = pool_set_file_open(f, 0, 1); if (psf == NULL) { perror(f); return -1; } if (psf->poolset->remote) { fprintf(stderr, "Conversion of remotely replicated pools is " "currently not supported. Remove the replica first\n"); pool_set_file_close(psf); return -1; } void *addr = pool_set_file_map(psf, 0); if (addr == NULL) { perror(f); ret = -1; goto out; } struct pool_hdr *phdr = addr; uint32_t m = le32toh(phdr->major); if (m >= COUNT_OF(version_convert) || !version_convert[m]) { fprintf(stderr, "There's no conversion method for the pool.\n" "Please make sure the pmempool utility " "is up-to-date.\n"); ret = -1; goto out; } printf("This tool will update the pool to the latest available " "layout version.\nThis process is NOT fail-safe.\n" "Proceed only if the pool has been backed up or\n" "the risks are fully understood and acceptable.\n"); if (ask_Yn('?', "convert the pool '%s' ?", f) != 'y') { ret = 0; goto out; } PMEMobjpool *pop = addr; for (unsigned r = 0; r < psf->poolset->nreplicas; ++r) { struct pool_replica *rep = psf->poolset->replica[r]; for (unsigned p = 0; p < rep->nparts; ++p) { struct pool_set_part *part = &rep->part[p]; if (util_map_hdr(part, MAP_SHARED, 0) != 0) { fprintf(stderr, "Failed to map headers.\n" "Conversion did not start.\n"); ret = -1; goto out; } } } uint32_t i; for (i = m; i < COUNT_OF(version_convert); ++i) { if (version_convert[i](psf, pop) != 0) { fprintf(stderr, "Failed to convert the pool\n"); break; } else { /* need to update every header of every part */ uint32_t target_m = i + 1; for (unsigned r = 0; r < psf->poolset->nreplicas; ++r) { struct pool_replica *rep = psf->poolset->replica[r]; for (unsigned p = 0; p < rep->nparts; ++p) { struct pool_set_part *part = &rep->part[p]; struct pool_hdr *hdr = part->hdr; hdr->major = htole32(target_m); util_checksum(hdr, sizeof(*hdr), &hdr->checksum, 1); PERSIST_GENERIC_AUTO(hdr, sizeof(struct pool_hdr)); } } } } if (i != m) /* at least one step has been performed */ printf("The pool has been converted to version %d\n.", i); PERSIST_GENERIC_AUTO(pop, psf->size); out: for (unsigned r = 0; r < psf->poolset->nreplicas; ++r) { struct pool_replica *rep = psf->poolset->replica[r]; for (unsigned p = 0; p < rep->nparts; ++p) { struct pool_set_part *part = &rep->part[p]; if (part->hdr != NULL) util_unmap_hdr(part); } } pool_set_file_close(psf); return ret; }
/* * util_replica_open -- (internal) open a memory pool replica */ static int util_replica_open(struct pool_set *set, unsigned repidx, int flags, size_t hdrsize) { LOG(3, "set %p repidx %u flags %d hdrsize %zu\n", set, repidx, flags, hdrsize); struct pool_replica *rep = set->replica[repidx]; rep->repsize -= (rep->nparts - 1) * hdrsize; /* determine a hint address for mmap() */ void *addr = util_map_hint(rep->repsize); /* XXX - randomize */ if (addr == NULL) { ERR("cannot find a contiguous region of given size"); return -1; } /* map the first part and reserve space for remaining parts */ if (util_map_part(&rep->part[0], addr, rep->repsize, 0, flags) != 0) { LOG(2, "pool mapping failed - part #0"); return -1; } VALGRIND_REGISTER_PMEM_MAPPING(rep->part[0].addr, rep->part[0].size); VALGRIND_REGISTER_PMEM_FILE(rep->part[0].fd, rep->part[0].addr, rep->part[0].size, 0); /* map all headers - don't care about the address */ for (unsigned p = 0; p < rep->nparts; p++) { if (util_map_hdr(&rep->part[p], hdrsize, 0, flags) != 0) { LOG(2, "header mapping failed - part #%d", p); goto err; } } size_t mapsize = rep->part[0].filesize & ~(Pagesize - 1); addr = (char *)rep->part[0].addr + mapsize; /* * map the remaining parts of the usable pool space * (4K-aligned) */ for (unsigned p = 1; p < rep->nparts; p++) { /* map data part */ if (util_map_part(&rep->part[p], addr, 0, hdrsize, flags | MAP_FIXED) != 0) { LOG(2, "usable space mapping failed - part #%d", p); goto err; } VALGRIND_REGISTER_PMEM_FILE(rep->part[p].fd, rep->part[p].addr, rep->part[p].size, hdrsize); mapsize += rep->part[p].size; addr = (char *)addr + rep->part[p].size; } rep->is_pmem = pmem_is_pmem(rep->part[0].addr, rep->part[0].size); ASSERTeq(mapsize, rep->repsize); /* calculate pool size - choose the smallest replica size */ if (rep->repsize < set->poolsize) set->poolsize = rep->repsize; LOG(3, "replica addr %p", rep->part[0].addr); return 0; err: LOG(4, "error clean up"); int oerrno = errno; for (unsigned p = 0; p < rep->nparts; p++) util_unmap_hdr(&rep->part[p]); util_unmap_part(&rep->part[0]); errno = oerrno; return -1; }
/* * util_replica_create -- (internal) create a new memory pool replica */ static int util_replica_create(struct pool_set *set, unsigned repidx, int flags, 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 flags %d sig %.8s major %u " "compat %#x incompat %#x ro_comapt %#x" "prev_repl_uuid %p next_repl_uuid %p arch_flags %p", set, repidx, flags, sig, major, compat, incompat, ro_compat, prev_repl_uuid, next_repl_uuid, arch_flags); struct pool_replica *rep = set->replica[repidx]; /* determine a hint address for mmap() */ void *addr = util_map_hint(rep->repsize, 0); if (addr == MAP_FAILED) { ERR("cannot find a contiguous region of given size"); return -1; } /* map the first part and reserve space for remaining parts */ /* XXX investigate this idea of reserving space on Windows */ if (util_map_part(&rep->part[0], addr, rep->repsize, 0, flags) != 0) { LOG(2, "pool mapping failed - part #0"); return -1; } VALGRIND_REGISTER_PMEM_MAPPING(rep->part[0].addr, rep->part[0].size); VALGRIND_REGISTER_PMEM_FILE(rep->part[0].fd, rep->part[0].addr, rep->part[0].size, 0); /* map all headers - don't care about the address */ for (unsigned p = 0; p < rep->nparts; p++) { if (util_map_hdr(&rep->part[p], flags) != 0) { LOG(2, "header mapping failed - part #%d", p); goto err; } } /* create headers, set UUID's */ for (unsigned p = 0; p < rep->nparts; p++) { if (util_header_create(set, repidx, p, sig, major, compat, incompat, ro_compat, prev_repl_uuid, next_repl_uuid, arch_flags) != 0) { LOG(2, "header creation failed - part #%d", p); goto err; } } /* unmap all headers */ for (unsigned p = 0; p < rep->nparts; p++) util_unmap_hdr(&rep->part[p]); set->zeroed &= rep->part[0].created; size_t mapsize = rep->part[0].filesize & ~(Pagesize - 1); addr = (char *)rep->part[0].addr + mapsize; /* * map the remaining parts of the usable pool space (4K-aligned) */ for (unsigned p = 1; p < rep->nparts; p++) { /* map data part */ if (util_map_part(&rep->part[p], addr, 0, POOL_HDR_SIZE, flags | MAP_FIXED) != 0) { LOG(2, "usable space mapping failed - part #%d", p); goto err; } VALGRIND_REGISTER_PMEM_FILE(rep->part[p].fd, rep->part[p].addr, rep->part[p].size, POOL_HDR_SIZE); mapsize += rep->part[p].size; set->zeroed &= rep->part[p].created; addr = (char *)addr + rep->part[p].size; } rep->is_pmem = pmem_is_pmem(rep->part[0].addr, rep->part[0].size); ASSERTeq(mapsize, rep->repsize); LOG(3, "replica addr %p", rep->part[0].addr); return 0; err: LOG(4, "error clean up"); int oerrno = errno; for (unsigned p = 0; p < rep->nparts; p++) util_unmap_hdr(&rep->part[p]); util_unmap_part(&rep->part[0]); errno = oerrno; return -1; }