From: Sage Weil Date: Tue, 12 May 2015 23:37:56 +0000 (-0700) Subject: mon: prevent bucket deletion when referenced by a rule X-Git-Tag: v0.94.3~41^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=bd91fb027ab91d487b1d61d25516c13590735d89;p=ceph.git 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) --- diff --git a/qa/workunits/mon/crush_ops.sh b/qa/workunits/mon/crush_ops.sh index 80950032fb2f9..adb3162038cb6 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 497c2196958a2..ec3414b3dda60 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -192,6 +192,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); @@ -219,6 +222,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++) { @@ -258,6 +264,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 @@ -293,6 +315,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 cfafab067dee2..43acc48f49e50 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -587,6 +587,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);