void RefreshRequest<I>::send_v2_get_parent() {
// NOTE: remove support when Mimic is EOLed
CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
+ ldout(cct, 10) << this << " " << __func__ << ": legacy=" << m_legacy_parent
+ << dendl;
librados::ObjectReadOperation op;
- cls_client::get_parent_start(&op, CEPH_NOSNAP);
+ if (!m_legacy_parent) {
+ cls_client::parent_get_start(&op);
+ cls_client::parent_overlap_get_start(&op, CEPH_NOSNAP);
+ } else {
+ cls_client::get_parent_start(&op, CEPH_NOSNAP);
+ }
auto aio_comp = create_rados_callback<
RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_parent>(this);
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
- if (*result == 0) {
- auto it = m_out_bl.cbegin();
+ auto it = m_out_bl.cbegin();
+ if (!m_legacy_parent) {
+ cls::rbd::ParentImageSpec parent_image_spec;
+ if (*result == 0) {
+ *result = cls_client::parent_get_finish(&it, &parent_image_spec);
+
+ m_parent_md.spec = {};
+ if (*result == 0) {
+ m_parent_md.spec.pool_id = parent_image_spec.pool_id;
+ m_parent_md.spec.image_id = parent_image_spec.image_id;
+ m_parent_md.spec.snap_id = parent_image_spec.snap_id;
+ }
+ }
+
+ std::optional<uint64_t> parent_overlap;
+ if (*result == 0) {
+ *result = cls_client::parent_overlap_get_finish(&it, &parent_overlap);
+ }
+
+ if (*result == 0 && parent_overlap) {
+ m_parent_md.overlap = *parent_overlap;
+ m_head_parent_overlap = true;
+ }
+ } else if (*result == 0) {
*result = cls_client::get_parent_finish(&it, &m_parent_md.spec,
&m_parent_md.overlap);
+ m_head_parent_overlap = true;
}
- if (*result < 0) {
+ if (*result == -EOPNOTSUPP && !m_legacy_parent) {
+ ldout(cct, 10) << "retrying using legacy parent method" << dendl;
+ m_legacy_parent = true;
+ send_v2_get_parent();
+ return nullptr;
+ } if (*result < 0) {
lderr(cct) << "failed to retrieve parent: " << cpp_strerror(*result)
<< dendl;
return m_on_finish;
} else {
cls_client::snapshot_get_start(&op, snap_id);
}
+
+ if (m_legacy_parent) {
+ cls_client::get_parent_start(&op, snap_id);
+ } else {
+ cls_client::parent_overlap_get_start(&op, snap_id);
+ }
+
cls_client::get_flags_start(&op, snap_id);
- cls_client::get_parent_start(&op, snap_id);
cls_client::get_protection_status_start(&op, snap_id);
}
*result = cls_client::snapshot_get_finish(&it, &m_snap_infos[i]);
}
- if (*result >= 0) {
- *result = cls_client::get_flags_finish(&it, &m_snap_flags[i]);
+ if (*result == 0) {
+ if (m_legacy_parent) {
+ *result = cls_client::get_parent_finish(&it, &m_snap_parents[i].spec,
+ &m_snap_parents[i].overlap);
+ } else {
+ std::optional<uint64_t> parent_overlap;
+ *result = cls_client::parent_overlap_get_finish(&it, &parent_overlap);
+ if (*result == 0 && parent_overlap && m_parent_md.spec.pool_id > -1) {
+ m_snap_parents[i].spec = m_parent_md.spec;
+ m_snap_parents[i].overlap = *parent_overlap;
+ }
+ }
}
if (*result >= 0) {
- *result = cls_client::get_parent_finish(&it, &m_snap_parents[i].spec,
- &m_snap_parents[i].overlap);
+ *result = cls_client::get_flags_finish(&it, &m_snap_flags[i]);
}
if (*result >= 0) {
m_image_ctx.object_prefix = std::move(m_object_prefix);
m_image_ctx.init_layout();
} else {
+ // HEAD revision doesn't have a defined overlap so it's only
+ // applicable to snapshots
+ if (!m_head_parent_overlap) {
+ m_parent_md = {};
+ }
+
m_image_ctx.features = m_features;
m_image_ctx.flags = m_flags;
m_image_ctx.op_features = m_op_features;
EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("get_info"), _, _, _))
.WillOnce(DoDefault());
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_parent"), _, _, _))
- .WillOnce(DoDefault());
+ }
+ }
+
+ void expect_parent_overlap_get(MockRefreshImageCtx &mock_image_ctx, int r) {
+ auto& expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
+ StrEq("parent_overlap_get"), _, _, _));
+ if (r < 0) {
+ expect.WillOnce(Return(r));
+ } else {
+ expect.WillOnce(DoDefault());
+ }
+ }
+
+ void expect_get_parent(MockRefreshImageCtx &mock_image_ctx, int r) {
+ auto& expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
+ StrEq("parent_get"), _, _, _));
+ if (r < 0) {
+ expect.WillOnce(Return(r));
+ } else {
+ expect.WillOnce(DoDefault());
+ expect_parent_overlap_get(mock_image_ctx, 0);
+ }
+ }
+
+ void expect_get_parent_legacy(MockRefreshImageCtx &mock_image_ctx, int r) {
+ auto& expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
+ StrEq("get_parent"), _, _, _));
+ if (r < 0) {
+ expect.WillOnce(Return(r));
+ } else {
+ expect.WillOnce(DoDefault());
}
}
}
}
- void expect_get_snapshots(MockRefreshImageCtx &mock_image_ctx, int r) {
+ void expect_get_snapshots(MockRefreshImageCtx &mock_image_ctx,
+ bool legacy_parent, int r) {
auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("snapshot_get"), _, _, _));
if (r < 0) {
expect.WillOnce(Return(r));
} else {
expect.WillOnce(DoDefault());
+ if (legacy_parent) {
+ EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_parent"), _, _, _))
+ .WillOnce(DoDefault());
+ } else {
+ expect_parent_overlap_get(mock_image_ctx, 0);
+ }
expect_get_flags(mock_image_ctx, 0);
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_parent"), _, _, _))
- .WillOnce(DoDefault());
EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_protection_status"), _, _, _))
.WillOnce(DoDefault());
EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapshot_timestamp"), _, _, _))
.WillOnce(DoDefault());
- expect_get_flags(mock_image_ctx, 0);
EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_parent"), _, _, _))
.WillOnce(DoDefault());
+ expect_get_flags(mock_image_ctx, 0);
EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_protection_status"), _, _, _))
.WillOnce(DoDefault());
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
- expect_get_snapshots(mock_image_ctx, 0);
+ expect_get_snapshots(mock_image_ctx, false, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
expect_init_exclusive_lock(mock_image_ctx, mock_exclusive_lock, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, -EOPNOTSUPP);
+ expect_get_parent_legacy(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
- expect_get_snapshots(mock_image_ctx, -EOPNOTSUPP);
+ expect_get_snapshots(mock_image_ctx, true, -EOPNOTSUPP);
expect_get_snapshots_legacy(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
- expect_get_snapshots(mock_image_ctx, 0);
+ expect_get_snapshots(mock_image_ctx, false, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
expect_open_object_map(mock_image_ctx, &mock_object_map, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx2->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_op_features(mock_image_ctx, RBD_OPERATION_FEATURE_CLONE_CHILD, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx2->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_op_features(mock_image_ctx, RBD_OPERATION_FEATURE_CLONE_CHILD, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, mock_image_ctx.features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_op_features(mock_image_ctx, 4096, 0);
// and journaling were never enabled (or active)
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// and journaling were never enabled (or active)
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// journal should be immediately opened if exclusive lock owned
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// do not open the journal if exclusive lock is not owned
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// verify journal is closed if feature disabled
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// object map should be immediately opened if exclusive lock owned
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// do not open the object map if exclusive lock is not owned
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// verify object map is closed if feature disabled
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
// object map should be immediately opened if exclusive lock owned
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
+ expect_get_parent(mock_image_ctx, 0);
expect_get_metadata(mock_image_ctx, 0);
expect_apply_metadata(mock_image_ctx, -EINVAL);
expect_get_group(mock_image_ctx, 0);