#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;
return 0;
}
+template <typename T>
+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) {
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;
}
}
}
}
- 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;
}
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;
}
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;
}
}
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;
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) ==
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) {
/// 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<uint64_t> 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<uint64_t>& 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<cls_rbd_parent*>& 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;
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);
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();