/* * pmempool_info_part -- (internal) print info about poolset part */ static int pmempool_info_part(struct pmem_info *pip, unsigned repn, unsigned partn, int v) { /* get path of the part file */ const char *path = NULL; if (repn != UNDEF_REPLICA && partn != UNDEF_PART) { outv(v, "part %u:\n", partn); struct pool_set_part *part = &pip->pfile->poolset->replica[repn]->part[partn]; path = part->path; } else { outv(v, "Part file:\n"); path = pip->file_name; } outv_field(v, "path", "%s", path); /* get type of the part file */ int is_dev_dax = util_file_is_device_dax(path); const char *type_str = is_dev_dax ? "device dax" : "regular file"; outv_field(v, "type", "%s", type_str); /* get size of the part file */ ssize_t size = util_file_get_size(path); if (size < 0) { outv_err("couldn't get size of %s", path); return -1; } outv_field(v, "size", "%s", out_get_size_str((size_t)size, pip->args.human)); return 0; }
/* * util_file_pread -- reads from a file with an offset */ ssize_t util_file_pread(const char *path, void *buffer, size_t size, off_t offset) { if (!util_file_is_device_dax(path)) { int fd = util_file_open(path, NULL, 0, O_RDONLY); if (fd < 0) return -1; ssize_t read_len = pread(fd, buffer, size, offset); int olderrno = errno; (void) close(fd); errno = olderrno; return read_len; } ssize_t file_size = util_file_get_size(path); if (file_size < 0) return -1; size_t max_size = (size_t)(file_size - offset); if (size > max_size) { LOG(1, "Requested size of read goes beyond the mapped memory"); size = max_size; } void *addr = util_file_map_whole(path); if (addr == NULL) return -1; memcpy(buffer, ADDR_SUM(addr, offset), size); util_unmap(addr, (size_t)file_size); return (ssize_t)size; }
/* * util_unlink -- unlinks a file or zeroes a device dax */ int util_unlink(const char *path) { if (util_file_is_device_dax(path)) { return util_file_zero_whole(path); } else { return unlink(path); } }
/* * util_unlink -- unlinks a file or zeroes a device dax */ int util_unlink(const char *path) { if (util_file_is_device_dax(path)) { return util_file_zero_whole(path); } else { /* * On Windows we can not unlink Read-Only files */ #ifdef _WIN32 _chmod(path, _S_IREAD | _S_IWRITE); #endif return unlink(path); } }
/* * is_dev_dax -- checks if given path points to device dax */ static int is_dev_dax(const char *path) { if (!util_file_is_device_dax(path)) { printf("%s -- not device dax\n", path); return 0; } if (access(path, W_OK|R_OK)) { printf("%s -- permission denied\n", path); return -1; } return 1; }
/* * util_file_get_size -- returns size of a file */ ssize_t util_file_get_size(const char *path) { #ifndef _WIN32 if (util_file_is_device_dax(path)) { return device_dax_size(path); } #endif util_stat_t stbuf; if (util_stat(path, &stbuf) < 0) { ERR("!fstat %s", path); return -1; } return stbuf.st_size; }
/* * pool_parse_params -- parse pool type, file size and block size */ static int pool_params_parse(const PMEMpoolcheck *ppc, struct pool_params *params, int check) { LOG(3, NULL); int is_btt = ppc->args.pool_type == PMEMPOOL_POOL_TYPE_BTT; params->type = POOL_TYPE_UNKNOWN; params->is_poolset = util_is_poolset_file(ppc->path) == 1; int fd = util_file_open(ppc->path, NULL, 0, O_RDONLY); if (fd < 0) return -1; int ret = 0; util_stat_t stat_buf; ret = util_fstat(fd, &stat_buf); if (ret) goto out_close; ASSERT(stat_buf.st_size >= 0); params->mode = stat_buf.st_mode; struct pool_set *set; void *addr; if (params->is_poolset) { /* * Need to close the poolset because it will be opened with * flock in the following instructions. */ close(fd); fd = -1; if (check) { if (pool_set_map(ppc->path, &set, 0)) return -1; } else { ret = util_poolset_create_set(&set, ppc->path, 0, 0); if (ret < 0) { LOG(2, "cannot open pool set -- '%s'", ppc->path); return -1; } if (set->remote) { ERR("poolsets with remote replicas are not " "supported"); return -1; } if (util_pool_open_nocheck(set, 0)) return -1; } params->size = set->poolsize; addr = set->replica[0]->part[0].addr; /* * XXX mprotect for device dax with length not aligned to its * page granularity causes SIGBUS on the next page fault. * The length argument of this call should be changed to * set->poolsize once the kernel issue is solved. */ if (mprotect(addr, set->replica[0]->repsize, PROT_READ) < 0) { ERR("!mprotect"); goto out_unmap; } params->is_device_dax = set->replica[0]->part[0].is_dax; } else if (is_btt) { params->size = (size_t)stat_buf.st_size; #ifndef _WIN32 if (params->mode & S_IFBLK) if (ioctl(fd, BLKGETSIZE64, ¶ms->size)) { ERR("!ioctl"); goto out_close; } #endif addr = NULL; } else { ssize_t s = util_file_get_size(ppc->path); if (s < 0) { ret = -1; goto out_close; } params->size = (size_t)s; addr = mmap(NULL, (uint64_t)params->size, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { ret = -1; goto out_close; } params->is_device_dax = util_file_is_device_dax(ppc->path); } /* stop processing for BTT device */ if (is_btt) { params->type = POOL_TYPE_BTT; params->is_part = false; goto out_close; } struct pool_hdr hdr; memcpy(&hdr, addr, sizeof(hdr)); util_convert2h_hdr_nocheck(&hdr); pool_params_from_header(params, &hdr); if (ppc->args.pool_type != PMEMPOOL_POOL_TYPE_DETECT) { enum pool_type declared_type = pmempool_check_type_to_pool_type(ppc->args.pool_type); if ((params->type & ~declared_type) != 0) { ERR("declared pool type does not match"); ret = 1; goto out_unmap; } } if (params->type == POOL_TYPE_BLK) { struct pmemblk pbp; memcpy(&pbp, addr, sizeof(pbp)); params->blk.bsize = le32toh(pbp.bsize); } else if (params->type == POOL_TYPE_OBJ) { struct pmemobjpool pop; memcpy(&pop, addr, sizeof(pop)); memcpy(params->obj.layout, pop.layout, PMEMOBJ_MAX_LAYOUT); } out_unmap: if (params->is_poolset) { ASSERTeq(fd, -1); ASSERTne(addr, NULL); util_poolset_close(set, 0); } else if (!is_btt) { ASSERTne(fd, -1); ASSERTne(addr, NULL); munmap(addr, params->size); } out_close: if (fd != -1) close(fd); return ret; }
/* * pobj_init - common part of the benchmark initialization functions. * Parses command line arguments, set variables and creates persistent pools. */ static int pobj_init(struct benchmark *bench, struct benchmark_args *args) { unsigned i = 0; size_t psize; size_t n_objs; assert(bench != nullptr); assert(args != nullptr); auto *bench_priv = (struct pobj_bench *)malloc(sizeof(struct pobj_bench)); if (bench_priv == nullptr) { perror("malloc"); return -1; } assert(args->opts != nullptr); bench_priv->args_priv = (struct pobj_args *)args->opts; bench_priv->args_priv->obj_size = args->dsize; bench_priv->args_priv->range = bench_priv->args_priv->min_size > 0 ? true : false; bench_priv->n_pools = !bench_priv->args_priv->one_pool ? args->n_threads : 1; bench_priv->pool = bench_priv->n_pools > 1 ? diff_num : one_num; bench_priv->obj = !bench_priv->args_priv->one_obj ? diff_num : one_num; if ((args->is_poolset || util_file_is_device_dax(args->fname)) && bench_priv->n_pools > 1) { fprintf(stderr, "cannot use poolset nor device dax for multiple pools," " please use -P|--one-pool option instead"); goto free_bench_priv; } /* * Multiplication by FACTOR prevents from out of memory error * as the actual size of the allocated persistent objects * is always larger than requested. */ n_objs = bench_priv->args_priv->n_objs; if (bench_priv->n_pools == 1) n_objs *= args->n_threads; psize = n_objs * args->dsize * args->n_threads * FACTOR; if (psize < PMEMOBJ_MIN_POOL) psize = PMEMOBJ_MIN_POOL; /* assign type_number determining function */ bench_priv->type_mode = parse_type_mode(bench_priv->args_priv->type_num); switch (bench_priv->type_mode) { case MAX_TYPE_MODE: fprintf(stderr, "unknown type mode"); goto free_bench_priv; case TYPE_MODE_RAND: if (random_types(bench_priv, args)) goto free_bench_priv; break; default: bench_priv->random_types = nullptr; } bench_priv->fn_type_num = type_mode_func[bench_priv->type_mode]; /* assign size determining function */ bench_priv->fn_size = bench_priv->args_priv->range ? range_size : static_size; bench_priv->rand_sizes = nullptr; if (bench_priv->args_priv->range) { if (bench_priv->args_priv->min_size > args->dsize) { fprintf(stderr, "Invalid allocation size"); goto free_random_types; } bench_priv->rand_sizes = rand_sizes(bench_priv->args_priv->min_size, bench_priv->args_priv->obj_size, bench_priv->args_priv->n_objs); if (bench_priv->rand_sizes == nullptr) goto free_random_types; } assert(bench_priv->n_pools > 0); bench_priv->pop = (PMEMobjpool **)calloc(bench_priv->n_pools, sizeof(PMEMobjpool *)); if (bench_priv->pop == nullptr) { perror("calloc"); goto free_random_sizes; } bench_priv->sets = (const char **)calloc(bench_priv->n_pools, sizeof(const char *)); if (bench_priv->sets == nullptr) { perror("calloc"); goto free_pop; } if (bench_priv->n_pools > 1) { assert(!args->is_poolset); if (util_file_mkdir(args->fname, DIR_MODE) != 0) { fprintf(stderr, "cannot create directory\n"); goto free_sets; } size_t path_len = (strlen(PART_NAME) + strlen(args->fname)) + MAX_DIGITS + 1; for (i = 0; i < bench_priv->n_pools; i++) { bench_priv->sets[i] = (char *)malloc(path_len * sizeof(char)); if (bench_priv->sets[i] == nullptr) { perror("malloc"); goto free_sets; } int ret = snprintf((char *)bench_priv->sets[i], path_len, "%s%s%02x", args->fname, PART_NAME, i); if (ret < 0 || ret >= (int)path_len) { perror("snprintf"); goto free_sets; } bench_priv->pop[i] = pmemobj_create(bench_priv->sets[i], LAYOUT_NAME, psize, FILE_MODE); if (bench_priv->pop[i] == nullptr) { perror(pmemobj_errormsg()); goto free_sets; } } } else { if (args->is_poolset || util_file_is_device_dax(args->fname)) { if (args->fsize < psize) { fprintf(stderr, "file size too large\n"); goto free_pools; } psize = 0; } bench_priv->sets[0] = args->fname; bench_priv->pop[0] = pmemobj_create( bench_priv->sets[0], LAYOUT_NAME, psize, FILE_MODE); if (bench_priv->pop[0] == nullptr) { perror(pmemobj_errormsg()); goto free_pools; } } pmembench_set_priv(bench, bench_priv); return 0; free_sets: for (; i > 0; i--) { pmemobj_close(bench_priv->pop[i - 1]); free((char *)bench_priv->sets[i - 1]); } free_pools: free(bench_priv->sets); free_pop: free(bench_priv->pop); free_random_sizes: free(bench_priv->rand_sizes); free_random_types: free(bench_priv->random_types); free_bench_priv: free(bench_priv); return -1; }