/* * remove_hdrs_replica -- (internal) remove headers from the replica */ static int remove_hdrs_replica(struct pool_set *set_in, struct pool_set *set_out, unsigned repn) { LOG(3, "set %p, repn %u", set_in, repn); int ret = 0; /* open all part files of the input replica */ if (replica_open_replica_part_files(set_in, repn)) { LOG(1, "opening replica %u, part files failed", repn); ret = -1; goto out; } /* share part file descriptors between poolset structures */ copy_part_fds(set_out, set_in); /* map the whole input replica */ if (util_replica_open(set_in, repn, MAP_SHARED)) { LOG(1, "opening input replica failed: replica %u", repn); ret = -1; goto out_close; } /* map the whole output replica */ if (util_replica_open(set_out, repn, MAP_SHARED)) { LOG(1, "opening output replica failed: replica %u", repn); ret = -1; goto out_unmap_in; } /* move data between the two mappings of the replica */ if (REP(set_in, repn)->nparts > 1) copy_replica_data_fw(set_out, set_in, repn); /* make changes to the first part's header */ update_replica_header(set_out, repn); util_replica_close(set_out, repn); out_unmap_in: util_replica_close(set_in, repn); out_close: util_replica_fdclose(REP(set_in, repn)); out: return ret; }
/* * util_pool_create -- create a new memory pool (set or a single file) * * On success returns 0 and a pointer to a newly allocated structure * containing the info of all the parts of the pool set and replicas. */ int util_pool_create(struct pool_set **setp, const char *path, size_t poolsize, 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 poolsize %zu minsize %zu " "hdrsize %zu sig %s major %u " "compat %#x incompat %#x ro_comapt %#x", setp, path, poolsize, minsize, hdrsize, sig, major, compat, incompat, ro_compat); int flags = MAP_SHARED; int ret = util_poolset_create(setp, path, poolsize, minsize); if (ret < 0) { LOG(2, "cannot create pool set"); return -1; } struct pool_set *set = *setp; ASSERT(set->nreplicas > 0); set->zeroed = 1; set->poolsize = SIZE_MAX; /* generate pool set UUID */ uuid_generate(set->uuid); /* generate UUID's for all the parts */ for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; for (unsigned i = 0; i < rep->nparts; i++) uuid_generate(rep->part[i].uuid); } for (unsigned r = 0; r < set->nreplicas; r++) { if (util_replica_create(set, r, flags, hdrsize, sig, major, compat, incompat, ro_compat) != 0) { LOG(2, "replica creation failed"); goto err; } } 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, 1); errno = oerrno; return -1; }
/* * unmap_all_headers -- (internal) unmap all headers in a poolset */ static int unmap_all_headers(struct pool_set *set) { for (unsigned r = 0; r < set->nreplicas; ++r) { struct pool_replica *rep = set->replica[r]; util_replica_close(set, r); if (rep->remote && rep->remote->rpp) { Rpmem_close(rep->remote->rpp); rep->remote->rpp = NULL; } } return 0; }
/* * util_pool_open_nocheck -- open a memory pool (set or a single file) * * This function opens opens a pool set without checking the header values. */ int util_pool_open_nocheck(struct pool_set **setp, const char *path, int rdonly, size_t hdrsize) { LOG(3, "setp %p path %s", setp, path); int flags = rdonly ? MAP_PRIVATE|MAP_NORESERVE : MAP_SHARED; int ret = util_poolset_open(setp, path, 0); 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; } } /* 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_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_pool_open_remote -- open a remote pool set 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_remote(struct pool_set **setp, const char *path, int rdonly, size_t minsize, char *sig, uint32_t *major, uint32_t *compat, uint32_t *incompat, uint32_t *ro_compat, unsigned char *poolset_uuid, unsigned char *first_part_uuid, unsigned char *prev_repl_uuid, unsigned char *next_repl_uuid, unsigned char *arch_flags) { LOG(3, "setp %p path %s rdonly %d minsize %zu " "sig %p major %p compat %p incompat %p ro_comapt %p" "poolset_uuid %p first_part_uuid %p" "prev_repl_uuid %p next_repl_uuid %p arch_flags %p", setp, path, rdonly, minsize, sig, major, compat, incompat, ro_compat, poolset_uuid, first_part_uuid, prev_repl_uuid, next_repl_uuid, arch_flags); 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; if (set->nreplicas > 1) { LOG(2, "remote pool set cannot have replicas"); goto err; } if (util_replica_open(set, 0, flags) != 0) { LOG(2, "replica open failed"); goto err; } struct pool_replica *rep = set->replica[0]; struct pool_hdr *hdr = rep->part[0].hdr; set->rdonly |= rep->part[0].rdonly; /* check headers, check UUID's, check replicas linkage */ for (unsigned p = 0; p < rep->nparts; p++) { if (util_header_check_remote(rep, p) != 0) { LOG(2, "header check failed - part #%d", p); goto err; } set->rdonly |= rep->part[p].rdonly; } memcpy(sig, hdr->signature, POOL_HDR_SIG_LEN); *major = hdr->major; *compat = hdr->compat_features; *incompat = hdr->incompat_features; *ro_compat = hdr->ro_compat_features; memcpy(poolset_uuid, hdr->poolset_uuid, POOL_HDR_UUID_LEN); memcpy(first_part_uuid, hdr->uuid, POOL_HDR_UUID_LEN); memcpy(prev_repl_uuid, hdr->prev_repl_uuid, POOL_HDR_UUID_LEN); memcpy(next_repl_uuid, hdr->next_repl_uuid, POOL_HDR_UUID_LEN); memcpy(arch_flags, &hdr->arch_flags, sizeof(struct arch_flags)); /* unmap all headers */ 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; util_replica_close(set, 0); util_poolset_close(set, 0); errno = oerrno; return -1; }
/* * util_pool_create_uuids -- create a new memory pool (set or a single file) * with given uuids * * On success returns 0 and a pointer to a newly allocated structure * containing the info of all the parts of the pool set and replicas. */ int util_pool_create_uuids(struct pool_set **setp, const char *path, size_t poolsize, size_t minsize, const char *sig, uint32_t major, uint32_t compat, uint32_t incompat, uint32_t ro_compat, const unsigned char *poolset_uuid, const unsigned char *first_part_uuid, const unsigned char *prev_repl_uuid, const unsigned char *next_repl_uuid, const unsigned char *arch_flags) { LOG(3, "setp %p path %s poolsize %zu minsize %zu " "sig %.8s major %u compat %#x incompat %#x ro_comapt %#x " "poolset_uuid %p first_part_uuid %p" "prev_repl_uuid %p next_repl_uuid %p arch_flags %p", setp, path, poolsize, minsize, sig, major, compat, incompat, ro_compat, poolset_uuid, first_part_uuid, prev_repl_uuid, next_repl_uuid, arch_flags); int flags = MAP_SHARED; int ret = util_poolset_create(setp, path, poolsize, minsize); if (ret < 0) { LOG(2, "cannot create pool set"); return -1; } struct pool_set *set = *setp; ASSERT(set->nreplicas > 0); set->zeroed = 1; if (poolset_uuid) { memcpy(set->uuid, poolset_uuid, POOL_HDR_UUID_LEN); } else { /* generate pool set UUID */ ret = util_uuid_generate(set->uuid); if (ret < 0) { LOG(2, "cannot generate pool set UUID"); util_poolset_close(*setp, 1); return -1; } } /* generate UUID's for all the parts */ for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; for (unsigned i = 0; i < rep->nparts; i++) { ret = util_uuid_generate(rep->part[i].uuid); if (ret < 0) { LOG(2, "cannot generate pool set part UUID"); util_poolset_close(*setp, 1); return -1; } } } /* overwrite UUID of the first part if given */ if (first_part_uuid) { memcpy(set->replica[0]->part[0].uuid, first_part_uuid, POOL_HDR_UUID_LEN); } if (set->nreplicas == 1 && prev_repl_uuid && next_repl_uuid) { if (util_replica_create(set, 0, flags, sig, major, compat, incompat, ro_compat, prev_repl_uuid, next_repl_uuid, arch_flags) != 0) { LOG(2, "replica creation failed"); goto err; } } else { for (unsigned r = 0; r < set->nreplicas; r++) { if (util_replica_create(set, r, flags, sig, major, compat, incompat, ro_compat, NULL, NULL, NULL) != 0) { LOG(2, "replica creation failed"); goto err; } } } 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, 1); errno = oerrno; return -1; }
/* * add_hdrs_replica -- (internal) add lacking headers to the replica * * when the operation fails and returns -1, the replica remains untouched */ static int add_hdrs_replica(struct pool_set *set_in, struct pool_set *set_out, unsigned repn) { LOG(3, "set %p, repn %u", set_in, repn); int ret = 0; /* open all part files of the input replica */ if (replica_open_replica_part_files(set_in, repn)) { LOG(1, "opening replica %u, part files failed", repn); ret = -1; goto out; } /* share part file descriptors between poolset structures */ copy_part_fds(set_out, set_in); /* map the whole input replica */ if (util_replica_open(set_in, repn, MAP_SHARED)) { LOG(1, "opening input replica failed: replica %u", repn); ret = -1; goto out_close; } /* map the whole output replica */ if (util_replica_open(set_out, repn, MAP_SHARED)) { LOG(1, "opening output replica failed: replica %u", repn); ret = -1; goto out_unmap_in; } /* generate new uuids for lacking headers */ if (fill_replica_struct_uuids(set_out, repn)) { LOG(1, "generating lacking uuids for parts failed: replica %u", repn); ret = -1; goto out_unmap_out; } /* copy data between the two mappings of the replica */ if (REP(set_in, repn)->nparts > 1) copy_replica_data_bw(set_out, set_in, repn); /* create the missing headers */ if (create_missing_headers(set_out, repn)) { LOG(1, "creating lacking headers failed: replica %u", repn); /* * copy the data back, so we could fall back to the original * state */ if (REP(set_in, repn)->nparts > 1) copy_replica_data_fw(set_in, set_out, repn); ret = -1; goto out_unmap_out; } /* make changes to the first part's header */ update_replica_header(set_out, repn); /* store new uuids in all headers and update linkage in the replica */ update_uuids(set_out, repn); out_unmap_out: util_replica_close(set_out, repn); out_unmap_in: util_replica_close(set_in, repn); out_close: util_replica_fdclose(REP(set_in, repn)); out: return ret; }