1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "cls/rbd/cls_rbd_types.h"
5 #include "test/librbd/test_fixture.h"
6 #include "test/librbd/test_support.h"
7 #include "include/rbd/librbd.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/ImageWatcher.h"
11 #include "librbd/internal.h"
12 #include "librbd/ObjectMap.h"
13 #include "librbd/Operations.h"
14 #include "librbd/api/DiffIterate.h"
15 #include "librbd/io/AioCompletion.h"
16 #include "librbd/io/ImageRequest.h"
17 #include "librbd/io/ImageRequestWQ.h"
18 #include "osdc/Striper.h"
19 #include <boost/scope_exit.hpp>
20 #include <boost/assign/list_of.hpp>
24 void register_test_internal() {
27 class TestInternal
: public TestFixture
{
32 typedef std::vector
<std::pair
<std::string
, bool> > Snaps
;
34 void TearDown() override
{
36 for (Snaps::iterator iter
= m_snaps
.begin(); iter
!= m_snaps
.end(); ++iter
) {
37 librbd::ImageCtx
*ictx
;
38 EXPECT_EQ(0, open_image(m_image_name
, &ictx
));
41 ictx
->operations
->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
42 iter
->first
.c_str()));
45 ictx
->operations
->snap_remove(cls::rbd::UserSnapshotNamespace(),
46 iter
->first
.c_str()));
49 TestFixture::TearDown();
52 int create_snapshot(const char *snap_name
, bool snap_protect
) {
53 librbd::ImageCtx
*ictx
;
54 int r
= open_image(m_image_name
, &ictx
);
59 r
= snap_create(*ictx
, snap_name
);
64 m_snaps
.push_back(std::make_pair(snap_name
, snap_protect
));
66 r
= ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(), snap_name
);
78 class DummyContext
: public Context
{
80 void finish(int r
) override
{
84 void generate_random_iomap(librbd::Image
&image
, int num_objects
, int object_size
,
85 int max_count
, map
<uint64_t, uint64_t> &iomap
)
87 uint64_t stripe_unit
, stripe_count
;
89 stripe_unit
= image
.get_stripe_unit();
90 stripe_count
= image
.get_stripe_count();
92 while (max_count
-- > 0) {
93 // generate random image offset based on base random object
94 // number and object offset and then map that back to an
95 // object number based on stripe unit and count.
96 uint64_t ono
= rand() % num_objects
;
97 uint64_t offset
= rand() % (object_size
- TEST_IO_SIZE
);
98 uint64_t imageoff
= (ono
* object_size
) + offset
;
100 file_layout_t layout
;
101 layout
.object_size
= object_size
;
102 layout
.stripe_unit
= stripe_unit
;
103 layout
.stripe_count
= stripe_count
;
105 vector
<ObjectExtent
> ex
;
106 Striper::file_to_extents(g_ceph_context
, 1, &layout
, imageoff
, TEST_IO_SIZE
, 0, ex
);
108 // lets not worry if IO spans multiple extents (>1 object). in such
109 // as case we would perform the write multiple times to the same
110 // offset, but we record all objects that would be generated with
111 // this IO. TODO: fix this if such a need is required by your
113 vector
<ObjectExtent
>::iterator it
;
114 map
<uint64_t, uint64_t> curr_iomap
;
115 for (it
= ex
.begin(); it
!= ex
.end(); ++it
) {
116 if (iomap
.find((*it
).objectno
) != iomap
.end()) {
120 curr_iomap
.insert(make_pair((*it
).objectno
, imageoff
));
123 if (it
== ex
.end()) {
124 iomap
.insert(curr_iomap
.begin(), curr_iomap
.end());
129 TEST_F(TestInternal
, OpenByID
) {
132 librbd::ImageCtx
*ictx
;
133 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
134 std::string id
= ictx
->id
;
137 ictx
= new librbd::ImageCtx("", id
, nullptr, m_ioctx
, true);
138 ASSERT_EQ(0, ictx
->state
->open(false));
139 ASSERT_EQ(ictx
->name
, m_image_name
);
143 TEST_F(TestInternal
, IsExclusiveLockOwner
) {
144 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
146 librbd::ImageCtx
*ictx
;
147 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
150 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
151 ASSERT_FALSE(is_owner
);
155 RWLock::WLocker
l(ictx
->owner_lock
);
156 ictx
->exclusive_lock
->try_acquire_lock(&ctx
);
158 ASSERT_EQ(0, ctx
.wait());
159 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
160 ASSERT_TRUE(is_owner
);
163 TEST_F(TestInternal
, ResizeLocksImage
) {
164 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
166 librbd::ImageCtx
*ictx
;
167 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
169 librbd::NoOpProgressContext no_op
;
170 ASSERT_EQ(0, ictx
->operations
->resize(m_image_size
>> 1, true, no_op
));
173 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
174 ASSERT_TRUE(is_owner
);
177 TEST_F(TestInternal
, ResizeFailsToLockImage
) {
178 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
180 librbd::ImageCtx
*ictx
;
181 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
182 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
, "manually locked"));
184 librbd::NoOpProgressContext no_op
;
185 ASSERT_EQ(-EROFS
, ictx
->operations
->resize(m_image_size
>> 1, true, no_op
));
188 TEST_F(TestInternal
, SnapCreateLocksImage
) {
189 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
191 librbd::ImageCtx
*ictx
;
192 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
194 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
195 BOOST_SCOPE_EXIT( (ictx
) ) {
197 ictx
->operations
->snap_remove(cls::rbd::UserSnapshotNamespace(),
199 } BOOST_SCOPE_EXIT_END
;
202 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
203 ASSERT_TRUE(is_owner
);
206 TEST_F(TestInternal
, SnapCreateFailsToLockImage
) {
207 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
209 librbd::ImageCtx
*ictx
;
210 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
211 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
, "manually locked"));
213 ASSERT_EQ(-EROFS
, snap_create(*ictx
, "snap1"));
216 TEST_F(TestInternal
, SnapRollbackLocksImage
) {
217 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
219 ASSERT_EQ(0, create_snapshot("snap1", false));
221 librbd::ImageCtx
*ictx
;
222 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
224 librbd::NoOpProgressContext no_op
;
225 ASSERT_EQ(0, ictx
->operations
->snap_rollback(cls::rbd::UserSnapshotNamespace(),
230 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
231 ASSERT_TRUE(is_owner
);
234 TEST_F(TestInternal
, SnapRollbackFailsToLockImage
) {
235 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
238 ASSERT_EQ(0, create_snapshot("snap1", false));
240 librbd::ImageCtx
*ictx
;
241 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
242 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
, "manually locked"));
244 librbd::NoOpProgressContext no_op
;
246 ictx
->operations
->snap_rollback(cls::rbd::UserSnapshotNamespace(),
251 TEST_F(TestInternal
, SnapSetReleasesLock
) {
252 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
254 ASSERT_EQ(0, create_snapshot("snap1", false));
256 librbd::ImageCtx
*ictx
;
257 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
258 ASSERT_EQ(0, librbd::snap_set(ictx
, cls::rbd::UserSnapshotNamespace(), "snap1"));
261 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
262 ASSERT_FALSE(is_owner
);
265 TEST_F(TestInternal
, FlattenLocksImage
) {
266 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_LAYERING
);
268 ASSERT_EQ(0, create_snapshot("snap1", true));
270 librbd::ImageCtx
*ictx
;
271 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
274 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
276 std::string clone_name
= get_temp_image_name();
277 int order
= ictx
->order
;
278 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
279 clone_name
.c_str(), features
, &order
, 0, 0));
281 librbd::ImageCtx
*ictx2
;
282 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
284 librbd::NoOpProgressContext no_op
;
285 ASSERT_EQ(0, ictx2
->operations
->flatten(no_op
));
288 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx2
, &is_owner
));
289 ASSERT_TRUE(is_owner
);
292 TEST_F(TestInternal
, FlattenFailsToLockImage
) {
293 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_LAYERING
);
295 ASSERT_EQ(0, create_snapshot("snap1", true));
297 librbd::ImageCtx
*ictx
;
298 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
301 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
303 std::string clone_name
= get_temp_image_name();
304 int order
= ictx
->order
;
305 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
306 clone_name
.c_str(), features
, &order
, 0, 0));
308 TestInternal
*parent
= this;
309 librbd::ImageCtx
*ictx2
= NULL
;
310 BOOST_SCOPE_EXIT( (&m_ioctx
) (clone_name
) (parent
) (&ictx2
) ) {
312 parent
->close_image(ictx2
);
313 parent
->unlock_image();
315 librbd::NoOpProgressContext no_op
;
316 ASSERT_EQ(0, librbd::remove(m_ioctx
, clone_name
, "", no_op
));
317 } BOOST_SCOPE_EXIT_END
;
319 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
320 ASSERT_EQ(0, lock_image(*ictx2
, LOCK_EXCLUSIVE
, "manually locked"));
322 librbd::NoOpProgressContext no_op
;
323 ASSERT_EQ(-EROFS
, ictx2
->operations
->flatten(no_op
));
326 TEST_F(TestInternal
, AioWriteRequestsLock
) {
327 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
329 librbd::ImageCtx
*ictx
;
330 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
331 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
, "manually locked"));
333 std::string
buffer(256, '1');
334 Context
*ctx
= new DummyContext();
335 auto c
= librbd::io::AioCompletion::create(ctx
);
340 ictx
->io_work_queue
->aio_write(c
, 0, buffer
.size(), std::move(bl
), 0);
343 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
344 ASSERT_FALSE(is_owner
);
345 ASSERT_FALSE(c
->is_complete());
348 ASSERT_EQ(0, c
->wait_for_complete());
352 TEST_F(TestInternal
, AioDiscardRequestsLock
) {
353 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
355 librbd::ImageCtx
*ictx
;
356 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
357 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
, "manually locked"));
359 Context
*ctx
= new DummyContext();
360 auto c
= librbd::io::AioCompletion::create(ctx
);
362 ictx
->io_work_queue
->aio_discard(c
, 0, 256, false);
365 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx
, &is_owner
));
366 ASSERT_FALSE(is_owner
);
367 ASSERT_FALSE(c
->is_complete());
370 ASSERT_EQ(0, c
->wait_for_complete());
374 TEST_F(TestInternal
, CancelAsyncResize
) {
375 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
377 librbd::ImageCtx
*ictx
;
378 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
382 RWLock::WLocker
l(ictx
->owner_lock
);
383 ictx
->exclusive_lock
->try_acquire_lock(&ctx
);
386 ASSERT_EQ(0, ctx
.wait());
388 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
389 ASSERT_TRUE(ictx
->exclusive_lock
->is_lock_owner());
393 ASSERT_EQ(0, librbd::get_size(ictx
, &size
));
395 uint32_t attempts
= 0;
396 while (attempts
++ < 20 && size
> 0) {
398 librbd::NoOpProgressContext prog_ctx
;
400 size
-= MIN(size
, 1<<18);
402 RWLock::RLocker
l(ictx
->owner_lock
);
403 ictx
->operations
->execute_resize(size
, true, prog_ctx
, &ctx
, 0);
406 // try to interrupt the in-progress resize
407 ictx
->cancel_async_requests();
410 if (r
== -ERESTART
) {
411 std::cout
<< "detected canceled async request" << std::endl
;
418 TEST_F(TestInternal
, MultipleResize
) {
419 librbd::ImageCtx
*ictx
;
420 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
422 if (ictx
->exclusive_lock
!= nullptr) {
425 RWLock::WLocker
l(ictx
->owner_lock
);
426 ictx
->exclusive_lock
->try_acquire_lock(&ctx
);
429 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
430 ASSERT_EQ(0, ctx
.wait());
431 ASSERT_TRUE(ictx
->exclusive_lock
->is_lock_owner());
435 ASSERT_EQ(0, librbd::get_size(ictx
, &size
));
436 uint64_t original_size
= size
;
438 std::vector
<C_SaferCond
*> contexts
;
440 uint32_t attempts
= 0;
441 librbd::NoOpProgressContext prog_ctx
;
443 uint64_t new_size
= original_size
;
444 if (attempts
++ % 2 == 0) {
445 size
-= MIN(size
, 1<<18);
449 RWLock::RLocker
l(ictx
->owner_lock
);
450 contexts
.push_back(new C_SaferCond());
451 ictx
->operations
->execute_resize(new_size
, true, prog_ctx
, contexts
.back(), 0);
454 for (uint32_t i
= 0; i
< contexts
.size(); ++i
) {
455 ASSERT_EQ(0, contexts
[i
]->wait());
459 ASSERT_EQ(0, librbd::get_size(ictx
, &size
));
463 TEST_F(TestInternal
, Metadata
) {
464 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
466 map
<string
, bool> test_confs
= boost::assign::map_list_of(
468 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", false)(
469 "cccccccccccccc", false);
470 map
<string
, bool>::iterator it
= test_confs
.begin();
472 librbd::ImageCtx
*ictx
;
473 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
475 r
= ictx
->operations
->metadata_set(it
->first
, "value1");
478 r
= ictx
->operations
->metadata_set(it
->first
, "value2");
481 r
= ictx
->operations
->metadata_set(it
->first
, "value3");
483 r
= ictx
->operations
->metadata_set("abcd", "value4");
485 r
= ictx
->operations
->metadata_set("xyz", "value5");
487 map
<string
, bufferlist
> pairs
;
488 r
= librbd::metadata_list(ictx
, "", 0, &pairs
);
490 ASSERT_EQ(5u, pairs
.size());
491 r
= ictx
->operations
->metadata_remove("abcd");
493 r
= ictx
->operations
->metadata_remove("xyz");
496 r
= librbd::metadata_list(ictx
, "", 0, &pairs
);
498 ASSERT_EQ(3u, pairs
.size());
500 r
= librbd::metadata_get(ictx
, it
->first
, &val
);
502 ASSERT_STREQ(val
.c_str(), "value3");
505 TEST_F(TestInternal
, MetadataFilter
) {
506 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
508 map
<string
, bool> test_confs
= boost::assign::map_list_of(
510 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", false)(
511 "cccccccccccccc", false);
512 map
<string
, bool>::iterator it
= test_confs
.begin();
513 const string prefix
= "test_config_";
515 librbd::ImageCtx
*ictx
;
516 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
518 librbd::Image image1
;
519 map
<string
, bufferlist
> pairs
, res
;
520 pairs
["abc"].append("value");
521 pairs
["abcabc"].append("value");
522 pairs
[prefix
+it
->first
].append("value1");
524 pairs
[prefix
+it
->first
].append("value2");
526 pairs
[prefix
+it
->first
].append("value3");
527 pairs
[prefix
+"asdfsdaf"].append("value6");
528 pairs
[prefix
+"zxvzxcv123"].append("value5");
530 is_continue
= ictx
->_filter_metadata_confs(prefix
, test_confs
, pairs
, &res
);
531 ASSERT_TRUE(is_continue
);
532 ASSERT_TRUE(res
.size() == 3U);
533 it
= test_confs
.begin();
534 ASSERT_TRUE(res
.count(it
->first
));
535 ASSERT_TRUE(it
->second
);
537 ASSERT_TRUE(res
.count(it
->first
));
538 ASSERT_TRUE(it
->second
);
540 ASSERT_TRUE(res
.count(it
->first
));
541 ASSERT_TRUE(it
->second
);
544 pairs
["zzzzzzzz"].append("value7");
545 is_continue
= ictx
->_filter_metadata_confs(prefix
, test_confs
, pairs
, &res
);
546 ASSERT_FALSE(is_continue
);
547 ASSERT_TRUE(res
.size() == 3U);
550 TEST_F(TestInternal
, SnapshotCopyup
)
552 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
554 librbd::ImageCtx
*ictx
;
555 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
558 bl
.append(std::string(256, '1'));
559 ASSERT_EQ(256, ictx
->io_work_queue
->write(0, bl
.length(), bufferlist
{bl
}, 0));
561 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
563 ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
567 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
569 std::string clone_name
= get_temp_image_name();
570 int order
= ictx
->order
;
571 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
572 clone_name
.c_str(), features
, &order
, 0, 0));
574 librbd::ImageCtx
*ictx2
;
575 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
577 ASSERT_EQ(0, snap_create(*ictx2
, "snap1"));
578 ASSERT_EQ(0, snap_create(*ictx2
, "snap2"));
580 ASSERT_EQ(256, ictx2
->io_work_queue
->write(256, bl
.length(), bufferlist
{bl
},
583 librados::IoCtx snap_ctx
;
584 snap_ctx
.dup(ictx2
->data_ctx
);
585 snap_ctx
.snap_set_read(CEPH_SNAPDIR
);
587 librados::snap_set_t snap_set
;
588 ASSERT_EQ(0, snap_ctx
.list_snaps(ictx2
->get_object_name(0), &snap_set
));
590 std::vector
< std::pair
<uint64_t,uint64_t> > expected_overlap
=
591 boost::assign::list_of(
592 std::make_pair(0, 256))(
593 std::make_pair(512, 2096640));
594 ASSERT_EQ(2U, snap_set
.clones
.size());
595 ASSERT_NE(CEPH_NOSNAP
, snap_set
.clones
[0].cloneid
);
596 ASSERT_EQ(2U, snap_set
.clones
[0].snaps
.size());
597 ASSERT_EQ(expected_overlap
, snap_set
.clones
[0].overlap
);
598 ASSERT_EQ(CEPH_NOSNAP
, snap_set
.clones
[1].cloneid
);
600 bufferptr
read_ptr(256);
602 read_bl
.push_back(read_ptr
);
604 std::list
<std::string
> snaps
= {"snap1", "snap2", ""};
605 librbd::io::ReadResult read_result
{&read_bl
};
606 for (std::list
<std::string
>::iterator it
= snaps
.begin();
607 it
!= snaps
.end(); ++it
) {
608 const char *snap_name
= it
->empty() ? NULL
: it
->c_str();
609 ASSERT_EQ(0, librbd::snap_set(ictx2
,
610 cls::rbd::UserSnapshotNamespace(),
614 ictx2
->io_work_queue
->read(0, 256,
615 librbd::io::ReadResult
{read_result
},
617 ASSERT_TRUE(bl
.contents_equal(read_bl
));
620 ictx2
->io_work_queue
->read(256, 256,
621 librbd::io::ReadResult
{read_result
},
623 if (snap_name
== NULL
) {
624 ASSERT_TRUE(bl
.contents_equal(read_bl
));
626 ASSERT_TRUE(read_bl
.is_zero());
629 // verify the object map was properly updated
630 if ((ictx2
->features
& RBD_FEATURE_OBJECT_MAP
) != 0) {
631 uint8_t state
= OBJECT_EXISTS
;
632 if ((ictx2
->features
& RBD_FEATURE_FAST_DIFF
) != 0 &&
633 it
!= snaps
.begin() && snap_name
!= NULL
) {
634 state
= OBJECT_EXISTS_CLEAN
;
637 librbd::ObjectMap
<> object_map(*ictx2
, ictx2
->snap_id
);
639 object_map
.open(&ctx
);
640 ASSERT_EQ(0, ctx
.wait());
642 RWLock::WLocker
object_map_locker(ictx2
->object_map_lock
);
643 ASSERT_EQ(state
, object_map
[0]);
648 TEST_F(TestInternal
, ResizeCopyup
)
650 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
652 m_image_name
= get_temp_image_name();
653 m_image_size
= 1 << 14;
655 uint64_t features
= 0;
656 get_features(&features
);
658 ASSERT_EQ(0, m_rbd
.create2(m_ioctx
, m_image_name
.c_str(), m_image_size
,
661 librbd::ImageCtx
*ictx
;
662 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
665 bl
.append(std::string(4096, '1'));
666 for (size_t i
= 0; i
< m_image_size
; i
+= bl
.length()) {
667 ASSERT_EQ((ssize_t
)bl
.length(),
668 ictx
->io_work_queue
->write(i
, bl
.length(),
672 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
674 ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
677 std::string clone_name
= get_temp_image_name();
678 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
679 clone_name
.c_str(), features
, &order
, 0, 0));
681 librbd::ImageCtx
*ictx2
;
682 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
683 ASSERT_EQ(0, snap_create(*ictx2
, "snap1"));
685 bufferptr
read_ptr(bl
.length());
687 read_bl
.push_back(read_ptr
);
689 // verify full / partial object removal properly copyup
690 librbd::NoOpProgressContext no_op
;
691 ASSERT_EQ(0, ictx2
->operations
->resize(m_image_size
- (1 << order
) - 32,
693 ASSERT_EQ(0, ictx2
->operations
->resize(m_image_size
- (2 << order
) - 32,
695 ASSERT_EQ(0, librbd::snap_set(ictx2
,
696 cls::rbd::UserSnapshotNamespace(),
700 // hide the parent from the snapshot
701 RWLock::WLocker
snap_locker(ictx2
->snap_lock
);
702 ictx2
->snap_info
.begin()->second
.parent
= librbd::ParentInfo();
705 librbd::io::ReadResult read_result
{&read_bl
};
706 for (size_t i
= 2 << order
; i
< m_image_size
; i
+= bl
.length()) {
707 ASSERT_EQ((ssize_t
)bl
.length(),
708 ictx2
->io_work_queue
->read(i
, bl
.length(),
709 librbd::io::ReadResult
{read_result
},
711 ASSERT_TRUE(bl
.contents_equal(read_bl
));
715 TEST_F(TestInternal
, DiscardCopyup
)
717 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
719 CephContext
* cct
= reinterpret_cast<CephContext
*>(_rados
.cct());
720 REQUIRE(!cct
->_conf
->rbd_skip_partial_discard
);
722 m_image_name
= get_temp_image_name();
723 m_image_size
= 1 << 14;
725 uint64_t features
= 0;
726 get_features(&features
);
728 ASSERT_EQ(0, m_rbd
.create2(m_ioctx
, m_image_name
.c_str(), m_image_size
,
731 librbd::ImageCtx
*ictx
;
732 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
735 bl
.append(std::string(4096, '1'));
736 for (size_t i
= 0; i
< m_image_size
; i
+= bl
.length()) {
737 ASSERT_EQ((ssize_t
)bl
.length(),
738 ictx
->io_work_queue
->write(i
, bl
.length(),
742 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
744 ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
747 std::string clone_name
= get_temp_image_name();
748 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
749 clone_name
.c_str(), features
, &order
, 0, 0));
751 librbd::ImageCtx
*ictx2
;
752 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
754 ASSERT_EQ(0, snap_create(*ictx2
, "snap1"));
756 bufferptr
read_ptr(bl
.length());
758 read_bl
.push_back(read_ptr
);
760 ASSERT_EQ(static_cast<int>(m_image_size
- 64),
761 ictx2
->io_work_queue
->discard(32, m_image_size
- 64, false));
762 ASSERT_EQ(0, librbd::snap_set(ictx2
,
763 cls::rbd::UserSnapshotNamespace(),
767 // hide the parent from the snapshot
768 RWLock::WLocker
snap_locker(ictx2
->snap_lock
);
769 ictx2
->snap_info
.begin()->second
.parent
= librbd::ParentInfo();
772 librbd::io::ReadResult read_result
{&read_bl
};
773 for (size_t i
= 0; i
< m_image_size
; i
+= bl
.length()) {
774 ASSERT_EQ((ssize_t
)bl
.length(),
775 ictx2
->io_work_queue
->read(i
, bl
.length(),
776 librbd::io::ReadResult
{read_result
},
778 ASSERT_TRUE(bl
.contents_equal(read_bl
));
782 TEST_F(TestInternal
, ShrinkFlushesCache
) {
783 librbd::ImageCtx
*ictx
;
784 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
786 std::string
buffer(4096, '1');
788 // ensure write-path is initialized
790 write_bl
.append(buffer
);
791 ictx
->io_work_queue
->write(0, buffer
.size(), bufferlist
{write_bl
}, 0);
793 C_SaferCond cond_ctx
;
794 auto c
= librbd::io::AioCompletion::create(&cond_ctx
);
796 ictx
->io_work_queue
->aio_write(c
, 0, buffer
.size(), bufferlist
{write_bl
}, 0);
798 librbd::NoOpProgressContext no_op
;
799 ASSERT_EQ(0, ictx
->operations
->resize(m_image_size
>> 1, true, no_op
));
801 ASSERT_TRUE(c
->is_complete());
802 ASSERT_EQ(0, c
->wait_for_complete());
803 ASSERT_EQ(0, cond_ctx
.wait());
807 TEST_F(TestInternal
, ImageOptions
) {
808 rbd_image_options_t opts1
= NULL
, opts2
= NULL
;
809 uint64_t uint64_val1
= 10, uint64_val2
= 0;
810 std::string string_val1
;
812 librbd::image_options_create(&opts1
);
813 ASSERT_NE((rbd_image_options_t
)NULL
, opts1
);
814 ASSERT_TRUE(librbd::image_options_is_empty(opts1
));
816 ASSERT_EQ(-EINVAL
, librbd::image_options_get(opts1
, RBD_IMAGE_OPTION_FEATURES
,
818 ASSERT_EQ(-ENOENT
, librbd::image_options_get(opts1
, RBD_IMAGE_OPTION_FEATURES
,
821 ASSERT_EQ(-EINVAL
, librbd::image_options_set(opts1
, RBD_IMAGE_OPTION_FEATURES
,
824 ASSERT_EQ(0, librbd::image_options_set(opts1
, RBD_IMAGE_OPTION_FEATURES
,
826 ASSERT_FALSE(librbd::image_options_is_empty(opts1
));
827 ASSERT_EQ(0, librbd::image_options_get(opts1
, RBD_IMAGE_OPTION_FEATURES
,
829 ASSERT_EQ(uint64_val1
, uint64_val2
);
831 librbd::image_options_create_ref(&opts2
, opts1
);
832 ASSERT_NE((rbd_image_options_t
)NULL
, opts2
);
833 ASSERT_FALSE(librbd::image_options_is_empty(opts2
));
836 ASSERT_NE(uint64_val1
, uint64_val2
);
837 ASSERT_EQ(0, librbd::image_options_get(opts2
, RBD_IMAGE_OPTION_FEATURES
,
839 ASSERT_EQ(uint64_val1
, uint64_val2
);
842 ASSERT_NE(uint64_val1
, uint64_val2
);
843 ASSERT_EQ(-ENOENT
, librbd::image_options_get(opts1
, RBD_IMAGE_OPTION_ORDER
,
845 ASSERT_EQ(-ENOENT
, librbd::image_options_get(opts2
, RBD_IMAGE_OPTION_ORDER
,
847 ASSERT_EQ(0, librbd::image_options_set(opts2
, RBD_IMAGE_OPTION_ORDER
,
849 ASSERT_EQ(0, librbd::image_options_get(opts1
, RBD_IMAGE_OPTION_ORDER
,
851 ASSERT_EQ(0, librbd::image_options_get(opts2
, RBD_IMAGE_OPTION_ORDER
,
853 ASSERT_EQ(uint64_val1
, uint64_val2
);
855 librbd::image_options_destroy(opts1
);
858 ASSERT_NE(uint64_val1
, uint64_val2
);
859 ASSERT_EQ(0, librbd::image_options_get(opts2
, RBD_IMAGE_OPTION_ORDER
,
861 ASSERT_EQ(uint64_val1
, uint64_val2
);
863 ASSERT_EQ(0, librbd::image_options_unset(opts2
, RBD_IMAGE_OPTION_ORDER
));
864 ASSERT_EQ(-ENOENT
, librbd::image_options_unset(opts2
, RBD_IMAGE_OPTION_ORDER
));
866 librbd::image_options_clear(opts2
);
867 ASSERT_EQ(-ENOENT
, librbd::image_options_get(opts2
, RBD_IMAGE_OPTION_FEATURES
,
869 ASSERT_TRUE(librbd::image_options_is_empty(opts2
));
871 librbd::image_options_destroy(opts2
);
874 TEST_F(TestInternal
, WriteFullCopyup
) {
875 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
877 librbd::ImageCtx
*ictx
;
878 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
880 librbd::NoOpProgressContext no_op
;
881 ASSERT_EQ(0, ictx
->operations
->resize(1 << ictx
->order
, true, no_op
));
884 bl
.append(std::string(1 << ictx
->order
, '1'));
885 ASSERT_EQ((ssize_t
)bl
.length(),
886 ictx
->io_work_queue
->write(0, bl
.length(), bufferlist
{bl
}, 0));
887 ASSERT_EQ(0, librbd::flush(ictx
));
889 ASSERT_EQ(0, create_snapshot("snap1", true));
891 std::string clone_name
= get_temp_image_name();
892 int order
= ictx
->order
;
893 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
894 clone_name
.c_str(), ictx
->features
, &order
, 0, 0));
896 TestInternal
*parent
= this;
897 librbd::ImageCtx
*ictx2
= NULL
;
898 BOOST_SCOPE_EXIT( (&m_ioctx
) (clone_name
) (parent
) (&ictx2
) ) {
900 ictx2
->operations
->snap_remove(cls::rbd::UserSnapshotNamespace(),
902 parent
->close_image(ictx2
);
905 librbd::NoOpProgressContext remove_no_op
;
906 ASSERT_EQ(0, librbd::remove(m_ioctx
, clone_name
, "", remove_no_op
));
907 } BOOST_SCOPE_EXIT_END
;
909 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
910 ASSERT_EQ(0, ictx2
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
913 bufferlist write_full_bl
;
914 write_full_bl
.append(std::string(1 << ictx2
->order
, '2'));
915 ASSERT_EQ((ssize_t
)write_full_bl
.length(),
916 ictx2
->io_work_queue
->write(0, write_full_bl
.length(),
917 bufferlist
{write_full_bl
}, 0));
919 ASSERT_EQ(0, ictx2
->operations
->flatten(no_op
));
921 bufferptr
read_ptr(bl
.length());
923 read_bl
.push_back(read_ptr
);
925 librbd::io::ReadResult read_result
{&read_bl
};
926 ASSERT_EQ((ssize_t
)read_bl
.length(),
927 ictx2
->io_work_queue
->read(0, read_bl
.length(),
928 librbd::io::ReadResult
{read_result
}, 0));
929 ASSERT_TRUE(write_full_bl
.contents_equal(read_bl
));
931 ASSERT_EQ(0, librbd::snap_set(ictx2
,
932 cls::rbd::UserSnapshotNamespace(),
934 ASSERT_EQ((ssize_t
)read_bl
.length(),
935 ictx2
->io_work_queue
->read(0, read_bl
.length(),
936 librbd::io::ReadResult
{read_result
}, 0));
937 ASSERT_TRUE(bl
.contents_equal(read_bl
));
940 TEST_F(TestInternal
, RemoveById
) {
941 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
943 librbd::ImageCtx
*ictx
;
944 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
946 std::string image_id
= ictx
->id
;
949 librbd::NoOpProgressContext remove_no_op
;
950 ASSERT_EQ(0, librbd::remove(m_ioctx
, "", image_id
, remove_no_op
));
953 static int iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
955 interval_set
<uint64_t> *diff
= static_cast<interval_set
<uint64_t> *>(arg
);
956 diff
->insert(off
, len
);
960 TEST_F(TestInternal
, DiffIterateCloneOverwrite
) {
961 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
965 uint64_t size
= 20 << 20;
968 ASSERT_EQ(0, rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
971 bl
.append(std::string(4096, '1'));
972 ASSERT_EQ(4096, image
.write(0, 4096, bl
));
974 interval_set
<uint64_t> one
;
975 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, false, false, iterate_cb
,
977 ASSERT_EQ(0, image
.snap_create("one"));
978 ASSERT_EQ(0, image
.snap_protect("one"));
980 std::string clone_name
= this->get_temp_image_name();
981 ASSERT_EQ(0, rbd
.clone(m_ioctx
, m_image_name
.c_str(), "one", m_ioctx
,
982 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
984 librbd::ImageCtx
*ictx
;
985 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
986 ASSERT_EQ(0, snap_create(*ictx
, "one"));
988 ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
991 // Simulate a client that doesn't support deep flatten (old librbd / krbd)
992 // which will copy up the full object from the parent
993 std::string oid
= ictx
->object_prefix
+ ".0000000000000000";
994 librados::IoCtx io_ctx
;
996 io_ctx
.selfmanaged_snap_set_write_ctx(ictx
->snapc
.seq
, ictx
->snaps
);
997 ASSERT_EQ(0, io_ctx
.write(oid
, bl
, 4096, 4096));
999 interval_set
<uint64_t> diff
;
1000 ASSERT_EQ(0, librbd::snap_set(ictx
, cls::rbd::UserSnapshotNamespace(), "one"));
1001 ASSERT_EQ(0, librbd::api::DiffIterate
<>::diff_iterate(
1002 ictx
, cls::rbd::UserSnapshotNamespace(), nullptr, 0, size
, true, false,
1003 iterate_cb
, (void *)&diff
));
1004 ASSERT_EQ(one
, diff
);
1007 TEST_F(TestInternal
, TestCoR
)
1009 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1011 std::string config_value
;
1012 ASSERT_EQ(0, _rados
.conf_get("rbd_clone_copy_on_read", config_value
));
1013 if (config_value
== "false") {
1014 std::cout
<< "SKIPPING due to disabled rbd_copy_on_read" << std::endl
;
1018 m_image_name
= get_temp_image_name();
1019 m_image_size
= 4 << 20;
1021 int order
= 12; // smallest object size is 4K
1023 ASSERT_TRUE(get_features(&features
));
1025 ASSERT_EQ(0, create_image_full_pp(m_rbd
, m_ioctx
, m_image_name
, m_image_size
,
1026 features
, false, &order
));
1028 librbd::Image image
;
1029 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
1031 librbd::image_info_t info
;
1032 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1034 const int object_num
= info
.size
/ info
.obj_size
;
1035 printf("made parent image \"%s\": %ldK (%d * %" PRIu64
"K)\n", m_image_name
.c_str(),
1036 (unsigned long)m_image_size
, object_num
, info
.obj_size
/1024);
1038 // write something into parent
1039 char test_data
[TEST_IO_SIZE
+ 1];
1040 for (int i
= 0; i
< TEST_IO_SIZE
; ++i
) {
1041 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
1043 test_data
[TEST_IO_SIZE
] = '\0';
1045 // generate a random map which covers every objects with random
1047 map
<uint64_t, uint64_t> write_tracker
;
1048 generate_random_iomap(image
, object_num
, info
.obj_size
, 100, write_tracker
);
1050 printf("generated random write map:\n");
1051 for (map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1052 itr
!= write_tracker
.end(); ++itr
)
1053 printf("\t [%-8ld, %-8ld]\n",
1054 (unsigned long)itr
->first
, (unsigned long)itr
->second
);
1057 bl
.append(test_data
, TEST_IO_SIZE
);
1059 printf("write data based on random map\n");
1060 for (map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1061 itr
!= write_tracker
.end(); ++itr
) {
1062 printf("\twrite object-%-4ld\t\n", (unsigned long)itr
->first
);
1063 ASSERT_EQ(TEST_IO_SIZE
, image
.write(itr
->second
, TEST_IO_SIZE
, bl
));
1067 printf("verify written data by reading\n");
1069 map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1070 printf("\tread object-%-4ld\n", (unsigned long)itr
->first
);
1071 ASSERT_EQ(TEST_IO_SIZE
, image
.read(itr
->second
, TEST_IO_SIZE
, readbl
));
1072 ASSERT_TRUE(readbl
.contents_equal(bl
));
1075 int64_t data_pool_id
= image
.get_data_pool_id();
1076 rados_ioctx_t d_ioctx
;
1077 rados_ioctx_create2(_cluster
, data_pool_id
, &d_ioctx
);
1080 rados_list_ctx_t list_ctx
;
1081 set
<string
> obj_checker
;
1082 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx
, &list_ctx
));
1083 while (rados_nobjects_list_next(list_ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
1084 if (strstr(entry
, info
.block_name_prefix
)) {
1085 const char *block_name_suffix
= entry
+ strlen(info
.block_name_prefix
) + 1;
1086 obj_checker
.insert(block_name_suffix
);
1089 rados_nobjects_list_close(list_ctx
);
1091 std::string snapname
= "snap";
1092 std::string clonename
= get_temp_image_name();
1093 ASSERT_EQ(0, image
.snap_create(snapname
.c_str()));
1094 ASSERT_EQ(0, image
.close());
1095 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), snapname
.c_str()));
1096 ASSERT_EQ(0, image
.snap_protect(snapname
.c_str()));
1097 printf("made snapshot \"%s@parent_snap\" and protect it\n", m_image_name
.c_str());
1099 ASSERT_EQ(0, clone_image_pp(m_rbd
, image
, m_ioctx
, m_image_name
.c_str(), snapname
.c_str(),
1100 m_ioctx
, clonename
.c_str(), features
));
1101 ASSERT_EQ(0, image
.close());
1102 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, image
, clonename
.c_str(), NULL
));
1103 printf("made and opened clone \"%s\"\n", clonename
.c_str());
1105 printf("read from \"child\"\n");
1107 map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1108 printf("\tread object-%-4ld\n", (unsigned long)itr
->first
);
1109 ASSERT_EQ(TEST_IO_SIZE
, image
.read(itr
->second
, TEST_IO_SIZE
, readbl
));
1110 ASSERT_TRUE(readbl
.contents_equal(bl
));
1113 for (map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1114 itr
!= write_tracker
.end(); ++itr
) {
1115 printf("\tread object-%-4ld\n", (unsigned long)itr
->first
);
1116 ASSERT_EQ(TEST_IO_SIZE
, image
.read(itr
->second
, TEST_IO_SIZE
, readbl
));
1117 ASSERT_TRUE(readbl
.contents_equal(bl
));
1120 printf("read again reversely\n");
1121 for (map
<uint64_t, uint64_t>::iterator itr
= --write_tracker
.end();
1122 itr
!= write_tracker
.begin(); --itr
) {
1123 printf("\tread object-%-4ld\n", (unsigned long)itr
->first
);
1124 ASSERT_EQ(TEST_IO_SIZE
, image
.read(itr
->second
, TEST_IO_SIZE
, readbl
));
1125 ASSERT_TRUE(readbl
.contents_equal(bl
));
1128 // close child to flush all copy-on-read
1129 ASSERT_EQ(0, image
.close());
1131 printf("check whether child image has the same set of objects as parent\n");
1132 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, image
, clonename
.c_str(), NULL
));
1133 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1135 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx
, &list_ctx
));
1136 while (rados_nobjects_list_next(list_ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
1137 if (strstr(entry
, info
.block_name_prefix
)) {
1138 const char *block_name_suffix
= entry
+ strlen(info
.block_name_prefix
) + 1;
1139 set
<string
>::iterator it
= obj_checker
.find(block_name_suffix
);
1140 ASSERT_TRUE(it
!= obj_checker
.end());
1141 obj_checker
.erase(it
);
1144 rados_nobjects_list_close(list_ctx
);
1145 ASSERT_TRUE(obj_checker
.empty());
1146 ASSERT_EQ(0, image
.close());
1148 rados_ioctx_destroy(d_ioctx
);
1151 TEST_F(TestInternal
, FlattenNoEmptyObjects
)
1153 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1155 m_image_name
= get_temp_image_name();
1156 m_image_size
= 4 << 20;
1158 int order
= 12; // smallest object size is 4K
1160 ASSERT_TRUE(get_features(&features
));
1162 ASSERT_EQ(0, create_image_full_pp(m_rbd
, m_ioctx
, m_image_name
, m_image_size
,
1163 features
, false, &order
));
1165 librbd::Image image
;
1166 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), NULL
));
1168 librbd::image_info_t info
;
1169 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1171 const int object_num
= info
.size
/ info
.obj_size
;
1172 printf("made parent image \"%s\": %" PRIu64
"K (%d * %" PRIu64
"K)\n",
1173 m_image_name
.c_str(), m_image_size
, object_num
, info
.obj_size
/1024);
1175 // write something into parent
1176 char test_data
[TEST_IO_SIZE
+ 1];
1177 for (int i
= 0; i
< TEST_IO_SIZE
; ++i
) {
1178 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
1180 test_data
[TEST_IO_SIZE
] = '\0';
1182 // generate a random map which covers every objects with random
1184 map
<uint64_t, uint64_t> write_tracker
;
1185 generate_random_iomap(image
, object_num
, info
.obj_size
, 100, write_tracker
);
1187 printf("generated random write map:\n");
1188 for (map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1189 itr
!= write_tracker
.end(); ++itr
)
1190 printf("\t [%-8ld, %-8ld]\n",
1191 (unsigned long)itr
->first
, (unsigned long)itr
->second
);
1194 bl
.append(test_data
, TEST_IO_SIZE
);
1196 printf("write data based on random map\n");
1197 for (map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1198 itr
!= write_tracker
.end(); ++itr
) {
1199 printf("\twrite object-%-4ld\t\n", (unsigned long)itr
->first
);
1200 ASSERT_EQ(TEST_IO_SIZE
, image
.write(itr
->second
, TEST_IO_SIZE
, bl
));
1204 printf("verify written data by reading\n");
1206 map
<uint64_t, uint64_t>::iterator itr
= write_tracker
.begin();
1207 printf("\tread object-%-4ld\n", (unsigned long)itr
->first
);
1208 ASSERT_EQ(TEST_IO_SIZE
, image
.read(itr
->second
, TEST_IO_SIZE
, readbl
));
1209 ASSERT_TRUE(readbl
.contents_equal(bl
));
1212 int64_t data_pool_id
= image
.get_data_pool_id();
1213 rados_ioctx_t d_ioctx
;
1214 rados_ioctx_create2(_cluster
, data_pool_id
, &d_ioctx
);
1217 rados_list_ctx_t list_ctx
;
1218 set
<string
> obj_checker
;
1219 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx
, &list_ctx
));
1220 while (rados_nobjects_list_next(list_ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
1221 if (strstr(entry
, info
.block_name_prefix
)) {
1222 const char *block_name_suffix
= entry
+ strlen(info
.block_name_prefix
) + 1;
1223 obj_checker
.insert(block_name_suffix
);
1226 rados_nobjects_list_close(list_ctx
);
1228 std::string snapname
= "snap";
1229 std::string clonename
= get_temp_image_name();
1230 ASSERT_EQ(0, image
.snap_create(snapname
.c_str()));
1231 ASSERT_EQ(0, image
.close());
1232 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, image
, m_image_name
.c_str(), snapname
.c_str()));
1233 ASSERT_EQ(0, image
.snap_protect(snapname
.c_str()));
1234 printf("made snapshot \"%s@parent_snap\" and protect it\n", m_image_name
.c_str());
1236 ASSERT_EQ(0, clone_image_pp(m_rbd
, image
, m_ioctx
, m_image_name
.c_str(), snapname
.c_str(),
1237 m_ioctx
, clonename
.c_str(), features
));
1238 ASSERT_EQ(0, image
.close());
1240 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, image
, clonename
.c_str(), NULL
));
1241 printf("made and opened clone \"%s\"\n", clonename
.c_str());
1243 printf("flattening clone: \"%s\"\n", clonename
.c_str());
1244 ASSERT_EQ(0, image
.flatten());
1246 printf("check whether child image has the same set of objects as parent\n");
1247 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1249 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx
, &list_ctx
));
1250 while (rados_nobjects_list_next(list_ctx
, &entry
, NULL
, NULL
) != -ENOENT
) {
1251 if (strstr(entry
, info
.block_name_prefix
)) {
1252 const char *block_name_suffix
= entry
+ strlen(info
.block_name_prefix
) + 1;
1253 set
<string
>::iterator it
= obj_checker
.find(block_name_suffix
);
1254 ASSERT_TRUE(it
!= obj_checker
.end());
1255 obj_checker
.erase(it
);
1258 rados_nobjects_list_close(list_ctx
);
1259 ASSERT_TRUE(obj_checker
.empty());
1260 ASSERT_EQ(0, image
.close());
1262 rados_ioctx_destroy(d_ioctx
);