]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/crypto/test_mock_CryptoObjectDispatch.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librbd / crypto / test_mock_CryptoObjectDispatch.cc
CommitLineData
f67539c2
TL
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"
14template bool librbd::io::util::trigger_copyup(
15 MockImageCtx *image_ctx, uint64_t object_no, IOContext io_context,
16 Context* on_finish);
17
18template class librbd::io::ObjectWriteRequest<librbd::MockImageCtx>;
19template class librbd::io::AbstractObjectWriteRequest<librbd::MockImageCtx>;
20#include "librbd/io/ObjectRequest.cc"
21
22namespace librbd {
23
24namespace util {
25
26inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
27 return image_ctx->image_ctx;
28}
29
30} // namespace util
31
32namespace io {
33
34template <>
35struct 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;
1e59de90
TL
42 static CopyupRequest* create(librbd::MockImageCtx* ictx, uint64_t objectno,
43 Extents&& image_extents, ImageArea area,
44 const ZTracer::Trace& parent_trace) {
f67539c2
TL
45 return s_instance;
46 }
47
48 CopyupRequest() {
49 s_instance = this;
50 }
51};
52
53CopyupRequest<librbd::MockImageCtx>* CopyupRequest<
54 librbd::MockImageCtx>::s_instance = nullptr;
55
56namespace util {
57
f67539c2
TL
58namespace {
59
60struct Mock {
61 static Mock* s_instance;
62
63 Mock() {
64 s_instance = this;
65 }
66
67 MOCK_METHOD6(read_parent,
68 void(MockImageCtx*, uint64_t, io::ReadExtents*,
69 librados::snap_t, const ZTracer::Trace &, Context*));
70};
71
72Mock *Mock::s_instance = nullptr;
73
74} // anonymous namespace
75
76template <> void read_parent(
77 MockImageCtx *image_ctx, uint64_t object_no,
78 io::ReadExtents* extents, librados::snap_t snap_id,
79 const ZTracer::Trace &trace, Context* on_finish) {
80
81 Mock::s_instance->read_parent(image_ctx, object_no, extents, snap_id, trace,
82 on_finish);
83}
84
85} // namespace util
86} // namespace io
87
88} // namespace librbd
89
90#include "librbd/crypto/CryptoObjectDispatch.cc"
91
92namespace librbd {
93namespace crypto {
94
1e59de90
TL
95template <>
96uint64_t get_file_offset(MockImageCtx *image_ctx, uint64_t object_no,
97 uint64_t offset) {
98 return Striper::get_file_offset(image_ctx->cct, &image_ctx->layout,
99 object_no, offset);
100}
101
f67539c2
TL
102using ::testing::_;
103using ::testing::ElementsAre;
104using ::testing::Invoke;
105using ::testing::InSequence;
106using ::testing::Pair;
107using ::testing::Return;
108using ::testing::WithArg;
109
110struct TestMockCryptoCryptoObjectDispatch : public TestMockFixture {
111 typedef CryptoObjectDispatch<librbd::MockImageCtx> MockCryptoObjectDispatch;
112 typedef io::AbstractObjectWriteRequest<librbd::MockImageCtx>
113 MockAbstractObjectWriteRequest;
114 typedef io::CopyupRequest<librbd::MockImageCtx> MockCopyupRequest;
115 typedef io::util::Mock MockUtils;
116
1e59de90 117 MockCryptoInterface crypto;
f67539c2
TL
118 MockImageCtx* mock_image_ctx;
119 MockCryptoObjectDispatch* mock_crypto_object_dispatch;
120
121 C_SaferCond finished_cond;
122 Context *on_finish = &finished_cond;
123 C_SaferCond dispatched_cond;
124 Context *on_dispatched = &dispatched_cond;
125 Context *dispatcher_ctx;
126 ceph::bufferlist data;
127 io::DispatchResult dispatch_result;
128 io::Extents extent_map;
129 int object_dispatch_flags = 0;
130 MockUtils mock_utils;
131 MockCopyupRequest copyup_request;
132
133 void SetUp() override {
134 TestMockFixture::SetUp();
135
136 librbd::ImageCtx *ictx;
137 ASSERT_EQ(0, open_image(m_image_name, &ictx));
f67539c2
TL
138 mock_image_ctx = new MockImageCtx(*ictx);
139 mock_crypto_object_dispatch = new MockCryptoObjectDispatch(
1e59de90 140 mock_image_ctx, &crypto);
f67539c2
TL
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
20effc67 150 delete mock_crypto_object_dispatch;
f67539c2
TL
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
1e59de90
TL
228 void expect_remap_to_logical(uint64_t offset, uint64_t length) {
229 EXPECT_CALL(*mock_image_ctx->io_image_dispatcher, remap_to_logical(
230 ElementsAre(Pair(offset, length))));
f67539c2
TL
231 }
232
233 void expect_get_parent_overlap(uint64_t overlap) {
234 EXPECT_CALL(*mock_image_ctx, get_parent_overlap(_, _))
235 .WillOnce(WithArg<1>(Invoke([overlap](uint64_t *o) {
236 *o = overlap;
237 return 0;
238 })));
239 }
240
241 void expect_prune_parent_extents(uint64_t object_overlap) {
1e59de90 242 EXPECT_CALL(*mock_image_ctx, prune_parent_extents(_, _, _, _))
f67539c2
TL
243 .WillOnce(Return(object_overlap));
244 }
245
246 void expect_copyup(MockAbstractObjectWriteRequest** write_request, int r) {
247 EXPECT_CALL(copyup_request, append_request(_, _))
248 .WillOnce(WithArg<0>(
249 Invoke([write_request](
250 MockAbstractObjectWriteRequest *req) {
251 *write_request = req;
252 })));
253 EXPECT_CALL(copyup_request, send())
254 .WillOnce(Invoke([write_request, r]() {
255 (*write_request)->handle_copyup(r);
256 }));
257 }
258
259 void expect_encrypt(int count = 1) {
1e59de90 260 EXPECT_CALL(crypto, encrypt(_, _)).Times(count);
f67539c2
TL
261 }
262
263 void expect_decrypt(int count = 1) {
1e59de90 264 EXPECT_CALL(crypto, decrypt(_, _)).Times(count);
f67539c2
TL
265 }
266};
267
268TEST_F(TestMockCryptoCryptoObjectDispatch, Flush) {
269 ASSERT_FALSE(mock_crypto_object_dispatch->flush(
270 io::FLUSH_SOURCE_USER, {}, nullptr, nullptr, &on_finish, nullptr));
271 ASSERT_EQ(on_finish, &finished_cond); // not modified
272 on_finish->complete(0);
273 ASSERT_EQ(0, finished_cond.wait());
274}
275
276TEST_F(TestMockCryptoCryptoObjectDispatch, Discard) {
277 expect_object_write_same();
278 ASSERT_TRUE(mock_crypto_object_dispatch->discard(
1e59de90 279 11, 0, 4096, mock_image_ctx->get_data_io_context(), 0, {},
f67539c2
TL
280 &object_dispatch_flags, nullptr, &dispatch_result, &on_finish,
281 on_dispatched));
282 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
283
284 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
285 dispatcher_ctx->complete(0);
286 ASSERT_EQ(0, dispatched_cond.wait());
287}
288
289TEST_F(TestMockCryptoCryptoObjectDispatch, AlignedReadFail) {
290 io::ReadExtents extents = {{0, 4096}};
291 expect_object_read(&extents);
292 ASSERT_TRUE(mock_crypto_object_dispatch->read(
1e59de90 293 11, &extents, mock_image_ctx->get_data_io_context(), 0, 0, {},
f67539c2
TL
294 nullptr, &object_dispatch_flags, &dispatch_result,
295 &on_finish, on_dispatched));
296 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
297 ASSERT_EQ(on_finish, &finished_cond);
298
299 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
300 dispatcher_ctx->complete(-EIO);
301 ASSERT_EQ(-EIO, dispatched_cond.wait());
302}
303
304TEST_F(TestMockCryptoCryptoObjectDispatch, AlignedRead) {
305 io::ReadExtents extents = {{0, 16384}, {32768, 4096}};
306 extents[0].bl.append(std::string(1024, '1') + std::string(1024, '2') +
307 std::string(1024, '3') + std::string(1024, '4'));
308 extents[0].extent_map = {{1024, 1024}, {3072, 2048}, {16384 - 1024, 1024}};
309 extents[1].bl.append(std::string(4096, '0'));
310 expect_object_read(&extents);
311 ASSERT_TRUE(mock_crypto_object_dispatch->read(
1e59de90 312 11, &extents, mock_image_ctx->get_data_io_context(), 0, 0, {},
f67539c2
TL
313 nullptr, &object_dispatch_flags, &dispatch_result,
314 &on_finish, on_dispatched));
315 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
316 ASSERT_EQ(on_finish, &finished_cond);
317 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
318
319 expect_decrypt(3);
320 dispatcher_ctx->complete(0);
321 ASSERT_EQ(16384 + 4096, dispatched_cond.wait());
322
323 auto expected_bl_data = (
324 std::string(1024, '\0') + std::string(1024, '1') +
325 std::string(1024, '\0') + std::string(1024, '2') +
326 std::string(1024, '3') + std::string(3072, '\0') +
327 std::string(3072, '\0') + std::string(1024, '4'));
328 ASSERT_TRUE(extents[0].bl.to_str() == expected_bl_data);
329 ASSERT_THAT(extents[0].extent_map,
330 ElementsAre(Pair(0, 8192), Pair(16384 - 4096, 4096)));
331}
332
333TEST_F(TestMockCryptoCryptoObjectDispatch, ReadFromParent) {
334 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
335 expect_object_read(&extents);
1e59de90 336 expect_read_parent(mock_utils, 11, &extents, CEPH_NOSNAP, 8192);
f67539c2 337 ASSERT_TRUE(mock_crypto_object_dispatch->read(
1e59de90 338 11, &extents, mock_image_ctx->get_data_io_context(), 0, 0, {},
f67539c2
TL
339 nullptr, &object_dispatch_flags, &dispatch_result,
340 &on_finish, on_dispatched));
341 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
342 ASSERT_EQ(on_finish, &finished_cond);
343 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
344
345 // no decrypt
346 dispatcher_ctx->complete(-ENOENT);
347 ASSERT_EQ(8192, dispatched_cond.wait());
348}
349
350TEST_F(TestMockCryptoCryptoObjectDispatch, ReadFromParentDisabled) {
351 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
352 expect_object_read(&extents);
353 ASSERT_TRUE(mock_crypto_object_dispatch->read(
1e59de90 354 11, &extents, mock_image_ctx->get_data_io_context(), 0,
f67539c2
TL
355 io::READ_FLAG_DISABLE_READ_FROM_PARENT, {},
356 nullptr, &object_dispatch_flags, &dispatch_result,
357 &on_finish, on_dispatched));
358 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
359 ASSERT_EQ(on_finish, &finished_cond);
360 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
361
362 // no decrypt
363 dispatcher_ctx->complete(-ENOENT);
364 ASSERT_EQ(-ENOENT, dispatched_cond.wait());
365}
366
367TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedRead) {
368 io::ReadExtents extents = {{0, 1}, {8191, 1}, {8193, 1},
369 {16384 + 1, 4096 * 5 - 2}};
370 io::ReadExtents aligned_extents = {{0, 4096}, {4096, 4096}, {8192, 4096},
371 {16384, 4096 * 5}};
372 aligned_extents[0].bl.append(std::string("1") + std::string(4096, '0'));
373 aligned_extents[1].bl.append(std::string(4095, '0') + std::string("2"));
374 aligned_extents[2].bl.append(std::string("03") + std::string(4094, '0'));
375 aligned_extents[3].bl.append(std::string("0") + std::string(4095, '4') +
376 std::string(4096, '5') +
377 std::string(4095, '6') + std::string("0"));
378 aligned_extents[3].extent_map = {{16384, 4096}, {16384 + 2 * 4096, 4096},
379 {16384 + 4 * 4096, 4096}};
380
381 expect_object_read(&aligned_extents);
382 ASSERT_TRUE(mock_crypto_object_dispatch->read(
1e59de90 383 11, &extents, mock_image_ctx->get_data_io_context(), 0, 0, {},
f67539c2
TL
384 nullptr, &object_dispatch_flags, &dispatch_result,
385 &on_finish, on_dispatched));
386 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
387 ASSERT_EQ(on_finish, &finished_cond);
388 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
389
390 dispatcher_ctx->complete(4096*8);
391 ASSERT_EQ(3 + 4096 * 5 - 2, dispatched_cond.wait());
392 ASSERT_TRUE(extents[0].bl.to_str() == std::string("1"));
393 ASSERT_TRUE(extents[1].bl.to_str() == std::string("2"));
394 ASSERT_TRUE(extents[2].bl.to_str() == std::string("3"));
395
396 auto expected_bl_data = (std::string(4095, '4') + std::string(4096, '5') +
397 std::string(4095, '6'));
398 ASSERT_TRUE(extents[3].bl.to_str() == expected_bl_data);
399 ASSERT_THAT(extents[3].extent_map,
400 ElementsAre(Pair(16384 + 1, 4095), Pair(16384 + 2 * 4096, 4096),
401 Pair(16384 + 4 * 4096, 4095)));
402}
403
404TEST_F(TestMockCryptoCryptoObjectDispatch, AlignedWrite) {
405 expect_encrypt();
406 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 407 11, 0, std::move(data), mock_image_ctx->get_data_io_context(), 0, 0,
f67539c2
TL
408 std::nullopt, {}, nullptr, nullptr, &dispatch_result, &on_finish,
409 on_dispatched));
410 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_CONTINUE);
411 ASSERT_EQ(on_finish, &finished_cond); // not modified
412 on_finish->complete(0);
413 ASSERT_EQ(0, finished_cond.wait());
414}
415
416TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWrite) {
417 ceph::bufferlist write_data;
418 uint64_t version = 1234;
419 write_data.append(std::string(8192, '1'));
420 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
421 extents[0].bl.append(std::string(4096, '2'));
422 extents[1].bl.append(std::string(4096, '3'));
423 expect_object_read(&extents, version);
424 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 425 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
426 0, 0, std::nullopt, {}, nullptr, nullptr, &dispatch_result,
427 &on_finish, on_dispatched));
428 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
429 ASSERT_EQ(on_finish, &finished_cond);
430
431 auto expected_data =
432 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
433 expect_object_write(0, expected_data, 0, std::make_optional(version));
434 dispatcher_ctx->complete(8192); // complete read
435 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
436 dispatcher_ctx->complete(0); // complete write
437 ASSERT_EQ(0, dispatched_cond.wait());
438}
439
440TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteWithNoObject) {
441 ceph::bufferlist write_data;
442 write_data.append(std::string(8192, '1'));
443 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
444 expect_object_read(&extents);
445 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 446 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
447 0, 0, std::nullopt, {}, nullptr, nullptr, &dispatch_result,
448 &on_finish, on_dispatched));
449 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
450 ASSERT_EQ(on_finish, &finished_cond);
451
452 expect_get_object_size();
453 expect_get_parent_overlap(0);
454 auto expected_data = (std::string(1, '\0') + std::string(8192, '1') +
455 std::string(4095, '\0'));
456 expect_object_write(0, expected_data, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE,
457 std::nullopt);
458 dispatcher_ctx->complete(-ENOENT); // complete read
459 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
460 dispatcher_ctx->complete(0); // complete write
461 ASSERT_EQ(0, dispatched_cond.wait());
462}
463
464TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteFailCreate) {
465 ceph::bufferlist write_data;
466 write_data.append(std::string(8192, '1'));
467 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
468 expect_object_read(&extents);
469 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 470 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
471 0, 0, std::nullopt, {}, nullptr, nullptr, &dispatch_result,
472 &on_finish, on_dispatched));
473 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
474 ASSERT_EQ(on_finish, &finished_cond);
475
476 expect_get_object_size();
477 expect_get_parent_overlap(0);
478 auto expected_data = (std::string(1, '\0') + std::string(8192, '1') +
479 std::string(4095, '\0'));
480 expect_object_write(0, expected_data, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE,
481 std::nullopt);
482 dispatcher_ctx->complete(-ENOENT); // complete read
483 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
484
485 extents[0].bl.append(std::string(4096, '2'));
486 extents[1].bl.append(std::string(4096, '3'));
487 uint64_t version = 1234;
488 expect_object_read(&extents, version);
489 dispatcher_ctx->complete(-EEXIST); // complete write, request will restart
490 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
491
492 auto expected_data2 =
493 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
494 expect_object_write(0, expected_data2, 0, std::make_optional(version));
495 dispatcher_ctx->complete(8192); // complete read
496 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
497 dispatcher_ctx->complete(0); // complete write
498 ASSERT_EQ(0, dispatched_cond.wait());
499}
500
501TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteCopyup) {
502 MockObjectMap mock_object_map;
503 mock_image_ctx->object_map = &mock_object_map;
504 MockExclusiveLock mock_exclusive_lock;
505 mock_image_ctx->exclusive_lock = &mock_exclusive_lock;
506
507 ceph::bufferlist write_data;
508 write_data.append(std::string(8192, '1'));
509 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
510 expect_object_read(&extents);
511 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 512 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
513 0, 0, std::nullopt, {}, nullptr, nullptr, &dispatch_result,
514 &on_finish, on_dispatched));
515 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
516 ASSERT_EQ(on_finish, &finished_cond);
517
518 expect_get_object_size();
1e59de90
TL
519 expect_get_parent_overlap(100 << 20);
520 expect_remap_to_logical(11 * mock_image_ctx->layout.object_size,
521 mock_image_ctx->layout.object_size);
f67539c2
TL
522 expect_prune_parent_extents(mock_image_ctx->layout.object_size);
523 EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillRepeatedly(
524 Return(true));
1e59de90 525 EXPECT_CALL(*mock_image_ctx->object_map, object_may_exist(11)).WillOnce(
f67539c2
TL
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
547TEST_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(
1e59de90 558 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
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();
1e59de90
TL
565 expect_get_parent_overlap(100 << 20);
566 expect_remap_to_logical(11 * mock_image_ctx->layout.object_size,
567 mock_image_ctx->layout.object_size);
f67539c2
TL
568 expect_prune_parent_extents(mock_image_ctx->layout.object_size);
569 EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillRepeatedly(
570 Return(true));
1e59de90 571 EXPECT_CALL(*mock_image_ctx->object_map, object_may_exist(11)).WillOnce(
f67539c2
TL
572 Return(false));
573 MockAbstractObjectWriteRequest *write_request = nullptr;
574 expect_copyup(&write_request, 0);
575
576 // unaligned write restarted
577 expect_object_read(&extents);
578 dispatcher_ctx->complete(-ENOENT); // complete first read
579 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
580
581 auto expected_data =
582 std::string(1, '\0') + std::string(8192, '1') +
583 std::string(4095, '\0');
584 expect_object_write(0, expected_data, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE,
585 std::nullopt);
586 dispatcher_ctx->complete(-ENOENT); // complete second read
587 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
588 dispatcher_ctx->complete(0); // complete write
589 ASSERT_EQ(0, dispatched_cond.wait());
590}
591
592TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteFailVersionCheck) {
593 ceph::bufferlist write_data;
594 uint64_t version = 1234;
595 write_data.append(std::string(8192, '1'));
596 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
597 extents[0].bl.append(std::string(4096, '2'));
598 extents[1].bl.append(std::string(4096, '3'));
599 expect_object_read(&extents, version);
600 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 601 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
602 0, 0, std::nullopt, {}, nullptr, nullptr, &dispatch_result,
603 &on_finish, on_dispatched));
604 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
605 ASSERT_EQ(on_finish, &finished_cond);
606
607 auto expected_data =
608 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
609 expect_object_write(0, expected_data, 0, std::make_optional(version));
610 dispatcher_ctx->complete(8192); // complete read
611 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
612
613 version = 1235;
614 expect_object_read(&extents, version);
615 extents[0].bl.append(std::string(4096, '2'));
616 extents[1].bl.append(std::string(4096, '3'));
617 dispatcher_ctx->complete(-ERANGE); // complete write, request will restart
618 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
619
620 expect_object_write(0, expected_data, 0, std::make_optional(version));
621 dispatcher_ctx->complete(8192); // complete read
622 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
623 dispatcher_ctx->complete(0); // complete write
624 ASSERT_EQ(0, dispatched_cond.wait());
625}
626
627TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteWithAssertVersion) {
628 ceph::bufferlist write_data;
629 uint64_t version = 1234;
630 uint64_t assert_version = 1233;
631 write_data.append(std::string(8192, '1'));
632 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
633 extents[0].bl.append(std::string(4096, '2'));
634 extents[1].bl.append(std::string(4096, '3'));
635 expect_object_read(&extents, version);
636 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 637 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
638 0, 0, std::make_optional(assert_version), {}, nullptr, nullptr,
639 &dispatch_result, &on_finish, on_dispatched));
640 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
641 ASSERT_EQ(on_finish, &finished_cond);
642
643 dispatcher_ctx->complete(8192); // complete read
644 ASSERT_EQ(-ERANGE, dispatched_cond.wait());
645}
646
647TEST_F(TestMockCryptoCryptoObjectDispatch, UnalignedWriteWithExclusiveCreate) {
648 ceph::bufferlist write_data;
649 write_data.append(std::string(8192, '1'));
650 io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
651 extents[0].bl.append(std::string(4096, '2'));
652 extents[1].bl.append(std::string(4096, '3'));
653 expect_object_read(&extents);
654 ASSERT_TRUE(mock_crypto_object_dispatch->write(
1e59de90 655 11, 1, std::move(write_data), mock_image_ctx->get_data_io_context(),
f67539c2
TL
656 0, io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE, std::nullopt, {}, nullptr,
657 nullptr, &dispatch_result, &on_finish, on_dispatched));
658 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
659 ASSERT_EQ(on_finish, &finished_cond);
660
661 dispatcher_ctx->complete(8192); // complete read
662 ASSERT_EQ(-EEXIST, dispatched_cond.wait());
663}
664
665TEST_F(TestMockCryptoCryptoObjectDispatch, CompareAndWrite) {
666 ceph::bufferlist write_data;
667 uint64_t version = 1234;
668 write_data.append(std::string(8192, '1'));
669 ceph::bufferlist cmp_data;
670 cmp_data.append(std::string(4096, '2'));
671 io::ReadExtents extents = {{0, 4096}, {8192, 4096}, {0, 8192}};
672 extents[0].bl.append(std::string(4096, '2'));
673 extents[1].bl.append(std::string(4096, '3'));
674 extents[2].bl.append(std::string(8192, '2'));
675 expect_object_read(&extents, version);
676
677 ASSERT_TRUE(mock_crypto_object_dispatch->compare_and_write(
1e59de90 678 11, 1, std::move(cmp_data), std::move(write_data),
f67539c2
TL
679 mock_image_ctx->get_data_io_context(), 0, {}, nullptr, nullptr,
680 nullptr, &dispatch_result, &on_finish, on_dispatched));
681 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
682 ASSERT_EQ(on_finish, &finished_cond);
683
684 auto expected_data =
685 std::string("2") + std::string(8192, '1') + std::string(4095, '3');
686 expect_object_write(0, expected_data, 0, std::make_optional(version));
687 dispatcher_ctx->complete(4096*4); // complete read
688 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
689 dispatcher_ctx->complete(0); // complete write
690 ASSERT_EQ(0, dispatched_cond.wait());
691}
692
693TEST_F(TestMockCryptoCryptoObjectDispatch, CompareAndWriteFail) {
694 ceph::bufferlist write_data;
695 uint64_t version = 1234;
696 write_data.append(std::string(8192, '1'));
697 ceph::bufferlist cmp_data;
698 cmp_data.append(std::string(4094, '2') + std::string(2, '4'));
699 io::ReadExtents extents = {{0, 4096}, {8192, 4096}, {0, 8192}};
700 extents[0].bl.append(std::string(4096, '2'));
701 extents[1].bl.append(std::string(4096, '3'));
702 extents[2].bl.append(std::string(8192, '2'));
703 expect_object_read(&extents, version);
704
705 uint64_t mismatch_offset;
706 ASSERT_TRUE(mock_crypto_object_dispatch->compare_and_write(
1e59de90 707 11, 1, std::move(cmp_data), std::move(write_data),
f67539c2
TL
708 mock_image_ctx->get_data_io_context(), 0, {}, &mismatch_offset,
709 nullptr, nullptr, &dispatch_result, &on_finish, on_dispatched));
710 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
711 ASSERT_EQ(on_finish, &finished_cond);
712
713 dispatcher_ctx->complete(4096*4); // complete read
714 ASSERT_EQ(-EILSEQ, dispatched_cond.wait());
715 ASSERT_EQ(mismatch_offset, 4094);
716}
717
718TEST_F(TestMockCryptoCryptoObjectDispatch, WriteSame) {
719 io::LightweightBufferExtents buffer_extents;
720 ceph::bufferlist write_data;
721 write_data.append(std::string("12"));
722 expect_object_write(0, std::string("12121") , 0, std::nullopt);
723 ASSERT_TRUE(mock_crypto_object_dispatch->write_same(
1e59de90 724 11, 0, 5, {{0, 5}}, std::move(write_data),
f67539c2
TL
725 mock_image_ctx->get_data_io_context(), 0, {}, nullptr, nullptr,
726 &dispatch_result, &on_finish, on_dispatched));
727 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
728
729 ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
730 dispatcher_ctx->complete(0);
731 ASSERT_EQ(0, dispatched_cond.wait());
732}
733
734TEST_F(TestMockCryptoCryptoObjectDispatch, PrepareCopyup) {
735 char* data = (char*)"0123456789";
736 io::SnapshotSparseBufferlist snapshot_sparse_bufferlist;
737 auto& snap1 = snapshot_sparse_bufferlist[0];
738 auto& snap2 = snapshot_sparse_bufferlist[1];
739
740 snap1.insert(0, 1, {io::SPARSE_EXTENT_STATE_DATA, 1,
741 ceph::bufferlist::static_from_mem(data + 1, 1)});
742 snap1.insert(8191, 1, {io::SPARSE_EXTENT_STATE_DATA, 1,
743 ceph::bufferlist::static_from_mem(data + 2, 1)});
744 snap1.insert(8193, 3, {io::SPARSE_EXTENT_STATE_DATA, 3,
745 ceph::bufferlist::static_from_mem(data + 3, 3)});
746
747 snap2.insert(0, 2, {io::SPARSE_EXTENT_STATE_ZEROED, 2});
748 snap2.insert(8191, 3, {io::SPARSE_EXTENT_STATE_DATA, 3,
749 ceph::bufferlist::static_from_mem(data + 6, 3)});
750 snap2.insert(16384, 1, {io::SPARSE_EXTENT_STATE_DATA, 1,
751 ceph::bufferlist::static_from_mem(data + 9, 1)});
752
753 expect_get_object_size();
754 expect_encrypt(6);
755 InSequence seq;
1e59de90
TL
756 uint64_t base = 11 * mock_image_ctx->layout.object_size;
757 expect_remap_to_logical(base, 4096);
758 expect_remap_to_logical(base + 4096, 4096);
759 expect_remap_to_logical(base + 8192, 4096);
760 expect_remap_to_logical(base, 4096);
761 expect_remap_to_logical(base + 4096, 8192);
762 expect_remap_to_logical(base + 16384, 4096);
f67539c2 763 ASSERT_EQ(0, mock_crypto_object_dispatch->prepare_copyup(
1e59de90 764 11, &snapshot_sparse_bufferlist));
f67539c2
TL
765
766 ASSERT_EQ(2, snapshot_sparse_bufferlist.size());
767
768 auto& snap1_result = snapshot_sparse_bufferlist[0];
769 auto& snap2_result = snapshot_sparse_bufferlist[1];
770
771 auto it = snap1_result.begin();
772 ASSERT_NE(it, snap1_result.end());
773 ASSERT_EQ(0, it.get_off());
774 ASSERT_EQ(4096 * 3, it.get_len());
775
776 ASSERT_TRUE(it.get_val().bl.to_str() ==
777 std::string("1") + std::string(4095, '\0') +
778 std::string(4095, '\0') + std::string("2") +
779 std::string(1, '\0') + std::string("345") + std::string(4092, '\0'));
780 ASSERT_EQ(++it, snap1_result.end());
781
782 it = snap2_result.begin();
783 ASSERT_NE(it, snap2_result.end());
784 ASSERT_EQ(0, it.get_off());
785 ASSERT_EQ(4096 * 3, it.get_len());
786 ASSERT_TRUE(it.get_val().bl.to_str() ==
787 std::string(4096, '\0') +
788 std::string(4095, '\0') + std::string("6") +
789 std::string("7845") + std::string(4092, '\0'));
790
791 ASSERT_NE(++it, snap2_result.end());
792 ASSERT_EQ(16384, it.get_off());
793 ASSERT_EQ(4096, it.get_len());
794 ASSERT_TRUE(it.get_val().bl.to_str() ==
795 std::string("9") + std::string(4095, '\0'));
796 ASSERT_EQ(++it, snap2_result.end());
797}
798
1e59de90 799} // namespace crypto
f67539c2 800} // namespace librbd