]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_CopyupRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librbd / io / test_mock_CopyupRequest.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/MockExclusiveLock.h"
7 #include "test/librbd/mock/MockImageCtx.h"
8 #include "test/librbd/mock/MockJournal.h"
9 #include "test/librbd/mock/MockObjectMap.h"
10 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
11 #include "test/librados_test_stub/MockTestMemRadosClient.h"
12 #include "include/rbd/librbd.hpp"
13 #include "librbd/api/Io.h"
14 #include "librbd/deep_copy/ObjectCopyRequest.h"
15 #include "librbd/io/CopyupRequest.h"
16 #include "librbd/io/ImageDispatchSpec.h"
17 #include "librbd/io/ObjectRequest.h"
18 #include "librbd/io/ReadResult.h"
19 #include "librbd/io/Utils.h"
20
21 namespace librbd {
22 namespace {
23
24 struct MockTestImageCtx : public MockImageCtx {
25 MockTestImageCtx(ImageCtx &image_ctx,
26 MockTestImageCtx* mock_parent_image_ctx = nullptr)
27 : MockImageCtx(image_ctx) {
28 parent = mock_parent_image_ctx;
29 }
30 ~MockTestImageCtx() override {
31 // copyups need to complete prior to attempting to delete this object
32 wait_for_async_ops();
33 }
34
35 std::map<uint64_t, librbd::io::CopyupRequest<librbd::MockTestImageCtx>*> copyup_list;
36 };
37
38 } // anonymous namespace
39
40 namespace util {
41
42 inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
43 return image_ctx->image_ctx;
44 }
45
46 } // namespace util
47
48 namespace deep_copy {
49
50 template <>
51 struct ObjectCopyRequest<librbd::MockTestImageCtx> {
52 static ObjectCopyRequest* s_instance;
53 static ObjectCopyRequest* create(librbd::MockImageCtx* parent_image_ctx,
54 librbd::MockTestImageCtx* image_ctx,
55 librados::snap_t src_snap_id_start,
56 librados::snap_t dst_snap_id_start,
57 const SnapMap &snap_map,
58 uint64_t object_number, uint32_t flags,
59 Handler*, Context *on_finish) {
60 ceph_assert(s_instance != nullptr);
61 s_instance->object_number = object_number;
62 s_instance->flatten = (
63 (flags & deep_copy::OBJECT_COPY_REQUEST_FLAG_FLATTEN) != 0);
64 s_instance->on_finish = on_finish;
65 return s_instance;
66 }
67
68 uint64_t object_number;
69 bool flatten;
70 Context *on_finish;
71
72 ObjectCopyRequest() {
73 s_instance = this;
74 }
75
76 MOCK_METHOD0(send, void());
77 };
78
79 ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
80
81 } // namespace deep_copy
82
83 namespace io {
84
85 namespace util {
86
87 template <>
88 void area_to_object_extents(MockTestImageCtx* image_ctx, uint64_t offset,
89 uint64_t length, ImageArea area,
90 uint64_t buffer_offset,
91 striper::LightweightObjectExtents* object_extents) {
92 Striper::file_to_extents(image_ctx->cct, &image_ctx->layout, offset, length,
93 0, buffer_offset, object_extents);
94 }
95
96 template <>
97 std::pair<Extents, ImageArea> object_to_area_extents(
98 MockTestImageCtx* image_ctx, uint64_t object_no,
99 const Extents& object_extents) {
100 Extents extents;
101 for (auto [off, len] : object_extents) {
102 Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no, off,
103 len, extents);
104 }
105 return {std::move(extents), ImageArea::DATA};
106 }
107
108 } // namespace util
109
110 template <>
111 struct ObjectRequest<librbd::MockTestImageCtx> {
112 static void add_write_hint(librbd::MockTestImageCtx&,
113 neorados::WriteOp*) {
114 }
115 };
116
117 template <>
118 struct AbstractObjectWriteRequest<librbd::MockTestImageCtx> {
119 C_SaferCond ctx;
120 void handle_copyup(int r) {
121 ctx.complete(r);
122 }
123
124 MOCK_CONST_METHOD0(get_pre_write_object_map_state, uint8_t());
125 MOCK_CONST_METHOD0(is_empty_write_op, bool());
126
127 MOCK_METHOD1(add_copyup_ops, void(neorados::WriteOp*));
128 };
129
130 } // namespace io
131 } // namespace librbd
132
133 static bool operator==(const SnapContext& rhs, const SnapContext& lhs) {
134 return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps);
135 }
136
137 #include "librbd/AsyncObjectThrottle.cc"
138 #include "librbd/io/CopyupRequest.cc"
139
140 MATCHER_P(IsRead, image_extents, "") {
141 auto req = boost::get<librbd::io::ImageDispatchSpec::Read>(&arg->request);
142 return (req != nullptr && image_extents == arg->image_extents);
143 }
144
145 namespace librbd {
146 namespace io {
147
148 using ::testing::_;
149 using ::testing::InSequence;
150 using ::testing::Invoke;
151 using ::testing::Return;
152 using ::testing::StrEq;
153 using ::testing::WithArg;
154 using ::testing::WithArgs;
155 using ::testing::WithoutArgs;
156
157 struct TestMockIoCopyupRequest : public TestMockFixture {
158 typedef CopyupRequest<librbd::MockTestImageCtx> MockCopyupRequest;
159 typedef ObjectRequest<librbd::MockTestImageCtx> MockObjectRequest;
160 typedef AbstractObjectWriteRequest<librbd::MockTestImageCtx> MockAbstractObjectWriteRequest;
161 typedef deep_copy::ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
162
163 void SetUp() override {
164 TestMockFixture::SetUp();
165 if (!is_feature_enabled(RBD_FEATURE_LAYERING)) {
166 return;
167 }
168
169 m_parent_image_name = m_image_name;
170 m_image_name = get_temp_image_name();
171
172 librbd::Image image;
173 librbd::RBD rbd;
174 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_parent_image_name.c_str(),
175 nullptr));
176 ASSERT_EQ(0, image.snap_create("one"));
177 ASSERT_EQ(0, image.snap_protect("one"));
178
179 uint64_t features;
180 ASSERT_EQ(0, image.features(&features));
181 image.close();
182
183 int order = 0;
184 ASSERT_EQ(0, rbd.clone(m_ioctx, m_parent_image_name.c_str(), "one", m_ioctx,
185 m_image_name.c_str(), features, &order));
186 }
187
188 void expect_get_parent_overlap(MockTestImageCtx& mock_image_ctx,
189 librados::snap_t snap_id, uint64_t overlap,
190 int r) {
191 EXPECT_CALL(mock_image_ctx, get_parent_overlap(snap_id, _))
192 .WillOnce(WithArg<1>(Invoke([overlap, r](uint64_t *o) {
193 *o = overlap;
194 return r;
195 })));
196 }
197
198 void expect_prune_parent_extents(MockTestImageCtx& mock_image_ctx,
199 uint64_t overlap, uint64_t object_overlap) {
200 EXPECT_CALL(mock_image_ctx, prune_parent_extents(_, _, overlap, _))
201 .WillOnce(WithoutArgs(Invoke([object_overlap]() {
202 return object_overlap;
203 })));
204 }
205
206 void expect_read_parent(librbd::MockTestImageCtx& mock_image_ctx,
207 const Extents& image_extents,
208 const std::string& data, int r) {
209 EXPECT_CALL(*mock_image_ctx.io_image_dispatcher,
210 send(IsRead(image_extents)))
211 .WillOnce(Invoke(
212 [&mock_image_ctx, image_extents, data, r](io::ImageDispatchSpec* spec) {
213 auto req = boost::get<librbd::io::ImageDispatchSpec::Read>(
214 &spec->request);
215 ASSERT_TRUE(req != nullptr);
216
217 if (r < 0) {
218 spec->fail(r);
219 return;
220 }
221
222 spec->dispatch_result = DISPATCH_RESULT_COMPLETE;
223
224 auto aio_comp = spec->aio_comp;
225 aio_comp->read_result = std::move(req->read_result);
226 aio_comp->read_result.set_image_extents(image_extents);
227 aio_comp->set_request_count(1);
228 auto ctx = new ReadResult::C_ImageReadRequest(aio_comp, 0,
229 image_extents);
230 ctx->bl.append(data);
231 mock_image_ctx.image_ctx->op_work_queue->queue(ctx, r);
232 }));
233 }
234
235 void expect_copyup(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
236 const std::string& oid, const std::string& data, int r) {
237 bufferlist in_bl;
238 in_bl.append(data);
239
240 SnapContext snapc;
241 if (snap_id == CEPH_NOSNAP) {
242 snapc = mock_image_ctx.snapc;
243 }
244
245 auto& mock_io_ctx = librados::get_mock_io_ctx(
246 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
247 EXPECT_CALL(mock_io_ctx,
248 exec(oid, _, StrEq("rbd"), StrEq("copyup"),
249 ContentsEqual(in_bl), _, _, snapc))
250 .WillOnce(Return(r));
251 }
252
253 void expect_sparse_copyup(MockTestImageCtx &mock_image_ctx, uint64_t snap_id,
254 const std::string &oid,
255 const std::map<uint64_t, uint64_t> &extent_map,
256 const std::string &data, int r) {
257 bufferlist data_bl;
258 data_bl.append(data);
259
260 bufferlist in_bl;
261 encode(extent_map, in_bl);
262 encode(data_bl, in_bl);
263
264 SnapContext snapc;
265 if (snap_id == CEPH_NOSNAP) {
266 snapc = mock_image_ctx.snapc;
267 }
268
269 auto& mock_io_ctx = librados::get_mock_io_ctx(
270 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
271 EXPECT_CALL(mock_io_ctx,
272 exec(oid, _, StrEq("rbd"), StrEq("sparse_copyup"),
273 ContentsEqual(in_bl), _, _, snapc))
274 .WillOnce(Return(r));
275 }
276
277 void expect_write(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
278 const std::string& oid, int r) {
279 SnapContext snapc;
280 if (snap_id == CEPH_NOSNAP) {
281 snapc = mock_image_ctx.snapc;
282 }
283
284 auto& mock_io_ctx = librados::get_mock_io_ctx(
285 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
286 EXPECT_CALL(mock_io_ctx, write(oid, _, 0, 0, snapc))
287 .WillOnce(Return(r));
288 }
289
290 void expect_test_features(MockTestImageCtx& mock_image_ctx) {
291 EXPECT_CALL(mock_image_ctx, test_features(_, _))
292 .WillRepeatedly(WithArg<0>(Invoke([&mock_image_ctx](uint64_t features) {
293 return (mock_image_ctx.features & features) != 0;
294 })));
295 }
296
297 void expect_is_lock_owner(MockTestImageCtx& mock_image_ctx) {
298 if (mock_image_ctx.exclusive_lock != nullptr) {
299 EXPECT_CALL(*mock_image_ctx.exclusive_lock,
300 is_lock_owner()).WillRepeatedly(Return(true));
301 }
302 }
303
304 void expect_is_empty_write_op(MockAbstractObjectWriteRequest& mock_write_request,
305 bool is_empty) {
306 EXPECT_CALL(mock_write_request, is_empty_write_op())
307 .WillOnce(Return(is_empty));
308 }
309
310 void expect_add_copyup_ops(MockAbstractObjectWriteRequest& mock_write_request) {
311 EXPECT_CALL(mock_write_request, add_copyup_ops(_))
312 .WillOnce(Invoke([](neorados::WriteOp* op) {
313 op->write(0, bufferlist{});
314 }));
315 }
316
317 void expect_get_pre_write_object_map_state(MockTestImageCtx& mock_image_ctx,
318 MockAbstractObjectWriteRequest& mock_write_request,
319 uint8_t state) {
320 if (mock_image_ctx.object_map != nullptr) {
321 EXPECT_CALL(mock_write_request, get_pre_write_object_map_state())
322 .WillOnce(Return(state));
323 }
324 }
325
326 void expect_object_map_at(MockTestImageCtx& mock_image_ctx,
327 uint64_t object_no, uint8_t state) {
328 if (mock_image_ctx.object_map != nullptr) {
329 EXPECT_CALL(*mock_image_ctx.object_map, at(object_no))
330 .WillOnce(Return(state));
331 }
332 }
333
334 void expect_object_map_update(MockTestImageCtx& mock_image_ctx,
335 uint64_t snap_id, uint64_t object_no,
336 uint8_t state, bool updated, int ret_val) {
337 if (mock_image_ctx.object_map != nullptr) {
338 if (!mock_image_ctx.image_ctx->test_features(RBD_FEATURE_FAST_DIFF) &&
339 state == OBJECT_EXISTS_CLEAN) {
340 state = OBJECT_EXISTS;
341 }
342
343 EXPECT_CALL(*mock_image_ctx.object_map,
344 aio_update(snap_id, object_no, object_no + 1, state,
345 boost::optional<uint8_t>(), _,
346 (snap_id != CEPH_NOSNAP), _))
347 .WillOnce(WithArg<7>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) {
348 if (updated) {
349 mock_image_ctx.op_work_queue->queue(ctx, ret_val);
350 }
351 return updated;
352 })));
353 }
354 }
355
356 void expect_object_copy(MockTestImageCtx& mock_image_ctx,
357 MockObjectCopyRequest& mock_object_copy_request,
358 bool flatten, int r) {
359 EXPECT_CALL(mock_object_copy_request, send())
360 .WillOnce(Invoke(
361 [&mock_image_ctx, &mock_object_copy_request, flatten, r]() {
362 ASSERT_EQ(flatten, mock_object_copy_request.flatten);
363 mock_image_ctx.op_work_queue->queue(
364 mock_object_copy_request.on_finish, r);
365 }));
366 }
367
368 void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx, int r = 0) {
369 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher,
370 prepare_copyup(_, _)).WillOnce(Return(r));
371 }
372
373 void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx,
374 const SparseBufferlist& in_sparse_bl,
375 const SparseBufferlist& out_sparse_bl) {
376 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher,
377 prepare_copyup(_, _))
378 .WillOnce(WithArg<1>(Invoke(
379 [in_sparse_bl, out_sparse_bl]
380 (SnapshotSparseBufferlist* snap_sparse_bl) {
381 auto& sparse_bl = (*snap_sparse_bl)[0];
382 EXPECT_EQ(in_sparse_bl, sparse_bl);
383
384 sparse_bl = out_sparse_bl;
385 return 0;
386 })));
387 }
388
389 void flush_async_operations(librbd::ImageCtx* ictx) {
390 api::Io<>::flush(*ictx);
391 }
392
393 std::string m_parent_image_name;
394 };
395
396 TEST_F(TestMockIoCopyupRequest, Standard) {
397 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
398
399 librbd::ImageCtx *ictx;
400 ASSERT_EQ(0, open_image(m_image_name, &ictx));
401
402 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
403 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
404
405 MockExclusiveLock mock_exclusive_lock;
406 MockJournal mock_journal;
407 MockObjectMap mock_object_map;
408 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
409 mock_object_map);
410
411 expect_op_work_queue(mock_image_ctx);
412 expect_is_lock_owner(mock_image_ctx);
413
414 InSequence seq;
415
416 std::string data(4096, '1');
417 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
418 expect_prepare_copyup(mock_image_ctx);
419
420 MockAbstractObjectWriteRequest mock_write_request;
421 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
422 OBJECT_EXISTS);
423 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
424 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
425 0);
426
427 expect_add_copyup_ops(mock_write_request);
428 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
429 {{0, 4096}}, data, 0);
430 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
431
432 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
433 ImageArea::DATA, {});
434 mock_image_ctx.copyup_list[0] = req;
435 req->append_request(&mock_write_request, {});
436 req->send();
437
438 ASSERT_EQ(0, mock_write_request.ctx.wait());
439 }
440
441 TEST_F(TestMockIoCopyupRequest, StandardWithSnaps) {
442 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
443
444 librbd::ImageCtx *ictx;
445 ASSERT_EQ(0, open_image(m_image_name, &ictx));
446 ictx->image_lock.lock();
447 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx->size,
448 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
449 0, {});
450 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
451 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
452 0, {});
453 ictx->snapc = {2, {2, 1}};
454 ictx->image_lock.unlock();
455
456 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
457 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
458
459 MockExclusiveLock mock_exclusive_lock;
460 MockJournal mock_journal;
461 MockObjectMap mock_object_map;
462 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
463 mock_object_map);
464
465 expect_test_features(mock_image_ctx);
466 expect_op_work_queue(mock_image_ctx);
467 expect_is_lock_owner(mock_image_ctx);
468
469 InSequence seq;
470
471 std::string data(4096, '1');
472 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
473 expect_prepare_copyup(mock_image_ctx);
474
475 MockAbstractObjectWriteRequest mock_write_request;
476 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
477 OBJECT_EXISTS);
478 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
479 expect_object_map_update(mock_image_ctx, 1, 0, OBJECT_EXISTS, true, 0);
480 expect_object_map_update(mock_image_ctx, 2, 0, OBJECT_EXISTS_CLEAN, true, 0);
481 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
482 0);
483
484 expect_add_copyup_ops(mock_write_request);
485 expect_sparse_copyup(mock_image_ctx, 0, ictx->get_object_name(0), {{0, 4096}},
486 data, 0);
487 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
488
489 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
490 ImageArea::DATA, {});
491 mock_image_ctx.copyup_list[0] = req;
492 req->append_request(&mock_write_request, {});
493 req->send();
494
495 ASSERT_EQ(0, mock_write_request.ctx.wait());
496 }
497
498 TEST_F(TestMockIoCopyupRequest, CopyOnRead) {
499 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
500
501 librbd::ImageCtx *ictx;
502 ASSERT_EQ(0, open_image(m_image_name, &ictx));
503
504 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
505 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
506
507 MockExclusiveLock mock_exclusive_lock;
508 MockJournal mock_journal;
509 MockObjectMap mock_object_map;
510 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
511 mock_object_map);
512
513 expect_op_work_queue(mock_image_ctx);
514 expect_is_lock_owner(mock_image_ctx);
515
516 InSequence seq;
517
518 std::string data(4096, '1');
519 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
520 expect_prepare_copyup(mock_image_ctx);
521
522 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
523 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
524 0);
525
526 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
527 {{0, 4096}}, data, 0);
528
529 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
530 ImageArea::DATA, {});
531 mock_image_ctx.copyup_list[0] = req;
532 req->send();
533 flush_async_operations(ictx);
534 }
535
536 TEST_F(TestMockIoCopyupRequest, CopyOnReadWithSnaps) {
537 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
538
539 librbd::ImageCtx *ictx;
540 ASSERT_EQ(0, open_image(m_image_name, &ictx));
541 ictx->image_lock.lock();
542 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
543 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
544 0, {});
545 ictx->snapc = {1, {1}};
546 ictx->image_lock.unlock();
547
548 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
549 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
550
551 MockExclusiveLock mock_exclusive_lock;
552 MockJournal mock_journal;
553 MockObjectMap mock_object_map;
554 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
555 mock_object_map);
556
557 expect_test_features(mock_image_ctx);
558 expect_op_work_queue(mock_image_ctx);
559 expect_is_lock_owner(mock_image_ctx);
560
561 InSequence seq;
562
563 std::string data(4096, '1');
564 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
565 expect_prepare_copyup(mock_image_ctx);
566
567 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
568 expect_object_map_update(mock_image_ctx, 1, 0, OBJECT_EXISTS, true, 0);
569 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS_CLEAN,
570 true, 0);
571
572 expect_sparse_copyup(mock_image_ctx, 0, ictx->get_object_name(0), {{0, 4096}},
573 data, 0);
574
575 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
576 ImageArea::DATA, {});
577 mock_image_ctx.copyup_list[0] = req;
578 req->send();
579 flush_async_operations(ictx);
580 }
581
582 TEST_F(TestMockIoCopyupRequest, DeepCopy) {
583 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
584
585 librbd::ImageCtx *ictx;
586 ASSERT_EQ(0, open_image(m_image_name, &ictx));
587
588 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
589 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
590
591 MockExclusiveLock mock_exclusive_lock;
592 MockJournal mock_journal;
593 MockObjectMap mock_object_map;
594 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
595 mock_object_map);
596
597 expect_op_work_queue(mock_image_ctx);
598 expect_is_lock_owner(mock_image_ctx);
599
600 InSequence seq;
601
602 MockAbstractObjectWriteRequest mock_write_request;
603 MockObjectCopyRequest mock_object_copy_request;
604 mock_image_ctx.migration_info = {1, "", "", "image id", "", {}, ictx->size,
605 true};
606 expect_is_empty_write_op(mock_write_request, false);
607 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
608
609 expect_is_empty_write_op(mock_write_request, false);
610 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
611 OBJECT_EXISTS);
612 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
613 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
614 0);
615
616 expect_add_copyup_ops(mock_write_request);
617 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
618 {}, "", 0);
619 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
620
621 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
622 ImageArea::DATA, {});
623 mock_image_ctx.copyup_list[0] = req;
624 req->append_request(&mock_write_request, {});
625 req->send();
626
627 ASSERT_EQ(0, mock_write_request.ctx.wait());
628 }
629
630 TEST_F(TestMockIoCopyupRequest, DeepCopyOnRead) {
631 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
632
633 librbd::ImageCtx *ictx;
634 ASSERT_EQ(0, open_image(m_image_name, &ictx));
635
636 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
637 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
638
639 MockExclusiveLock mock_exclusive_lock;
640 MockJournal mock_journal;
641 MockObjectMap mock_object_map;
642 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
643 mock_object_map);
644
645 expect_op_work_queue(mock_image_ctx);
646 expect_is_lock_owner(mock_image_ctx);
647
648 InSequence seq;
649
650 MockObjectCopyRequest mock_object_copy_request;
651 mock_image_ctx.migration_info = {1, "", "", "image id", "", {}, ictx->size,
652 false};
653 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
654
655 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
656 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
657 0);
658
659 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
660 ImageArea::DATA, {});
661 mock_image_ctx.copyup_list[0] = req;
662 req->send();
663 flush_async_operations(ictx);
664 }
665
666 TEST_F(TestMockIoCopyupRequest, DeepCopyWithPostSnaps) {
667 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
668
669 librbd::ImageCtx *ictx;
670 ASSERT_EQ(0, open_image(m_image_name, &ictx));
671 ictx->image_lock.lock();
672 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx->size,
673 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
674 0, {});
675 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx->size,
676 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
677 0, {});
678 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
679 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
680 0, {});
681 ictx->snapc = {3, {3, 2, 1}};
682 ictx->image_lock.unlock();
683
684 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
685 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
686
687 MockExclusiveLock mock_exclusive_lock;
688 MockJournal mock_journal;
689 MockObjectMap mock_object_map;
690 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
691 mock_object_map);
692
693 expect_test_features(mock_image_ctx);
694 expect_op_work_queue(mock_image_ctx);
695 expect_is_lock_owner(mock_image_ctx);
696
697 InSequence seq;
698
699 MockAbstractObjectWriteRequest mock_write_request;
700 MockObjectCopyRequest mock_object_copy_request;
701 mock_image_ctx.migration_info = {1, "", "", "image id", "",
702 {{CEPH_NOSNAP, {2, 1}}},
703 ictx->size, true};
704 expect_is_empty_write_op(mock_write_request, false);
705 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
706
707 expect_is_empty_write_op(mock_write_request, false);
708 expect_get_parent_overlap(mock_image_ctx, 1, 0, 0);
709 expect_get_parent_overlap(mock_image_ctx, 2, 1, 0);
710 expect_prune_parent_extents(mock_image_ctx, 1, 1);
711 expect_get_parent_overlap(mock_image_ctx, 3, 1, 0);
712 expect_prune_parent_extents(mock_image_ctx, 1, 1);
713 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
714 OBJECT_EXISTS);
715 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
716 expect_object_map_update(mock_image_ctx, 2, 0, OBJECT_EXISTS, true, 0);
717 expect_object_map_update(mock_image_ctx, 3, 0, OBJECT_EXISTS_CLEAN, true, 0);
718 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
719 0);
720
721 expect_add_copyup_ops(mock_write_request);
722 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
723 {}, "", 0);
724 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
725
726 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
727 ImageArea::DATA, {});
728 mock_image_ctx.copyup_list[0] = req;
729 req->append_request(&mock_write_request, {});
730 req->send();
731
732 ASSERT_EQ(0, mock_write_request.ctx.wait());
733 }
734
735 TEST_F(TestMockIoCopyupRequest, DeepCopyWithPreAndPostSnaps) {
736 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
737
738 librbd::ImageCtx *ictx;
739 ASSERT_EQ(0, open_image(m_image_name, &ictx));
740 ictx->image_lock.lock();
741 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "4", 4, ictx->size,
742 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
743 0, {});
744 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx->size,
745 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
746 0, {});
747 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx->size,
748 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
749 0, {});
750 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
751 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
752 0, {});
753 ictx->snapc = {4, {4, 3, 2, 1}};
754 ictx->image_lock.unlock();
755
756 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
757 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
758
759 MockExclusiveLock mock_exclusive_lock;
760 MockJournal mock_journal;
761 MockObjectMap mock_object_map;
762 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
763 mock_object_map);
764
765 expect_test_features(mock_image_ctx);
766 expect_op_work_queue(mock_image_ctx);
767 expect_is_lock_owner(mock_image_ctx);
768
769 InSequence seq;
770
771 MockAbstractObjectWriteRequest mock_write_request;
772 MockObjectCopyRequest mock_object_copy_request;
773 mock_image_ctx.migration_info = {1, "", "", "image id", "",
774 {{CEPH_NOSNAP, {2, 1}}, {10, {1}}},
775 ictx->size, true};
776 expect_is_empty_write_op(mock_write_request, false);
777 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
778
779 expect_is_empty_write_op(mock_write_request, false);
780 expect_get_parent_overlap(mock_image_ctx, 2, 0, 0);
781 expect_get_parent_overlap(mock_image_ctx, 3, 1, 0);
782 expect_prune_parent_extents(mock_image_ctx, 1, 1);
783 expect_get_parent_overlap(mock_image_ctx, 4, 1, 0);
784 expect_prune_parent_extents(mock_image_ctx, 1, 1);
785 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
786 OBJECT_EXISTS);
787 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
788 expect_object_map_update(mock_image_ctx, 3, 0, OBJECT_EXISTS_CLEAN, true, 0);
789 expect_object_map_update(mock_image_ctx, 4, 0, OBJECT_EXISTS_CLEAN, true, 0);
790 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
791 0);
792
793 expect_add_copyup_ops(mock_write_request);
794 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
795 {}, "", 0);
796 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
797
798 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
799 ImageArea::DATA, {});
800 mock_image_ctx.copyup_list[0] = req;
801 req->append_request(&mock_write_request, {});
802 req->send();
803
804 ASSERT_EQ(0, mock_write_request.ctx.wait());
805 }
806
807 TEST_F(TestMockIoCopyupRequest, ZeroedCopyup) {
808 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
809
810 librbd::ImageCtx *ictx;
811 ASSERT_EQ(0, open_image(m_image_name, &ictx));
812
813 MockTestImageCtx mock_image_ctx(*ictx);
814
815 MockExclusiveLock mock_exclusive_lock;
816 MockJournal mock_journal;
817 MockObjectMap mock_object_map;
818 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
819 mock_object_map);
820
821 expect_op_work_queue(mock_image_ctx);
822 expect_is_lock_owner(mock_image_ctx);
823
824 InSequence seq;
825
826 MockAbstractObjectWriteRequest mock_write_request;
827 expect_prepare_copyup(mock_image_ctx);
828 expect_is_empty_write_op(mock_write_request, false);
829 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
830 OBJECT_EXISTS);
831 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
832 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
833 0);
834
835 expect_add_copyup_ops(mock_write_request);
836 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
837 {}, "", 0);
838 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
839
840 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
841 ImageArea::DATA, {});
842 mock_image_ctx.copyup_list[0] = req;
843 req->append_request(&mock_write_request, {});
844 req->send();
845
846 ASSERT_EQ(0, mock_write_request.ctx.wait());
847 }
848
849 TEST_F(TestMockIoCopyupRequest, ZeroedCopyOnRead) {
850 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
851
852 librbd::ImageCtx *ictx;
853 ASSERT_EQ(0, open_image(m_image_name, &ictx));
854
855 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
856 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
857
858 MockExclusiveLock mock_exclusive_lock;
859 MockJournal mock_journal;
860 MockObjectMap mock_object_map;
861 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
862 mock_object_map);
863
864 expect_op_work_queue(mock_image_ctx);
865 expect_is_lock_owner(mock_image_ctx);
866
867 InSequence seq;
868
869 std::string data(4096, '\0');
870 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
871 expect_prepare_copyup(mock_image_ctx);
872
873 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
874 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
875 0);
876
877 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
878 {}, "", 0);
879
880 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
881 ImageArea::DATA, {});
882 mock_image_ctx.copyup_list[0] = req;
883 req->send();
884 flush_async_operations(ictx);
885 }
886
887 TEST_F(TestMockIoCopyupRequest, NoOpCopyup) {
888 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
889
890 librbd::ImageCtx *ictx;
891 ASSERT_EQ(0, open_image(m_image_name, &ictx));
892
893 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
894 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
895
896 MockExclusiveLock mock_exclusive_lock;
897 MockJournal mock_journal;
898 MockObjectMap mock_object_map;
899 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
900 mock_object_map);
901
902 expect_op_work_queue(mock_image_ctx);
903 expect_is_lock_owner(mock_image_ctx);
904
905 InSequence seq;
906
907 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, "", -ENOENT);
908
909 expect_prepare_copyup(mock_image_ctx);
910
911 MockAbstractObjectWriteRequest mock_write_request;
912 expect_is_empty_write_op(mock_write_request, true);
913
914 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
915 ImageArea::DATA, {});
916 mock_image_ctx.copyup_list[0] = req;
917 req->append_request(&mock_write_request, {});
918 req->send();
919
920 ASSERT_EQ(0, mock_write_request.ctx.wait());
921 }
922
923 TEST_F(TestMockIoCopyupRequest, RestartWrite) {
924 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
925
926 librbd::ImageCtx *ictx;
927 ASSERT_EQ(0, open_image(m_image_name, &ictx));
928
929 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
930 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
931
932 MockExclusiveLock mock_exclusive_lock;
933 MockJournal mock_journal;
934 MockObjectMap mock_object_map;
935 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
936 mock_object_map);
937
938 expect_op_work_queue(mock_image_ctx);
939 expect_is_lock_owner(mock_image_ctx);
940
941 InSequence seq;
942
943 std::string data(4096, '1');
944 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
945 expect_prepare_copyup(mock_image_ctx);
946
947 MockAbstractObjectWriteRequest mock_write_request1;
948 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request1,
949 OBJECT_EXISTS);
950 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
951 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
952 0);
953
954 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
955 ImageArea::DATA, {});
956 expect_add_copyup_ops(mock_write_request1);
957 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
958 {{0, 4096}}, data, 0);
959
960 MockAbstractObjectWriteRequest mock_write_request2;
961 auto& mock_io_ctx = librados::get_mock_io_ctx(
962 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
963 EXPECT_CALL(mock_io_ctx, write(ictx->get_object_name(0), _, 0, 0, _))
964 .WillOnce(WithoutArgs(Invoke([req, &mock_write_request2]() {
965 req->append_request(&mock_write_request2, {});
966 return 0;
967 })));
968
969 mock_image_ctx.copyup_list[0] = req;
970 req->append_request(&mock_write_request1, {});
971 req->send();
972
973 ASSERT_EQ(0, mock_write_request1.ctx.wait());
974 ASSERT_EQ(-ERESTART, mock_write_request2.ctx.wait());
975 }
976
977 TEST_F(TestMockIoCopyupRequest, ReadFromParentError) {
978 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
979
980 librbd::ImageCtx *ictx;
981 ASSERT_EQ(0, open_image(m_image_name, &ictx));
982
983 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
984 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
985
986 MockExclusiveLock mock_exclusive_lock;
987 MockJournal mock_journal;
988 MockObjectMap mock_object_map;
989 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
990 mock_object_map);
991
992 expect_op_work_queue(mock_image_ctx);
993 expect_is_lock_owner(mock_image_ctx);
994
995 InSequence seq;
996
997 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, "", -EPERM);
998
999 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1000 ImageArea::DATA, {});
1001 mock_image_ctx.copyup_list[0] = req;
1002 MockAbstractObjectWriteRequest mock_write_request;
1003 req->append_request(&mock_write_request, {});
1004 req->send();
1005
1006 ASSERT_EQ(-EPERM, mock_write_request.ctx.wait());
1007 }
1008
1009 TEST_F(TestMockIoCopyupRequest, PrepareCopyupError) {
1010 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1011
1012 librbd::ImageCtx *ictx;
1013 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1014
1015 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1016 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1017
1018 MockExclusiveLock mock_exclusive_lock;
1019 MockJournal mock_journal;
1020 MockObjectMap mock_object_map;
1021 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1022 mock_object_map);
1023
1024 expect_op_work_queue(mock_image_ctx);
1025 expect_is_lock_owner(mock_image_ctx);
1026
1027 InSequence seq;
1028
1029 std::string data(4096, '1');
1030 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
1031 expect_prepare_copyup(mock_image_ctx, -EIO);
1032
1033 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1034 ImageArea::DATA, {});
1035 mock_image_ctx.copyup_list[0] = req;
1036 MockAbstractObjectWriteRequest mock_write_request;
1037 req->append_request(&mock_write_request, {});
1038 req->send();
1039
1040 ASSERT_EQ(-EIO, mock_write_request.ctx.wait());
1041 }
1042
1043 TEST_F(TestMockIoCopyupRequest, DeepCopyError) {
1044 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1045
1046 librbd::ImageCtx *ictx;
1047 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1048
1049 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1050 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1051
1052 MockExclusiveLock mock_exclusive_lock;
1053 MockJournal mock_journal;
1054 MockObjectMap mock_object_map;
1055 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1056 mock_object_map);
1057
1058 expect_op_work_queue(mock_image_ctx);
1059 expect_is_lock_owner(mock_image_ctx);
1060
1061 InSequence seq;
1062
1063 MockAbstractObjectWriteRequest mock_write_request;
1064 MockObjectCopyRequest mock_object_copy_request;
1065 mock_image_ctx.migration_info = {1, "", "", "image id", "", {}, ictx->size,
1066 true};
1067 expect_is_empty_write_op(mock_write_request, false);
1068 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, -EPERM);
1069
1070 expect_is_empty_write_op(mock_write_request, false);
1071
1072 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1073 ImageArea::DATA, {});
1074 mock_image_ctx.copyup_list[0] = req;
1075 req->append_request(&mock_write_request, {});
1076 req->send();
1077
1078 ASSERT_EQ(-EPERM, mock_write_request.ctx.wait());
1079 }
1080
1081 TEST_F(TestMockIoCopyupRequest, UpdateObjectMapError) {
1082 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_OBJECT_MAP);
1083
1084 librbd::ImageCtx *ictx;
1085 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1086
1087 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1088 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1089
1090 MockExclusiveLock mock_exclusive_lock;
1091 MockJournal mock_journal;
1092 MockObjectMap mock_object_map;
1093 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1094 mock_object_map);
1095
1096 expect_op_work_queue(mock_image_ctx);
1097 expect_is_lock_owner(mock_image_ctx);
1098
1099 InSequence seq;
1100
1101 std::string data(4096, '1');
1102 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
1103 expect_prepare_copyup(mock_image_ctx);
1104
1105 MockAbstractObjectWriteRequest mock_write_request;
1106 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
1107 OBJECT_EXISTS);
1108 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
1109 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
1110 -EINVAL);
1111
1112 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1113 ImageArea::DATA, {});
1114 mock_image_ctx.copyup_list[0] = req;
1115 req->append_request(&mock_write_request, {});
1116 req->send();
1117
1118 ASSERT_EQ(-EINVAL, mock_write_request.ctx.wait());
1119 }
1120
1121 TEST_F(TestMockIoCopyupRequest, CopyupError) {
1122 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1123
1124 librbd::ImageCtx *ictx;
1125 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1126 ictx->image_lock.lock();
1127 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
1128 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
1129 0, {});
1130 ictx->snapc = {1, {1}};
1131 ictx->image_lock.unlock();
1132
1133 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1134 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1135
1136 MockExclusiveLock mock_exclusive_lock;
1137 MockJournal mock_journal;
1138 MockObjectMap mock_object_map;
1139 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1140 mock_object_map);
1141
1142 expect_test_features(mock_image_ctx);
1143 expect_op_work_queue(mock_image_ctx);
1144 expect_is_lock_owner(mock_image_ctx);
1145
1146 InSequence seq;
1147
1148 std::string data(4096, '1');
1149 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
1150 expect_prepare_copyup(mock_image_ctx);
1151
1152 MockAbstractObjectWriteRequest mock_write_request;
1153 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
1154 OBJECT_EXISTS);
1155 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
1156 expect_object_map_update(mock_image_ctx, 1, 0, OBJECT_EXISTS, true, 0);
1157 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
1158 0);
1159
1160 expect_add_copyup_ops(mock_write_request);
1161 expect_sparse_copyup(mock_image_ctx, 0, ictx->get_object_name(0), {{0, 4096}},
1162 data, -EPERM);
1163 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
1164
1165 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1166 ImageArea::DATA, {});
1167 mock_image_ctx.copyup_list[0] = req;
1168 req->append_request(&mock_write_request, {});
1169 req->send();
1170
1171 ASSERT_EQ(-EPERM, mock_write_request.ctx.wait());
1172 flush_async_operations(ictx);
1173 }
1174
1175 TEST_F(TestMockIoCopyupRequest, SparseCopyupNotSupported) {
1176 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1177
1178 librbd::ImageCtx *ictx;
1179 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1180
1181 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1182 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1183 mock_image_ctx.enable_sparse_copyup = false;
1184
1185 MockExclusiveLock mock_exclusive_lock;
1186 MockJournal mock_journal;
1187 MockObjectMap mock_object_map;
1188 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1189 mock_object_map);
1190
1191 expect_op_work_queue(mock_image_ctx);
1192 expect_is_lock_owner(mock_image_ctx);
1193
1194 InSequence seq;
1195
1196 std::string data(4096, '1');
1197 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
1198 expect_prepare_copyup(mock_image_ctx);
1199
1200 MockAbstractObjectWriteRequest mock_write_request;
1201 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
1202 OBJECT_EXISTS);
1203 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
1204 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
1205 0);
1206
1207 expect_add_copyup_ops(mock_write_request);
1208 expect_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), data, 0);
1209 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
1210
1211 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1212 ImageArea::DATA, {});
1213 mock_image_ctx.copyup_list[0] = req;
1214 req->append_request(&mock_write_request, {});
1215 req->send();
1216
1217 ASSERT_EQ(0, mock_write_request.ctx.wait());
1218 }
1219
1220 TEST_F(TestMockIoCopyupRequest, ProcessCopyup) {
1221 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1222
1223 librbd::ImageCtx *ictx;
1224 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1225
1226 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1227 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1228
1229 MockExclusiveLock mock_exclusive_lock;
1230 MockJournal mock_journal;
1231 MockObjectMap mock_object_map;
1232 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1233 mock_object_map);
1234
1235 expect_op_work_queue(mock_image_ctx);
1236 expect_is_lock_owner(mock_image_ctx);
1237
1238 InSequence seq;
1239
1240 std::string data(4096, '1');
1241 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
1242
1243 bufferlist in_prepare_bl;
1244 in_prepare_bl.append(std::string(3072, '1'));
1245 bufferlist out_prepare_bl;
1246 out_prepare_bl.substr_of(in_prepare_bl, 0, 1024);
1247 expect_prepare_copyup(
1248 mock_image_ctx,
1249 {{1024U, {3072U, {SPARSE_EXTENT_STATE_DATA, 3072,
1250 std::move(in_prepare_bl)}}}},
1251 {{2048U, {1024U, {SPARSE_EXTENT_STATE_DATA, 1024,
1252 std::move(out_prepare_bl)}}}});
1253
1254 MockAbstractObjectWriteRequest mock_write_request;
1255 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
1256 OBJECT_EXISTS);
1257 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
1258 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
1259 0);
1260
1261 expect_add_copyup_ops(mock_write_request);
1262 expect_sparse_copyup(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0),
1263 {{2048, 1024}}, data.substr(0, 1024), 0);
1264 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
1265
1266 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1267 ImageArea::DATA, {});
1268 mock_image_ctx.copyup_list[0] = req;
1269 req->append_request(&mock_write_request, {{0, 1024}});
1270 req->send();
1271
1272 ASSERT_EQ(0, mock_write_request.ctx.wait());
1273 }
1274
1275 TEST_F(TestMockIoCopyupRequest, ProcessCopyupOverwrite) {
1276 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1277
1278 librbd::ImageCtx *ictx;
1279 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1280 ictx->image_lock.lock();
1281 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
1282 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
1283 0, {});
1284 ictx->snapc = {1, {1}};
1285 ictx->image_lock.unlock();
1286
1287 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1288 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1289
1290 MockExclusiveLock mock_exclusive_lock;
1291 MockJournal mock_journal;
1292 MockObjectMap mock_object_map;
1293 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1294 mock_object_map);
1295
1296 expect_test_features(mock_image_ctx);
1297 expect_op_work_queue(mock_image_ctx);
1298 expect_is_lock_owner(mock_image_ctx);
1299
1300 InSequence seq;
1301
1302 std::string data(4096, '1');
1303 expect_read_parent(mock_parent_image_ctx, {{0, 4096}}, data, 0);
1304
1305 bufferlist in_prepare_bl;
1306 in_prepare_bl.append(data);
1307 bufferlist out_prepare_bl;
1308 out_prepare_bl.substr_of(in_prepare_bl, 0, 1024);
1309 expect_prepare_copyup(
1310 mock_image_ctx,
1311 {{0, {4096, {SPARSE_EXTENT_STATE_DATA, 4096,
1312 std::move(in_prepare_bl)}}}},
1313 {{0, {1024, {SPARSE_EXTENT_STATE_DATA, 1024, bufferlist{out_prepare_bl}}}},
1314 {2048, {1024, {SPARSE_EXTENT_STATE_DATA, 1024,
1315 bufferlist{out_prepare_bl}}}}});
1316
1317 MockAbstractObjectWriteRequest mock_write_request;
1318 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
1319 OBJECT_EXISTS);
1320 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
1321 expect_object_map_update(mock_image_ctx, 1, 0, OBJECT_EXISTS, true, 0);
1322 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
1323 0);
1324
1325 expect_add_copyup_ops(mock_write_request);
1326 expect_sparse_copyup(mock_image_ctx, 0, ictx->get_object_name(0),
1327 {{0, 1024}, {2048, 1024}}, data.substr(0, 2048), 0);
1328 expect_write(mock_image_ctx, CEPH_NOSNAP, ictx->get_object_name(0), 0);
1329
1330 auto req = new MockCopyupRequest(&mock_image_ctx, 0, {{0, 4096}},
1331 ImageArea::DATA, {});
1332 mock_image_ctx.copyup_list[0] = req;
1333 req->append_request(&mock_write_request, {{0, 1024}});
1334 req->send();
1335
1336 ASSERT_EQ(0, mock_write_request.ctx.wait());
1337 }
1338
1339 } // namespace io
1340 } // namespace librbd