1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
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
;
30 std::map
<uint64_t, librbd::io::CopyupRequest
<librbd::MockTestImageCtx
>*> copyup_list
;
33 } // anonymous namespace
37 inline ImageCtx
*get_image_ctx(MockImageCtx
*image_ctx
) {
38 return image_ctx
->image_ctx
;
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
;
62 uint64_t object_number
;
70 MOCK_METHOD0(send
, void());
73 ObjectCopyRequest
<librbd::MockTestImageCtx
>* ObjectCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
75 } // namespace deep_copy
80 struct ObjectRequest
<librbd::MockTestImageCtx
> {
81 static void add_write_hint(librbd::MockTestImageCtx
&,
82 librados::ObjectWriteOperation
*) {
87 struct AbstractObjectWriteRequest
<librbd::MockTestImageCtx
> {
89 void handle_copyup(int r
) {
93 MOCK_CONST_METHOD0(get_pre_write_object_map_state
, uint8_t());
94 MOCK_CONST_METHOD0(is_empty_write_op
, bool());
96 MOCK_METHOD1(add_copyup_ops
, void(librados::ObjectWriteOperation
*));
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
);
108 MOCK_METHOD3(aio_read
, void(AioCompletion
*, const Extents
&, ReadResult
*));
115 ImageRequest
<librbd::MockTestImageCtx
>* ImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
118 } // namespace librbd
120 static bool operator==(const SnapContext
& rhs
, const SnapContext
& lhs
) {
121 return (rhs
.seq
== lhs
.seq
&& rhs
.snaps
== lhs
.snaps
);
124 #include "librbd/AsyncObjectThrottle.cc"
125 #include "librbd/io/CopyupRequest.cc"
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
;
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
;
146 void SetUp() override
{
147 TestMockFixture::SetUp();
148 if (!is_feature_enabled(RBD_FEATURE_LAYERING
)) {
152 m_parent_image_name
= m_image_name
;
153 m_image_name
= get_temp_image_name();
157 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_parent_image_name
.c_str(),
159 ASSERT_EQ(0, image
.snap_create("one"));
160 ASSERT_EQ(0, image
.snap_protect("one"));
163 ASSERT_EQ(0, image
.features(&features
));
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
));
171 void expect_get_parent_overlap(MockTestImageCtx
& mock_image_ctx
,
172 librados::snap_t snap_id
, uint64_t overlap
,
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
) {
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
;
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
,
205 ctx
->bl
.append(data
);
206 mock_image_ctx
.image_ctx
->op_work_queue
->queue(ctx
, r
);
210 void expect_copyup(MockTestImageCtx
& mock_image_ctx
, uint64_t snap_id
,
211 const std::string
& oid
, const std::string
& data
, int r
) {
216 if (snap_id
== CEPH_NOSNAP
) {
217 snapc
= mock_image_ctx
.snapc
;
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
));
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
) {
231 data_bl
.append(data
);
234 encode(extent_map
, in_bl
);
235 encode(data_bl
, in_bl
);
238 if (snap_id
== CEPH_NOSNAP
) {
239 snapc
= mock_image_ctx
.snapc
;
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
));
248 void expect_write(MockTestImageCtx
& mock_image_ctx
, uint64_t snap_id
,
249 const std::string
& oid
, int r
) {
251 if (snap_id
== CEPH_NOSNAP
) {
252 snapc
= mock_image_ctx
.snapc
;
255 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
256 write(oid
, _
, 0, 0, snapc
))
257 .WillOnce(Return(r
));
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;
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));
274 void expect_is_empty_write_op(MockAbstractObjectWriteRequest
& mock_write_request
,
276 EXPECT_CALL(mock_write_request
, is_empty_write_op())
277 .WillOnce(Return(is_empty
));
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
{});
287 void expect_get_pre_write_object_map_state(MockTestImageCtx
& mock_image_ctx
,
288 MockAbstractObjectWriteRequest
& mock_write_request
,
290 if (mock_image_ctx
.object_map
!= nullptr) {
291 EXPECT_CALL(mock_write_request
, get_pre_write_object_map_state())
292 .WillOnce(Return(state
));
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
));
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
;
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
) {
319 mock_image_ctx
.op_work_queue
->queue(ctx
, ret_val
);
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())
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
);
338 void flush_async_operations(librbd::ImageCtx
* ictx
) {
339 ictx
->io_work_queue
->flush();
342 std::string m_parent_image_name
;
345 TEST_F(TestMockIoCopyupRequest
, Standard
) {
346 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
348 librbd::ImageCtx
*ictx
;
349 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
351 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
352 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
360 expect_op_work_queue(mock_image_ctx
);
361 expect_is_lock_owner(mock_image_ctx
);
365 MockImageRequest mock_image_request
;
366 std::string
data(4096, '1');
367 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
370 MockAbstractObjectWriteRequest mock_write_request
;
371 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
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,
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);
382 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
384 mock_image_ctx
.copyup_list
[0] = req
;
385 req
->append_request(&mock_write_request
);
388 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
391 TEST_F(TestMockIoCopyupRequest
, StandardWithSnaps
) {
392 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
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
,
400 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
401 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
403 ictx
->snapc
= {2, {2, 1}};
404 ictx
->image_lock
.unlock();
406 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
407 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
415 expect_test_features(mock_image_ctx
);
416 expect_op_work_queue(mock_image_ctx
);
417 expect_is_lock_owner(mock_image_ctx
);
421 MockImageRequest mock_image_request
;
422 std::string
data(4096, '1');
423 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
426 MockAbstractObjectWriteRequest mock_write_request
;
427 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
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,
435 expect_add_copyup_ops(mock_write_request
);
436 expect_sparse_copyup(mock_image_ctx
, 0, ictx
->get_object_name(0), {{0, 4096}},
438 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
440 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
442 mock_image_ctx
.copyup_list
[0] = req
;
443 req
->append_request(&mock_write_request
);
446 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
449 TEST_F(TestMockIoCopyupRequest
, CopyOnRead
) {
450 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
452 librbd::ImageCtx
*ictx
;
453 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
455 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
456 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
464 expect_op_work_queue(mock_image_ctx
);
465 expect_is_lock_owner(mock_image_ctx
);
469 MockImageRequest mock_image_request
;
470 std::string
data(4096, '1');
471 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
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,
478 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
479 {{0, 4096}}, data
, 0);
481 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
483 mock_image_ctx
.copyup_list
[0] = req
;
485 flush_async_operations(ictx
);
488 TEST_F(TestMockIoCopyupRequest
, CopyOnReadWithSnaps
) {
489 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
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
,
497 ictx
->snapc
= {1, {1}};
498 ictx
->image_lock
.unlock();
500 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
501 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
509 expect_test_features(mock_image_ctx
);
510 expect_op_work_queue(mock_image_ctx
);
511 expect_is_lock_owner(mock_image_ctx
);
515 MockImageRequest mock_image_request
;
516 std::string
data(4096, '1');
517 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
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
,
525 expect_sparse_copyup(mock_image_ctx
, 0, ictx
->get_object_name(0), {{0, 4096}},
528 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
530 mock_image_ctx
.copyup_list
[0] = req
;
532 flush_async_operations(ictx
);
535 TEST_F(TestMockIoCopyupRequest
, DeepCopy
) {
536 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
538 librbd::ImageCtx
*ictx
;
539 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
541 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
542 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
550 expect_op_work_queue(mock_image_ctx
);
551 expect_is_lock_owner(mock_image_ctx
);
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);
561 expect_is_empty_write_op(mock_write_request
, false);
562 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
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,
568 expect_add_copyup_ops(mock_write_request
);
569 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
571 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
573 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
575 mock_image_ctx
.copyup_list
[0] = req
;
576 req
->append_request(&mock_write_request
);
579 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
582 TEST_F(TestMockIoCopyupRequest
, DeepCopyOnRead
) {
583 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
585 librbd::ImageCtx
*ictx
;
586 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
588 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
589 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
597 expect_op_work_queue(mock_image_ctx
);
598 expect_is_lock_owner(mock_image_ctx
);
602 MockObjectCopyRequest mock_object_copy_request
;
603 mock_image_ctx
.migration_info
= {1, "", "", "image id", {}, ictx
->size
,
605 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
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,
611 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
614 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
616 mock_image_ctx
.copyup_list
[0] = req
;
618 flush_async_operations(ictx
);
621 TEST_F(TestMockIoCopyupRequest
, DeepCopyWithPostSnaps
) {
622 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
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
,
630 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
631 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
633 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
634 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
636 ictx
->snapc
= {3, {3, 2, 1}};
637 ictx
->image_lock
.unlock();
639 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
640 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
648 expect_test_features(mock_image_ctx
);
649 expect_op_work_queue(mock_image_ctx
);
650 expect_is_lock_owner(mock_image_ctx
);
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}}},
659 expect_is_empty_write_op(mock_write_request
, false);
660 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
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
,
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,
676 expect_add_copyup_ops(mock_write_request
);
677 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
679 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
681 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
683 mock_image_ctx
.copyup_list
[0] = req
;
684 req
->append_request(&mock_write_request
);
687 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
690 TEST_F(TestMockIoCopyupRequest
, DeepCopyWithPreAndPostSnaps
) {
691 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
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
,
699 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx
->size
,
700 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
702 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
703 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
705 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
706 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
708 ictx
->snapc
= {4, {4, 3, 2, 1}};
709 ictx
->image_lock
.unlock();
711 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
712 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
720 expect_test_features(mock_image_ctx
);
721 expect_op_work_queue(mock_image_ctx
);
722 expect_is_lock_owner(mock_image_ctx
);
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}}},
731 expect_is_empty_write_op(mock_write_request
, false);
732 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
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
,
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,
748 expect_add_copyup_ops(mock_write_request
);
749 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
751 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
753 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
755 mock_image_ctx
.copyup_list
[0] = req
;
756 req
->append_request(&mock_write_request
);
759 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
762 TEST_F(TestMockIoCopyupRequest
, ZeroedCopyup
) {
763 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
765 librbd::ImageCtx
*ictx
;
766 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
768 MockTestImageCtx
mock_image_ctx(*ictx
);
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
,
776 expect_op_work_queue(mock_image_ctx
);
777 expect_is_lock_owner(mock_image_ctx
);
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
,
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,
789 expect_add_copyup_ops(mock_write_request
);
790 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
792 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
794 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
796 mock_image_ctx
.copyup_list
[0] = req
;
797 req
->append_request(&mock_write_request
);
800 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
803 TEST_F(TestMockIoCopyupRequest
, ZeroedCopyOnRead
) {
804 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
806 librbd::ImageCtx
*ictx
;
807 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
809 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
810 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
818 expect_op_work_queue(mock_image_ctx
);
819 expect_is_lock_owner(mock_image_ctx
);
823 MockImageRequest mock_image_request
;
824 std::string
data(4096, '\0');
825 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
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,
832 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
835 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
837 mock_image_ctx
.copyup_list
[0] = req
;
839 flush_async_operations(ictx
);
842 TEST_F(TestMockIoCopyupRequest
, NoOpCopyup
) {
843 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
845 librbd::ImageCtx
*ictx
;
846 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
848 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
849 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
857 expect_op_work_queue(mock_image_ctx
);
858 expect_is_lock_owner(mock_image_ctx
);
862 MockImageRequest mock_image_request
;
863 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
866 MockAbstractObjectWriteRequest mock_write_request
;
867 expect_is_empty_write_op(mock_write_request
, true);
869 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
871 mock_image_ctx
.copyup_list
[0] = req
;
872 req
->append_request(&mock_write_request
);
875 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
878 TEST_F(TestMockIoCopyupRequest
, RestartWrite
) {
879 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
881 librbd::ImageCtx
*ictx
;
882 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
884 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
885 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
893 expect_op_work_queue(mock_image_ctx
);
894 expect_is_lock_owner(mock_image_ctx
);
898 MockImageRequest mock_image_request
;
899 std::string
data(4096, '1');
900 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
903 MockAbstractObjectWriteRequest mock_write_request1
;
904 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request1
,
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,
910 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
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);
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
);
924 mock_image_ctx
.copyup_list
[0] = req
;
925 req
->append_request(&mock_write_request1
);
928 ASSERT_EQ(0, mock_write_request1
.ctx
.wait());
929 ASSERT_EQ(-ERESTART
, mock_write_request2
.ctx
.wait());
932 TEST_F(TestMockIoCopyupRequest
, ReadFromParentError
) {
933 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
935 librbd::ImageCtx
*ictx
;
936 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
938 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
939 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
947 expect_op_work_queue(mock_image_ctx
);
948 expect_is_lock_owner(mock_image_ctx
);
952 MockImageRequest mock_image_request
;
953 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
956 MockAbstractObjectWriteRequest mock_write_request
;
957 expect_is_empty_write_op(mock_write_request
, false);
959 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
961 mock_image_ctx
.copyup_list
[0] = req
;
962 req
->append_request(&mock_write_request
);
965 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
968 TEST_F(TestMockIoCopyupRequest
, DeepCopyError
) {
969 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
971 librbd::ImageCtx
*ictx
;
972 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
974 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
975 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
983 expect_op_work_queue(mock_image_ctx
);
984 expect_is_lock_owner(mock_image_ctx
);
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
);
994 expect_is_empty_write_op(mock_write_request
, false);
996 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
998 mock_image_ctx
.copyup_list
[0] = req
;
999 req
->append_request(&mock_write_request
);
1002 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
1005 TEST_F(TestMockIoCopyupRequest
, UpdateObjectMapError
) {
1006 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_OBJECT_MAP
);
1008 librbd::ImageCtx
*ictx
;
1009 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1011 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1012 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
1020 expect_op_work_queue(mock_image_ctx
);
1021 expect_is_lock_owner(mock_image_ctx
);
1025 MockImageRequest mock_image_request
;
1026 std::string
data(4096, '1');
1027 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
1030 MockAbstractObjectWriteRequest mock_write_request
;
1031 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
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,
1037 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
1039 mock_image_ctx
.copyup_list
[0] = req
;
1040 req
->append_request(&mock_write_request
);
1043 ASSERT_EQ(-EINVAL
, mock_write_request
.ctx
.wait());
1046 TEST_F(TestMockIoCopyupRequest
, CopyupError
) {
1047 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
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
,
1055 ictx
->snapc
= {1, {1}};
1056 ictx
->image_lock
.unlock();
1058 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1059 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
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
,
1067 expect_test_features(mock_image_ctx
);
1068 expect_op_work_queue(mock_image_ctx
);
1069 expect_is_lock_owner(mock_image_ctx
);
1073 MockImageRequest mock_image_request
;
1074 std::string
data(4096, '1');
1075 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
1078 MockAbstractObjectWriteRequest mock_write_request
;
1079 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
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,
1086 expect_add_copyup_ops(mock_write_request
);
1087 expect_sparse_copyup(mock_image_ctx
, 0, ictx
->get_object_name(0), {{0, 4096}},
1089 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
1091 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0,
1093 mock_image_ctx
.copyup_list
[0] = req
;
1094 req
->append_request(&mock_write_request
);
1097 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
1098 flush_async_operations(ictx
);
1101 TEST_F(TestMockIoCopyupRequest
, SparseCopyupNotSupported
) {
1102 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1104 librbd::ImageCtx
*ictx
;
1105 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
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;
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
,
1117 expect_op_work_queue(mock_image_ctx
);
1118 expect_is_lock_owner(mock_image_ctx
);
1122 MockImageRequest mock_image_request
;
1123 std::string
data(4096, '1');
1124 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
1127 MockAbstractObjectWriteRequest mock_write_request
;
1128 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
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,
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);
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
);
1143 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
1147 } // namespace librbd