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 const SnapMap
&snap_map
,
51 uint64_t object_number
, bool flatten
,
53 ceph_assert(s_instance
!= nullptr);
54 s_instance
->object_number
= object_number
;
55 s_instance
->flatten
= flatten
;
56 s_instance
->on_finish
= on_finish
;
60 uint64_t object_number
;
68 MOCK_METHOD0(send
, void());
71 ObjectCopyRequest
<librbd::MockTestImageCtx
>* ObjectCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
73 } // namespace deep_copy
78 struct ObjectRequest
<librbd::MockTestImageCtx
> {
79 static void add_write_hint(librbd::MockTestImageCtx
&,
80 librados::ObjectWriteOperation
*) {
85 struct AbstractObjectWriteRequest
<librbd::MockTestImageCtx
> {
87 void handle_copyup(int r
) {
91 MOCK_CONST_METHOD0(get_pre_write_object_map_state
, uint8_t());
92 MOCK_CONST_METHOD0(is_empty_write_op
, bool());
94 MOCK_METHOD1(add_copyup_ops
, void(librados::ObjectWriteOperation
*));
98 struct ImageRequest
<librbd::MockTestImageCtx
> {
99 static ImageRequest
*s_instance
;
100 static void aio_read(librbd::MockImageCtx
*ictx
, AioCompletion
*c
,
101 Extents
&&image_extents
, ReadResult
&&read_result
,
102 int op_flags
, const ZTracer::Trace
&parent_trace
) {
103 s_instance
->aio_read(c
, image_extents
, &read_result
);
106 MOCK_METHOD3(aio_read
, void(AioCompletion
*, const Extents
&, ReadResult
*));
113 ImageRequest
<librbd::MockTestImageCtx
>* ImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
116 } // namespace librbd
118 static bool operator==(const SnapContext
& rhs
, const SnapContext
& lhs
) {
119 return (rhs
.seq
== lhs
.seq
&& rhs
.snaps
== lhs
.snaps
);
122 #include "librbd/AsyncObjectThrottle.cc"
123 #include "librbd/io/CopyupRequest.cc"
129 using ::testing::InSequence
;
130 using ::testing::Invoke
;
131 using ::testing::Return
;
132 using ::testing::StrEq
;
133 using ::testing::WithArg
;
134 using ::testing::WithArgs
;
135 using ::testing::WithoutArgs
;
137 struct TestMockIoCopyupRequest
: public TestMockFixture
{
138 typedef CopyupRequest
<librbd::MockTestImageCtx
> MockCopyupRequest
;
139 typedef ImageRequest
<librbd::MockTestImageCtx
> MockImageRequest
;
140 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
141 typedef AbstractObjectWriteRequest
<librbd::MockTestImageCtx
> MockAbstractObjectWriteRequest
;
142 typedef deep_copy::ObjectCopyRequest
<librbd::MockTestImageCtx
> MockObjectCopyRequest
;
144 void SetUp() override
{
145 TestMockFixture::SetUp();
146 if (!is_feature_enabled(RBD_FEATURE_LAYERING
)) {
150 m_parent_image_name
= m_image_name
;
151 m_image_name
= get_temp_image_name();
155 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_parent_image_name
.c_str(),
157 ASSERT_EQ(0, image
.snap_create("one"));
158 ASSERT_EQ(0, image
.snap_protect("one"));
161 ASSERT_EQ(0, image
.features(&features
));
165 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_parent_image_name
.c_str(), "one", m_ioctx
,
166 m_image_name
.c_str(), features
, &order
));
169 void expect_get_parent_overlap(MockTestImageCtx
& mock_image_ctx
,
170 librados::snap_t snap_id
, uint64_t overlap
,
172 if (mock_image_ctx
.object_map
!= nullptr) {
173 EXPECT_CALL(mock_image_ctx
, get_parent_overlap(snap_id
, _
))
174 .WillOnce(WithArg
<1>(Invoke([overlap
, r
](uint64_t *o
) {
181 void expect_prune_parent_extents(MockTestImageCtx
& mock_image_ctx
,
182 uint64_t overlap
, uint64_t object_overlap
) {
183 if (mock_image_ctx
.object_map
!= nullptr) {
184 EXPECT_CALL(mock_image_ctx
, prune_parent_extents(_
, overlap
))
185 .WillOnce(WithoutArgs(Invoke([object_overlap
]() {
186 return object_overlap
;
191 void expect_read_parent(MockTestImageCtx
& mock_image_ctx
,
192 MockImageRequest
& mock_image_request
,
193 const Extents
& image_extents
,
194 const std::string
& data
, int r
) {
195 EXPECT_CALL(mock_image_request
, aio_read(_
, image_extents
, _
))
196 .WillOnce(WithArgs
<0, 2>(Invoke(
197 [&mock_image_ctx
, image_extents
, data
, r
](
198 AioCompletion
* aio_comp
, ReadResult
* read_result
) {
199 aio_comp
->read_result
= std::move(*read_result
);
200 aio_comp
->set_request_count(1);
201 auto ctx
= new ReadResult::C_ImageReadRequest(aio_comp
,
203 ctx
->bl
.append(data
);
204 mock_image_ctx
.image_ctx
->op_work_queue
->queue(ctx
, r
);
208 void expect_copyup(MockTestImageCtx
& mock_image_ctx
, uint64_t snap_id
,
209 const std::string
& oid
, const std::string
& data
, int r
) {
214 if (snap_id
== CEPH_NOSNAP
) {
215 snapc
= mock_image_ctx
.snapc
;
218 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
219 exec(oid
, _
, StrEq("rbd"), StrEq("copyup"),
220 ContentsEqual(in_bl
), _
, snapc
))
221 .WillOnce(Return(r
));
224 void expect_write(MockTestImageCtx
& mock_image_ctx
, uint64_t snap_id
,
225 const std::string
& oid
, int r
) {
227 if (snap_id
== CEPH_NOSNAP
) {
228 snapc
= mock_image_ctx
.snapc
;
231 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
232 write(oid
, _
, 0, 0, snapc
))
233 .WillOnce(Return(r
));
236 void expect_test_features(MockTestImageCtx
& mock_image_ctx
) {
237 EXPECT_CALL(mock_image_ctx
, test_features(_
, _
))
238 .WillRepeatedly(WithArg
<0>(Invoke([&mock_image_ctx
](uint64_t features
) {
239 return (mock_image_ctx
.features
& features
) != 0;
243 void expect_is_lock_owner(MockTestImageCtx
& mock_image_ctx
) {
244 if (mock_image_ctx
.exclusive_lock
!= nullptr) {
245 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
,
246 is_lock_owner()).WillRepeatedly(Return(true));
250 void expect_is_empty_write_op(MockAbstractObjectWriteRequest
& mock_write_request
,
252 EXPECT_CALL(mock_write_request
, is_empty_write_op())
253 .WillOnce(Return(is_empty
));
256 void expect_add_copyup_ops(MockAbstractObjectWriteRequest
& mock_write_request
) {
257 EXPECT_CALL(mock_write_request
, add_copyup_ops(_
))
258 .WillOnce(Invoke([](librados::ObjectWriteOperation
* op
) {
259 op
->write(0, bufferlist
{});
263 void expect_get_pre_write_object_map_state(MockTestImageCtx
& mock_image_ctx
,
264 MockAbstractObjectWriteRequest
& mock_write_request
,
266 if (mock_image_ctx
.object_map
!= nullptr) {
267 EXPECT_CALL(mock_write_request
, get_pre_write_object_map_state())
268 .WillOnce(Return(state
));
272 void expect_object_map_at(MockTestImageCtx
& mock_image_ctx
,
273 uint64_t object_no
, uint8_t state
) {
274 if (mock_image_ctx
.object_map
!= nullptr) {
275 EXPECT_CALL(*mock_image_ctx
.object_map
, at(object_no
))
276 .WillOnce(Return(state
));
280 void expect_object_map_update(MockTestImageCtx
& mock_image_ctx
,
281 uint64_t snap_id
, uint64_t object_no
,
282 uint8_t state
, bool updated
, int ret_val
) {
283 if (mock_image_ctx
.object_map
!= nullptr) {
284 if (!mock_image_ctx
.image_ctx
->test_features(RBD_FEATURE_FAST_DIFF
) &&
285 state
== OBJECT_EXISTS_CLEAN
) {
286 state
= OBJECT_EXISTS
;
289 EXPECT_CALL(*mock_image_ctx
.object_map
,
290 aio_update(snap_id
, object_no
, object_no
+ 1, state
,
291 boost::optional
<uint8_t>(), _
,
292 (snap_id
!= CEPH_NOSNAP
), _
))
293 .WillOnce(WithArg
<7>(Invoke([&mock_image_ctx
, updated
, ret_val
](Context
*ctx
) {
295 mock_image_ctx
.op_work_queue
->queue(ctx
, ret_val
);
302 void expect_object_copy(MockTestImageCtx
& mock_image_ctx
,
303 MockObjectCopyRequest
& mock_object_copy_request
,
304 bool flatten
, int r
) {
305 EXPECT_CALL(mock_object_copy_request
, send())
307 [&mock_image_ctx
, &mock_object_copy_request
, flatten
, r
]() {
308 ASSERT_EQ(flatten
, mock_object_copy_request
.flatten
);
309 mock_image_ctx
.op_work_queue
->queue(
310 mock_object_copy_request
.on_finish
, r
);
314 void flush_async_operations(librbd::ImageCtx
* ictx
) {
315 ictx
->io_work_queue
->flush();
318 std::string m_parent_image_name
;
321 TEST_F(TestMockIoCopyupRequest
, Standard
) {
322 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
324 librbd::ImageCtx
*ictx
;
325 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
327 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
328 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
330 MockExclusiveLock mock_exclusive_lock
;
331 MockJournal mock_journal
;
332 MockObjectMap mock_object_map
;
333 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
336 expect_op_work_queue(mock_image_ctx
);
337 expect_is_lock_owner(mock_image_ctx
);
341 MockImageRequest mock_image_request
;
342 std::string
data(4096, '1');
343 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
346 MockAbstractObjectWriteRequest mock_write_request
;
347 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
349 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
350 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
353 expect_add_copyup_ops(mock_write_request
);
354 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", data
, 0);
355 expect_write(mock_image_ctx
, CEPH_NOSNAP
, "oid", 0);
357 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
359 mock_image_ctx
.copyup_list
[0] = req
;
360 req
->append_request(&mock_write_request
);
363 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
366 TEST_F(TestMockIoCopyupRequest
, StandardWithSnaps
) {
367 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
369 librbd::ImageCtx
*ictx
;
370 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
371 ictx
->snap_lock
.get_write();
372 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
373 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
375 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
376 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
378 ictx
->snapc
= {2, {2, 1}};
379 ictx
->snap_lock
.put_write();
381 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
382 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
384 MockExclusiveLock mock_exclusive_lock
;
385 MockJournal mock_journal
;
386 MockObjectMap mock_object_map
;
387 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
390 expect_test_features(mock_image_ctx
);
391 expect_op_work_queue(mock_image_ctx
);
392 expect_is_lock_owner(mock_image_ctx
);
396 MockImageRequest mock_image_request
;
397 std::string
data(4096, '1');
398 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
401 MockAbstractObjectWriteRequest mock_write_request
;
402 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
404 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
405 expect_object_map_update(mock_image_ctx
, 1, 0, OBJECT_EXISTS
, true, 0);
406 expect_object_map_update(mock_image_ctx
, 2, 0, OBJECT_EXISTS_CLEAN
, true, 0);
407 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
410 expect_add_copyup_ops(mock_write_request
);
411 expect_copyup(mock_image_ctx
, 0, "oid", data
, 0);
412 expect_write(mock_image_ctx
, CEPH_NOSNAP
, "oid", 0);
414 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
416 mock_image_ctx
.copyup_list
[0] = req
;
417 req
->append_request(&mock_write_request
);
420 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
423 TEST_F(TestMockIoCopyupRequest
, CopyOnRead
) {
424 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
426 librbd::ImageCtx
*ictx
;
427 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
429 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
430 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
432 MockExclusiveLock mock_exclusive_lock
;
433 MockJournal mock_journal
;
434 MockObjectMap mock_object_map
;
435 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
438 expect_op_work_queue(mock_image_ctx
);
439 expect_is_lock_owner(mock_image_ctx
);
443 MockImageRequest mock_image_request
;
444 std::string
data(4096, '1');
445 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
448 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
449 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
452 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", data
, 0);
454 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
456 mock_image_ctx
.copyup_list
[0] = req
;
458 flush_async_operations(ictx
);
461 TEST_F(TestMockIoCopyupRequest
, CopyOnReadWithSnaps
) {
462 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
464 librbd::ImageCtx
*ictx
;
465 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
466 ictx
->snap_lock
.get_write();
467 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
468 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
470 ictx
->snapc
= {1, {1}};
471 ictx
->snap_lock
.put_write();
473 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
474 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
476 MockExclusiveLock mock_exclusive_lock
;
477 MockJournal mock_journal
;
478 MockObjectMap mock_object_map
;
479 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
482 expect_test_features(mock_image_ctx
);
483 expect_op_work_queue(mock_image_ctx
);
484 expect_is_lock_owner(mock_image_ctx
);
488 MockImageRequest mock_image_request
;
489 std::string
data(4096, '1');
490 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
493 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
494 expect_object_map_update(mock_image_ctx
, 1, 0, OBJECT_EXISTS
, true, 0);
495 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS_CLEAN
,
498 expect_copyup(mock_image_ctx
, 0, "oid", data
, 0);
500 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
502 mock_image_ctx
.copyup_list
[0] = req
;
504 flush_async_operations(ictx
);
507 TEST_F(TestMockIoCopyupRequest
, DeepCopy
) {
508 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
510 librbd::ImageCtx
*ictx
;
511 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
513 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
514 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
516 MockExclusiveLock mock_exclusive_lock
;
517 MockJournal mock_journal
;
518 MockObjectMap mock_object_map
;
519 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
522 expect_op_work_queue(mock_image_ctx
);
523 expect_is_lock_owner(mock_image_ctx
);
527 MockAbstractObjectWriteRequest mock_write_request
;
528 MockObjectCopyRequest mock_object_copy_request
;
529 mock_image_ctx
.migration_info
= {1, "", "", "image id", {}, ictx
->size
, true};
530 expect_is_empty_write_op(mock_write_request
, false);
531 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
533 expect_is_empty_write_op(mock_write_request
, false);
534 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
536 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
537 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
540 expect_add_copyup_ops(mock_write_request
);
541 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", "", 0);
542 expect_write(mock_image_ctx
, CEPH_NOSNAP
, "oid", 0);
544 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
546 mock_image_ctx
.copyup_list
[0] = req
;
547 req
->append_request(&mock_write_request
);
550 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
553 TEST_F(TestMockIoCopyupRequest
, DeepCopyOnRead
) {
554 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
556 librbd::ImageCtx
*ictx
;
557 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
559 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
560 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
562 MockExclusiveLock mock_exclusive_lock
;
563 MockJournal mock_journal
;
564 MockObjectMap mock_object_map
;
565 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
568 expect_op_work_queue(mock_image_ctx
);
569 expect_is_lock_owner(mock_image_ctx
);
573 MockObjectCopyRequest mock_object_copy_request
;
574 mock_image_ctx
.migration_info
= {1, "", "", "image id", {}, ictx
->size
,
576 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
578 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
579 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
582 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", "", 0);
584 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
586 mock_image_ctx
.copyup_list
[0] = req
;
588 flush_async_operations(ictx
);
591 TEST_F(TestMockIoCopyupRequest
, DeepCopyWithPostSnaps
) {
592 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
594 librbd::ImageCtx
*ictx
;
595 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
596 ictx
->snap_lock
.get_write();
597 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx
->size
,
598 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
600 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
601 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
603 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
604 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
606 ictx
->snapc
= {3, {3, 2, 1}};
607 ictx
->snap_lock
.put_write();
609 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
610 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
612 MockExclusiveLock mock_exclusive_lock
;
613 MockJournal mock_journal
;
614 MockObjectMap mock_object_map
;
615 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
618 expect_test_features(mock_image_ctx
);
619 expect_op_work_queue(mock_image_ctx
);
620 expect_is_lock_owner(mock_image_ctx
);
624 MockAbstractObjectWriteRequest mock_write_request
;
625 MockObjectCopyRequest mock_object_copy_request
;
626 mock_image_ctx
.migration_info
= {1, "", "", "image id",
627 {{CEPH_NOSNAP
, {2, 1}}},
629 expect_is_empty_write_op(mock_write_request
, false);
630 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
632 expect_is_empty_write_op(mock_write_request
, false);
633 expect_get_parent_overlap(mock_image_ctx
, 1, 0, 0);
634 expect_get_parent_overlap(mock_image_ctx
, 2, 1, 0);
635 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
636 expect_get_parent_overlap(mock_image_ctx
, 3, 1, 0);
637 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
638 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
640 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
641 expect_object_map_update(mock_image_ctx
, 2, 0, OBJECT_EXISTS
, true, 0);
642 expect_object_map_update(mock_image_ctx
, 3, 0, OBJECT_EXISTS_CLEAN
, true, 0);
643 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
646 expect_add_copyup_ops(mock_write_request
);
647 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", "", 0);
648 expect_write(mock_image_ctx
, CEPH_NOSNAP
, "oid", 0);
650 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
652 mock_image_ctx
.copyup_list
[0] = req
;
653 req
->append_request(&mock_write_request
);
656 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
659 TEST_F(TestMockIoCopyupRequest
, DeepCopyWithPreAndPostSnaps
) {
660 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
662 librbd::ImageCtx
*ictx
;
663 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
664 ictx
->snap_lock
.get_write();
665 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "4", 4, ictx
->size
,
666 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
668 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx
->size
,
669 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
671 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
672 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
674 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
675 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
677 ictx
->snapc
= {4, {4, 3, 2, 1}};
678 ictx
->snap_lock
.put_write();
680 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
681 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
683 MockExclusiveLock mock_exclusive_lock
;
684 MockJournal mock_journal
;
685 MockObjectMap mock_object_map
;
686 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
689 expect_test_features(mock_image_ctx
);
690 expect_op_work_queue(mock_image_ctx
);
691 expect_is_lock_owner(mock_image_ctx
);
695 MockAbstractObjectWriteRequest mock_write_request
;
696 MockObjectCopyRequest mock_object_copy_request
;
697 mock_image_ctx
.migration_info
= {1, "", "", "image id",
698 {{CEPH_NOSNAP
, {2, 1}}, {10, {1}}},
700 expect_is_empty_write_op(mock_write_request
, false);
701 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
703 expect_is_empty_write_op(mock_write_request
, false);
704 expect_get_parent_overlap(mock_image_ctx
, 2, 0, 0);
705 expect_get_parent_overlap(mock_image_ctx
, 3, 1, 0);
706 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
707 expect_get_parent_overlap(mock_image_ctx
, 4, 1, 0);
708 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
709 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
711 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
712 expect_object_map_update(mock_image_ctx
, 3, 0, OBJECT_EXISTS_CLEAN
, true, 0);
713 expect_object_map_update(mock_image_ctx
, 4, 0, OBJECT_EXISTS_CLEAN
, true, 0);
714 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
717 expect_add_copyup_ops(mock_write_request
);
718 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", "", 0);
719 expect_write(mock_image_ctx
, CEPH_NOSNAP
, "oid", 0);
721 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
723 mock_image_ctx
.copyup_list
[0] = req
;
724 req
->append_request(&mock_write_request
);
727 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
730 TEST_F(TestMockIoCopyupRequest
, ZeroedCopyup
) {
731 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
733 librbd::ImageCtx
*ictx
;
734 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
736 MockTestImageCtx
mock_image_ctx(*ictx
);
738 MockExclusiveLock mock_exclusive_lock
;
739 MockJournal mock_journal
;
740 MockObjectMap mock_object_map
;
741 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
744 expect_op_work_queue(mock_image_ctx
);
745 expect_is_lock_owner(mock_image_ctx
);
749 MockAbstractObjectWriteRequest mock_write_request
;
750 expect_is_empty_write_op(mock_write_request
, false);
751 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
753 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
754 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
757 expect_add_copyup_ops(mock_write_request
);
758 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", "", 0);
759 expect_write(mock_image_ctx
, CEPH_NOSNAP
, "oid", 0);
761 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
763 mock_image_ctx
.copyup_list
[0] = req
;
764 req
->append_request(&mock_write_request
);
767 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
770 TEST_F(TestMockIoCopyupRequest
, ZeroedCopyOnRead
) {
771 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
773 librbd::ImageCtx
*ictx
;
774 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
776 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
777 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
779 MockExclusiveLock mock_exclusive_lock
;
780 MockJournal mock_journal
;
781 MockObjectMap mock_object_map
;
782 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
785 expect_op_work_queue(mock_image_ctx
);
786 expect_is_lock_owner(mock_image_ctx
);
790 MockImageRequest mock_image_request
;
791 std::string
data(4096, '\0');
792 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
795 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
796 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
799 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", "", 0);
801 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
803 mock_image_ctx
.copyup_list
[0] = req
;
805 flush_async_operations(ictx
);
808 TEST_F(TestMockIoCopyupRequest
, NoOpCopyup
) {
809 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
811 librbd::ImageCtx
*ictx
;
812 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
814 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
815 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
817 MockExclusiveLock mock_exclusive_lock
;
818 MockJournal mock_journal
;
819 MockObjectMap mock_object_map
;
820 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
823 expect_op_work_queue(mock_image_ctx
);
824 expect_is_lock_owner(mock_image_ctx
);
828 MockImageRequest mock_image_request
;
829 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
832 MockAbstractObjectWriteRequest mock_write_request
;
833 expect_is_empty_write_op(mock_write_request
, true);
835 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
837 mock_image_ctx
.copyup_list
[0] = req
;
838 req
->append_request(&mock_write_request
);
841 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
844 TEST_F(TestMockIoCopyupRequest
, RestartWrite
) {
845 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
847 librbd::ImageCtx
*ictx
;
848 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
850 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
851 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
853 MockExclusiveLock mock_exclusive_lock
;
854 MockJournal mock_journal
;
855 MockObjectMap mock_object_map
;
856 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
859 expect_op_work_queue(mock_image_ctx
);
860 expect_is_lock_owner(mock_image_ctx
);
864 MockImageRequest mock_image_request
;
865 std::string
data(4096, '1');
866 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
869 MockAbstractObjectWriteRequest mock_write_request1
;
870 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request1
,
872 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
873 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
876 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
878 expect_add_copyup_ops(mock_write_request1
);
879 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, "oid", data
, 0);
881 MockAbstractObjectWriteRequest mock_write_request2
;
882 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
883 write("oid", _
, 0, 0, _
))
884 .WillOnce(WithoutArgs(Invoke([req
, &mock_write_request2
]() {
885 req
->append_request(&mock_write_request2
);
889 mock_image_ctx
.copyup_list
[0] = req
;
890 req
->append_request(&mock_write_request1
);
893 ASSERT_EQ(0, mock_write_request1
.ctx
.wait());
894 ASSERT_EQ(-ERESTART
, mock_write_request2
.ctx
.wait());
897 TEST_F(TestMockIoCopyupRequest
, ReadFromParentError
) {
898 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
900 librbd::ImageCtx
*ictx
;
901 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
903 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
904 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
906 MockExclusiveLock mock_exclusive_lock
;
907 MockJournal mock_journal
;
908 MockObjectMap mock_object_map
;
909 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
912 expect_op_work_queue(mock_image_ctx
);
913 expect_is_lock_owner(mock_image_ctx
);
917 MockImageRequest mock_image_request
;
918 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
921 MockAbstractObjectWriteRequest mock_write_request
;
922 expect_is_empty_write_op(mock_write_request
, false);
924 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
926 mock_image_ctx
.copyup_list
[0] = req
;
927 req
->append_request(&mock_write_request
);
930 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
933 TEST_F(TestMockIoCopyupRequest
, DeepCopyError
) {
934 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
936 librbd::ImageCtx
*ictx
;
937 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
939 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
940 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
942 MockExclusiveLock mock_exclusive_lock
;
943 MockJournal mock_journal
;
944 MockObjectMap mock_object_map
;
945 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
948 expect_op_work_queue(mock_image_ctx
);
949 expect_is_lock_owner(mock_image_ctx
);
953 MockAbstractObjectWriteRequest mock_write_request
;
954 MockObjectCopyRequest mock_object_copy_request
;
955 mock_image_ctx
.migration_info
= {1, "", "", "image id", {}, ictx
->size
, true};
956 expect_is_empty_write_op(mock_write_request
, false);
957 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, -EPERM
);
959 expect_is_empty_write_op(mock_write_request
, false);
961 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
963 mock_image_ctx
.copyup_list
[0] = req
;
964 req
->append_request(&mock_write_request
);
967 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
970 TEST_F(TestMockIoCopyupRequest
, UpdateObjectMapError
) {
971 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_OBJECT_MAP
);
973 librbd::ImageCtx
*ictx
;
974 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
976 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
977 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
979 MockExclusiveLock mock_exclusive_lock
;
980 MockJournal mock_journal
;
981 MockObjectMap mock_object_map
;
982 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
985 expect_op_work_queue(mock_image_ctx
);
986 expect_is_lock_owner(mock_image_ctx
);
990 MockImageRequest mock_image_request
;
991 std::string
data(4096, '1');
992 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
995 MockAbstractObjectWriteRequest mock_write_request
;
996 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
998 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
999 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
1002 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
1004 mock_image_ctx
.copyup_list
[0] = req
;
1005 req
->append_request(&mock_write_request
);
1008 ASSERT_EQ(-EINVAL
, mock_write_request
.ctx
.wait());
1011 TEST_F(TestMockIoCopyupRequest
, CopyupError
) {
1012 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1014 librbd::ImageCtx
*ictx
;
1015 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1016 ictx
->snap_lock
.get_write();
1017 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
1018 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
1020 ictx
->snapc
= {1, {1}};
1021 ictx
->snap_lock
.put_write();
1023 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1024 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1026 MockExclusiveLock mock_exclusive_lock
;
1027 MockJournal mock_journal
;
1028 MockObjectMap mock_object_map
;
1029 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1032 expect_test_features(mock_image_ctx
);
1033 expect_op_work_queue(mock_image_ctx
);
1034 expect_is_lock_owner(mock_image_ctx
);
1038 MockImageRequest mock_image_request
;
1039 std::string
data(4096, '1');
1040 expect_read_parent(mock_parent_image_ctx
, mock_image_request
, {{0, 4096}},
1043 MockAbstractObjectWriteRequest mock_write_request
;
1044 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
1046 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
1047 expect_object_map_update(mock_image_ctx
, 1, 0, OBJECT_EXISTS
, true, 0);
1048 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
1051 expect_add_copyup_ops(mock_write_request
);
1052 expect_copyup(mock_image_ctx
, 0, "oid", data
, -EPERM
);
1053 expect_write(mock_image_ctx
, CEPH_NOSNAP
, "oid", 0);
1055 auto req
= new MockCopyupRequest(&mock_image_ctx
, "oid", 0,
1057 mock_image_ctx
.copyup_list
[0] = req
;
1058 req
->append_request(&mock_write_request
);
1061 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
1062 flush_async_operations(ictx
);
1066 } // namespace librbd