From 39fea5e5d0abdef7b51dd25f17bfca95f13eb732 Mon Sep 17 00:00:00 2001 From: Gui Hecheng Date: Tue, 21 Feb 2017 22:44:39 +0800 Subject: [PATCH] test/librbd: add tests for rbd writesame Based on pr: https://github.com/ceph/ceph/pull/10019. Signed-off-by: Gui Hecheng Signed-off-by: Mingxin Liu --- src/test/librbd/io/test_mock_ImageRequest.cc | 45 +++ src/test/librbd/mock/cache/MockImageCache.h | 6 + src/test/librbd/test_librbd.cc | 304 +++++++++++++++++++ 3 files changed, 355 insertions(+) diff --git a/src/test/librbd/io/test_mock_ImageRequest.cc b/src/test/librbd/io/test_mock_ImageRequest.cc index b5950ce66a9d1..0c0acd9261957 100644 --- a/src/test/librbd/io/test_mock_ImageRequest.cc +++ b/src/test/librbd/io/test_mock_ImageRequest.cc @@ -78,6 +78,19 @@ struct ObjectRequest : public ObjectRequestHandle { return s_instance; } + static ObjectRequest* create_writesame(librbd::MockTestImageCtx *ictx, + const std::string &oid, + uint64_t object_no, + uint64_t object_off, + uint64_t object_len, + const ceph::bufferlist &data, + const ::SnapContext &snapc, + Context *completion, int op_flags) { + assert(s_instance != nullptr); + s_instance->on_finish = completion; + return s_instance; + } + ObjectRequest() { assert(s_instance == nullptr); s_instance = this; @@ -146,6 +159,7 @@ struct TestMockIoImageRequest : public TestMockFixture { typedef ImageWriteRequest MockImageWriteRequest; typedef ImageDiscardRequest MockImageDiscardRequest; typedef ImageFlushRequest MockImageFlushRequest; + typedef ImageWriteSameRequest MockImageWriteSameRequest; typedef ObjectRequest MockObjectRequest; typedef ObjectReadRequest MockObjectReadRequest; @@ -266,5 +280,36 @@ TEST_F(TestMockIoImageRequest, AioFlushJournalAppendDisabled) { ASSERT_EQ(0, aio_comp_ctx.wait()); } +TEST_F(TestMockIoImageRequest, AioWriteSameJournalAppendDisabled) { + REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockObjectRequest mock_aio_object_request; + MockTestImageCtx mock_image_ctx(*ictx); + MockJournal mock_journal; + mock_image_ctx.journal = &mock_journal; + + InSequence seq; + expect_is_journal_appending(mock_journal, false); + expect_write_to_cache(mock_image_ctx, ictx->get_object_name(0), + 0, 1, 0, 0); + + C_SaferCond aio_comp_ctx; + AioCompletion *aio_comp = AioCompletion::create_and_start( + &aio_comp_ctx, ictx, AIO_TYPE_WRITESAME); + + bufferlist bl; + bl.append("1"); + MockImageWriteSameRequest mock_aio_image_writesame(mock_image_ctx, aio_comp, + 0, 1, std::move(bl), 0); + { + RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); + mock_aio_image_writesame.send(); + } + ASSERT_EQ(0, aio_comp_ctx.wait()); +} + } // namespace io } // namespace librbd diff --git a/src/test/librbd/mock/cache/MockImageCache.h b/src/test/librbd/mock/cache/MockImageCache.h index 6dd9f57c84232..36ce5b71a7c85 100644 --- a/src/test/librbd/mock/cache/MockImageCache.h +++ b/src/test/librbd/mock/cache/MockImageCache.h @@ -30,6 +30,12 @@ struct MockImageCache { MOCK_METHOD3(aio_discard, void(uint64_t, uint64_t, Context *)); MOCK_METHOD1(aio_flush, void(Context *)); + MOCK_METHOD5(aio_writesame_mock, void(uint64_t, uint64_t, ceph::bufferlist& bl, + int, Context *)); + void aio_writesame(uint64_t off, uint64_t len, ceph::bufferlist&& bl, + int fadvise_flags, Context *on_finish) { + aio_writesame_mock(off, len, bl, fadvise_flags, on_finish); + } }; } // namespace cache diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 320170b3a59cd..f50cdceecef8b 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -1362,6 +1362,94 @@ void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_ *passed = true; } +void aio_writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len, + uint64_t data_len, uint32_t iohint, bool *passed) +{ + rbd_completion_t comp; + rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp); + printf("created completion\n"); + int r; + r = rbd_aio_writesame(image, off, len, test_data, data_len, comp, iohint); + printf("started writesame\n"); + if (len % data_len) { + ASSERT_EQ(-EINVAL, r); + printf("expected fail, finished writesame\n"); + rbd_aio_release(comp); + *passed = true; + return; + } + + rbd_aio_wait_for_complete(comp); + r = rbd_aio_get_return_value(comp); + printf("return value is: %d\n", r); + ASSERT_EQ(0, r); + printf("finished writesame\n"); + rbd_aio_release(comp); + + //verify data + printf("to verify the data\n"); + ssize_t read; + char *result = (char *)malloc(data_len+ 1); + ASSERT_NE(static_cast(NULL), result); + uint64_t left = len; + while (left > 0) { + read = rbd_read(image, off, data_len, result); + ASSERT_EQ(data_len, static_cast(read)); + result[data_len] = '\0'; + if (memcmp(result, test_data, data_len)) { + printf("read: %d ~ %d\n", (int) off, (int) read); + printf("read: %s\nexpected: %s\n", result, test_data); + ASSERT_EQ(0, memcmp(result, test_data, data_len)); + } + off += data_len; + left -= data_len; + } + ASSERT_EQ(0, left); + free(result); + printf("verified\n"); + + *passed = true; +} + +void writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len, + uint64_t data_len, uint32_t iohint, bool *passed) +{ + ssize_t written; + written = rbd_writesame(image, off, len, test_data, data_len, iohint); + if (len % data_len) { + ASSERT_EQ(-EINVAL, written); + printf("expected fail, finished writesame\n"); + *passed = true; + return; + } + ASSERT_EQ(len, static_cast(written)); + printf("wrote: %d\n", (int) written); + + //verify data + printf("to verify the data\n"); + ssize_t read; + char *result = (char *)malloc(data_len+ 1); + ASSERT_NE(static_cast(NULL), result); + uint64_t left = len; + while (left > 0) { + read = rbd_read(image, off, data_len, result); + ASSERT_EQ(data_len, static_cast(read)); + result[data_len] = '\0'; + if (memcmp(result, test_data, data_len)) { + printf("read: %d ~ %d\n", (int) off, (int) read); + printf("read: %s\nexpected: %s\n", result, test_data); + ASSERT_EQ(0, memcmp(result, test_data, data_len)); + } + off += data_len; + left -= data_len; + } + ASSERT_EQ(0, left); + free(result); + printf("verified\n"); + + *passed = true; +} + TEST_F(TestLibRBD, TestIO) { rados_ioctx_t ioctx; @@ -1411,6 +1499,31 @@ TEST_F(TestLibRBD, TestIO) TEST_IO_SIZE*3, TEST_IO_SIZE, 0); ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0); + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + } else if (i % 3 == 1) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } else { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } + } + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + } else if (i % 3 == 1) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } else { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } + } + rbd_image_info_t info; rbd_completion_t comp; ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); @@ -1497,6 +1610,43 @@ TEST_F(TestLibRBD, TestIOWithIOHint) LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL); ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0); + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + } else if (i % 3 == 1) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + } else { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + } + } + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + } else if (i % 3 == 1) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + } else { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, + TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + } + } + rbd_image_info_t info; rbd_completion_t comp; ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); @@ -1825,6 +1975,96 @@ void read_test_data(librbd::Image& image, const char *expected, off_t off, size_ *passed = true; } +void aio_writesame_test_data(librbd::Image& image, const char *test_data, off_t off, + size_t len, size_t data_len, uint32_t iohint, bool *passed) +{ + ceph::bufferlist bl; + bl.append(test_data, data_len); + librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp); + printf("created completion\n"); + int r; + r = image.aio_writesame(off, len, bl, comp, iohint); + printf("started writesame\n"); + if (len % data_len) { + ASSERT_EQ(-EINVAL, r); + printf("expected fail, finished writesame\n"); + comp->release(); + *passed = true; + return; + } + + comp->wait_for_complete(); + r = comp->get_return_value(); + printf("return value is: %d\n", r); + ASSERT_EQ(0, r); + printf("finished writesame\n"); + comp->release(); + + //verify data + printf("to verify the data\n"); + int read; + uint64_t left = len; + while (left > 0) { + ceph::bufferlist bl; + read = image.read(off, data_len, bl); + ASSERT_EQ(data_len, static_cast(read)); + std::string bl_str(bl.c_str(), read); + int result = memcmp(bl_str.c_str(), test_data, data_len); + if (result !=0 ) { + printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read); + printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data); + ASSERT_EQ(0, result); + } + off += data_len; + left -= data_len; + } + ASSERT_EQ(0, left); + printf("verified\n"); + + *passed = true; +} + +void writesame_test_data(librbd::Image& image, const char *test_data, off_t off, size_t len, + size_t data_len, uint32_t iohint, bool *passed) +{ + ssize_t written; + ceph::bufferlist bl; + bl.append(test_data, data_len); + written = image.writesame(off, len, bl, iohint); + if (len % data_len) { + ASSERT_EQ(-EINVAL, written); + printf("expected fail, finished writesame\n"); + *passed = true; + return; + } + ASSERT_EQ(len, written); + printf("wrote: %u\n", (unsigned int) written); + *passed = true; + + //verify data + printf("to verify the data\n"); + int read; + uint64_t left = len; + while (left > 0) { + ceph::bufferlist bl; + read = image.read(off, data_len, bl); + ASSERT_EQ(data_len, static_cast(read)); + std::string bl_str(bl.c_str(), read); + int result = memcmp(bl_str.c_str(), test_data, data_len); + if (result !=0 ) { + printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read); + printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data); + ASSERT_EQ(0, result); + } + off += data_len; + left -= data_len; + } + ASSERT_EQ(0, left); + printf("verified\n"); + + *passed = true; +} + TEST_F(TestLibRBD, TestIOPP) { librados::IoCtx ioctx; @@ -1876,6 +2116,31 @@ TEST_F(TestLibRBD, TestIOPP) TEST_IO_SIZE*3, TEST_IO_SIZE, 0); ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0); + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + } else if (i % 3 == 1) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } else { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } + } + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0); + } else if (i % 3 == 1) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } else { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0); + } + } + ASSERT_PASSED(validate_object_map, image); } @@ -1898,12 +2163,14 @@ TEST_F(TestLibRBD, TestIOPPWithIOHint) ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); char test_data[TEST_IO_SIZE + 1]; + char zero_data[TEST_IO_SIZE + 1]; test_data[TEST_IO_SIZE] = '\0'; int i; for (i = 0; i < TEST_IO_SIZE; ++i) { test_data[i] = (char) (rand() % (126 - 33) + 33); } + memset(zero_data, 0, sizeof(zero_data)); for (i = 0; i < 5; ++i) ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i, @@ -1920,6 +2187,43 @@ TEST_F(TestLibRBD, TestIOPPWithIOHint) ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + } else if (i % 3 == 1) { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + } else { + ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); + } + } + for (i = 0; i < 15; ++i) { + if (i % 3 == 2) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + } else if (i % 3 == 1) { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + } else { + ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, + TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + } + } + ASSERT_PASSED(validate_object_map, image); } -- 2.39.5