]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / librbd / deep_copy / test_mock_ObjectCopyRequest.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 "include/interval_set.h"
6 #include "include/rbd/librbd.hpp"
7 #include "include/rbd/object_map_types.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/internal.h"
11 #include "librbd/Operations.h"
12 #include "librbd/api/Image.h"
13 #include "librbd/deep_copy/ObjectCopyRequest.h"
14 #include "librbd/io/ImageRequest.h"
15 #include "librbd/io/ImageRequestWQ.h"
16 #include "librbd/io/ReadResult.h"
17 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
18 #include "test/librbd/mock/MockImageCtx.h"
19 #include "test/librbd/test_support.h"
20
21 namespace librbd {
22 namespace {
23
24 struct MockTestImageCtx : public librbd::MockImageCtx {
25 explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
26 : librbd::MockImageCtx(image_ctx) {
27 }
28
29 MockTestImageCtx *parent = nullptr;
30 };
31
32 } // anonymous namespace
33
34 namespace util {
35
36 inline ImageCtx* get_image_ctx(MockTestImageCtx* image_ctx) {
37 return image_ctx->image_ctx;
38 }
39
40 } // namespace util
41
42 namespace io {
43
44 template <>
45 struct ImageRequest<MockTestImageCtx> {
46 static ImageRequest *s_instance;
47
48 static void aio_read(MockTestImageCtx *ictx, AioCompletion *c,
49 Extents &&image_extents, ReadResult &&read_result,
50 int op_flags, const ZTracer::Trace &parent_trace) {
51 ceph_assert(s_instance != nullptr);
52 s_instance->aio_read(c, image_extents);
53 }
54 MOCK_METHOD2(aio_read, void(AioCompletion *, const Extents&));
55 };
56
57 ImageRequest<MockTestImageCtx> *ImageRequest<MockTestImageCtx>::s_instance = nullptr;
58
59 } // namespace io
60
61 } // namespace librbd
62
63 // template definitions
64 #include "librbd/deep_copy/ObjectCopyRequest.cc"
65 template class librbd::deep_copy::ObjectCopyRequest<librbd::MockTestImageCtx>;
66
67 bool operator==(const SnapContext& rhs, const SnapContext& lhs) {
68 return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps);
69 }
70
71 namespace librbd {
72 namespace deep_copy {
73
74 using ::testing::_;
75 using ::testing::DoAll;
76 using ::testing::DoDefault;
77 using ::testing::InSequence;
78 using ::testing::Invoke;
79 using ::testing::Return;
80 using ::testing::ReturnNew;
81 using ::testing::WithArg;
82
83 namespace {
84
85 void scribble(librbd::ImageCtx *image_ctx, int num_ops, size_t max_size,
86 interval_set<uint64_t> *what)
87 {
88 uint64_t object_size = 1 << image_ctx->order;
89 for (int i = 0; i < num_ops; i++) {
90 uint64_t off = rand() % (object_size - max_size + 1);
91 uint64_t len = 1 + rand() % max_size;
92 std::cout << __func__ << ": off=" << off << ", len=" << len << std::endl;
93
94 bufferlist bl;
95 bl.append(std::string(len, '1'));
96
97 int r = image_ctx->io_work_queue->write(off, len, std::move(bl), 0);
98 ASSERT_EQ(static_cast<int>(len), r);
99
100 interval_set<uint64_t> w;
101 w.insert(off, len);
102 what->union_of(w);
103 }
104 std::cout << " wrote " << *what << std::endl;
105 }
106
107 } // anonymous namespace
108
109 class TestMockDeepCopyObjectCopyRequest : public TestMockFixture {
110 public:
111 typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
112
113 librbd::ImageCtx *m_src_image_ctx;
114 librbd::ImageCtx *m_dst_image_ctx;
115 ThreadPool *m_thread_pool;
116 ContextWQ *m_work_queue;
117
118 SnapMap m_snap_map;
119 std::vector<librados::snap_t> m_src_snap_ids;
120 std::vector<librados::snap_t> m_dst_snap_ids;
121
122 void SetUp() override {
123 TestMockFixture::SetUp();
124
125 ASSERT_EQ(0, open_image(m_image_name, &m_src_image_ctx));
126
127 librbd::NoOpProgressContext no_op;
128 m_image_size = 1 << m_src_image_ctx->order;
129 ASSERT_EQ(0, m_src_image_ctx->operations->resize(m_image_size, true, no_op));
130
131 librbd::RBD rbd;
132 std::string dst_image_name = get_temp_image_name();
133 ASSERT_EQ(0, create_image_pp(rbd, m_ioctx, dst_image_name, m_image_size));
134 ASSERT_EQ(0, open_image(dst_image_name, &m_dst_image_ctx));
135
136 librbd::ImageCtx::get_thread_pool_instance(m_src_image_ctx->cct,
137 &m_thread_pool, &m_work_queue);
138 }
139
140 bool is_fast_diff(librbd::MockImageCtx &mock_image_ctx) {
141 return (mock_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0;
142 }
143
144 void prepare_exclusive_lock(librbd::MockImageCtx &mock_image_ctx,
145 librbd::MockExclusiveLock &mock_exclusive_lock) {
146 if ((mock_image_ctx.features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
147 return;
148 }
149 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
150 }
151
152 void expect_get_object_count(librbd::MockImageCtx& mock_image_ctx) {
153 EXPECT_CALL(mock_image_ctx, get_object_count(_))
154 .WillRepeatedly(Invoke([&mock_image_ctx](librados::snap_t snap_id) {
155 return mock_image_ctx.image_ctx->get_object_count(snap_id);
156 }));
157 }
158
159 void expect_test_features(librbd::MockImageCtx &mock_image_ctx) {
160 EXPECT_CALL(mock_image_ctx, test_features(_))
161 .WillRepeatedly(WithArg<0>(Invoke([&mock_image_ctx](uint64_t features) {
162 return (mock_image_ctx.features & features) != 0;
163 })));
164 }
165
166 void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
167 if ((m_src_image_ctx->features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
168 return;
169 }
170 EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(
171 ReturnNew<FunctionContext>([](int) {}));
172 }
173
174 void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
175 librados::MockTestMemIoCtxImpl &mock_io_ctx,
176 const librados::snap_set_t &snap_set) {
177 expect_get_object_name(mock_image_ctx);
178 expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
179 EXPECT_CALL(mock_io_ctx,
180 list_snaps(mock_image_ctx.image_ctx->get_object_name(0), _))
181 .WillOnce(DoAll(WithArg<1>(Invoke([&snap_set](librados::snap_set_t *out_snap_set) {
182 *out_snap_set = snap_set;
183 })),
184 Return(0)));
185 }
186
187 void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
188 librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
189 expect_get_object_name(mock_image_ctx);
190 expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
191 auto &expect = EXPECT_CALL(mock_io_ctx,
192 list_snaps(mock_image_ctx.image_ctx->get_object_name(0),
193 _));
194 if (r < 0) {
195 expect.WillOnce(Return(r));
196 } else {
197 expect.WillOnce(DoDefault());
198 }
199 }
200
201 void expect_get_object_name(librbd::MockTestImageCtx &mock_image_ctx) {
202 EXPECT_CALL(mock_image_ctx, get_object_name(0))
203 .WillOnce(Return(mock_image_ctx.image_ctx->get_object_name(0)));
204 }
205
206 MockObjectCopyRequest *create_request(
207 librbd::MockTestImageCtx &mock_src_image_ctx,
208 librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish) {
209 expect_get_object_name(mock_dst_image_ctx);
210 expect_get_object_count(mock_dst_image_ctx);
211 return new MockObjectCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx,
212 m_snap_map, 0, false, on_finish);
213 }
214
215 void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
216 uint64_t snap_id) {
217 EXPECT_CALL(mock_io_ctx, set_snap_read(snap_id));
218 }
219
220 void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, uint64_t offset,
221 uint64_t length, int r) {
222
223 auto &expect = EXPECT_CALL(mock_io_ctx, sparse_read(_, offset, length, _, _));
224 if (r < 0) {
225 expect.WillOnce(Return(r));
226 } else {
227 expect.WillOnce(DoDefault());
228 }
229 }
230
231 void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
232 const interval_set<uint64_t> &extents, int r) {
233 for (auto extent : extents) {
234 expect_sparse_read(mock_io_ctx, extent.first, extent.second, r);
235 if (r < 0) {
236 break;
237 }
238 }
239 }
240
241 void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
242 uint64_t offset, uint64_t length,
243 const SnapContext &snapc, int r) {
244 auto &expect = EXPECT_CALL(mock_io_ctx, write(_, _, length, offset, snapc));
245 if (r < 0) {
246 expect.WillOnce(Return(r));
247 } else {
248 expect.WillOnce(DoDefault());
249 }
250 }
251
252 void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
253 const interval_set<uint64_t> &extents,
254 const SnapContext &snapc, int r) {
255 for (auto extent : extents) {
256 expect_write(mock_io_ctx, extent.first, extent.second, snapc, r);
257 if (r < 0) {
258 break;
259 }
260 }
261 }
262
263 void expect_truncate(librados::MockTestMemIoCtxImpl &mock_io_ctx,
264 uint64_t offset, int r) {
265 auto &expect = EXPECT_CALL(mock_io_ctx, truncate(_, offset, _));
266 if (r < 0) {
267 expect.WillOnce(Return(r));
268 } else {
269 expect.WillOnce(DoDefault());
270 }
271 }
272
273 void expect_remove(librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
274 auto &expect = EXPECT_CALL(mock_io_ctx, remove(_, _));
275 if (r < 0) {
276 expect.WillOnce(Return(r));
277 } else {
278 expect.WillOnce(DoDefault());
279 }
280 }
281
282 void expect_update_object_map(librbd::MockTestImageCtx &mock_image_ctx,
283 librbd::MockObjectMap &mock_object_map,
284 librados::snap_t snap_id, uint8_t state,
285 int r) {
286 if (mock_image_ctx.image_ctx->object_map != nullptr) {
287 auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, false, _));
288 if (r < 0) {
289 expect.WillOnce(DoAll(WithArg<7>(Invoke([this, r](Context *ctx) {
290 m_work_queue->queue(ctx, r);
291 })),
292 Return(true)));
293 } else {
294 expect.WillOnce(DoAll(WithArg<7>(Invoke([&mock_image_ctx, snap_id, state](Context *ctx) {
295 ceph_assert(mock_image_ctx.image_ctx->snap_lock.is_locked());
296 ceph_assert(mock_image_ctx.image_ctx->object_map_lock.is_wlocked());
297 mock_image_ctx.image_ctx->object_map->aio_update<Context>(
298 snap_id, 0, 1, state, boost::none, {}, false, ctx);
299 })),
300 Return(true)));
301 }
302 }
303 }
304
305 int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name,
306 librados::snap_t *snap_id) {
307 int r = image_ctx->operations->snap_create(
308 cls::rbd::UserSnapshotNamespace(), snap_name);
309 if (r < 0) {
310 return r;
311 }
312
313 r = image_ctx->state->refresh();
314 if (r < 0) {
315 return r;
316 }
317
318 if (image_ctx->snap_ids.count({cls::rbd::UserSnapshotNamespace(),
319 snap_name}) == 0) {
320 return -ENOENT;
321 }
322
323 if (snap_id != nullptr) {
324 *snap_id = image_ctx->snap_ids[{cls::rbd::UserSnapshotNamespace(),
325 snap_name}];
326 }
327 return 0;
328 }
329
330 int create_snap(const char* snap_name) {
331 librados::snap_t src_snap_id;
332 int r = create_snap(m_src_image_ctx, snap_name, &src_snap_id);
333 if (r < 0) {
334 return r;
335 }
336
337 librados::snap_t dst_snap_id;
338 r = create_snap(m_dst_image_ctx, snap_name, &dst_snap_id);
339 if (r < 0) {
340 return r;
341 }
342
343 // collection of all existing snaps in dst image
344 SnapIds dst_snap_ids({dst_snap_id});
345 if (!m_snap_map.empty()) {
346 dst_snap_ids.insert(dst_snap_ids.end(),
347 m_snap_map.rbegin()->second.begin(),
348 m_snap_map.rbegin()->second.end());
349 }
350 m_snap_map[src_snap_id] = dst_snap_ids;
351 m_src_snap_ids.push_back(src_snap_id);
352 m_dst_snap_ids.push_back(dst_snap_id);
353
354 return 0;
355 }
356
357 std::string get_snap_name(librbd::ImageCtx *image_ctx,
358 librados::snap_t snap_id) {
359 auto it = std::find_if(image_ctx->snap_ids.begin(),
360 image_ctx->snap_ids.end(),
361 [snap_id](const std::pair<std::pair<cls::rbd::SnapshotNamespace,
362 std::string>,
363 librados::snap_t> &pair) {
364 return (pair.second == snap_id);
365 });
366 if (it == image_ctx->snap_ids.end()) {
367 return "";
368 }
369 return it->first.second;
370 }
371
372 int compare_objects() {
373 SnapMap snap_map(m_snap_map);
374 if (snap_map.empty()) {
375 return -ENOENT;
376 }
377
378 int r;
379 uint64_t object_size = 1 << m_src_image_ctx->order;
380 while (!snap_map.empty()) {
381 librados::snap_t src_snap_id = snap_map.begin()->first;
382 librados::snap_t dst_snap_id = *snap_map.begin()->second.begin();
383 snap_map.erase(snap_map.begin());
384
385 std::string snap_name = get_snap_name(m_src_image_ctx, src_snap_id);
386 if (snap_name.empty()) {
387 return -ENOENT;
388 }
389
390 std::cout << "comparing '" << snap_name << " (" << src_snap_id
391 << " to " << dst_snap_id << ")" << std::endl;
392
393 r = librbd::api::Image<>::snap_set(m_src_image_ctx,
394 cls::rbd::UserSnapshotNamespace(),
395 snap_name.c_str());
396 if (r < 0) {
397 return r;
398 }
399
400 r = librbd::api::Image<>::snap_set(m_dst_image_ctx,
401 cls::rbd::UserSnapshotNamespace(),
402 snap_name.c_str());
403 if (r < 0) {
404 return r;
405 }
406
407 bufferlist src_bl;
408 src_bl.append(std::string(object_size, '1'));
409 r = m_src_image_ctx->io_work_queue->read(
410 0, object_size, librbd::io::ReadResult{&src_bl}, 0);
411 if (r < 0) {
412 return r;
413 }
414
415 bufferlist dst_bl;
416 dst_bl.append(std::string(object_size, '1'));
417 r = m_dst_image_ctx->io_work_queue->read(
418 0, object_size, librbd::io::ReadResult{&dst_bl}, 0);
419 if (r < 0) {
420 return r;
421 }
422
423 if (!src_bl.contents_equal(dst_bl)) {
424 return -EBADMSG;
425 }
426 }
427
428 r = librbd::api::Image<>::snap_set(m_src_image_ctx,
429 cls::rbd::UserSnapshotNamespace(),
430 nullptr);
431 if (r < 0) {
432 return r;
433 }
434 r = librbd::api::Image<>::snap_set(m_dst_image_ctx,
435 cls::rbd::UserSnapshotNamespace(),
436 nullptr);
437 if (r < 0) {
438 return r;
439 }
440
441 return 0;
442 }
443 };
444
445 TEST_F(TestMockDeepCopyObjectCopyRequest, DNE) {
446 ASSERT_EQ(0, create_snap("copy"));
447 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
448 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
449
450 librbd::MockExclusiveLock mock_exclusive_lock;
451 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
452
453 librbd::MockObjectMap mock_object_map;
454 mock_dst_image_ctx.object_map = &mock_object_map;
455 expect_test_features(mock_dst_image_ctx);
456
457 C_SaferCond ctx;
458 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
459 mock_dst_image_ctx, &ctx);
460
461 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
462 request->get_src_io_ctx()));
463
464 InSequence seq;
465 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, -ENOENT);
466
467 request->send();
468 ASSERT_EQ(-ENOENT, ctx.wait());
469 }
470
471 TEST_F(TestMockDeepCopyObjectCopyRequest, Write) {
472 // scribble some data
473 interval_set<uint64_t> one;
474 scribble(m_src_image_ctx, 10, 102400, &one);
475
476 ASSERT_EQ(0, create_snap("copy"));
477 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
478 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
479
480 librbd::MockExclusiveLock mock_exclusive_lock;
481 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
482
483 librbd::MockObjectMap mock_object_map;
484 mock_dst_image_ctx.object_map = &mock_object_map;
485
486 expect_test_features(mock_dst_image_ctx);
487
488 C_SaferCond ctx;
489 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
490 mock_dst_image_ctx, &ctx);
491
492 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
493 request->get_src_io_ctx()));
494 librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
495 request->get_dst_io_ctx()));
496
497 InSequence seq;
498 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
499 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
500 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
501 expect_start_op(mock_exclusive_lock);
502 expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
503 expect_start_op(mock_exclusive_lock);
504 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
505 m_dst_snap_ids[0], OBJECT_EXISTS, 0);
506
507 request->send();
508 ASSERT_EQ(0, ctx.wait());
509 ASSERT_EQ(0, compare_objects());
510 }
511
512 TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingStaleSnapSet) {
513 ASSERT_EQ(0, create_snap("one"));
514 ASSERT_EQ(0, create_snap("two"));
515
516 // scribble some data
517 interval_set<uint64_t> one;
518 scribble(m_src_image_ctx, 10, 102400, &one);
519 ASSERT_EQ(0, create_snap("three"));
520
521 ASSERT_EQ(0, create_snap("copy"));
522 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
523 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
524
525 librbd::MockExclusiveLock mock_exclusive_lock;
526 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
527
528 librbd::MockObjectMap mock_object_map;
529 mock_dst_image_ctx.object_map = &mock_object_map;
530
531 expect_test_features(mock_dst_image_ctx);
532
533 C_SaferCond ctx;
534 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
535 mock_dst_image_ctx, &ctx);
536
537 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
538 request->get_src_io_ctx()));
539 librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
540 request->get_dst_io_ctx()));
541
542 librados::clone_info_t dummy_clone_info;
543 dummy_clone_info.cloneid = librados::SNAP_HEAD;
544 dummy_clone_info.size = 123;
545
546 librados::snap_set_t dummy_snap_set1;
547 dummy_snap_set1.clones.push_back(dummy_clone_info);
548
549 dummy_clone_info.size = 234;
550 librados::snap_set_t dummy_snap_set2;
551 dummy_snap_set2.clones.push_back(dummy_clone_info);
552
553 InSequence seq;
554 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, dummy_snap_set1);
555 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[3]);
556 expect_sparse_read(mock_src_io_ctx, 0, 123, -ENOENT);
557 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, dummy_snap_set2);
558 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[3]);
559 expect_sparse_read(mock_src_io_ctx, 0, 234, -ENOENT);
560 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
561 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[3]);
562 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
563 expect_start_op(mock_exclusive_lock);
564 expect_write(mock_dst_io_ctx, 0, one.range_end(),
565 {m_dst_snap_ids[1], {m_dst_snap_ids[1],
566 m_dst_snap_ids[0]}},
567 0);
568 expect_start_op(mock_exclusive_lock);
569 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
570 m_dst_snap_ids[2], OBJECT_EXISTS, 0);
571 expect_start_op(mock_exclusive_lock);
572 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
573 m_dst_snap_ids[3], is_fast_diff(mock_dst_image_ctx) ?
574 OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
575
576 request->send();
577 ASSERT_EQ(0, ctx.wait());
578 ASSERT_EQ(0, compare_objects());
579 }
580
581 TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingUpToDateSnapMap) {
582 // scribble some data
583 interval_set<uint64_t> one;
584 scribble(m_src_image_ctx, 10, 102400, &one);
585
586 ASSERT_EQ(0, create_snap("copy"));
587 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
588 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
589
590 librbd::MockExclusiveLock mock_exclusive_lock;
591 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
592
593 librbd::MockObjectMap mock_object_map;
594 mock_dst_image_ctx.object_map = &mock_object_map;
595
596 expect_test_features(mock_dst_image_ctx);
597
598 C_SaferCond ctx;
599 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
600 mock_dst_image_ctx, &ctx);
601
602 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
603 request->get_src_io_ctx()));
604
605 InSequence seq;
606 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
607 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
608 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), -ENOENT);
609 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
610
611 request->send();
612 ASSERT_EQ(-ENOENT, ctx.wait());
613 }
614
615 TEST_F(TestMockDeepCopyObjectCopyRequest, ReadError) {
616 // scribble some data
617 interval_set<uint64_t> one;
618 scribble(m_src_image_ctx, 10, 102400, &one);
619
620 ASSERT_EQ(0, create_snap("copy"));
621 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
622 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
623
624 librbd::MockExclusiveLock mock_exclusive_lock;
625 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
626
627 librbd::MockObjectMap mock_object_map;
628 mock_dst_image_ctx.object_map = &mock_object_map;
629
630 expect_test_features(mock_dst_image_ctx);
631
632 C_SaferCond ctx;
633 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
634 mock_dst_image_ctx, &ctx);
635
636 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
637 request->get_src_io_ctx()));
638
639 InSequence seq;
640 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
641 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
642 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), -EINVAL);
643
644 request->send();
645 ASSERT_EQ(-EINVAL, ctx.wait());
646 }
647
648 TEST_F(TestMockDeepCopyObjectCopyRequest, WriteError) {
649 // scribble some data
650 interval_set<uint64_t> one;
651 scribble(m_src_image_ctx, 10, 102400, &one);
652
653 ASSERT_EQ(0, create_snap("copy"));
654 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
655 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
656
657 librbd::MockExclusiveLock mock_exclusive_lock;
658 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
659
660 librbd::MockObjectMap mock_object_map;
661 mock_dst_image_ctx.object_map = &mock_object_map;
662
663 expect_test_features(mock_dst_image_ctx);
664
665 C_SaferCond ctx;
666 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
667 mock_dst_image_ctx, &ctx);
668
669 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
670 request->get_src_io_ctx()));
671 librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
672 request->get_dst_io_ctx()));
673
674 InSequence seq;
675 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
676 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
677 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
678 expect_start_op(mock_exclusive_lock);
679 expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL);
680
681 request->send();
682 ASSERT_EQ(-EINVAL, ctx.wait());
683 }
684
685 TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnaps) {
686 // scribble some data
687 interval_set<uint64_t> one;
688 scribble(m_src_image_ctx, 10, 102400, &one);
689 ASSERT_EQ(0, create_snap("one"));
690
691 interval_set<uint64_t> two;
692 scribble(m_src_image_ctx, 10, 102400, &two);
693 ASSERT_EQ(0, create_snap("two"));
694
695 if (one.range_end() < two.range_end()) {
696 interval_set<uint64_t> resize_diff;
697 resize_diff.insert(one.range_end(), two.range_end() - one.range_end());
698 two.union_of(resize_diff);
699 }
700
701 ASSERT_EQ(0, create_snap("copy"));
702 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
703 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
704
705 librbd::MockExclusiveLock mock_exclusive_lock;
706 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
707
708 librbd::MockObjectMap mock_object_map;
709 mock_dst_image_ctx.object_map = &mock_object_map;
710
711 expect_test_features(mock_dst_image_ctx);
712
713 C_SaferCond ctx;
714 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
715 mock_dst_image_ctx, &ctx);
716
717 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
718 request->get_src_io_ctx()));
719 librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
720 request->get_dst_io_ctx()));
721
722 InSequence seq;
723 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
724 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
725 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
726 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[2]);
727 expect_sparse_read(mock_src_io_ctx, two, 0);
728 expect_start_op(mock_exclusive_lock);
729 expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
730 expect_start_op(mock_exclusive_lock);
731 expect_write(mock_dst_io_ctx, two,
732 {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0);
733 expect_start_op(mock_exclusive_lock);
734 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
735 m_dst_snap_ids[0], OBJECT_EXISTS, 0);
736 expect_start_op(mock_exclusive_lock);
737 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
738 m_dst_snap_ids[1], OBJECT_EXISTS, 0);
739 expect_start_op(mock_exclusive_lock);
740 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
741 m_dst_snap_ids[2], is_fast_diff(mock_dst_image_ctx) ?
742 OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
743
744 request->send();
745 ASSERT_EQ(0, ctx.wait());
746 ASSERT_EQ(0, compare_objects());
747 }
748
749 TEST_F(TestMockDeepCopyObjectCopyRequest, Trim) {
750 ASSERT_EQ(0, m_src_image_ctx->operations->metadata_set(
751 "conf_rbd_skip_partial_discard", "false"));
752 m_src_image_ctx->discard_granularity_bytes = 0;
753
754 // scribble some data
755 interval_set<uint64_t> one;
756 scribble(m_src_image_ctx, 10, 102400, &one);
757 ASSERT_EQ(0, create_snap("one"));
758
759 // trim the object
760 uint64_t trim_offset = rand() % one.range_end();
761 ASSERT_LE(0, m_src_image_ctx->io_work_queue->discard(
762 trim_offset, one.range_end() - trim_offset,
763 m_src_image_ctx->discard_granularity_bytes));
764 ASSERT_EQ(0, create_snap("copy"));
765
766 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
767 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
768
769 librbd::MockExclusiveLock mock_exclusive_lock;
770 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
771
772 librbd::MockObjectMap mock_object_map;
773 mock_dst_image_ctx.object_map = &mock_object_map;
774
775 expect_test_features(mock_dst_image_ctx);
776
777 C_SaferCond ctx;
778 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
779 mock_dst_image_ctx, &ctx);
780
781 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
782 request->get_src_io_ctx()));
783 librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
784 request->get_dst_io_ctx()));
785
786 InSequence seq;
787 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
788 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
789 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
790 expect_start_op(mock_exclusive_lock);
791 expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
792 expect_start_op(mock_exclusive_lock);
793 expect_truncate(mock_dst_io_ctx, trim_offset, 0);
794 expect_start_op(mock_exclusive_lock);
795 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
796 m_dst_snap_ids[0], OBJECT_EXISTS, 0);
797 expect_start_op(mock_exclusive_lock);
798 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
799 m_dst_snap_ids[1], OBJECT_EXISTS, 0);
800
801 request->send();
802 ASSERT_EQ(0, ctx.wait());
803 ASSERT_EQ(0, compare_objects());
804 }
805
806 TEST_F(TestMockDeepCopyObjectCopyRequest, Remove) {
807 // scribble some data
808 interval_set<uint64_t> one;
809 scribble(m_src_image_ctx, 10, 102400, &one);
810 ASSERT_EQ(0, create_snap("one"));
811 ASSERT_EQ(0, create_snap("two"));
812
813 // remove the object
814 uint64_t object_size = 1 << m_src_image_ctx->order;
815 ASSERT_LE(0, m_src_image_ctx->io_work_queue->discard(
816 0, object_size, m_src_image_ctx->discard_granularity_bytes));
817 ASSERT_EQ(0, create_snap("copy"));
818 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
819 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
820
821 librbd::MockExclusiveLock mock_exclusive_lock;
822 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
823
824 librbd::MockObjectMap mock_object_map;
825 mock_dst_image_ctx.object_map = &mock_object_map;
826
827 expect_test_features(mock_dst_image_ctx);
828
829 C_SaferCond ctx;
830 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
831 mock_dst_image_ctx, &ctx);
832
833 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
834 request->get_src_io_ctx()));
835 librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
836 request->get_dst_io_ctx()));
837
838 InSequence seq;
839 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
840 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[1]);
841 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
842 expect_start_op(mock_exclusive_lock);
843 expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
844 expect_start_op(mock_exclusive_lock);
845 expect_remove(mock_dst_io_ctx, 0);
846 expect_start_op(mock_exclusive_lock);
847 uint8_t state = OBJECT_EXISTS;
848 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
849 m_dst_snap_ids[0], state, 0);
850 expect_start_op(mock_exclusive_lock);
851 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
852 m_dst_snap_ids[1], is_fast_diff(mock_dst_image_ctx) ?
853 OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
854
855 request->send();
856 ASSERT_EQ(0, ctx.wait());
857 ASSERT_EQ(0, compare_objects());
858 }
859
860 TEST_F(TestMockDeepCopyObjectCopyRequest, ObjectMapUpdateError) {
861 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
862
863 // scribble some data
864 interval_set<uint64_t> one;
865 scribble(m_src_image_ctx, 10, 102400, &one);
866
867 ASSERT_EQ(0, create_snap("copy"));
868 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
869 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
870
871 librbd::MockExclusiveLock mock_exclusive_lock;
872 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
873
874 librbd::MockObjectMap mock_object_map;
875 mock_dst_image_ctx.object_map = &mock_object_map;
876
877 expect_test_features(mock_dst_image_ctx);
878
879 C_SaferCond ctx;
880 MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
881 mock_dst_image_ctx, &ctx);
882
883 librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
884 request->get_src_io_ctx()));
885 librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
886 request->get_dst_io_ctx()));
887
888 InSequence seq;
889 expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
890 expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
891 expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
892 expect_start_op(mock_exclusive_lock);
893 expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
894 expect_start_op(mock_exclusive_lock);
895 expect_update_object_map(mock_dst_image_ctx, mock_object_map,
896 m_dst_snap_ids[0], OBJECT_EXISTS, -EBLACKLISTED);
897
898 request->send();
899 ASSERT_EQ(-EBLACKLISTED, ctx.wait());
900 }
901
902 } // namespace deep_copy
903 } // namespace librbd