]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_CopyupRequest.cc
import 14.2.4 nautilus point release
[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/deep_copy/ObjectCopyRequest.h"
14 #include "librbd/io/CopyupRequest.h"
15 #include "librbd/io/ImageRequest.h"
16 #include "librbd/io/ImageRequestWQ.h"
17 #include "librbd/io/ObjectRequest.h"
18 #include "librbd/io/ReadResult.h"
19
20 namespace librbd {
21 namespace {
22
23 struct MockTestImageCtx : public MockImageCtx {
24 MockTestImageCtx(ImageCtx &image_ctx,
25 MockTestImageCtx* mock_parent_image_ctx = nullptr)
26 : MockImageCtx(image_ctx) {
27 parent = mock_parent_image_ctx;
28 }
29
30 std::map<uint64_t, librbd::io::CopyupRequest<librbd::MockTestImageCtx>*> copyup_list;
31 };
32
33 } // anonymous namespace
34
35 namespace util {
36
37 inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
38 return image_ctx->image_ctx;
39 }
40
41 } // namespace util
42
43 namespace deep_copy {
44
45 template <>
46 struct ObjectCopyRequest<librbd::MockTestImageCtx> {
47 static ObjectCopyRequest* s_instance;
48 static ObjectCopyRequest* create(librbd::MockImageCtx* parent_image_ctx,
49 librbd::MockTestImageCtx* image_ctx,
50 const SnapMap &snap_map,
51 uint64_t object_number, bool flatten,
52 Context *on_finish) {
53 ceph_assert(s_instance != nullptr);
54 s_instance->object_number = object_number;
55 s_instance->flatten = flatten;
56 s_instance->on_finish = on_finish;
57 return s_instance;
58 }
59
60 uint64_t object_number;
61 bool flatten;
62 Context *on_finish;
63
64 ObjectCopyRequest() {
65 s_instance = this;
66 }
67
68 MOCK_METHOD0(send, void());
69 };
70
71 ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
72
73 } // namespace deep_copy
74
75 namespace io {
76
77 template <>
78 struct ObjectRequest<librbd::MockTestImageCtx> {
79 static void add_write_hint(librbd::MockTestImageCtx&,
80 librados::ObjectWriteOperation*) {
81 }
82 };
83
84 template <>
85 struct AbstractObjectWriteRequest<librbd::MockTestImageCtx> {
86 C_SaferCond ctx;
87 void handle_copyup(int r) {
88 ctx.complete(r);
89 }
90
91 MOCK_CONST_METHOD0(get_pre_write_object_map_state, uint8_t());
92 MOCK_CONST_METHOD0(is_empty_write_op, bool());
93
94 MOCK_METHOD1(add_copyup_ops, void(librados::ObjectWriteOperation*));
95 };
96
97 template <>
98 struct ImageRequest<librbd::MockTestImageCtx> {
99 static ImageRequest *s_instance;
100 static void aio_read(librbd::MockImageCtx *ictx, AioCompletion *c,
101 Extents &&image_extents, ReadResult &&read_result,
102 int op_flags, const ZTracer::Trace &parent_trace) {
103 s_instance->aio_read(c, image_extents, &read_result);
104 }
105
106 MOCK_METHOD3(aio_read, void(AioCompletion *, const Extents&, ReadResult*));
107
108 ImageRequest() {
109 s_instance = this;
110 }
111 };
112
113 ImageRequest<librbd::MockTestImageCtx>* ImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
114
115 } // namespace io
116 } // namespace librbd
117
118 static bool operator==(const SnapContext& rhs, const SnapContext& lhs) {
119 return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps);
120 }
121
122 #include "librbd/AsyncObjectThrottle.cc"
123 #include "librbd/io/CopyupRequest.cc"
124
125 namespace librbd {
126 namespace io {
127
128 using ::testing::_;
129 using ::testing::InSequence;
130 using ::testing::Invoke;
131 using ::testing::Return;
132 using ::testing::StrEq;
133 using ::testing::WithArg;
134 using ::testing::WithArgs;
135 using ::testing::WithoutArgs;
136
137 struct TestMockIoCopyupRequest : public TestMockFixture {
138 typedef CopyupRequest<librbd::MockTestImageCtx> MockCopyupRequest;
139 typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
140 typedef ObjectRequest<librbd::MockTestImageCtx> MockObjectRequest;
141 typedef AbstractObjectWriteRequest<librbd::MockTestImageCtx> MockAbstractObjectWriteRequest;
142 typedef deep_copy::ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
143
144 void SetUp() override {
145 TestMockFixture::SetUp();
146 if (!is_feature_enabled(RBD_FEATURE_LAYERING)) {
147 return;
148 }
149
150 m_parent_image_name = m_image_name;
151 m_image_name = get_temp_image_name();
152
153 librbd::Image image;
154 librbd::RBD rbd;
155 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_parent_image_name.c_str(),
156 nullptr));
157 ASSERT_EQ(0, image.snap_create("one"));
158 ASSERT_EQ(0, image.snap_protect("one"));
159
160 uint64_t features;
161 ASSERT_EQ(0, image.features(&features));
162 image.close();
163
164 int order = 0;
165 ASSERT_EQ(0, rbd.clone(m_ioctx, m_parent_image_name.c_str(), "one", m_ioctx,
166 m_image_name.c_str(), features, &order));
167 }
168
169 void expect_get_parent_overlap(MockTestImageCtx& mock_image_ctx,
170 librados::snap_t snap_id, uint64_t overlap,
171 int r) {
172 if (mock_image_ctx.object_map != nullptr) {
173 EXPECT_CALL(mock_image_ctx, get_parent_overlap(snap_id, _))
174 .WillOnce(WithArg<1>(Invoke([overlap, r](uint64_t *o) {
175 *o = overlap;
176 return r;
177 })));
178 }
179 }
180
181 void expect_prune_parent_extents(MockTestImageCtx& mock_image_ctx,
182 uint64_t overlap, uint64_t object_overlap) {
183 if (mock_image_ctx.object_map != nullptr) {
184 EXPECT_CALL(mock_image_ctx, prune_parent_extents(_, overlap))
185 .WillOnce(WithoutArgs(Invoke([object_overlap]() {
186 return object_overlap;
187 })));
188 }
189 }
190
191 void expect_read_parent(MockTestImageCtx& mock_image_ctx,
192 MockImageRequest& mock_image_request,
193 const Extents& image_extents,
194 const std::string& data, int r) {
195 EXPECT_CALL(mock_image_request, aio_read(_, image_extents, _))
196 .WillOnce(WithArgs<0, 2>(Invoke(
197 [&mock_image_ctx, image_extents, data, r](
198 AioCompletion* aio_comp, ReadResult* read_result) {
199 aio_comp->read_result = std::move(*read_result);
200 aio_comp->set_request_count(1);
201 auto ctx = new ReadResult::C_ImageReadRequest(aio_comp,
202 image_extents);
203 ctx->bl.append(data);
204 mock_image_ctx.image_ctx->op_work_queue->queue(ctx, r);
205 })));
206 }
207
208 void expect_copyup(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
209 const std::string& oid, const std::string& data, int r) {
210 bufferlist in_bl;
211 in_bl.append(data);
212
213 SnapContext snapc;
214 if (snap_id == CEPH_NOSNAP) {
215 snapc = mock_image_ctx.snapc;
216 }
217
218 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
219 exec(oid, _, StrEq("rbd"), StrEq("copyup"),
220 ContentsEqual(in_bl), _, snapc))
221 .WillOnce(Return(r));
222 }
223
224 void expect_write(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
225 const std::string& oid, int r) {
226 SnapContext snapc;
227 if (snap_id == CEPH_NOSNAP) {
228 snapc = mock_image_ctx.snapc;
229 }
230
231 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
232 write(oid, _, 0, 0, snapc))
233 .WillOnce(Return(r));
234 }
235
236 void expect_test_features(MockTestImageCtx& mock_image_ctx) {
237 EXPECT_CALL(mock_image_ctx, test_features(_, _))
238 .WillRepeatedly(WithArg<0>(Invoke([&mock_image_ctx](uint64_t features) {
239 return (mock_image_ctx.features & features) != 0;
240 })));
241 }
242
243 void expect_is_lock_owner(MockTestImageCtx& mock_image_ctx) {
244 if (mock_image_ctx.exclusive_lock != nullptr) {
245 EXPECT_CALL(*mock_image_ctx.exclusive_lock,
246 is_lock_owner()).WillRepeatedly(Return(true));
247 }
248 }
249
250 void expect_is_empty_write_op(MockAbstractObjectWriteRequest& mock_write_request,
251 bool is_empty) {
252 EXPECT_CALL(mock_write_request, is_empty_write_op())
253 .WillOnce(Return(is_empty));
254 }
255
256 void expect_add_copyup_ops(MockAbstractObjectWriteRequest& mock_write_request) {
257 EXPECT_CALL(mock_write_request, add_copyup_ops(_))
258 .WillOnce(Invoke([](librados::ObjectWriteOperation* op) {
259 op->write(0, bufferlist{});
260 }));
261 }
262
263 void expect_get_pre_write_object_map_state(MockTestImageCtx& mock_image_ctx,
264 MockAbstractObjectWriteRequest& mock_write_request,
265 uint8_t state) {
266 if (mock_image_ctx.object_map != nullptr) {
267 EXPECT_CALL(mock_write_request, get_pre_write_object_map_state())
268 .WillOnce(Return(state));
269 }
270 }
271
272 void expect_object_map_at(MockTestImageCtx& mock_image_ctx,
273 uint64_t object_no, uint8_t state) {
274 if (mock_image_ctx.object_map != nullptr) {
275 EXPECT_CALL(*mock_image_ctx.object_map, at(object_no))
276 .WillOnce(Return(state));
277 }
278 }
279
280 void expect_object_map_update(MockTestImageCtx& mock_image_ctx,
281 uint64_t snap_id, uint64_t object_no,
282 uint8_t state, bool updated, int ret_val) {
283 if (mock_image_ctx.object_map != nullptr) {
284 if (!mock_image_ctx.image_ctx->test_features(RBD_FEATURE_FAST_DIFF) &&
285 state == OBJECT_EXISTS_CLEAN) {
286 state = OBJECT_EXISTS;
287 }
288
289 EXPECT_CALL(*mock_image_ctx.object_map,
290 aio_update(snap_id, object_no, object_no + 1, state,
291 boost::optional<uint8_t>(), _,
292 (snap_id != CEPH_NOSNAP), _))
293 .WillOnce(WithArg<7>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) {
294 if (updated) {
295 mock_image_ctx.op_work_queue->queue(ctx, ret_val);
296 }
297 return updated;
298 })));
299 }
300 }
301
302 void expect_object_copy(MockTestImageCtx& mock_image_ctx,
303 MockObjectCopyRequest& mock_object_copy_request,
304 bool flatten, int r) {
305 EXPECT_CALL(mock_object_copy_request, send())
306 .WillOnce(Invoke(
307 [&mock_image_ctx, &mock_object_copy_request, flatten, r]() {
308 ASSERT_EQ(flatten, mock_object_copy_request.flatten);
309 mock_image_ctx.op_work_queue->queue(
310 mock_object_copy_request.on_finish, r);
311 }));
312 }
313
314 void flush_async_operations(librbd::ImageCtx* ictx) {
315 ictx->io_work_queue->flush();
316 }
317
318 std::string m_parent_image_name;
319 };
320
321 TEST_F(TestMockIoCopyupRequest, Standard) {
322 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
323
324 librbd::ImageCtx *ictx;
325 ASSERT_EQ(0, open_image(m_image_name, &ictx));
326
327 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
328 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
329
330 MockExclusiveLock mock_exclusive_lock;
331 MockJournal mock_journal;
332 MockObjectMap mock_object_map;
333 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
334 mock_object_map);
335
336 expect_op_work_queue(mock_image_ctx);
337 expect_is_lock_owner(mock_image_ctx);
338
339 InSequence seq;
340
341 MockImageRequest mock_image_request;
342 std::string data(4096, '1');
343 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
344 data, 0);
345
346 MockAbstractObjectWriteRequest mock_write_request;
347 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
348 OBJECT_EXISTS);
349 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
350 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
351 0);
352
353 expect_add_copyup_ops(mock_write_request);
354 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", data, 0);
355 expect_write(mock_image_ctx, CEPH_NOSNAP, "oid", 0);
356
357 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
358 {{0, 4096}}, {});
359 mock_image_ctx.copyup_list[0] = req;
360 req->append_request(&mock_write_request);
361 req->send();
362
363 ASSERT_EQ(0, mock_write_request.ctx.wait());
364 }
365
366 TEST_F(TestMockIoCopyupRequest, StandardWithSnaps) {
367 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
368
369 librbd::ImageCtx *ictx;
370 ASSERT_EQ(0, open_image(m_image_name, &ictx));
371 ictx->snap_lock.get_write();
372 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx->size,
373 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
374 0, {});
375 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
376 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
377 0, {});
378 ictx->snapc = {2, {2, 1}};
379 ictx->snap_lock.put_write();
380
381 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
382 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
383
384 MockExclusiveLock mock_exclusive_lock;
385 MockJournal mock_journal;
386 MockObjectMap mock_object_map;
387 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
388 mock_object_map);
389
390 expect_test_features(mock_image_ctx);
391 expect_op_work_queue(mock_image_ctx);
392 expect_is_lock_owner(mock_image_ctx);
393
394 InSequence seq;
395
396 MockImageRequest mock_image_request;
397 std::string data(4096, '1');
398 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
399 data, 0);
400
401 MockAbstractObjectWriteRequest mock_write_request;
402 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
403 OBJECT_EXISTS);
404 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
405 expect_object_map_update(mock_image_ctx, 1, 0, OBJECT_EXISTS, true, 0);
406 expect_object_map_update(mock_image_ctx, 2, 0, OBJECT_EXISTS_CLEAN, true, 0);
407 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
408 0);
409
410 expect_add_copyup_ops(mock_write_request);
411 expect_copyup(mock_image_ctx, 0, "oid", data, 0);
412 expect_write(mock_image_ctx, CEPH_NOSNAP, "oid", 0);
413
414 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
415 {{0, 4096}}, {});
416 mock_image_ctx.copyup_list[0] = req;
417 req->append_request(&mock_write_request);
418 req->send();
419
420 ASSERT_EQ(0, mock_write_request.ctx.wait());
421 }
422
423 TEST_F(TestMockIoCopyupRequest, CopyOnRead) {
424 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
425
426 librbd::ImageCtx *ictx;
427 ASSERT_EQ(0, open_image(m_image_name, &ictx));
428
429 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
430 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
431
432 MockExclusiveLock mock_exclusive_lock;
433 MockJournal mock_journal;
434 MockObjectMap mock_object_map;
435 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
436 mock_object_map);
437
438 expect_op_work_queue(mock_image_ctx);
439 expect_is_lock_owner(mock_image_ctx);
440
441 InSequence seq;
442
443 MockImageRequest mock_image_request;
444 std::string data(4096, '1');
445 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
446 data, 0);
447
448 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
449 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
450 0);
451
452 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", data, 0);
453
454 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
455 {{0, 4096}}, {});
456 mock_image_ctx.copyup_list[0] = req;
457 req->send();
458 flush_async_operations(ictx);
459 }
460
461 TEST_F(TestMockIoCopyupRequest, CopyOnReadWithSnaps) {
462 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
463
464 librbd::ImageCtx *ictx;
465 ASSERT_EQ(0, open_image(m_image_name, &ictx));
466 ictx->snap_lock.get_write();
467 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
468 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
469 0, {});
470 ictx->snapc = {1, {1}};
471 ictx->snap_lock.put_write();
472
473 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
474 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
475
476 MockExclusiveLock mock_exclusive_lock;
477 MockJournal mock_journal;
478 MockObjectMap mock_object_map;
479 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
480 mock_object_map);
481
482 expect_test_features(mock_image_ctx);
483 expect_op_work_queue(mock_image_ctx);
484 expect_is_lock_owner(mock_image_ctx);
485
486 InSequence seq;
487
488 MockImageRequest mock_image_request;
489 std::string data(4096, '1');
490 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
491 data, 0);
492
493 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
494 expect_object_map_update(mock_image_ctx, 1, 0, OBJECT_EXISTS, true, 0);
495 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS_CLEAN,
496 true, 0);
497
498 expect_copyup(mock_image_ctx, 0, "oid", data, 0);
499
500 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
501 {{0, 4096}}, {});
502 mock_image_ctx.copyup_list[0] = req;
503 req->send();
504 flush_async_operations(ictx);
505 }
506
507 TEST_F(TestMockIoCopyupRequest, DeepCopy) {
508 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
509
510 librbd::ImageCtx *ictx;
511 ASSERT_EQ(0, open_image(m_image_name, &ictx));
512
513 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
514 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
515
516 MockExclusiveLock mock_exclusive_lock;
517 MockJournal mock_journal;
518 MockObjectMap mock_object_map;
519 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
520 mock_object_map);
521
522 expect_op_work_queue(mock_image_ctx);
523 expect_is_lock_owner(mock_image_ctx);
524
525 InSequence seq;
526
527 MockAbstractObjectWriteRequest mock_write_request;
528 MockObjectCopyRequest mock_object_copy_request;
529 mock_image_ctx.migration_info = {1, "", "", "image id", {}, ictx->size, true};
530 expect_is_empty_write_op(mock_write_request, false);
531 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
532
533 expect_is_empty_write_op(mock_write_request, false);
534 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
535 OBJECT_EXISTS);
536 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
537 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
538 0);
539
540 expect_add_copyup_ops(mock_write_request);
541 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", "", 0);
542 expect_write(mock_image_ctx, CEPH_NOSNAP, "oid", 0);
543
544 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
545 {{0, 4096}}, {});
546 mock_image_ctx.copyup_list[0] = req;
547 req->append_request(&mock_write_request);
548 req->send();
549
550 ASSERT_EQ(0, mock_write_request.ctx.wait());
551 }
552
553 TEST_F(TestMockIoCopyupRequest, DeepCopyOnRead) {
554 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
555
556 librbd::ImageCtx *ictx;
557 ASSERT_EQ(0, open_image(m_image_name, &ictx));
558
559 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
560 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
561
562 MockExclusiveLock mock_exclusive_lock;
563 MockJournal mock_journal;
564 MockObjectMap mock_object_map;
565 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
566 mock_object_map);
567
568 expect_op_work_queue(mock_image_ctx);
569 expect_is_lock_owner(mock_image_ctx);
570
571 InSequence seq;
572
573 MockObjectCopyRequest mock_object_copy_request;
574 mock_image_ctx.migration_info = {1, "", "", "image id", {}, ictx->size,
575 false};
576 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
577
578 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
579 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
580 0);
581
582 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", "", 0);
583
584 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
585 {{0, 4096}}, {});
586 mock_image_ctx.copyup_list[0] = req;
587 req->send();
588 flush_async_operations(ictx);
589 }
590
591 TEST_F(TestMockIoCopyupRequest, DeepCopyWithPostSnaps) {
592 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
593
594 librbd::ImageCtx *ictx;
595 ASSERT_EQ(0, open_image(m_image_name, &ictx));
596 ictx->snap_lock.get_write();
597 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx->size,
598 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
599 0, {});
600 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx->size,
601 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
602 0, {});
603 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
604 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
605 0, {});
606 ictx->snapc = {3, {3, 2, 1}};
607 ictx->snap_lock.put_write();
608
609 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
610 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
611
612 MockExclusiveLock mock_exclusive_lock;
613 MockJournal mock_journal;
614 MockObjectMap mock_object_map;
615 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
616 mock_object_map);
617
618 expect_test_features(mock_image_ctx);
619 expect_op_work_queue(mock_image_ctx);
620 expect_is_lock_owner(mock_image_ctx);
621
622 InSequence seq;
623
624 MockAbstractObjectWriteRequest mock_write_request;
625 MockObjectCopyRequest mock_object_copy_request;
626 mock_image_ctx.migration_info = {1, "", "", "image id",
627 {{CEPH_NOSNAP, {2, 1}}},
628 ictx->size, true};
629 expect_is_empty_write_op(mock_write_request, false);
630 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
631
632 expect_is_empty_write_op(mock_write_request, false);
633 expect_get_parent_overlap(mock_image_ctx, 1, 0, 0);
634 expect_get_parent_overlap(mock_image_ctx, 2, 1, 0);
635 expect_prune_parent_extents(mock_image_ctx, 1, 1);
636 expect_get_parent_overlap(mock_image_ctx, 3, 1, 0);
637 expect_prune_parent_extents(mock_image_ctx, 1, 1);
638 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
639 OBJECT_EXISTS);
640 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
641 expect_object_map_update(mock_image_ctx, 2, 0, OBJECT_EXISTS, true, 0);
642 expect_object_map_update(mock_image_ctx, 3, 0, OBJECT_EXISTS_CLEAN, true, 0);
643 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
644 0);
645
646 expect_add_copyup_ops(mock_write_request);
647 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", "", 0);
648 expect_write(mock_image_ctx, CEPH_NOSNAP, "oid", 0);
649
650 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
651 {{0, 4096}}, {});
652 mock_image_ctx.copyup_list[0] = req;
653 req->append_request(&mock_write_request);
654 req->send();
655
656 ASSERT_EQ(0, mock_write_request.ctx.wait());
657 }
658
659 TEST_F(TestMockIoCopyupRequest, DeepCopyWithPreAndPostSnaps) {
660 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
661
662 librbd::ImageCtx *ictx;
663 ASSERT_EQ(0, open_image(m_image_name, &ictx));
664 ictx->snap_lock.get_write();
665 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "4", 4, ictx->size,
666 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
667 0, {});
668 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx->size,
669 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
670 0, {});
671 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx->size,
672 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
673 0, {});
674 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
675 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
676 0, {});
677 ictx->snapc = {4, {4, 3, 2, 1}};
678 ictx->snap_lock.put_write();
679
680 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
681 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
682
683 MockExclusiveLock mock_exclusive_lock;
684 MockJournal mock_journal;
685 MockObjectMap mock_object_map;
686 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
687 mock_object_map);
688
689 expect_test_features(mock_image_ctx);
690 expect_op_work_queue(mock_image_ctx);
691 expect_is_lock_owner(mock_image_ctx);
692
693 InSequence seq;
694
695 MockAbstractObjectWriteRequest mock_write_request;
696 MockObjectCopyRequest mock_object_copy_request;
697 mock_image_ctx.migration_info = {1, "", "", "image id",
698 {{CEPH_NOSNAP, {2, 1}}, {10, {1}}},
699 ictx->size, true};
700 expect_is_empty_write_op(mock_write_request, false);
701 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, 0);
702
703 expect_is_empty_write_op(mock_write_request, false);
704 expect_get_parent_overlap(mock_image_ctx, 2, 0, 0);
705 expect_get_parent_overlap(mock_image_ctx, 3, 1, 0);
706 expect_prune_parent_extents(mock_image_ctx, 1, 1);
707 expect_get_parent_overlap(mock_image_ctx, 4, 1, 0);
708 expect_prune_parent_extents(mock_image_ctx, 1, 1);
709 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
710 OBJECT_EXISTS);
711 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
712 expect_object_map_update(mock_image_ctx, 3, 0, OBJECT_EXISTS_CLEAN, true, 0);
713 expect_object_map_update(mock_image_ctx, 4, 0, OBJECT_EXISTS_CLEAN, true, 0);
714 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
715 0);
716
717 expect_add_copyup_ops(mock_write_request);
718 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", "", 0);
719 expect_write(mock_image_ctx, CEPH_NOSNAP, "oid", 0);
720
721 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
722 {{0, 4096}}, {});
723 mock_image_ctx.copyup_list[0] = req;
724 req->append_request(&mock_write_request);
725 req->send();
726
727 ASSERT_EQ(0, mock_write_request.ctx.wait());
728 }
729
730 TEST_F(TestMockIoCopyupRequest, ZeroedCopyup) {
731 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
732
733 librbd::ImageCtx *ictx;
734 ASSERT_EQ(0, open_image(m_image_name, &ictx));
735
736 MockTestImageCtx mock_image_ctx(*ictx);
737
738 MockExclusiveLock mock_exclusive_lock;
739 MockJournal mock_journal;
740 MockObjectMap mock_object_map;
741 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
742 mock_object_map);
743
744 expect_op_work_queue(mock_image_ctx);
745 expect_is_lock_owner(mock_image_ctx);
746
747 InSequence seq;
748
749 MockAbstractObjectWriteRequest mock_write_request;
750 expect_is_empty_write_op(mock_write_request, false);
751 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
752 OBJECT_EXISTS);
753 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
754 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
755 0);
756
757 expect_add_copyup_ops(mock_write_request);
758 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", "", 0);
759 expect_write(mock_image_ctx, CEPH_NOSNAP, "oid", 0);
760
761 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
762 {{0, 4096}}, {});
763 mock_image_ctx.copyup_list[0] = req;
764 req->append_request(&mock_write_request);
765 req->send();
766
767 ASSERT_EQ(0, mock_write_request.ctx.wait());
768 }
769
770 TEST_F(TestMockIoCopyupRequest, ZeroedCopyOnRead) {
771 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
772
773 librbd::ImageCtx *ictx;
774 ASSERT_EQ(0, open_image(m_image_name, &ictx));
775
776 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
777 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
778
779 MockExclusiveLock mock_exclusive_lock;
780 MockJournal mock_journal;
781 MockObjectMap mock_object_map;
782 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
783 mock_object_map);
784
785 expect_op_work_queue(mock_image_ctx);
786 expect_is_lock_owner(mock_image_ctx);
787
788 InSequence seq;
789
790 MockImageRequest mock_image_request;
791 std::string data(4096, '\0');
792 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
793 data, 0);
794
795 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
796 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
797 0);
798
799 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", "", 0);
800
801 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
802 {{0, 4096}}, {});
803 mock_image_ctx.copyup_list[0] = req;
804 req->send();
805 flush_async_operations(ictx);
806 }
807
808 TEST_F(TestMockIoCopyupRequest, NoOpCopyup) {
809 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
810
811 librbd::ImageCtx *ictx;
812 ASSERT_EQ(0, open_image(m_image_name, &ictx));
813
814 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
815 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
816
817 MockExclusiveLock mock_exclusive_lock;
818 MockJournal mock_journal;
819 MockObjectMap mock_object_map;
820 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
821 mock_object_map);
822
823 expect_op_work_queue(mock_image_ctx);
824 expect_is_lock_owner(mock_image_ctx);
825
826 InSequence seq;
827
828 MockImageRequest mock_image_request;
829 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
830 "", -ENOENT);
831
832 MockAbstractObjectWriteRequest mock_write_request;
833 expect_is_empty_write_op(mock_write_request, true);
834
835 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
836 {{0, 4096}}, {});
837 mock_image_ctx.copyup_list[0] = req;
838 req->append_request(&mock_write_request);
839 req->send();
840
841 ASSERT_EQ(0, mock_write_request.ctx.wait());
842 }
843
844 TEST_F(TestMockIoCopyupRequest, RestartWrite) {
845 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
846
847 librbd::ImageCtx *ictx;
848 ASSERT_EQ(0, open_image(m_image_name, &ictx));
849
850 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
851 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
852
853 MockExclusiveLock mock_exclusive_lock;
854 MockJournal mock_journal;
855 MockObjectMap mock_object_map;
856 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
857 mock_object_map);
858
859 expect_op_work_queue(mock_image_ctx);
860 expect_is_lock_owner(mock_image_ctx);
861
862 InSequence seq;
863
864 MockImageRequest mock_image_request;
865 std::string data(4096, '1');
866 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
867 data, 0);
868
869 MockAbstractObjectWriteRequest mock_write_request1;
870 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request1,
871 OBJECT_EXISTS);
872 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
873 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
874 0);
875
876 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
877 {{0, 4096}}, {});
878 expect_add_copyup_ops(mock_write_request1);
879 expect_copyup(mock_image_ctx, CEPH_NOSNAP, "oid", data, 0);
880
881 MockAbstractObjectWriteRequest mock_write_request2;
882 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
883 write("oid", _, 0, 0, _))
884 .WillOnce(WithoutArgs(Invoke([req, &mock_write_request2]() {
885 req->append_request(&mock_write_request2);
886 return 0;
887 })));
888
889 mock_image_ctx.copyup_list[0] = req;
890 req->append_request(&mock_write_request1);
891 req->send();
892
893 ASSERT_EQ(0, mock_write_request1.ctx.wait());
894 ASSERT_EQ(-ERESTART, mock_write_request2.ctx.wait());
895 }
896
897 TEST_F(TestMockIoCopyupRequest, ReadFromParentError) {
898 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
899
900 librbd::ImageCtx *ictx;
901 ASSERT_EQ(0, open_image(m_image_name, &ictx));
902
903 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
904 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
905
906 MockExclusiveLock mock_exclusive_lock;
907 MockJournal mock_journal;
908 MockObjectMap mock_object_map;
909 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
910 mock_object_map);
911
912 expect_op_work_queue(mock_image_ctx);
913 expect_is_lock_owner(mock_image_ctx);
914
915 InSequence seq;
916
917 MockImageRequest mock_image_request;
918 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
919 "", -EPERM);
920
921 MockAbstractObjectWriteRequest mock_write_request;
922 expect_is_empty_write_op(mock_write_request, false);
923
924 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
925 {{0, 4096}}, {});
926 mock_image_ctx.copyup_list[0] = req;
927 req->append_request(&mock_write_request);
928 req->send();
929
930 ASSERT_EQ(-EPERM, mock_write_request.ctx.wait());
931 }
932
933 TEST_F(TestMockIoCopyupRequest, DeepCopyError) {
934 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
935
936 librbd::ImageCtx *ictx;
937 ASSERT_EQ(0, open_image(m_image_name, &ictx));
938
939 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
940 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
941
942 MockExclusiveLock mock_exclusive_lock;
943 MockJournal mock_journal;
944 MockObjectMap mock_object_map;
945 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
946 mock_object_map);
947
948 expect_op_work_queue(mock_image_ctx);
949 expect_is_lock_owner(mock_image_ctx);
950
951 InSequence seq;
952
953 MockAbstractObjectWriteRequest mock_write_request;
954 MockObjectCopyRequest mock_object_copy_request;
955 mock_image_ctx.migration_info = {1, "", "", "image id", {}, ictx->size, true};
956 expect_is_empty_write_op(mock_write_request, false);
957 expect_object_copy(mock_image_ctx, mock_object_copy_request, true, -EPERM);
958
959 expect_is_empty_write_op(mock_write_request, false);
960
961 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
962 {{0, 4096}}, {});
963 mock_image_ctx.copyup_list[0] = req;
964 req->append_request(&mock_write_request);
965 req->send();
966
967 ASSERT_EQ(-EPERM, mock_write_request.ctx.wait());
968 }
969
970 TEST_F(TestMockIoCopyupRequest, UpdateObjectMapError) {
971 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_OBJECT_MAP);
972
973 librbd::ImageCtx *ictx;
974 ASSERT_EQ(0, open_image(m_image_name, &ictx));
975
976 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
977 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
978
979 MockExclusiveLock mock_exclusive_lock;
980 MockJournal mock_journal;
981 MockObjectMap mock_object_map;
982 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
983 mock_object_map);
984
985 expect_op_work_queue(mock_image_ctx);
986 expect_is_lock_owner(mock_image_ctx);
987
988 InSequence seq;
989
990 MockImageRequest mock_image_request;
991 std::string data(4096, '1');
992 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
993 data, 0);
994
995 MockAbstractObjectWriteRequest mock_write_request;
996 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
997 OBJECT_EXISTS);
998 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
999 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
1000 -EINVAL);
1001
1002 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
1003 {{0, 4096}}, {});
1004 mock_image_ctx.copyup_list[0] = req;
1005 req->append_request(&mock_write_request);
1006 req->send();
1007
1008 ASSERT_EQ(-EINVAL, mock_write_request.ctx.wait());
1009 }
1010
1011 TEST_F(TestMockIoCopyupRequest, CopyupError) {
1012 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1013
1014 librbd::ImageCtx *ictx;
1015 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1016 ictx->snap_lock.get_write();
1017 ictx->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx->size,
1018 ictx->parent_md, RBD_PROTECTION_STATUS_UNPROTECTED,
1019 0, {});
1020 ictx->snapc = {1, {1}};
1021 ictx->snap_lock.put_write();
1022
1023 MockTestImageCtx mock_parent_image_ctx(*ictx->parent);
1024 MockTestImageCtx mock_image_ctx(*ictx, &mock_parent_image_ctx);
1025
1026 MockExclusiveLock mock_exclusive_lock;
1027 MockJournal mock_journal;
1028 MockObjectMap mock_object_map;
1029 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
1030 mock_object_map);
1031
1032 expect_test_features(mock_image_ctx);
1033 expect_op_work_queue(mock_image_ctx);
1034 expect_is_lock_owner(mock_image_ctx);
1035
1036 InSequence seq;
1037
1038 MockImageRequest mock_image_request;
1039 std::string data(4096, '1');
1040 expect_read_parent(mock_parent_image_ctx, mock_image_request, {{0, 4096}},
1041 data, 0);
1042
1043 MockAbstractObjectWriteRequest mock_write_request;
1044 expect_get_pre_write_object_map_state(mock_image_ctx, mock_write_request,
1045 OBJECT_EXISTS);
1046 expect_object_map_at(mock_image_ctx, 0, OBJECT_NONEXISTENT);
1047 expect_object_map_update(mock_image_ctx, 1, 0, OBJECT_EXISTS, true, 0);
1048 expect_object_map_update(mock_image_ctx, CEPH_NOSNAP, 0, OBJECT_EXISTS, true,
1049 0);
1050
1051 expect_add_copyup_ops(mock_write_request);
1052 expect_copyup(mock_image_ctx, 0, "oid", data, -EPERM);
1053 expect_write(mock_image_ctx, CEPH_NOSNAP, "oid", 0);
1054
1055 auto req = new MockCopyupRequest(&mock_image_ctx, "oid", 0,
1056 {{0, 4096}}, {});
1057 mock_image_ctx.copyup_list[0] = req;
1058 req->append_request(&mock_write_request);
1059 req->send();
1060
1061 ASSERT_EQ(-EPERM, mock_write_request.ctx.wait());
1062 flush_async_operations(ictx);
1063 }
1064
1065 } // namespace io
1066 } // namespace librbd