1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License version 2, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "include/int_types.h"
16 #include "include/rados/librados.h"
17 #include "include/rbd_types.h"
18 #include "include/rbd/librbd.h"
19 #include "include/rbd/librbd.hpp"
20 #include "include/event_type.h"
22 #include "gtest/gtest.h"
28 #include <sys/types.h>
34 #include <condition_variable>
42 #include "test/librados/test.h"
43 #include "test/librbd/test_support.h"
44 #include "common/event_socket.h"
45 #include "include/interval_set.h"
46 #include "include/stringify.h"
48 #include <boost/assign/list_of.hpp>
49 #include <boost/scope_exit.hpp>
52 #include <sys/eventfd.h>
57 using std::chrono::seconds
;
59 #define ASSERT_PASSED(x, args...) \
61 bool passed = false; \
63 ASSERT_TRUE(passed); \
66 void register_test_librbd() {
69 static int get_features(bool *old_format
, uint64_t *features
)
71 const char *c
= getenv("RBD_FEATURES");
79 cout
<< "using new format!" << std::endl
;
83 cout
<< "using old format" << std::endl
;
89 static int create_image_full(rados_ioctx_t ioctx
, const char *name
,
90 uint64_t size
, int *order
, int old_format
,
94 // ensure old-format tests actually use the old format
95 int r
= rados_conf_set(rados_ioctx_get_cluster(ioctx
),
96 "rbd_default_format", "1");
100 return rbd_create(ioctx
, name
, size
, order
);
101 } else if ((features
& RBD_FEATURE_STRIPINGV2
) != 0) {
102 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
104 // use a conservative stripe_unit for non default order
105 stripe_unit
= (1ull << (*order
-1));
108 printf("creating image with stripe unit: %" PRIu64
", "
109 "stripe count: %" PRIu64
"\n",
110 stripe_unit
, IMAGE_STRIPE_COUNT
);
111 return rbd_create3(ioctx
, name
, size
, features
, order
,
112 stripe_unit
, IMAGE_STRIPE_COUNT
);
114 return rbd_create2(ioctx
, name
, size
, features
, order
);
118 static int clone_image(rados_ioctx_t p_ioctx
,
119 rbd_image_t p_image
, const char *p_name
,
120 const char *p_snap_name
, rados_ioctx_t c_ioctx
,
121 const char *c_name
, uint64_t features
, int *c_order
)
123 uint64_t stripe_unit
, stripe_count
;
126 r
= rbd_get_stripe_unit(p_image
, &stripe_unit
);
131 r
= rbd_get_stripe_count(p_image
, &stripe_count
);
136 return rbd_clone2(p_ioctx
, p_name
, p_snap_name
, c_ioctx
,
137 c_name
, features
, c_order
, stripe_unit
, stripe_count
);
141 static int create_image(rados_ioctx_t ioctx
, const char *name
,
142 uint64_t size
, int *order
)
147 int r
= get_features(&old_format
, &features
);
150 return create_image_full(ioctx
, name
, size
, order
, old_format
, features
);
153 static int create_image_pp(librbd::RBD
&rbd
,
154 librados::IoCtx
&ioctx
,
156 uint64_t size
, int *order
) {
159 int r
= get_features(&old_format
, &features
);
163 librados::Rados
rados(ioctx
);
164 int r
= rados
.conf_set("rbd_default_format", "1");
168 return rbd
.create(ioctx
, name
, size
, order
);
170 return rbd
.create2(ioctx
, name
, size
, features
, order
);
174 class TestLibRBD
: public ::testing::Test
{
177 TestLibRBD() : m_pool_number() {
180 static void SetUpTestCase() {
181 static bool seeded
= false;
185 cout
<< "seed " << seed
<< std::endl
;
190 _unique_pool_names
.clear();
192 ASSERT_EQ("", connect_cluster(&_cluster
));
193 ASSERT_EQ("", connect_cluster_pp(_rados
));
195 create_optional_data_pool();
198 static void TearDownTestCase() {
199 rados_shutdown(_cluster
);
200 _rados
.wait_for_latest_osdmap();
201 _pool_names
.insert(_pool_names
.end(), _unique_pool_names
.begin(),
202 _unique_pool_names
.end());
203 for (size_t i
= 1; i
< _pool_names
.size(); ++i
) {
204 ASSERT_EQ(0, _rados
.pool_delete(_pool_names
[i
].c_str()));
206 if (!_pool_names
.empty()) {
207 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names
[0], _rados
));
211 void SetUp() override
{
212 ASSERT_NE("", m_pool_name
= create_pool());
215 bool is_skip_partial_discard_enabled() {
217 EXPECT_EQ(0, _rados
.conf_get("rbd_skip_partial_discard", value
));
218 return value
== "true";
221 void validate_object_map(rbd_image_t image
, bool *passed
) {
223 ASSERT_EQ(0, rbd_get_flags(image
, &flags
));
224 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
227 void validate_object_map(librbd::Image
&image
, bool *passed
) {
229 ASSERT_EQ(0, image
.get_flags(&flags
));
230 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
233 std::string
get_temp_image_name() {
235 return "image" + stringify(_image_number
);
238 static void create_optional_data_pool() {
239 bool created
= false;
240 std::string data_pool
;
241 ASSERT_EQ(0, create_image_data_pool(_rados
, data_pool
, &created
));
242 if (!data_pool
.empty()) {
243 printf("using image data pool: %s\n", data_pool
.c_str());
245 _unique_pool_names
.push_back(data_pool
);
250 std::string
create_pool(bool unique
= false) {
251 librados::Rados rados
;
252 std::string pool_name
;
254 pool_name
= get_temp_pool_name("test-librbd-");
255 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
256 _unique_pool_names
.push_back(pool_name
);
257 } else if (m_pool_number
< _pool_names
.size()) {
258 pool_name
= _pool_names
[m_pool_number
];
260 pool_name
= get_temp_pool_name("test-librbd-");
261 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
262 _pool_names
.push_back(pool_name
);
268 static std::vector
<std::string
> _pool_names
;
269 static std::vector
<std::string
> _unique_pool_names
;
270 static rados_t _cluster
;
271 static librados::Rados _rados
;
272 static uint64_t _image_number
;
274 std::string m_pool_name
;
275 uint32_t m_pool_number
;
279 std::vector
<std::string
> TestLibRBD::_pool_names
;
280 std::vector
<std::string
> TestLibRBD::_unique_pool_names
;
281 rados_t
TestLibRBD::_cluster
;
282 librados::Rados
TestLibRBD::_rados
;
283 uint64_t TestLibRBD::_image_number
= 0;
285 TEST_F(TestLibRBD
, CreateAndStat
)
288 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
290 rbd_image_info_t info
;
293 std::string name
= get_temp_image_name();
294 uint64_t size
= 2 << 20;
296 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
297 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
298 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
299 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
300 ASSERT_EQ(info
.size
, size
);
301 ASSERT_EQ(info
.order
, order
);
302 ASSERT_EQ(0, rbd_close(image
));
304 rados_ioctx_destroy(ioctx
);
307 TEST_F(TestLibRBD
, CreateWithSameDataPool
)
312 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
315 std::string name
= get_temp_image_name();
316 uint64_t size
= 2 << 20;
320 ASSERT_EQ(0, get_features(&old_format
, &features
));
321 ASSERT_FALSE(old_format
);
323 rbd_image_options_t image_options
;
324 rbd_image_options_create(&image_options
);
325 BOOST_SCOPE_EXIT( (&image_options
) ) {
326 rbd_image_options_destroy(image_options
);
327 } BOOST_SCOPE_EXIT_END
;
329 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
330 RBD_IMAGE_OPTION_FEATURES
,
332 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
333 RBD_IMAGE_OPTION_DATA_POOL
,
334 m_pool_name
.c_str()));
336 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
337 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
339 ASSERT_EQ(0, rbd_close(image
));
341 rados_ioctx_destroy(ioctx
);
344 TEST_F(TestLibRBD
, CreateAndStatPP
)
346 librados::IoCtx ioctx
;
347 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
351 librbd::image_info_t info
;
354 std::string name
= get_temp_image_name();
355 uint64_t size
= 2 << 20;
357 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
358 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
359 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
360 ASSERT_EQ(info
.size
, size
);
361 ASSERT_EQ(info
.order
, order
);
367 TEST_F(TestLibRBD
, GetId
)
370 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
374 std::string name
= get_temp_image_name();
376 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
377 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
380 if (!is_feature_enabled(0)) {
382 ASSERT_EQ(-EINVAL
, rbd_get_id(image
, id
, sizeof(id
)));
384 ASSERT_EQ(-ERANGE
, rbd_get_id(image
, id
, 0));
385 ASSERT_EQ(0, rbd_get_id(image
, id
, sizeof(id
)));
386 ASSERT_LT(0U, strlen(id
));
389 ASSERT_EQ(0, rbd_close(image
));
390 rados_ioctx_destroy(ioctx
);
393 TEST_F(TestLibRBD
, GetIdPP
)
395 librados::IoCtx ioctx
;
396 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
401 std::string name
= get_temp_image_name();
404 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
405 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
406 if (!is_feature_enabled(0)) {
408 ASSERT_EQ(-EINVAL
, image
.get_id(&id
));
410 ASSERT_EQ(0, image
.get_id(&id
));
411 ASSERT_LT(0U, id
.size());
415 TEST_F(TestLibRBD
, GetBlockNamePrefix
)
418 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
422 std::string name
= get_temp_image_name();
424 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
425 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
428 ASSERT_EQ(-ERANGE
, rbd_get_block_name_prefix(image
, prefix
, 0));
429 ASSERT_EQ(0, rbd_get_block_name_prefix(image
, prefix
, sizeof(prefix
)));
430 ASSERT_LT(0U, strlen(prefix
));
432 ASSERT_EQ(0, rbd_close(image
));
433 rados_ioctx_destroy(ioctx
);
436 TEST_F(TestLibRBD
, GetBlockNamePrefixPP
)
438 librados::IoCtx ioctx
;
439 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
444 std::string name
= get_temp_image_name();
446 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
447 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
448 ASSERT_LT(0U, image
.get_block_name_prefix().size());
451 TEST_F(TestLibRBD
, TestGetCreateTimestamp
)
456 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
460 std::string name
= get_temp_image_name();
462 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
463 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
465 struct timespec timestamp
;
466 ASSERT_EQ(0, rbd_get_create_timestamp(image
, ×tamp
));
467 ASSERT_LT(0, timestamp
.tv_sec
);
469 ASSERT_EQ(0, rbd_close(image
));
471 rados_ioctx_destroy(ioctx
);
474 TEST_F(TestLibRBD
, GetCreateTimestampPP
)
478 librados::IoCtx ioctx
;
479 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
484 std::string name
= get_temp_image_name();
486 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
487 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
489 struct timespec timestamp
;
490 ASSERT_EQ(0, image
.get_create_timestamp(×tamp
));
491 ASSERT_LT(0, timestamp
.tv_sec
);
494 TEST_F(TestLibRBD
, OpenAio
)
497 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
499 rbd_image_info_t info
;
502 std::string name
= get_temp_image_name();
503 uint64_t size
= 2 << 20;
505 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
507 rbd_completion_t open_comp
;
508 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
509 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
510 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
511 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
512 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp
));
513 rbd_aio_release(open_comp
);
515 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
516 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
517 ASSERT_EQ(info
.size
, size
);
518 ASSERT_EQ(info
.order
, order
);
520 rbd_completion_t close_comp
;
521 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &close_comp
));
522 ASSERT_EQ(0, rbd_aio_close(image
, close_comp
));
523 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp
));
524 ASSERT_EQ(1, rbd_aio_is_complete(close_comp
));
525 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp
));
526 rbd_aio_release(close_comp
);
528 rados_ioctx_destroy(ioctx
);
531 TEST_F(TestLibRBD
, OpenAioFail
)
534 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
536 std::string name
= get_temp_image_name();
538 rbd_completion_t open_comp
;
539 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
540 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
541 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
542 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
543 ASSERT_EQ(-ENOENT
, rbd_aio_get_return_value(open_comp
));
544 rbd_aio_release(open_comp
);
546 rados_ioctx_destroy(ioctx
);
549 TEST_F(TestLibRBD
, OpenAioPP
)
551 librados::IoCtx ioctx
;
552 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
555 librbd::image_info_t info
;
558 std::string name
= get_temp_image_name();
559 uint64_t size
= 2 << 20;
561 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
563 librbd::RBD::AioCompletion
*open_comp
=
564 new librbd::RBD::AioCompletion(NULL
, NULL
);
565 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
566 ASSERT_EQ(0, open_comp
->wait_for_complete());
567 ASSERT_EQ(1, open_comp
->is_complete());
568 ASSERT_EQ(0, open_comp
->get_return_value());
569 open_comp
->release();
571 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
572 ASSERT_EQ(info
.size
, size
);
573 ASSERT_EQ(info
.order
, order
);
576 open_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
577 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
578 ASSERT_EQ(0, open_comp
->wait_for_complete());
579 ASSERT_EQ(1, open_comp
->is_complete());
580 ASSERT_EQ(0, open_comp
->get_return_value());
581 open_comp
->release();
584 librbd::RBD::AioCompletion
*close_comp
=
585 new librbd::RBD::AioCompletion(NULL
, NULL
);
586 ASSERT_EQ(0, image
.aio_close(close_comp
));
587 ASSERT_EQ(0, close_comp
->wait_for_complete());
588 ASSERT_EQ(1, close_comp
->is_complete());
589 ASSERT_EQ(0, close_comp
->get_return_value());
590 close_comp
->release();
592 // close closed image
593 close_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
594 ASSERT_EQ(-EINVAL
, image
.aio_close(close_comp
));
595 close_comp
->release();
600 TEST_F(TestLibRBD
, OpenAioFailPP
)
602 librados::IoCtx ioctx
;
603 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
608 std::string name
= get_temp_image_name();
610 librbd::RBD::AioCompletion
*open_comp
=
611 new librbd::RBD::AioCompletion(NULL
, NULL
);
612 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
613 ASSERT_EQ(0, open_comp
->wait_for_complete());
614 ASSERT_EQ(1, open_comp
->is_complete());
615 ASSERT_EQ(-ENOENT
, open_comp
->get_return_value());
616 open_comp
->release();
622 TEST_F(TestLibRBD
, ResizeAndStat
)
625 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
627 rbd_image_info_t info
;
630 std::string name
= get_temp_image_name();
631 uint64_t size
= 2 << 20;
633 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
634 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
636 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
637 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
638 ASSERT_EQ(info
.size
, size
* 4);
640 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
641 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
642 ASSERT_EQ(info
.size
, size
/ 2);
644 // downsizing without allowing shrink should fail
645 // and image size should not change
646 ASSERT_EQ(-EINVAL
, rbd_resize2(image
, size
/ 4, false, NULL
, NULL
));
647 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
648 ASSERT_EQ(info
.size
, size
/ 2);
650 ASSERT_EQ(0, rbd_resize2(image
, size
/ 4, true, NULL
, NULL
));
651 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
652 ASSERT_EQ(info
.size
, size
/ 4);
654 ASSERT_PASSED(validate_object_map
, image
);
655 ASSERT_EQ(0, rbd_close(image
));
657 rados_ioctx_destroy(ioctx
);
660 TEST_F(TestLibRBD
, ResizeAndStatPP
)
662 librados::IoCtx ioctx
;
663 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
667 librbd::image_info_t info
;
670 std::string name
= get_temp_image_name();
671 uint64_t size
= 2 << 20;
673 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
674 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
676 ASSERT_EQ(0, image
.resize(size
* 4));
677 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
678 ASSERT_EQ(info
.size
, size
* 4);
680 ASSERT_EQ(0, image
.resize(size
/ 2));
681 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
682 ASSERT_EQ(info
.size
, size
/ 2);
683 ASSERT_PASSED(validate_object_map
, image
);
689 TEST_F(TestLibRBD
, UpdateWatchAndResize
)
692 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
696 std::string name
= get_temp_image_name();
697 uint64_t size
= 2 << 20;
699 rbd_image_t
&m_image
;
701 condition_variable m_cond
;
703 static void cb(void *arg
) {
704 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
705 watcher
->handle_notify();
707 Watcher(rbd_image_t
&image
) : m_image(image
) {}
708 void handle_notify() {
709 rbd_image_info_t info
;
710 ASSERT_EQ(0, rbd_stat(m_image
, &info
, sizeof(info
)));
711 lock_guard
<mutex
> locker(m_lock
);
715 void wait_for_size(size_t size
) {
716 unique_lock
<mutex
> locker(m_lock
);
717 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
719 return this->m_size
== size
;}));
724 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
725 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
727 ASSERT_EQ(0, rbd_update_watch(image
, &handle
, Watcher::cb
, &watcher
));
729 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
730 watcher
.wait_for_size(size
* 4);
732 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
733 watcher
.wait_for_size(size
/ 2);
735 ASSERT_EQ(0, rbd_update_unwatch(image
, handle
));
737 ASSERT_EQ(0, rbd_close(image
));
738 rados_ioctx_destroy(ioctx
);
741 TEST_F(TestLibRBD
, UpdateWatchAndResizePP
)
743 librados::IoCtx ioctx
;
744 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
750 std::string name
= get_temp_image_name();
751 uint64_t size
= 2 << 20;
752 struct Watcher
: public librbd::UpdateWatchCtx
{
753 Watcher(librbd::Image
&image
) : m_image(image
) {
755 void handle_notify() override
{
756 librbd::image_info_t info
;
757 ASSERT_EQ(0, m_image
.stat(info
, sizeof(info
)));
758 lock_guard
<mutex
> locker(m_lock
);
762 void wait_for_size(size_t size
) {
763 unique_lock
<mutex
> locker(m_lock
);
764 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
766 return this->m_size
== size
;}));
768 librbd::Image
&m_image
;
770 condition_variable m_cond
;
775 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
776 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
778 ASSERT_EQ(0, image
.update_watch(&watcher
, &handle
));
780 ASSERT_EQ(0, image
.resize(size
* 4));
781 watcher
.wait_for_size(size
* 4);
783 ASSERT_EQ(0, image
.resize(size
/ 2));
784 watcher
.wait_for_size(size
/ 2);
786 ASSERT_EQ(0, image
.update_unwatch(handle
));
792 int test_ls(rados_ioctx_t io_ctx
, size_t num_expected
, ...)
795 char *names
, *cur_name
;
797 size_t max_size
= 1024;
799 names
= (char *) malloc(sizeof(char) * 1024);
800 int len
= rbd_list(io_ctx
, names
, &max_size
);
802 std::set
<std::string
> image_names
;
803 for (i
= 0, num_images
= 0, cur_name
= names
; cur_name
< names
+ len
; i
++) {
804 printf("image: %s\n", cur_name
);
805 image_names
.insert(cur_name
);
806 cur_name
+= strlen(cur_name
) + 1;
811 va_start(ap
, num_expected
);
812 for (i
= num_expected
; i
> 0; i
--) {
813 char *expected
= va_arg(ap
, char *);
814 printf("expected = %s\n", expected
);
815 std::set
<std::string
>::iterator it
= image_names
.find(expected
);
816 if (it
!= image_names
.end()) {
817 printf("found %s\n", expected
);
818 image_names
.erase(it
);
819 printf("erased %s\n", expected
);
821 ADD_FAILURE() << "Unable to find image " << expected
;
828 if (!image_names
.empty()) {
829 ADD_FAILURE() << "Unexpected images discovered";
835 TEST_F(TestLibRBD
, TestCreateLsDelete
)
838 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
841 std::string name
= get_temp_image_name();
842 std::string name2
= get_temp_image_name();
843 uint64_t size
= 2 << 20;
845 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
846 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
847 ASSERT_EQ(0, create_image(ioctx
, name2
.c_str(), size
, &order
));
848 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
849 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
850 ASSERT_EQ(1, test_ls(ioctx
, 1, name2
.c_str()));
852 ASSERT_EQ(-ENOENT
, rbd_remove(ioctx
, name
.c_str()));
854 rados_ioctx_destroy(ioctx
);
857 int test_ls_pp(librbd::RBD
& rbd
, librados::IoCtx
& io_ctx
, size_t num_expected
, ...)
862 vector
<string
> names
;
863 r
= rbd
.list(io_ctx
, names
);
867 cout
<< "num images is: " << names
.size() << std::endl
868 << "expected: " << num_expected
<< std::endl
;
869 int num
= names
.size();
871 for (i
= 0; i
< names
.size(); i
++) {
872 cout
<< "image: " << names
[i
] << std::endl
;
875 va_start(ap
, num_expected
);
876 for (i
= num_expected
; i
> 0; i
--) {
877 char *expected
= va_arg(ap
, char *);
878 cout
<< "expected = " << expected
<< std::endl
;
879 vector
<string
>::iterator listed_name
= find(names
.begin(), names
.end(), string(expected
));
880 if (listed_name
== names
.end()) {
881 ADD_FAILURE() << "Unable to find image " << expected
;
885 names
.erase(listed_name
);
889 if (!names
.empty()) {
890 ADD_FAILURE() << "Unexpected images discovered";
896 TEST_F(TestLibRBD
, TestCreateLsDeletePP
)
898 librados::IoCtx ioctx
;
899 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
905 std::string name
= get_temp_image_name();
906 std::string name2
= get_temp_image_name();
907 uint64_t size
= 2 << 20;
909 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
910 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
911 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
912 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
913 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
914 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name2
.c_str()));
921 static int print_progress_percent(uint64_t offset
, uint64_t src_size
,
924 float percent
= ((float)offset
* 100) / src_size
;
925 printf("%3.2f%% done\n", percent
);
929 TEST_F(TestLibRBD
, TestCopy
)
932 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
936 std::string name
= get_temp_image_name();
937 std::string name2
= get_temp_image_name();
938 std::string name3
= get_temp_image_name();
940 uint64_t size
= 2 << 20;
942 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
943 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
944 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
945 ASSERT_EQ(0, rbd_copy(image
, ioctx
, name2
.c_str()));
946 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
947 ASSERT_EQ(0, rbd_copy_with_progress(image
, ioctx
, name3
.c_str(),
948 print_progress_percent
, NULL
));
949 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
951 ASSERT_EQ(0, rbd_close(image
));
952 rados_ioctx_destroy(ioctx
);
955 class PrintProgress
: public librbd::ProgressContext
958 int update_progress(uint64_t offset
, uint64_t src_size
) override
960 float percent
= ((float)offset
* 100) / src_size
;
961 printf("%3.2f%% done\n", percent
);
966 TEST_F(TestLibRBD
, TestCopyPP
)
968 librados::IoCtx ioctx
;
969 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
975 std::string name
= get_temp_image_name();
976 std::string name2
= get_temp_image_name();
977 std::string name3
= get_temp_image_name();
978 uint64_t size
= 2 << 20;
981 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
982 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
983 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
984 ASSERT_EQ(0, image
.copy(ioctx
, name2
.c_str()));
985 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
986 ASSERT_EQ(0, image
.copy_with_progress(ioctx
, name3
.c_str(), pp
));
987 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
994 int test_ls_snaps(rbd_image_t image
, int num_expected
, ...)
996 int num_snaps
, i
, j
, max_size
= 10;
998 rbd_snap_info_t snaps
[max_size
];
999 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1000 printf("num snaps is: %d\nexpected: %d\n", num_snaps
, num_expected
);
1002 for (i
= 0; i
< num_snaps
; i
++) {
1003 printf("snap: %s\n", snaps
[i
].name
);
1006 va_start(ap
, num_expected
);
1007 for (i
= num_expected
; i
> 0; i
--) {
1008 char *expected
= va_arg(ap
, char *);
1009 uint64_t expected_size
= va_arg(ap
, uint64_t);
1011 for (j
= 0; j
< num_snaps
; j
++) {
1012 if (snaps
[j
].name
== NULL
)
1014 if (strcmp(snaps
[j
].name
, expected
) == 0) {
1015 printf("found %s with size %llu\n", snaps
[j
].name
, (unsigned long long) snaps
[j
].size
);
1016 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1017 free((void *) snaps
[j
].name
);
1018 snaps
[j
].name
= NULL
;
1027 for (i
= 0; i
< num_snaps
; i
++) {
1028 EXPECT_EQ((const char *)0, snaps
[i
].name
);
1034 TEST_F(TestLibRBD
, TestCreateLsDeleteSnap
)
1036 rados_ioctx_t ioctx
;
1037 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1041 std::string name
= get_temp_image_name();
1042 uint64_t size
= 2 << 20;
1043 uint64_t size2
= 4 << 20;
1045 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1046 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1048 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1049 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1050 ASSERT_EQ(0, rbd_resize(image
, size2
));
1051 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1052 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1053 ASSERT_EQ(0, rbd_snap_remove(image
, "snap1"));
1054 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1055 ASSERT_EQ(0, rbd_snap_remove(image
, "snap2"));
1056 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1058 ASSERT_EQ(0, rbd_close(image
));
1060 rados_ioctx_destroy(ioctx
);
1063 int test_get_snapshot_timestamp(rbd_image_t image
, uint64_t snap_id
)
1065 struct timespec timestamp
;
1066 EXPECT_EQ(0, rbd_snap_get_timestamp(image
, snap_id
, ×tamp
));
1067 EXPECT_LT(0, timestamp
.tv_sec
);
1071 TEST_F(TestLibRBD
, TestGetSnapShotTimeStamp
)
1073 REQUIRE_FORMAT_V2();
1075 rados_ioctx_t ioctx
;
1076 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1080 std::string name
= get_temp_image_name();
1081 uint64_t size
= 2 << 20;
1082 int num_snaps
, max_size
= 10;
1083 rbd_snap_info_t snaps
[max_size
];
1085 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1086 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1088 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1089 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1090 ASSERT_EQ(1, num_snaps
);
1091 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1092 free((void *)snaps
[0].name
);
1094 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1095 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1096 ASSERT_EQ(2, num_snaps
);
1097 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1098 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[1].id
));
1099 free((void *)snaps
[0].name
);
1100 free((void *)snaps
[1].name
);
1102 ASSERT_EQ(0, rbd_close(image
));
1104 rados_ioctx_destroy(ioctx
);
1108 int test_ls_snaps(librbd::Image
& image
, size_t num_expected
, ...)
1113 vector
<librbd::snap_info_t
> snaps
;
1114 r
= image
.snap_list(snaps
);
1115 EXPECT_TRUE(r
>= 0);
1116 cout
<< "num snaps is: " << snaps
.size() << std::endl
1117 << "expected: " << num_expected
<< std::endl
;
1119 for (i
= 0; i
< snaps
.size(); i
++) {
1120 cout
<< "snap: " << snaps
[i
].name
<< std::endl
;
1123 va_start(ap
, num_expected
);
1124 for (i
= num_expected
; i
> 0; i
--) {
1125 char *expected
= va_arg(ap
, char *);
1126 uint64_t expected_size
= va_arg(ap
, uint64_t);
1128 for (j
= 0; j
< snaps
.size(); j
++) {
1129 if (snaps
[j
].name
== "")
1131 if (strcmp(snaps
[j
].name
.c_str(), expected
) == 0) {
1132 cout
<< "found " << snaps
[j
].name
<< " with size " << snaps
[j
].size
1134 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1144 for (i
= 0; i
< snaps
.size(); i
++) {
1145 EXPECT_EQ("", snaps
[i
].name
);
1148 return snaps
.size();
1151 TEST_F(TestLibRBD
, TestCreateLsDeleteSnapPP
)
1153 librados::IoCtx ioctx
;
1154 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1158 librbd::Image image
;
1160 std::string name
= get_temp_image_name();
1161 uint64_t size
= 2 << 20;
1162 uint64_t size2
= 4 << 20;
1164 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1165 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1168 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1169 ASSERT_FALSE(exists
);
1170 ASSERT_EQ(0, image
.snap_create("snap1"));
1171 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1172 ASSERT_TRUE(exists
);
1173 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1174 ASSERT_EQ(0, image
.resize(size2
));
1175 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1176 ASSERT_FALSE(exists
);
1177 ASSERT_EQ(0, image
.snap_create("snap2"));
1178 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1179 ASSERT_TRUE(exists
);
1180 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1181 ASSERT_EQ(0, image
.snap_remove("snap1"));
1182 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1183 ASSERT_FALSE(exists
);
1184 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1185 ASSERT_EQ(0, image
.snap_remove("snap2"));
1186 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1187 ASSERT_FALSE(exists
);
1188 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1194 TEST_F(TestLibRBD
, TestCreateLsRenameSnapPP
)
1196 librados::IoCtx ioctx
;
1197 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1201 librbd::Image image
;
1203 std::string name
= get_temp_image_name();
1204 uint64_t size
= 2 << 20;
1205 uint64_t size2
= 4 << 20;
1207 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1208 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1211 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1212 ASSERT_FALSE(exists
);
1213 ASSERT_EQ(0, image
.snap_create("snap1"));
1214 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1215 ASSERT_TRUE(exists
);
1216 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1217 ASSERT_EQ(0, image
.resize(size2
));
1218 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1219 ASSERT_FALSE(exists
);
1220 ASSERT_EQ(0, image
.snap_create("snap2"));
1221 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1222 ASSERT_TRUE(exists
);
1223 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1224 ASSERT_EQ(0, image
.snap_rename("snap1","snap1-rename"));
1225 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1-rename", size
, "snap2", size2
));
1226 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1227 ASSERT_FALSE(exists
);
1228 ASSERT_EQ(0, image
.snap_exists2("snap1-rename", &exists
));
1229 ASSERT_TRUE(exists
);
1230 ASSERT_EQ(0, image
.snap_remove("snap1-rename"));
1231 ASSERT_EQ(0, image
.snap_rename("snap2","snap2-rename"));
1232 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2-rename", size2
));
1233 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1234 ASSERT_FALSE(exists
);
1235 ASSERT_EQ(0, image
.snap_exists2("snap2-rename", &exists
));
1236 ASSERT_TRUE(exists
);
1237 ASSERT_EQ(0, image
.snap_remove("snap2-rename"));
1238 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1244 void simple_write_cb(rbd_completion_t cb
, void *arg
)
1246 printf("write completion cb called!\n");
1249 void simple_read_cb(rbd_completion_t cb
, void *arg
)
1251 printf("read completion cb called!\n");
1254 void aio_write_test_data_and_poll(rbd_image_t image
, int fd
, const char *test_data
,
1255 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1257 rbd_completion_t comp
;
1258 uint64_t data
= 0x123;
1259 rbd_aio_create_completion((void*)&data
, (rbd_callback_t
) simple_write_cb
, &comp
);
1260 printf("created completion\n");
1261 printf("started write\n");
1263 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
1265 rbd_aio_write(image
, off
, len
, test_data
, comp
);
1269 pfd
.events
= POLLIN
;
1271 ASSERT_EQ(1, poll(&pfd
, 1, -1));
1272 ASSERT_TRUE(pfd
.revents
& POLLIN
);
1274 rbd_completion_t comps
[1];
1275 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
1277 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
1278 read(fd
, &count
, sizeof(count
)));
1279 int r
= rbd_aio_get_return_value(comps
[0]);
1280 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
1281 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps
[0]) == data
);
1282 printf("return value is: %d\n", r
);
1284 printf("finished write\n");
1285 rbd_aio_release(comps
[0]);
1289 void aio_write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1291 rbd_completion_t comp
;
1292 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1293 printf("created completion\n");
1295 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
1297 rbd_aio_write(image
, off
, len
, test_data
, comp
);
1298 printf("started write\n");
1299 rbd_aio_wait_for_complete(comp
);
1300 int r
= rbd_aio_get_return_value(comp
);
1301 printf("return value is: %d\n", r
);
1303 printf("finished write\n");
1304 rbd_aio_release(comp
);
1308 void write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1312 written
= rbd_write2(image
, off
, len
, test_data
, iohint
);
1314 written
= rbd_write(image
, off
, len
, test_data
);
1315 printf("wrote: %d\n", (int) written
);
1316 ASSERT_EQ(len
, static_cast<size_t>(written
));
1320 void aio_discard_test_data(rbd_image_t image
, uint64_t off
, uint64_t len
, bool *passed
)
1322 rbd_completion_t comp
;
1323 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1324 rbd_aio_discard(image
, off
, len
, comp
);
1325 rbd_aio_wait_for_complete(comp
);
1326 int r
= rbd_aio_get_return_value(comp
);
1328 printf("aio discard: %d~%d = %d\n", (int)off
, (int)len
, (int)r
);
1329 rbd_aio_release(comp
);
1333 void discard_test_data(rbd_image_t image
, uint64_t off
, size_t len
, bool *passed
)
1336 written
= rbd_discard(image
, off
, len
);
1337 printf("discard: %d~%d = %d\n", (int)off
, (int)len
, (int)written
);
1338 ASSERT_EQ(len
, static_cast<size_t>(written
));
1342 void aio_read_test_data_and_poll(rbd_image_t image
, int fd
, const char *expected
,
1343 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1345 rbd_completion_t comp
;
1346 char *result
= (char *)malloc(len
+ 1);
1348 ASSERT_NE(static_cast<char *>(NULL
), result
);
1349 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1350 printf("created completion\n");
1351 printf("started read\n");
1353 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
1355 rbd_aio_read(image
, off
, len
, result
, comp
);
1359 pfd
.events
= POLLIN
;
1361 ASSERT_EQ(1, poll(&pfd
, 1, -1));
1362 ASSERT_TRUE(pfd
.revents
& POLLIN
);
1364 rbd_completion_t comps
[1];
1365 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
1367 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
1368 read(fd
, &count
, sizeof(count
)));
1370 int r
= rbd_aio_get_return_value(comps
[0]);
1371 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
1372 printf("return value is: %d\n", r
);
1373 ASSERT_EQ(len
, static_cast<size_t>(r
));
1374 rbd_aio_release(comps
[0]);
1375 if (memcmp(result
, expected
, len
)) {
1376 printf("read: %s\nexpected: %s\n", result
, expected
);
1377 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1383 void aio_read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1385 rbd_completion_t comp
;
1386 char *result
= (char *)malloc(len
+ 1);
1388 ASSERT_NE(static_cast<char *>(NULL
), result
);
1389 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1390 printf("created completion\n");
1392 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
1394 rbd_aio_read(image
, off
, len
, result
, comp
);
1395 printf("started read\n");
1396 rbd_aio_wait_for_complete(comp
);
1397 int r
= rbd_aio_get_return_value(comp
);
1398 printf("return value is: %d\n", r
);
1399 ASSERT_EQ(len
, static_cast<size_t>(r
));
1400 rbd_aio_release(comp
);
1401 if (memcmp(result
, expected
, len
)) {
1402 printf("read: %s\nexpected: %s\n", result
, expected
);
1403 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1409 void read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1412 char *result
= (char *)malloc(len
+ 1);
1414 ASSERT_NE(static_cast<char *>(NULL
), result
);
1416 read
= rbd_read2(image
, off
, len
, result
, iohint
);
1418 read
= rbd_read(image
, off
, len
, result
);
1419 printf("read: %d\n", (int) read
);
1420 ASSERT_EQ(len
, static_cast<size_t>(read
));
1422 if (memcmp(result
, expected
, len
)) {
1423 printf("read: %s\nexpected: %s\n", result
, expected
);
1424 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1430 void aio_writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
1431 uint64_t data_len
, uint32_t iohint
, bool *passed
)
1433 rbd_completion_t comp
;
1434 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1435 printf("created completion\n");
1437 r
= rbd_aio_writesame(image
, off
, len
, test_data
, data_len
, comp
, iohint
);
1438 printf("started writesame\n");
1439 if (len
% data_len
) {
1440 ASSERT_EQ(-EINVAL
, r
);
1441 printf("expected fail, finished writesame\n");
1442 rbd_aio_release(comp
);
1447 rbd_aio_wait_for_complete(comp
);
1448 r
= rbd_aio_get_return_value(comp
);
1449 printf("return value is: %d\n", r
);
1451 printf("finished writesame\n");
1452 rbd_aio_release(comp
);
1455 printf("to verify the data\n");
1457 char *result
= (char *)malloc(data_len
+ 1);
1458 ASSERT_NE(static_cast<char *>(NULL
), result
);
1459 uint64_t left
= len
;
1461 read
= rbd_read(image
, off
, data_len
, result
);
1462 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
1463 result
[data_len
] = '\0';
1464 if (memcmp(result
, test_data
, data_len
)) {
1465 printf("read: %d ~ %d\n", (int) off
, (int) read
);
1466 printf("read: %s\nexpected: %s\n", result
, test_data
);
1467 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
1472 ASSERT_EQ(0U, left
);
1474 printf("verified\n");
1479 void writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
1480 uint64_t data_len
, uint32_t iohint
, bool *passed
)
1483 written
= rbd_writesame(image
, off
, len
, test_data
, data_len
, iohint
);
1484 if (len
% data_len
) {
1485 ASSERT_EQ(-EINVAL
, written
);
1486 printf("expected fail, finished writesame\n");
1490 ASSERT_EQ(len
, static_cast<size_t>(written
));
1491 printf("wrote: %d\n", (int) written
);
1494 printf("to verify the data\n");
1496 char *result
= (char *)malloc(data_len
+ 1);
1497 ASSERT_NE(static_cast<char *>(NULL
), result
);
1498 uint64_t left
= len
;
1500 read
= rbd_read(image
, off
, data_len
, result
);
1501 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
1502 result
[data_len
] = '\0';
1503 if (memcmp(result
, test_data
, data_len
)) {
1504 printf("read: %d ~ %d\n", (int) off
, (int) read
);
1505 printf("read: %s\nexpected: %s\n", result
, test_data
);
1506 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
1511 ASSERT_EQ(0U, left
);
1513 printf("verified\n");
1518 TEST_F(TestLibRBD
, TestIO
)
1520 rados_ioctx_t ioctx
;
1521 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1523 bool skip_discard
= is_skip_partial_discard_enabled();
1527 std::string name
= get_temp_image_name();
1528 uint64_t size
= 2 << 20;
1530 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1531 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1533 char test_data
[TEST_IO_SIZE
+ 1];
1534 char zero_data
[TEST_IO_SIZE
+ 1];
1537 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
1538 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
1540 test_data
[TEST_IO_SIZE
] = '\0';
1541 memset(zero_data
, 0, sizeof(zero_data
));
1543 for (i
= 0; i
< 5; ++i
)
1544 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1546 for (i
= 5; i
< 10; ++i
)
1547 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1549 for (i
= 0; i
< 5; ++i
)
1550 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1552 for (i
= 5; i
< 10; ++i
)
1553 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1555 // discard 2nd, 4th sections.
1556 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
1557 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
1559 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
1560 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1561 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
1562 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
1563 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1564 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
1565 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
1567 for (i
= 0; i
< 15; ++i
) {
1569 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1570 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1571 } else if (i
% 3 == 1) {
1572 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1573 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1575 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1576 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1579 for (i
= 0; i
< 15; ++i
) {
1581 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1582 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1583 } else if (i
% 3 == 1) {
1584 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1585 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1587 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1588 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1592 rbd_image_info_t info
;
1593 rbd_completion_t comp
;
1594 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1595 // can't read or write starting past end
1596 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
1597 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
1598 // reading through end returns amount up to end
1599 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
1600 // writing through end returns amount up to end
1601 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
1603 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1604 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
1605 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1606 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
1607 rbd_aio_release(comp
);
1609 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1610 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
1611 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1612 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
1613 rbd_aio_release(comp
);
1615 ASSERT_PASSED(validate_object_map
, image
);
1616 ASSERT_EQ(0, rbd_close(image
));
1618 rados_ioctx_destroy(ioctx
);
1621 TEST_F(TestLibRBD
, TestIOWithIOHint
)
1623 rados_ioctx_t ioctx
;
1624 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1626 bool skip_discard
= is_skip_partial_discard_enabled();
1630 std::string name
= get_temp_image_name();
1631 uint64_t size
= 2 << 20;
1633 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1634 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1636 char test_data
[TEST_IO_SIZE
+ 1];
1637 char zero_data
[TEST_IO_SIZE
+ 1];
1640 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
1641 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
1643 test_data
[TEST_IO_SIZE
] = '\0';
1644 memset(zero_data
, 0, sizeof(zero_data
));
1646 for (i
= 0; i
< 5; ++i
)
1647 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
1648 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
1650 for (i
= 5; i
< 10; ++i
)
1651 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
1652 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1654 for (i
= 0; i
< 5; ++i
)
1655 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
,
1656 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
1658 for (i
= 5; i
< 10; ++i
)
1659 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
1660 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1662 // discard 2nd, 4th sections.
1663 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
1664 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
1666 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
,
1667 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
1668 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1669 TEST_IO_SIZE
, TEST_IO_SIZE
,
1670 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
1671 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
,
1672 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
1673 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1674 TEST_IO_SIZE
*3, TEST_IO_SIZE
,
1675 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
1676 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
1678 for (i
= 0; i
< 15; ++i
) {
1680 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
1681 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
1682 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
1683 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
1684 } else if (i
% 3 == 1) {
1685 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
1686 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
1687 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
1688 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
1690 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
1691 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
1692 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
1693 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
1696 for (i
= 0; i
< 15; ++i
) {
1698 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
1699 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1700 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
1701 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1702 } else if (i
% 3 == 1) {
1703 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
1704 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1705 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
1706 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1708 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
1709 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1710 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
1711 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
1715 rbd_image_info_t info
;
1716 rbd_completion_t comp
;
1717 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1718 // can't read or write starting past end
1719 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
1720 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
1721 // reading through end returns amount up to end
1722 ASSERT_EQ(10, rbd_read2(image
, info
.size
- 10, 100, test_data
,
1723 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
));
1724 // writing through end returns amount up to end
1725 ASSERT_EQ(10, rbd_write2(image
, info
.size
- 10, 100, test_data
,
1726 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
1728 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1729 ASSERT_EQ(0, rbd_aio_read2(image
, info
.size
, 1, test_data
, comp
,
1730 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
1731 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1732 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
1733 rbd_aio_release(comp
);
1735 ASSERT_PASSED(validate_object_map
, image
);
1736 ASSERT_EQ(0, rbd_close(image
));
1738 rados_ioctx_destroy(ioctx
);
1741 TEST_F(TestLibRBD
, TestDataPoolIO
)
1743 REQUIRE_FORMAT_V2();
1745 rados_ioctx_t ioctx
;
1746 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1748 std::string data_pool_name
= create_pool(true);
1750 bool skip_discard
= is_skip_partial_discard_enabled();
1753 std::string name
= get_temp_image_name();
1754 uint64_t size
= 2 << 20;
1758 ASSERT_EQ(0, get_features(&old_format
, &features
));
1759 ASSERT_FALSE(old_format
);
1761 rbd_image_options_t image_options
;
1762 rbd_image_options_create(&image_options
);
1763 BOOST_SCOPE_EXIT( (&image_options
) ) {
1764 rbd_image_options_destroy(image_options
);
1765 } BOOST_SCOPE_EXIT_END
;
1767 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
1768 RBD_IMAGE_OPTION_FEATURES
,
1770 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
1771 RBD_IMAGE_OPTION_DATA_POOL
,
1772 data_pool_name
.c_str()));
1774 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
1775 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1776 ASSERT_NE(-1, rbd_get_data_pool_id(image
));
1778 char test_data
[TEST_IO_SIZE
+ 1];
1779 char zero_data
[TEST_IO_SIZE
+ 1];
1782 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
1783 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
1785 test_data
[TEST_IO_SIZE
] = '\0';
1786 memset(zero_data
, 0, sizeof(zero_data
));
1788 for (i
= 0; i
< 5; ++i
)
1789 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1791 for (i
= 5; i
< 10; ++i
)
1792 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1794 for (i
= 0; i
< 5; ++i
)
1795 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1797 for (i
= 5; i
< 10; ++i
)
1798 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1800 // discard 2nd, 4th sections.
1801 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
1802 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
1804 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
1805 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1806 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
1807 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
1808 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1809 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
1810 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
1812 rbd_image_info_t info
;
1813 rbd_completion_t comp
;
1814 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1815 // can't read or write starting past end
1816 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
1817 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
1818 // reading through end returns amount up to end
1819 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
1820 // writing through end returns amount up to end
1821 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
1823 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1824 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
1825 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1826 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
1827 rbd_aio_release(comp
);
1829 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1830 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
1831 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1832 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
1833 rbd_aio_release(comp
);
1835 ASSERT_PASSED(validate_object_map
, image
);
1836 ASSERT_EQ(0, rbd_close(image
));
1838 rados_ioctx_destroy(ioctx
);
1841 TEST_F(TestLibRBD
, TestScatterGatherIO
)
1843 rados_ioctx_t ioctx
;
1844 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1848 std::string name
= get_temp_image_name();
1849 uint64_t size
= 20 << 20;
1851 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1852 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1854 std::string
write_buffer("This is a test");
1855 struct iovec bad_iovs
[] = {
1856 {.iov_base
= NULL
, .iov_len
= static_cast<size_t>(-1)}
1858 struct iovec write_iovs
[] = {
1859 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
1860 {.iov_base
= &write_buffer
[5], .iov_len
= 3},
1861 {.iov_base
= &write_buffer
[8], .iov_len
= 2},
1862 {.iov_base
= &write_buffer
[10], .iov_len
= 4}
1865 rbd_completion_t comp
;
1866 rbd_aio_create_completion(NULL
, NULL
, &comp
);
1867 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, write_iovs
, 0, 0, comp
));
1868 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, bad_iovs
, 1, 0, comp
));
1869 ASSERT_EQ(0, rbd_aio_writev(image
, write_iovs
,
1870 sizeof(write_iovs
) / sizeof(struct iovec
),
1872 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1873 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
1874 rbd_aio_release(comp
);
1876 std::string
read_buffer(write_buffer
.size(), '1');
1877 struct iovec read_iovs
[] = {
1878 {.iov_base
= &read_buffer
[0], .iov_len
= 4},
1879 {.iov_base
= &read_buffer
[8], .iov_len
= 4},
1880 {.iov_base
= &read_buffer
[12], .iov_len
= 2}
1883 rbd_aio_create_completion(NULL
, NULL
, &comp
);
1884 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, read_iovs
, 0, 0, comp
));
1885 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, bad_iovs
, 1, 0, comp
));
1886 ASSERT_EQ(0, rbd_aio_readv(image
, read_iovs
,
1887 sizeof(read_iovs
) / sizeof(struct iovec
),
1889 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1890 ASSERT_EQ(10, rbd_aio_get_return_value(comp
));
1891 rbd_aio_release(comp
);
1892 ASSERT_EQ("This1111 is a ", read_buffer
);
1894 std::string
linear_buffer(write_buffer
.size(), '1');
1895 struct iovec linear_iovs
[] = {
1896 {.iov_base
= &linear_buffer
[4], .iov_len
= 4}
1898 rbd_aio_create_completion(NULL
, NULL
, &comp
);
1899 ASSERT_EQ(0, rbd_aio_readv(image
, linear_iovs
,
1900 sizeof(linear_iovs
) / sizeof(struct iovec
),
1902 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1903 ASSERT_EQ(4, rbd_aio_get_return_value(comp
));
1904 rbd_aio_release(comp
);
1905 ASSERT_EQ("1111This111111", linear_buffer
);
1907 ASSERT_PASSED(validate_object_map
, image
);
1908 ASSERT_EQ(0, rbd_close(image
));
1910 rados_ioctx_destroy(ioctx
);
1913 TEST_F(TestLibRBD
, TestEmptyDiscard
)
1915 rados_ioctx_t ioctx
;
1916 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1920 std::string name
= get_temp_image_name();
1921 uint64_t size
= 20 << 20;
1923 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1924 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1926 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 1*1024*1024);
1927 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 4*1024*1024);
1928 ASSERT_PASSED(aio_discard_test_data
, image
, 3*1024*1024, 1*1024*1024);
1930 ASSERT_PASSED(validate_object_map
, image
);
1931 ASSERT_EQ(0, rbd_close(image
));
1933 rados_ioctx_destroy(ioctx
);
1937 void simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
1939 cout
<< "write completion cb called!" << std::endl
;
1942 void simple_read_cb_pp(librbd::completion_t cb
, void *arg
)
1944 cout
<< "read completion cb called!" << std::endl
;
1947 void aio_write_test_data(librbd::Image
& image
, const char *test_data
,
1948 off_t off
, uint32_t iohint
, bool *passed
)
1950 ceph::bufferlist bl
;
1951 bl
.append(test_data
, strlen(test_data
));
1952 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
1953 printf("created completion\n");
1955 image
.aio_write2(off
, strlen(test_data
), bl
, comp
, iohint
);
1957 image
.aio_write(off
, strlen(test_data
), bl
, comp
);
1958 printf("started write\n");
1959 comp
->wait_for_complete();
1960 int r
= comp
->get_return_value();
1961 printf("return value is: %d\n", r
);
1963 printf("finished write\n");
1968 void aio_discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
1970 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
1971 image
.aio_discard(off
, len
, comp
);
1972 comp
->wait_for_complete();
1973 int r
= comp
->get_return_value();
1979 void write_test_data(librbd::Image
& image
, const char *test_data
, off_t off
, uint32_t iohint
, bool *passed
)
1982 size_t len
= strlen(test_data
);
1983 ceph::bufferlist bl
;
1984 bl
.append(test_data
, len
);
1986 written
= image
.write2(off
, len
, bl
, iohint
);
1988 written
= image
.write(off
, len
, bl
);
1989 printf("wrote: %u\n", (unsigned int) written
);
1990 ASSERT_EQ(bl
.length(), written
);
1994 void discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
1997 written
= image
.discard(off
, len
);
1998 printf("discard: %u~%u\n", (unsigned)off
, (unsigned)len
);
1999 ASSERT_EQ(len
, written
);
2003 void aio_read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2005 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_read_cb_pp
);
2006 ceph::bufferlist bl
;
2007 printf("created completion\n");
2009 image
.aio_read2(off
, expected_len
, bl
, comp
, iohint
);
2011 image
.aio_read(off
, expected_len
, bl
, comp
);
2012 printf("started read\n");
2013 comp
->wait_for_complete();
2014 int r
= comp
->get_return_value();
2015 printf("return value is: %d\n", r
);
2016 ASSERT_EQ(TEST_IO_SIZE
, r
);
2017 ASSERT_EQ(0, memcmp(expected
, bl
.c_str(), TEST_IO_SIZE
));
2018 printf("finished read\n");
2023 void read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2026 size_t len
= expected_len
;
2027 ceph::bufferlist bl
;
2029 read
= image
.read2(off
, len
, bl
, iohint
);
2031 read
= image
.read(off
, len
, bl
);
2032 ASSERT_TRUE(read
>= 0);
2033 std::string
bl_str(bl
.c_str(), read
);
2035 printf("read: %u\n", (unsigned int) read
);
2036 int result
= memcmp(bl_str
.c_str(), expected
, expected_len
);
2038 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), expected
);
2039 ASSERT_EQ(0, result
);
2044 void aio_writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2045 size_t len
, size_t data_len
, uint32_t iohint
, bool *passed
)
2047 ceph::bufferlist bl
;
2048 bl
.append(test_data
, data_len
);
2049 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2050 printf("created completion\n");
2052 r
= image
.aio_writesame(off
, len
, bl
, comp
, iohint
);
2053 printf("started writesame\n");
2054 if (len
% data_len
) {
2055 ASSERT_EQ(-EINVAL
, r
);
2056 printf("expected fail, finished writesame\n");
2062 comp
->wait_for_complete();
2063 r
= comp
->get_return_value();
2064 printf("return value is: %d\n", r
);
2066 printf("finished writesame\n");
2070 printf("to verify the data\n");
2072 uint64_t left
= len
;
2074 ceph::bufferlist bl
;
2075 read
= image
.read(off
, data_len
, bl
);
2076 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2077 std::string
bl_str(bl
.c_str(), read
);
2078 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2080 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2081 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2082 ASSERT_EQ(0, result
);
2087 ASSERT_EQ(0U, left
);
2088 printf("verified\n");
2093 void writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2094 ssize_t len
, size_t data_len
, uint32_t iohint
,
2098 ceph::bufferlist bl
;
2099 bl
.append(test_data
, data_len
);
2100 written
= image
.writesame(off
, len
, bl
, iohint
);
2101 if (len
% data_len
) {
2102 ASSERT_EQ(-EINVAL
, written
);
2103 printf("expected fail, finished writesame\n");
2107 ASSERT_EQ(len
, written
);
2108 printf("wrote: %u\n", (unsigned int) written
);
2112 printf("to verify the data\n");
2114 uint64_t left
= len
;
2116 ceph::bufferlist bl
;
2117 read
= image
.read(off
, data_len
, bl
);
2118 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2119 std::string
bl_str(bl
.c_str(), read
);
2120 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2122 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2123 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2124 ASSERT_EQ(0, result
);
2129 ASSERT_EQ(0U, left
);
2130 printf("verified\n");
2135 TEST_F(TestLibRBD
, TestIOPP
)
2137 librados::IoCtx ioctx
;
2138 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2140 bool skip_discard
= is_skip_partial_discard_enabled();
2144 librbd::Image image
;
2146 std::string name
= get_temp_image_name();
2147 uint64_t size
= 2 << 20;
2149 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2150 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2152 char test_data
[TEST_IO_SIZE
+ 1];
2153 char zero_data
[TEST_IO_SIZE
+ 1];
2156 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2157 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2159 test_data
[TEST_IO_SIZE
] = '\0';
2160 memset(zero_data
, 0, sizeof(zero_data
));
2162 for (i
= 0; i
< 5; ++i
)
2163 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2165 for (i
= 5; i
< 10; ++i
)
2166 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2168 for (i
= 0; i
< 5; ++i
)
2169 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
2171 for (i
= 5; i
< 10; ++i
)
2172 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
2174 // discard 2nd, 4th sections.
2175 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2176 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2178 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
2179 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2180 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
2181 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
2182 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2183 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
2184 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2186 for (i
= 0; i
< 15; ++i
) {
2188 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2189 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2190 } else if (i
% 3 == 1) {
2191 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2192 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2194 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2195 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2198 for (i
= 0; i
< 15; ++i
) {
2200 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2201 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2202 } else if (i
% 3 == 1) {
2203 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2204 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2206 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2207 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2211 ASSERT_PASSED(validate_object_map
, image
);
2217 TEST_F(TestLibRBD
, TestIOPPWithIOHint
)
2219 librados::IoCtx ioctx
;
2220 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2224 librbd::Image image
;
2226 std::string name
= get_temp_image_name();
2227 uint64_t size
= 2 << 20;
2229 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2230 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2232 char test_data
[TEST_IO_SIZE
+ 1];
2233 char zero_data
[TEST_IO_SIZE
+ 1];
2234 test_data
[TEST_IO_SIZE
] = '\0';
2237 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2238 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2240 memset(zero_data
, 0, sizeof(zero_data
));
2242 for (i
= 0; i
< 5; ++i
)
2243 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
,
2244 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2246 for (i
= 5; i
< 10; ++i
)
2247 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
,
2248 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2250 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
),
2251 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_RANDOM
);
2253 for (i
= 5; i
< 10; ++i
)
2254 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
,
2255 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2257 for (i
= 0; i
< 15; ++i
) {
2259 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2260 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2261 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2262 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2263 } else if (i
% 3 == 1) {
2264 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
2265 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2266 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
2267 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2269 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2270 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2271 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2272 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2275 for (i
= 0; i
< 15; ++i
) {
2277 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2278 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2279 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2280 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2281 } else if (i
% 3 == 1) {
2282 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
2283 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2284 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
2285 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2287 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2288 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2289 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2290 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2294 ASSERT_PASSED(validate_object_map
, image
);
2302 TEST_F(TestLibRBD
, TestIOToSnapshot
)
2304 rados_ioctx_t ioctx
;
2305 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2309 std::string name
= get_temp_image_name();
2310 uint64_t isize
= 2 << 20;
2312 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
2313 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2316 rbd_image_t image_at_snap
;
2317 char orig_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
2318 char test_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
2320 for (i
= 0; i
< TEST_IO_TO_SNAP_SIZE
; ++i
)
2321 test_data
[i
] = (char) (i
+ 48);
2322 test_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
2323 orig_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
2325 r
= rbd_read(image
, 0, TEST_IO_TO_SNAP_SIZE
, orig_data
);
2326 ASSERT_EQ(r
, TEST_IO_TO_SNAP_SIZE
);
2328 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2329 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
2330 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
2331 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2333 printf("write test data!\n");
2334 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2335 ASSERT_EQ(0, rbd_snap_create(image
, "written"));
2336 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
2338 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2340 rbd_snap_set(image
, "orig");
2341 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2343 rbd_snap_set(image
, "written");
2344 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2346 rbd_snap_set(image
, "orig");
2348 r
= rbd_write(image
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
2349 printf("write to snapshot returned %d\n", r
);
2351 cout
<< strerror(-r
) << std::endl
;
2353 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2354 rbd_snap_set(image
, "written");
2355 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2357 r
= rbd_snap_rollback(image
, "orig");
2358 ASSERT_EQ(r
, -EROFS
);
2360 r
= rbd_snap_set(image
, NULL
);
2362 r
= rbd_snap_rollback(image
, "orig");
2365 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2369 printf("opening testimg@orig\n");
2370 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_at_snap
, "orig"));
2371 ASSERT_PASSED(read_test_data
, image_at_snap
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2372 r
= rbd_write(image_at_snap
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
2373 printf("write to snapshot returned %d\n", r
);
2375 cout
<< strerror(-r
) << std::endl
;
2376 ASSERT_EQ(0, rbd_close(image_at_snap
));
2378 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
2379 ASSERT_EQ(0, rbd_snap_remove(image
, "written"));
2380 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
2381 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
2382 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2384 ASSERT_PASSED(validate_object_map
, image
);
2385 ASSERT_EQ(0, rbd_close(image
));
2387 rados_ioctx_destroy(ioctx
);
2390 TEST_F(TestLibRBD
, TestClone
)
2392 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2394 rados_ioctx_t ioctx
;
2395 rbd_image_info_t pinfo
, cinfo
;
2396 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2400 rbd_image_t parent
, child
;
2403 ASSERT_EQ(0, get_features(&old_format
, &features
));
2404 ASSERT_FALSE(old_format
);
2406 std::string parent_name
= get_temp_image_name();
2407 std::string child_name
= get_temp_image_name();
2409 // make a parent to clone from
2410 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
2412 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
2413 printf("made parent image \"parent\"\n");
2415 char *data
= (char *)"testdata";
2416 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
2418 // can't clone a non-snapshot, expect failure
2419 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
2420 child_name
.c_str(), features
, &order
));
2422 // verify that there is no parent info on "parent"
2423 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
2424 printf("parent has no parent info\n");
2426 // create a snapshot, reopen as the parent we're interested in
2427 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
2428 printf("made snapshot \"parent@parent_snap\"\n");
2429 ASSERT_EQ(0, rbd_close(parent
));
2430 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
2432 ASSERT_EQ(-EINVAL
, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
2433 ioctx
, child_name
.c_str(), features
, &order
));
2435 // unprotected image should fail unprotect
2436 ASSERT_EQ(-EINVAL
, rbd_snap_unprotect(parent
, "parent_snap"));
2437 printf("can't unprotect an unprotected snap\n");
2439 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
2440 // protecting again should fail
2441 ASSERT_EQ(-EBUSY
, rbd_snap_protect(parent
, "parent_snap"));
2442 printf("can't protect a protected snap\n");
2444 // This clone and open should work
2445 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
2446 ioctx
, child_name
.c_str(), features
, &order
));
2447 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
2448 printf("made and opened clone \"child\"\n");
2451 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
2454 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(child
, 20, strlen(data
), data
));
2455 ASSERT_PASSED(read_test_data
, child
, data
, 20, strlen(data
), 0);
2456 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
2459 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
2460 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
2461 EXPECT_EQ(cinfo
.size
, pinfo
.size
);
2463 rbd_get_overlap(child
, &overlap
);
2464 EXPECT_EQ(overlap
, pinfo
.size
);
2465 EXPECT_EQ(cinfo
.obj_size
, pinfo
.obj_size
);
2466 EXPECT_EQ(cinfo
.order
, pinfo
.order
);
2467 printf("sizes and overlaps are good between parent and child\n");
2469 // sizing down child results in changing overlap and size, not parent size
2470 ASSERT_EQ(0, rbd_resize(child
, 2UL<<20));
2471 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
2472 rbd_get_overlap(child
, &overlap
);
2473 ASSERT_EQ(overlap
, 2UL<<20);
2474 ASSERT_EQ(cinfo
.size
, 2UL<<20);
2475 ASSERT_EQ(0, rbd_resize(child
, 4UL<<20));
2476 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
2477 rbd_get_overlap(child
, &overlap
);
2478 ASSERT_EQ(overlap
, 2UL<<20);
2479 ASSERT_EQ(cinfo
.size
, 4UL<<20);
2480 printf("sized down clone, changed overlap\n");
2482 // sizing back up doesn't change that
2483 ASSERT_EQ(0, rbd_resize(child
, 5UL<<20));
2484 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
2485 rbd_get_overlap(child
, &overlap
);
2486 ASSERT_EQ(overlap
, 2UL<<20);
2487 ASSERT_EQ(cinfo
.size
, 5UL<<20);
2488 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
2489 printf("parent info: size %lld obj_size %lld parent_pool %lld\n",
2490 (unsigned long long)pinfo
.size
, (unsigned long long)pinfo
.obj_size
,
2491 (unsigned long long)pinfo
.parent_pool
);
2492 ASSERT_EQ(pinfo
.size
, 4UL<<20);
2493 printf("sized up clone, changed size but not overlap or parent's size\n");
2495 ASSERT_PASSED(validate_object_map
, child
);
2496 ASSERT_EQ(0, rbd_close(child
));
2498 ASSERT_PASSED(validate_object_map
, parent
);
2499 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
2500 printf("can't remove parent while child still exists\n");
2501 ASSERT_EQ(0, rbd_remove(ioctx
, child_name
.c_str()));
2502 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
2503 printf("can't remove parent while still protected\n");
2504 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
2505 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
2506 printf("removed parent snap after unprotecting\n");
2508 ASSERT_EQ(0, rbd_close(parent
));
2509 rados_ioctx_destroy(ioctx
);
2512 TEST_F(TestLibRBD
, TestClone2
)
2514 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2516 rados_ioctx_t ioctx
;
2517 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2521 rbd_image_t parent
, child
;
2524 ASSERT_EQ(0, get_features(&old_format
, &features
));
2525 ASSERT_FALSE(old_format
);
2527 std::string parent_name
= get_temp_image_name();
2528 std::string child_name
= get_temp_image_name();
2530 // make a parent to clone from
2531 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
2533 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
2534 printf("made parent image \"parent\"\n");
2536 char *data
= (char *)"testdata";
2537 char *childata
= (char *)"childata";
2538 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
2539 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
2541 // can't clone a non-snapshot, expect failure
2542 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
2543 child_name
.c_str(), features
, &order
));
2545 // verify that there is no parent info on "parent"
2546 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
2547 printf("parent has no parent info\n");
2549 // create a snapshot, reopen as the parent we're interested in
2550 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
2551 printf("made snapshot \"parent@parent_snap\"\n");
2552 ASSERT_EQ(0, rbd_close(parent
));
2553 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
2555 ASSERT_EQ(-EINVAL
, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
2556 ioctx
, child_name
.c_str(), features
, &order
));
2558 // unprotected image should fail unprotect
2559 ASSERT_EQ(-EINVAL
, rbd_snap_unprotect(parent
, "parent_snap"));
2560 printf("can't unprotect an unprotected snap\n");
2562 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
2563 // protecting again should fail
2564 ASSERT_EQ(-EBUSY
, rbd_snap_protect(parent
, "parent_snap"));
2565 printf("can't protect a protected snap\n");
2567 // This clone and open should work
2568 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
2569 ioctx
, child_name
.c_str(), features
, &order
));
2570 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
2571 printf("made and opened clone \"child\"\n");
2573 // write something in
2574 ASSERT_EQ((ssize_t
)strlen(childata
), rbd_write(child
, 20, strlen(childata
), childata
));
2576 char test
[strlen(data
) * 2];
2577 ASSERT_EQ((ssize_t
)strlen(data
), rbd_read(child
, 20, strlen(data
), test
));
2578 ASSERT_EQ(0, memcmp(test
, childata
, strlen(childata
)));
2581 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 20 - strlen(data
), sizeof(test
), test
));
2582 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
2583 ASSERT_EQ(0, memcmp(test
+ strlen(data
), childata
, strlen(childata
)));
2586 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 0, sizeof(test
), test
));
2587 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
2589 ASSERT_PASSED(validate_object_map
, child
);
2590 ASSERT_PASSED(validate_object_map
, parent
);
2592 ASSERT_EQ(0, rbd_close(child
));
2593 ASSERT_EQ(0, rbd_close(parent
));
2594 rados_ioctx_destroy(ioctx
);
2597 static void test_list_children(rbd_image_t image
, ssize_t num_expected
, ...)
2600 va_start(ap
, num_expected
);
2601 size_t pools_len
= 100;
2602 size_t children_len
= 100;
2604 char *children
= NULL
;
2605 ssize_t num_children
;
2610 pools
= (char *) malloc(pools_len
);
2611 children
= (char *) malloc(children_len
);
2612 num_children
= rbd_list_children(image
, pools
, &pools_len
,
2613 children
, &children_len
);
2614 } while (num_children
== -ERANGE
);
2616 ASSERT_EQ(num_expected
, num_children
);
2617 for (ssize_t i
= num_expected
; i
> 0; --i
) {
2618 char *expected_pool
= va_arg(ap
, char *);
2619 char *expected_image
= va_arg(ap
, char *);
2621 char *image
= children
;
2623 printf("\ntrying to find %s/%s\n", expected_pool
, expected_image
);
2624 for (ssize_t j
= 0; j
< num_children
; ++j
) {
2625 printf("checking %s/%s\n", pool
, image
);
2626 if (strcmp(expected_pool
, pool
) == 0 &&
2627 strcmp(expected_image
, image
) == 0) {
2628 printf("found child %s/%s\n\n", pool
, image
);
2632 pool
+= strlen(pool
) + 1;
2633 image
+= strlen(image
) + 1;
2634 if (j
== num_children
- 1) {
2635 ASSERT_EQ(pool
- pools
- 1, (ssize_t
) pools_len
);
2636 ASSERT_EQ(image
- children
- 1, (ssize_t
) children_len
);
2649 TEST_F(TestLibRBD
, ListChildren
)
2651 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2653 rados_ioctx_t ioctx1
, ioctx2
;
2654 string pool_name1
= create_pool(true);
2655 string pool_name2
= create_pool(true);
2656 ASSERT_NE("", pool_name2
);
2658 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
2659 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
2666 ASSERT_EQ(0, get_features(&old_format
, &features
));
2667 ASSERT_FALSE(old_format
);
2669 std::string parent_name
= get_temp_image_name();
2670 std::string child_name1
= get_temp_image_name();
2671 std::string child_name2
= get_temp_image_name();
2672 std::string child_name3
= get_temp_image_name();
2673 std::string child_name4
= get_temp_image_name();
2675 // make a parent to clone from
2676 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
2678 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
2679 // create a snapshot, reopen as the parent we're interested in
2680 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
2681 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
2682 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
2684 ASSERT_EQ(0, rbd_close(parent
));
2685 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
2687 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2688 ioctx2
, child_name1
.c_str(), features
, &order
));
2689 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
2691 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2692 ioctx1
, child_name2
.c_str(), features
, &order
));
2693 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
2694 pool_name1
.c_str(), child_name2
.c_str());
2696 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2697 ioctx2
, child_name3
.c_str(), features
, &order
));
2698 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
2699 pool_name1
.c_str(), child_name2
.c_str(),
2700 pool_name2
.c_str(), child_name3
.c_str());
2702 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2703 ioctx2
, child_name4
.c_str(), features
, &order
));
2704 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
2705 pool_name1
.c_str(), child_name2
.c_str(),
2706 pool_name2
.c_str(), child_name3
.c_str(),
2707 pool_name2
.c_str(), child_name4
.c_str());
2709 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
2710 test_list_children(parent
, 3,
2711 pool_name1
.c_str(), child_name2
.c_str(),
2712 pool_name2
.c_str(), child_name3
.c_str(),
2713 pool_name2
.c_str(), child_name4
.c_str());
2715 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
2716 test_list_children(parent
, 2,
2717 pool_name1
.c_str(), child_name2
.c_str(),
2718 pool_name2
.c_str(), child_name4
.c_str());
2720 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
2721 test_list_children(parent
, 1,
2722 pool_name1
.c_str(), child_name2
.c_str());
2724 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
2725 test_list_children(parent
, 0);
2727 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
2728 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
2729 ASSERT_EQ(0, rbd_close(parent
));
2730 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
2731 rados_ioctx_destroy(ioctx1
);
2732 rados_ioctx_destroy(ioctx2
);
2735 TEST_F(TestLibRBD
, ListChildrenTiered
)
2737 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2739 string pool_name1
= m_pool_name
;
2740 string pool_name2
= create_pool(true);
2741 string pool_name3
= create_pool(true);
2742 ASSERT_NE("", pool_name2
);
2743 ASSERT_NE("", pool_name3
);
2745 std::string cmdstr
= "{\"prefix\": \"osd tier add\", \"pool\": \"" +
2746 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\", \"force_nonempty\":\"\"}";
2748 cmd
[0] = (char *)cmdstr
.c_str();
2749 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
2751 cmdstr
= "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
2752 pool_name3
+ "\", \"mode\":\"writeback\"}";
2753 cmd
[0] = (char *)cmdstr
.c_str();
2754 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
2756 cmdstr
= "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
2757 pool_name1
+ "\", \"overlaypool\":\"" + pool_name3
+ "\"}";
2758 cmd
[0] = (char *)cmdstr
.c_str();
2759 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
2761 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
2763 string parent_name
= get_temp_image_name();
2764 string child_name1
= get_temp_image_name();
2765 string child_name2
= get_temp_image_name();
2766 string child_name3
= get_temp_image_name();
2767 string child_name4
= get_temp_image_name();
2769 rados_ioctx_t ioctx1
, ioctx2
;
2770 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
2771 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
2778 ASSERT_EQ(0, get_features(&old_format
, &features
));
2779 ASSERT_FALSE(old_format
);
2781 // make a parent to clone from
2782 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
2784 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
2785 // create a snapshot, reopen as the parent we're interested in
2786 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
2787 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
2788 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
2790 ASSERT_EQ(0, rbd_close(parent
));
2791 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
2793 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2794 ioctx2
, child_name1
.c_str(), features
, &order
));
2795 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
2797 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2798 ioctx1
, child_name2
.c_str(), features
, &order
));
2799 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
2800 pool_name1
.c_str(), child_name2
.c_str());
2802 // read from the cache to populate it
2803 rbd_image_t tier_image
;
2804 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &tier_image
, NULL
));
2805 size_t len
= 4 * 1024 * 1024;
2806 char* buf
= (char*)malloc(len
);
2807 ssize_t size
= rbd_read(tier_image
, 0, len
, buf
);
2810 ASSERT_EQ(0, rbd_close(tier_image
));
2812 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2813 ioctx2
, child_name3
.c_str(), features
, &order
));
2814 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
2815 pool_name1
.c_str(), child_name2
.c_str(),
2816 pool_name2
.c_str(), child_name3
.c_str());
2818 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
2819 ioctx2
, child_name4
.c_str(), features
, &order
));
2820 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
2821 pool_name1
.c_str(), child_name2
.c_str(),
2822 pool_name2
.c_str(), child_name3
.c_str(),
2823 pool_name2
.c_str(), child_name4
.c_str());
2825 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
2826 test_list_children(parent
, 3,
2827 pool_name1
.c_str(), child_name2
.c_str(),
2828 pool_name2
.c_str(), child_name3
.c_str(),
2829 pool_name2
.c_str(), child_name4
.c_str());
2831 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
2832 test_list_children(parent
, 2,
2833 pool_name1
.c_str(), child_name2
.c_str(),
2834 pool_name2
.c_str(), child_name4
.c_str());
2836 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
2837 test_list_children(parent
, 1,
2838 pool_name1
.c_str(), child_name2
.c_str());
2840 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
2841 test_list_children(parent
, 0);
2843 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
2844 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
2845 ASSERT_EQ(0, rbd_close(parent
));
2846 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
2847 rados_ioctx_destroy(ioctx1
);
2848 rados_ioctx_destroy(ioctx2
);
2849 cmdstr
= "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
2851 cmd
[0] = (char *)cmdstr
.c_str();
2852 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
2853 cmdstr
= "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
2854 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\"}";
2855 cmd
[0] = (char *)cmdstr
.c_str();
2856 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
2859 TEST_F(TestLibRBD
, LockingPP
)
2861 librados::IoCtx ioctx
;
2862 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2866 librbd::Image image
;
2868 std::string name
= get_temp_image_name();
2869 uint64_t size
= 2 << 20;
2870 std::string cookie1
= "foo";
2871 std::string cookie2
= "bar";
2873 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2874 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2876 // no lockers initially
2877 std::list
<librbd::locker_t
> lockers
;
2880 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
2881 ASSERT_EQ(0u, lockers
.size());
2884 // exclusive lock is exclusive
2885 ASSERT_EQ(0, image
.lock_exclusive(cookie1
));
2886 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
2887 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
2888 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
2889 ASSERT_EQ(-EBUSY
, image
.lock_shared(cookie1
, "test"));
2890 ASSERT_EQ(-EBUSY
, image
.lock_shared("", "test"));
2891 ASSERT_EQ(-EBUSY
, image
.lock_shared("", ""));
2894 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
2895 ASSERT_TRUE(exclusive
);
2897 ASSERT_EQ(1u, lockers
.size());
2898 ASSERT_EQ(cookie1
, lockers
.front().cookie
);
2901 ASSERT_EQ(-ENOENT
, image
.unlock(""));
2902 ASSERT_EQ(-ENOENT
, image
.unlock(cookie2
));
2903 ASSERT_EQ(0, image
.unlock(cookie1
));
2904 ASSERT_EQ(-ENOENT
, image
.unlock(cookie1
));
2905 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
2906 ASSERT_EQ(0u, lockers
.size());
2908 ASSERT_EQ(0, image
.lock_shared(cookie1
, ""));
2909 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
2910 ASSERT_EQ(0, image
.lock_shared(cookie2
, ""));
2911 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie2
, ""));
2912 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
2913 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie2
));
2914 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
2915 ASSERT_EQ(-EBUSY
, image
.lock_exclusive("test"));
2918 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
2919 ASSERT_EQ(2u, lockers
.size());
2925 TEST_F(TestLibRBD
, FlushAio
)
2927 rados_ioctx_t ioctx
;
2928 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2932 std::string name
= get_temp_image_name();
2933 uint64_t size
= 2 << 20;
2934 size_t num_aios
= 256;
2936 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2937 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2939 char test_data
[TEST_IO_SIZE
+ 1];
2941 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2942 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2945 rbd_completion_t write_comps
[num_aios
];
2946 for (i
= 0; i
< num_aios
; ++i
) {
2947 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &write_comps
[i
]));
2948 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
2949 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
2953 rbd_completion_t flush_comp
;
2954 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &flush_comp
));
2955 ASSERT_EQ(0, rbd_aio_flush(image
, flush_comp
));
2956 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp
));
2957 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp
));
2958 rbd_aio_release(flush_comp
);
2960 for (i
= 0; i
< num_aios
; ++i
) {
2961 ASSERT_EQ(1, rbd_aio_is_complete(write_comps
[i
]));
2962 rbd_aio_release(write_comps
[i
]);
2965 ASSERT_PASSED(validate_object_map
, image
);
2966 ASSERT_EQ(0, rbd_close(image
));
2967 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2968 rados_ioctx_destroy(ioctx
);
2971 TEST_F(TestLibRBD
, FlushAioPP
)
2973 librados::IoCtx ioctx
;
2974 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2978 librbd::Image image
;
2980 std::string name
= get_temp_image_name();
2981 uint64_t size
= 2 << 20;
2982 const size_t num_aios
= 256;
2984 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2985 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2987 char test_data
[TEST_IO_SIZE
+ 1];
2989 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2990 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2992 test_data
[TEST_IO_SIZE
] = '\0';
2994 librbd::RBD::AioCompletion
*write_comps
[num_aios
];
2995 ceph::bufferlist bls
[num_aios
];
2996 for (i
= 0; i
< num_aios
; ++i
) {
2997 bls
[i
].append(test_data
, strlen(test_data
));
2998 write_comps
[i
] = new librbd::RBD::AioCompletion(NULL
, NULL
);
2999 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
3000 ASSERT_EQ(0, image
.aio_write(offset
, TEST_IO_SIZE
, bls
[i
],
3004 librbd::RBD::AioCompletion
*flush_comp
=
3005 new librbd::RBD::AioCompletion(NULL
, NULL
);
3006 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
3007 ASSERT_EQ(0, flush_comp
->wait_for_complete());
3008 ASSERT_EQ(1, flush_comp
->is_complete());
3009 flush_comp
->release();
3011 for (i
= 0; i
< num_aios
; ++i
) {
3012 librbd::RBD::AioCompletion
*comp
= write_comps
[i
];
3013 ASSERT_EQ(1, comp
->is_complete());
3016 ASSERT_PASSED(validate_object_map
, image
);
3023 int iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3025 //cout << "iterate_cb " << off << "~" << len << std::endl;
3026 interval_set
<uint64_t> *diff
= static_cast<interval_set
<uint64_t> *>(arg
);
3027 diff
->insert(off
, len
);
3031 static int iterate_error_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3036 void scribble(librbd::Image
& image
, int n
, int max
, bool skip_discard
,
3037 interval_set
<uint64_t> *exists
,
3038 interval_set
<uint64_t> *what
)
3042 interval_set
<uint64_t> exists_at_start
= *exists
;
3044 for (int i
=0; i
<n
; i
++) {
3045 uint64_t off
= rand() % (size
- max
+ 1);
3046 uint64_t len
= 1 + rand() % max
;
3047 if (!skip_discard
&& rand() % 4 == 0) {
3048 ASSERT_EQ((int)len
, image
.discard(off
, len
));
3049 interval_set
<uint64_t> w
;
3052 // the zeroed bit no longer exists...
3053 w
.intersection_of(*exists
);
3054 exists
->subtract(w
);
3056 // the bits we discarded are no long written...
3057 interval_set
<uint64_t> w2
= w
;
3058 w2
.intersection_of(*what
);
3061 // except for the extents that existed at the start that we overwrote.
3062 interval_set
<uint64_t> w3
;
3063 w3
.insert(off
, len
);
3064 w3
.intersection_of(exists_at_start
);
3069 bl
.append(buffer::create(len
));
3071 ASSERT_EQ((int)len
, image
.write(off
, len
, bl
));
3072 interval_set
<uint64_t> w
;
3075 exists
->union_of(w
);
3080 interval_set
<uint64_t> round_diff_interval(const interval_set
<uint64_t>& diff
,
3081 uint64_t object_size
)
3083 if (object_size
== 0) {
3087 interval_set
<uint64_t> rounded_diff
;
3088 for (interval_set
<uint64_t>::const_iterator it
= diff
.begin();
3089 it
!= diff
.end(); ++it
) {
3090 uint64_t off
= it
.get_start();
3091 uint64_t len
= it
.get_len();
3092 off
-= off
% object_size
;
3093 len
+= (object_size
- (len
% object_size
));
3094 interval_set
<uint64_t> interval
;
3095 interval
.insert(off
, len
);
3096 rounded_diff
.union_of(interval
);
3098 return rounded_diff
;
3101 template <typename T
>
3102 class DiffIterateTest
: public TestLibRBD
{
3104 static const uint8_t whole_object
= T::whole_object
;
3107 template <bool _whole_object
>
3108 class DiffIterateParams
{
3110 static const uint8_t whole_object
= _whole_object
;
3113 typedef ::testing::Types
<DiffIterateParams
<false>,
3114 DiffIterateParams
<true> > DiffIterateTypes
;
3115 TYPED_TEST_CASE(DiffIterateTest
, DiffIterateTypes
);
3117 TYPED_TEST(DiffIterateTest
, DiffIterate
)
3119 librados::IoCtx ioctx
;
3120 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3122 bool skip_discard
= this->is_skip_partial_discard_enabled();
3126 librbd::Image image
;
3128 std::string name
= this->get_temp_image_name();
3129 uint64_t size
= 20 << 20;
3131 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3132 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3134 uint64_t object_size
= 0;
3135 if (this->whole_object
) {
3136 object_size
= 1 << order
;
3139 interval_set
<uint64_t> exists
;
3140 interval_set
<uint64_t> one
, two
;
3141 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
3142 cout
<< " wrote " << one
<< std::endl
;
3143 ASSERT_EQ(0, image
.snap_create("one"));
3144 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
3146 two
= round_diff_interval(two
, object_size
);
3147 cout
<< " wrote " << two
<< std::endl
;
3149 interval_set
<uint64_t> diff
;
3150 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
3151 iterate_cb
, (void *)&diff
));
3152 cout
<< " diff was " << diff
<< std::endl
;
3153 if (!two
.subset_of(diff
)) {
3154 interval_set
<uint64_t> i
;
3155 i
.intersection_of(two
, diff
);
3156 interval_set
<uint64_t> l
= two
;
3158 cout
<< " ... two - (two*diff) = " << l
<< std::endl
;
3160 ASSERT_TRUE(two
.subset_of(diff
));
3165 struct diff_extent
{
3166 diff_extent(uint64_t _offset
, uint64_t _length
, bool _exists
,
3167 uint64_t object_size
) :
3168 offset(_offset
), length(_length
), exists(_exists
)
3170 if (object_size
!= 0) {
3171 offset
-= offset
% object_size
;
3172 length
= object_size
;
3178 bool operator==(const diff_extent
& o
) const {
3179 return offset
== o
.offset
&& length
== o
.length
&& exists
== o
.exists
;
3183 ostream
& operator<<(ostream
& o
, const diff_extent
& e
) {
3184 return o
<< '(' << e
.offset
<< '~' << e
.length
<< ' ' << (e
.exists
? "true" : "false") << ')';
3187 int vector_iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3189 cout
<< "iterate_cb " << off
<< "~" << len
<< std::endl
;
3190 vector
<diff_extent
> *diff
= static_cast<vector
<diff_extent
> *>(arg
);
3191 diff
->push_back(diff_extent(off
, len
, exists
, 0));
3195 TYPED_TEST(DiffIterateTest
, DiffIterateDiscard
)
3197 librados::IoCtx ioctx
;
3198 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3201 librbd::Image image
;
3203 std::string name
= this->get_temp_image_name();
3204 uint64_t size
= 20 << 20;
3206 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3207 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3209 uint64_t object_size
= 0;
3210 if (this->whole_object
) {
3211 object_size
= 1 << order
;
3213 vector
<diff_extent
> extents
;
3214 ceph::bufferlist bl
;
3216 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3217 vector_iterate_cb
, (void *) &extents
));
3218 ASSERT_EQ(0u, extents
.size());
3221 memset(data
, 1, sizeof(data
));
3222 bl
.append(data
, 256);
3223 ASSERT_EQ(256, image
.write(0, 256, bl
));
3224 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3225 vector_iterate_cb
, (void *) &extents
));
3226 ASSERT_EQ(1u, extents
.size());
3227 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
3230 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
3233 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3234 vector_iterate_cb
, (void *) &extents
));
3235 ASSERT_EQ(0u, extents
.size());
3237 ASSERT_EQ(0, image
.snap_create("snap1"));
3238 ASSERT_EQ(256, image
.write(0, 256, bl
));
3239 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3240 vector_iterate_cb
, (void *) &extents
));
3241 ASSERT_EQ(1u, extents
.size());
3242 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
3243 ASSERT_EQ(0, image
.snap_create("snap2"));
3245 ASSERT_EQ(obj_ofs
, image
.discard(0, obj_ofs
));
3248 ASSERT_EQ(0, image
.snap_set("snap2"));
3249 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
3250 vector_iterate_cb
, (void *) &extents
));
3251 ASSERT_EQ(1u, extents
.size());
3252 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
3254 ASSERT_EQ(0, image
.snap_set(NULL
));
3255 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
3256 ASSERT_EQ(0, image
.snap_create("snap3"));
3257 ASSERT_EQ(0, image
.snap_set("snap3"));
3260 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
3261 vector_iterate_cb
, (void *) &extents
));
3262 ASSERT_EQ(1u, extents
.size());
3263 ASSERT_EQ(diff_extent(0, 256, false, object_size
), extents
[0]);
3264 ASSERT_PASSED(this->validate_object_map
, image
);
3267 TYPED_TEST(DiffIterateTest
, DiffIterateStress
)
3269 librados::IoCtx ioctx
;
3270 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3272 bool skip_discard
= this->is_skip_partial_discard_enabled();
3275 librbd::Image image
;
3277 std::string name
= this->get_temp_image_name();
3278 uint64_t size
= 400 << 20;
3280 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3281 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3283 uint64_t object_size
= 0;
3284 if (this->whole_object
) {
3285 object_size
= 1 << order
;
3288 interval_set
<uint64_t> curexists
;
3289 vector
<interval_set
<uint64_t> > wrote
;
3290 vector
<interval_set
<uint64_t> > exists
;
3291 vector
<string
> snap
;
3293 for (int i
=0; i
<n
; i
++) {
3294 interval_set
<uint64_t> w
;
3295 scribble(image
, 10, 8192000, skip_discard
, &curexists
, &w
);
3296 cout
<< " i=" << i
<< " exists " << curexists
<< " wrote " << w
<< std::endl
;
3297 string s
= "snap" + stringify(i
);
3298 ASSERT_EQ(0, image
.snap_create(s
.c_str()));
3300 exists
.push_back(curexists
);
3304 for (int h
=0; h
<n
-1; h
++) {
3305 for (int i
=0; i
<n
-h
-1; i
++) {
3306 for (int j
=(h
==0 ? i
+1 : n
-1); j
<n
; j
++) {
3307 interval_set
<uint64_t> diff
, actual
, uex
;
3308 for (int k
=i
+1; k
<=j
; k
++)
3309 diff
.union_of(wrote
[k
]);
3310 cout
<< "from " << i
<< " to "
3311 << (h
!= 0 ? string("HEAD") : stringify(j
)) << " diff "
3312 << round_diff_interval(diff
, object_size
) << std::endl
;
3314 // limit to extents that exists both at the beginning and at the end
3315 uex
.union_of(exists
[i
], exists
[j
]);
3316 diff
.intersection_of(uex
);
3317 diff
= round_diff_interval(diff
, object_size
);
3318 cout
<< " limited diff " << diff
<< std::endl
;
3320 ASSERT_EQ(0, image
.snap_set(h
==0 ? snap
[j
].c_str() : NULL
));
3321 ASSERT_EQ(0, image
.diff_iterate2(snap
[i
].c_str(), 0, size
, true,
3322 this->whole_object
, iterate_cb
,
3324 cout
<< " actual was " << actual
<< std::endl
;
3325 if (!diff
.subset_of(actual
)) {
3326 interval_set
<uint64_t> i
;
3327 i
.intersection_of(diff
, actual
);
3328 interval_set
<uint64_t> l
= diff
;
3330 cout
<< " ... diff - (actual*diff) = " << l
<< std::endl
;
3332 ASSERT_TRUE(diff
.subset_of(actual
));
3335 ASSERT_EQ(0, image
.snap_set(NULL
));
3336 ASSERT_EQ(0, image
.snap_remove(snap
[n
-h
-1].c_str()));
3339 ASSERT_PASSED(this->validate_object_map
, image
);
3342 TYPED_TEST(DiffIterateTest
, DiffIterateRegression6926
)
3344 librados::IoCtx ioctx
;
3345 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3348 librbd::Image image
;
3350 std::string name
= this->get_temp_image_name();
3351 uint64_t size
= 20 << 20;
3353 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3354 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3356 uint64_t object_size
= 0;
3357 if (this->whole_object
) {
3358 object_size
= 1 << order
;
3360 vector
<diff_extent
> extents
;
3361 ceph::bufferlist bl
;
3363 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3364 vector_iterate_cb
, (void *) &extents
));
3365 ASSERT_EQ(0u, extents
.size());
3367 ASSERT_EQ(0, image
.snap_create("snap1"));
3369 memset(data
, 1, sizeof(data
));
3370 bl
.append(data
, 256);
3371 ASSERT_EQ(256, image
.write(0, 256, bl
));
3374 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3375 vector_iterate_cb
, (void *) &extents
));
3376 ASSERT_EQ(1u, extents
.size());
3377 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
3379 ASSERT_EQ(0, image
.snap_set("snap1"));
3381 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3382 vector_iterate_cb
, (void *) &extents
));
3383 ASSERT_EQ(static_cast<size_t>(0), extents
.size());
3386 TYPED_TEST(DiffIterateTest
, DiffIterateIgnoreParent
)
3388 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3390 librados::IoCtx ioctx
;
3391 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3393 bool skip_discard
= this->is_skip_partial_discard_enabled();
3396 librbd::Image image
;
3397 std::string name
= this->get_temp_image_name();
3398 uint64_t size
= 20 << 20;
3401 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3402 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3404 uint64_t object_size
= 0;
3405 if (this->whole_object
) {
3406 object_size
= 1 << order
;
3410 bl
.append(buffer::create(size
));
3412 interval_set
<uint64_t> one
;
3413 one
.insert(0, size
);
3414 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
3415 ASSERT_EQ(0, image
.snap_create("one"));
3416 ASSERT_EQ(0, image
.snap_protect("one"));
3418 std::string clone_name
= this->get_temp_image_name();
3419 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
3420 RBD_FEATURE_LAYERING
, &order
));
3421 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
3423 interval_set
<uint64_t> exists
;
3424 interval_set
<uint64_t> two
;
3425 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
3426 two
= round_diff_interval(two
, object_size
);
3427 cout
<< " wrote " << two
<< " to clone" << std::endl
;
3429 interval_set
<uint64_t> diff
;
3430 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, false, this->whole_object
,
3431 iterate_cb
, (void *)&diff
));
3432 cout
<< " diff was " << diff
<< std::endl
;
3433 if (!this->whole_object
) {
3434 ASSERT_FALSE(one
.subset_of(diff
));
3436 ASSERT_TRUE(two
.subset_of(diff
));
3439 TYPED_TEST(DiffIterateTest
, DiffIterateCallbackError
)
3441 librados::IoCtx ioctx
;
3442 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3444 bool skip_discard
= this->is_skip_partial_discard_enabled();
3448 librbd::Image image
;
3450 std::string name
= this->get_temp_image_name();
3451 uint64_t size
= 20 << 20;
3453 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3454 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3456 interval_set
<uint64_t> exists
;
3457 interval_set
<uint64_t> one
;
3458 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
3459 cout
<< " wrote " << one
<< std::endl
;
3461 interval_set
<uint64_t> diff
;
3462 ASSERT_EQ(-EINVAL
, image
.diff_iterate2(NULL
, 0, size
, true,
3464 iterate_error_cb
, NULL
));
3469 TYPED_TEST(DiffIterateTest
, DiffIterateParentDiscard
)
3471 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3473 librados::IoCtx ioctx
;
3474 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3476 bool skip_discard
= this->is_skip_partial_discard_enabled();
3479 librbd::Image image
;
3480 std::string name
= this->get_temp_image_name();
3481 uint64_t size
= 20 << 20;
3484 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3485 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3487 uint64_t object_size
= 0;
3488 if (this->whole_object
) {
3489 object_size
= 1 << order
;
3492 interval_set
<uint64_t> exists
;
3493 interval_set
<uint64_t> one
;
3494 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
3495 ASSERT_EQ(0, image
.snap_create("one"));
3497 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
3498 ASSERT_EQ(0, image
.snap_create("two"));
3499 ASSERT_EQ(0, image
.snap_protect("two"));
3503 std::string clone_name
= this->get_temp_image_name();
3504 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "two", ioctx
,
3505 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
3506 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
3508 interval_set
<uint64_t> two
;
3509 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
3510 two
= round_diff_interval(two
, object_size
);
3512 interval_set
<uint64_t> diff
;
3513 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
3514 iterate_cb
, (void *)&diff
));
3515 ASSERT_TRUE(two
.subset_of(diff
));
3518 TEST_F(TestLibRBD
, ZeroLengthWrite
)
3520 rados_ioctx_t ioctx
;
3521 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3525 std::string name
= get_temp_image_name();
3526 uint64_t size
= 2 << 20;
3528 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3529 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3532 ASSERT_EQ(0, rbd_write(image
, 0, 0, NULL
));
3533 ASSERT_EQ(1, rbd_read(image
, 0, 1, read_data
));
3534 ASSERT_EQ('\0', read_data
[0]);
3536 ASSERT_PASSED(validate_object_map
, image
);
3537 ASSERT_EQ(0, rbd_close(image
));
3539 rados_ioctx_destroy(ioctx
);
3543 TEST_F(TestLibRBD
, ZeroLengthDiscard
)
3545 rados_ioctx_t ioctx
;
3546 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3550 std::string name
= get_temp_image_name();
3551 uint64_t size
= 2 << 20;
3553 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3554 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3556 const char data
[] = "blah";
3557 char read_data
[sizeof(data
)];
3558 ASSERT_EQ((int)strlen(data
), rbd_write(image
, 0, strlen(data
), data
));
3559 ASSERT_EQ(0, rbd_discard(image
, 0, 0));
3560 ASSERT_EQ((int)strlen(data
), rbd_read(image
, 0, strlen(data
), read_data
));
3561 ASSERT_EQ(0, memcmp(data
, read_data
, strlen(data
)));
3563 ASSERT_PASSED(validate_object_map
, image
);
3564 ASSERT_EQ(0, rbd_close(image
));
3566 rados_ioctx_destroy(ioctx
);
3569 TEST_F(TestLibRBD
, ZeroLengthRead
)
3571 rados_ioctx_t ioctx
;
3572 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3576 std::string name
= get_temp_image_name();
3577 uint64_t size
= 2 << 20;
3579 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3580 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3583 ASSERT_EQ(0, rbd_read(image
, 0, 0, read_data
));
3585 ASSERT_EQ(0, rbd_close(image
));
3587 rados_ioctx_destroy(ioctx
);
3590 TEST_F(TestLibRBD
, LargeCacheRead
)
3592 std::string config_value
;
3593 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", config_value
));
3594 if (config_value
== "false") {
3595 std::cout
<< "SKIPPING due to disabled cache" << std::endl
;
3599 rados_ioctx_t ioctx
;
3600 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3602 uint32_t new_cache_size
= 1 << 20;
3603 std::string orig_cache_size
;
3604 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", orig_cache_size
));
3605 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size",
3606 stringify(new_cache_size
).c_str()));
3607 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", config_value
));
3608 ASSERT_EQ(stringify(new_cache_size
), config_value
);
3609 BOOST_SCOPE_EXIT( (orig_cache_size
) ) {
3610 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size", orig_cache_size
.c_str()));
3611 } BOOST_SCOPE_EXIT_END
;
3615 std::string name
= get_temp_image_name();
3616 uint64_t size
= 1 << order
;
3618 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3619 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3621 std::string
buffer(1 << order
, '1');
3623 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
3624 rbd_write(image
, 0, buffer
.size(), buffer
.c_str()));
3626 ASSERT_EQ(0, rbd_invalidate_cache(image
));
3628 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
3629 rbd_read(image
, 0, buffer
.size(), &buffer
[0]));
3631 ASSERT_EQ(0, rbd_close(image
));
3633 rados_ioctx_destroy(ioctx
);
3636 TEST_F(TestLibRBD
, TestPendingAio
)
3638 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3640 rados_ioctx_t ioctx
;
3641 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3648 ASSERT_EQ(0, get_features(&old_format
, &features
));
3649 ASSERT_FALSE(old_format
);
3651 std::string name
= get_temp_image_name();
3653 uint64_t size
= 4 << 20;
3654 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
3656 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3658 char test_data
[TEST_IO_SIZE
];
3659 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3660 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3663 size_t num_aios
= 256;
3664 rbd_completion_t comps
[num_aios
];
3665 for (size_t i
= 0; i
< num_aios
; ++i
) {
3666 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
3667 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
3668 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
3671 for (size_t i
= 0; i
< num_aios
; ++i
) {
3672 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps
[i
]));
3673 rbd_aio_release(comps
[i
]);
3675 ASSERT_EQ(0, rbd_invalidate_cache(image
));
3677 for (size_t i
= 0; i
< num_aios
; ++i
) {
3678 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
3679 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
3680 ASSERT_LE(0, rbd_aio_read(image
, offset
, TEST_IO_SIZE
, test_data
,
3684 ASSERT_PASSED(validate_object_map
, image
);
3685 ASSERT_EQ(0, rbd_close(image
));
3686 for (size_t i
= 0; i
< num_aios
; ++i
) {
3687 ASSERT_EQ(1, rbd_aio_is_complete(comps
[i
]));
3688 rbd_aio_release(comps
[i
]);
3691 rados_ioctx_destroy(ioctx
);
3694 TEST_F(TestLibRBD
, Flatten
)
3696 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3698 librados::IoCtx ioctx
;
3699 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3702 std::string parent_name
= get_temp_image_name();
3703 uint64_t size
= 2 << 20;
3705 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
3707 librbd::Image parent_image
;
3708 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
3711 bl
.append(std::string(4096, '1'));
3712 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
3714 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
3715 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
3718 ASSERT_EQ(0, parent_image
.features(&features
));
3720 std::string clone_name
= get_temp_image_name();
3721 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
3722 clone_name
.c_str(), features
, &order
));
3724 librbd::Image clone_image
;
3725 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
3726 ASSERT_EQ(0, clone_image
.flatten());
3728 librbd::RBD::AioCompletion
*read_comp
=
3729 new librbd::RBD::AioCompletion(NULL
, NULL
);
3731 clone_image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
3732 ASSERT_EQ(0, read_comp
->wait_for_complete());
3733 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
3734 read_comp
->release();
3735 ASSERT_TRUE(bl
.contents_equal(read_bl
));
3737 ASSERT_PASSED(validate_object_map
, clone_image
);
3740 TEST_F(TestLibRBD
, SnapshotLimit
)
3742 rados_ioctx_t ioctx
;
3743 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3747 std::string name
= get_temp_image_name();
3748 uint64_t size
= 2 << 20;
3751 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3752 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3754 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
3755 ASSERT_EQ(UINT64_MAX
, limit
);
3756 ASSERT_EQ(0, rbd_snap_set_limit(image
, 2));
3757 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
3758 ASSERT_EQ(2U, limit
);
3760 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
3761 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
3762 ASSERT_EQ(-EDQUOT
, rbd_snap_create(image
, "snap3"));
3763 ASSERT_EQ(0, rbd_snap_set_limit(image
, UINT64_MAX
));
3764 ASSERT_EQ(0, rbd_snap_create(image
, "snap3"));
3765 ASSERT_EQ(0, rbd_close(image
));
3767 rados_ioctx_destroy(ioctx
);
3771 TEST_F(TestLibRBD
, SnapshotLimitPP
)
3773 librados::IoCtx ioctx
;
3774 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3778 librbd::Image image
;
3779 std::string name
= get_temp_image_name();
3780 uint64_t size
= 2 << 20;
3784 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3785 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3787 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
3788 ASSERT_EQ(UINT64_MAX
, limit
);
3789 ASSERT_EQ(0, image
.snap_set_limit(2));
3790 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
3791 ASSERT_EQ(2U, limit
);
3793 ASSERT_EQ(0, image
.snap_create("snap1"));
3794 ASSERT_EQ(0, image
.snap_create("snap2"));
3795 ASSERT_EQ(-EDQUOT
, image
.snap_create("snap3"));
3796 ASSERT_EQ(0, image
.snap_set_limit(UINT64_MAX
));
3797 ASSERT_EQ(0, image
.snap_create("snap3"));
3803 TEST_F(TestLibRBD
, RebuildObjectMapViaLockOwner
)
3805 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_OBJECT_MAP
);
3807 librados::IoCtx ioctx
;
3808 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3811 std::string name
= get_temp_image_name();
3812 uint64_t size
= 2 << 20;
3814 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3816 std::string object_map_oid
;
3818 librbd::Image image
;
3819 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3821 std::string image_id
;
3822 ASSERT_EQ(0, get_image_id(image
, &image_id
));
3823 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
3826 // corrupt the object map
3829 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
3831 librbd::Image image1
;
3832 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
3836 ASSERT_EQ(0, image1
.write(0, 0, bl
));
3837 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
3838 ASSERT_TRUE(lock_owner
);
3841 ASSERT_EQ(0, image1
.get_flags(&flags
));
3842 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
3844 librbd::Image image2
;
3845 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
3846 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
3847 ASSERT_FALSE(lock_owner
);
3849 PrintProgress prog_ctx
;
3850 ASSERT_EQ(0, image2
.rebuild_object_map(prog_ctx
));
3851 ASSERT_PASSED(validate_object_map
, image1
);
3852 ASSERT_PASSED(validate_object_map
, image2
);
3855 TEST_F(TestLibRBD
, RenameViaLockOwner
)
3857 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
3859 librados::IoCtx ioctx
;
3860 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3863 std::string name
= get_temp_image_name();
3864 uint64_t size
= 2 << 20;
3866 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3868 librbd::Image image1
;
3869 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
3872 ASSERT_EQ(0, image1
.write(0, 0, bl
));
3875 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
3876 ASSERT_TRUE(lock_owner
);
3878 std::string new_name
= get_temp_image_name();
3879 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
3880 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
3881 ASSERT_TRUE(lock_owner
);
3883 librbd::Image image2
;
3884 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, new_name
.c_str(), NULL
));
3887 TEST_F(TestLibRBD
, SnapCreateViaLockOwner
)
3889 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
3891 librados::IoCtx ioctx
;
3892 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3895 std::string name
= get_temp_image_name();
3896 uint64_t size
= 2 << 20;
3898 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3900 librbd::Image image1
;
3901 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
3903 // switch to writeback cache
3904 ASSERT_EQ(0, image1
.flush());
3907 bl
.append(std::string(4096, '1'));
3908 ASSERT_EQ((ssize_t
)bl
.length(), image1
.write(0, bl
.length(), bl
));
3911 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
3912 ASSERT_TRUE(lock_owner
);
3914 librbd::Image image2
;
3915 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
3917 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
3918 ASSERT_FALSE(lock_owner
);
3920 ASSERT_EQ(0, image2
.snap_create("snap1"));
3922 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
3923 ASSERT_TRUE(exists
);
3924 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
3925 ASSERT_TRUE(exists
);
3927 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
3928 ASSERT_TRUE(lock_owner
);
3931 TEST_F(TestLibRBD
, SnapRemoveViaLockOwner
)
3933 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
3935 librados::IoCtx ioctx
;
3936 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3939 std::string name
= get_temp_image_name();
3940 uint64_t size
= 2 << 20;
3942 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3944 librbd::Image image1
;
3945 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
3948 ASSERT_EQ(0, image1
.write(0, 0, bl
));
3949 ASSERT_EQ(0, image1
.snap_create("snap1"));
3952 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
3953 ASSERT_TRUE(lock_owner
);
3955 librbd::Image image2
;
3956 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
3958 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
3959 ASSERT_FALSE(lock_owner
);
3961 ASSERT_EQ(0, image2
.snap_remove("snap1"));
3963 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
3964 ASSERT_FALSE(exists
);
3965 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
3966 ASSERT_FALSE(exists
);
3968 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
3969 ASSERT_TRUE(lock_owner
);
3972 TEST_F(TestLibRBD
, SnapRemove2
)
3974 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3976 librados::IoCtx ioctx
;
3977 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3980 std::string name
= get_temp_image_name();
3981 uint64_t size
= 2 << 20;
3983 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3985 librbd::Image image1
;
3986 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
3989 ASSERT_EQ(0, image1
.write(0, 0, bl
));
3990 ASSERT_EQ(0, image1
.snap_create("snap1"));
3992 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
3993 ASSERT_TRUE(exists
);
3994 ASSERT_EQ(0, image1
.snap_protect("snap1"));
3996 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
3997 ASSERT_TRUE(is_protected
);
4000 ASSERT_EQ(0, image1
.features(&features
));
4002 std::string child_name
= get_temp_image_name();
4003 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
4004 child_name
.c_str(), features
, &order
));
4006 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
4007 ASSERT_TRUE(exists
);
4008 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
4009 ASSERT_TRUE(is_protected
);
4011 ASSERT_EQ(-EBUSY
, image1
.snap_remove("snap1"));
4013 ASSERT_EQ(0, image1
.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE
, pp
));
4014 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
4015 ASSERT_FALSE(exists
);
4018 TEST_F(TestLibRBD
, SnapRenameViaLockOwner
)
4020 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
4022 librados::IoCtx ioctx
;
4023 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4026 std::string name
= get_temp_image_name();
4027 uint64_t size
= 2 << 20;
4029 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4031 librbd::Image image1
;
4032 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4035 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4036 ASSERT_EQ(0, image1
.snap_create("snap1"));
4039 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4040 ASSERT_TRUE(lock_owner
);
4042 librbd::Image image2
;
4043 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4045 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4046 ASSERT_FALSE(lock_owner
);
4048 ASSERT_EQ(0, image2
.snap_rename("snap1", "snap1-rename"));
4050 ASSERT_EQ(0, image1
.snap_exists2("snap1-rename", &exists
));
4051 ASSERT_TRUE(exists
);
4052 ASSERT_EQ(0, image2
.snap_exists2("snap1-rename", &exists
));
4053 ASSERT_TRUE(exists
);
4055 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4056 ASSERT_TRUE(lock_owner
);
4059 TEST_F(TestLibRBD
, SnapProtectViaLockOwner
)
4061 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
4063 librados::IoCtx ioctx
;
4064 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4067 std::string name
= get_temp_image_name();
4068 uint64_t size
= 2 << 20;
4070 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4072 librbd::Image image1
;
4073 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4076 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4079 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4080 ASSERT_TRUE(lock_owner
);
4081 ASSERT_EQ(0, image1
.snap_create("snap1"));
4083 librbd::Image image2
;
4084 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4086 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4087 ASSERT_FALSE(lock_owner
);
4089 ASSERT_EQ(0, image2
.snap_protect("snap1"));
4091 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
4092 ASSERT_TRUE(is_protected
);
4093 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
4094 ASSERT_TRUE(is_protected
);
4096 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4097 ASSERT_TRUE(lock_owner
);
4100 TEST_F(TestLibRBD
, SnapUnprotectViaLockOwner
)
4102 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
4104 librados::IoCtx ioctx
;
4105 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4108 std::string name
= get_temp_image_name();
4109 uint64_t size
= 2 << 20;
4111 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4113 librbd::Image image1
;
4114 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4117 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4120 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4121 ASSERT_TRUE(lock_owner
);
4122 ASSERT_EQ(0, image1
.snap_create("snap1"));
4123 ASSERT_EQ(0, image1
.snap_protect("snap1"));
4125 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
4126 ASSERT_TRUE(is_protected
);
4128 librbd::Image image2
;
4129 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4131 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4132 ASSERT_FALSE(lock_owner
);
4134 ASSERT_EQ(0, image2
.snap_unprotect("snap1"));
4135 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
4136 ASSERT_FALSE(is_protected
);
4137 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
4138 ASSERT_FALSE(is_protected
);
4140 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4141 ASSERT_TRUE(lock_owner
);
4144 TEST_F(TestLibRBD
, FlattenViaLockOwner
)
4146 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
4148 librados::IoCtx ioctx
;
4149 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4152 std::string parent_name
= get_temp_image_name();
4153 uint64_t size
= 2 << 20;
4155 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4157 librbd::Image parent_image
;
4158 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4159 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4160 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4163 ASSERT_EQ(0, parent_image
.features(&features
));
4165 std::string name
= get_temp_image_name();
4166 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4167 name
.c_str(), features
, &order
));
4169 librbd::Image image1
;
4170 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4173 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4176 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4177 ASSERT_TRUE(lock_owner
);
4179 librbd::Image image2
;
4180 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4182 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4183 ASSERT_FALSE(lock_owner
);
4185 ASSERT_EQ(0, image2
.flatten());
4187 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4188 ASSERT_TRUE(lock_owner
);
4189 ASSERT_PASSED(validate_object_map
, image1
);
4192 TEST_F(TestLibRBD
, ResizeViaLockOwner
)
4194 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
4196 librados::IoCtx ioctx
;
4197 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4200 std::string name
= get_temp_image_name();
4201 uint64_t size
= 2 << 20;
4203 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4205 librbd::Image image1
;
4206 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4209 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4212 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4213 ASSERT_TRUE(lock_owner
);
4215 librbd::Image image2
;
4216 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4218 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4219 ASSERT_FALSE(lock_owner
);
4221 ASSERT_EQ(0, image2
.resize(0));
4223 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4224 ASSERT_TRUE(lock_owner
);
4225 ASSERT_PASSED(validate_object_map
, image1
);
4228 TEST_F(TestLibRBD
, ObjectMapConsistentSnap
)
4230 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
4232 librados::IoCtx ioctx
;
4233 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4236 std::string name
= get_temp_image_name();
4237 uint64_t size
= 1 << 20;
4239 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4241 librbd::Image image1
;
4242 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4245 for (int i
= 0; i
< num_snaps
; ++i
) {
4246 std::string snap_name
= "snap" + stringify(i
);
4247 ASSERT_EQ(0, image1
.snap_create(snap_name
.c_str()));
4251 thread
writer([&image1
](){
4252 librbd::image_info_t info
;
4253 int r
= image1
.stat(info
, sizeof(info
));
4257 for (unsigned i
= 0; i
< info
.num_objs
; ++i
) {
4258 r
= image1
.write((1 << info
.order
) * i
, bl
.length(), bl
);
4259 assert(r
== (int) bl
.length());
4264 for (int i
= 0; i
< num_snaps
; ++i
) {
4265 std::string snap_name
= "snap" + stringify(i
);
4266 ASSERT_EQ(0, image1
.snap_set(snap_name
.c_str()));
4267 ASSERT_PASSED(validate_object_map
, image1
);
4270 ASSERT_EQ(0, image1
.snap_set(NULL
));
4271 ASSERT_PASSED(validate_object_map
, image1
);
4274 void memset_rand(char *buf
, size_t len
) {
4275 for (size_t i
= 0; i
< len
; ++i
) {
4276 buf
[i
] = (char) (rand() % (126 - 33) + 33);
4280 TEST_F(TestLibRBD
, Metadata
)
4282 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4284 rados_ioctx_t ioctx
;
4285 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4287 std::string name
= get_temp_image_name();
4288 uint64_t size
= 2 << 20;
4290 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4293 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4296 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
4300 size_t keys_len
= sizeof(keys
);
4301 size_t vals_len
= sizeof(vals
);
4303 memset_rand(keys
, keys_len
);
4304 memset_rand(vals
, vals_len
);
4306 ASSERT_EQ(0, rbd_metadata_list(image
, "", 0, keys
, &keys_len
, vals
,
4308 ASSERT_EQ(0U, keys_len
);
4309 ASSERT_EQ(0U, vals_len
);
4312 size_t value_len
= sizeof(value
);
4313 memset_rand(value
, value_len
);
4315 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
4316 ASSERT_EQ(0, rbd_metadata_set(image1
, "key2", "value2"));
4317 ASSERT_EQ(0, rbd_metadata_get(image1
, "key1", value
, &value_len
));
4318 ASSERT_STREQ(value
, "value1");
4320 ASSERT_EQ(-ERANGE
, rbd_metadata_get(image1
, "key1", value
, &value_len
));
4321 ASSERT_EQ(value_len
, strlen("value1") + 1);
4323 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
4325 keys_len
= sizeof(keys
);
4326 vals_len
= sizeof(vals
);
4327 memset_rand(keys
, keys_len
);
4328 memset_rand(vals
, vals_len
);
4329 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
4331 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
4332 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
4333 ASSERT_STREQ(keys
, "key1");
4334 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
4335 ASSERT_STREQ(vals
, "value1");
4336 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
4338 ASSERT_EQ(0, rbd_metadata_remove(image1
, "key1"));
4339 ASSERT_EQ(0, rbd_metadata_remove(image1
, "key3"));
4340 value_len
= sizeof(value
);
4341 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key3", value
, &value_len
));
4342 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
4344 ASSERT_EQ(keys_len
, strlen("key2") + 1);
4345 ASSERT_EQ(vals_len
, strlen("value2") + 1);
4346 ASSERT_STREQ(keys
, "key2");
4347 ASSERT_STREQ(vals
, "value2");
4349 // test config setting
4350 ASSERT_EQ(0, rbd_metadata_set(image1
, "conf_rbd_cache", "false"));
4351 ASSERT_EQ(-EINVAL
, rbd_metadata_set(image1
, "conf_rbd_cache", "INVALID_VAL"));
4352 ASSERT_EQ(0, rbd_metadata_remove(image1
, "conf_rbd_cache"));
4354 // test metadata with snapshot adding
4355 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
4356 ASSERT_EQ(0, rbd_snap_protect(image1
, "snap1"));
4357 ASSERT_EQ(0, rbd_snap_set(image1
, "snap1"));
4359 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
4360 ASSERT_EQ(0, rbd_metadata_set(image1
, "key3", "value3"));
4362 keys_len
= sizeof(keys
);
4363 vals_len
= sizeof(vals
);
4364 memset_rand(keys
, keys_len
);
4365 memset_rand(vals
, vals_len
);
4366 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
4369 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4371 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4372 ASSERT_STREQ(keys
, "key1");
4373 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
4374 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
4375 ASSERT_STREQ(vals
, "value1");
4376 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
4377 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
4379 ASSERT_EQ(0, rbd_snap_set(image1
, NULL
));
4380 keys_len
= sizeof(keys
);
4381 vals_len
= sizeof(vals
);
4382 memset_rand(keys
, keys_len
);
4383 memset_rand(vals
, vals_len
);
4384 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
4387 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4389 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4390 ASSERT_STREQ(keys
, "key1");
4391 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
4392 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
4393 ASSERT_STREQ(vals
, "value1");
4394 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
4395 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
4397 // test metadata with cloning
4399 ASSERT_EQ(0, rbd_get_features(image1
, &features
));
4401 string cname
= get_temp_image_name();
4402 EXPECT_EQ(0, rbd_clone(ioctx
, name
.c_str(), "snap1", ioctx
,
4403 cname
.c_str(), features
, &order
));
4405 ASSERT_EQ(0, rbd_open(ioctx
, cname
.c_str(), &image2
, NULL
));
4406 ASSERT_EQ(0, rbd_metadata_set(image2
, "key4", "value4"));
4408 keys_len
= sizeof(keys
);
4409 vals_len
= sizeof(vals
);
4410 memset_rand(keys
, keys_len
);
4411 memset_rand(vals
, vals_len
);
4412 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 0, keys
, &keys_len
, vals
,
4414 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4415 1 + strlen("key4") + 1);
4416 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
4417 strlen("value3") + 1 + strlen("value4") + 1);
4418 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4420 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1 +
4421 strlen("value3") + 1, "value4");
4423 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
4426 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4428 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4429 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key4", value
, &value_len
));
4431 // test short buffer cases
4432 keys_len
= strlen("key1") + 1;
4433 vals_len
= strlen("value1") + 1;
4434 memset_rand(keys
, keys_len
);
4435 memset_rand(vals
, vals_len
);
4436 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 1, keys
, &keys_len
, vals
,
4438 ASSERT_EQ(keys_len
, strlen("key1") + 1);
4439 ASSERT_EQ(vals_len
, strlen("value1") + 1);
4440 ASSERT_STREQ(keys
, "key1");
4441 ASSERT_STREQ(vals
, "value1");
4443 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "", 2, keys
, &keys_len
, vals
,
4445 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
4446 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
4448 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "", 0, keys
, &keys_len
, vals
,
4450 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4451 1 + strlen("key4") + 1);
4452 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
4453 strlen("value3") + 1 + strlen("value4") + 1);
4455 // test `start` param
4456 keys_len
= sizeof(keys
);
4457 vals_len
= sizeof(vals
);
4458 memset_rand(keys
, keys_len
);
4459 memset_rand(vals
, vals_len
);
4460 ASSERT_EQ(0, rbd_metadata_list(image2
, "key2", 0, keys
, &keys_len
, vals
,
4462 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
4463 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
4464 ASSERT_STREQ(keys
, "key3");
4465 ASSERT_STREQ(vals
, "value3");
4467 ASSERT_EQ(0, rbd_close(image
));
4468 ASSERT_EQ(0, rbd_close(image1
));
4469 ASSERT_EQ(0, rbd_close(image2
));
4470 rados_ioctx_destroy(ioctx
);
4473 TEST_F(TestLibRBD
, MetadataPP
)
4475 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4477 librados::IoCtx ioctx
;
4478 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4481 string name
= get_temp_image_name();
4482 uint64_t size
= 2 << 20;
4486 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4488 librbd::Image image1
;
4489 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4490 map
<string
, bufferlist
> pairs
;
4491 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
4492 ASSERT_TRUE(pairs
.empty());
4494 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
4495 ASSERT_EQ(0, image1
.metadata_set("key2", "value2"));
4496 ASSERT_EQ(0, image1
.metadata_get("key1", &value
));
4497 ASSERT_EQ(0, strcmp("value1", value
.c_str()));
4498 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
4499 ASSERT_EQ(2U, pairs
.size());
4500 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
4501 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
4504 ASSERT_EQ(0, image1
.metadata_remove("key1"));
4505 ASSERT_EQ(0, image1
.metadata_remove("key3"));
4506 ASSERT_TRUE(image1
.metadata_get("key3", &value
) < 0);
4507 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
4508 ASSERT_EQ(1U, pairs
.size());
4509 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
4511 // test config setting
4512 ASSERT_EQ(0, image1
.metadata_set("conf_rbd_cache", "false"));
4513 ASSERT_EQ(-EINVAL
, image1
.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
4514 ASSERT_EQ(0, image1
.metadata_remove("conf_rbd_cache"));
4516 // test metadata with snapshot adding
4517 ASSERT_EQ(0, image1
.snap_create("snap1"));
4518 ASSERT_EQ(0, image1
.snap_protect("snap1"));
4519 ASSERT_EQ(0, image1
.snap_set("snap1"));
4522 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
4523 ASSERT_EQ(0, image1
.metadata_set("key3", "value3"));
4524 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
4525 ASSERT_EQ(3U, pairs
.size());
4526 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
4527 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
4528 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
4530 ASSERT_EQ(0, image1
.snap_set(NULL
));
4531 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
4532 ASSERT_EQ(3U, pairs
.size());
4533 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
4534 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
4535 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
4537 // test metadata with cloning
4538 string cname
= get_temp_image_name();
4539 librbd::Image image2
;
4540 ASSERT_EQ(0, image1
.features(&features
));
4541 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
4542 cname
.c_str(), features
, &order
));
4543 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, cname
.c_str(), NULL
));
4544 ASSERT_EQ(0, image2
.metadata_set("key4", "value4"));
4546 ASSERT_EQ(0, image2
.metadata_list("", 0, &pairs
));
4547 ASSERT_EQ(4U, pairs
.size());
4549 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
4550 ASSERT_EQ(3U, pairs
.size());
4551 ASSERT_EQ(-ENOENT
, image1
.metadata_get("key4", &value
));
4554 TEST_F(TestLibRBD
, UpdateFeatures
)
4556 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4558 librados::IoCtx ioctx
;
4559 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4562 std::string name
= get_temp_image_name();
4563 uint64_t size
= 1 << 20;
4565 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4567 librbd::Image image
;
4568 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4571 ASSERT_EQ(0, image
.old_format(&old_format
));
4573 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
4578 ASSERT_EQ(0, image
.features(&features
));
4580 // must provide a single feature
4581 ASSERT_EQ(-EINVAL
, image
.update_features(0, true));
4583 uint64_t disable_features
;
4584 disable_features
= features
& (RBD_FEATURE_EXCLUSIVE_LOCK
|
4585 RBD_FEATURE_OBJECT_MAP
|
4586 RBD_FEATURE_FAST_DIFF
|
4587 RBD_FEATURE_JOURNALING
);
4588 if (disable_features
!= 0) {
4589 ASSERT_EQ(0, image
.update_features(disable_features
, false));
4592 ASSERT_EQ(0, image
.features(&features
));
4593 ASSERT_EQ(0U, features
& disable_features
);
4595 // cannot enable object map nor journaling w/o exclusive lock
4596 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
4597 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_JOURNALING
, true));
4598 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
4600 ASSERT_EQ(0, image
.features(&features
));
4601 ASSERT_NE(0U, features
& RBD_FEATURE_EXCLUSIVE_LOCK
);
4603 // cannot enable fast diff w/o object map
4604 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_FAST_DIFF
, true));
4605 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
4606 ASSERT_EQ(0, image
.features(&features
));
4607 ASSERT_NE(0U, features
& RBD_FEATURE_OBJECT_MAP
);
4609 uint64_t expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
;
4611 ASSERT_EQ(0, image
.get_flags(&flags
));
4612 ASSERT_EQ(expected_flags
, flags
);
4614 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
4615 ASSERT_EQ(0, image
.features(&features
));
4616 ASSERT_EQ(0U, features
& RBD_FEATURE_OBJECT_MAP
);
4618 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
|
4619 RBD_FEATURE_FAST_DIFF
|
4620 RBD_FEATURE_JOURNALING
, true));
4622 expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
| RBD_FLAG_FAST_DIFF_INVALID
;
4623 ASSERT_EQ(0, image
.get_flags(&flags
));
4624 ASSERT_EQ(expected_flags
, flags
);
4626 // cannot disable object map w/ fast diff
4627 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
4628 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_FAST_DIFF
, false));
4629 ASSERT_EQ(0, image
.features(&features
));
4630 ASSERT_EQ(0U, features
& RBD_FEATURE_FAST_DIFF
);
4632 expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
;
4633 ASSERT_EQ(0, image
.get_flags(&flags
));
4634 ASSERT_EQ(expected_flags
, flags
);
4636 // cannot disable exclusive lock w/ object map
4637 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
4638 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
4640 // cannot disable exclusive lock w/ journaling
4641 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
4642 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, false));
4644 ASSERT_EQ(0, image
.get_flags(&flags
));
4645 ASSERT_EQ(0U, flags
);
4647 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
4649 ASSERT_EQ(0, image
.features(&features
));
4650 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0) {
4651 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, false));
4653 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, true));
4656 TEST_F(TestLibRBD
, RebuildObjectMap
)
4658 librados::IoCtx ioctx
;
4659 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4662 std::string name
= get_temp_image_name();
4663 uint64_t size
= 1 << 20;
4665 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4667 PrintProgress prog_ctx
;
4668 std::string object_map_oid
;
4672 librbd::Image image
;
4673 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4676 ASSERT_EQ(0, image
.features(&features
));
4677 if ((features
& RBD_FEATURE_OBJECT_MAP
) == 0) {
4678 ASSERT_EQ(-EINVAL
, image
.rebuild_object_map(prog_ctx
));
4682 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
4684 ASSERT_EQ(0, image
.snap_create("snap1"));
4685 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(1<<order
, bl
.length(), bl
));
4687 std::string image_id
;
4688 ASSERT_EQ(0, get_image_id(image
, &image_id
));
4689 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
4692 // corrupt the object map
4693 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
4695 librbd::Image image1
;
4696 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4700 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4701 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4702 ASSERT_TRUE(lock_owner
);
4705 ASSERT_EQ(0, image1
.get_flags(&flags
));
4706 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
4708 ASSERT_EQ(0, image1
.rebuild_object_map(prog_ctx
));
4710 librbd::Image image2
;
4711 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4714 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(0, bl
.length(), read_bl
));
4715 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4718 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(1<<order
, bl
.length(), read_bl
));
4719 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4721 ASSERT_PASSED(validate_object_map
, image1
);
4722 ASSERT_PASSED(validate_object_map
, image2
);
4725 TEST_F(TestLibRBD
, RebuildNewObjectMap
)
4727 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
4729 rados_ioctx_t ioctx
;
4730 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4732 std::string name
= get_temp_image_name();
4733 uint64_t size
= 1 << 20;
4735 uint64_t features
= RBD_FEATURE_EXCLUSIVE_LOCK
;
4736 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
4740 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4741 ASSERT_EQ(0, rbd_update_features(image
, RBD_FEATURE_OBJECT_MAP
, true));
4742 ASSERT_EQ(0, rbd_rebuild_object_map(image
, print_progress_percent
, NULL
));
4744 ASSERT_PASSED(validate_object_map
, image
);
4746 ASSERT_EQ(0, rbd_close(image
));
4747 rados_ioctx_destroy(ioctx
);
4750 TEST_F(TestLibRBD
, CheckObjectMap
)
4752 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
4754 librados::IoCtx ioctx
;
4755 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4758 std::string name
= get_temp_image_name();
4759 uint64_t size
= 1 << 20;
4761 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4763 PrintProgress prog_ctx
;
4768 librbd::Image image
;
4769 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4772 ASSERT_EQ(0, image
.features(&features
));
4774 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(0, bl1
.length(), bl1
));
4776 ASSERT_EQ(0, image
.snap_create("snap1"));
4777 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(1<<order
, bl1
.length(), bl1
));
4780 librbd::Image image1
;
4781 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4783 std::string image_id
;
4784 ASSERT_EQ(0, get_image_id(image1
, &image_id
));
4786 std::string object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
4788 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl2
, 1024, 0));
4791 ASSERT_EQ((ssize_t
)bl1
.length(), image1
.write(3 * (1 << 18), bl1
.length(), bl1
));
4792 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4793 ASSERT_TRUE(lock_owner
);
4795 //reopen image to reread now corrupt object map from disk
4799 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl1
, 1024, 0));
4800 ASSERT_FALSE(bl1
.contents_equal(bl2
));
4802 ASSERT_EQ(0, ioctx
.write_full(object_map_oid
, bl2
));
4803 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4806 ASSERT_EQ(0, image1
.get_flags(&flags
));
4807 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
4809 ASSERT_EQ(0, image1
.check_object_map(prog_ctx
));
4811 ASSERT_EQ(0, image1
.get_flags(&flags
));
4812 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
4815 TEST_F(TestLibRBD
, BlockingAIO
)
4817 librados::IoCtx ioctx
;
4818 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4820 bool skip_discard
= is_skip_partial_discard_enabled();
4823 std::string name
= get_temp_image_name();
4824 uint64_t size
= 1 << 20;
4826 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4828 std::string non_blocking_aio
;
4829 ASSERT_EQ(0, _rados
.conf_get("rbd_non_blocking_aio", non_blocking_aio
));
4830 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio", "0"));
4831 BOOST_SCOPE_EXIT( (non_blocking_aio
) ) {
4832 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio",
4833 non_blocking_aio
.c_str()));
4834 } BOOST_SCOPE_EXIT_END
;
4836 librbd::Image image
;
4837 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4840 ASSERT_EQ(0, image
.write(0, bl
.length(), bl
));
4842 bl
.append(std::string(256, '1'));
4843 librbd::RBD::AioCompletion
*write_comp
=
4844 new librbd::RBD::AioCompletion(NULL
, NULL
);
4845 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
4847 librbd::RBD::AioCompletion
*flush_comp
=
4848 new librbd::RBD::AioCompletion(NULL
, NULL
);
4849 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
4850 ASSERT_EQ(0, flush_comp
->wait_for_complete());
4851 ASSERT_EQ(0, flush_comp
->get_return_value());
4852 flush_comp
->release();
4854 ASSERT_EQ(1, write_comp
->is_complete());
4855 ASSERT_EQ(0, write_comp
->get_return_value());
4856 write_comp
->release();
4858 librbd::RBD::AioCompletion
*discard_comp
=
4859 new librbd::RBD::AioCompletion(NULL
, NULL
);
4860 ASSERT_EQ(0, image
.aio_discard(128, 128, discard_comp
));
4861 ASSERT_EQ(0, discard_comp
->wait_for_complete());
4862 discard_comp
->release();
4864 librbd::RBD::AioCompletion
*read_comp
=
4865 new librbd::RBD::AioCompletion(NULL
, NULL
);
4867 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
4868 ASSERT_EQ(0, read_comp
->wait_for_complete());
4869 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
4870 read_comp
->release();
4872 bufferlist expected_bl
;
4873 expected_bl
.append(std::string(128, '1'));
4874 expected_bl
.append(std::string(128, skip_discard
? '1' : '\0'));
4875 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
4878 TEST_F(TestLibRBD
, ExclusiveLockTransition
)
4880 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
4882 librados::IoCtx ioctx
;
4883 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4886 std::string name
= get_temp_image_name();
4888 uint64_t size
= 1 << 18;
4890 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4892 librbd::Image image1
;
4893 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4895 librbd::Image image2
;
4896 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4898 std::list
<librbd::RBD::AioCompletion
*> comps
;
4899 ceph::bufferlist bl
;
4900 bl
.append(std::string(1 << order
, '1'));
4901 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
4902 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
4904 comps
.push_back(comp
);
4905 if (object_no
% 2 == 0) {
4906 ASSERT_EQ(0, image1
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
4908 ASSERT_EQ(0, image2
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
4912 while (!comps
.empty()) {
4913 librbd::RBD::AioCompletion
*comp
= comps
.front();
4915 ASSERT_EQ(0, comp
->wait_for_complete());
4916 ASSERT_EQ(1, comp
->is_complete());
4920 librbd::Image image3
;
4921 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
4922 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
4924 ASSERT_EQ((ssize_t
)bl
.length(), image3
.read(object_no
<< order
, bl
.length(),
4926 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4929 ASSERT_PASSED(validate_object_map
, image1
);
4930 ASSERT_PASSED(validate_object_map
, image2
);
4931 ASSERT_PASSED(validate_object_map
, image3
);
4934 TEST_F(TestLibRBD
, ExclusiveLockReadTransition
)
4936 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
4938 librados::IoCtx ioctx
;
4939 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4942 std::string name
= get_temp_image_name();
4944 uint64_t size
= 1 << 18;
4946 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4948 librbd::Image image1
;
4949 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4952 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4953 ASSERT_FALSE(lock_owner
);
4955 // journaling should force read ops to acquire the lock
4957 ASSERT_EQ(0, image1
.read(0, 0, read_bl
));
4959 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4960 ASSERT_TRUE(lock_owner
);
4962 librbd::Image image2
;
4963 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4965 std::list
<librbd::RBD::AioCompletion
*> comps
;
4966 std::list
<bufferlist
> read_bls
;
4967 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
4968 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
4970 comps
.push_back(comp
);
4971 read_bls
.emplace_back();
4972 if (object_no
% 2 == 0) {
4973 ASSERT_EQ(0, image1
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
4975 ASSERT_EQ(0, image2
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
4979 while (!comps
.empty()) {
4980 librbd::RBD::AioCompletion
*comp
= comps
.front();
4982 ASSERT_EQ(0, comp
->wait_for_complete());
4983 ASSERT_EQ(1, comp
->is_complete());
4988 TEST_F(TestLibRBD
, CacheMayCopyOnWrite
) {
4989 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4991 librados::IoCtx ioctx
;
4992 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4995 std::string name
= get_temp_image_name();
4997 uint64_t size
= 1 << 18;
4999 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5001 librbd::Image image
;
5002 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5003 ASSERT_EQ(0, image
.snap_create("one"));
5004 ASSERT_EQ(0, image
.snap_protect("one"));
5006 std::string clone_name
= this->get_temp_image_name();
5007 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
5008 RBD_FEATURE_LAYERING
, &order
));
5010 librbd::Image clone
;
5011 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
5012 ASSERT_EQ(0, clone
.flush());
5014 bufferlist expect_bl
;
5015 expect_bl
.append(std::string(1024, '\0'));
5017 // test double read path
5019 uint64_t offset
= 0;
5020 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
5021 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
5023 bufferlist write_bl
;
5024 write_bl
.append(std::string(1024, '1'));
5025 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
5028 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
5029 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
5031 // test read retry path
5032 offset
= 1 << order
;
5033 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
5036 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
5037 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
5040 TEST_F(TestLibRBD
, FlushEmptyOpsOnExternalSnapshot
) {
5041 std::string cache_enabled
;
5042 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", cache_enabled
));
5043 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", "false"));
5044 BOOST_SCOPE_EXIT( (cache_enabled
) ) {
5045 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", cache_enabled
.c_str()));
5046 } BOOST_SCOPE_EXIT_END
;
5048 librados::IoCtx ioctx
;
5049 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5052 std::string name
= get_temp_image_name();
5053 uint64_t size
= 1 << 18;
5055 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5057 librbd::Image image1
;
5058 librbd::Image image2
;
5059 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5060 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5061 ASSERT_EQ(0, image1
.snap_create("snap1"));
5063 librbd::RBD::AioCompletion
*read_comp
=
5064 new librbd::RBD::AioCompletion(NULL
, NULL
);
5066 image2
.aio_read(0, 1024, read_bl
, read_comp
);
5067 ASSERT_EQ(0, read_comp
->wait_for_complete());
5068 read_comp
->release();
5071 TEST_F(TestLibRBD
, TestImageOptions
)
5073 rados_ioctx_t ioctx
;
5074 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5076 //make create image options
5077 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
5079 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
5080 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
5081 rbd_image_options_t opts
;
5082 rbd_image_options_create(&opts
);
5085 ASSERT_EQ(-EINVAL
, rbd_image_options_is_set(opts
, 12345, &is_set
));
5086 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
5088 ASSERT_FALSE(is_set
);
5090 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FORMAT
,
5092 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FEATURES
,
5094 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
5096 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_UNIT
,
5098 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_COUNT
,
5101 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
5103 ASSERT_TRUE(is_set
);
5105 std::string parent_name
= get_temp_image_name();
5108 ASSERT_EQ(0, rbd_create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
5110 // check order is returned in opts
5111 ASSERT_EQ(0, rbd_image_options_get_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
5113 ASSERT_NE((uint64_t)0, order
);
5115 // write some data to parent
5117 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
5118 char *data
= (char *)"testdata";
5119 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
5120 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
5122 // create a snapshot, reopen as the parent we're interested in
5123 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
5124 ASSERT_EQ(0, rbd_close(parent
));
5125 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
5128 std::string child_name
= get_temp_image_name();
5129 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
5130 ASSERT_EQ(0, rbd_clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
5131 child_name
.c_str(), opts
));
5134 std::string copy1_name
= get_temp_image_name();
5135 ASSERT_EQ(0, rbd_copy3(parent
, ioctx
, copy1_name
.c_str(), opts
));
5136 std::string copy2_name
= get_temp_image_name();
5137 ASSERT_EQ(0, rbd_copy_with_progress3(parent
, ioctx
, copy2_name
.c_str(), opts
,
5138 print_progress_percent
, NULL
));
5140 ASSERT_EQ(0, rbd_close(parent
));
5142 rbd_image_options_destroy(opts
);
5144 rados_ioctx_destroy(ioctx
);
5147 TEST_F(TestLibRBD
, TestImageOptionsPP
)
5149 librados::IoCtx ioctx
;
5150 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5152 //make create image options
5153 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
5155 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
5156 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
5157 librbd::ImageOptions opts
;
5158 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FORMAT
, static_cast<uint64_t>(2)));
5159 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FEATURES
, features
));
5160 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_ORDER
, order
));
5161 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
));
5162 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
));
5165 std::string parent_name
= get_temp_image_name();
5168 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
5170 // check order is returned in opts
5171 ASSERT_EQ(0, opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
));
5172 ASSERT_NE((uint64_t)0, order
);
5174 // write some data to parent
5175 librbd::Image parent
;
5176 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
5180 bl
.append(buffer::create(len
));
5182 ASSERT_EQ(len
, parent
.write(0, len
, bl
));
5183 ASSERT_EQ(len
, parent
.write(len
, len
, bl
));
5185 // create a snapshot, reopen as the parent we're interested in
5186 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
5187 ASSERT_EQ(0, parent
.close());
5188 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
5191 std::string child_name
= get_temp_image_name();
5192 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
5193 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
5194 child_name
.c_str(), opts
));
5197 std::string copy1_name
= get_temp_image_name();
5198 ASSERT_EQ(0, parent
.copy3(ioctx
, copy1_name
.c_str(), opts
));
5199 std::string copy2_name
= get_temp_image_name();
5201 ASSERT_EQ(0, parent
.copy_with_progress3(ioctx
, copy2_name
.c_str(), opts
, pp
));
5203 ASSERT_EQ(0, parent
.close());
5206 TEST_F(TestLibRBD
, EventSocketPipe
)
5208 EventSocket event_sock
;
5209 int pipe_fd
[2]; // read and write fd
5212 ASSERT_EQ(0, pipe(pipe_fd
));
5214 ASSERT_FALSE(event_sock
.is_valid());
5216 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_NONE
));
5217 ASSERT_FALSE(event_sock
.is_valid());
5219 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], 44));
5220 ASSERT_FALSE(event_sock
.is_valid());
5222 #ifndef HAVE_EVENTFD
5223 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_EVENTFD
));
5224 ASSERT_FALSE(event_sock
.is_valid());
5227 ASSERT_EQ(0, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_PIPE
));
5228 ASSERT_TRUE(event_sock
.is_valid());
5229 ASSERT_EQ(0, event_sock
.notify());
5230 ASSERT_EQ(1, read(pipe_fd
[0], buf
, 32));
5231 ASSERT_EQ('i', buf
[0]);
5237 TEST_F(TestLibRBD
, EventSocketEventfd
)
5240 EventSocket event_sock
;
5242 struct pollfd poll_fd
;
5245 event_fd
= eventfd(0, EFD_NONBLOCK
);
5246 ASSERT_NE(-1, event_fd
);
5248 ASSERT_FALSE(event_sock
.is_valid());
5250 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_NONE
));
5251 ASSERT_FALSE(event_sock
.is_valid());
5253 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, 44));
5254 ASSERT_FALSE(event_sock
.is_valid());
5256 ASSERT_EQ(0, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_EVENTFD
));
5257 ASSERT_TRUE(event_sock
.is_valid());
5258 ASSERT_EQ(0, event_sock
.notify());
5260 poll_fd
.fd
= event_fd
;
5261 poll_fd
.events
= POLLIN
;
5262 ASSERT_EQ(1, poll(&poll_fd
, 1, -1));
5263 ASSERT_TRUE(poll_fd
.revents
& POLLIN
);
5265 ASSERT_EQ(static_cast<ssize_t
>(sizeof(uint64_t)), read(event_fd
, buf
, 32));
5266 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf
));
5272 TEST_F(TestLibRBD
, ImagePollIO
)
5275 rados_ioctx_t ioctx
;
5276 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5280 std::string name
= get_temp_image_name();
5281 uint64_t size
= 2 << 20;
5282 int fd
= eventfd(0, EFD_NONBLOCK
);
5284 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5285 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5287 ASSERT_EQ(0, rbd_set_image_notification(image
, fd
, EVENT_SOCKET_TYPE_EVENTFD
));
5289 char test_data
[TEST_IO_SIZE
+ 1];
5290 char zero_data
[TEST_IO_SIZE
+ 1];
5293 for (i
= 0; i
< TEST_IO_SIZE
; ++i
)
5294 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
5295 test_data
[TEST_IO_SIZE
] = '\0';
5296 memset(zero_data
, 0, sizeof(zero_data
));
5298 for (i
= 0; i
< 5; ++i
)
5299 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
5301 for (i
= 5; i
< 10; ++i
)
5302 ASSERT_PASSED(aio_write_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
5304 for (i
= 5; i
< 10; ++i
)
5305 ASSERT_PASSED(aio_read_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
5307 ASSERT_EQ(0, rbd_close(image
));
5308 rados_ioctx_destroy(ioctx
);
5314 static bool operator==(const mirror_peer_t
&lhs
, const mirror_peer_t
&rhs
) {
5315 return (lhs
.uuid
== rhs
.uuid
&&
5316 lhs
.cluster_name
== rhs
.cluster_name
&&
5317 lhs
.client_name
== rhs
.client_name
);
5320 static std::ostream
& operator<<(std::ostream
&os
, const mirror_peer_t
&peer
) {
5321 os
<< "uuid=" << peer
.uuid
<< ", "
5322 << "cluster=" << peer
.cluster_name
<< ", "
5323 << "client=" << peer
.client_name
;
5327 } // namespace librbd
5329 TEST_F(TestLibRBD
, Mirror
) {
5330 librados::IoCtx ioctx
;
5331 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5335 std::vector
<librbd::mirror_peer_t
> expected_peers
;
5336 std::vector
<librbd::mirror_peer_t
> peers
;
5337 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
5338 ASSERT_EQ(expected_peers
, peers
);
5341 ASSERT_EQ(-EINVAL
, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
5343 rbd_mirror_mode_t mirror_mode
;
5344 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
5345 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED
, mirror_mode
);
5347 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
5348 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
5350 // Add some images to the pool
5352 std::string parent_name
= get_temp_image_name();
5353 std::string child_name
= get_temp_image_name();
5354 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), 2 << 20,
5358 ASSERT_EQ(0, get_features(&old_format
, &features
));
5359 if ((features
& RBD_FEATURE_LAYERING
) != 0) {
5360 librbd::Image parent
;
5361 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
5362 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
5363 ASSERT_EQ(0, parent
.close());
5364 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
5365 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
5366 ASSERT_EQ(0, parent
.close());
5367 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
5368 child_name
.c_str(), features
, &order
));
5371 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE
, mirror_mode
);
5373 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_POOL
));
5374 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
5375 ASSERT_EQ(RBD_MIRROR_MODE_POOL
, mirror_mode
);
5379 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
5380 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid2
, "cluster2", "admin"));
5381 ASSERT_EQ(-EEXIST
, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster1", "foo"));
5382 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster3", "admin"));
5384 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
5385 auto sort_peers
= [](const librbd::mirror_peer_t
&lhs
,
5386 const librbd::mirror_peer_t
&rhs
) {
5387 return lhs
.uuid
< rhs
.uuid
;
5390 {uuid1
, "cluster1", "client"},
5391 {uuid2
, "cluster2", "admin"},
5392 {uuid3
, "cluster3", "admin"}};
5393 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
5394 ASSERT_EQ(expected_peers
, peers
);
5396 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, "uuid4"));
5397 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid2
));
5399 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_client(ioctx
, "uuid4", "new client"));
5400 ASSERT_EQ(0, rbd
.mirror_peer_set_client(ioctx
, uuid1
, "new client"));
5402 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_cluster(ioctx
, "uuid4",
5404 ASSERT_EQ(0, rbd
.mirror_peer_set_cluster(ioctx
, uuid3
, "new cluster"));
5406 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
5408 {uuid1
, "cluster1", "new client"},
5409 {uuid3
, "new cluster", "admin"}};
5410 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
5411 ASSERT_EQ(expected_peers
, peers
);
5413 ASSERT_EQ(-EBUSY
, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
5416 TEST_F(TestLibRBD
, FlushCacheWithCopyupOnExternalSnapshot
) {
5417 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5419 librados::IoCtx ioctx
;
5420 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5423 librbd::Image image
;
5424 std::string name
= get_temp_image_name();
5426 uint64_t size
= 1 << 18;
5429 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5430 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5433 bl
.append(std::string(size
, '1'));
5434 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
5435 ASSERT_EQ(0, image
.snap_create("one"));
5436 ASSERT_EQ(0, image
.snap_protect("one"));
5438 std::string clone_name
= this->get_temp_image_name();
5439 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
5440 RBD_FEATURE_LAYERING
, &order
));
5441 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
5443 librbd::Image image2
;
5444 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, clone_name
.c_str(), NULL
));
5446 // prepare CoW writeback that will be flushed on next op
5448 bl
.append(std::string(1, '1'));
5449 ASSERT_EQ(0, image
.flush());
5450 ASSERT_EQ(1, image
.write(0, 1, bl
));
5451 ASSERT_EQ(0, image2
.snap_create("snap1"));
5453 librbd::RBD::AioCompletion
*read_comp
=
5454 new librbd::RBD::AioCompletion(NULL
, NULL
);
5456 image
.aio_read(0, 1024, read_bl
, read_comp
);
5457 ASSERT_EQ(0, read_comp
->wait_for_complete());
5458 read_comp
->release();
5461 TEST_F(TestLibRBD
, ExclusiveLock
)
5463 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5465 static char buf
[10];
5467 rados_ioctx_t ioctx
;
5468 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5470 std::string name
= get_temp_image_name();
5471 uint64_t size
= 2 << 20;
5473 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5476 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
5479 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
5480 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
5481 ASSERT_TRUE(lock_owner
);
5483 rbd_lock_mode_t lock_mode
;
5484 char *lock_owners
[1];
5485 size_t max_lock_owners
= 0;
5486 ASSERT_EQ(-ERANGE
, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
5488 ASSERT_EQ(1U, max_lock_owners
);
5490 max_lock_owners
= 2;
5491 ASSERT_EQ(0, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
5493 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
5494 ASSERT_STRNE("", lock_owners
[0]);
5495 ASSERT_EQ(1U, max_lock_owners
);
5498 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
5500 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
5501 ASSERT_FALSE(lock_owner
);
5503 ASSERT_EQ(-EOPNOTSUPP
, rbd_lock_break(image1
, RBD_LOCK_MODE_SHARED
, ""));
5504 ASSERT_EQ(-EBUSY
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
5507 ASSERT_EQ(0, rbd_lock_release(image1
));
5508 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
5509 ASSERT_FALSE(lock_owner
);
5511 ASSERT_EQ(-ENOENT
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
5513 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
5515 ASSERT_EQ(-EROFS
, rbd_write(image1
, 0, sizeof(buf
), buf
));
5516 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image2
, 0, sizeof(buf
), buf
));
5518 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
5519 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
5520 ASSERT_TRUE(lock_owner
);
5522 ASSERT_EQ(0, rbd_lock_release(image2
));
5523 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
5524 ASSERT_FALSE(lock_owner
);
5526 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
5527 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
5528 ASSERT_TRUE(lock_owner
);
5530 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image1
, 0, sizeof(buf
), buf
));
5531 ASSERT_EQ(-EROFS
, rbd_write(image2
, 0, sizeof(buf
), buf
));
5533 ASSERT_EQ(0, rbd_lock_release(image1
));
5534 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
5535 ASSERT_FALSE(lock_owner
);
5539 const auto pingpong
= [&,this](int m_id
, rbd_image_t
&m_image
) {
5540 for (int i
= 0; i
< 10; i
++) {
5542 lock_guard
<mutex
> locker(lock
);
5543 if (owner_id
== m_id
) {
5544 std::cout
<< m_id
<< ": releasing exclusive lock" << std::endl
;
5545 EXPECT_EQ(0, rbd_lock_release(m_image
));
5547 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
5548 EXPECT_FALSE(lock_owner
);
5550 std::cout
<< m_id
<< ": exclusive lock released" << std::endl
;
5555 std::cout
<< m_id
<< ": acquiring exclusive lock" << std::endl
;
5558 r
= rbd_lock_acquire(m_image
, RBD_LOCK_MODE_EXCLUSIVE
);
5562 } while (r
== -EROFS
);
5566 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
5567 EXPECT_TRUE(lock_owner
);
5568 std::cout
<< m_id
<< ": exclusive lock acquired" << std::endl
;
5570 lock_guard
<mutex
> locker(lock
);
5573 usleep(rand() % 50000);
5576 lock_guard
<mutex
> locker(lock
);
5577 if (owner_id
== m_id
) {
5578 EXPECT_EQ(0, rbd_lock_release(m_image
));
5580 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
5581 EXPECT_FALSE(lock_owner
);
5585 thread
ping(bind(pingpong
, 1, ref(image1
)));
5586 thread
pong(bind(pingpong
, 2, ref(image2
)));
5591 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
5592 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
5593 ASSERT_TRUE(lock_owner
);
5595 ASSERT_EQ(0, rbd_close(image2
));
5597 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
5598 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
5599 ASSERT_TRUE(lock_owner
);
5601 ASSERT_EQ(0, rbd_close(image1
));
5602 rados_ioctx_destroy(ioctx
);
5605 TEST_F(TestLibRBD
, BreakLock
)
5607 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5609 static char buf
[10];
5611 rados_t blacklist_cluster
;
5612 ASSERT_EQ("", connect_cluster(&blacklist_cluster
));
5614 rados_ioctx_t ioctx
, blacklist_ioctx
;
5615 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
5616 ASSERT_EQ(0, rados_ioctx_create(blacklist_cluster
, m_pool_name
.c_str(),
5619 std::string name
= get_temp_image_name();
5620 uint64_t size
= 2 << 20;
5622 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5624 rbd_image_t image
, blacklist_image
;
5625 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5626 ASSERT_EQ(0, rbd_open(blacklist_ioctx
, name
.c_str(), &blacklist_image
, NULL
));
5628 ASSERT_EQ(0, rbd_metadata_set(image
, "rbd_blacklist_on_break_lock", "true"));
5629 ASSERT_EQ(0, rbd_lock_acquire(blacklist_image
, RBD_LOCK_MODE_EXCLUSIVE
));
5631 rbd_lock_mode_t lock_mode
;
5632 char *lock_owners
[1];
5633 size_t max_lock_owners
= 1;
5634 ASSERT_EQ(0, rbd_lock_get_owners(image
, &lock_mode
, lock_owners
,
5636 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
5637 ASSERT_STRNE("", lock_owners
[0]);
5638 ASSERT_EQ(1U, max_lock_owners
);
5640 ASSERT_EQ(0, rbd_lock_break(image
, RBD_LOCK_MODE_EXCLUSIVE
, lock_owners
[0]));
5641 ASSERT_EQ(0, rbd_lock_acquire(image
, RBD_LOCK_MODE_EXCLUSIVE
));
5642 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blacklist_cluster
));
5644 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image
, 0, sizeof(buf
), buf
));
5645 ASSERT_EQ(-EBLACKLISTED
, rbd_write(blacklist_image
, 0, sizeof(buf
), buf
));
5647 ASSERT_EQ(0, rbd_close(image
));
5648 ASSERT_EQ(0, rbd_close(blacklist_image
));
5650 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
5652 rados_ioctx_destroy(ioctx
);
5653 rados_ioctx_destroy(blacklist_ioctx
);
5654 rados_shutdown(blacklist_cluster
);
5657 TEST_F(TestLibRBD
, DiscardAfterWrite
)
5659 REQUIRE(!is_skip_partial_discard_enabled());
5661 librados::IoCtx ioctx
;
5662 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5665 std::string name
= get_temp_image_name();
5666 uint64_t size
= 1 << 20;
5668 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5670 librbd::Image image
;
5671 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5673 // enable writeback cache
5674 ASSERT_EQ(0, image
.flush());
5677 bl
.append(std::string(256, '1'));
5679 librbd::RBD::AioCompletion
*write_comp
=
5680 new librbd::RBD::AioCompletion(NULL
, NULL
);
5681 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
5682 ASSERT_EQ(0, write_comp
->wait_for_complete());
5683 write_comp
->release();
5685 librbd::RBD::AioCompletion
*discard_comp
=
5686 new librbd::RBD::AioCompletion(NULL
, NULL
);
5687 ASSERT_EQ(0, image
.aio_discard(0, 256, discard_comp
));
5688 ASSERT_EQ(0, discard_comp
->wait_for_complete());
5689 discard_comp
->release();
5691 librbd::RBD::AioCompletion
*read_comp
=
5692 new librbd::RBD::AioCompletion(NULL
, NULL
);
5694 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
5695 ASSERT_EQ(0, read_comp
->wait_for_complete());
5696 ASSERT_EQ(bl
.length(), read_comp
->get_return_value());
5697 ASSERT_TRUE(read_bl
.is_zero());
5698 read_comp
->release();
5701 TEST_F(TestLibRBD
, DefaultFeatures
) {
5702 std::string orig_default_features
;
5703 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", orig_default_features
));
5704 BOOST_SCOPE_EXIT_ALL(orig_default_features
) {
5705 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features",
5706 orig_default_features
.c_str()));
5709 std::list
<std::pair
<std::string
, std::string
> > feature_names_to_bitmask
= {
5710 {"", orig_default_features
},
5712 {"layering, exclusive-lock", "5"},
5713 {"exclusive-lock,journaling", "68"},
5717 for (auto &pair
: feature_names_to_bitmask
) {
5718 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features", pair
.first
.c_str()));
5719 std::string features
;
5720 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", features
));
5721 ASSERT_EQ(pair
.second
, features
);
5725 TEST_F(TestLibRBD
, TestTrashMoveAndPurge
) {
5726 librados::IoCtx ioctx
;
5727 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5730 std::string name
= get_temp_image_name();
5732 uint64_t size
= 1 << 18;
5734 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5736 librbd::Image image
;
5737 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
5739 ASSERT_EQ(0, image
.old_format(&old_format
));
5742 ASSERT_EQ(-EOPNOTSUPP
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
5746 std::string image_id
;
5747 ASSERT_EQ(0, image
.get_id(&image_id
));
5750 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 0));
5752 std::vector
<std::string
> images
;
5753 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
5754 for (const auto& image
: images
) {
5755 ASSERT_TRUE(image
!= name
);
5758 librbd::trash_image_info_t info
;
5759 ASSERT_EQ(-ENOENT
, rbd
.trash_get(ioctx
, "dummy image id", &info
));
5760 ASSERT_EQ(0, rbd
.trash_get(ioctx
, image_id
.c_str(), &info
));
5761 ASSERT_EQ(image_id
, info
.id
);
5763 std::vector
<librbd::trash_image_info_t
> entries
;
5764 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
5765 ASSERT_FALSE(entries
.empty());
5766 ASSERT_EQ(entries
.begin()->id
, image_id
);
5770 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
5772 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
5773 ASSERT_TRUE(entries
.empty());
5776 TEST_F(TestLibRBD
, TestTrashMoveAndPurgeNonExpiredDelay
) {
5777 librados::IoCtx ioctx
;
5778 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5781 std::string name
= get_temp_image_name();
5783 uint64_t size
= 1 << 18;
5785 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5787 librbd::Image image
;
5788 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
5790 ASSERT_EQ(0, image
.old_format(&old_format
));
5793 ASSERT_EQ(-EOPNOTSUPP
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
5797 std::string image_id
;
5798 ASSERT_EQ(0, image
.get_id(&image_id
));
5801 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 100));
5804 ASSERT_EQ(-EPERM
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
5808 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
5812 TEST_F(TestLibRBD
, TestTrashMoveAndRestore
) {
5813 librados::IoCtx ioctx
;
5814 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5817 std::string name
= get_temp_image_name();
5819 uint64_t size
= 1 << 18;
5821 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5823 librbd::Image image
;
5824 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
5826 ASSERT_EQ(0, image
.old_format(&old_format
));
5829 ASSERT_EQ(-EOPNOTSUPP
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
5833 std::string image_id
;
5834 ASSERT_EQ(0, image
.get_id(&image_id
));
5837 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 10));
5839 std::vector
<std::string
> images
;
5840 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
5841 for (const auto& image
: images
) {
5842 ASSERT_TRUE(image
!= name
);
5845 std::vector
<librbd::trash_image_info_t
> entries
;
5846 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
5847 ASSERT_FALSE(entries
.empty());
5848 ASSERT_EQ(entries
.begin()->id
, image_id
);
5851 ASSERT_EQ(0, rbd
.trash_restore(ioctx
, image_id
.c_str(), ""));
5852 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
5853 ASSERT_FALSE(images
.empty());
5855 for (const auto& image
: images
) {
5856 if (image
== name
) {
5864 // poorman's assert()
5866 void __ceph_assert_fail(const char *assertion
, const char *file
, int line
,