/* * 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; }
/* * sync_replica -- synchronize data across replicas within a poolset */ int sync_replica(struct pool_set *set, unsigned flags) { ASSERTne(set, NULL); /* examine poolset's health */ struct poolset_health_status *set_hs = NULL; if (replica_check_poolset_health(set, &set_hs, flags)) { ERR("poolset health check failed"); return -1; } /* check if poolset is broken; if not, nothing to do */ if (replica_is_poolset_healthy(set_hs)) { LOG(1, "Poolset is healthy"); goto OK_close; } /* find one good replica; it will be the source of data */ unsigned healthy_replica = replica_find_healthy_replica(set_hs); if (healthy_replica == UNDEF_REPLICA) { ERR("no healthy replica found"); goto err; } /* in dry-run mode we can stop here */ if (is_dry_run(flags)) { LOG(1, "Sync in dry-run mode finished successfully"); goto OK_close; } /* recreate broken parts */ if (recreate_broken_parts(set, set_hs, flags)) { ERR("recreating broken parts failed"); goto err; } /* open all part files */ if (replica_open_poolset_part_files(set)) { ERR("opening poolset part files failed"); goto err; } /* map all replicas */ if (util_poolset_open(set)) { ERR("opening poolset failed"); goto err; } /* this is required for opening remote pools */ set->poolsize = set_hs->replica[healthy_replica]->pool_size; /* open all remote replicas */ if (open_remote_replicas(set, set_hs)) { ERR("opening remote replicas failed"); goto err; } /* update uuid fields in the set structure with part headers */ if (fill_struct_uuids(set, healthy_replica, set_hs, flags)) { ERR("gathering uuids failed"); goto err; } /* create headers for broken parts */ if (!is_dry_run(flags)) { if (create_headers_for_broken_parts(set, healthy_replica, set_hs)) { ERR("creating headers for broken parts failed"); goto err; } } if (is_dry_run(flags)) goto OK_close; /* update uuids of replicas and parts */ update_uuids(set, set_hs); /* create all remote replicas */ if (create_remote_replicas(set, set_hs)) { ERR("creating remote replicas failed"); goto err; } /* check and copy data if possible */ if (copy_data_to_broken_parts(set, healthy_replica, flags, set_hs)) { ERR("copying data to broken parts failed"); goto err; } /* grant permissions to all created parts */ if (grant_broken_parts_perm(set, healthy_replica, set_hs)) { ERR("granting permissions to broken parts failed"); goto err; } OK_close: replica_free_poolset_health_status(set_hs); return 0; err: replica_free_poolset_health_status(set_hs); 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; }
/* * sync_replica -- synchronize data across replicas within a poolset */ int replica_sync(struct pool_set *set, struct poolset_health_status *s_hs, unsigned flags) { LOG(3, "set %p, flags %u", set, flags); int ret = 0; struct poolset_health_status *set_hs = NULL; /* check if we already know the poolset health status */ if (s_hs == NULL) { /* validate poolset before checking its health */ if (validate_args(set)) return -1; /* examine poolset's health */ if (replica_check_poolset_health(set, &set_hs, flags)) { ERR("poolset health check failed"); return -1; } /* check if poolset is broken; if not, nothing to do */ if (replica_is_poolset_healthy(set_hs)) { LOG(1, "Poolset is healthy"); goto out; } } else { set_hs = s_hs; } /* find one good replica; it will be the source of data */ unsigned healthy_replica = replica_find_healthy_replica(set_hs); if (healthy_replica == UNDEF_REPLICA) { ERR("no healthy replica found"); ret = -1; goto out; } /* in dry-run mode we can stop here */ if (is_dry_run(flags)) { LOG(1, "Sync in dry-run mode finished successfully"); goto out; } /* recreate broken parts */ if (recreate_broken_parts(set, set_hs, flags)) { ERR("recreating broken parts failed"); ret = -1; goto out; } /* open all part files */ if (replica_open_poolset_part_files(set)) { ERR("opening poolset part files failed"); ret = -1; goto out; } /* map all replicas */ if (util_poolset_open(set)) { ERR("opening poolset failed"); ret = -1; goto out; } /* this is required for opening remote pools */ set->poolsize = set_hs->replica[healthy_replica]->pool_size; /* open all remote replicas */ if (open_remote_replicas(set, set_hs)) { ERR("opening remote replicas failed"); ret = -1; goto out; } /* update uuid fields in the set structure with part headers */ if (fill_struct_uuids(set, healthy_replica, set_hs, flags)) { ERR("gathering uuids failed"); ret = -1; goto out; } /* create headers for broken parts */ if (!is_dry_run(flags)) { if (create_headers_for_broken_parts(set, healthy_replica, set_hs)) { ERR("creating headers for broken parts failed"); ret = -1; goto out; } } if (is_dry_run(flags)) goto out; /* create all remote replicas */ if (create_remote_replicas(set, set_hs, flags)) { ERR("creating remote replicas failed"); ret = -1; goto out; } /* check and copy data if possible */ if (copy_data_to_broken_parts(set, healthy_replica, flags, set_hs)) { ERR("copying data to broken parts failed"); ret = -1; goto out; } /* update uuids of replicas and parts */ if (update_uuids(set, set_hs)) { ERR("updating uuids failed"); ret = -1; goto out; } /* grant permissions to all created parts */ if (grant_created_parts_perm(set, healthy_replica, set_hs)) { ERR("granting permissions to created parts failed"); ret = -1; } out: if (s_hs == NULL) replica_free_poolset_health_status(set_hs); return ret; }