diff options
Diffstat (limited to 'src/test/librbd/test_DeepCopy.cc')
-rw-r--r-- | src/test/librbd/test_DeepCopy.cc | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/src/test/librbd/test_DeepCopy.cc b/src/test/librbd/test_DeepCopy.cc new file mode 100644 index 000000000..fcce0c642 --- /dev/null +++ b/src/test/librbd/test_DeepCopy.cc @@ -0,0 +1,763 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/librbd/test_fixture.h" +#include "test/librbd/test_support.h" +#include "librbd/Operations.h" +#include "librbd/api/Io.h" +#include "librbd/api/Image.h" +#include "librbd/api/Snapshot.h" +#include "librbd/internal.h" +#include "librbd/io/ReadResult.h" +#include "test/librados/crimson_utils.h" + +void register_test_deep_copy() { +} + +namespace librbd { + +struct TestDeepCopy : public TestFixture { + void SetUp() override { + TestFixture::SetUp(); + + std::string image_name = get_temp_image_name(); + int order = 22; + uint64_t size = (1 << order) * 20; + uint64_t features = 0; + bool old_format = !::get_features(&features); + EXPECT_EQ(0, create_image_full_pp(m_rbd, m_ioctx, image_name, size, + features, old_format, &order)); + ASSERT_EQ(0, open_image(image_name, &m_src_ictx)); + + if (old_format) { + // The destination should always be in the new format. + uint64_t format = 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FORMAT, format)); + } + } + + void TearDown() override { + if (m_src_ictx != nullptr) { + deep_copy(); + if (m_dst_ictx != nullptr) { + compare(); + close_image(m_dst_ictx); + } + close_image(m_src_ictx); + } + + TestFixture::TearDown(); + } + + void deep_copy() { + std::string dst_name = get_temp_image_name(); + librbd::NoOpProgressContext no_op; + EXPECT_EQ(0, api::Io<>::flush(*m_src_ictx)); + EXPECT_EQ(0, librbd::api::Image<>::deep_copy(m_src_ictx, m_src_ictx->md_ctx, + dst_name.c_str(), m_opts, + no_op)); + EXPECT_EQ(0, open_image(dst_name, &m_dst_ictx)); + } + + void compare() { + std::vector<librbd::snap_info_t> src_snaps, dst_snaps; + + EXPECT_EQ(m_src_ictx->size, m_dst_ictx->size); + EXPECT_EQ(0, librbd::api::Snapshot<>::list(m_src_ictx, src_snaps)); + EXPECT_EQ(0, librbd::api::Snapshot<>::list(m_dst_ictx, dst_snaps)); + EXPECT_EQ(src_snaps.size(), dst_snaps.size()); + for (size_t i = 0; i <= src_snaps.size(); i++) { + const char *src_snap_name = nullptr; + const char *dst_snap_name = nullptr; + if (i < src_snaps.size()) { + EXPECT_EQ(src_snaps[i].name, dst_snaps[i].name); + src_snap_name = src_snaps[i].name.c_str(); + dst_snap_name = dst_snaps[i].name.c_str(); + } + EXPECT_EQ(0, librbd::api::Image<>::snap_set( + m_src_ictx, cls::rbd::UserSnapshotNamespace(), + src_snap_name)); + EXPECT_EQ(0, librbd::api::Image<>::snap_set( + m_dst_ictx, cls::rbd::UserSnapshotNamespace(), + dst_snap_name)); + uint64_t src_size, dst_size; + { + std::shared_lock src_locker{m_src_ictx->image_lock}; + std::shared_lock dst_locker{m_dst_ictx->image_lock}; + src_size = m_src_ictx->get_image_size(m_src_ictx->snap_id); + dst_size = m_dst_ictx->get_image_size(m_dst_ictx->snap_id); + } + EXPECT_EQ(src_size, dst_size); + + if (m_dst_ictx->test_features(RBD_FEATURE_LAYERING)) { + bool flags_set; + std::shared_lock dst_locker{m_dst_ictx->image_lock}; + EXPECT_EQ(0, m_dst_ictx->test_flags(m_dst_ictx->snap_id, + RBD_FLAG_OBJECT_MAP_INVALID, + m_dst_ictx->image_lock, &flags_set)); + EXPECT_FALSE(flags_set); + } + + ssize_t read_size = 1 << m_src_ictx->order; + uint64_t offset = 0; + while (offset < src_size) { + read_size = std::min(read_size, static_cast<ssize_t>(src_size - offset)); + + bufferptr src_ptr(read_size); + bufferlist src_bl; + src_bl.push_back(src_ptr); + librbd::io::ReadResult src_result{&src_bl}; + EXPECT_EQ(read_size, api::Io<>::read( + *m_src_ictx, offset, read_size, + librbd::io::ReadResult{src_result}, 0)); + + bufferptr dst_ptr(read_size); + bufferlist dst_bl; + dst_bl.push_back(dst_ptr); + librbd::io::ReadResult dst_result{&dst_bl}; + EXPECT_EQ(read_size, api::Io<>::read( + *m_dst_ictx, offset, read_size, + librbd::io::ReadResult{dst_result}, 0)); + + if (!src_bl.contents_equal(dst_bl)) { + std::cout << "snap: " << (src_snap_name ? src_snap_name : "null") + << ", block " << offset << "~" << read_size << " differs" + << std::endl; + std::cout << "src block: " << std::endl; src_bl.hexdump(std::cout); + std::cout << "dst block: " << std::endl; dst_bl.hexdump(std::cout); + } + EXPECT_TRUE(src_bl.contents_equal(dst_bl)); + offset += read_size; + } + } + } + + void test_no_snaps() { + bufferlist bl; + bl.append(std::string(((1 << m_src_ictx->order) * 2) + 1, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 0 * bl.length(), bl.length(), + bufferlist{bl}, 0)); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 2 * bl.length(), bl.length(), + bufferlist{bl}, 0)); + } + + void test_snaps() { + bufferlist bl; + bl.append(std::string(((1 << m_src_ictx->order) * 2) + 1, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 0 * bl.length(), bl.length(), + bufferlist{bl}, 0)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap1")); + + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 1 * bl.length(), bl.length(), + bufferlist{bl}, 0)); + bufferlist bl1; + bl1.append(std::string(1000, 'X')); + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::write(*m_src_ictx, 0 * bl.length(), bl1.length(), + bufferlist{bl1}, 0)); + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::discard(*m_src_ictx, bl1.length() + 10, + bl1.length(), false)); + + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap2")); + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::write(*m_src_ictx, 1 * bl.length(), bl1.length(), + bufferlist{bl1}, 0)); + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::discard(*m_src_ictx, 2 * bl1.length() + 10, + bl1.length(), false)); + } + + void test_snap_discard() { + bufferlist bl; + bl.append(std::string(100, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 0, bl.length(), bufferlist{bl}, 0)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap")); + + size_t len = (1 << m_src_ictx->order) * 2; + ASSERT_EQ(static_cast<ssize_t>(len), + api::Io<>::discard(*m_src_ictx, 0, len, false)); + } + + void test_clone_discard() { + bufferlist bl; + bl.append(std::string(100, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 0, bl.length(), bufferlist{bl}, 0)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap")); + ASSERT_EQ(0, snap_protect(*m_src_ictx, "snap")); + + std::string clone_name = get_temp_image_name(); + int order = m_src_ictx->order; + uint64_t features; + ASSERT_EQ(0, librbd::get_features(m_src_ictx, &features)); + ASSERT_EQ(0, librbd::clone(m_ioctx, m_src_ictx->name.c_str(), "snap", + m_ioctx, clone_name.c_str(), features, &order, 0, + 0)); + close_image(m_src_ictx); + ASSERT_EQ(0, open_image(clone_name, &m_src_ictx)); + + size_t len = (1 << m_src_ictx->order) * 2; + ASSERT_EQ(static_cast<ssize_t>(len), + api::Io<>::discard(*m_src_ictx, 0, len, false)); + } + + void test_clone_shrink() { + bufferlist bl; + bl.append(std::string(100, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 0, bl.length(), bufferlist{bl}, 0)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap")); + ASSERT_EQ(0, snap_protect(*m_src_ictx, "snap")); + + std::string clone_name = get_temp_image_name(); + int order = m_src_ictx->order; + uint64_t features; + ASSERT_EQ(0, librbd::get_features(m_src_ictx, &features)); + ASSERT_EQ(0, librbd::clone(m_ioctx, m_src_ictx->name.c_str(), "snap", + m_ioctx, clone_name.c_str(), features, &order, 0, + 0)); + close_image(m_src_ictx); + ASSERT_EQ(0, open_image(clone_name, &m_src_ictx)); + + librbd::NoOpProgressContext no_op; + auto new_size = m_src_ictx->size >> 1; + ASSERT_EQ(0, m_src_ictx->operations->resize(new_size, true, no_op)); + } + + void test_clone_expand() { + bufferlist bl; + bl.append(std::string(100, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 0, bl.length(), bufferlist{bl}, 0)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap")); + ASSERT_EQ(0, snap_protect(*m_src_ictx, "snap")); + + std::string clone_name = get_temp_image_name(); + int order = m_src_ictx->order; + uint64_t features; + ASSERT_EQ(0, librbd::get_features(m_src_ictx, &features)); + ASSERT_EQ(0, librbd::clone(m_ioctx, m_src_ictx->name.c_str(), "snap", + m_ioctx, clone_name.c_str(), features, &order, 0, + 0)); + close_image(m_src_ictx); + ASSERT_EQ(0, open_image(clone_name, &m_src_ictx)); + + librbd::NoOpProgressContext no_op; + auto new_size = m_src_ictx->size << 1; + ASSERT_EQ(0, m_src_ictx->operations->resize(new_size, true, no_op)); + } + + void test_clone_hide_parent() { + uint64_t object_size = 1 << m_src_ictx->order; + bufferlist bl; + bl.append(std::string(100, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, object_size, bl.length(), + bufferlist{bl}, 0)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap")); + ASSERT_EQ(0, snap_protect(*m_src_ictx, "snap")); + + std::string clone_name = get_temp_image_name(); + int order = m_src_ictx->order; + uint64_t features; + ASSERT_EQ(0, librbd::get_features(m_src_ictx, &features)); + ASSERT_EQ(0, librbd::clone(m_ioctx, m_src_ictx->name.c_str(), "snap", + m_ioctx, clone_name.c_str(), features, &order, 0, + 0)); + close_image(m_src_ictx); + ASSERT_EQ(0, open_image(clone_name, &m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap1")); + + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::discard(*m_src_ictx, object_size, bl.length(), false)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap2")); + + librbd::NoOpProgressContext no_op; + ASSERT_EQ(0, m_src_ictx->operations->resize(object_size, true, no_op)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap3")); + + ASSERT_EQ(0, m_src_ictx->operations->resize(2 * object_size, true, no_op)); + } + + void test_clone() { + bufferlist bl; + bl.append(std::string(((1 << m_src_ictx->order) * 2) + 1, '1')); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 0 * bl.length(), bl.length(), + bufferlist{bl}, 0)); + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, 2 * bl.length(), bl.length(), + bufferlist{bl}, 0)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap")); + ASSERT_EQ(0, snap_protect(*m_src_ictx, "snap")); + + std::string clone_name = get_temp_image_name(); + int order = m_src_ictx->order; + uint64_t features; + ASSERT_EQ(0, librbd::get_features(m_src_ictx, &features)); + ASSERT_EQ(0, librbd::clone(m_ioctx, m_src_ictx->name.c_str(), "snap", + m_ioctx, clone_name.c_str(), features, &order, 0, + 0)); + close_image(m_src_ictx); + ASSERT_EQ(0, open_image(clone_name, &m_src_ictx)); + + bufferlist bl1; + bl1.append(std::string(1000, 'X')); + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::write(*m_src_ictx, 0 * bl.length(), bl1.length(), + bufferlist{bl1}, 0)); + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::discard(*m_src_ictx, bl1.length() + 10, + bl1.length(), false)); + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + ASSERT_EQ(0, snap_create(*m_src_ictx, "snap")); + ASSERT_EQ(0, snap_protect(*m_src_ictx, "snap")); + + clone_name = get_temp_image_name(); + ASSERT_EQ(0, librbd::clone(m_ioctx, m_src_ictx->name.c_str(), "snap", + m_ioctx, clone_name.c_str(), features, &order, 0, + 0)); + close_image(m_src_ictx); + ASSERT_EQ(0, open_image(clone_name, &m_src_ictx)); + + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::write(*m_src_ictx, 1 * bl.length(), bl1.length(), + bufferlist{bl1}, 0)); + ASSERT_EQ(static_cast<ssize_t>(bl1.length()), + api::Io<>::discard(*m_src_ictx, 2 * bl1.length() + 10, + bl1.length(), false)); + } + + void test_stress() { + uint64_t initial_size, size; + { + std::shared_lock src_locker{m_src_ictx->image_lock}; + size = initial_size = m_src_ictx->get_image_size(CEPH_NOSNAP); + } + + int nsnaps = 4; + const char *c = getenv("TEST_RBD_DEEPCOPY_STRESS_NSNAPS"); + if (c != NULL) { + std::stringstream ss(c); + ASSERT_TRUE(ss >> nsnaps); + } + + int nwrites = 4; + c = getenv("TEST_RBD_DEEPCOPY_STRESS_NWRITES"); + if (c != NULL) { + std::stringstream ss(c); + ASSERT_TRUE(ss >> nwrites); + } + + for (int i = 0; i < nsnaps; i++) { + for (int j = 0; j < nwrites; j++) { + size_t len = rand() % ((1 << m_src_ictx->order) * 2); + ASSERT_GT(size, len); + bufferlist bl; + bl.append(std::string(len, static_cast<char>('A' + i))); + uint64_t off = std::min(static_cast<uint64_t>(rand() % size), + static_cast<uint64_t>(size - len)); + std::cout << "write: " << static_cast<char>('A' + i) << " " << off + << "~" << len << std::endl; + ASSERT_EQ(static_cast<ssize_t>(bl.length()), + api::Io<>::write(*m_src_ictx, off, bl.length(), + bufferlist{bl}, 0)); + len = rand() % ((1 << m_src_ictx->order) * 2); + ASSERT_GT(size, len); + off = std::min(static_cast<uint64_t>(rand() % size), + static_cast<uint64_t>(size - len)); + std::cout << "discard: " << off << "~" << len << std::endl; + ASSERT_EQ(static_cast<ssize_t>(len), + api::Io<>::discard(*m_src_ictx, off, len, false)); + } + + ASSERT_EQ(0, api::Io<>::flush(*m_src_ictx)); + + std::string snap_name = "snap" + stringify(i); + std::cout << "snap: " << snap_name << std::endl; + ASSERT_EQ(0, snap_create(*m_src_ictx, snap_name.c_str())); + + if (m_src_ictx->test_features(RBD_FEATURE_LAYERING) && rand() % 4) { + ASSERT_EQ(0, snap_protect(*m_src_ictx, snap_name.c_str())); + + std::string clone_name = get_temp_image_name(); + int order = m_src_ictx->order; + uint64_t features; + ASSERT_EQ(0, librbd::get_features(m_src_ictx, &features)); + + std::cout << "clone " << m_src_ictx->name << " -> " << clone_name + << std::endl; + ASSERT_EQ(0, librbd::clone(m_ioctx, m_src_ictx->name.c_str(), + snap_name.c_str(), m_ioctx, + clone_name.c_str(), features, &order, + m_src_ictx->stripe_unit, + m_src_ictx->stripe_count)); + close_image(m_src_ictx); + ASSERT_EQ(0, open_image(clone_name, &m_src_ictx)); + } + + if (rand() % 2) { + librbd::NoOpProgressContext no_op; + uint64_t new_size = initial_size + rand() % size; + std::cout << "resize: " << new_size << std::endl; + ASSERT_EQ(0, m_src_ictx->operations->resize(new_size, true, no_op)); + { + std::shared_lock src_locker{m_src_ictx->image_lock}; + size = m_src_ictx->get_image_size(CEPH_NOSNAP); + } + ASSERT_EQ(new_size, size); + } + } + } + + librbd::ImageCtx *m_src_ictx = nullptr; + librbd::ImageCtx *m_dst_ictx = nullptr; + librbd::ImageOptions m_opts; +}; + +TEST_F(TestDeepCopy, Empty) +{ +} + +TEST_F(TestDeepCopy, NoSnaps) +{ + test_no_snaps(); +} + +TEST_F(TestDeepCopy, Snaps) +{ + test_snaps(); +} + +TEST_F(TestDeepCopy, SnapDiscard) +{ + test_snap_discard(); +} + +TEST_F(TestDeepCopy, CloneDiscard) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + test_clone_discard(); +} + +TEST_F(TestDeepCopy, CloneShrink) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + test_clone_shrink(); +} + +TEST_F(TestDeepCopy, CloneExpand) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + test_clone_expand(); +} + +TEST_F(TestDeepCopy, CloneHideParent) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + test_clone_hide_parent(); +} + +TEST_F(TestDeepCopy, Clone) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + test_clone(); +} + +TEST_F(TestDeepCopy, CloneFlatten) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + uint64_t flatten = 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten)); + + test_clone(); +} + +TEST_F(TestDeepCopy, Stress) +{ + test_stress(); +} + +TEST_F(TestDeepCopy, NoSnaps_LargerDstObjSize) +{ + SKIP_IF_CRIMSON(); + uint64_t order = m_src_ictx->order + 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + + test_no_snaps(); +} + +TEST_F(TestDeepCopy, Snaps_LargerDstObjSize) +{ + SKIP_IF_CRIMSON(); + uint64_t order = m_src_ictx->order + 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + + test_snaps(); +} + +TEST_F(TestDeepCopy, Clone_LargerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + uint64_t order = m_src_ictx->order + 1 + rand() % 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + + test_clone(); +} + +TEST_F(TestDeepCopy, CloneFlatten_LargerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + uint64_t order = m_src_ictx->order + 1 + rand() % 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + uint64_t flatten = 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten)); + + test_clone(); +} + +TEST_F(TestDeepCopy, Stress_LargerDstObjSize) +{ + SKIP_IF_CRIMSON(); + uint64_t order = m_src_ictx->order + 1 + rand() % 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + + test_stress(); +} + +TEST_F(TestDeepCopy, NoSnaps_SmallerDstObjSize) +{ + uint64_t order = m_src_ictx->order - 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + uint64_t stripe_unit = m_src_ictx->stripe_unit >> 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + + test_no_snaps(); +} + +TEST_F(TestDeepCopy, Snaps_SmallerDstObjSize) +{ + uint64_t order = m_src_ictx->order - 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + uint64_t stripe_unit = m_src_ictx->stripe_unit >> 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + + test_snaps(); +} + +TEST_F(TestDeepCopy, Clone_SmallerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + uint64_t order = m_src_ictx->order - 1 - rand() % 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + uint64_t stripe_unit = m_src_ictx->stripe_unit >> 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + + test_clone(); +} + +TEST_F(TestDeepCopy, CloneFlatten_SmallerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING); + + uint64_t order = m_src_ictx->order - 1 - rand() % 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + uint64_t stripe_unit = m_src_ictx->stripe_unit >> 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + uint64_t flatten = 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten)); + + test_clone(); +} + +TEST_F(TestDeepCopy, Stress_SmallerDstObjSize) +{ + uint64_t order = m_src_ictx->order - 1 - rand() % 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + uint64_t stripe_unit = m_src_ictx->stripe_unit >> 2; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + + test_stress(); +} + +TEST_F(TestDeepCopy, NoSnaps_StrippingLargerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order + 1; + uint64_t stripe_unit = 1 << (order - 2); + uint64_t stripe_count = 4; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_no_snaps(); +} + +TEST_F(TestDeepCopy, Snaps_StrippingLargerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order + 1; + uint64_t stripe_unit = 1 << (order - 2); + uint64_t stripe_count = 4; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_snaps(); +} + +TEST_F(TestDeepCopy, Clone_StrippingLargerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order + 1; + uint64_t stripe_unit = 1 << (order - 2); + uint64_t stripe_count = 4; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_clone(); +} + +TEST_F(TestDeepCopy, CloneFlatten_StrippingLargerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order + 1; + uint64_t stripe_unit = 1 << (order - 2); + uint64_t stripe_count = 4; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + uint64_t flatten = 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten)); + + test_clone(); +} + +TEST_F(TestDeepCopy, Stress_StrippingLargerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order + 1 + rand() % 2; + uint64_t stripe_unit = 1 << (order - rand() % 4); + uint64_t stripe_count = 2 + rand() % 14; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_stress(); +} + +TEST_F(TestDeepCopy, NoSnaps_StrippingSmallerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order - 1; + uint64_t stripe_unit = 1 << (order - 2); + uint64_t stripe_count = 4; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_no_snaps(); +} + +TEST_F(TestDeepCopy, Snaps_StrippingSmallerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order - 1; + uint64_t stripe_unit = 1 << (order - 2); + uint64_t stripe_count = 4; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_snaps(); +} + +TEST_F(TestDeepCopy, Clone_StrippingSmallerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order - 1 - rand() % 2; + uint64_t stripe_unit = 1 << (order - rand() % 4); + uint64_t stripe_count = 2 + rand() % 14; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_clone(); +} + +TEST_F(TestDeepCopy, CloneFlatten_StrippingSmallerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order - 1 - rand() % 2; + uint64_t stripe_unit = 1 << (order - rand() % 4); + uint64_t stripe_count = 2 + rand() % 14; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + uint64_t flatten = 1; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FLATTEN, flatten)); + + test_clone(); +} + +TEST_F(TestDeepCopy, Stress_StrippingSmallerDstObjSize) +{ + REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2); + + uint64_t order = m_src_ictx->order - 1 - rand() % 2; + uint64_t stripe_unit = 1 << (order - rand() % 4); + uint64_t stripe_count = 2 + rand() % 14; + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_ORDER, order)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit)); + ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count)); + + test_stress(); +} + +} // namespace librbd |