]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mon: prevent bucket deletion when referenced by a rule 4769/head
authorSage Weil <sage@redhat.com>
Tue, 12 May 2015 23:37:56 +0000 (16:37 -0700)
committerNathan Cutler <ncutler@suse.com>
Tue, 26 May 2015 17:17:41 +0000 (19:17 +0200)
If a rule references a bucket with 'take', prevent deletion.

Fixes: #11602
Signed-off-by: Sage Weil <sage@redhat.com>
(cherry picked from commit 3d591afef90b0601572c748f13faac029d05f5a0)

qa/workunits/mon/crush_ops.sh
src/crush/CrushWrapper.cc
src/crush/CrushWrapper.h

index 56a0d232d71248bc352f946fdd6c6fd672804449..847edd83c37d54fe7915c7d658a65cf27624dcc8 100755 (executable)
@@ -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
index b17829b8e8eceb49aa0a55799a5a70344ce57a49..abf79af701f11526112f2e78db2ce07ae783b7a5 100644 (file)
@@ -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;
index 9fac2fe443ab64f170dff92e43be16842dcb2ee1..8e285976dd49349ab620bb7a3c866df417cb8de8 100644 (file)
@@ -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);