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/MockImageCtx.h"
7 #include "test/librbd/mock/MockObjectMap.h"
8 #include "test/librbd/mock/cache/MockImageCache.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "test/librados_test_stub/MockTestMemRadosClient.h"
11 #include "include/rbd/librbd.hpp"
12 #include "librbd/io/CopyupRequest.h"
13 #include "librbd/io/ObjectRequest.h"
14 #include "librbd/io/Utils.h"
19 struct MockTestImageCtx
: public MockImageCtx
{
20 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
24 } // anonymous namespace
28 inline ImageCtx
*get_image_ctx(MockImageCtx
*image_ctx
) {
29 return image_ctx
->image_ctx
;
37 struct CopyupRequest
<librbd::MockImageCtx
> {
38 MOCK_METHOD0(send
, void());
39 MOCK_METHOD1(append_request
, void(AbstractObjectWriteRequest
<librbd::MockTestImageCtx
>*));
43 struct CopyupRequest
<librbd::MockTestImageCtx
> : public CopyupRequest
<librbd::MockImageCtx
> {
44 static CopyupRequest
* s_instance
;
45 static CopyupRequest
* create(librbd::MockTestImageCtx
*ictx
,
46 uint64_t objectno
, Extents
&&image_extents
,
47 const ZTracer::Trace
&parent_trace
) {
56 CopyupRequest
<librbd::MockTestImageCtx
>* CopyupRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
63 static Mock
* s_instance
;
69 MOCK_METHOD8(read_parent
,
70 void(librbd::MockTestImageCtx
*, uint64_t, uint64_t, uint64_t,
71 librados::snap_t
, const ZTracer::Trace
&, ceph::bufferlist
*,
75 Mock
*Mock::s_instance
= nullptr;
77 } // anonymous namespace
79 template<> void read_parent(
80 librbd::MockTestImageCtx
*image_ctx
, uint64_t object_no
, uint64_t off
,
81 uint64_t len
, librados::snap_t snap_id
, const ZTracer::Trace
&trace
,
82 ceph::bufferlist
* data
, Context
* on_finish
) {
83 Mock::s_instance
->read_parent(image_ctx
, object_no
, off
, len
, snap_id
, trace
,
92 #include "librbd/io/ObjectRequest.cc"
98 using ::testing::DoDefault
;
99 using ::testing::InSequence
;
100 using ::testing::Invoke
;
101 using ::testing::Return
;
102 using ::testing::WithArg
;
103 using ::testing::WithArgs
;
105 struct TestMockIoObjectRequest
: public TestMockFixture
{
106 typedef ObjectRequest
<librbd::MockTestImageCtx
> MockObjectRequest
;
107 typedef ObjectReadRequest
<librbd::MockTestImageCtx
> MockObjectReadRequest
;
108 typedef ObjectWriteRequest
<librbd::MockTestImageCtx
> MockObjectWriteRequest
;
109 typedef ObjectDiscardRequest
<librbd::MockTestImageCtx
> MockObjectDiscardRequest
;
110 typedef ObjectWriteSameRequest
<librbd::MockTestImageCtx
> MockObjectWriteSameRequest
;
111 typedef ObjectCompareAndWriteRequest
<librbd::MockTestImageCtx
> MockObjectCompareAndWriteRequest
;
112 typedef AbstractObjectWriteRequest
<librbd::MockTestImageCtx
> MockAbstractObjectWriteRequest
;
113 typedef CopyupRequest
<librbd::MockTestImageCtx
> MockCopyupRequest
;
114 typedef util::Mock MockUtils
;
116 void expect_object_may_exist(MockTestImageCtx
&mock_image_ctx
,
117 uint64_t object_no
, bool exists
) {
118 if (mock_image_ctx
.object_map
!= nullptr) {
119 EXPECT_CALL(*mock_image_ctx
.object_map
, object_may_exist(object_no
))
120 .WillOnce(Return(exists
));
124 void expect_get_object_size(MockTestImageCtx
&mock_image_ctx
) {
125 EXPECT_CALL(mock_image_ctx
, get_object_size()).WillRepeatedly(Return(
126 mock_image_ctx
.layout
.object_size
));
129 void expect_get_parent_overlap(MockTestImageCtx
&mock_image_ctx
,
130 librados::snap_t snap_id
, uint64_t overlap
,
132 EXPECT_CALL(mock_image_ctx
, get_parent_overlap(snap_id
, _
))
133 .WillOnce(WithArg
<1>(Invoke([overlap
, r
](uint64_t *o
) {
139 void expect_prune_parent_extents(MockTestImageCtx
&mock_image_ctx
,
140 const Extents
& extents
,
141 uint64_t overlap
, uint64_t object_overlap
) {
142 EXPECT_CALL(mock_image_ctx
, prune_parent_extents(_
, overlap
))
143 .WillOnce(WithArg
<0>(Invoke([extents
, object_overlap
](Extents
& e
) {
145 return object_overlap
;
149 void expect_get_read_flags(MockTestImageCtx
&mock_image_ctx
,
150 librados::snap_t snap_id
, int flags
) {
151 EXPECT_CALL(mock_image_ctx
, get_read_flags(snap_id
))
152 .WillOnce(Return(flags
));
155 void expect_is_lock_owner(MockExclusiveLock
& mock_exclusive_lock
) {
156 EXPECT_CALL(mock_exclusive_lock
, is_lock_owner()).WillRepeatedly(
160 void expect_read(MockTestImageCtx
&mock_image_ctx
,
161 const std::string
& oid
, uint64_t off
, uint64_t len
,
162 const std::string
& data
, int r
) {
166 auto& expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
167 read(oid
, len
, off
, _
));
169 expect
.WillOnce(Return(r
));
171 expect
.WillOnce(WithArg
<3>(Invoke([bl
](bufferlist
*out_bl
) {
178 void expect_sparse_read(MockTestImageCtx
&mock_image_ctx
,
179 const std::string
& oid
, uint64_t off
, uint64_t len
,
180 const std::string
& data
, int r
) {
184 auto& expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
185 sparse_read(oid
, off
, len
, _
, _
));
187 expect
.WillOnce(Return(r
));
189 expect
.WillOnce(WithArg
<4>(Invoke([bl
](bufferlist
*out_bl
) {
196 void expect_read_parent(MockUtils
&mock_utils
, uint64_t object_no
,
197 uint64_t off
, uint64_t len
, librados::snap_t snap_id
,
199 EXPECT_CALL(mock_utils
,
200 read_parent(_
, object_no
, off
, len
, snap_id
, _
, _
, _
))
201 .WillOnce(WithArg
<7>(CompleteContext(r
, static_cast<ContextWQ
*>(nullptr))));
204 void expect_copyup(MockCopyupRequest
& mock_copyup_request
, int r
) {
205 EXPECT_CALL(mock_copyup_request
, send())
206 .WillOnce(Invoke([]() {}));
209 void expect_copyup(MockCopyupRequest
& mock_copyup_request
,
210 MockAbstractObjectWriteRequest
** write_request
, int r
) {
211 EXPECT_CALL(mock_copyup_request
, append_request(_
))
212 .WillOnce(Invoke([write_request
](MockAbstractObjectWriteRequest
*req
) {
213 *write_request
= req
;
215 EXPECT_CALL(mock_copyup_request
, send())
216 .WillOnce(Invoke([write_request
, r
]() {
217 (*write_request
)->handle_copyup(r
);
221 void expect_object_map_update(MockTestImageCtx
&mock_image_ctx
,
222 uint64_t start_object
, uint64_t end_object
,
224 const boost::optional
<uint8_t> ¤t_state
,
225 bool updated
, int ret_val
) {
226 if (mock_image_ctx
.object_map
!= nullptr) {
227 EXPECT_CALL(*mock_image_ctx
.object_map
,
228 aio_update(CEPH_NOSNAP
, start_object
, end_object
, state
,
229 current_state
, _
, false, _
))
230 .WillOnce(WithArg
<7>(Invoke([&mock_image_ctx
, updated
, ret_val
](Context
*ctx
) {
232 mock_image_ctx
.op_work_queue
->queue(ctx
, ret_val
);
239 void expect_assert_exists(MockTestImageCtx
&mock_image_ctx
, int r
) {
240 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
), assert_exists(_
))
241 .WillOnce(Return(r
));
244 void expect_write(MockTestImageCtx
&mock_image_ctx
,
245 uint64_t offset
, uint64_t length
, int r
) {
246 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
247 write(_
, _
, length
, offset
, _
));
249 expect
.WillOnce(Return(r
));
251 expect
.WillOnce(DoDefault());
255 void expect_write_full(MockTestImageCtx
&mock_image_ctx
, int r
) {
256 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
257 write_full(_
, _
, _
));
259 expect
.WillOnce(Return(r
));
261 expect
.WillOnce(DoDefault());
265 void expect_writesame(MockTestImageCtx
&mock_image_ctx
,
266 uint64_t offset
, uint64_t length
, int r
) {
267 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
268 writesame(_
, _
, length
, offset
, _
));
270 expect
.WillOnce(Return(r
));
272 expect
.WillOnce(DoDefault());
276 void expect_remove(MockTestImageCtx
&mock_image_ctx
, int r
) {
277 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
280 expect
.WillOnce(Return(r
));
282 expect
.WillOnce(DoDefault());
286 void expect_create(MockTestImageCtx
&mock_image_ctx
, bool exclusive
) {
287 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
), create(_
, exclusive
, _
))
291 void expect_truncate(MockTestImageCtx
&mock_image_ctx
, int offset
, int r
) {
292 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
293 truncate(_
, offset
, _
));
295 expect
.WillOnce(Return(r
));
297 expect
.WillOnce(DoDefault());
301 void expect_zero(MockTestImageCtx
&mock_image_ctx
, int offset
, int length
,
303 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
304 zero(_
, offset
, length
, _
));
306 expect
.WillOnce(Return(r
));
308 expect
.WillOnce(DoDefault());
312 void expect_cmpext(MockTestImageCtx
&mock_image_ctx
, int offset
, int r
) {
313 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
314 cmpext(_
, offset
, _
));
316 expect
.WillOnce(Return(r
));
318 expect
.WillOnce(DoDefault());
323 TEST_F(TestMockIoObjectRequest
, Read
) {
324 librbd::ImageCtx
*ictx
;
325 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
326 ictx
->sparse_read_threshold_bytes
= 8096;
328 MockTestImageCtx
mock_image_ctx(*ictx
);
330 MockObjectMap mock_object_map
;
331 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
332 mock_image_ctx
.object_map
= &mock_object_map
;
336 expect_object_may_exist(mock_image_ctx
, 0, true);
337 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
338 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096,
339 std::string(4096, '1'), 0);
342 ExtentMap extent_map
;
344 auto req
= MockObjectReadRequest::create(
345 &mock_image_ctx
, 0, 0, 4096, CEPH_NOSNAP
, 0, {}, &bl
, &extent_map
, &ctx
);
347 ASSERT_EQ(0, ctx
.wait());
350 TEST_F(TestMockIoObjectRequest
, SparseReadThreshold
) {
351 librbd::ImageCtx
*ictx
;
352 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
353 ictx
->sparse_read_threshold_bytes
= ictx
->get_object_size();
355 MockTestImageCtx
mock_image_ctx(*ictx
);
357 MockObjectMap mock_object_map
;
358 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
359 mock_image_ctx
.object_map
= &mock_object_map
;
363 expect_object_may_exist(mock_image_ctx
, 0, true);
364 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
365 expect_sparse_read(mock_image_ctx
, ictx
->get_object_name(0), 0,
366 ictx
->sparse_read_threshold_bytes
,
367 std::string(ictx
->sparse_read_threshold_bytes
, '1'), 0);
370 ExtentMap extent_map
;
372 auto req
= MockObjectReadRequest::create(
373 &mock_image_ctx
, 0, 0, ictx
->sparse_read_threshold_bytes
, CEPH_NOSNAP
, 0,
374 {}, &bl
, &extent_map
, &ctx
);
376 ASSERT_EQ(0, ctx
.wait());
379 TEST_F(TestMockIoObjectRequest
, ReadError
) {
380 librbd::ImageCtx
*ictx
;
381 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
382 ictx
->sparse_read_threshold_bytes
= 8096;
384 MockTestImageCtx
mock_image_ctx(*ictx
);
386 MockObjectMap mock_object_map
;
387 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
388 mock_image_ctx
.object_map
= &mock_object_map
;
392 expect_object_may_exist(mock_image_ctx
, 0, true);
393 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
394 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -EPERM
);
397 ExtentMap extent_map
;
399 auto req
= MockObjectReadRequest::create(
400 &mock_image_ctx
, 0, 0, 4096, CEPH_NOSNAP
, 0, {}, &bl
, &extent_map
, &ctx
);
402 ASSERT_EQ(-EPERM
, ctx
.wait());
405 TEST_F(TestMockIoObjectRequest
, ParentRead
) {
406 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
410 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
411 ASSERT_EQ(0, image
.snap_create("one"));
412 ASSERT_EQ(0, image
.snap_protect("one"));
415 std::string clone_name
= get_temp_image_name();
417 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
418 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
420 librbd::ImageCtx
*ictx
;
421 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
422 ictx
->sparse_read_threshold_bytes
= 8096;
423 ictx
->clone_copy_on_read
= false;
425 MockTestImageCtx
mock_image_ctx(*ictx
);
426 mock_image_ctx
.parent
= &mock_image_ctx
;
428 MockObjectMap mock_object_map
;
429 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
430 mock_image_ctx
.object_map
= &mock_object_map
;
434 expect_object_may_exist(mock_image_ctx
, 0, true);
435 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
436 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -ENOENT
);
438 MockUtils mock_utils
;
439 expect_read_parent(mock_utils
, 0, 0, 4096, CEPH_NOSNAP
, 0);
442 ExtentMap extent_map
;
444 auto req
= MockObjectReadRequest::create(
445 &mock_image_ctx
, 0, 0, 4096, CEPH_NOSNAP
, 0, {}, &bl
, &extent_map
, &ctx
);
447 ASSERT_EQ(0, ctx
.wait());
450 TEST_F(TestMockIoObjectRequest
, ParentReadError
) {
451 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
455 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
456 ASSERT_EQ(0, image
.snap_create("one"));
457 ASSERT_EQ(0, image
.snap_protect("one"));
460 std::string clone_name
= get_temp_image_name();
462 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
463 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
465 librbd::ImageCtx
*ictx
;
466 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
467 ictx
->sparse_read_threshold_bytes
= 8096;
468 ictx
->clone_copy_on_read
= false;
470 MockTestImageCtx
mock_image_ctx(*ictx
);
471 mock_image_ctx
.parent
= &mock_image_ctx
;
473 MockObjectMap mock_object_map
;
474 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
475 mock_image_ctx
.object_map
= &mock_object_map
;
479 expect_object_may_exist(mock_image_ctx
, 0, true);
480 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
481 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -ENOENT
);
483 MockUtils mock_utils
;
484 expect_read_parent(mock_utils
, 0, 0, 4096, CEPH_NOSNAP
, -EPERM
);
487 ExtentMap extent_map
;
489 auto req
= MockObjectReadRequest::create(
490 &mock_image_ctx
, 0, 0, 4096, CEPH_NOSNAP
, 0, {}, &bl
, &extent_map
, &ctx
);
492 ASSERT_EQ(-EPERM
, ctx
.wait());
495 TEST_F(TestMockIoObjectRequest
, CopyOnRead
) {
496 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
500 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
501 ASSERT_EQ(0, image
.snap_create("one"));
502 ASSERT_EQ(0, image
.snap_protect("one"));
505 std::string clone_name
= get_temp_image_name();
507 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
508 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
510 librbd::ImageCtx
*ictx
;
511 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
512 ictx
->sparse_read_threshold_bytes
= 8096;
513 ictx
->clone_copy_on_read
= true;
515 MockTestImageCtx
mock_image_ctx(*ictx
);
516 mock_image_ctx
.parent
= &mock_image_ctx
;
518 MockObjectMap mock_object_map
;
519 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
520 mock_image_ctx
.object_map
= &mock_object_map
;
524 expect_object_may_exist(mock_image_ctx
, 0, true);
525 expect_get_read_flags(mock_image_ctx
, CEPH_NOSNAP
, 0);
526 expect_read(mock_image_ctx
, ictx
->get_object_name(0), 0, 4096, "", -ENOENT
);
528 MockUtils mock_utils
;
529 expect_read_parent(mock_utils
, 0, 0, 4096, CEPH_NOSNAP
, 0);
531 MockCopyupRequest mock_copyup_request
;
532 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
533 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
534 expect_copyup(mock_copyup_request
, 0);
537 ExtentMap extent_map
;
539 auto req
= MockObjectReadRequest::create(
540 &mock_image_ctx
, 0, 0, 4096, CEPH_NOSNAP
, 0, {}, &bl
, &extent_map
, &ctx
);
542 ASSERT_EQ(0, ctx
.wait());
545 TEST_F(TestMockIoObjectRequest
, Write
) {
546 librbd::ImageCtx
*ictx
;
547 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
549 MockTestImageCtx
mock_image_ctx(*ictx
);
550 expect_get_object_size(mock_image_ctx
);
552 MockExclusiveLock mock_exclusive_lock
;
553 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
554 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
555 expect_is_lock_owner(mock_exclusive_lock
);
558 MockObjectMap mock_object_map
;
559 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
560 mock_image_ctx
.object_map
= &mock_object_map
;
564 bl
.append(std::string(4096, '1'));
567 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
568 expect_object_may_exist(mock_image_ctx
, 0, true);
569 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
570 expect_write(mock_image_ctx
, 0, 4096, 0);
573 auto req
= MockObjectWriteRequest::create_write(
574 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
576 ASSERT_EQ(0, ctx
.wait());
579 TEST_F(TestMockIoObjectRequest
, WriteFull
) {
580 librbd::ImageCtx
*ictx
;
581 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
583 MockTestImageCtx
mock_image_ctx(*ictx
);
584 expect_get_object_size(mock_image_ctx
);
586 MockExclusiveLock mock_exclusive_lock
;
587 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
588 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
589 expect_is_lock_owner(mock_exclusive_lock
);
592 MockObjectMap mock_object_map
;
593 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
594 mock_image_ctx
.object_map
= &mock_object_map
;
598 bl
.append(std::string(ictx
->get_object_size(), '1'));
601 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
602 expect_object_may_exist(mock_image_ctx
, 0, true);
603 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
604 expect_write_full(mock_image_ctx
, 0);
607 auto req
= MockObjectWriteRequest::create_write(
608 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
610 ASSERT_EQ(0, ctx
.wait());
613 TEST_F(TestMockIoObjectRequest
, WriteObjectMap
) {
614 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
616 librbd::ImageCtx
*ictx
;
617 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
619 MockTestImageCtx
mock_image_ctx(*ictx
);
620 expect_op_work_queue(mock_image_ctx
);
621 expect_get_object_size(mock_image_ctx
);
623 MockExclusiveLock mock_exclusive_lock
;
624 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
625 expect_is_lock_owner(mock_exclusive_lock
);
627 MockObjectMap mock_object_map
;
628 mock_image_ctx
.object_map
= &mock_object_map
;
631 bl
.append(std::string(4096, '1'));
634 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
635 expect_object_may_exist(mock_image_ctx
, 0, true);
636 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, true, 0);
637 expect_write(mock_image_ctx
, 0, 4096, 0);
640 auto req
= MockObjectWriteRequest::create_write(
641 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
643 ASSERT_EQ(0, ctx
.wait());
646 TEST_F(TestMockIoObjectRequest
, WriteError
) {
647 librbd::ImageCtx
*ictx
;
648 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
650 MockTestImageCtx
mock_image_ctx(*ictx
);
651 expect_get_object_size(mock_image_ctx
);
654 bl
.append(std::string(4096, '1'));
657 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
658 expect_write(mock_image_ctx
, 0, 4096, -EPERM
);
661 auto req
= MockObjectWriteRequest::create_write(
662 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
664 ASSERT_EQ(-EPERM
, ctx
.wait());
667 TEST_F(TestMockIoObjectRequest
, Copyup
) {
668 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
672 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
673 ASSERT_EQ(0, image
.snap_create("one"));
674 ASSERT_EQ(0, image
.snap_protect("one"));
677 std::string clone_name
= get_temp_image_name();
679 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
680 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
682 librbd::ImageCtx
*ictx
;
683 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
685 MockTestImageCtx
mock_image_ctx(*ictx
);
686 expect_get_object_size(mock_image_ctx
);
688 MockExclusiveLock mock_exclusive_lock
;
689 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
690 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
691 expect_is_lock_owner(mock_exclusive_lock
);
694 MockObjectMap mock_object_map
;
695 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
696 mock_image_ctx
.object_map
= &mock_object_map
;
700 bl
.append(std::string(4096, '1'));
703 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
704 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
705 expect_object_may_exist(mock_image_ctx
, 0, true);
706 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
707 expect_assert_exists(mock_image_ctx
, -ENOENT
);
709 MockAbstractObjectWriteRequest
*write_request
= nullptr;
710 MockCopyupRequest mock_copyup_request
;
711 expect_copyup(mock_copyup_request
, &write_request
, 0);
714 auto req
= MockObjectWriteRequest::create_write(
715 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
717 ASSERT_EQ(0, ctx
.wait());
720 TEST_F(TestMockIoObjectRequest
, CopyupRestart
) {
721 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
725 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
726 ASSERT_EQ(0, image
.snap_create("one"));
727 ASSERT_EQ(0, image
.snap_protect("one"));
730 std::string clone_name
= get_temp_image_name();
732 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
733 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
735 librbd::ImageCtx
*ictx
;
736 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
738 MockTestImageCtx
mock_image_ctx(*ictx
);
739 expect_get_object_size(mock_image_ctx
);
741 MockExclusiveLock mock_exclusive_lock
;
742 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
743 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
744 expect_is_lock_owner(mock_exclusive_lock
);
747 MockObjectMap mock_object_map
;
748 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
749 mock_image_ctx
.object_map
= &mock_object_map
;
753 bl
.append(std::string(4096, '1'));
756 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
757 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
758 expect_object_may_exist(mock_image_ctx
, 0, true);
759 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
760 expect_assert_exists(mock_image_ctx
, -ENOENT
);
762 MockAbstractObjectWriteRequest
*write_request
= nullptr;
763 MockCopyupRequest mock_copyup_request
;
764 expect_copyup(mock_copyup_request
, &write_request
, -ERESTART
);
765 expect_assert_exists(mock_image_ctx
, 0);
766 expect_write(mock_image_ctx
, 0, 4096, 0);
769 auto req
= MockObjectWriteRequest::create_write(
770 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
772 ASSERT_EQ(0, ctx
.wait());
775 TEST_F(TestMockIoObjectRequest
, CopyupOptimization
) {
776 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_OBJECT_MAP
);
780 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
781 ASSERT_EQ(0, image
.snap_create("one"));
782 ASSERT_EQ(0, image
.snap_protect("one"));
785 std::string clone_name
= get_temp_image_name();
787 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
788 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
790 librbd::ImageCtx
*ictx
;
791 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
793 MockTestImageCtx
mock_image_ctx(*ictx
);
794 expect_get_object_size(mock_image_ctx
);
796 MockExclusiveLock mock_exclusive_lock
;
797 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
798 expect_is_lock_owner(mock_exclusive_lock
);
800 MockObjectMap mock_object_map
;
801 mock_image_ctx
.object_map
= &mock_object_map
;
804 bl
.append(std::string(4096, '1'));
807 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
808 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
809 expect_object_may_exist(mock_image_ctx
, 0, false);
811 MockAbstractObjectWriteRequest
*write_request
= nullptr;
812 MockCopyupRequest mock_copyup_request
;
813 expect_copyup(mock_copyup_request
, &write_request
, 0);
816 auto req
= MockObjectWriteRequest::create_write(
817 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
819 ASSERT_EQ(0, ctx
.wait());
822 TEST_F(TestMockIoObjectRequest
, CopyupError
) {
823 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
827 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
828 ASSERT_EQ(0, image
.snap_create("one"));
829 ASSERT_EQ(0, image
.snap_protect("one"));
832 std::string clone_name
= get_temp_image_name();
834 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
835 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
837 librbd::ImageCtx
*ictx
;
838 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
840 MockTestImageCtx
mock_image_ctx(*ictx
);
841 expect_get_object_size(mock_image_ctx
);
844 bl
.append(std::string(4096, '1'));
847 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
848 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
849 expect_assert_exists(mock_image_ctx
, -ENOENT
);
851 MockAbstractObjectWriteRequest
*write_request
= nullptr;
852 MockCopyupRequest mock_copyup_request
;
853 expect_copyup(mock_copyup_request
, &write_request
, -EPERM
);
856 auto req
= MockObjectWriteRequest::create_write(
857 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
859 ASSERT_EQ(-EPERM
, ctx
.wait());
862 TEST_F(TestMockIoObjectRequest
, DiscardRemove
) {
863 librbd::ImageCtx
*ictx
;
864 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
866 MockTestImageCtx
mock_image_ctx(*ictx
);
867 expect_get_object_size(mock_image_ctx
);
869 MockExclusiveLock mock_exclusive_lock
;
870 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
871 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
872 expect_is_lock_owner(mock_exclusive_lock
);
875 MockObjectMap mock_object_map
;
876 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
877 mock_image_ctx
.object_map
= &mock_object_map
;
881 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
882 expect_object_may_exist(mock_image_ctx
, 0, true);
883 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_PENDING
, {}, false, 0);
884 expect_remove(mock_image_ctx
, 0);
885 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_NONEXISTENT
,
886 OBJECT_PENDING
, false, 0);
889 auto req
= MockObjectDiscardRequest::create_discard(
890 &mock_image_ctx
, 0, 0, mock_image_ctx
.get_object_size(),
891 mock_image_ctx
.snapc
, 0, {}, &ctx
);
893 ASSERT_EQ(0, ctx
.wait());
896 TEST_F(TestMockIoObjectRequest
, DiscardRemoveTruncate
) {
897 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
901 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
902 ASSERT_EQ(0, image
.snap_create("one"));
903 ASSERT_EQ(0, image
.snap_protect("one"));
905 ASSERT_EQ(0, image
.features(&features
));
908 std::string clone_name
= get_temp_image_name();
910 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
911 clone_name
.c_str(), features
, &order
));
913 librbd::ImageCtx
*ictx
;
914 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
916 MockTestImageCtx
mock_image_ctx(*ictx
);
917 expect_get_object_size(mock_image_ctx
);
919 MockExclusiveLock mock_exclusive_lock
;
920 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
921 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
922 expect_is_lock_owner(mock_exclusive_lock
);
925 MockObjectMap mock_object_map
;
926 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
927 mock_image_ctx
.object_map
= &mock_object_map
;
931 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
932 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
933 expect_object_may_exist(mock_image_ctx
, 0, false);
934 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
935 expect_create(mock_image_ctx
, false);
936 expect_truncate(mock_image_ctx
, 0, 0);
939 auto req
= MockObjectDiscardRequest::create_discard(
940 &mock_image_ctx
, 0, 0, mock_image_ctx
.get_object_size(),
941 mock_image_ctx
.snapc
, OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE
, {}, &ctx
);
943 ASSERT_EQ(0, ctx
.wait());
946 TEST_F(TestMockIoObjectRequest
, DiscardTruncateAssertExists
) {
947 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
951 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
952 ASSERT_EQ(0, image
.snap_create("one"));
953 ASSERT_EQ(0, image
.snap_protect("one"));
955 ASSERT_EQ(0, image
.features(&features
));
958 std::string clone_name
= get_temp_image_name();
960 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
961 clone_name
.c_str(), features
, &order
));
962 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, clone_name
.c_str(), NULL
));
963 ASSERT_EQ(0, image
.snap_create("one"));
966 librbd::ImageCtx
*ictx
;
967 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
969 MockTestImageCtx
mock_image_ctx(*ictx
);
970 expect_get_object_size(mock_image_ctx
);
972 MockExclusiveLock mock_exclusive_lock
;
973 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
974 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
975 expect_is_lock_owner(mock_exclusive_lock
);
978 MockObjectMap mock_object_map
;
979 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
980 mock_image_ctx
.object_map
= &mock_object_map
;
984 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
985 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
986 expect_object_may_exist(mock_image_ctx
, 0, true);
987 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
988 expect_assert_exists(mock_image_ctx
, 0);
989 expect_truncate(mock_image_ctx
, 0, 0);
991 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
), create(_
, _
, _
))
995 auto req
= MockObjectDiscardRequest::create_discard(
996 &mock_image_ctx
, 0, 0, mock_image_ctx
.get_object_size(),
997 mock_image_ctx
.snapc
, OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE
, {}, &ctx
);
999 ASSERT_EQ(0, ctx
.wait());
1002 TEST_F(TestMockIoObjectRequest
, DiscardTruncate
) {
1003 librbd::ImageCtx
*ictx
;
1004 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1006 MockTestImageCtx
mock_image_ctx(*ictx
);
1007 expect_get_object_size(mock_image_ctx
);
1009 MockExclusiveLock mock_exclusive_lock
;
1010 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1011 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1012 expect_is_lock_owner(mock_exclusive_lock
);
1015 MockObjectMap mock_object_map
;
1016 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1017 mock_image_ctx
.object_map
= &mock_object_map
;
1021 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1022 expect_object_may_exist(mock_image_ctx
, 0, true);
1023 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1024 expect_truncate(mock_image_ctx
, 1, 0);
1026 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
), create(_
, _
, _
))
1030 auto req
= MockObjectDiscardRequest::create_discard(
1031 &mock_image_ctx
, 0, 1, mock_image_ctx
.get_object_size() - 1,
1032 mock_image_ctx
.snapc
, 0, {}, &ctx
);
1034 ASSERT_EQ(0, ctx
.wait());
1037 TEST_F(TestMockIoObjectRequest
, DiscardZero
) {
1038 librbd::ImageCtx
*ictx
;
1039 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1041 MockTestImageCtx
mock_image_ctx(*ictx
);
1042 expect_get_object_size(mock_image_ctx
);
1044 MockExclusiveLock mock_exclusive_lock
;
1045 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1046 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1047 expect_is_lock_owner(mock_exclusive_lock
);
1050 MockObjectMap mock_object_map
;
1051 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1052 mock_image_ctx
.object_map
= &mock_object_map
;
1056 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1057 expect_object_may_exist(mock_image_ctx
, 0, true);
1058 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1059 expect_zero(mock_image_ctx
, 1, 1, 0);
1062 auto req
= MockObjectDiscardRequest::create_discard(
1063 &mock_image_ctx
, 0, 1, 1, mock_image_ctx
.snapc
, 0, {}, &ctx
);
1065 ASSERT_EQ(0, ctx
.wait());
1068 TEST_F(TestMockIoObjectRequest
, DiscardDisableObjectMapUpdate
) {
1069 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
1071 librbd::ImageCtx
*ictx
;
1072 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1074 MockTestImageCtx
mock_image_ctx(*ictx
);
1075 expect_get_object_size(mock_image_ctx
);
1077 MockExclusiveLock mock_exclusive_lock
;
1078 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1079 expect_is_lock_owner(mock_exclusive_lock
);
1081 MockObjectMap mock_object_map
;
1082 mock_image_ctx
.object_map
= &mock_object_map
;
1085 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1086 expect_object_may_exist(mock_image_ctx
, 0, true);
1087 expect_remove(mock_image_ctx
, 0);
1090 auto req
= MockObjectDiscardRequest::create_discard(
1091 &mock_image_ctx
, 0, 0, mock_image_ctx
.get_object_size(),
1092 mock_image_ctx
.snapc
,
1093 OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE
|
1094 OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE
, {}, &ctx
);
1096 ASSERT_EQ(0, ctx
.wait());
1099 TEST_F(TestMockIoObjectRequest
, DiscardNoOp
) {
1100 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
1102 librbd::ImageCtx
*ictx
;
1103 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1105 MockTestImageCtx
mock_image_ctx(*ictx
);
1106 expect_op_work_queue(mock_image_ctx
);
1107 expect_get_object_size(mock_image_ctx
);
1109 MockExclusiveLock mock_exclusive_lock
;
1110 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1111 expect_is_lock_owner(mock_exclusive_lock
);
1113 MockObjectMap mock_object_map
;
1114 mock_image_ctx
.object_map
= &mock_object_map
;
1117 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1118 expect_object_may_exist(mock_image_ctx
, 0, false);
1121 auto req
= MockObjectDiscardRequest::create_discard(
1122 &mock_image_ctx
, 0, 0, mock_image_ctx
.get_object_size(),
1123 mock_image_ctx
.snapc
,
1124 OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE
|
1125 OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE
, {},
1128 ASSERT_EQ(0, ctx
.wait());
1131 TEST_F(TestMockIoObjectRequest
, WriteSame
) {
1132 librbd::ImageCtx
*ictx
;
1133 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1135 MockTestImageCtx
mock_image_ctx(*ictx
);
1136 expect_get_object_size(mock_image_ctx
);
1138 MockExclusiveLock mock_exclusive_lock
;
1139 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1140 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1141 expect_is_lock_owner(mock_exclusive_lock
);
1144 MockObjectMap mock_object_map
;
1145 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1146 mock_image_ctx
.object_map
= &mock_object_map
;
1150 bl
.append(std::string(4096, '1'));
1153 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1154 expect_object_may_exist(mock_image_ctx
, 0, true);
1155 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1156 expect_writesame(mock_image_ctx
, 0, 4096, 0);
1159 auto req
= MockObjectWriteSameRequest::create_write_same(
1160 &mock_image_ctx
, 0, 0, 4096, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
1162 ASSERT_EQ(0, ctx
.wait());
1165 TEST_F(TestMockIoObjectRequest
, CompareAndWrite
) {
1166 librbd::ImageCtx
*ictx
;
1167 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1169 MockTestImageCtx
mock_image_ctx(*ictx
);
1170 expect_get_object_size(mock_image_ctx
);
1172 MockExclusiveLock mock_exclusive_lock
;
1173 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1174 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1175 expect_is_lock_owner(mock_exclusive_lock
);
1178 MockObjectMap mock_object_map
;
1179 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1180 mock_image_ctx
.object_map
= &mock_object_map
;
1184 cmp_bl
.append_zero(4096);
1187 bl
.append(std::string(4096, '1'));
1190 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1191 expect_object_may_exist(mock_image_ctx
, 0, true);
1192 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1193 expect_cmpext(mock_image_ctx
, 0, 0);
1194 expect_write(mock_image_ctx
, 0, 4096, 0);
1197 uint64_t mismatch_offset
;
1198 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1199 &mock_image_ctx
, 0, 0, std::move(cmp_bl
), std::move(bl
),
1200 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1202 ASSERT_EQ(0, ctx
.wait());
1205 TEST_F(TestMockIoObjectRequest
, CompareAndWriteFull
) {
1206 librbd::ImageCtx
*ictx
;
1207 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1209 MockTestImageCtx
mock_image_ctx(*ictx
);
1210 expect_get_object_size(mock_image_ctx
);
1212 MockExclusiveLock mock_exclusive_lock
;
1213 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1214 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1215 expect_is_lock_owner(mock_exclusive_lock
);
1218 MockObjectMap mock_object_map
;
1219 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1220 mock_image_ctx
.object_map
= &mock_object_map
;
1224 cmp_bl
.append_zero(ictx
->get_object_size());
1227 bl
.append(std::string(ictx
->get_object_size(), '1'));
1230 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1231 expect_object_may_exist(mock_image_ctx
, 0, true);
1232 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1233 expect_cmpext(mock_image_ctx
, 0, 0);
1234 expect_write_full(mock_image_ctx
, 0);
1237 uint64_t mismatch_offset
;
1238 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1239 &mock_image_ctx
, 0, 0, std::move(cmp_bl
), std::move(bl
),
1240 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1242 ASSERT_EQ(0, ctx
.wait());
1245 TEST_F(TestMockIoObjectRequest
, CompareAndWriteCopyup
) {
1246 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1248 librbd::Image image
;
1250 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
1251 ASSERT_EQ(0, image
.snap_create("one"));
1252 ASSERT_EQ(0, image
.snap_protect("one"));
1255 std::string clone_name
= get_temp_image_name();
1257 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
1258 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
1260 librbd::ImageCtx
*ictx
;
1261 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
1263 MockTestImageCtx
mock_image_ctx(*ictx
);
1264 expect_get_object_size(mock_image_ctx
);
1266 MockExclusiveLock mock_exclusive_lock
;
1267 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1268 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1269 expect_is_lock_owner(mock_exclusive_lock
);
1272 MockObjectMap mock_object_map
;
1273 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1274 mock_image_ctx
.object_map
= &mock_object_map
;
1278 cmp_bl
.append_zero(4096);
1281 bl
.append(std::string(4096, '1'));
1284 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 4096, 0);
1285 expect_prune_parent_extents(mock_image_ctx
, {{0, 4096}}, 4096, 4096);
1286 expect_object_may_exist(mock_image_ctx
, 0, true);
1287 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1288 expect_assert_exists(mock_image_ctx
, -ENOENT
);
1290 MockAbstractObjectWriteRequest
*write_request
= nullptr;
1291 MockCopyupRequest mock_copyup_request
;
1292 expect_copyup(mock_copyup_request
, &write_request
, 0);
1294 expect_assert_exists(mock_image_ctx
, 0);
1295 expect_cmpext(mock_image_ctx
, 0, 0);
1296 expect_write(mock_image_ctx
, 0, 4096, 0);
1299 uint64_t mismatch_offset
;
1300 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1301 &mock_image_ctx
, 0, 0, std::move(cmp_bl
), std::move(bl
),
1302 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1304 ASSERT_EQ(0, ctx
.wait());
1307 TEST_F(TestMockIoObjectRequest
, CompareAndWriteMismatch
) {
1308 librbd::ImageCtx
*ictx
;
1309 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1311 MockTestImageCtx
mock_image_ctx(*ictx
);
1312 expect_get_object_size(mock_image_ctx
);
1314 MockExclusiveLock mock_exclusive_lock
;
1315 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
1316 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1317 expect_is_lock_owner(mock_exclusive_lock
);
1320 MockObjectMap mock_object_map
;
1321 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
1322 mock_image_ctx
.object_map
= &mock_object_map
;
1326 cmp_bl
.append_zero(4096);
1329 bl
.append(std::string(4096, '1'));
1332 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1333 expect_object_may_exist(mock_image_ctx
, 0, true);
1334 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, false, 0);
1335 expect_cmpext(mock_image_ctx
, 0, -MAX_ERRNO
- 1);
1338 uint64_t mismatch_offset
;
1339 auto req
= MockObjectWriteSameRequest::create_compare_and_write(
1340 &mock_image_ctx
, 0, 0, std::move(cmp_bl
), std::move(bl
),
1341 mock_image_ctx
.snapc
, &mismatch_offset
, 0, {}, &ctx
);
1343 ASSERT_EQ(-EILSEQ
, ctx
.wait());
1344 ASSERT_EQ(1ULL, mismatch_offset
);
1347 TEST_F(TestMockIoObjectRequest
, ObjectMapError
) {
1348 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
1350 librbd::ImageCtx
*ictx
;
1351 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1353 MockTestImageCtx
mock_image_ctx(*ictx
);
1354 expect_op_work_queue(mock_image_ctx
);
1355 expect_get_object_size(mock_image_ctx
);
1357 MockExclusiveLock mock_exclusive_lock
;
1358 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
1359 expect_is_lock_owner(mock_exclusive_lock
);
1361 MockObjectMap mock_object_map
;
1362 mock_image_ctx
.object_map
= &mock_object_map
;
1365 bl
.append(std::string(4096, '1'));
1368 expect_get_parent_overlap(mock_image_ctx
, CEPH_NOSNAP
, 0, 0);
1369 expect_object_may_exist(mock_image_ctx
, 0, true);
1370 expect_object_map_update(mock_image_ctx
, 0, 1, OBJECT_EXISTS
, {}, true,
1374 auto req
= MockObjectWriteRequest::create_write(
1375 &mock_image_ctx
, 0, 0, std::move(bl
), mock_image_ctx
.snapc
, 0, {}, &ctx
);
1377 ASSERT_EQ(-EBLACKLISTED
, ctx
.wait());
1381 } // namespace librbd