]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd/migration: prune snapshot extents in RawFormat::list_snaps()
authorIlya Dryomov <idryomov@gmail.com>
Sat, 31 Aug 2024 10:33:55 +0000 (12:33 +0200)
committerIlya Dryomov <idryomov@gmail.com>
Sun, 8 Sep 2024 20:03:57 +0000 (22:03 +0200)
list-snaps is exempt from clipping in ImageDispatcher::PreprocessVisitor
because it's considered to be an internal API.  Further, reads issued
by ObjectCopyRequest based on list-snaps results may also be exempt
because of READ_FLAG_DISABLE_CLIPPING.

Since RawFormat allows specifying a set of snapshots (possibly of
varying size!) to be imported, it needs to compensate for that in its
list-snaps implementation.  Otherwise, an out-of-bounds read will
eventually be submitted to the stream.

Fixes: https://tracker.ceph.com/issues/67845
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
(cherry picked from commit d9192b5aca156b706f14bd858df6fb3e45050079)

qa/workunits/rbd/cli_migration.sh
src/librbd/migration/RawFormat.cc
src/test/librbd/migration/test_mock_RawFormat.cc

index be8e031fd1bc8e12a399eec0073b536dc3aff450..3d598de5af73d61910fc23a6ef7dd3e907b3582c 100755 (executable)
@@ -25,7 +25,10 @@ cleanup_tempdir() {
 create_base_image() {
     local image=$1
 
-    rbd create --size 1G ${image}
+    # size is not a multiple of object size to trigger an edge case in
+    # list-snaps
+    rbd create --size 1025M ${image}
+
     rbd bench --io-type write --io-pattern rand --io-size=4K --io-total 256M ${image}
     rbd snap create ${image}@1
     rbd bench --io-type write --io-pattern rand --io-size=4K --io-total 64M ${image}
index 5feeb50e5e36bf243271dda300a92907fbaec91f..7f4c411ca03e5d9582462067f1bce976933d9792 100644 (file)
@@ -9,6 +9,7 @@
 #include "librbd/Utils.h"
 #include "librbd/io/AioCompletion.h"
 #include "librbd/io/ReadResult.h"
+#include "librbd/io/Utils.h"
 #include "librbd/migration/SnapshotInterface.h"
 #include "librbd/migration/SourceSpecBuilder.h"
 #include "librbd/migration/Utils.h"
@@ -209,7 +210,9 @@ void RawFormat<I>::list_snaps(io::Extents&& image_extents,
                                &previous_size, &sparse_extents);
 
     // build set of data/zeroed extents for the current snapshot
-    snapshot->list_snap(io::Extents{image_extents}, list_snaps_flags,
+    auto snapshot_extents = image_extents;
+    io::util::prune_extents(snapshot_extents, snap_info.size);
+    snapshot->list_snap(std::move(snapshot_extents), list_snaps_flags,
                         &sparse_extents, parent_trace, gather_ctx->new_sub());
   }
 
index 761e205bd1ee397a283858546d09b13ed4fb55a8..99210a66fa3bb52efaa40bc93abcc958cc3d12cb 100644 (file)
@@ -466,7 +466,7 @@ TEST_F(TestMockMigrationRawFormat, ListSnapsMerge) {
   expect_snapshot_get_info(*mock_snapshot_interface_2, snap_info_2);
   io::SparseExtents sparse_extents_2;
   sparse_extents_2.insert(0, 32, {io::SPARSE_EXTENT_STATE_DATA, 32});
-  expect_snapshot_list_snap(*mock_snapshot_interface_2, {{0, 123}},
+  expect_snapshot_list_snap(*mock_snapshot_interface_2, {{0, 64}},
                             sparse_extents_2, 0);
 
   expect_snapshot_get_info(*mock_snapshot_interface_head, snap_info_head);