diff options
author | Or Ozeri <oro@il.ibm.com> | 2020-10-29 12:42:17 +0100 |
---|---|---|
committer | Or Ozeri <oro@il.ibm.com> | 2020-11-04 09:25:45 +0100 |
commit | 27c24d39ed00ea2273dce59d56c3540c93be2a4f (patch) | |
tree | b636c0d68c0d7b3a69c2eef6361f5a1a70532ee4 /src/test/librbd/crypto | |
parent | Merge pull request #37757 from votdev/issue_47884_display_time (diff) | |
download | ceph-27c24d39ed00ea2273dce59d56c3540c93be2a4f.tar.xz ceph-27c24d39ed00ea2273dce59d56c3540c93be2a4f.zip |
librbd: wait for copyup in unaligned crypto write
librbd copyup is not built to handle unaligned encrypted writes.
Therefore, a such write should kick-off a copyup and wait for it to complete before executing.
This commit implements this logic.
Signed-off-by: Or Ozeri <oro@il.ibm.com>
Diffstat (limited to 'src/test/librbd/crypto')
-rw-r--r-- | src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc | 123 |
1 files changed, 121 insertions, 2 deletions
diff --git a/src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc b/src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc index 181cc2caf94..805a83d75bd 100644 --- a/src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc +++ b/src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc @@ -4,11 +4,21 @@ #include "test/librbd/test_mock_fixture.h" #include "test/librbd/test_support.h" #include "test/librbd/mock/MockImageCtx.h" +#include "test/librbd/mock/MockObjectMap.h" #include "test/librbd/mock/crypto/MockCryptoInterface.h" #include "librbd/crypto/CryptoObjectDispatch.h" #include "librbd/io/ObjectDispatchSpec.h" #include "librbd/io/Utils.h" +#include "librbd/io/Utils.cc" +template bool librbd::io::util::trigger_copyup( + MockImageCtx *image_ctx, uint64_t object_no, IOContext io_context, + Context* on_finish); + +#include "librbd/io/ObjectRequest.cc" +template class librbd::io::ObjectWriteRequest<librbd::MockImageCtx>; +template class librbd::io::AbstractObjectWriteRequest<librbd::MockImageCtx>; + namespace librbd { namespace util { @@ -20,6 +30,29 @@ inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) { } // namespace util namespace io { + +template <> +struct CopyupRequest<librbd::MockImageCtx> { + MOCK_METHOD0(send, void()); + MOCK_METHOD2(append_request, void( + AbstractObjectWriteRequest<librbd::MockImageCtx>*, + const Extents&)); + + static CopyupRequest* s_instance; + static CopyupRequest* create(librbd::MockImageCtx *ictx, + uint64_t objectno, Extents &&image_extents, + const ZTracer::Trace &parent_trace) { + return s_instance; + } + + CopyupRequest() { + s_instance = this; + } +}; + +CopyupRequest<librbd::MockImageCtx>* CopyupRequest< + librbd::MockImageCtx>::s_instance = nullptr; + namespace util { namespace { @@ -63,10 +96,14 @@ using ::testing::_; using ::testing::ElementsAre; using ::testing::Invoke; using ::testing::Pair; +using ::testing::Return; using ::testing::WithArg; struct TestMockCryptoCryptoObjectDispatch : public TestMockFixture { typedef CryptoObjectDispatch<librbd::MockImageCtx> MockCryptoObjectDispatch; + typedef io::AbstractObjectWriteRequest<librbd::MockImageCtx> + MockAbstractObjectWriteRequest; + typedef io::CopyupRequest<librbd::MockImageCtx> MockCopyupRequest; typedef io::util::Mock MockUtils; MockCryptoInterface* crypto; @@ -83,6 +120,7 @@ struct TestMockCryptoCryptoObjectDispatch : public TestMockFixture { io::Extents extent_map; int object_dispatch_flags = 0; MockUtils mock_utils; + MockCopyupRequest copyup_request; void SetUp() override { TestMockFixture::SetUp(); @@ -91,7 +129,8 @@ struct TestMockCryptoCryptoObjectDispatch : public TestMockFixture { ASSERT_EQ(0, open_image(m_image_name, &ictx)); crypto = new MockCryptoInterface(); mock_image_ctx = new MockImageCtx(*ictx); - mock_crypto_object_dispatch = new MockCryptoObjectDispatch(mock_image_ctx, crypto); + mock_crypto_object_dispatch = new MockCryptoObjectDispatch( + mock_image_ctx, crypto); data.append(std::string(4096, '1')); } @@ -136,7 +175,8 @@ struct TestMockCryptoCryptoObjectDispatch : public TestMockFixture { int r) { EXPECT_CALL(mock_utils, read_parent(_, object_no, extents, snap_id, _, _)) - .WillOnce(WithArg<5>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr)))); + .WillOnce(WithArg<5>(CompleteContext( + r, static_cast<asio::ContextWQ*>(nullptr)))); } void expect_object_write(uint64_t object_off, const std::string& data, @@ -172,6 +212,37 @@ struct TestMockCryptoCryptoObjectDispatch : public TestMockFixture { })); } + void expect_get_object_size() { + EXPECT_CALL(*mock_image_ctx, get_object_size()).WillOnce(Return( + mock_image_ctx->layout.object_size)); + } + + void expect_get_parent_overlap(uint64_t overlap) { + EXPECT_CALL(*mock_image_ctx, get_parent_overlap(_, _)) + .WillOnce(WithArg<1>(Invoke([overlap](uint64_t *o) { + *o = overlap; + return 0; + }))); + } + + void expect_prune_parent_extents(uint64_t object_overlap) { + EXPECT_CALL(*mock_image_ctx, prune_parent_extents(_, _)) + .WillOnce(Return(object_overlap)); + } + + void expect_copyup(MockAbstractObjectWriteRequest** write_request, int r) { + EXPECT_CALL(copyup_request, append_request(_, _)) + .WillOnce(WithArg<0>( + Invoke([write_request]( + MockAbstractObjectWriteRequest *req) { + *write_request = req; + }))); + EXPECT_CALL(copyup_request, send()) + .WillOnce(Invoke([write_request, r]() { + (*write_request)->handle_copyup(r); + })); + } + void expect_encrypt(int count = 1) { EXPECT_CALL(*crypto, encrypt(_, _)).Times(count); } @@ -365,6 +436,8 @@ TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteWithNoObject) { ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE); ASSERT_EQ(on_finish, &finished_cond); + expect_get_object_size(); + expect_get_parent_overlap(0); auto expected_data = (std::string(1, '\0') + std::string(8192, '1') + std::string(4095, '\0')); expect_object_write(0, expected_data, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE, @@ -387,6 +460,8 @@ TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteFailCreate) { ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE); ASSERT_EQ(on_finish, &finished_cond); + expect_get_object_size(); + expect_get_parent_overlap(0); auto expected_data = (std::string(1, '\0') + std::string(8192, '1') + std::string(4095, '\0')); expect_object_write(0, expected_data, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE, @@ -410,6 +485,50 @@ TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteFailCreate) { ASSERT_EQ(0, dispatched_cond.wait()); } +TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteCopyup) { + MockObjectMap mock_object_map; + mock_image_ctx->object_map = &mock_object_map; + MockExclusiveLock mock_exclusive_lock; + mock_image_ctx->exclusive_lock = &mock_exclusive_lock; + + ceph::bufferlist write_data; + write_data.append(std::string(8192, '1')); + io::ReadExtents extents = {{0, 4096}, {8192, 4096}}; + expect_object_read(&extents); + ASSERT_TRUE(mock_crypto_object_dispatch->write( + 0, 1, std::move(write_data), mock_image_ctx->get_data_io_context(), + 0, 0, std::nullopt, {}, nullptr, nullptr, &dispatch_result, + &on_finish, on_dispatched)); + ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE); + ASSERT_EQ(on_finish, &finished_cond); + + expect_get_object_size(); + expect_get_parent_overlap(mock_image_ctx->layout.object_size); + expect_prune_parent_extents(mock_image_ctx->layout.object_size); + EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillRepeatedly( + Return(true)); + EXPECT_CALL(*mock_image_ctx->object_map, object_may_exist(0)).WillOnce( + Return(false)); + MockAbstractObjectWriteRequest *write_request = nullptr; + expect_copyup(&write_request, 0); + + // unaligned write restarted + uint64_t version = 1234; + extents[0].bl.append(std::string(4096, '2')); + extents[1].bl.append(std::string(4096, '3')); + expect_object_read(&extents, version); + dispatcher_ctx->complete(-ENOENT); // complete first read + ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0)); + + auto expected_data = + std::string("2") + std::string(8192, '1') + std::string(4095, '3'); + expect_object_write(0, expected_data, 0, std::make_optional(version)); + dispatcher_ctx->complete(0); // complete second read + ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0)); + dispatcher_ctx->complete(0); // complete write + ASSERT_EQ(0, dispatched_cond.wait()); +} + TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteFailVersionCheck) { ceph::bufferlist write_data; uint64_t version = 1234; |