From: Jason Dillaman Date: Tue, 21 Aug 2018 01:48:20 +0000 (-0400) Subject: librbd: invoke new parent class API methods X-Git-Tag: v14.0.1~241^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4c6132b676de7e9ad247769d45e9b0e60ad42a76;p=ceph.git librbd: invoke new parent class API methods If the OSDs don't support the new methods, revert to the legacy class API methods. Signed-off-by: Jason Dillaman --- diff --git a/src/librbd/image/RefreshRequest.cc b/src/librbd/image/RefreshRequest.cc index 6c1218b94a9..d9178fc3b2d 100644 --- a/src/librbd/image/RefreshRequest.cc +++ b/src/librbd/image/RefreshRequest.cc @@ -423,10 +423,16 @@ template void RefreshRequest::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, &RefreshRequest::handle_v2_get_parent>(this); @@ -442,13 +448,41 @@ Context *RefreshRequest::handle_v2_get_parent(int *result) { 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 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; @@ -622,8 +656,14 @@ void RefreshRequest::send_v2_get_snapshots() { } 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); } @@ -672,13 +712,22 @@ Context *RefreshRequest::handle_v2_get_snapshots(int *result) { *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 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) { @@ -1202,6 +1251,12 @@ void RefreshRequest::apply() { 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; diff --git a/src/librbd/image/RefreshRequest.h b/src/librbd/image/RefreshRequest.h index 1d982425dba..1fa380fc7c3 100644 --- a/src/librbd/image/RefreshRequest.h +++ b/src/librbd/image/RefreshRequest.h @@ -57,7 +57,10 @@ private: * v v * V2_GET_METADATA * | | - * v | + * | -EOPNOTSUPP | + * | * * * | + * | * * | + * v v * | * V2_GET_PARENT | * | | * v (skip if not enabled) | @@ -129,6 +132,7 @@ private: bufferlist m_out_bl; + bool m_legacy_parent = false; bool m_legacy_snapshot = false; uint8_t m_order = 0; @@ -143,6 +147,7 @@ private: std::string m_object_prefix; ParentInfo m_parent_md; + bool m_head_parent_overlap = false; cls::rbd::GroupSpec m_group_spec; ::SnapContext m_snapc; diff --git a/src/test/librbd/image/test_mock_RefreshRequest.cc b/src/test/librbd/image/test_mock_RefreshRequest.cc index d3dcf5e0e5c..2b5c8422e77 100644 --- a/src/test/librbd/image/test_mock_RefreshRequest.cc +++ b/src/test/librbd/image/test_mock_RefreshRequest.cc @@ -209,9 +209,40 @@ public: 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()); } } @@ -270,17 +301,22 @@ public: } } - 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()); @@ -300,10 +336,10 @@ public: 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()); @@ -507,6 +543,7 @@ TEST_F(TestMockImageRefreshRequest, SuccessV2) { 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); @@ -537,10 +574,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessSnapshotV2) { 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); @@ -569,10 +607,12 @@ TEST_F(TestMockImageRefreshRequest, SuccessLegacySnapshotV2) { 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)) { @@ -605,10 +645,11 @@ TEST_F(TestMockImageRefreshRequest, SuccessSetSnapshotV2) { 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); @@ -657,6 +698,7 @@ TEST_F(TestMockImageRefreshRequest, SuccessChild) { 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); @@ -709,6 +751,7 @@ TEST_F(TestMockImageRefreshRequest, SuccessChildDontOpenParent) { 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); @@ -740,6 +783,7 @@ TEST_F(TestMockImageRefreshRequest, SuccessOpFeatures) { 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); @@ -809,6 +853,7 @@ TEST_F(TestMockImageRefreshRequest, DisableExclusiveLock) { // 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); @@ -863,6 +908,7 @@ TEST_F(TestMockImageRefreshRequest, DisableExclusiveLockWhileAcquiringLock) { // 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); @@ -907,6 +953,7 @@ TEST_F(TestMockImageRefreshRequest, JournalDisabledByPolicy) { 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); @@ -956,6 +1003,7 @@ TEST_F(TestMockImageRefreshRequest, EnableJournalWithExclusiveLock) { // 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); @@ -1004,6 +1052,7 @@ TEST_F(TestMockImageRefreshRequest, EnableJournalWithoutExclusiveLock) { // 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); @@ -1050,6 +1099,7 @@ TEST_F(TestMockImageRefreshRequest, DisableJournal) { // 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); @@ -1096,6 +1146,7 @@ TEST_F(TestMockImageRefreshRequest, EnableObjectMapWithExclusiveLock) { // 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); @@ -1135,6 +1186,7 @@ TEST_F(TestMockImageRefreshRequest, EnableObjectMapWithoutExclusiveLock) { // 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); @@ -1185,6 +1237,7 @@ TEST_F(TestMockImageRefreshRequest, DisableObjectMap) { // 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); @@ -1226,6 +1279,7 @@ TEST_F(TestMockImageRefreshRequest, OpenObjectMapError) { // 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); @@ -1254,6 +1308,7 @@ TEST_F(TestMockImageRefreshRequest, ApplyMetadataError) { 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);