int main(int argc, char *argv[]) { START(argc, argv, "util_poolset"); common_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR, MAJOR_VERSION, MINOR_VERSION); if (argc < 3) UT_FATAL("usage: %s cmd minsize [mockopts] " "setfile ...", argv[0]); char *fname; struct pool_set *set; int ret; size_t minsize = strtoul(argv[2], &fname, 0); for (int arg = 3; arg < argc; arg++) { arg += mock_options(argv[arg]); fname = argv[arg]; struct pool_attr attr; memset(&attr, 0, sizeof(attr)); memcpy(attr.signature, SIG, sizeof(SIG)); attr.major = 1; switch (argv[1][0]) { case 'c': ret = util_pool_create(&set, fname, 0, minsize, MIN_PART, &attr, NULL, REPLICAS_ENABLED); if (ret == -1) UT_OUT("!%s: util_pool_create", fname); else { /* * XXX: On Windows pool files are created with * R/W permissions, so no need for chmod(). */ #ifndef _WIN32 util_poolset_chmod(set, S_IWUSR | S_IRUSR); #endif poolset_info(fname, set, 0); util_poolset_close(set, DO_NOT_DELETE_PARTS); } break; case 'o': attr.incompat_features = TEST_FORMAT_INCOMPAT_CHECK; ret = util_pool_open(&set, fname, 0 /* rdonly */, MIN_PART, &attr, NULL, false, NULL); if (ret == -1) UT_OUT("!%s: util_pool_open", fname); else { poolset_info(fname, set, 1); util_poolset_close(set, DO_NOT_DELETE_PARTS); } break; case 'e': attr.incompat_features = TEST_FORMAT_INCOMPAT_CHECK; ret = util_pool_open(&set, fname, 0 /* rdonly */, MIN_PART, &attr, NULL, false, NULL); UT_ASSERTeq(ret, 0); void *nptr = util_pool_extend(set, Extend_size); if (nptr == NULL) UT_OUT("!%s: util_pool_extend", fname); else { poolset_info(fname, set, 1); } util_poolset_close(set, DO_NOT_DELETE_PARTS); break; } } common_fini(); DONE(NULL); }
/* * pmemobj_open_common -- open a transactional memory pool (set) * * This routine does all the work, but takes a cow flag so internal * calls can map a read-only pool if required. */ static PMEMobjpool * pmemobj_open_common(const char *path, const char *layout, int cow, int boot) { LOG(3, "path %s layout %s cow %d", path, layout, cow); struct pool_set *set; if (util_pool_open(&set, path, cow, PMEMOBJ_MIN_POOL, roundup(sizeof (struct pmemobjpool), Pagesize), OBJ_HDR_SIG, OBJ_FORMAT_MAJOR, OBJ_FORMAT_COMPAT, OBJ_FORMAT_INCOMPAT, OBJ_FORMAT_RO_COMPAT) != 0) { LOG(2, "cannot open pool or pool set"); return NULL; } ASSERT(set->nreplicas > 0); /* read-only mode is not supported in libpmemobj */ if (set->rdonly) { ERR("read-only mode is not supported"); errno = EINVAL; goto err; } PMEMobjpool *pop; for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; pop = rep->part[0].addr; VALGRIND_REMOVE_PMEM_MAPPING(&pop->addr, sizeof (struct pmemobjpool) - ((uintptr_t)&pop->addr - (uintptr_t)&pop->hdr)); pop->addr = pop; pop->size = rep->repsize; if (pmemobj_descr_check(pop, layout, set->poolsize) != 0) { LOG(2, "descriptor check failed"); goto err; } /* initialize replica runtime - is_pmem, funcs, ... */ if (pmemobj_replica_init(pop, rep->is_pmem) != 0) { ERR("pool initialization failed"); goto err; } /* link replicas */ if (r < set->nreplicas - 1) pop->replica = set->replica[r + 1]->part[0].addr; } /* * If there is more than one replica, check if all of them are * consistent (recoverable). * On success, choose any replica and copy entire lanes (redo logs) * to all the other replicas to synchronize them. */ if (set->nreplicas > 1) { for (unsigned r = 0; r < set->nreplicas; r++) { pop = set->replica[r]->part[0].addr; if (pmemobj_check_basic(pop) == 0) { ERR("inconsistent replica #%u", r); goto err; } } /* copy lanes */ pop = set->replica[0]->part[0].addr; void *src = (void *)((uintptr_t)pop + pop->lanes_offset); size_t len = pop->nlanes * sizeof (struct lane_layout); for (unsigned r = 1; r < set->nreplicas; r++) { pop = set->replica[r]->part[0].addr; void *dst = (void *)((uintptr_t)pop + pop->lanes_offset); pop->memcpy_persist_local(dst, src, len); } } pop = set->replica[0]->part[0].addr; pop->is_master_replica = 1; for (unsigned r = 1; r < set->nreplicas; r++) { PMEMobjpool *rep = set->replica[r]->part[0].addr; rep->is_master_replica = 0; } #ifdef USE_VG_MEMCHECK heap_vg_open(pop); #endif VALGRIND_DO_CREATE_MEMPOOL(pop, 0, 0); /* initialize runtime parts - lanes, obj stores, ... */ if (pmemobj_runtime_init(pop, 0, boot) != 0) { ERR("pool initialization failed"); goto err; } util_poolset_fdclose(set); util_poolset_free(set); #ifdef USE_VG_MEMCHECK if (boot) pmemobj_vg_boot(pop); #endif LOG(3, "pop %p", pop); return pop; err: LOG(4, "error clean up"); int oerrno = errno; util_poolset_close(set, 0); errno = oerrno; return NULL; }
/* * pmempool_setup_poolset -- parse poolset file and setup reading from it */ static int pmempool_setup_poolset(struct pmem_info *pip) { struct pool_set *set = NULL; int fd = -1; struct pool_hdr hdr; /* parse poolset file */ if (util_poolset_parse(pip->file_name, pip->fd, &set)) { outv_err("parsing poolset file failed\n"); return -1; } close(pip->fd); pip->fd = -1; /* open the first part set file to read the pool header values */ int ret = 0; fd = util_file_open(set->replica[0]->part[0].path, NULL, 0, O_RDONLY); if (fd < 0) { outv_err("cannot open poolset part file\n"); ret = -1; goto err_pool_set; } /* read the pool header from first pool set file */ if (pread(fd, &hdr, sizeof (hdr), 0) != sizeof (hdr)) { outv_err("cannot read pool header from poolset\n"); ret = -1; goto err_close; } close(fd); fd = -1; util_convert2h_pool_hdr(&hdr); /* parse pool type from first pool set file */ pmem_pool_type_t type = pmem_pool_type_parse_hdr(&hdr); if (type == PMEM_POOL_TYPE_UNKNOWN) { outv_err("cannot determine pool type from poolset\n"); ret = -1; goto err_close; } /* get minimum size based on pool type for util_pool_open */ size_t minsize = pmem_pool_get_min_size(type); /* * Open the poolset, the values passed to util_pool_open are read * from the first poolset file, these values are then compared with * the values from all headers of poolset files. */ if (util_pool_open(&pip->poolset, pip->file_name, 1, minsize, sizeof (struct pool_hdr), hdr.signature, hdr.major, hdr.compat_features, hdr.incompat_features, hdr.ro_compat_features)) { outv_err("openning poolset failed\n"); ret = -1; } err_close: if (fd != -1) close(fd); err_pool_set: util_poolset_free(set); return ret; }
/* * blk_open_common -- (internal) open a block memory pool * * This routine does all the work, but takes a cow flag so internal * calls can map a read-only pool if required. * * Passing in bsize == 0 means a valid pool header must exist (which * will supply the block size). */ static PMEMblkpool * blk_open_common(const char *path, size_t bsize, int cow) { LOG(3, "path %s bsize %zu cow %d", path, bsize, cow); struct pool_set *set; if (util_pool_open(&set, path, cow, PMEMBLK_MIN_POOL, BLK_HDR_SIG, BLK_FORMAT_MAJOR, BLK_FORMAT_COMPAT, BLK_FORMAT_INCOMPAT, BLK_FORMAT_RO_COMPAT, NULL) != 0) { LOG(2, "cannot open pool or pool set"); return NULL; } ASSERT(set->nreplicas > 0); struct pool_replica *rep = set->replica[0]; PMEMblkpool *pbp = rep->part[0].addr; VALGRIND_REMOVE_PMEM_MAPPING(&pbp->addr, sizeof(struct pmemblk) - ((uintptr_t)&pbp->addr - (uintptr_t)&pbp->hdr)); pbp->addr = pbp; pbp->size = rep->repsize; pbp->set = set; pbp->is_pmem = rep->is_pmem; pbp->is_dev_dax = rep->part[0].is_dev_dax; /* is_dev_dax implies is_pmem */ ASSERT(!pbp->is_dev_dax || pbp->is_pmem); if (set->nreplicas > 1) { errno = ENOTSUP; ERR("!replicas not supported"); goto err; } /* validate pool descriptor */ if (blk_descr_check(pbp, &bsize) != 0) { LOG(2, "descriptor check failed"); goto err; } /* initialize runtime parts */ if (blk_runtime_init(pbp, bsize, set->rdonly) != 0) { ERR("pool initialization failed"); goto err; } util_poolset_fdclose(set); LOG(3, "pbp %p", pbp); return pbp; err: LOG(4, "error clean up"); int oerrno = errno; util_poolset_close(set, DO_NOT_DELETE_PARTS); errno = oerrno; return NULL; }