]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / librbd / crypto / test_mock_CryptoObjectDispatch.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
12
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,
16 Context* on_finish);
17
18 template class librbd::io::ObjectWriteRequest<librbd::MockImageCtx>;
19 template class librbd::io::AbstractObjectWriteRequest<librbd::MockImageCtx>;
20 #include "librbd/io/ObjectRequest.cc"
21
22 namespace librbd {
23
24 namespace util {
25
26 inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
27 return image_ctx->image_ctx;
28 }
29
30 } // namespace util
31
32 namespace io {
33
34 template <>
35 struct CopyupRequest<librbd::MockImageCtx> {
36 MOCK_METHOD0(send, void());
37 MOCK_METHOD2(append_request, void(
38 AbstractObjectWriteRequest<librbd::MockImageCtx>*,
39 const Extents&));
40
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) {
45 return s_instance;
46 }
47
48 CopyupRequest() {
49 s_instance = this;
50 }
51 };
52
53 CopyupRequest<librbd::MockImageCtx>* CopyupRequest<
54 librbd::MockImageCtx>::s_instance = nullptr;
55
56 namespace util {
57
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,
61 object_no, offset);
62 }
63
64 namespace {
65
66 struct Mock {
67 static Mock* s_instance;
68
69 Mock() {
70 s_instance = this;
71 }
72
73 MOCK_METHOD6(read_parent,
74 void(MockImageCtx*, uint64_t, io::ReadExtents*,
75 librados::snap_t, const ZTracer::Trace &, Context*));
76 };
77
78 Mock *Mock::s_instance = nullptr;
79
80 } // anonymous namespace
81
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) {
86
87 Mock::s_instance->read_parent(image_ctx, object_no, extents, snap_id, trace,
88 on_finish);
89 }
90
91 } // namespace util
92 } // namespace io
93
94 } // namespace librbd
95
96 #include "librbd/crypto/CryptoObjectDispatch.cc"
97
98 namespace librbd {
99 namespace crypto {
100
101 using ::testing::_;
102 using ::testing::ElementsAre;
103 using ::testing::Invoke;
104 using ::testing::InSequence;
105 using ::testing::Pair;
106 using ::testing::Return;
107 using ::testing::WithArg;
108
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;
115
116 MockCryptoInterface* crypto;
117 MockImageCtx* mock_image_ctx;
118 MockCryptoObjectDispatch* mock_crypto_object_dispatch;
119
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;
131
132 void SetUp() override {
133 TestMockFixture::SetUp();
134
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'));
142 }
143
144 void TearDown() override {
145 C_SaferCond cond;
146 Context *on_finish = &cond;
147 mock_crypto_object_dispatch->shut_down(on_finish);
148 ASSERT_EQ(0, cond.wait());
149
150 delete mock_crypto_object_dispatch;
151 delete mock_image_ctx;
152
153 TestMockFixture::TearDown();
154 }
155
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>(
161 &spec->request);
162 ASSERT_TRUE(read != nullptr);
163
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;
170 }
171
172 if (read->version != nullptr) {
173 *(read->version) = version;
174 }
175
176 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
177 dispatcher_ctx = &spec->dispatcher_ctx;
178 }));
179 }
180
181 void expect_read_parent(MockUtils &mock_utils, uint64_t object_no,
182 io::ReadExtents* extents, librados::snap_t snap_id,
183 int r) {
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))));
188 }
189
190 void expect_object_write(uint64_t object_off, const std::string& data,
191 int write_flags,
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>(
197 &spec->request);
198 ASSERT_TRUE(write != nullptr);
199
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);
204
205 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
206 dispatcher_ctx = &spec->dispatcher_ctx;
207 }));
208 }
209
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>(
215 &spec->request);
216 ASSERT_TRUE(write_same != nullptr);
217
218 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
219 dispatcher_ctx = &spec->dispatcher_ctx;
220 }));
221 }
222
223 void expect_get_object_size() {
224 EXPECT_CALL(*mock_image_ctx, get_object_size()).WillOnce(Return(
225 mock_image_ctx->layout.object_size));
226 }
227
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));
232 }
233
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) {
237 *o = overlap;
238 return 0;
239 })));
240 }
241
242 void expect_prune_parent_extents(uint64_t object_overlap) {
243 EXPECT_CALL(*mock_image_ctx, prune_parent_extents(_, _))
244 .WillOnce(Return(object_overlap));
245 }
246
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;
253 })));
254 EXPECT_CALL(copyup_request, send())
255 .WillOnce(Invoke([write_request, r]() {
256 (*write_request)->handle_copyup(r);
257 }));
258 }
259
260 void expect_encrypt(int count = 1) {
261 EXPECT_CALL(*crypto, encrypt(_, _)).Times(count);
262 }
263
264 void expect_decrypt(int count = 1) {
265 EXPECT_CALL(*crypto, decrypt(_, _)).Times(count);
266 }
267 };
268
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());
275 }
276
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,
282 on_dispatched));
283 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
284
285 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
286 dispatcher_ctx->complete(0);
287 ASSERT_EQ(0, dispatched_cond.wait());
288 }
289
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);
299
300 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
301 dispatcher_ctx->complete(-EIO);
302 ASSERT_EQ(-EIO, dispatched_cond.wait());
303 }
304
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));
319
320 expect_decrypt(3);
321 dispatcher_ctx->complete(0);
322 ASSERT_EQ(16384 + 4096, dispatched_cond.wait());
323
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)));
332 }
333
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));
345
346 // no decrypt
347 dispatcher_ctx->complete(-ENOENT);
348 ASSERT_EQ(8192, dispatched_cond.wait());
349 }
350
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));
362
363 // no decrypt
364 dispatcher_ctx->complete(-ENOENT);
365 ASSERT_EQ(-ENOENT, dispatched_cond.wait());
366 }
367
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},
372 {16384, 4096 * 5}};
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}};
381
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));
390
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"));
396
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)));
403 }
404
405 TEST_F(TestMockCryptoCryptoObjectDispatch, AlignedWrite) {
406 expect_encrypt();
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,
410 on_dispatched));
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());
415 }
416
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);
431
432 auto expected_data =
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());
439 }
440
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);
452
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,
458 std::nullopt);
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());
463 }
464
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);
476
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,
482 std::nullopt);
483 dispatcher_ctx->complete(-ENOENT); // complete read
484 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
485
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));
492
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());
500 }
501
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;
507
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);
518
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(
524 Return(true));
525 EXPECT_CALL(*mock_image_ctx->object_map, object_may_exist(0)).WillOnce(
526 Return(false));
527 MockAbstractObjectWriteRequest *write_request = nullptr;
528 expect_copyup(&write_request, 0);
529
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));
537
538 auto expected_data =
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());
545 }
546
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;
552
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);
563
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(
569 Return(true));
570 EXPECT_CALL(*mock_image_ctx->object_map, object_may_exist(0)).WillOnce(
571 Return(false));
572 MockAbstractObjectWriteRequest *write_request = nullptr;
573 expect_copyup(&write_request, 0);
574
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));
579
580 auto expected_data =
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,
584 std::nullopt);
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());
589 }
590
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);
605
606 auto expected_data =
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));
611
612 version = 1235;
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));
618
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());
624 }
625
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);
641
642 dispatcher_ctx->complete(8192); // complete read
643 ASSERT_EQ(-ERANGE, dispatched_cond.wait());
644 }
645
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);
659
660 dispatcher_ctx->complete(8192); // complete read
661 ASSERT_EQ(-EEXIST, dispatched_cond.wait());
662 }
663
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);
675
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);
682
683 auto expected_data =
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());
690 }
691
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);
703
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);
711
712 dispatcher_ctx->complete(4096*4); // complete read
713 ASSERT_EQ(-EILSEQ, dispatched_cond.wait());
714 ASSERT_EQ(mismatch_offset, 4094);
715 }
716
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);
727
728 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
729 dispatcher_ctx->complete(0);
730 ASSERT_EQ(0, dispatched_cond.wait());
731 }
732
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];
738
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)});
745
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)});
751
752 expect_get_object_size();
753 expect_encrypt(6);
754 InSequence seq;
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));
763
764 ASSERT_EQ(2, snapshot_sparse_bufferlist.size());
765
766 auto& snap1_result = snapshot_sparse_bufferlist[0];
767 auto& snap2_result = snapshot_sparse_bufferlist[1];
768
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());
773
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());
779
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'));
788
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());
795 }
796
797 } // namespace io
798 } // namespace librbd