From 9d83bfd64d2a806b0c07aa8dcbf1ffa74b423446 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Mon, 20 Aug 2018 07:47:51 -0400 Subject: [PATCH] librbd: cls_rbd_parent on-disk struct supports namespaces If the OSDs are required to be Nautilus or later, it will automatically break backwards compatibility of the structure to support pool namespaces. Signed-off-by: Jason Dillaman --- src/cls/rbd/cls_rbd.cc | 70 +++++++++++++------- src/cls/rbd/cls_rbd.h | 113 ++++++++++++++++++++++---------- src/tools/ceph-dencoder/types.h | 2 +- 3 files changed, 124 insertions(+), 61 deletions(-) diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index 1cee8b904d66..0d747db59b45 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -66,6 +66,19 @@ CLS_NAME(rbd) #define RBD_DIR_NAME_KEY_PREFIX "name_" #define RBD_METADATA_KEY_PREFIX "metadata_" +namespace { + +uint64_t get_encode_features(cls_method_context_t hctx) { + uint64_t features = 0; + int8_t require_osd_release = cls_get_required_osd_release(hctx); + if (require_osd_release >= CEPH_RELEASE_NAUTILUS) { + features |= CEPH_FEATURE_SERVER_NAUTILUS; + } + return features; +} + +} // anonymous namespace + static int snap_read_header(cls_method_context_t hctx, bufferlist& bl) { unsigned snap_count = 0; @@ -153,6 +166,20 @@ static int write_key(cls_method_context_t hctx, const string &key, const T &t) { return 0; } +template +static int write_key(cls_method_context_t hctx, const string &key, const T &t, + uint64_t features) { + bufferlist bl; + encode(t, bl, features); + + int r = cls_cxx_map_set_val(hctx, key, &bl); + if (r < 0) { + CLS_ERR("failed to set omap key: %s", key.c_str()); + return r; + } + return 0; +} + static int remove_key(cls_method_context_t hctx, const string &key) { int r = cls_cxx_map_remove_key(hctx, key); if (r < 0 && r != -ENOENT) { @@ -801,13 +828,10 @@ int set_size(cls_method_context_t hctx, bufferlist *in, bufferlist *out) r = 0; if (r < 0) return r; - if (parent.exists() && parent.overlap > size) { - bufferlist parentbl; - parent.overlap = size; - encode(parent, parentbl); - r = cls_cxx_map_set_val(hctx, "parent", &parentbl); + if (parent.exists() && parent.head_overlap.value_or(0ULL) > size) { + parent.head_overlap = size; + r = write_key(hctx, "parent", parent, get_encode_features(hctx)); if (r < 0) { - CLS_ERR("error writing parent: %s", cpp_strerror(r).c_str()); return r; } } @@ -1398,10 +1422,10 @@ int get_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) } } - encode(parent.pool, *out); - encode(parent.id, *out); - encode(parent.snapid, *out); - encode(parent.overlap, *out); + encode(parent.pool_id, *out); + encode(parent.image_id, *out); + encode(parent.snap_id, *out); + encode(parent.head_overlap.value_or(0ULL), *out); return 0; } @@ -1459,9 +1483,10 @@ int set_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) r = read_key(hctx, "parent", &parent); if (r == 0) { CLS_LOG(20, "set_parent existing parent pool=%llu id=%s snapid=%llu" - "overlap=%llu", (unsigned long long)parent.pool, parent.id.c_str(), - (unsigned long long)parent.snapid.val, - (unsigned long long)parent.overlap); + "overlap=%llu", (unsigned long long)parent.pool_id, + parent.image_id.c_str(), + (unsigned long long)parent.snap_id.val, + (unsigned long long)parent.head_overlap.value_or(0ULL)); return -EEXIST; } @@ -1471,15 +1496,12 @@ int set_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) if (r < 0) return r; - bufferlist parentbl; - parent.pool = pool; - parent.id = id; - parent.snapid = snapid; - parent.overlap = std::min(our_size, size); - encode(parent, parentbl); - r = cls_cxx_map_set_val(hctx, "parent", &parentbl); + parent.pool_id = pool; + parent.image_id = id; + parent.snap_id = snapid; + parent.head_overlap = std::min(our_size, size); + r = write_key(hctx, "parent", parent, get_encode_features(hctx)); if (r < 0) { - CLS_ERR("error writing parent: %s", cpp_strerror(r).c_str()); return r; } @@ -1511,7 +1533,7 @@ int remove_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) } auto flatten_lambda = [hctx, features](const cls_rbd_snap& snap_meta) { - if (snap_meta.parent.pool != -1) { + if (snap_meta.parent.pool_id != -1) { if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0ULL) { // remove parent reference from snapshot cls_rbd_snap snap_meta_copy = snap_meta; @@ -2246,7 +2268,7 @@ int snapshot_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out) auto remove_lambda = [snap_id, &has_child_snaps, &has_trash_snaps](const cls_rbd_snap& snap_meta) { if (snap_meta.id != snap_id) { - if (snap_meta.parent.pool != -1) { + if (snap_meta.parent.pool_id != -1) { has_child_snaps = true; } if (cls::rbd::get_snap_namespace_type(snap_meta.snapshot_namespace) == @@ -2267,7 +2289,7 @@ int snapshot_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out) if (r < 0 && r != -ENOENT) { return r; } - bool has_parent = (r >= 0 && parent.pool != -1); + bool has_parent = (r >= 0 && parent.pool_id != -1); uint64_t op_features_mask = 0ULL; if (!has_child_snaps && !has_parent) { diff --git a/src/cls/rbd/cls_rbd.h b/src/cls/rbd/cls_rbd.h index 37f9a5efcf84..202ff97b7216 100644 --- a/src/cls/rbd/cls_rbd.h +++ b/src/cls/rbd/cls_rbd.h @@ -12,51 +12,95 @@ /// information about our parent image, if any struct cls_rbd_parent { - int64_t pool; ///< parent pool id - string id; ///< parent image id - snapid_t snapid; ///< parent snapid we refer to - uint64_t overlap; ///< portion of this image mapped onto parent (bytes) + int64_t pool_id = -1; + std::string pool_namespace; + std::string image_id; + snapid_t snap_id = CEPH_NOSNAP; + std::optional head_overlap = std::nullopt; - /// true if our parent pointer information is defined - bool exists() const { - return snapid != CEPH_NOSNAP && pool >= 0 && id.length() > 0 && overlap > 0; + cls_rbd_parent() { + } + cls_rbd_parent(const cls::rbd::ParentImageSpec& parent_image_spec, + const std::optional& head_overlap) + : pool_id(parent_image_spec.pool_id), + pool_namespace(parent_image_spec.pool_namespace), + image_id(parent_image_spec.image_id), snap_id(parent_image_spec.snap_id), + head_overlap(head_overlap) { } - cls_rbd_parent() : pool(-1), snapid(CEPH_NOSNAP), overlap(0) {} + inline bool exists() const { + return (pool_id >= 0 && !image_id.empty() && snap_id != CEPH_NOSNAP); + } - void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); - encode(pool, bl); - encode(id, bl); - encode(snapid, bl); - encode(overlap, bl); + inline bool operator==(const cls_rbd_parent& rhs) const { + return (pool_id == rhs.pool_id && + pool_namespace == rhs.pool_namespace && + image_id == rhs.image_id && + snap_id == rhs.snap_id); + } + inline bool operator!=(const cls_rbd_parent& rhs) const { + return !(*this == rhs); + } + + void encode(bufferlist& bl, uint64_t features) const { + // NOTE: remove support for version 1 after Nautilus EOLed + uint8_t version = 1; + if ((features & CEPH_FEATURE_SERVER_NAUTILUS) != 0ULL) { + // break backwards compatability when using nautilus or later OSDs + version = 2; + } + + ENCODE_START(version, version, bl); + encode(pool_id, bl); + if (version >= 2) { + encode(pool_namespace, bl); + } + encode(image_id, bl); + encode(snap_id, bl); + if (version == 1) { + encode(head_overlap.value_or(0ULL), bl); + } else { + encode(head_overlap, bl); + } ENCODE_FINISH(bl); } + void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); - decode(pool, bl); - decode(id, bl); - decode(snapid, bl); - decode(overlap, bl); + DECODE_START(2, bl); + decode(pool_id, bl); + if (struct_v >= 2) { + decode(pool_namespace, bl); + } + decode(image_id, bl); + decode(snap_id, bl); + if (struct_v == 1) { + uint64_t overlap; + decode(overlap, bl); + head_overlap = overlap; + } else { + decode(head_overlap, bl); + } DECODE_FINISH(bl); } + void dump(Formatter *f) const { - f->dump_int("pool", pool); - f->dump_string("id", id); - f->dump_unsigned("snapid", snapid); - f->dump_unsigned("overlap", overlap); + f->dump_int("pool_id", pool_id); + f->dump_string("pool_namespace", pool_namespace); + f->dump_string("image_id", image_id); + f->dump_unsigned("snap_id", snap_id); + if (head_overlap) { + f->dump_unsigned("head_overlap", *head_overlap); + } } + static void generate_test_instances(list& o) { - o.push_back(new cls_rbd_parent); - cls_rbd_parent *t = new cls_rbd_parent; - t->pool = 1; - t->id = "foo"; - t->snapid = 3; - t->overlap = 500; - o.push_back(t); + o.push_back(new cls_rbd_parent{}); + o.push_back(new cls_rbd_parent{{1, "", "image id", 234}, {}}); + o.push_back(new cls_rbd_parent{{1, "", "image id", 234}, {123}}); + o.push_back(new cls_rbd_parent{{1, "ns", "image id", 234}, {123}}); } }; -WRITE_CLASS_ENCODER(cls_rbd_parent) +WRITE_CLASS_ENCODER_FEATURES(cls_rbd_parent) struct cls_rbd_snap { snapid_t id = CEPH_NOSNAP; @@ -82,7 +126,7 @@ struct cls_rbd_snap { encode(image_size, bl); uint64_t features = 0; encode(features, bl); // unused -- preserve ABI - encode(parent, bl); + encode(parent, bl, 0); encode(protection_status, bl); encode(flags, bl); encode(snapshot_namespace, bl); @@ -154,10 +198,7 @@ struct cls_rbd_snap { t->id = 2; t->name = "snap2"; t->image_size = 12345678; - t->parent.pool = 1; - t->parent.id = "parent"; - t->parent.snapid = 456; - t->parent.overlap = 12345; + t->parent = {{1, "", "parent", 456}, 12345}; t->protection_status = RBD_PROTECTION_STATUS_PROTECTED; t->flags = 14; t->timestamp = utime_t(); diff --git a/src/tools/ceph-dencoder/types.h b/src/tools/ceph-dencoder/types.h index d8a5dd00d3c2..b56110df2a2c 100644 --- a/src/tools/ceph-dencoder/types.h +++ b/src/tools/ceph-dencoder/types.h @@ -461,7 +461,7 @@ TYPE(rgw_data_sync_status) #ifdef WITH_RBD #include "cls/rbd/cls_rbd.h" -TYPE(cls_rbd_parent) +TYPE_FEATUREFUL(cls_rbd_parent) TYPE(cls_rbd_snap) #include "cls/rbd/cls_rbd_types.h" -- 2.47.3