From b508f64aa492c26c63323d30a7002b48187db19b Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 4 Jan 2022 20:38:35 +0100 Subject: [PATCH] librbd: diff-iterate reports incorrect offsets in fast-diff mode If rbd_diff_iterate2() is called on an image offset that doesn't correspond to an object boundary, the callback is invoked with an incorrect image offset. For example, assuming a fully allocated image, a diff request for 806354944~57344 results in offs=807403520, len=57344, exists=true invocation, which is ahead by 1048576 bytes. This occurs only in fast-diff mode, for a diff request on an image with the fast-diff feature disabled or if whole_object parameter is set to false the invocation is correct. This bug goes back to the introduction of fast-diff mode in commit 6d5b969d4206 ("librbd: add diff_iterate2 to API"). Fixes: https://tracker.ceph.com/issues/53784 Signed-off-by: Ilya Dryomov (cherry picked from commit ea07d1e834018c693fc03637d338806f3c2f494f) Conflicts: src/librbd/api/DiffIterate.cc Cherry-pick notes: - Octopus still has explicit iterator syntax in for loop for extents --- src/librbd/api/DiffIterate.cc | 9 +++-- src/test/librbd/test_librbd.cc | 66 ++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/librbd/api/DiffIterate.cc b/src/librbd/api/DiffIterate.cc index 527193b90533c..4318116732dfc 100644 --- a/src/librbd/api/DiffIterate.cc +++ b/src/librbd/api/DiffIterate.cc @@ -399,9 +399,12 @@ int DiffIterate::execute() { bool updated = (diff_state == object_map::DIFF_STATE_DATA_UPDATED); for (std::vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { - r = m_callback(off + q->offset, q->length, updated, m_callback_arg); - if (r < 0) { - return r; + for (auto& be : q->buffer_extents) { + r = m_callback(off + be.first, be.second, updated, + m_callback_arg); + if (r < 0) { + return r; + } } } } diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 7937dd95d6643..ec6108fd021a5 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -4345,6 +4345,72 @@ TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard) ASSERT_TRUE(two.subset_of(diff)); } +TYPED_TEST(DiffIterateTest, DiffIterateUnalignedSmall) +{ + librados::IoCtx ioctx; + ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + + { + librbd::RBD rbd; + librbd::Image image; + int order = 0; + std::string name = this->get_temp_image_name(); + ssize_t size = 10 << 20; + + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); + ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); + + ceph::bufferlist bl; + bl.append(std::string(size, '1')); + ASSERT_EQ(size, image.write(0, size, bl)); + + std::vector extents; + ASSERT_EQ(0, image.diff_iterate2(NULL, 5000005, 1234, true, + this->whole_object, vector_iterate_cb, + &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(5000005, 1234, true, 0), extents[0]); + + ASSERT_PASSED(this->validate_object_map, image); + } + + ioctx.close(); +} + +TYPED_TEST(DiffIterateTest, DiffIterateUnaligned) +{ + librados::IoCtx ioctx; + ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + + { + librbd::RBD rbd; + librbd::Image image; + int order = 22; + std::string name = this->get_temp_image_name(); + ssize_t size = 20 << 20; + + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); + ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); + + ceph::bufferlist bl; + bl.append(std::string(size, '1')); + ASSERT_EQ(size, image.write(0, size, bl)); + + std::vector extents; + ASSERT_EQ(0, image.diff_iterate2(NULL, 8376263, 4260970, true, + this->whole_object, vector_iterate_cb, + &extents)); + ASSERT_EQ(3u, extents.size()); + ASSERT_EQ(diff_extent(8376263, 12345, true, 0), extents[0]); + ASSERT_EQ(diff_extent(8388608, 4194304, true, 0), extents[1]); + ASSERT_EQ(diff_extent(12582912, 54321, true, 0), extents[2]); + + ASSERT_PASSED(this->validate_object_map, image); + } + + ioctx.close(); +} + TEST_F(TestLibRBD, ZeroLengthWrite) { rados_ioctx_t ioctx; -- 2.39.5