/* * pool_copy -- make a copy of the pool */ int pool_copy(struct pool_data *pool, const char *dst_path) { struct pool_set_file *file = pool->set_file; int dfd = util_file_create(dst_path, file->size, 0); if (dfd < 0) return -1; int result = 0; struct stat stat_buf; if (stat(file->fname, &stat_buf)) { result = -1; goto out_close; } if (fchmod(dfd, stat_buf.st_mode)) { result = -1; goto out_close; } void *daddr = mmap(NULL, file->size, PROT_READ | PROT_WRITE, MAP_SHARED, dfd, 0); if (daddr == MAP_FAILED) { result = -1; goto out_close; } if (pool->params.type != POOL_TYPE_BTT) { void *saddr = pool_set_file_map(file, 0); memcpy(daddr, saddr, file->size); goto out_unmap; } void *buf = malloc(RW_BUFFERING_SIZE); if (buf == NULL) { ERR("!malloc"); result = -1; goto out_unmap; } pool_btt_lseek(pool, 0, SEEK_SET); ssize_t buf_read = 0; void *dst = daddr; while ((buf_read = pool_btt_read(pool, buf, RW_BUFFERING_SIZE))) { if (buf_read == -1) break; memcpy(dst, buf, (size_t)buf_read); dst = (void *)((ssize_t)dst + buf_read); } free(buf); out_unmap: munmap(daddr, file->size); out_close: if (dfd >= 0) close(dfd); return result; }
/* * pool_copy -- make a copy of the pool */ int pool_copy(struct pool_data *pool, const char *dst_path, int overwrite) { struct pool_set_file *file = pool->set_file; int dfd; if (!os_access(dst_path, F_OK)) { if (!overwrite) { errno = EEXIST; return -1; } dfd = util_file_open(dst_path, NULL, 0, O_RDWR); } else { if (errno == ENOENT) { errno = 0; dfd = util_file_create(dst_path, file->size, 0); } else { return -1; } } if (dfd < 0) return -1; int result = 0; os_stat_t stat_buf; if (os_stat(file->fname, &stat_buf)) { result = -1; goto out_close; } if (fchmod(dfd, stat_buf.st_mode)) { result = -1; goto out_close; } void *daddr = mmap(NULL, file->size, PROT_READ | PROT_WRITE, MAP_SHARED, dfd, 0); if (daddr == MAP_FAILED) { result = -1; goto out_close; } if (pool->params.type != POOL_TYPE_BTT) { void *saddr = pool_set_file_map(file, 0); memcpy(daddr, saddr, file->size); goto out_unmap; } void *buf = malloc(RW_BUFFERING_SIZE); if (buf == NULL) { ERR("!malloc"); result = -1; goto out_unmap; } if (pool_btt_lseek(pool, 0, SEEK_SET) == -1) { result = -1; goto out_free; } ssize_t buf_read = 0; void *dst = daddr; while ((buf_read = pool_btt_read(pool, buf, RW_BUFFERING_SIZE))) { if (buf_read == -1) break; memcpy(dst, buf, (size_t)buf_read); dst = (void *)((ssize_t)dst + buf_read); } out_free: free(buf); out_unmap: munmap(daddr, file->size); out_close: (void) os_close(dfd); return result; }
/* * 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; }