mirror of
https://github.com/ceph/ceph
synced 2025-04-01 23:02:17 +00:00
crush, osd: handle multiple parents properly when applying pg upmaps
Fixes: http://tracker.ceph.com/issues/23921 Signed-off-by: xiexingguo <xie.xingguo@gmail.com>
This commit is contained in:
parent
5865b0cbec
commit
482ec97c98
@ -297,6 +297,19 @@ void CrushWrapper::find_takes(set<int> *roots) const
|
||||
}
|
||||
}
|
||||
|
||||
void CrushWrapper::find_takes_by_rule(int rule, set<int> *roots) const
|
||||
{
|
||||
if (rule < 0 || rule >= (int)crush->max_rules)
|
||||
return;
|
||||
crush_rule *r = crush->rules[rule];
|
||||
if (!r)
|
||||
return;
|
||||
for (unsigned i = 0; i < r->len; i++) {
|
||||
if (r->steps[i].op == CRUSH_RULE_TAKE)
|
||||
roots->insert(r->steps[i].arg1);
|
||||
}
|
||||
}
|
||||
|
||||
void CrushWrapper::find_roots(set<int> *roots) const
|
||||
{
|
||||
for (int i = 0; i < crush->max_buckets; i++) {
|
||||
@ -780,6 +793,36 @@ int CrushWrapper::get_children(int id, list<int> *children) const
|
||||
return b->size;
|
||||
}
|
||||
|
||||
void CrushWrapper::get_children_of_type(int id,
|
||||
int type,
|
||||
set<int> *children,
|
||||
bool exclude_shadow) const
|
||||
{
|
||||
if (id >= 0) {
|
||||
if (type == 0) {
|
||||
// want leaf?
|
||||
children->insert(id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto b = get_bucket(id);
|
||||
if (IS_ERR(b)) {
|
||||
return;
|
||||
}
|
||||
if (b->type < type) {
|
||||
// give up
|
||||
return;
|
||||
} else if (b->type == type) {
|
||||
if (!is_shadow_item(b->id) || !exclude_shadow) {
|
||||
children->insert(b->id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (unsigned n = 0; n < b->size; n++) {
|
||||
get_children_of_type(b->items[n], type, children, exclude_shadow);
|
||||
}
|
||||
}
|
||||
|
||||
int CrushWrapper::get_rule_failure_domain(int rule_id)
|
||||
{
|
||||
crush_rule *rule = get_rule(rule_id);
|
||||
@ -1387,15 +1430,33 @@ int CrushWrapper::get_immediate_parent_id(int id, int *parent) const
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int CrushWrapper::get_parent_of_type(int item, int type) const
|
||||
int CrushWrapper::get_parent_of_type(int item, int type, int rule) const
|
||||
{
|
||||
do {
|
||||
int r = get_immediate_parent_id(item, &item);
|
||||
if (r < 0) {
|
||||
return 0;
|
||||
if (rule < 0) {
|
||||
// no rule specified
|
||||
do {
|
||||
int r = get_immediate_parent_id(item, &item);
|
||||
if (r < 0) {
|
||||
return 0;
|
||||
}
|
||||
} while (get_bucket_type(item) != type);
|
||||
return item;
|
||||
}
|
||||
set<int> roots;
|
||||
find_takes_by_rule(rule, &roots);
|
||||
for (auto root : roots) {
|
||||
set<int> candidates;
|
||||
get_children_of_type(root, type, &candidates, false);
|
||||
for (auto candidate : candidates) {
|
||||
if (subtree_contains(candidate, item)) {
|
||||
// note that here we assure that no two different buckets
|
||||
// from a single crush rule will share a same device,
|
||||
// which should generally be true.
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
} while (get_bucket_type(item) != type);
|
||||
return item;
|
||||
}
|
||||
return 0; // not found
|
||||
}
|
||||
|
||||
int CrushWrapper::rename_class(const string& srcname, const string& dstname)
|
||||
|
@ -587,6 +587,7 @@ public:
|
||||
* Note that these may not be parentless roots.
|
||||
*/
|
||||
void find_takes(set<int> *roots) const;
|
||||
void find_takes_by_rule(int rule, set<int> *roots) const;
|
||||
|
||||
/**
|
||||
* find tree roots
|
||||
@ -683,9 +684,10 @@ public:
|
||||
|
||||
/**
|
||||
* return ancestor of the given type, or 0 if none
|
||||
* can pass in a specific crush **rule** to return ancestor from that rule only
|
||||
* (parent is always a bucket and thus <0)
|
||||
*/
|
||||
int get_parent_of_type(int id, int type) const;
|
||||
int get_parent_of_type(int id, int type, int rule = -1) const;
|
||||
|
||||
/**
|
||||
* get the fully qualified location of a device by successively finding
|
||||
@ -735,6 +737,10 @@ public:
|
||||
* @return number of items, or error
|
||||
*/
|
||||
int get_children(int id, list<int> *children) const;
|
||||
void get_children_of_type(int id,
|
||||
int type,
|
||||
set<int> *children,
|
||||
bool exclude_shadow = true) const;
|
||||
|
||||
/**
|
||||
* get failure-domain type of a specific crush rule
|
||||
|
@ -1678,7 +1678,7 @@ void OSDMap::maybe_remove_pg_upmaps(CephContext *cct,
|
||||
set<int> parents;
|
||||
for (auto osd : raw) {
|
||||
if (type > 0) {
|
||||
auto parent = tmpmap.crush->get_parent_of_type(osd, type);
|
||||
auto parent = tmpmap.crush->get_parent_of_type(osd, type, crush_rule);
|
||||
if (parent >= 0) {
|
||||
lderr(cct) << __func__ << " unable to get parent of raw osd."
|
||||
<< osd << " of pg " << pg
|
||||
|
Loading…
Reference in New Issue
Block a user