]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: don't clip expanded diff on truncate in ObjectListSnapsRequest
authorIlya Dryomov <idryomov@gmail.com>
Wed, 28 Feb 2024 13:20:16 +0000 (14:20 +0100)
committerIlya Dryomov <idryomov@gmail.com>
Fri, 15 Mar 2024 10:05:16 +0000 (11:05 +0100)
If the diff was expanded due to LIST_SNAPS_FLAG_WHOLE_OBJECT, clipping
it when handling a truncate is wrong -- when subtracting that interval,
we either split the expanded extent into two or chop off a piece of it.
However the point of LIST_SNAPS_FLAG_WHOLE_OBJECT is to report a single
extent covering the entire object.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
(cherry picked from commit 0ebca5fe22d976f1a17f8078f20a47c49a057edb)

src/librbd/io/ObjectRequest.cc
src/test/librbd/io/test_mock_ObjectRequest.cc

index 428f0fbdf5844a5cdf74c323fa75389fc876c31e..a7748623037e290f3df9c9fdd14451a0a0e41ad4 100644 (file)
@@ -865,7 +865,8 @@ void ObjectListSnapsRequest<I>::handle_list_snaps(int r) {
 
     // clip diff to size of object (in case it was truncated)
     interval_set<uint64_t> zero_interval;
-    if (end_size < prev_end_size) {
+    if (end_size < prev_end_size &&
+        (m_list_snaps_flags & LIST_SNAPS_FLAG_WHOLE_OBJECT) == 0) {
       zero_interval.insert(end_size, prev_end_size - end_size);
       zero_interval.intersection_of(object_interval);
 
index cd553d2a509c4ab0b7e1efbc7c1fdbacf849632f..55c1e096ab7bca2f7d81486f6fa690be62dda2ea 100644 (file)
@@ -2410,6 +2410,129 @@ TEST_F(TestMockIoObjectRequest, ListSnapsWholeObject) {
   }
 }
 
+TEST_F(TestMockIoObjectRequest, ListSnapsWholeObjectTruncate) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+  mock_image_ctx.snaps = {3};
+
+  InSequence seq;
+
+  librados::snap_set_t snap_set;
+  snap_set.seq = 3;
+  librados::clone_info_t clone_info;
+
+  clone_info.cloneid = 3;
+  clone_info.snaps = {3};
+  clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{
+    {2, mock_image_ctx.layout.object_size - 4}};
+  clone_info.size = mock_image_ctx.layout.object_size;
+  snap_set.clones.push_back(clone_info);
+
+  clone_info.cloneid = CEPH_NOSNAP;
+  clone_info.snaps = {};
+  clone_info.overlap = {};
+  clone_info.size = mock_image_ctx.layout.object_size - 2;
+  snap_set.clones.push_back(clone_info);
+
+  expect_list_snaps(mock_image_ctx, snap_set, 0);
+
+  {
+    SnapshotDelta snapshot_delta;
+    C_SaferCond ctx;
+    auto req = MockObjectListSnapsRequest::create(
+      &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}},
+      {3, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
+    req->send();
+    ASSERT_EQ(0, ctx.wait());
+
+    SnapshotDelta expected_snapshot_delta;
+    expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert(
+      1, 1, {SPARSE_EXTENT_STATE_DATA, 1});
+    expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert(
+      mock_image_ctx.layout.object_size - 2, 1,
+      {SPARSE_EXTENT_STATE_ZEROED, 1});
+    EXPECT_EQ(expected_snapshot_delta, snapshot_delta);
+  }
+
+  expect_list_snaps(mock_image_ctx, snap_set, 0);
+
+  {
+    SnapshotDelta snapshot_delta;
+    C_SaferCond ctx;
+    auto req = MockObjectListSnapsRequest::create(
+      &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}},
+      {3, CEPH_NOSNAP}, LIST_SNAPS_FLAG_WHOLE_OBJECT, {}, &snapshot_delta,
+      &ctx);
+    req->send();
+    ASSERT_EQ(0, ctx.wait());
+
+    SnapshotDelta expected_snapshot_delta;
+    expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert(
+      1, mock_image_ctx.layout.object_size - 2,
+      {SPARSE_EXTENT_STATE_DATA, mock_image_ctx.layout.object_size - 2});
+    EXPECT_EQ(expected_snapshot_delta, snapshot_delta);
+  }
+}
+
+TEST_F(TestMockIoObjectRequest, ListSnapsWholeObjectRemove) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+  mock_image_ctx.snaps = {3};
+
+  InSequence seq;
+
+  librados::snap_set_t snap_set;
+  snap_set.seq = 3;
+  librados::clone_info_t clone_info;
+
+  clone_info.cloneid = 3;
+  clone_info.snaps = {3};
+  clone_info.overlap = {};
+  clone_info.size = mock_image_ctx.layout.object_size - 2;
+  snap_set.clones.push_back(clone_info);
+
+  expect_list_snaps(mock_image_ctx, snap_set, 0);
+
+  {
+    SnapshotDelta snapshot_delta;
+    C_SaferCond ctx;
+    auto req = MockObjectListSnapsRequest::create(
+      &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}},
+      {3, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
+    req->send();
+    ASSERT_EQ(0, ctx.wait());
+
+    SnapshotDelta expected_snapshot_delta;
+    expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert(
+      1, mock_image_ctx.layout.object_size - 3,
+      {SPARSE_EXTENT_STATE_ZEROED, mock_image_ctx.layout.object_size - 3});
+    EXPECT_EQ(expected_snapshot_delta, snapshot_delta);
+  }
+
+  expect_list_snaps(mock_image_ctx, snap_set, 0);
+
+  {
+    SnapshotDelta snapshot_delta;
+    C_SaferCond ctx;
+    auto req = MockObjectListSnapsRequest::create(
+      &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}},
+      {3, CEPH_NOSNAP}, LIST_SNAPS_FLAG_WHOLE_OBJECT, {}, &snapshot_delta,
+      &ctx);
+    req->send();
+    ASSERT_EQ(0, ctx.wait());
+
+    SnapshotDelta expected_snapshot_delta;
+    expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert(
+      1, mock_image_ctx.layout.object_size - 2,
+      {SPARSE_EXTENT_STATE_ZEROED, mock_image_ctx.layout.object_size - 2});
+    EXPECT_EQ(expected_snapshot_delta, snapshot_delta);
+  }
+}
+
 TEST_F(TestMockIoObjectRequest, ListSnapsWholeObjectEndSize) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));