1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librbd/mock/MockImageCtx.h"
7 #include "test/librbd/mock/MockObjectMap.h"
8 #include "test/librbd/mock/crypto/MockCryptoInterface.h"
9 #include "librbd/crypto/CryptoObjectDispatch.h"
10 #include "librbd/io/ObjectDispatchSpec.h"
11 #include "librbd/io/Utils.h"
13 #include "librbd/io/Utils.cc"
14 template bool librbd::io::util::trigger_copyup(
15 MockImageCtx
*image_ctx
, uint64_t object_no
, IOContext io_context
,
18 template class librbd::io::ObjectWriteRequest
<librbd::MockImageCtx
>;
19 template class librbd::io::AbstractObjectWriteRequest
<librbd::MockImageCtx
>;
20 #include "librbd/io/ObjectRequest.cc"
26 inline ImageCtx
*get_image_ctx(MockImageCtx
*image_ctx
) {
27 return image_ctx
->image_ctx
;
35 struct CopyupRequest
<librbd::MockImageCtx
> {
36 MOCK_METHOD0(send
, void());
37 MOCK_METHOD2(append_request
, void(
38 AbstractObjectWriteRequest
<librbd::MockImageCtx
>*,
41 static CopyupRequest
* s_instance
;
42 static CopyupRequest
* create(librbd::MockImageCtx
*ictx
,
43 uint64_t objectno
, Extents
&&image_extents
,
44 const ZTracer::Trace
&parent_trace
) {
53 CopyupRequest
<librbd::MockImageCtx
>* CopyupRequest
<
54 librbd::MockImageCtx
>::s_instance
= nullptr;
58 template <> uint64_t get_file_offset(
59 MockImageCtx
*image_ctx
, uint64_t object_no
, uint64_t offset
) {
60 return Striper::get_file_offset(image_ctx
->cct
, &image_ctx
->layout
,
67 static Mock
* s_instance
;
73 MOCK_METHOD6(read_parent
,
74 void(MockImageCtx
*, uint64_t, io::ReadExtents
*,
75 librados::snap_t
, const ZTracer::Trace
&, Context
*));
78 Mock
*Mock::s_instance
= nullptr;
80 } // anonymous namespace
82 template <> void read_parent(
83 MockImageCtx
*image_ctx
, uint64_t object_no
,
84 io::ReadExtents
* extents
, librados::snap_t snap_id
,
85 const ZTracer::Trace
&trace
, Context
* on_finish
) {
87 Mock::s_instance
->read_parent(image_ctx
, object_no
, extents
, snap_id
, trace
,
96 #include "librbd/crypto/CryptoObjectDispatch.cc"
102 using ::testing::ElementsAre
;
103 using ::testing::Invoke
;
104 using ::testing::InSequence
;
105 using ::testing::Pair
;
106 using ::testing::Return
;
107 using ::testing::WithArg
;
109 struct TestMockCryptoCryptoObjectDispatch
: public TestMockFixture
{
110 typedef CryptoObjectDispatch
<librbd::MockImageCtx
> MockCryptoObjectDispatch
;
111 typedef io::AbstractObjectWriteRequest
<librbd::MockImageCtx
>
112 MockAbstractObjectWriteRequest
;
113 typedef io::CopyupRequest
<librbd::MockImageCtx
> MockCopyupRequest
;
114 typedef io::util::Mock MockUtils
;
116 MockCryptoInterface
* crypto
;
117 MockImageCtx
* mock_image_ctx
;
118 MockCryptoObjectDispatch
* mock_crypto_object_dispatch
;
120 C_SaferCond finished_cond
;
121 Context
*on_finish
= &finished_cond
;
122 C_SaferCond dispatched_cond
;
123 Context
*on_dispatched
= &dispatched_cond
;
124 Context
*dispatcher_ctx
;
125 ceph::bufferlist data
;
126 io::DispatchResult dispatch_result
;
127 io::Extents extent_map
;
128 int object_dispatch_flags
= 0;
129 MockUtils mock_utils
;
130 MockCopyupRequest copyup_request
;
132 void SetUp() override
{
133 TestMockFixture::SetUp();
135 librbd::ImageCtx
*ictx
;
136 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
137 crypto
= new MockCryptoInterface();
138 mock_image_ctx
= new MockImageCtx(*ictx
);
139 mock_crypto_object_dispatch
= new MockCryptoObjectDispatch(
140 mock_image_ctx
, crypto
);
141 data
.append(std::string(4096, '1'));
144 void TearDown() override
{
146 Context
*on_finish
= &cond
;
147 mock_crypto_object_dispatch
->shut_down(on_finish
);
148 ASSERT_EQ(0, cond
.wait());
150 delete mock_crypto_object_dispatch
;
151 delete mock_image_ctx
;
153 TestMockFixture::TearDown();
156 void expect_object_read(io::ReadExtents
* extents
, uint64_t version
= 0) {
157 EXPECT_CALL(*mock_image_ctx
->io_object_dispatcher
, send(_
))
158 .WillOnce(Invoke([this, extents
,
159 version
](io::ObjectDispatchSpec
* spec
) {
160 auto* read
= boost::get
<io::ObjectDispatchSpec::ReadRequest
>(
162 ASSERT_TRUE(read
!= nullptr);
164 ASSERT_EQ(extents
->size(), read
->extents
->size());
165 for (uint64_t i
= 0; i
< extents
->size(); ++i
) {
166 ASSERT_EQ((*extents
)[i
].offset
, (*read
->extents
)[i
].offset
);
167 ASSERT_EQ((*extents
)[i
].length
, (*read
->extents
)[i
].length
);
168 (*read
->extents
)[i
].bl
= (*extents
)[i
].bl
;
169 (*read
->extents
)[i
].extent_map
= (*extents
)[i
].extent_map
;
172 if (read
->version
!= nullptr) {
173 *(read
->version
) = version
;
176 spec
->dispatch_result
= io::DISPATCH_RESULT_COMPLETE
;
177 dispatcher_ctx
= &spec
->dispatcher_ctx
;
181 void expect_read_parent(MockUtils
&mock_utils
, uint64_t object_no
,
182 io::ReadExtents
* extents
, librados::snap_t snap_id
,
184 EXPECT_CALL(mock_utils
,
185 read_parent(_
, object_no
, extents
, snap_id
, _
, _
))
186 .WillOnce(WithArg
<5>(CompleteContext(
187 r
, static_cast<asio::ContextWQ
*>(nullptr))));
190 void expect_object_write(uint64_t object_off
, const std::string
& data
,
192 std::optional
<uint64_t> assert_version
) {
193 EXPECT_CALL(*mock_image_ctx
->io_object_dispatcher
, send(_
))
194 .WillOnce(Invoke([this, object_off
, data
, write_flags
,
195 assert_version
](io::ObjectDispatchSpec
* spec
) {
196 auto* write
= boost::get
<io::ObjectDispatchSpec::WriteRequest
>(
198 ASSERT_TRUE(write
!= nullptr);
200 ASSERT_EQ(object_off
, write
->object_off
);
201 ASSERT_TRUE(data
== write
->data
.to_str());
202 ASSERT_EQ(write_flags
, write
->write_flags
);
203 ASSERT_EQ(assert_version
, write
->assert_version
);
205 spec
->dispatch_result
= io::DISPATCH_RESULT_COMPLETE
;
206 dispatcher_ctx
= &spec
->dispatcher_ctx
;
210 void expect_object_write_same() {
211 EXPECT_CALL(*mock_image_ctx
->io_object_dispatcher
, send(_
))
212 .WillOnce(Invoke([this](io::ObjectDispatchSpec
* spec
) {
213 auto* write_same
= boost::get
<
214 io::ObjectDispatchSpec::WriteSameRequest
>(
216 ASSERT_TRUE(write_same
!= nullptr);
218 spec
->dispatch_result
= io::DISPATCH_RESULT_COMPLETE
;
219 dispatcher_ctx
= &spec
->dispatcher_ctx
;
223 void expect_get_object_size() {
224 EXPECT_CALL(*mock_image_ctx
, get_object_size()).WillOnce(Return(
225 mock_image_ctx
->layout
.object_size
));
228 void expect_remap_extents(uint64_t offset
, uint64_t length
) {
229 EXPECT_CALL(*mock_image_ctx
->io_image_dispatcher
, remap_extents(
230 ElementsAre(Pair(offset
, length
)),
231 io::IMAGE_EXTENTS_MAP_TYPE_PHYSICAL_TO_LOGICAL
));
234 void expect_get_parent_overlap(uint64_t overlap
) {
235 EXPECT_CALL(*mock_image_ctx
, get_parent_overlap(_
, _
))
236 .WillOnce(WithArg
<1>(Invoke([overlap
](uint64_t *o
) {
242 void expect_prune_parent_extents(uint64_t object_overlap
) {
243 EXPECT_CALL(*mock_image_ctx
, prune_parent_extents(_
, _
))
244 .WillOnce(Return(object_overlap
));
247 void expect_copyup(MockAbstractObjectWriteRequest
** write_request
, int r
) {
248 EXPECT_CALL(copyup_request
, append_request(_
, _
))
249 .WillOnce(WithArg
<0>(
250 Invoke([write_request
](
251 MockAbstractObjectWriteRequest
*req
) {
252 *write_request
= req
;
254 EXPECT_CALL(copyup_request
, send())
255 .WillOnce(Invoke([write_request
, r
]() {
256 (*write_request
)->handle_copyup(r
);
260 void expect_encrypt(int count
= 1) {
261 EXPECT_CALL(*crypto
, encrypt(_
, _
)).Times(count
);
264 void expect_decrypt(int count
= 1) {
265 EXPECT_CALL(*crypto
, decrypt(_
, _
)).Times(count
);
269 TEST_F(TestMockCryptoCryptoObjectDispatch
, Flush
) {
270 ASSERT_FALSE(mock_crypto_object_dispatch
->flush(
271 io::FLUSH_SOURCE_USER
, {}, nullptr, nullptr, &on_finish
, nullptr));
272 ASSERT_EQ(on_finish
, &finished_cond
); // not modified
273 on_finish
->complete(0);
274 ASSERT_EQ(0, finished_cond
.wait());
277 TEST_F(TestMockCryptoCryptoObjectDispatch
, Discard
) {
278 expect_object_write_same();
279 ASSERT_TRUE(mock_crypto_object_dispatch
->discard(
280 0, 0, 4096, mock_image_ctx
->get_data_io_context(), 0, {},
281 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish
,
283 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
285 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
286 dispatcher_ctx
->complete(0);
287 ASSERT_EQ(0, dispatched_cond
.wait());
290 TEST_F(TestMockCryptoCryptoObjectDispatch
, AlignedReadFail
) {
291 io::ReadExtents extents
= {{0, 4096}};
292 expect_object_read(&extents
);
293 ASSERT_TRUE(mock_crypto_object_dispatch
->read(
294 0, &extents
, mock_image_ctx
->get_data_io_context(), 0, 0, {},
295 nullptr, &object_dispatch_flags
, &dispatch_result
,
296 &on_finish
, on_dispatched
));
297 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
298 ASSERT_EQ(on_finish
, &finished_cond
);
300 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
301 dispatcher_ctx
->complete(-EIO
);
302 ASSERT_EQ(-EIO
, dispatched_cond
.wait());
305 TEST_F(TestMockCryptoCryptoObjectDispatch
, AlignedRead
) {
306 io::ReadExtents extents
= {{0, 16384}, {32768, 4096}};
307 extents
[0].bl
.append(std::string(1024, '1') + std::string(1024, '2') +
308 std::string(1024, '3') + std::string(1024, '4'));
309 extents
[0].extent_map
= {{1024, 1024}, {3072, 2048}, {16384 - 1024, 1024}};
310 extents
[1].bl
.append(std::string(4096, '0'));
311 expect_object_read(&extents
);
312 ASSERT_TRUE(mock_crypto_object_dispatch
->read(
313 0, &extents
, mock_image_ctx
->get_data_io_context(), 0, 0, {},
314 nullptr, &object_dispatch_flags
, &dispatch_result
,
315 &on_finish
, on_dispatched
));
316 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
317 ASSERT_EQ(on_finish
, &finished_cond
);
318 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
321 dispatcher_ctx
->complete(0);
322 ASSERT_EQ(16384 + 4096, dispatched_cond
.wait());
324 auto expected_bl_data
= (
325 std::string(1024, '\0') + std::string(1024, '1') +
326 std::string(1024, '\0') + std::string(1024, '2') +
327 std::string(1024, '3') + std::string(3072, '\0') +
328 std::string(3072, '\0') + std::string(1024, '4'));
329 ASSERT_TRUE(extents
[0].bl
.to_str() == expected_bl_data
);
330 ASSERT_THAT(extents
[0].extent_map
,
331 ElementsAre(Pair(0, 8192), Pair(16384 - 4096, 4096)));
334 TEST_F(TestMockCryptoCryptoObjectDispatch
, ReadFromParent
) {
335 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
336 expect_object_read(&extents
);
337 expect_read_parent(mock_utils
, 0, &extents
, CEPH_NOSNAP
, 8192);
338 ASSERT_TRUE(mock_crypto_object_dispatch
->read(
339 0, &extents
, mock_image_ctx
->get_data_io_context(), 0, 0, {},
340 nullptr, &object_dispatch_flags
, &dispatch_result
,
341 &on_finish
, on_dispatched
));
342 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
343 ASSERT_EQ(on_finish
, &finished_cond
);
344 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
347 dispatcher_ctx
->complete(-ENOENT
);
348 ASSERT_EQ(8192, dispatched_cond
.wait());
351 TEST_F(TestMockCryptoCryptoObjectDispatch
, ReadFromParentDisabled
) {
352 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
353 expect_object_read(&extents
);
354 ASSERT_TRUE(mock_crypto_object_dispatch
->read(
355 0, &extents
, mock_image_ctx
->get_data_io_context(), 0,
356 io::READ_FLAG_DISABLE_READ_FROM_PARENT
, {},
357 nullptr, &object_dispatch_flags
, &dispatch_result
,
358 &on_finish
, on_dispatched
));
359 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
360 ASSERT_EQ(on_finish
, &finished_cond
);
361 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
364 dispatcher_ctx
->complete(-ENOENT
);
365 ASSERT_EQ(-ENOENT
, dispatched_cond
.wait());
368 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedRead
) {
369 io::ReadExtents extents
= {{0, 1}, {8191, 1}, {8193, 1},
370 {16384 + 1, 4096 * 5 - 2}};
371 io::ReadExtents aligned_extents
= {{0, 4096}, {4096, 4096}, {8192, 4096},
373 aligned_extents
[0].bl
.append(std::string("1") + std::string(4096, '0'));
374 aligned_extents
[1].bl
.append(std::string(4095, '0') + std::string("2"));
375 aligned_extents
[2].bl
.append(std::string("03") + std::string(4094, '0'));
376 aligned_extents
[3].bl
.append(std::string("0") + std::string(4095, '4') +
377 std::string(4096, '5') +
378 std::string(4095, '6') + std::string("0"));
379 aligned_extents
[3].extent_map
= {{16384, 4096}, {16384 + 2 * 4096, 4096},
380 {16384 + 4 * 4096, 4096}};
382 expect_object_read(&aligned_extents
);
383 ASSERT_TRUE(mock_crypto_object_dispatch
->read(
384 0, &extents
, mock_image_ctx
->get_data_io_context(), 0, 0, {},
385 nullptr, &object_dispatch_flags
, &dispatch_result
,
386 &on_finish
, on_dispatched
));
387 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
388 ASSERT_EQ(on_finish
, &finished_cond
);
389 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
391 dispatcher_ctx
->complete(4096*8);
392 ASSERT_EQ(3 + 4096 * 5 - 2, dispatched_cond
.wait());
393 ASSERT_TRUE(extents
[0].bl
.to_str() == std::string("1"));
394 ASSERT_TRUE(extents
[1].bl
.to_str() == std::string("2"));
395 ASSERT_TRUE(extents
[2].bl
.to_str() == std::string("3"));
397 auto expected_bl_data
= (std::string(4095, '4') + std::string(4096, '5') +
398 std::string(4095, '6'));
399 ASSERT_TRUE(extents
[3].bl
.to_str() == expected_bl_data
);
400 ASSERT_THAT(extents
[3].extent_map
,
401 ElementsAre(Pair(16384 + 1, 4095), Pair(16384 + 2 * 4096, 4096),
402 Pair(16384 + 4 * 4096, 4095)));
405 TEST_F(TestMockCryptoCryptoObjectDispatch
, AlignedWrite
) {
407 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
408 0, 0, std::move(data
), mock_image_ctx
->get_data_io_context(), 0, 0,
409 std::nullopt
, {}, nullptr, nullptr, &dispatch_result
, &on_finish
,
411 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_CONTINUE
);
412 ASSERT_EQ(on_finish
, &finished_cond
); // not modified
413 on_finish
->complete(0);
414 ASSERT_EQ(0, finished_cond
.wait());
417 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWrite
) {
418 ceph::bufferlist write_data
;
419 uint64_t version
= 1234;
420 write_data
.append(std::string(8192, '1'));
421 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
422 extents
[0].bl
.append(std::string(4096, '2'));
423 extents
[1].bl
.append(std::string(4096, '3'));
424 expect_object_read(&extents
, version
);
425 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
426 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
427 0, 0, std::nullopt
, {}, nullptr, nullptr, &dispatch_result
,
428 &on_finish
, on_dispatched
));
429 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
430 ASSERT_EQ(on_finish
, &finished_cond
);
433 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
434 expect_object_write(0, expected_data
, 0, std::make_optional(version
));
435 dispatcher_ctx
->complete(8192); // complete read
436 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
437 dispatcher_ctx
->complete(0); // complete write
438 ASSERT_EQ(0, dispatched_cond
.wait());
441 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWriteWithNoObject
) {
442 ceph::bufferlist write_data
;
443 write_data
.append(std::string(8192, '1'));
444 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
445 expect_object_read(&extents
);
446 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
447 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
448 0, 0, std::nullopt
, {}, nullptr, nullptr, &dispatch_result
,
449 &on_finish
, on_dispatched
));
450 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
451 ASSERT_EQ(on_finish
, &finished_cond
);
453 expect_get_object_size();
454 expect_get_parent_overlap(0);
455 auto expected_data
= (std::string(1, '\0') + std::string(8192, '1') +
456 std::string(4095, '\0'));
457 expect_object_write(0, expected_data
, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE
,
459 dispatcher_ctx
->complete(-ENOENT
); // complete read
460 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
461 dispatcher_ctx
->complete(0); // complete write
462 ASSERT_EQ(0, dispatched_cond
.wait());
465 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWriteFailCreate
) {
466 ceph::bufferlist write_data
;
467 write_data
.append(std::string(8192, '1'));
468 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
469 expect_object_read(&extents
);
470 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
471 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
472 0, 0, std::nullopt
, {}, nullptr, nullptr, &dispatch_result
,
473 &on_finish
, on_dispatched
));
474 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
475 ASSERT_EQ(on_finish
, &finished_cond
);
477 expect_get_object_size();
478 expect_get_parent_overlap(0);
479 auto expected_data
= (std::string(1, '\0') + std::string(8192, '1') +
480 std::string(4095, '\0'));
481 expect_object_write(0, expected_data
, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE
,
483 dispatcher_ctx
->complete(-ENOENT
); // complete read
484 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
486 extents
[0].bl
.append(std::string(4096, '2'));
487 extents
[1].bl
.append(std::string(4096, '3'));
488 uint64_t version
= 1234;
489 expect_object_read(&extents
, version
);
490 dispatcher_ctx
->complete(-EEXIST
); // complete write, request will restart
491 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
493 auto expected_data2
=
494 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
495 expect_object_write(0, expected_data2
, 0, std::make_optional(version
));
496 dispatcher_ctx
->complete(8192); // complete read
497 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
498 dispatcher_ctx
->complete(0); // complete write
499 ASSERT_EQ(0, dispatched_cond
.wait());
502 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWriteCopyup
) {
503 MockObjectMap mock_object_map
;
504 mock_image_ctx
->object_map
= &mock_object_map
;
505 MockExclusiveLock mock_exclusive_lock
;
506 mock_image_ctx
->exclusive_lock
= &mock_exclusive_lock
;
508 ceph::bufferlist write_data
;
509 write_data
.append(std::string(8192, '1'));
510 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
511 expect_object_read(&extents
);
512 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
513 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
514 0, 0, std::nullopt
, {}, nullptr, nullptr, &dispatch_result
,
515 &on_finish
, on_dispatched
));
516 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
517 ASSERT_EQ(on_finish
, &finished_cond
);
519 expect_get_object_size();
520 expect_get_parent_overlap(mock_image_ctx
->layout
.object_size
);
521 expect_remap_extents(0, mock_image_ctx
->layout
.object_size
);
522 expect_prune_parent_extents(mock_image_ctx
->layout
.object_size
);
523 EXPECT_CALL(mock_exclusive_lock
, is_lock_owner()).WillRepeatedly(
525 EXPECT_CALL(*mock_image_ctx
->object_map
, object_may_exist(0)).WillOnce(
527 MockAbstractObjectWriteRequest
*write_request
= nullptr;
528 expect_copyup(&write_request
, 0);
530 // unaligned write restarted
531 uint64_t version
= 1234;
532 extents
[0].bl
.append(std::string(4096, '2'));
533 extents
[1].bl
.append(std::string(4096, '3'));
534 expect_object_read(&extents
, version
);
535 dispatcher_ctx
->complete(-ENOENT
); // complete first read
536 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
539 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
540 expect_object_write(0, expected_data
, 0, std::make_optional(version
));
541 dispatcher_ctx
->complete(8192); // complete second read
542 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
543 dispatcher_ctx
->complete(0); // complete write
544 ASSERT_EQ(0, dispatched_cond
.wait());
547 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWriteEmptyCopyup
) {
548 MockObjectMap mock_object_map
;
549 mock_image_ctx
->object_map
= &mock_object_map
;
550 MockExclusiveLock mock_exclusive_lock
;
551 mock_image_ctx
->exclusive_lock
= &mock_exclusive_lock
;
553 ceph::bufferlist write_data
;
554 write_data
.append(std::string(8192, '1'));
555 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
556 expect_object_read(&extents
);
557 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
558 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
559 0, 0, std::nullopt
, {}, nullptr, nullptr, &dispatch_result
,
560 &on_finish
, on_dispatched
));
561 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
562 ASSERT_EQ(on_finish
, &finished_cond
);
564 expect_get_object_size();
565 expect_get_parent_overlap(mock_image_ctx
->layout
.object_size
);
566 expect_remap_extents(0, mock_image_ctx
->layout
.object_size
);
567 expect_prune_parent_extents(mock_image_ctx
->layout
.object_size
);
568 EXPECT_CALL(mock_exclusive_lock
, is_lock_owner()).WillRepeatedly(
570 EXPECT_CALL(*mock_image_ctx
->object_map
, object_may_exist(0)).WillOnce(
572 MockAbstractObjectWriteRequest
*write_request
= nullptr;
573 expect_copyup(&write_request
, 0);
575 // unaligned write restarted
576 expect_object_read(&extents
);
577 dispatcher_ctx
->complete(-ENOENT
); // complete first read
578 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
581 std::string(1, '\0') + std::string(8192, '1') +
582 std::string(4095, '\0');
583 expect_object_write(0, expected_data
, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE
,
585 dispatcher_ctx
->complete(-ENOENT
); // complete second read
586 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
587 dispatcher_ctx
->complete(0); // complete write
588 ASSERT_EQ(0, dispatched_cond
.wait());
591 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWriteFailVersionCheck
) {
592 ceph::bufferlist write_data
;
593 uint64_t version
= 1234;
594 write_data
.append(std::string(8192, '1'));
595 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
596 extents
[0].bl
.append(std::string(4096, '2'));
597 extents
[1].bl
.append(std::string(4096, '3'));
598 expect_object_read(&extents
, version
);
599 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
600 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
601 0, 0, std::nullopt
, {}, nullptr, nullptr, &dispatch_result
,
602 &on_finish
, on_dispatched
));
603 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
604 ASSERT_EQ(on_finish
, &finished_cond
);
607 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
608 expect_object_write(0, expected_data
, 0, std::make_optional(version
));
609 dispatcher_ctx
->complete(8192); // complete read
610 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
613 expect_object_read(&extents
, version
);
614 extents
[0].bl
.append(std::string(4096, '2'));
615 extents
[1].bl
.append(std::string(4096, '3'));
616 dispatcher_ctx
->complete(-ERANGE
); // complete write, request will restart
617 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
619 expect_object_write(0, expected_data
, 0, std::make_optional(version
));
620 dispatcher_ctx
->complete(8192); // complete read
621 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
622 dispatcher_ctx
->complete(0); // complete write
623 ASSERT_EQ(0, dispatched_cond
.wait());
626 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWriteWithAssertVersion
) {
627 ceph::bufferlist write_data
;
628 uint64_t version
= 1234;
629 uint64_t assert_version
= 1233;
630 write_data
.append(std::string(8192, '1'));
631 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
632 extents
[0].bl
.append(std::string(4096, '2'));
633 extents
[1].bl
.append(std::string(4096, '3'));
634 expect_object_read(&extents
, version
);
635 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
636 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
637 0, 0, std::make_optional(assert_version
), {}, nullptr, nullptr,
638 &dispatch_result
, &on_finish
, on_dispatched
));
639 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
640 ASSERT_EQ(on_finish
, &finished_cond
);
642 dispatcher_ctx
->complete(8192); // complete read
643 ASSERT_EQ(-ERANGE
, dispatched_cond
.wait());
646 TEST_F(TestMockCryptoCryptoObjectDispatch
, UnalignedWriteWithExclusiveCreate
) {
647 ceph::bufferlist write_data
;
648 write_data
.append(std::string(8192, '1'));
649 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}};
650 extents
[0].bl
.append(std::string(4096, '2'));
651 extents
[1].bl
.append(std::string(4096, '3'));
652 expect_object_read(&extents
);
653 ASSERT_TRUE(mock_crypto_object_dispatch
->write(
654 0, 1, std::move(write_data
), mock_image_ctx
->get_data_io_context(),
655 0, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE
, std::nullopt
, {}, nullptr,
656 nullptr, &dispatch_result
, &on_finish
, on_dispatched
));
657 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
658 ASSERT_EQ(on_finish
, &finished_cond
);
660 dispatcher_ctx
->complete(8192); // complete read
661 ASSERT_EQ(-EEXIST
, dispatched_cond
.wait());
664 TEST_F(TestMockCryptoCryptoObjectDispatch
, CompareAndWrite
) {
665 ceph::bufferlist write_data
;
666 uint64_t version
= 1234;
667 write_data
.append(std::string(8192, '1'));
668 ceph::bufferlist cmp_data
;
669 cmp_data
.append(std::string(4096, '2'));
670 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}, {0, 8192}};
671 extents
[0].bl
.append(std::string(4096, '2'));
672 extents
[1].bl
.append(std::string(4096, '3'));
673 extents
[2].bl
.append(std::string(8192, '2'));
674 expect_object_read(&extents
, version
);
676 ASSERT_TRUE(mock_crypto_object_dispatch
->compare_and_write(
677 0, 1, std::move(cmp_data
), std::move(write_data
),
678 mock_image_ctx
->get_data_io_context(), 0, {}, nullptr, nullptr,
679 nullptr, &dispatch_result
, &on_finish
, on_dispatched
));
680 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
681 ASSERT_EQ(on_finish
, &finished_cond
);
684 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
685 expect_object_write(0, expected_data
, 0, std::make_optional(version
));
686 dispatcher_ctx
->complete(4096*4); // complete read
687 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
688 dispatcher_ctx
->complete(0); // complete write
689 ASSERT_EQ(0, dispatched_cond
.wait());
692 TEST_F(TestMockCryptoCryptoObjectDispatch
, CompareAndWriteFail
) {
693 ceph::bufferlist write_data
;
694 uint64_t version
= 1234;
695 write_data
.append(std::string(8192, '1'));
696 ceph::bufferlist cmp_data
;
697 cmp_data
.append(std::string(4094, '2') + std::string(2, '4'));
698 io::ReadExtents extents
= {{0, 4096}, {8192, 4096}, {0, 8192}};
699 extents
[0].bl
.append(std::string(4096, '2'));
700 extents
[1].bl
.append(std::string(4096, '3'));
701 extents
[2].bl
.append(std::string(8192, '2'));
702 expect_object_read(&extents
, version
);
704 uint64_t mismatch_offset
;
705 ASSERT_TRUE(mock_crypto_object_dispatch
->compare_and_write(
706 0, 1, std::move(cmp_data
), std::move(write_data
),
707 mock_image_ctx
->get_data_io_context(), 0, {}, &mismatch_offset
,
708 nullptr, nullptr, &dispatch_result
, &on_finish
, on_dispatched
));
709 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
710 ASSERT_EQ(on_finish
, &finished_cond
);
712 dispatcher_ctx
->complete(4096*4); // complete read
713 ASSERT_EQ(-EILSEQ
, dispatched_cond
.wait());
714 ASSERT_EQ(mismatch_offset
, 4094);
717 TEST_F(TestMockCryptoCryptoObjectDispatch
, WriteSame
) {
718 io::LightweightBufferExtents buffer_extents
;
719 ceph::bufferlist write_data
;
720 write_data
.append(std::string("12"));
721 expect_object_write(0, std::string("12121") , 0, std::nullopt
);
722 ASSERT_TRUE(mock_crypto_object_dispatch
->write_same(
723 0, 0, 5, {{0, 5}}, std::move(write_data
),
724 mock_image_ctx
->get_data_io_context(), 0, {}, nullptr, nullptr,
725 &dispatch_result
, &on_finish
, on_dispatched
));
726 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
728 ASSERT_EQ(ETIMEDOUT
, dispatched_cond
.wait_for(0));
729 dispatcher_ctx
->complete(0);
730 ASSERT_EQ(0, dispatched_cond
.wait());
733 TEST_F(TestMockCryptoCryptoObjectDispatch
, PrepareCopyup
) {
734 char* data
= (char*)"0123456789";
735 io::SnapshotSparseBufferlist snapshot_sparse_bufferlist
;
736 auto& snap1
= snapshot_sparse_bufferlist
[0];
737 auto& snap2
= snapshot_sparse_bufferlist
[1];
739 snap1
.insert(0, 1, {io::SPARSE_EXTENT_STATE_DATA
, 1,
740 ceph::bufferlist::static_from_mem(data
+ 1, 1)});
741 snap1
.insert(8191, 1, {io::SPARSE_EXTENT_STATE_DATA
, 1,
742 ceph::bufferlist::static_from_mem(data
+ 2, 1)});
743 snap1
.insert(8193, 3, {io::SPARSE_EXTENT_STATE_DATA
, 3,
744 ceph::bufferlist::static_from_mem(data
+ 3, 3)});
746 snap2
.insert(0, 2, {io::SPARSE_EXTENT_STATE_ZEROED
, 2});
747 snap2
.insert(8191, 3, {io::SPARSE_EXTENT_STATE_DATA
, 3,
748 ceph::bufferlist::static_from_mem(data
+ 6, 3)});
749 snap2
.insert(16384, 1, {io::SPARSE_EXTENT_STATE_DATA
, 1,
750 ceph::bufferlist::static_from_mem(data
+ 9, 1)});
752 expect_get_object_size();
755 expect_remap_extents(0, 4096);
756 expect_remap_extents(4096, 4096);
757 expect_remap_extents(8192, 4096);
758 expect_remap_extents(0, 4096);
759 expect_remap_extents(4096, 8192);
760 expect_remap_extents(16384, 4096);
761 ASSERT_EQ(0, mock_crypto_object_dispatch
->prepare_copyup(
762 0, &snapshot_sparse_bufferlist
));
764 ASSERT_EQ(2, snapshot_sparse_bufferlist
.size());
766 auto& snap1_result
= snapshot_sparse_bufferlist
[0];
767 auto& snap2_result
= snapshot_sparse_bufferlist
[1];
769 auto it
= snap1_result
.begin();
770 ASSERT_NE(it
, snap1_result
.end());
771 ASSERT_EQ(0, it
.get_off());
772 ASSERT_EQ(4096 * 3, it
.get_len());
774 ASSERT_TRUE(it
.get_val().bl
.to_str() ==
775 std::string("1") + std::string(4095, '\0') +
776 std::string(4095, '\0') + std::string("2") +
777 std::string(1, '\0') + std::string("345") + std::string(4092, '\0'));
778 ASSERT_EQ(++it
, snap1_result
.end());
780 it
= snap2_result
.begin();
781 ASSERT_NE(it
, snap2_result
.end());
782 ASSERT_EQ(0, it
.get_off());
783 ASSERT_EQ(4096 * 3, it
.get_len());
784 ASSERT_TRUE(it
.get_val().bl
.to_str() ==
785 std::string(4096, '\0') +
786 std::string(4095, '\0') + std::string("6") +
787 std::string("7845") + std::string(4092, '\0'));
789 ASSERT_NE(++it
, snap2_result
.end());
790 ASSERT_EQ(16384, it
.get_off());
791 ASSERT_EQ(4096, it
.get_len());
792 ASSERT_TRUE(it
.get_val().bl
.to_str() ==
793 std::string("9") + std::string(4095, '\0'));
794 ASSERT_EQ(++it
, snap2_result
.end());
798 } // namespace librbd