/* * check_uuids_between_replicas -- (internal) check if uuids between internally * consistent adjacent replicas are consistent */ static int check_uuids_between_replicas(struct pool_set *set, struct poolset_health_status *set_hs) { for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip comparing inconsistent pairs of replicas */ if (!replica_is_replica_consistent(r, set_hs) || !replica_is_replica_consistent(r + 1, set_hs)) continue; struct pool_replica *rep = REP(set, r); struct pool_replica *rep_n = REP(set, r + 1); struct replica_health_status *rep_hs = REP(set_hs, r); struct replica_health_status *rep_n_hs = REP(set_hs, r + 1); /* check adjacent replica uuids for yet unbroken parts */ unsigned p = replica_find_unbroken_part(r, set_hs); unsigned p_n = replica_find_unbroken_part(r + 1, set_hs); /* if the first part is broken, cannot compare replica uuids */ if (p > 0) { rep_hs->flags |= IS_BROKEN; continue; } /* if the first part is broken, cannot compare replica uuids */ if (p_n > 0) { rep_n_hs->flags |= IS_BROKEN; continue; } /* check if replica uuids are consistent between replicas */ if (uuidcmp(HDR(rep_n, p_n)->prev_repl_uuid, HDR(rep, p)->uuid) || uuidcmp( HDR(rep, p)->next_repl_uuid, HDR(rep_n, p_n)->uuid)) { if (set->nreplicas == 1) { rep_hs->flags |= IS_INCONSISTENT; } else { if (replica_is_replica_broken(r, set_hs)) { rep_hs->flags |= IS_BROKEN; continue; } if (replica_is_replica_broken(r + 1, set_hs)) { rep_n_hs->flags |= IS_BROKEN; continue; } // two unbroken and internally consistent // adjacent replicas have different adjacent // replica uuids - mark one as inconsistent rep_n_hs->flags |= IS_INCONSISTENT; continue; } } } return 0; }
/* * create_headers_for_broken_parts -- (internal) create headers for all new * parts created in place of the broken ones */ static int create_headers_for_broken_parts(struct pool_set *set, unsigned src_replica, struct poolset_health_status *set_hs) { struct pool_hdr *src_hdr = HDR(REP(set, src_replica), 0); for (unsigned r = 0; r < set_hs->nreplicas; ++r) { /* skip unbroken replicas */ if (!replica_is_replica_broken(r, set_hs)) continue; for (unsigned p = 0; p < set_hs->replica[r]->nparts; p++) { /* skip unbroken parts */ if (!replica_is_part_broken(r, p, set_hs)) continue; if (util_header_create(set, r, p, src_hdr->signature, src_hdr->major, src_hdr->compat_features, src_hdr->incompat_features, src_hdr->ro_compat_features, NULL, NULL, NULL) != 0) { LOG(1, "part headers create failed for" " replica %u part %u", r, p); errno = EINVAL; return -1; } } } return 0; }
/* * replica_is_replica_healthy -- check if replica is unbroken and consistent */ int replica_is_replica_healthy(unsigned repn, struct poolset_health_status *set_hs) { return !replica_is_replica_broken(repn, set_hs) && replica_is_replica_consistent(repn, set_hs); }
/* * do_added_parts_exist -- (internal) check if any part of the replicas that are * to be added (marked as broken) already exists */ static int do_added_parts_exist(struct pool_set *set, struct poolset_health_status *set_hs) { for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip unbroken (i.e. not being added) replicas */ if (!replica_is_replica_broken(r, set_hs)) continue; struct pool_replica *rep = REP(set, r); /* skip remote replicas */ if (rep->remote) continue; for (unsigned p = 0; p < rep->nparts; ++p) { /* check if part file exists */ int oerrno = errno; if (os_access(rep->part[p].path, F_OK) == 0 && !rep->part[p].is_dev_dax) { LOG(1, "part file %s exists", rep->part[p].path); return 1; } errno = oerrno; } } return 0; }
/* * create_headers_for_broken_parts -- (internal) create headers for all new * parts created in place of the broken ones */ static int create_headers_for_broken_parts(struct pool_set *set, unsigned src_replica, struct poolset_health_status *set_hs) { LOG(3, "set %p, src_replica %u, set_hs %p", set, src_replica, set_hs); struct pool_hdr *src_hdr = HDR(REP(set, src_replica), 0); for (unsigned r = 0; r < set_hs->nreplicas; ++r) { /* skip unbroken replicas */ if (!replica_is_replica_broken(r, set_hs)) continue; for (unsigned p = 0; p < set_hs->replica[r]->nhdrs; p++) { /* skip unbroken parts */ if (!replica_is_part_broken(r, p, set_hs)) continue; struct pool_attr attr; util_pool_hdr2attr(&attr, src_hdr); if (util_header_create(set, r, p, &attr, 0) != 0) { LOG(1, "part headers create failed for" " replica %u part %u", r, p); errno = EINVAL; return -1; } } } return 0; }
/* * replica_find_healthy_replica -- find a replica number which is a good source * of data */ unsigned replica_find_healthy_replica(struct poolset_health_status *set_hs) { if (set_hs->nreplicas == 1) { return replica_is_replica_broken(0, set_hs) ? UNDEF_REPLICA : 0; } else { for (unsigned r = 0; r < set_hs->nreplicas; ++r) { if (replica_is_replica_healthy(r, set_hs)) return r; } return UNDEF_REPLICA; } }
/* * grant_created_parts_perm -- (internal) set RW permission rights to all * the parts created in place of the broken ones */ static int grant_created_parts_perm(struct pool_set *set, unsigned src_repn, struct poolset_health_status *set_hs) { LOG(3, "set %p, src_repn %u, set_hs %p", set, src_repn, set_hs); /* choose the default permissions */ mode_t def_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; /* get permissions of the first part of the source replica */ mode_t src_mode; os_stat_t sb; if (os_stat(PART(REP(set, src_repn), 0).path, &sb) != 0) { ERR("cannot check file permissions of %s (replica %u, part %u)", PART(REP(set, src_repn), 0).path, src_repn, 0); src_mode = def_mode; } else { src_mode = sb.st_mode; } /* set permissions to all recreated parts */ for (unsigned r = 0; r < set_hs->nreplicas; ++r) { /* skip unbroken replicas */ if (!replica_is_replica_broken(r, set_hs)) continue; if (set->replica[r]->remote) continue; for (unsigned p = 0; p < set_hs->replica[r]->nparts; p++) { /* skip parts which were not created */ if (!PART(REP(set, r), p).created) continue; LOG(4, "setting permissions for part %u, replica %u", p, r); /* set rights to those of existing part files */ if (os_chmod(PART(REP(set, r), p).path, src_mode)) { ERR("cannot set permission rights for created" " parts: replica %u, part %u", r, p); errno = EPERM; return -1; } } } return 0; }
/* * check_replica_poolset_uuids - (internal) check if poolset_uuid fields are * consistent among all parts of a replica; * the replica is initially considered as * consistent */ static int check_replica_poolset_uuids(struct pool_set *set, unsigned repn, uuid_t poolset_uuid, struct poolset_health_status *set_hs) { LOG(3, "set %p, repn %u, poolset_uuid %p, set_hs %p", set, repn, poolset_uuid, set_hs); struct pool_replica *rep = REP(set, repn); for (unsigned p = 0; p < rep->nparts; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (!uuidcmp(HDR(rep, p)->poolset_uuid, poolset_uuid)) { /* * two internally consistent replicas have * different poolset_uuid */ if (replica_is_replica_broken(repn, set_hs)) { /* mark broken replica as inconsistent */ REP(set_hs, repn)->flags |= IS_INCONSISTENT; } else { /* * two consistent unbroken replicas * - cannot synchronize */ ERR("inconsistent poolset_uuid values"); return -1; } } else { /* * it is sufficient to check only one part * from internally consistent replica */ break; } } return 0; }
/* * check_uuids_between_replicas -- (internal) check if uuids between internally * consistent adjacent replicas are consistent */ static int check_uuids_between_replicas(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip comparing inconsistent pairs of replicas */ if (!replica_is_replica_consistent(r, set_hs) || !replica_is_replica_consistent(r + 1, set_hs)) continue; struct pool_replica *rep = REP(set, r); struct pool_replica *rep_n = REPN(set, r); /* get uuids of the two adjacent replicas */ uuid_t *rep_uuidp = NULL; uuid_t *rep_n_uuidp = NULL; unsigned r_n = REPNidx(set_hs, r); if (get_replica_uuid(rep, r, set_hs, &rep_uuidp)) LOG(2, "cannot get replica uuid, replica %u", r); if (get_replica_uuid(rep_n, r_n, set_hs, &rep_n_uuidp)) LOG(2, "cannot get replica uuid, replica %u", r_n); /* * check if replica uuids are consistent between two adjacent * replicas */ unsigned p = replica_find_unbroken_part(r, set_hs); unsigned p_n = replica_find_unbroken_part(r_n, set_hs); if (p_n != UNDEF_PART && rep_uuidp != NULL && uuidcmp(*rep_uuidp, HDR(rep_n, p_n)->prev_repl_uuid)) { ERR( "inconsistent replica uuids between replicas %u and %u", r, r_n); return -1; } if (p != UNDEF_PART && rep_n_uuidp != NULL && uuidcmp(*rep_n_uuidp, HDR(rep, p)->next_repl_uuid)) { ERR( "inconsistent replica uuids between replicas %u and %u", r, r_n); return -1; } /* * check if replica uuids on borders of a broken replica are * consistent */ unsigned r_nn = REPNidx(set_hs, r_n); if (set->nreplicas > 1 && p != UNDEF_PART && replica_is_replica_broken(r_n, set_hs) && replica_is_replica_consistent(r_nn, set_hs)) { unsigned p_nn = replica_find_unbroken_part(r_nn, set_hs); if (p_nn == UNDEF_PART) { LOG(2, "cannot compare uuids on borders of replica %u", r); continue; } struct pool_replica *rep_nn = REP(set, r_nn); if (uuidcmp(HDR(rep, p)->next_repl_uuid, HDR(rep_nn, p_nn)->prev_repl_uuid)) { ERR( "inconsistent replica uuids on borders of replica %u", r); return -1; } } } return 0; }