/* * util_file_open -- open a memory pool file */ int util_file_open(const char *path, size_t *size, size_t minsize, int flags) { LOG(3, "path %s size %p minsize %zu flags %d", path, size, minsize, flags); int oerrno; int fd; if ((fd = open(path, flags)) < 0) { ERR("!open %s", path); return -1; } if (flock(fd, LOCK_EX | LOCK_NB) < 0) { ERR("!flock"); (void) close(fd); return -1; } if (size || minsize) { if (size) ASSERTeq(*size, 0); util_stat_t stbuf; if (util_fstat(fd, &stbuf) < 0) { ERR("!fstat %s", path); goto err; } if (stbuf.st_size < 0) { ERR("stat %s: negative size", path); errno = EINVAL; goto err; } if ((size_t)stbuf.st_size < minsize) { ERR("size %zu smaller than %zu", (size_t)stbuf.st_size, minsize); errno = EINVAL; goto err; } if (size) *size = (size_t)stbuf.st_size; } return fd; err: oerrno = errno; if (flock(fd, LOCK_UN)) ERR("!flock unlock"); (void) close(fd); errno = oerrno; return -1; }
/* * util_poolset_chmod -- change mode for all created files related to pool set */ int util_poolset_chmod(struct pool_set *set, mode_t mode) { LOG(3, "set %p mode %o", set, mode); for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; for (unsigned p = 0; p < rep->nparts; p++) { struct pool_set_part *part = &rep->part[p]; if (!part->created) continue; util_stat_t stbuf; if (util_fstat(part->fd, &stbuf) != 0) { ERR("!fstat"); return -1; } if (stbuf.st_mode & ~(unsigned)S_IFMT) { LOG(1, "file permissions changed during pool " "initialization, file: %s (%o)", part->path, stbuf.st_mode & ~(unsigned)S_IFMT); } if (chmod(part->path, mode)) { ERR("!chmod %u/%u/%s", r, p, part->path); return -1; } } } return 0; }
/* * 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; }