From f93eadd793f9f4fded30df5589f98ccfc0e1839f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 12 May 2015 16:37:56 -0700 Subject: [PATCH] mon: prevent bucket deletion when referenced by a rule If a rule references a bucket with 'take', prevent deletion. Fixes: #11602 Signed-off-by: Sage Weil (cherry picked from commit 3d591afef90b0601572c748f13faac029d05f5a0) --- qa/workunits/mon/crush_ops.sh | 6 ++++++ src/crush/CrushWrapper.cc | 27 +++++++++++++++++++++++++++ src/crush/CrushWrapper.h | 1 + 3 files changed, 34 insertions(+) diff --git a/qa/workunits/mon/crush_ops.sh b/qa/workunits/mon/crush_ops.sh index 56a0d232d7124..847edd83c37d5 100755 --- a/qa/workunits/mon/crush_ops.sh +++ b/qa/workunits/mon/crush_ops.sh @@ -63,6 +63,12 @@ ceph osd tree | grep -c host1 | grep -q 0 expect_false ceph osd crush rm bar # not empty ceph osd crush unlink host2 + +# reference foo and bar with a rule +ceph osd crush rule create-simple foo-rule foo host firstn +expect_false ceph osd crush rm foo +ceph osd crush rule rm foo-rule + ceph osd crush rm bar ceph osd crush rm foo ceph osd crush rm osd.$o2 host2 diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index b17829b8e8ece..abf79af701f11 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -113,6 +113,9 @@ bool CrushWrapper::_maybe_remove_last_instance(CephContext *cct, int item, bool if (_search_item_exists(item)) { return false; } + if (item < 0 && _bucket_is_in_use(cct, item)) { + return false; + } if (item < 0 && !unlink_only) { crush_bucket *t = get_bucket(item); @@ -140,6 +143,9 @@ int CrushWrapper::remove_item(CephContext *cct, int item, bool unlink_only) << " items, not empty" << dendl; return -ENOTEMPTY; } + if (_bucket_is_in_use(cct, item)) { + return -EBUSY; + } } for (int i = 0; i < crush->max_buckets; i++) { @@ -179,6 +185,22 @@ bool CrushWrapper::_search_item_exists(int item) const return false; } +bool CrushWrapper::_bucket_is_in_use(CephContext *cct, int item) +{ + for (unsigned i = 0; i < crush->max_rules; ++i) { + crush_rule *r = crush->rules[i]; + if (!r) + continue; + for (unsigned j = 0; j < r->len; ++j) { + if (r->steps[j].op == CRUSH_RULE_TAKE && + r->steps[j].arg1 == item) { + return true; + } + } + } + return false; +} + int CrushWrapper::_remove_item_under(CephContext *cct, int item, int ancestor, bool unlink_only) { ldout(cct, 5) << "_remove_item_under " << item << " under " << ancestor @@ -214,6 +236,11 @@ int CrushWrapper::remove_item_under(CephContext *cct, int item, int ancestor, bo { ldout(cct, 5) << "remove_item_under " << item << " under " << ancestor << (unlink_only ? " unlink_only":"") << dendl; + + if (!unlink_only && _bucket_is_in_use(cct, item)) { + return -EBUSY; + } + int ret = _remove_item_under(cct, item, ancestor, unlink_only); if (ret < 0) return ret; diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index 9fac2fe443ab6..8e285976dd493 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -518,6 +518,7 @@ public: private: bool _maybe_remove_last_instance(CephContext *cct, int id, bool unlink_only); int _remove_item_under(CephContext *cct, int id, int ancestor, bool unlink_only); + bool _bucket_is_in_use(CephContext *cct, int id); public: int remove_item_under(CephContext *cct, int id, int ancestor, bool unlink_only); -- 2.39.5