From d9192b5aca156b706f14bd858df6fb3e45050079 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Sat, 31 Aug 2024 12:33:55 +0200 Subject: [PATCH] librbd/migration: prune snapshot extents in RawFormat::list_snaps() 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 --- qa/workunits/rbd/cli_migration.sh | 5 ++++- src/librbd/migration/RawFormat.cc | 5 ++++- src/test/librbd/migration/test_mock_RawFormat.cc | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/qa/workunits/rbd/cli_migration.sh b/qa/workunits/rbd/cli_migration.sh index 5a7bb41376e..3d3321bc07e 100755 --- a/qa/workunits/rbd/cli_migration.sh +++ b/qa/workunits/rbd/cli_migration.sh @@ -27,7 +27,10 @@ expect_false() { 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} diff --git a/src/librbd/migration/RawFormat.cc b/src/librbd/migration/RawFormat.cc index 5feeb50e5e3..7f4c411ca03 100644 --- a/src/librbd/migration/RawFormat.cc +++ b/src/librbd/migration/RawFormat.cc @@ -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::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()); } diff --git a/src/test/librbd/migration/test_mock_RawFormat.cc b/src/test/librbd/migration/test_mock_RawFormat.cc index 761e205bd1e..99210a66fa3 100644 --- a/src/test/librbd/migration/test_mock_RawFormat.cc +++ b/src/test/librbd/migration/test_mock_RawFormat.cc @@ -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); -- 2.39.5