osd/OSDMap: cancel mapping if target osd is out

Suppose we have a bad pg_upmap_item, say:
```
pg_upmap_items 2.0 [0,8,5,4,6,12]
```
which maps osd.6 to osd.12 that is currently marked as out.

It turns out **maybe_remove_pg_upmaps** can not handle the
above case well because **_apply_upmap** will silently discard
any bad mappings whenver they try to target at some current
__out__ OSDs. So if you call **pg_to_raw_up(2.0)**, you'll probably
get something like: ```up [8,4,6] ``` (e.g., the last mapping pair 6->12
is simply ignored by **_apply_upmap**).

Make **clean_pg_upmaps** do the tidy-up check instead, since it
already has __bare__ access to those pg_upmaps and pg_upmap_items.

Fixes: http://tracker.ceph.com/issues/37501
Signed-off-by: xie xingguo <xie.xingguo@zte.com.cn>
Signed-off-by: ningtao <ningtao@sangfor.com.cn>
This commit is contained in:
xie xingguo 2018-12-19 17:01:23 +08:00
parent b5f33ae372
commit d06b65a0ab
2 changed files with 62 additions and 2 deletions

View File

@ -4211,9 +4211,16 @@ int OSDMap::clean_pg_upmaps(
pg_to_raw_osds(p.first, &raw, &primary);
mempool::osdmap::vector<pair<int,int>> newmap;
for (auto& q : p.second) {
if (std::find(raw.begin(), raw.end(), q.first) != raw.end()) {
newmap.push_back(q);
if (std::find(raw.begin(), raw.end(), q.first) == raw.end()) {
// cancel mapping if source osd does not exist anymore
continue;
}
if (q.second != CRUSH_ITEM_NONE && q.second < max_osd &&
q.second >= 0 && osd_weight[q.second] == 0) {
// cancel mapping if target osd is out
continue;
}
newmap.push_back(q);
}
if (newmap.empty()) {
ldout(cct, 10) << " removing no-op pg_upmap_items " << p.first << " "

View File

@ -689,6 +689,59 @@ TEST_F(OSDMapTest, CleanPGUpmaps) {
}
}
{
// http://tracker.ceph.com/issues/37501
pg_t ec_pg(0, my_ec_pool);
pg_t ec_pgid = osdmap.raw_pg_to_pg(ec_pg);
OSDMap tmpmap; // use a tmpmap here, so we do not dirty origin map..
int from = -1;
int to = -1;
{
// insert a valid pg_upmap_item
vector<int> ec_up;
int ec_up_primary;
osdmap.pg_to_raw_up(ec_pgid, &ec_up, &ec_up_primary);
ASSERT_TRUE(!ec_up.empty());
from = *(ec_up.begin());
ASSERT_TRUE(from >= 0);
for (int i = 0; i < (int)get_num_osds(); i++) {
if (std::find(ec_up.begin(), ec_up.end(), i) == ec_up.end()) {
to = i;
break;
}
}
ASSERT_TRUE(to >= 0);
ASSERT_TRUE(from != to);
vector<pair<int32_t,int32_t>> new_pg_upmap_items;
new_pg_upmap_items.push_back(make_pair(from, to));
OSDMap::Incremental pending_inc(osdmap.get_epoch() + 1);
pending_inc.new_pg_upmap_items[ec_pgid] =
mempool::osdmap::vector<pair<int32_t,int32_t>>(
new_pg_upmap_items.begin(), new_pg_upmap_items.end());
tmpmap.deepish_copy_from(osdmap);
tmpmap.apply_incremental(pending_inc);
ASSERT_TRUE(tmpmap.have_pg_upmaps(ec_pgid));
}
{
// mark one of the target OSDs of the above pg_upmap_item as out
OSDMap::Incremental pending_inc(tmpmap.get_epoch() + 1);
pending_inc.new_weight[to] = CEPH_OSD_OUT;
tmpmap.apply_incremental(pending_inc);
ASSERT_TRUE(tmpmap.is_out(to));
ASSERT_TRUE(tmpmap.have_pg_upmaps(ec_pgid));
}
{
// *maybe_remove_pg_upmaps* should be able to remove the above *bad* mapping
OSDMap::Incremental pending_inc(tmpmap.get_epoch() + 1);
OSDMap nextmap;
nextmap.deepish_copy_from(tmpmap);
nextmap.maybe_remove_pg_upmaps(g_ceph_context, tmpmap,
nextmap, &pending_inc);
tmpmap.apply_incremental(pending_inc);
ASSERT_TRUE(!tmpmap.have_pg_upmaps(ec_pgid));
}
}
{
// TEST pg_upmap
{