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/api/Io.h"
14 #include "librbd/deep_copy/ObjectCopyRequest.h"
15 #include "librbd/io/CopyupRequest.h"
16 #include "librbd/io/ImageDispatchSpec.h"
17 #include "librbd/io/ObjectRequest.h"
18 #include "librbd/io/ReadResult.h"
19 #include "librbd/io/Utils.h"
24 struct MockTestImageCtx
: public MockImageCtx
{
25 MockTestImageCtx(ImageCtx
&image_ctx
,
26 MockTestImageCtx
* mock_parent_image_ctx
= nullptr)
27 : MockImageCtx(image_ctx
) {
28 parent
= mock_parent_image_ctx
;
30 ~MockTestImageCtx() override
{
31 // copyups need to complete prior to attempting to delete this object
35 std::map
<uint64_t, librbd::io::CopyupRequest
<librbd::MockTestImageCtx
>*> copyup_list
;
38 } // anonymous namespace
42 inline ImageCtx
*get_image_ctx(MockImageCtx
*image_ctx
) {
43 return image_ctx
->image_ctx
;
51 struct ObjectCopyRequest
<librbd::MockTestImageCtx
> {
52 static ObjectCopyRequest
* s_instance
;
53 static ObjectCopyRequest
* create(librbd::MockImageCtx
* parent_image_ctx
,
54 librbd::MockTestImageCtx
* image_ctx
,
55 librados::snap_t src_snap_id_start
,
56 librados::snap_t dst_snap_id_start
,
57 const SnapMap
&snap_map
,
58 uint64_t object_number
, uint32_t flags
,
59 Handler
*, Context
*on_finish
) {
60 ceph_assert(s_instance
!= nullptr);
61 s_instance
->object_number
= object_number
;
62 s_instance
->flatten
= (
63 (flags
& deep_copy::OBJECT_COPY_REQUEST_FLAG_FLATTEN
) != 0);
64 s_instance
->on_finish
= on_finish
;
68 uint64_t object_number
;
76 MOCK_METHOD0(send
, void());
79 ObjectCopyRequest
<librbd::MockTestImageCtx
>* ObjectCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
81 } // namespace deep_copy
88 void area_to_object_extents(MockTestImageCtx
* image_ctx
, uint64_t offset
,
89 uint64_t length
, ImageArea area
,
90 uint64_t buffer_offset
,
91 striper::LightweightObjectExtents
* object_extents
) {
92 Striper::file_to_extents(image_ctx
->cct
, &image_ctx
->layout
, offset
, length
,
93 0, buffer_offset
, object_extents
);
97 std::pair
<Extents
, ImageArea
> object_to_area_extents(
98 MockTestImageCtx
* image_ctx
, uint64_t object_no
,
99 const Extents
& object_extents
) {
101 for (auto [off
, len
] : object_extents
) {
102 Striper::extent_to_file(image_ctx
->cct
, &image_ctx
->layout
, object_no
, off
,
105 return {std::move(extents
), ImageArea::DATA
};
111 struct ObjectRequest
<librbd::MockTestImageCtx
> {
112 static void add_write_hint(librbd::MockTestImageCtx
&,
113 neorados::WriteOp
*) {
118 struct AbstractObjectWriteRequest
<librbd::MockTestImageCtx
> {
120 void handle_copyup(int r
) {
124 MOCK_CONST_METHOD0(get_pre_write_object_map_state
, uint8_t());
125 MOCK_CONST_METHOD0(is_empty_write_op
, bool());
127 MOCK_METHOD1(add_copyup_ops
, void(neorados::WriteOp
*));
131 } // namespace librbd
133 static bool operator==(const SnapContext
& rhs
, const SnapContext
& lhs
) {
134 return (rhs
.seq
== lhs
.seq
&& rhs
.snaps
== lhs
.snaps
);
137 #include "librbd/AsyncObjectThrottle.cc"
138 #include "librbd/io/CopyupRequest.cc"
140 MATCHER_P(IsRead
, image_extents
, "") {
141 auto req
= boost::get
<librbd::io::ImageDispatchSpec::Read
>(&arg
->request
);
142 return (req
!= nullptr && image_extents
== arg
->image_extents
);
149 using ::testing::InSequence
;
150 using ::testing::Invoke
;
151 using ::testing::Return
;
152 using ::testing::StrEq
;
153 using ::testing::WithArg
;
154 using ::testing::WithArgs
;
155 using ::testing::WithoutArgs
;
157 struct TestMockIoCopyupRequest
: public TestMockFixture
{
158 typedef CopyupRequest
<librbd::MockTestImageCtx
> MockCopyupRequest
;
159 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
160 typedef AbstractObjectWriteRequest
<librbd::MockTestImageCtx
> MockAbstractObjectWriteRequest
;
161 typedef deep_copy::ObjectCopyRequest
<librbd::MockTestImageCtx
> MockObjectCopyRequest
;
163 void SetUp() override
{
164 TestMockFixture::SetUp();
165 if (!is_feature_enabled(RBD_FEATURE_LAYERING
)) {
169 m_parent_image_name
= m_image_name
;
170 m_image_name
= get_temp_image_name();
174 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_parent_image_name
.c_str(),
176 ASSERT_EQ(0, image
.snap_create("one"));
177 ASSERT_EQ(0, image
.snap_protect("one"));
180 ASSERT_EQ(0, image
.features(&features
));
184 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_parent_image_name
.c_str(), "one", m_ioctx
,
185 m_image_name
.c_str(), features
, &order
));
188 void expect_get_parent_overlap(MockTestImageCtx
& mock_image_ctx
,
189 librados::snap_t snap_id
, uint64_t overlap
,
191 EXPECT_CALL(mock_image_ctx
, get_parent_overlap(snap_id
, _
))
192 .WillOnce(WithArg
<1>(Invoke([overlap
, r
](uint64_t *o
) {
198 void expect_prune_parent_extents(MockTestImageCtx
& mock_image_ctx
,
199 uint64_t overlap
, uint64_t object_overlap
) {
200 EXPECT_CALL(mock_image_ctx
, prune_parent_extents(_
, _
, overlap
, _
))
201 .WillOnce(WithoutArgs(Invoke([object_overlap
]() {
202 return object_overlap
;
206 void expect_read_parent(librbd::MockTestImageCtx
& mock_image_ctx
,
207 const Extents
& image_extents
,
208 const std::string
& data
, int r
) {
209 EXPECT_CALL(*mock_image_ctx
.io_image_dispatcher
,
210 send(IsRead(image_extents
)))
212 [&mock_image_ctx
, image_extents
, data
, r
](io::ImageDispatchSpec
* spec
) {
213 auto req
= boost::get
<librbd::io::ImageDispatchSpec::Read
>(
215 ASSERT_TRUE(req
!= nullptr);
222 spec
->dispatch_result
= DISPATCH_RESULT_COMPLETE
;
224 auto aio_comp
= spec
->aio_comp
;
225 aio_comp
->read_result
= std::move(req
->read_result
);
226 aio_comp
->read_result
.set_image_extents(image_extents
);
227 aio_comp
->set_request_count(1);
228 auto ctx
= new ReadResult::C_ImageReadRequest(aio_comp
, 0,
230 ctx
->bl
.append(data
);
231 mock_image_ctx
.image_ctx
->op_work_queue
->queue(ctx
, r
);
235 void expect_copyup(MockTestImageCtx
& mock_image_ctx
, uint64_t snap_id
,
236 const std::string
& oid
, const std::string
& data
, int r
) {
241 if (snap_id
== CEPH_NOSNAP
) {
242 snapc
= mock_image_ctx
.snapc
;
245 auto& mock_io_ctx
= librados::get_mock_io_ctx(
246 mock_image_ctx
.rados_api
, *mock_image_ctx
.get_data_io_context());
247 EXPECT_CALL(mock_io_ctx
,
248 exec(oid
, _
, StrEq("rbd"), StrEq("copyup"),
249 ContentsEqual(in_bl
), _
, _
, snapc
))
250 .WillOnce(Return(r
));
253 void expect_sparse_copyup(MockTestImageCtx
&mock_image_ctx
, uint64_t snap_id
,
254 const std::string
&oid
,
255 const std::map
<uint64_t, uint64_t> &extent_map
,
256 const std::string
&data
, int r
) {
258 data_bl
.append(data
);
261 encode(extent_map
, in_bl
);
262 encode(data_bl
, in_bl
);
265 if (snap_id
== CEPH_NOSNAP
) {
266 snapc
= mock_image_ctx
.snapc
;
269 auto& mock_io_ctx
= librados::get_mock_io_ctx(
270 mock_image_ctx
.rados_api
, *mock_image_ctx
.get_data_io_context());
271 EXPECT_CALL(mock_io_ctx
,
272 exec(oid
, _
, StrEq("rbd"), StrEq("sparse_copyup"),
273 ContentsEqual(in_bl
), _
, _
, snapc
))
274 .WillOnce(Return(r
));
277 void expect_write(MockTestImageCtx
& mock_image_ctx
, uint64_t snap_id
,
278 const std::string
& oid
, int r
) {
280 if (snap_id
== CEPH_NOSNAP
) {
281 snapc
= mock_image_ctx
.snapc
;
284 auto& mock_io_ctx
= librados::get_mock_io_ctx(
285 mock_image_ctx
.rados_api
, *mock_image_ctx
.get_data_io_context());
286 EXPECT_CALL(mock_io_ctx
, write(oid
, _
, 0, 0, snapc
))
287 .WillOnce(Return(r
));
290 void expect_test_features(MockTestImageCtx
& mock_image_ctx
) {
291 EXPECT_CALL(mock_image_ctx
, test_features(_
, _
))
292 .WillRepeatedly(WithArg
<0>(Invoke([&mock_image_ctx
](uint64_t features
) {
293 return (mock_image_ctx
.features
& features
) != 0;
297 void expect_is_lock_owner(MockTestImageCtx
& mock_image_ctx
) {
298 if (mock_image_ctx
.exclusive_lock
!= nullptr) {
299 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
,
300 is_lock_owner()).WillRepeatedly(Return(true));
304 void expect_is_empty_write_op(MockAbstractObjectWriteRequest
& mock_write_request
,
306 EXPECT_CALL(mock_write_request
, is_empty_write_op())
307 .WillOnce(Return(is_empty
));
310 void expect_add_copyup_ops(MockAbstractObjectWriteRequest
& mock_write_request
) {
311 EXPECT_CALL(mock_write_request
, add_copyup_ops(_
))
312 .WillOnce(Invoke([](neorados::WriteOp
* op
) {
313 op
->write(0, bufferlist
{});
317 void expect_get_pre_write_object_map_state(MockTestImageCtx
& mock_image_ctx
,
318 MockAbstractObjectWriteRequest
& mock_write_request
,
320 if (mock_image_ctx
.object_map
!= nullptr) {
321 EXPECT_CALL(mock_write_request
, get_pre_write_object_map_state())
322 .WillOnce(Return(state
));
326 void expect_object_map_at(MockTestImageCtx
& mock_image_ctx
,
327 uint64_t object_no
, uint8_t state
) {
328 if (mock_image_ctx
.object_map
!= nullptr) {
329 EXPECT_CALL(*mock_image_ctx
.object_map
, at(object_no
))
330 .WillOnce(Return(state
));
334 void expect_object_map_update(MockTestImageCtx
& mock_image_ctx
,
335 uint64_t snap_id
, uint64_t object_no
,
336 uint8_t state
, bool updated
, int ret_val
) {
337 if (mock_image_ctx
.object_map
!= nullptr) {
338 if (!mock_image_ctx
.image_ctx
->test_features(RBD_FEATURE_FAST_DIFF
) &&
339 state
== OBJECT_EXISTS_CLEAN
) {
340 state
= OBJECT_EXISTS
;
343 EXPECT_CALL(*mock_image_ctx
.object_map
,
344 aio_update(snap_id
, object_no
, object_no
+ 1, state
,
345 boost::optional
<uint8_t>(), _
,
346 (snap_id
!= CEPH_NOSNAP
), _
))
347 .WillOnce(WithArg
<7>(Invoke([&mock_image_ctx
, updated
, ret_val
](Context
*ctx
) {
349 mock_image_ctx
.op_work_queue
->queue(ctx
, ret_val
);
356 void expect_object_copy(MockTestImageCtx
& mock_image_ctx
,
357 MockObjectCopyRequest
& mock_object_copy_request
,
358 bool flatten
, int r
) {
359 EXPECT_CALL(mock_object_copy_request
, send())
361 [&mock_image_ctx
, &mock_object_copy_request
, flatten
, r
]() {
362 ASSERT_EQ(flatten
, mock_object_copy_request
.flatten
);
363 mock_image_ctx
.op_work_queue
->queue(
364 mock_object_copy_request
.on_finish
, r
);
368 void expect_prepare_copyup(MockTestImageCtx
& mock_image_ctx
, int r
= 0) {
369 EXPECT_CALL(*mock_image_ctx
.io_object_dispatcher
,
370 prepare_copyup(_
, _
)).WillOnce(Return(r
));
373 void expect_prepare_copyup(MockTestImageCtx
& mock_image_ctx
,
374 const SparseBufferlist
& in_sparse_bl
,
375 const SparseBufferlist
& out_sparse_bl
) {
376 EXPECT_CALL(*mock_image_ctx
.io_object_dispatcher
,
377 prepare_copyup(_
, _
))
378 .WillOnce(WithArg
<1>(Invoke(
379 [in_sparse_bl
, out_sparse_bl
]
380 (SnapshotSparseBufferlist
* snap_sparse_bl
) {
381 auto& sparse_bl
= (*snap_sparse_bl
)[0];
382 EXPECT_EQ(in_sparse_bl
, sparse_bl
);
384 sparse_bl
= out_sparse_bl
;
389 void flush_async_operations(librbd::ImageCtx
* ictx
) {
390 api::Io
<>::flush(*ictx
);
393 std::string m_parent_image_name
;
396 TEST_F(TestMockIoCopyupRequest
, Standard
) {
397 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
399 librbd::ImageCtx
*ictx
;
400 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
402 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
403 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
405 MockExclusiveLock mock_exclusive_lock
;
406 MockJournal mock_journal
;
407 MockObjectMap mock_object_map
;
408 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
411 expect_op_work_queue(mock_image_ctx
);
412 expect_is_lock_owner(mock_image_ctx
);
416 std::string
data(4096, '1');
417 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
418 expect_prepare_copyup(mock_image_ctx
);
420 MockAbstractObjectWriteRequest mock_write_request
;
421 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
423 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
424 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
427 expect_add_copyup_ops(mock_write_request
);
428 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
429 {{0, 4096}}, data
, 0);
430 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
432 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
433 ImageArea::DATA
, {});
434 mock_image_ctx
.copyup_list
[0] = req
;
435 req
->append_request(&mock_write_request
, {});
438 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
441 TEST_F(TestMockIoCopyupRequest
, StandardWithSnaps
) {
442 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
444 librbd::ImageCtx
*ictx
;
445 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
446 ictx
->image_lock
.lock();
447 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
448 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
450 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
451 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
453 ictx
->snapc
= {2, {2, 1}};
454 ictx
->image_lock
.unlock();
456 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
457 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
459 MockExclusiveLock mock_exclusive_lock
;
460 MockJournal mock_journal
;
461 MockObjectMap mock_object_map
;
462 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
465 expect_test_features(mock_image_ctx
);
466 expect_op_work_queue(mock_image_ctx
);
467 expect_is_lock_owner(mock_image_ctx
);
471 std::string
data(4096, '1');
472 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
473 expect_prepare_copyup(mock_image_ctx
);
475 MockAbstractObjectWriteRequest mock_write_request
;
476 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
478 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
479 expect_object_map_update(mock_image_ctx
, 1, 0, OBJECT_EXISTS
, true, 0);
480 expect_object_map_update(mock_image_ctx
, 2, 0, OBJECT_EXISTS_CLEAN
, true, 0);
481 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
484 expect_add_copyup_ops(mock_write_request
);
485 expect_sparse_copyup(mock_image_ctx
, 0, ictx
->get_object_name(0), {{0, 4096}},
487 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
489 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
490 ImageArea::DATA
, {});
491 mock_image_ctx
.copyup_list
[0] = req
;
492 req
->append_request(&mock_write_request
, {});
495 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
498 TEST_F(TestMockIoCopyupRequest
, CopyOnRead
) {
499 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
501 librbd::ImageCtx
*ictx
;
502 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
504 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
505 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
507 MockExclusiveLock mock_exclusive_lock
;
508 MockJournal mock_journal
;
509 MockObjectMap mock_object_map
;
510 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
513 expect_op_work_queue(mock_image_ctx
);
514 expect_is_lock_owner(mock_image_ctx
);
518 std::string
data(4096, '1');
519 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
520 expect_prepare_copyup(mock_image_ctx
);
522 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
523 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
526 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
527 {{0, 4096}}, data
, 0);
529 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
530 ImageArea::DATA
, {});
531 mock_image_ctx
.copyup_list
[0] = req
;
533 flush_async_operations(ictx
);
536 TEST_F(TestMockIoCopyupRequest
, CopyOnReadWithSnaps
) {
537 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
539 librbd::ImageCtx
*ictx
;
540 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
541 ictx
->image_lock
.lock();
542 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
543 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
545 ictx
->snapc
= {1, {1}};
546 ictx
->image_lock
.unlock();
548 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
549 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
551 MockExclusiveLock mock_exclusive_lock
;
552 MockJournal mock_journal
;
553 MockObjectMap mock_object_map
;
554 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
557 expect_test_features(mock_image_ctx
);
558 expect_op_work_queue(mock_image_ctx
);
559 expect_is_lock_owner(mock_image_ctx
);
563 std::string
data(4096, '1');
564 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
565 expect_prepare_copyup(mock_image_ctx
);
567 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
568 expect_object_map_update(mock_image_ctx
, 1, 0, OBJECT_EXISTS
, true, 0);
569 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS_CLEAN
,
572 expect_sparse_copyup(mock_image_ctx
, 0, ictx
->get_object_name(0), {{0, 4096}},
575 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
576 ImageArea::DATA
, {});
577 mock_image_ctx
.copyup_list
[0] = req
;
579 flush_async_operations(ictx
);
582 TEST_F(TestMockIoCopyupRequest
, DeepCopy
) {
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 MockAbstractObjectWriteRequest mock_write_request
;
603 MockObjectCopyRequest mock_object_copy_request
;
604 mock_image_ctx
.migration_info
= {1, "", "", "image id", "", {}, ictx
->size
,
606 expect_is_empty_write_op(mock_write_request
, false);
607 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
609 expect_is_empty_write_op(mock_write_request
, false);
610 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
612 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
613 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
616 expect_add_copyup_ops(mock_write_request
);
617 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
619 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
621 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
622 ImageArea::DATA
, {});
623 mock_image_ctx
.copyup_list
[0] = req
;
624 req
->append_request(&mock_write_request
, {});
627 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
630 TEST_F(TestMockIoCopyupRequest
, DeepCopyOnRead
) {
631 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
633 librbd::ImageCtx
*ictx
;
634 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
636 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
637 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
639 MockExclusiveLock mock_exclusive_lock
;
640 MockJournal mock_journal
;
641 MockObjectMap mock_object_map
;
642 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
645 expect_op_work_queue(mock_image_ctx
);
646 expect_is_lock_owner(mock_image_ctx
);
650 MockObjectCopyRequest mock_object_copy_request
;
651 mock_image_ctx
.migration_info
= {1, "", "", "image id", "", {}, ictx
->size
,
653 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
655 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
656 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
659 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
660 ImageArea::DATA
, {});
661 mock_image_ctx
.copyup_list
[0] = req
;
663 flush_async_operations(ictx
);
666 TEST_F(TestMockIoCopyupRequest
, DeepCopyWithPostSnaps
) {
667 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
669 librbd::ImageCtx
*ictx
;
670 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
671 ictx
->image_lock
.lock();
672 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx
->size
,
673 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
675 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
676 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
678 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
679 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
681 ictx
->snapc
= {3, {3, 2, 1}};
682 ictx
->image_lock
.unlock();
684 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
685 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
687 MockExclusiveLock mock_exclusive_lock
;
688 MockJournal mock_journal
;
689 MockObjectMap mock_object_map
;
690 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
693 expect_test_features(mock_image_ctx
);
694 expect_op_work_queue(mock_image_ctx
);
695 expect_is_lock_owner(mock_image_ctx
);
699 MockAbstractObjectWriteRequest mock_write_request
;
700 MockObjectCopyRequest mock_object_copy_request
;
701 mock_image_ctx
.migration_info
= {1, "", "", "image id", "",
702 {{CEPH_NOSNAP
, {2, 1}}},
704 expect_is_empty_write_op(mock_write_request
, false);
705 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
707 expect_is_empty_write_op(mock_write_request
, false);
708 expect_get_parent_overlap(mock_image_ctx
, 1, 0, 0);
709 expect_get_parent_overlap(mock_image_ctx
, 2, 1, 0);
710 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
711 expect_get_parent_overlap(mock_image_ctx
, 3, 1, 0);
712 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
713 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
715 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
716 expect_object_map_update(mock_image_ctx
, 2, 0, OBJECT_EXISTS
, true, 0);
717 expect_object_map_update(mock_image_ctx
, 3, 0, OBJECT_EXISTS_CLEAN
, true, 0);
718 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
721 expect_add_copyup_ops(mock_write_request
);
722 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
724 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
726 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
727 ImageArea::DATA
, {});
728 mock_image_ctx
.copyup_list
[0] = req
;
729 req
->append_request(&mock_write_request
, {});
732 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
735 TEST_F(TestMockIoCopyupRequest
, DeepCopyWithPreAndPostSnaps
) {
736 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
738 librbd::ImageCtx
*ictx
;
739 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
740 ictx
->image_lock
.lock();
741 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "4", 4, ictx
->size
,
742 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
744 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "3", 3, ictx
->size
,
745 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
747 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "2", 2, ictx
->size
,
748 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
750 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
751 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
753 ictx
->snapc
= {4, {4, 3, 2, 1}};
754 ictx
->image_lock
.unlock();
756 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
757 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
759 MockExclusiveLock mock_exclusive_lock
;
760 MockJournal mock_journal
;
761 MockObjectMap mock_object_map
;
762 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
765 expect_test_features(mock_image_ctx
);
766 expect_op_work_queue(mock_image_ctx
);
767 expect_is_lock_owner(mock_image_ctx
);
771 MockAbstractObjectWriteRequest mock_write_request
;
772 MockObjectCopyRequest mock_object_copy_request
;
773 mock_image_ctx
.migration_info
= {1, "", "", "image id", "",
774 {{CEPH_NOSNAP
, {2, 1}}, {10, {1}}},
776 expect_is_empty_write_op(mock_write_request
, false);
777 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, 0);
779 expect_is_empty_write_op(mock_write_request
, false);
780 expect_get_parent_overlap(mock_image_ctx
, 2, 0, 0);
781 expect_get_parent_overlap(mock_image_ctx
, 3, 1, 0);
782 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
783 expect_get_parent_overlap(mock_image_ctx
, 4, 1, 0);
784 expect_prune_parent_extents(mock_image_ctx
, 1, 1);
785 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
787 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
788 expect_object_map_update(mock_image_ctx
, 3, 0, OBJECT_EXISTS_CLEAN
, true, 0);
789 expect_object_map_update(mock_image_ctx
, 4, 0, OBJECT_EXISTS_CLEAN
, true, 0);
790 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
793 expect_add_copyup_ops(mock_write_request
);
794 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
796 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
798 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
799 ImageArea::DATA
, {});
800 mock_image_ctx
.copyup_list
[0] = req
;
801 req
->append_request(&mock_write_request
, {});
804 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
807 TEST_F(TestMockIoCopyupRequest
, ZeroedCopyup
) {
808 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
810 librbd::ImageCtx
*ictx
;
811 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
813 MockTestImageCtx
mock_image_ctx(*ictx
);
815 MockExclusiveLock mock_exclusive_lock
;
816 MockJournal mock_journal
;
817 MockObjectMap mock_object_map
;
818 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
821 expect_op_work_queue(mock_image_ctx
);
822 expect_is_lock_owner(mock_image_ctx
);
826 MockAbstractObjectWriteRequest mock_write_request
;
827 expect_prepare_copyup(mock_image_ctx
);
828 expect_is_empty_write_op(mock_write_request
, false);
829 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
831 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
832 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
835 expect_add_copyup_ops(mock_write_request
);
836 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
838 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
840 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
841 ImageArea::DATA
, {});
842 mock_image_ctx
.copyup_list
[0] = req
;
843 req
->append_request(&mock_write_request
, {});
846 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
849 TEST_F(TestMockIoCopyupRequest
, ZeroedCopyOnRead
) {
850 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
852 librbd::ImageCtx
*ictx
;
853 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
855 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
856 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
858 MockExclusiveLock mock_exclusive_lock
;
859 MockJournal mock_journal
;
860 MockObjectMap mock_object_map
;
861 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
864 expect_op_work_queue(mock_image_ctx
);
865 expect_is_lock_owner(mock_image_ctx
);
869 std::string
data(4096, '\0');
870 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
871 expect_prepare_copyup(mock_image_ctx
);
873 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
874 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
877 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
880 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
881 ImageArea::DATA
, {});
882 mock_image_ctx
.copyup_list
[0] = req
;
884 flush_async_operations(ictx
);
887 TEST_F(TestMockIoCopyupRequest
, NoOpCopyup
) {
888 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
890 librbd::ImageCtx
*ictx
;
891 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
893 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
894 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
896 MockExclusiveLock mock_exclusive_lock
;
897 MockJournal mock_journal
;
898 MockObjectMap mock_object_map
;
899 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
902 expect_op_work_queue(mock_image_ctx
);
903 expect_is_lock_owner(mock_image_ctx
);
907 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, "", -ENOENT
);
909 expect_prepare_copyup(mock_image_ctx
);
911 MockAbstractObjectWriteRequest mock_write_request
;
912 expect_is_empty_write_op(mock_write_request
, true);
914 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
915 ImageArea::DATA
, {});
916 mock_image_ctx
.copyup_list
[0] = req
;
917 req
->append_request(&mock_write_request
, {});
920 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
923 TEST_F(TestMockIoCopyupRequest
, RestartWrite
) {
924 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
926 librbd::ImageCtx
*ictx
;
927 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
929 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
930 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
932 MockExclusiveLock mock_exclusive_lock
;
933 MockJournal mock_journal
;
934 MockObjectMap mock_object_map
;
935 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
938 expect_op_work_queue(mock_image_ctx
);
939 expect_is_lock_owner(mock_image_ctx
);
943 std::string
data(4096, '1');
944 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
945 expect_prepare_copyup(mock_image_ctx
);
947 MockAbstractObjectWriteRequest mock_write_request1
;
948 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request1
,
950 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
951 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
954 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
955 ImageArea::DATA
, {});
956 expect_add_copyup_ops(mock_write_request1
);
957 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
958 {{0, 4096}}, data
, 0);
960 MockAbstractObjectWriteRequest mock_write_request2
;
961 auto& mock_io_ctx
= librados::get_mock_io_ctx(
962 mock_image_ctx
.rados_api
, *mock_image_ctx
.get_data_io_context());
963 EXPECT_CALL(mock_io_ctx
, write(ictx
->get_object_name(0), _
, 0, 0, _
))
964 .WillOnce(WithoutArgs(Invoke([req
, &mock_write_request2
]() {
965 req
->append_request(&mock_write_request2
, {});
969 mock_image_ctx
.copyup_list
[0] = req
;
970 req
->append_request(&mock_write_request1
, {});
973 ASSERT_EQ(0, mock_write_request1
.ctx
.wait());
974 ASSERT_EQ(-ERESTART
, mock_write_request2
.ctx
.wait());
977 TEST_F(TestMockIoCopyupRequest
, ReadFromParentError
) {
978 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
980 librbd::ImageCtx
*ictx
;
981 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
983 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
984 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
986 MockExclusiveLock mock_exclusive_lock
;
987 MockJournal mock_journal
;
988 MockObjectMap mock_object_map
;
989 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
992 expect_op_work_queue(mock_image_ctx
);
993 expect_is_lock_owner(mock_image_ctx
);
997 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, "", -EPERM
);
999 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1000 ImageArea::DATA
, {});
1001 mock_image_ctx
.copyup_list
[0] = req
;
1002 MockAbstractObjectWriteRequest mock_write_request
;
1003 req
->append_request(&mock_write_request
, {});
1006 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
1009 TEST_F(TestMockIoCopyupRequest
, PrepareCopyupError
) {
1010 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1012 librbd::ImageCtx
*ictx
;
1013 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1015 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1016 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1018 MockExclusiveLock mock_exclusive_lock
;
1019 MockJournal mock_journal
;
1020 MockObjectMap mock_object_map
;
1021 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1024 expect_op_work_queue(mock_image_ctx
);
1025 expect_is_lock_owner(mock_image_ctx
);
1029 std::string
data(4096, '1');
1030 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
1031 expect_prepare_copyup(mock_image_ctx
, -EIO
);
1033 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1034 ImageArea::DATA
, {});
1035 mock_image_ctx
.copyup_list
[0] = req
;
1036 MockAbstractObjectWriteRequest mock_write_request
;
1037 req
->append_request(&mock_write_request
, {});
1040 ASSERT_EQ(-EIO
, mock_write_request
.ctx
.wait());
1043 TEST_F(TestMockIoCopyupRequest
, DeepCopyError
) {
1044 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1046 librbd::ImageCtx
*ictx
;
1047 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1049 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1050 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1052 MockExclusiveLock mock_exclusive_lock
;
1053 MockJournal mock_journal
;
1054 MockObjectMap mock_object_map
;
1055 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1058 expect_op_work_queue(mock_image_ctx
);
1059 expect_is_lock_owner(mock_image_ctx
);
1063 MockAbstractObjectWriteRequest mock_write_request
;
1064 MockObjectCopyRequest mock_object_copy_request
;
1065 mock_image_ctx
.migration_info
= {1, "", "", "image id", "", {}, ictx
->size
,
1067 expect_is_empty_write_op(mock_write_request
, false);
1068 expect_object_copy(mock_image_ctx
, mock_object_copy_request
, true, -EPERM
);
1070 expect_is_empty_write_op(mock_write_request
, false);
1072 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1073 ImageArea::DATA
, {});
1074 mock_image_ctx
.copyup_list
[0] = req
;
1075 req
->append_request(&mock_write_request
, {});
1078 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
1081 TEST_F(TestMockIoCopyupRequest
, UpdateObjectMapError
) {
1082 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_OBJECT_MAP
);
1084 librbd::ImageCtx
*ictx
;
1085 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1087 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1088 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1090 MockExclusiveLock mock_exclusive_lock
;
1091 MockJournal mock_journal
;
1092 MockObjectMap mock_object_map
;
1093 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1096 expect_op_work_queue(mock_image_ctx
);
1097 expect_is_lock_owner(mock_image_ctx
);
1101 std::string
data(4096, '1');
1102 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
1103 expect_prepare_copyup(mock_image_ctx
);
1105 MockAbstractObjectWriteRequest mock_write_request
;
1106 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
1108 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
1109 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
1112 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1113 ImageArea::DATA
, {});
1114 mock_image_ctx
.copyup_list
[0] = req
;
1115 req
->append_request(&mock_write_request
, {});
1118 ASSERT_EQ(-EINVAL
, mock_write_request
.ctx
.wait());
1121 TEST_F(TestMockIoCopyupRequest
, CopyupError
) {
1122 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1124 librbd::ImageCtx
*ictx
;
1125 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1126 ictx
->image_lock
.lock();
1127 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
1128 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
1130 ictx
->snapc
= {1, {1}};
1131 ictx
->image_lock
.unlock();
1133 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1134 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1136 MockExclusiveLock mock_exclusive_lock
;
1137 MockJournal mock_journal
;
1138 MockObjectMap mock_object_map
;
1139 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1142 expect_test_features(mock_image_ctx
);
1143 expect_op_work_queue(mock_image_ctx
);
1144 expect_is_lock_owner(mock_image_ctx
);
1148 std::string
data(4096, '1');
1149 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
1150 expect_prepare_copyup(mock_image_ctx
);
1152 MockAbstractObjectWriteRequest mock_write_request
;
1153 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
1155 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
1156 expect_object_map_update(mock_image_ctx
, 1, 0, OBJECT_EXISTS
, true, 0);
1157 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
1160 expect_add_copyup_ops(mock_write_request
);
1161 expect_sparse_copyup(mock_image_ctx
, 0, ictx
->get_object_name(0), {{0, 4096}},
1163 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
1165 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1166 ImageArea::DATA
, {});
1167 mock_image_ctx
.copyup_list
[0] = req
;
1168 req
->append_request(&mock_write_request
, {});
1171 ASSERT_EQ(-EPERM
, mock_write_request
.ctx
.wait());
1172 flush_async_operations(ictx
);
1175 TEST_F(TestMockIoCopyupRequest
, SparseCopyupNotSupported
) {
1176 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1178 librbd::ImageCtx
*ictx
;
1179 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1181 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1182 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1183 mock_image_ctx
.enable_sparse_copyup
= false;
1185 MockExclusiveLock mock_exclusive_lock
;
1186 MockJournal mock_journal
;
1187 MockObjectMap mock_object_map
;
1188 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1191 expect_op_work_queue(mock_image_ctx
);
1192 expect_is_lock_owner(mock_image_ctx
);
1196 std::string
data(4096, '1');
1197 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
1198 expect_prepare_copyup(mock_image_ctx
);
1200 MockAbstractObjectWriteRequest mock_write_request
;
1201 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
1203 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
1204 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
1207 expect_add_copyup_ops(mock_write_request
);
1208 expect_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), data
, 0);
1209 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
1211 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1212 ImageArea::DATA
, {});
1213 mock_image_ctx
.copyup_list
[0] = req
;
1214 req
->append_request(&mock_write_request
, {});
1217 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
1220 TEST_F(TestMockIoCopyupRequest
, ProcessCopyup
) {
1221 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1223 librbd::ImageCtx
*ictx
;
1224 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1226 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1227 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1229 MockExclusiveLock mock_exclusive_lock
;
1230 MockJournal mock_journal
;
1231 MockObjectMap mock_object_map
;
1232 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1235 expect_op_work_queue(mock_image_ctx
);
1236 expect_is_lock_owner(mock_image_ctx
);
1240 std::string
data(4096, '1');
1241 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
1243 bufferlist in_prepare_bl
;
1244 in_prepare_bl
.append(std::string(3072, '1'));
1245 bufferlist out_prepare_bl
;
1246 out_prepare_bl
.substr_of(in_prepare_bl
, 0, 1024);
1247 expect_prepare_copyup(
1249 {{1024U, {3072U, {SPARSE_EXTENT_STATE_DATA
, 3072,
1250 std::move(in_prepare_bl
)}}}},
1251 {{2048U, {1024U, {SPARSE_EXTENT_STATE_DATA
, 1024,
1252 std::move(out_prepare_bl
)}}}});
1254 MockAbstractObjectWriteRequest mock_write_request
;
1255 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
1257 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
1258 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
1261 expect_add_copyup_ops(mock_write_request
);
1262 expect_sparse_copyup(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0),
1263 {{2048, 1024}}, data
.substr(0, 1024), 0);
1264 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
1266 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1267 ImageArea::DATA
, {});
1268 mock_image_ctx
.copyup_list
[0] = req
;
1269 req
->append_request(&mock_write_request
, {{0, 1024}});
1272 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
1275 TEST_F(TestMockIoCopyupRequest
, ProcessCopyupOverwrite
) {
1276 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1278 librbd::ImageCtx
*ictx
;
1279 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1280 ictx
->image_lock
.lock();
1281 ictx
->add_snap(cls::rbd::UserSnapshotNamespace(), "1", 1, ictx
->size
,
1282 ictx
->parent_md
, RBD_PROTECTION_STATUS_UNPROTECTED
,
1284 ictx
->snapc
= {1, {1}};
1285 ictx
->image_lock
.unlock();
1287 MockTestImageCtx
mock_parent_image_ctx(*ictx
->parent
);
1288 MockTestImageCtx
mock_image_ctx(*ictx
, &mock_parent_image_ctx
);
1290 MockExclusiveLock mock_exclusive_lock
;
1291 MockJournal mock_journal
;
1292 MockObjectMap mock_object_map
;
1293 initialize_features(ictx
, mock_image_ctx
, mock_exclusive_lock
, mock_journal
,
1296 expect_test_features(mock_image_ctx
);
1297 expect_op_work_queue(mock_image_ctx
);
1298 expect_is_lock_owner(mock_image_ctx
);
1302 std::string
data(4096, '1');
1303 expect_read_parent(mock_parent_image_ctx
, {{0, 4096}}, data
, 0);
1305 bufferlist in_prepare_bl
;
1306 in_prepare_bl
.append(data
);
1307 bufferlist out_prepare_bl
;
1308 out_prepare_bl
.substr_of(in_prepare_bl
, 0, 1024);
1309 expect_prepare_copyup(
1311 {{0, {4096, {SPARSE_EXTENT_STATE_DATA
, 4096,
1312 std::move(in_prepare_bl
)}}}},
1313 {{0, {1024, {SPARSE_EXTENT_STATE_DATA
, 1024, bufferlist
{out_prepare_bl
}}}},
1314 {2048, {1024, {SPARSE_EXTENT_STATE_DATA
, 1024,
1315 bufferlist
{out_prepare_bl
}}}}});
1317 MockAbstractObjectWriteRequest mock_write_request
;
1318 expect_get_pre_write_object_map_state(mock_image_ctx
, mock_write_request
,
1320 expect_object_map_at(mock_image_ctx
, 0, OBJECT_NONEXISTENT
);
1321 expect_object_map_update(mock_image_ctx
, 1, 0, OBJECT_EXISTS
, true, 0);
1322 expect_object_map_update(mock_image_ctx
, CEPH_NOSNAP
, 0, OBJECT_EXISTS
, true,
1325 expect_add_copyup_ops(mock_write_request
);
1326 expect_sparse_copyup(mock_image_ctx
, 0, ictx
->get_object_name(0),
1327 {{0, 1024}, {2048, 1024}}, data
.substr(0, 2048), 0);
1328 expect_write(mock_image_ctx
, CEPH_NOSNAP
, ictx
->get_object_name(0), 0);
1330 auto req
= new MockCopyupRequest(&mock_image_ctx
, 0, {{0, 4096}},
1331 ImageArea::DATA
, {});
1332 mock_image_ctx
.copyup_list
[0] = req
;
1333 req
->append_request(&mock_write_request
, {{0, 1024}});
1336 ASSERT_EQ(0, mock_write_request
.ctx
.wait());
1340 } // namespace librbd