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