/* * pool_hdr_nondefault_fix -- (internal) fix custom value fields */ static int pool_hdr_nondefault_fix(PMEMpoolcheck *ppc, location *loc, uint32_t question, void *context) { LOG(3, NULL); ASSERTne(loc, NULL); uint64_t *flags = NULL; switch (question) { case Q_CRTIME: CHECK_INFO(ppc, "%ssetting pool_hdr.crtime to file's modtime: " "%s", loc->prefix, check_get_time_str(ppc->pool->set_file->mtime)); util_convert2h_hdr_nocheck(&loc->hdr); loc->hdr.crtime = (uint64_t)ppc->pool->set_file->mtime; util_convert2le_hdr(&loc->hdr); break; case Q_ARCH_FLAGS: flags = (uint64_t *)&loc->valid_part_hdrp->arch_flags; CHECK_INFO(ppc, "%ssetting pool_hdr.arch_flags to 0x%08" PRIx64 "%08" PRIx64, loc->prefix, flags[0], flags[1]); util_convert2h_hdr_nocheck(&loc->hdr); memcpy(&loc->hdr.arch_flags, &loc->valid_part_hdrp->arch_flags, sizeof(struct arch_flags)); util_convert2le_hdr(&loc->hdr); break; default: ERR("not implemented question id: %u", question); } return 0; }
/* * pool_set_map -- (internal) map poolset */ static int pool_set_map(const char *fname, struct pool_set **poolset, int rdonly) { ASSERTeq(util_is_poolset_file(fname), 1); struct pool_hdr hdr; if (pool_set_read_header(fname, &hdr)) return -1; util_convert2h_hdr_nocheck(&hdr); /* parse pool type from first pool set file */ enum pool_type type = pool_hdr_get_type(&hdr); if (type == POOL_TYPE_UNKNOWN) { ERR("cannot determine pool type from poolset"); return -1; } /* get minimum size based on pool type for util_pool_open */ size_t minsize = 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(poolset, fname, rdonly, minsize, hdr.signature, hdr.major, hdr.compat_features, hdr.incompat_features, hdr.ro_compat_features, NULL)) { ERR("opening poolset failed"); return -1; } return 0; }
/* * pool_set_map -- (internal) map poolset */ static int pool_set_map(const char *fname, struct pool_set **poolset, unsigned flags) { ASSERTeq(util_is_poolset_file(fname), 1); struct pool_hdr hdr; if (pool_set_read_header(fname, &hdr)) return -1; util_convert2h_hdr_nocheck(&hdr); /* parse pool type from first pool set file */ enum pool_type type = pool_hdr_get_type(&hdr); if (type == POOL_TYPE_UNKNOWN) { ERR("cannot determine pool type from poolset"); return -1; } /* * 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. */ struct pool_attr attr; util_pool_hdr2attr(&attr, &hdr); if (util_pool_open(poolset, fname, 0 /* minpartsize */, &attr, NULL, NULL, flags | POOL_OPEN_IGNORE_SDS | POOL_OPEN_IGNORE_BAD_BLOCKS)) { ERR("opening poolset failed"); return -1; } return 0; }
/* * pool_set_type -- get pool type of a poolset */ enum pool_type pool_set_type(struct pool_set *set) { struct pool_hdr hdr; /* open the first part file to read the pool header values */ const struct pool_set_part *part = &PART(REP(set, 0), 0); int fdp = util_file_open(part->path, NULL, 0, O_RDONLY); if (fdp < 0) { ERR("cannot open poolset part file"); return POOL_TYPE_UNKNOWN; } /* read the pool header from first pool set file */ if (read(fdp, &hdr, sizeof(hdr)) != sizeof(hdr)) { ERR("cannot read pool header from poolset"); close(fdp); return POOL_TYPE_UNKNOWN; } close(fdp); util_convert2h_hdr_nocheck(&hdr); enum pool_type type = pool_hdr_get_type(&hdr); return type; }
/* * pool_set_type -- get pool type of a poolset */ enum pool_type pool_set_type(struct pool_set *set) { struct pool_hdr hdr; /* open the first part file to read the pool header values */ const struct pool_set_part *part = &PART(REP(set, 0), 0); if (util_file_pread(part->path, &hdr, sizeof(hdr), 0) != sizeof(hdr)) { ERR("cannot read pool header from poolset"); return POOL_TYPE_UNKNOWN; } util_convert2h_hdr_nocheck(&hdr); enum pool_type type = pool_hdr_get_type(&hdr); return type; }
/* * util_convert_hdr -- convert header to host byte order & validate * * Returns true if header is valid, and all the integer fields are * converted to host byte order. If the header is not valid, this * routine returns false and the header passed in is left in an * unknown state. */ int util_convert_hdr(struct pool_hdr *hdrp) { LOG(3, "hdrp %p", hdrp); util_convert2h_hdr_nocheck(hdrp); /* to be valid, a header must have a major version of at least 1 */ if (hdrp->major == 0) { ERR("invalid major version (0)"); return 0; } /* and to be valid, the fields must checksum correctly */ if (!util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 0)) { ERR("invalid checksum of pool header"); return 0; } LOG(3, "valid header, signature \"%.8s\"", hdrp->signature); return 1; }
/* * pmempool_info_pool_hdr -- (internal) print pool header information */ static int pmempool_info_pool_hdr(struct pmem_info *pip, int v) { static const char *alignment_desc_str[] = { " char", " short", " int", " long", " long long", " size_t", " off_t", " float", " double", " long double", " void *", }; static const size_t alignment_desc_n = sizeof(alignment_desc_str) / sizeof(alignment_desc_str[0]); int ret = 0; struct pool_hdr *hdr = malloc(sizeof(struct pool_hdr)); if (!hdr) err(1, "Cannot allocate memory for pool_hdr"); if (pmempool_info_read(pip, hdr, sizeof(*hdr), 0)) { outv_err("cannot read pool header\n"); free(hdr); return -1; } struct arch_flags arch_flags; if (util_get_arch_flags(&arch_flags)) { outv_err("cannot read architecture flags\n"); free(hdr); return -1; } outv_title(v, "POOL Header"); outv_hexdump(pip->args.vhdrdump, hdr, sizeof(*hdr), 0, 1); util_convert2h_hdr_nocheck(hdr); outv_field(v, "Signature", "%.*s%s", POOL_HDR_SIG_LEN, hdr->signature, pip->params.is_part ? " [part file]" : ""); outv_field(v, "Major", "%d", hdr->major); outv_field(v, "Mandatory features", "0x%x", hdr->incompat_features); outv_field(v, "Not mandatory features", "0x%x", hdr->compat_features); outv_field(v, "Forced RO", "0x%x", hdr->ro_compat_features); outv_field(v, "Pool set UUID", "%s", out_get_uuid_str(hdr->poolset_uuid)); outv_field(v, "UUID", "%s", out_get_uuid_str(hdr->uuid)); outv_field(v, "Previous part UUID", "%s", out_get_uuid_str(hdr->prev_part_uuid)); outv_field(v, "Next part UUID", "%s", out_get_uuid_str(hdr->next_part_uuid)); outv_field(v, "Previous replica UUID", "%s", out_get_uuid_str(hdr->prev_repl_uuid)); outv_field(v, "Next replica UUID", "%s", out_get_uuid_str(hdr->next_repl_uuid)); outv_field(v, "Creation Time", "%s", out_get_time_str((time_t)hdr->crtime)); uint64_t ad = hdr->arch_flags.alignment_desc; uint64_t cur_ad = arch_flags.alignment_desc; outv_field(v, "Alignment Descriptor", "%s", out_get_alignment_desc_str(ad, cur_ad)); for (size_t i = 0; i < alignment_desc_n; i++) { uint64_t a = GET_ALIGNMENT(ad, i); if (ad == cur_ad) { outv_field(v + 1, alignment_desc_str[i], "%2lu", a); } else { uint64_t av = GET_ALIGNMENT(cur_ad, i); if (a == av) { outv_field(v + 1, alignment_desc_str[i], "%2lu [OK]", a); } else { outv_field(v + 1, alignment_desc_str[i], "%2lu [wrong! should be %2lu]", a, av); } } } outv_field(v, "Class", "%s", out_get_ei_class_str(hdr->arch_flags.ei_class)); outv_field(v, "Data", "%s", out_get_ei_data_str(hdr->arch_flags.ei_data)); outv_field(v, "Machine", "%s", out_get_e_machine_str(hdr->arch_flags.e_machine)); outv_field(v, "Checksum", "%s", out_get_checksum(hdr, sizeof(*hdr), &hdr->checksum)); free(hdr); return ret; }
/* * 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; }