/* * util_pool_open -- open a memory pool (set or a single file) * * This routine does all the work, but takes a rdonly flag so internal * calls can map a read-only pool if required. */ int util_pool_open(struct pool_set **setp, const char *path, int rdonly, size_t minsize, size_t hdrsize, const char *sig, uint32_t major, uint32_t compat, uint32_t incompat, uint32_t ro_compat) { LOG(3, "setp %p path %s rdonly %d minsize %zu " "hdrsize %zu sig %s major %u " "compat %#x incompat %#x ro_comapt %#x", setp, path, rdonly, minsize, hdrsize, sig, major, compat, incompat, ro_compat); int flags = rdonly ? MAP_PRIVATE|MAP_NORESERVE : MAP_SHARED; int ret = util_poolset_open(setp, path, minsize); if (ret < 0) { LOG(2, "cannot open pool set"); return -1; } struct pool_set *set = *setp; ASSERT(set->nreplicas > 0); set->rdonly = 0; set->poolsize = SIZE_MAX; for (unsigned r = 0; r < set->nreplicas; r++) { if (util_replica_open(set, r, flags, hdrsize) != 0) { LOG(2, "replica open failed"); goto err; } } /* check headers, check UUID's, check replicas linkage */ for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; for (unsigned p = 0; p < rep->nparts; p++) { if (util_header_check(set, r, p, sig, major, compat, incompat, ro_compat) != 0) { LOG(2, "header check failed - part #%d", p); goto err; } set->rdonly |= rep->part[p].rdonly; } if (memcmp(HDR(REP(set, r - 1), 0)->uuid, HDR(REP(set, r), 0)->prev_repl_uuid, POOL_HDR_UUID_LEN) || memcmp(HDR(REP(set, r + 1), 0)->uuid, HDR(REP(set, r), 0)->next_repl_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong replica UUID"); errno = EINVAL; goto err; } } /* unmap all headers */ for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; for (unsigned p = 0; p < rep->nparts; p++) util_unmap_hdr(&rep->part[p]); } return 0; err: LOG(4, "error clean up"); int oerrno = errno; for (unsigned r = 0; r < set->nreplicas; r++) util_replica_close(set, r); util_poolset_close(set, 0); errno = oerrno; return -1; }
/* * util_replica_open -- (internal) open a memory pool replica */ static int util_replica_open(struct pool_set *set, unsigned repidx, int flags, size_t hdrsize, const char *sig, uint32_t major, uint32_t compat, uint32_t incompat, uint32_t ro_compat) { LOG(3, "set %p repidx %u flags %d hdrsize %zu sig %s major %u " "compat %#x incompat %#x ro_comapt %#x", set, repidx, flags, hdrsize, sig, major, compat, incompat, ro_compat); struct pool_replica *rep = set->replica[repidx]; rep->repsize -= (rep->nparts - 1) * hdrsize; /* determine a hint address for mmap() */ void *addr = util_map_hint(rep->repsize); /* XXX - randomize */ if (addr == NULL) { ERR("cannot find a contiguous region of given size"); return -1; } /* map the first part and reserve space for remaining parts */ if (util_map_part(&rep->part[0], addr, rep->repsize, 0, flags) != 0) { LOG(2, "pool mapping failed - part #0"); return -1; } VALGRIND_REGISTER_PMEM_MAPPING(rep->part[0].addr, rep->part[0].size); VALGRIND_REGISTER_PMEM_FILE(rep->part[0].fd, rep->part[0].addr, rep->part[0].size, 0); /* map all the remaining headers - don't care about the address */ for (unsigned p = 1; p < rep->nparts; p++) { if (util_map_part(&rep->part[p], NULL, hdrsize, 0, flags) != 0) { LOG(2, "header mapping failed - part #%d", p); goto err; } VALGRIND_REGISTER_PMEM_FILE(rep->part[p].fd, rep->part[p].addr, rep->part[p].size, 0); } /* check headers, check UUID's */ for (unsigned p = 0; p < rep->nparts; p++) { if (util_header_check(set, repidx, p, sig, major, compat, incompat, ro_compat) != 0) { LOG(2, "header check failed - part #%d", p); goto err; } } set->rdonly |= rep->part[0].rdonly; size_t mapsize = rep->part[0].filesize & ~(Pagesize - 1); addr = rep->part[0].addr + mapsize; /* * unmap headers; map the remaining parts of the usable pool space * (4K-aligned) */ for (unsigned p = 1; p < rep->nparts; p++) { /* unmap header */ if (util_unmap_part(&rep->part[p]) != 0) { LOG(2, "header unmapping failed - part #%d", p); } /* map data part */ if (util_map_part(&rep->part[p], addr, 0, hdrsize, flags | MAP_FIXED) != 0) { LOG(2, "usable space mapping failed - part #%d", p); goto err; } VALGRIND_REGISTER_PMEM_FILE(rep->part[p].fd, rep->part[p].addr, rep->part[p].size, hdrsize); mapsize += rep->part[p].size; set->rdonly |= rep->part[p].rdonly; /* XXX - not needed? */ addr += rep->part[p].size; } rep->is_pmem = pmem_is_pmem(rep->part[0].addr, rep->part[0].size); ASSERTeq(mapsize, rep->repsize); /* calculate pool size - choose the smallest replica size */ if (rep->repsize < set->poolsize) set->poolsize = rep->repsize; LOG(3, "replica addr %p", rep->part[0].addr); return 0; err: LOG(4, "error clean up"); int oerrno = errno; VALGRIND_REMOVE_PMEM_MAPPING(rep->part[0].addr, rep->part[0].size); util_unmap(rep->part[0].addr, rep->part[0].size); errno = oerrno; return -1; }