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"
21 #include "include/err.h"
23 #include "gtest/gtest.h"
29 #include <sys/types.h>
35 #include <condition_variable>
43 #include "test/librados/test.h"
44 #include "test/librados/test_cxx.h"
45 #include "test/librbd/test_support.h"
46 #include "common/event_socket.h"
47 #include "include/interval_set.h"
48 #include "include/stringify.h"
50 #include <boost/assign/list_of.hpp>
51 #include <boost/scope_exit.hpp>
54 #include <sys/eventfd.h>
57 #pragma GCC diagnostic ignored "-Wpragmas"
58 #pragma GCC diagnostic push
59 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
63 using std::chrono::seconds
;
65 #define ASSERT_PASSED(x, args...) \
67 bool passed = false; \
69 ASSERT_TRUE(passed); \
72 void register_test_librbd() {
75 static int get_features(bool *old_format
, uint64_t *features
)
77 const char *c
= getenv("RBD_FEATURES");
78 if (c
&& strlen(c
) > 0) {
85 cout
<< "using new format!" << std::endl
;
89 cout
<< "using old format" << std::endl
;
95 static int create_image_full(rados_ioctx_t ioctx
, const char *name
,
96 uint64_t size
, int *order
, int old_format
,
100 // ensure old-format tests actually use the old format
101 int r
= rados_conf_set(rados_ioctx_get_cluster(ioctx
),
102 "rbd_default_format", "1");
106 return rbd_create(ioctx
, name
, size
, order
);
107 } else if ((features
& RBD_FEATURE_STRIPINGV2
) != 0) {
108 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
110 // use a conservative stripe_unit for non default order
111 stripe_unit
= (1ull << (*order
-1));
114 printf("creating image with stripe unit: %" PRIu64
", "
115 "stripe count: %" PRIu64
"\n",
116 stripe_unit
, IMAGE_STRIPE_COUNT
);
117 return rbd_create3(ioctx
, name
, size
, features
, order
,
118 stripe_unit
, IMAGE_STRIPE_COUNT
);
120 return rbd_create2(ioctx
, name
, size
, features
, order
);
124 static int clone_image(rados_ioctx_t p_ioctx
,
125 rbd_image_t p_image
, const char *p_name
,
126 const char *p_snap_name
, rados_ioctx_t c_ioctx
,
127 const char *c_name
, uint64_t features
, int *c_order
)
129 uint64_t stripe_unit
, stripe_count
;
132 r
= rbd_get_stripe_unit(p_image
, &stripe_unit
);
137 r
= rbd_get_stripe_count(p_image
, &stripe_count
);
142 return rbd_clone2(p_ioctx
, p_name
, p_snap_name
, c_ioctx
,
143 c_name
, features
, c_order
, stripe_unit
, stripe_count
);
147 static int create_image(rados_ioctx_t ioctx
, const char *name
,
148 uint64_t size
, int *order
)
153 int r
= get_features(&old_format
, &features
);
156 return create_image_full(ioctx
, name
, size
, order
, old_format
, features
);
159 static int create_image_pp(librbd::RBD
&rbd
,
160 librados::IoCtx
&ioctx
,
162 uint64_t size
, int *order
) {
165 int r
= get_features(&old_format
, &features
);
169 librados::Rados
rados(ioctx
);
170 int r
= rados
.conf_set("rbd_default_format", "1");
174 return rbd
.create(ioctx
, name
, size
, order
);
176 return rbd
.create2(ioctx
, name
, size
, features
, order
);
180 class TestLibRBD
: public ::testing::Test
{
183 TestLibRBD() : m_pool_number() {
186 static void SetUpTestCase() {
188 _unique_pool_names
.clear();
190 ASSERT_EQ("", connect_cluster(&_cluster
));
191 ASSERT_EQ("", connect_cluster_pp(_rados
));
193 create_optional_data_pool();
196 static void TearDownTestCase() {
197 rados_shutdown(_cluster
);
198 _rados
.wait_for_latest_osdmap();
199 _pool_names
.insert(_pool_names
.end(), _unique_pool_names
.begin(),
200 _unique_pool_names
.end());
201 for (size_t i
= 1; i
< _pool_names
.size(); ++i
) {
202 ASSERT_EQ(0, _rados
.pool_delete(_pool_names
[i
].c_str()));
204 if (!_pool_names
.empty()) {
205 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names
[0], _rados
));
209 void SetUp() override
{
210 ASSERT_NE("", m_pool_name
= create_pool());
213 bool is_skip_partial_discard_enabled() {
215 EXPECT_EQ(0, _rados
.conf_get("rbd_skip_partial_discard", value
));
216 return value
== "true";
219 void validate_object_map(rbd_image_t image
, bool *passed
) {
221 ASSERT_EQ(0, rbd_get_flags(image
, &flags
));
222 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
225 void validate_object_map(librbd::Image
&image
, bool *passed
) {
227 ASSERT_EQ(0, image
.get_flags(&flags
));
228 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
231 static std::string
get_temp_image_name() {
233 return "image" + stringify(_image_number
);
236 static void create_optional_data_pool() {
237 bool created
= false;
238 std::string data_pool
;
239 ASSERT_EQ(0, create_image_data_pool(_rados
, data_pool
, &created
));
240 if (!data_pool
.empty()) {
241 printf("using image data pool: %s\n", data_pool
.c_str());
243 _unique_pool_names
.push_back(data_pool
);
248 std::string
create_pool(bool unique
= false) {
249 librados::Rados rados
;
250 std::string pool_name
;
252 pool_name
= get_temp_pool_name("test-librbd-");
253 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
254 _unique_pool_names
.push_back(pool_name
);
255 } else if (m_pool_number
< _pool_names
.size()) {
256 pool_name
= _pool_names
[m_pool_number
];
258 pool_name
= get_temp_pool_name("test-librbd-");
259 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
260 _pool_names
.push_back(pool_name
);
266 static std::vector
<std::string
> _pool_names
;
267 static std::vector
<std::string
> _unique_pool_names
;
268 static rados_t _cluster
;
269 static librados::Rados _rados
;
270 static uint64_t _image_number
;
272 std::string m_pool_name
;
273 uint32_t m_pool_number
;
277 std::vector
<std::string
> TestLibRBD::_pool_names
;
278 std::vector
<std::string
> TestLibRBD::_unique_pool_names
;
279 rados_t
TestLibRBD::_cluster
;
280 librados::Rados
TestLibRBD::_rados
;
281 uint64_t TestLibRBD::_image_number
= 0;
283 TEST_F(TestLibRBD
, CreateAndStat
)
286 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
288 rbd_image_info_t info
;
291 std::string name
= get_temp_image_name();
292 uint64_t size
= 2 << 20;
294 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
295 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
296 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
297 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
298 ASSERT_EQ(info
.size
, size
);
299 ASSERT_EQ(info
.order
, order
);
300 ASSERT_EQ(0, rbd_close(image
));
302 rados_ioctx_destroy(ioctx
);
305 TEST_F(TestLibRBD
, CreateWithSameDataPool
)
310 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
313 std::string name
= get_temp_image_name();
314 uint64_t size
= 2 << 20;
318 ASSERT_EQ(0, get_features(&old_format
, &features
));
319 ASSERT_FALSE(old_format
);
321 rbd_image_options_t image_options
;
322 rbd_image_options_create(&image_options
);
323 BOOST_SCOPE_EXIT( (&image_options
) ) {
324 rbd_image_options_destroy(image_options
);
325 } BOOST_SCOPE_EXIT_END
;
327 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
328 RBD_IMAGE_OPTION_FEATURES
,
330 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
331 RBD_IMAGE_OPTION_DATA_POOL
,
332 m_pool_name
.c_str()));
334 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
335 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
337 ASSERT_EQ(0, rbd_close(image
));
339 rados_ioctx_destroy(ioctx
);
342 TEST_F(TestLibRBD
, CreateAndStatPP
)
344 librados::IoCtx ioctx
;
345 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
349 librbd::image_info_t info
;
352 std::string name
= get_temp_image_name();
353 uint64_t size
= 2 << 20;
355 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
356 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
357 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
358 ASSERT_EQ(info
.size
, size
);
359 ASSERT_EQ(info
.order
, order
);
365 TEST_F(TestLibRBD
, GetId
)
368 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
372 std::string name
= get_temp_image_name();
374 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
375 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
378 if (!is_feature_enabled(0)) {
380 ASSERT_EQ(-EINVAL
, rbd_get_id(image
, id
, sizeof(id
)));
382 ASSERT_EQ(-ERANGE
, rbd_get_id(image
, id
, 0));
383 ASSERT_EQ(0, rbd_get_id(image
, id
, sizeof(id
)));
384 ASSERT_LT(0U, strlen(id
));
386 ASSERT_EQ(0, rbd_close(image
));
387 ASSERT_EQ(0, rbd_open_by_id(ioctx
, id
, &image
, NULL
));
389 ASSERT_EQ(-ERANGE
, rbd_get_name(image
, NULL
, &name_len
));
390 ASSERT_EQ(name_len
, name
.size() + 1);
391 char image_name
[name_len
];
392 ASSERT_EQ(0, rbd_get_name(image
, image_name
, &name_len
));
393 ASSERT_STREQ(name
.c_str(), image_name
);
396 ASSERT_EQ(0, rbd_close(image
));
397 rados_ioctx_destroy(ioctx
);
400 TEST_F(TestLibRBD
, GetIdPP
)
402 librados::IoCtx ioctx
;
403 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
408 std::string name
= get_temp_image_name();
411 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
412 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
413 if (!is_feature_enabled(0)) {
415 ASSERT_EQ(-EINVAL
, image
.get_id(&id
));
417 ASSERT_EQ(0, image
.get_id(&id
));
418 ASSERT_LT(0U, id
.size());
420 ASSERT_EQ(0, image
.close());
421 ASSERT_EQ(0, rbd
.open_by_id(ioctx
, image
, id
.c_str(), NULL
));
422 std::string image_name
;
423 ASSERT_EQ(0, image
.get_name(&image_name
));
424 ASSERT_EQ(name
, image_name
);
428 TEST_F(TestLibRBD
, GetBlockNamePrefix
)
431 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
435 std::string name
= get_temp_image_name();
437 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
438 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
441 ASSERT_EQ(-ERANGE
, rbd_get_block_name_prefix(image
, prefix
, 0));
442 ASSERT_EQ(0, rbd_get_block_name_prefix(image
, prefix
, sizeof(prefix
)));
443 ASSERT_LT(0U, strlen(prefix
));
445 ASSERT_EQ(0, rbd_close(image
));
446 rados_ioctx_destroy(ioctx
);
449 TEST_F(TestLibRBD
, GetBlockNamePrefixPP
)
451 librados::IoCtx ioctx
;
452 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
457 std::string name
= get_temp_image_name();
459 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
460 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
461 ASSERT_LT(0U, image
.get_block_name_prefix().size());
464 TEST_F(TestLibRBD
, TestGetCreateTimestamp
)
469 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
473 std::string name
= get_temp_image_name();
475 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
476 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
478 struct timespec timestamp
;
479 ASSERT_EQ(0, rbd_get_create_timestamp(image
, ×tamp
));
480 ASSERT_LT(0, timestamp
.tv_sec
);
482 ASSERT_EQ(0, rbd_close(image
));
484 rados_ioctx_destroy(ioctx
);
487 TEST_F(TestLibRBD
, GetCreateTimestampPP
)
491 librados::IoCtx ioctx
;
492 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
497 std::string name
= get_temp_image_name();
499 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
500 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
502 struct timespec timestamp
;
503 ASSERT_EQ(0, image
.get_create_timestamp(×tamp
));
504 ASSERT_LT(0, timestamp
.tv_sec
);
507 TEST_F(TestLibRBD
, OpenAio
)
510 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
512 rbd_image_info_t info
;
515 std::string name
= get_temp_image_name();
516 uint64_t size
= 2 << 20;
518 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
520 rbd_completion_t open_comp
;
521 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
522 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
523 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
524 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
525 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp
));
526 rbd_aio_release(open_comp
);
528 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
529 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
530 ASSERT_EQ(info
.size
, size
);
531 ASSERT_EQ(info
.order
, order
);
533 rbd_completion_t close_comp
;
534 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &close_comp
));
535 ASSERT_EQ(0, rbd_aio_close(image
, close_comp
));
536 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp
));
537 ASSERT_EQ(1, rbd_aio_is_complete(close_comp
));
538 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp
));
539 rbd_aio_release(close_comp
);
541 rados_ioctx_destroy(ioctx
);
544 TEST_F(TestLibRBD
, OpenAioFail
)
547 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
549 std::string name
= get_temp_image_name();
551 rbd_completion_t open_comp
;
552 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
553 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
554 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
555 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
556 ASSERT_EQ(-ENOENT
, rbd_aio_get_return_value(open_comp
));
557 rbd_aio_release(open_comp
);
559 rados_ioctx_destroy(ioctx
);
562 TEST_F(TestLibRBD
, OpenAioPP
)
564 librados::IoCtx ioctx
;
565 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
568 librbd::image_info_t info
;
571 std::string name
= get_temp_image_name();
572 uint64_t size
= 2 << 20;
574 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
576 librbd::RBD::AioCompletion
*open_comp
=
577 new librbd::RBD::AioCompletion(NULL
, NULL
);
578 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
579 ASSERT_EQ(0, open_comp
->wait_for_complete());
580 ASSERT_EQ(1, open_comp
->is_complete());
581 ASSERT_EQ(0, open_comp
->get_return_value());
582 open_comp
->release();
584 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
585 ASSERT_EQ(info
.size
, size
);
586 ASSERT_EQ(info
.order
, order
);
589 open_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
590 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
591 ASSERT_EQ(0, open_comp
->wait_for_complete());
592 ASSERT_EQ(1, open_comp
->is_complete());
593 ASSERT_EQ(0, open_comp
->get_return_value());
594 open_comp
->release();
597 librbd::RBD::AioCompletion
*close_comp
=
598 new librbd::RBD::AioCompletion(NULL
, NULL
);
599 ASSERT_EQ(0, image
.aio_close(close_comp
));
600 ASSERT_EQ(0, close_comp
->wait_for_complete());
601 ASSERT_EQ(1, close_comp
->is_complete());
602 ASSERT_EQ(0, close_comp
->get_return_value());
603 close_comp
->release();
605 // close closed image
606 close_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
607 ASSERT_EQ(-EINVAL
, image
.aio_close(close_comp
));
608 close_comp
->release();
613 TEST_F(TestLibRBD
, OpenAioFailPP
)
615 librados::IoCtx ioctx
;
616 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
621 std::string name
= get_temp_image_name();
623 librbd::RBD::AioCompletion
*open_comp
=
624 new librbd::RBD::AioCompletion(NULL
, NULL
);
625 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
626 ASSERT_EQ(0, open_comp
->wait_for_complete());
627 ASSERT_EQ(1, open_comp
->is_complete());
628 ASSERT_EQ(-ENOENT
, open_comp
->get_return_value());
629 open_comp
->release();
635 TEST_F(TestLibRBD
, ResizeAndStat
)
638 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
640 rbd_image_info_t info
;
643 std::string name
= get_temp_image_name();
644 uint64_t size
= 2 << 20;
646 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
647 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
649 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
650 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
651 ASSERT_EQ(info
.size
, size
* 4);
653 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
654 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
655 ASSERT_EQ(info
.size
, size
/ 2);
657 // downsizing without allowing shrink should fail
658 // and image size should not change
659 ASSERT_EQ(-EINVAL
, rbd_resize2(image
, size
/ 4, false, NULL
, NULL
));
660 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
661 ASSERT_EQ(info
.size
, size
/ 2);
663 ASSERT_EQ(0, rbd_resize2(image
, size
/ 4, true, NULL
, NULL
));
664 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
665 ASSERT_EQ(info
.size
, size
/ 4);
667 ASSERT_PASSED(validate_object_map
, image
);
668 ASSERT_EQ(0, rbd_close(image
));
670 rados_ioctx_destroy(ioctx
);
673 TEST_F(TestLibRBD
, ResizeAndStatPP
)
675 librados::IoCtx ioctx
;
676 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
680 librbd::image_info_t info
;
683 std::string name
= get_temp_image_name();
684 uint64_t size
= 2 << 20;
686 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
687 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
689 ASSERT_EQ(0, image
.resize(size
* 4));
690 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
691 ASSERT_EQ(info
.size
, size
* 4);
693 ASSERT_EQ(0, image
.resize(size
/ 2));
694 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
695 ASSERT_EQ(info
.size
, size
/ 2);
696 ASSERT_PASSED(validate_object_map
, image
);
702 TEST_F(TestLibRBD
, UpdateWatchAndResize
)
705 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
709 std::string name
= get_temp_image_name();
710 uint64_t size
= 2 << 20;
712 rbd_image_t
&m_image
;
714 condition_variable m_cond
;
716 static void cb(void *arg
) {
717 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
718 watcher
->handle_notify();
720 explicit Watcher(rbd_image_t
&image
) : m_image(image
) {}
721 void handle_notify() {
722 rbd_image_info_t info
;
723 ASSERT_EQ(0, rbd_stat(m_image
, &info
, sizeof(info
)));
724 lock_guard
<mutex
> locker(m_lock
);
728 void wait_for_size(size_t size
) {
729 unique_lock
<mutex
> locker(m_lock
);
730 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
732 return this->m_size
== size
;}));
737 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
738 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
740 ASSERT_EQ(0, rbd_update_watch(image
, &handle
, Watcher::cb
, &watcher
));
742 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
743 watcher
.wait_for_size(size
* 4);
745 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
746 watcher
.wait_for_size(size
/ 2);
748 ASSERT_EQ(0, rbd_update_unwatch(image
, handle
));
750 ASSERT_EQ(0, rbd_close(image
));
751 rados_ioctx_destroy(ioctx
);
754 TEST_F(TestLibRBD
, UpdateWatchAndResizePP
)
756 librados::IoCtx ioctx
;
757 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
763 std::string name
= get_temp_image_name();
764 uint64_t size
= 2 << 20;
765 struct Watcher
: public librbd::UpdateWatchCtx
{
766 explicit Watcher(librbd::Image
&image
) : m_image(image
) {
768 void handle_notify() override
{
769 librbd::image_info_t info
;
770 ASSERT_EQ(0, m_image
.stat(info
, sizeof(info
)));
771 lock_guard
<mutex
> locker(m_lock
);
775 void wait_for_size(size_t size
) {
776 unique_lock
<mutex
> locker(m_lock
);
777 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
779 return this->m_size
== size
;}));
781 librbd::Image
&m_image
;
783 condition_variable m_cond
;
788 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
789 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
791 ASSERT_EQ(0, image
.update_watch(&watcher
, &handle
));
793 ASSERT_EQ(0, image
.resize(size
* 4));
794 watcher
.wait_for_size(size
* 4);
796 ASSERT_EQ(0, image
.resize(size
/ 2));
797 watcher
.wait_for_size(size
/ 2);
799 ASSERT_EQ(0, image
.update_unwatch(handle
));
805 int test_ls(rados_ioctx_t io_ctx
, size_t num_expected
, ...)
808 char *names
, *cur_name
;
810 size_t max_size
= 1024;
812 names
= (char *) malloc(sizeof(char) * 1024);
813 int len
= rbd_list(io_ctx
, names
, &max_size
);
815 std::set
<std::string
> image_names
;
816 for (i
= 0, num_images
= 0, cur_name
= names
; cur_name
< names
+ len
; i
++) {
817 printf("image: %s\n", cur_name
);
818 image_names
.insert(cur_name
);
819 cur_name
+= strlen(cur_name
) + 1;
824 va_start(ap
, num_expected
);
825 for (i
= num_expected
; i
> 0; i
--) {
826 char *expected
= va_arg(ap
, char *);
827 printf("expected = %s\n", expected
);
828 std::set
<std::string
>::iterator it
= image_names
.find(expected
);
829 if (it
!= image_names
.end()) {
830 printf("found %s\n", expected
);
831 image_names
.erase(it
);
832 printf("erased %s\n", expected
);
834 ADD_FAILURE() << "Unable to find image " << expected
;
841 if (!image_names
.empty()) {
842 ADD_FAILURE() << "Unexpected images discovered";
848 TEST_F(TestLibRBD
, TestCreateLsDelete
)
851 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
854 std::string name
= get_temp_image_name();
855 std::string name2
= get_temp_image_name();
856 uint64_t size
= 2 << 20;
858 ASSERT_EQ(0, test_ls(ioctx
, 0));
859 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
860 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
861 ASSERT_EQ(0, create_image(ioctx
, name2
.c_str(), size
, &order
));
862 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
863 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
864 ASSERT_EQ(1, test_ls(ioctx
, 1, name2
.c_str()));
866 ASSERT_EQ(-ENOENT
, rbd_remove(ioctx
, name
.c_str()));
868 rados_ioctx_destroy(ioctx
);
871 int test_ls_pp(librbd::RBD
& rbd
, librados::IoCtx
& io_ctx
, size_t num_expected
, ...)
876 vector
<string
> names
;
877 r
= rbd
.list(io_ctx
, names
);
881 cout
<< "num images is: " << names
.size() << std::endl
882 << "expected: " << num_expected
<< std::endl
;
883 int num
= names
.size();
885 for (i
= 0; i
< names
.size(); i
++) {
886 cout
<< "image: " << names
[i
] << std::endl
;
889 va_start(ap
, num_expected
);
890 for (i
= num_expected
; i
> 0; i
--) {
891 char *expected
= va_arg(ap
, char *);
892 cout
<< "expected = " << expected
<< std::endl
;
893 vector
<string
>::iterator listed_name
= find(names
.begin(), names
.end(), string(expected
));
894 if (listed_name
== names
.end()) {
895 ADD_FAILURE() << "Unable to find image " << expected
;
899 names
.erase(listed_name
);
903 if (!names
.empty()) {
904 ADD_FAILURE() << "Unexpected images discovered";
910 TEST_F(TestLibRBD
, TestCreateLsDeletePP
)
912 librados::IoCtx ioctx
;
913 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
919 std::string name
= get_temp_image_name();
920 std::string name2
= get_temp_image_name();
921 uint64_t size
= 2 << 20;
923 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
924 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
925 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
926 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
927 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
928 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name2
.c_str()));
935 static int print_progress_percent(uint64_t offset
, uint64_t src_size
,
938 float percent
= ((float)offset
* 100) / src_size
;
939 printf("%3.2f%% done\n", percent
);
943 TEST_F(TestLibRBD
, TestCopy
)
946 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
952 std::string name
= get_temp_image_name();
953 std::string name2
= get_temp_image_name();
954 std::string name3
= get_temp_image_name();
956 uint64_t size
= 2 << 20;
958 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
959 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
960 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
962 size_t sum_key_len
= 0;
963 size_t sum_value_len
= 0;
966 for (int i
= 1; i
<= 70; i
++) {
967 key
= "key" + stringify(i
);
968 val
= "value" + stringify(i
);
969 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
971 sum_key_len
+= (key
.size() + 1);
972 sum_value_len
+= (val
.size() + 1);
977 size_t keys_len
= sizeof(keys
);
978 size_t vals_len
= sizeof(vals
);
981 size_t value_len
= sizeof(value
);
983 ASSERT_EQ(0, rbd_copy(image
, ioctx
, name2
.c_str()));
984 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
985 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
986 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 70, keys
, &keys_len
, vals
,
988 ASSERT_EQ(keys_len
, sum_key_len
);
989 ASSERT_EQ(vals_len
, sum_value_len
);
991 for (int i
= 1; i
<= 70; i
++) {
992 key
= "key" + stringify(i
);
993 val
= "value" + stringify(i
);
994 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
995 ASSERT_STREQ(val
.c_str(), value
);
997 value_len
= sizeof(value
);
1000 ASSERT_EQ(0, rbd_copy_with_progress(image
, ioctx
, name3
.c_str(),
1001 print_progress_percent
, NULL
));
1002 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1004 keys_len
= sizeof(keys
);
1005 vals_len
= sizeof(vals
);
1006 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1007 ASSERT_EQ(0, rbd_metadata_list(image3
, "", 70, keys
, &keys_len
, vals
,
1009 ASSERT_EQ(keys_len
, sum_key_len
);
1010 ASSERT_EQ(vals_len
, sum_value_len
);
1012 for (int i
= 1; i
<= 70; i
++) {
1013 key
= "key" + stringify(i
);
1014 val
= "value" + stringify(i
);
1015 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1016 ASSERT_STREQ(val
.c_str(), value
);
1018 value_len
= sizeof(value
);
1021 ASSERT_EQ(0, rbd_close(image
));
1022 ASSERT_EQ(0, rbd_close(image2
));
1023 ASSERT_EQ(0, rbd_close(image3
));
1024 rados_ioctx_destroy(ioctx
);
1027 class PrintProgress
: public librbd::ProgressContext
1030 int update_progress(uint64_t offset
, uint64_t src_size
) override
1032 float percent
= ((float)offset
* 100) / src_size
;
1033 printf("%3.2f%% done\n", percent
);
1038 TEST_F(TestLibRBD
, TestCopyPP
)
1040 librados::IoCtx ioctx
;
1041 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1045 librbd::Image image
;
1046 librbd::Image image2
;
1047 librbd::Image image3
;
1049 std::string name
= get_temp_image_name();
1050 std::string name2
= get_temp_image_name();
1051 std::string name3
= get_temp_image_name();
1052 uint64_t size
= 2 << 20;
1055 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1056 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1060 for (int i
= 1; i
<= 70; i
++) {
1061 key
= "key" + stringify(i
);
1062 val
= "value" + stringify(i
);
1063 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1066 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1067 ASSERT_EQ(0, image
.copy(ioctx
, name2
.c_str()));
1068 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1069 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1071 map
<string
, bufferlist
> pairs
;
1073 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1074 ASSERT_EQ(70U, pairs
.size());
1076 for (int i
= 1; i
<= 70; i
++) {
1077 key
= "key" + stringify(i
);
1078 val
= "value" + stringify(i
);
1079 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1080 ASSERT_STREQ(val
.c_str(), value
.c_str());
1083 ASSERT_EQ(0, image
.copy_with_progress(ioctx
, name3
.c_str(), pp
));
1084 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1086 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1089 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1090 ASSERT_EQ(70U, pairs
.size());
1092 for (int i
= 1; i
<= 70; i
++) {
1093 key
= "key" + stringify(i
);
1094 val
= "value" + stringify(i
);
1095 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1096 ASSERT_STREQ(val
.c_str(), value
.c_str());
1103 TEST_F(TestLibRBD
, TestDeepCopy
)
1105 REQUIRE_FORMAT_V2();
1106 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1108 rados_ioctx_t ioctx
;
1109 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1110 BOOST_SCOPE_EXIT_ALL( (&ioctx
) ) {
1111 rados_ioctx_destroy(ioctx
);
1121 std::string name
= get_temp_image_name();
1122 std::string name2
= get_temp_image_name();
1123 std::string name3
= get_temp_image_name();
1124 std::string name4
= get_temp_image_name();
1125 std::string name5
= get_temp_image_name();
1126 std::string name6
= get_temp_image_name();
1128 uint64_t size
= 2 << 20;
1130 rbd_image_options_t opts
;
1131 rbd_image_options_create(&opts
);
1132 BOOST_SCOPE_EXIT_ALL( (&opts
) ) {
1133 rbd_image_options_destroy(opts
);
1136 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1137 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1138 BOOST_SCOPE_EXIT_ALL( (&image
) ) {
1139 ASSERT_EQ(0, rbd_close(image
));
1141 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1143 size_t sum_key_len
= 0;
1144 size_t sum_value_len
= 0;
1147 for (int i
= 1; i
<= 70; i
++) {
1148 key
= "key" + stringify(i
);
1149 val
= "value" + stringify(i
);
1150 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
1152 sum_key_len
+= (key
.size() + 1);
1153 sum_value_len
+= (val
.size() + 1);
1158 size_t keys_len
= sizeof(keys
);
1159 size_t vals_len
= sizeof(vals
);
1162 size_t value_len
= sizeof(value
);
1164 ASSERT_EQ(0, rbd_deep_copy(image
, ioctx
, name2
.c_str(), opts
));
1165 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1166 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
1167 BOOST_SCOPE_EXIT_ALL( (&image2
) ) {
1168 ASSERT_EQ(0, rbd_close(image2
));
1170 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 70, keys
, &keys_len
, vals
,
1172 ASSERT_EQ(keys_len
, sum_key_len
);
1173 ASSERT_EQ(vals_len
, sum_value_len
);
1175 for (int i
= 1; i
<= 70; i
++) {
1176 key
= "key" + stringify(i
);
1177 val
= "value" + stringify(i
);
1178 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
1179 ASSERT_STREQ(val
.c_str(), value
);
1181 value_len
= sizeof(value
);
1184 ASSERT_EQ(0, rbd_deep_copy_with_progress(image
, ioctx
, name3
.c_str(), opts
,
1185 print_progress_percent
, NULL
));
1186 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1188 keys_len
= sizeof(keys
);
1189 vals_len
= sizeof(vals
);
1190 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1191 BOOST_SCOPE_EXIT_ALL( (&image3
) ) {
1192 ASSERT_EQ(0, rbd_close(image3
));
1194 ASSERT_EQ(0, rbd_metadata_list(image3
, "", 70, keys
, &keys_len
, vals
,
1196 ASSERT_EQ(keys_len
, sum_key_len
);
1197 ASSERT_EQ(vals_len
, sum_value_len
);
1199 for (int i
= 1; i
<= 70; i
++) {
1200 key
= "key" + stringify(i
);
1201 val
= "value" + stringify(i
);
1202 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1203 ASSERT_STREQ(val
.c_str(), value
);
1205 value_len
= sizeof(value
);
1208 ASSERT_EQ(0, rbd_snap_create(image
, "deep_snap"));
1209 ASSERT_EQ(0, rbd_close(image
));
1210 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, "deep_snap"));
1211 ASSERT_EQ(0, rbd_snap_protect(image
, "deep_snap"));
1212 ASSERT_EQ(0, rbd_clone3(ioctx
, name
.c_str(), "deep_snap", ioctx
,
1213 name4
.c_str(), opts
));
1215 ASSERT_EQ(4, test_ls(ioctx
, 4, name
.c_str(), name2
.c_str(), name3
.c_str(),
1217 ASSERT_EQ(0, rbd_open(ioctx
, name4
.c_str(), &image4
, NULL
));
1218 BOOST_SCOPE_EXIT_ALL( (&image4
) ) {
1219 ASSERT_EQ(0, rbd_close(image4
));
1221 ASSERT_EQ(0, rbd_snap_create(image4
, "deep_snap"));
1223 ASSERT_EQ(0, rbd_deep_copy(image4
, ioctx
, name5
.c_str(), opts
));
1224 ASSERT_EQ(5, test_ls(ioctx
, 5, name
.c_str(), name2
.c_str(), name3
.c_str(),
1225 name4
.c_str(), name5
.c_str()));
1226 ASSERT_EQ(0, rbd_open(ioctx
, name5
.c_str(), &image5
, NULL
));
1227 BOOST_SCOPE_EXIT_ALL( (&image5
) ) {
1228 ASSERT_EQ(0, rbd_close(image5
));
1230 ASSERT_EQ(0, rbd_metadata_list(image5
, "", 70, keys
, &keys_len
, vals
,
1232 ASSERT_EQ(keys_len
, sum_key_len
);
1233 ASSERT_EQ(vals_len
, sum_value_len
);
1235 for (int i
= 1; i
<= 70; i
++) {
1236 key
= "key" + stringify(i
);
1237 val
= "value" + stringify(i
);
1238 ASSERT_EQ(0, rbd_metadata_get(image5
, key
.c_str(), value
, &value_len
));
1239 ASSERT_STREQ(val
.c_str(), value
);
1241 value_len
= sizeof(value
);
1244 ASSERT_EQ(0, rbd_deep_copy_with_progress(image4
, ioctx
, name6
.c_str(), opts
,
1245 print_progress_percent
, NULL
));
1246 ASSERT_EQ(6, test_ls(ioctx
, 6, name
.c_str(), name2
.c_str(), name3
.c_str(),
1247 name4
.c_str(), name5
.c_str(), name6
.c_str()));
1249 keys_len
= sizeof(keys
);
1250 vals_len
= sizeof(vals
);
1251 ASSERT_EQ(0, rbd_open(ioctx
, name6
.c_str(), &image6
, NULL
));
1252 BOOST_SCOPE_EXIT_ALL( (&image6
) ) {
1253 ASSERT_EQ(0, rbd_close(image6
));
1255 ASSERT_EQ(0, rbd_metadata_list(image6
, "", 70, keys
, &keys_len
, vals
,
1257 ASSERT_EQ(keys_len
, sum_key_len
);
1258 ASSERT_EQ(vals_len
, sum_value_len
);
1260 for (int i
= 1; i
<= 70; i
++) {
1261 key
= "key" + stringify(i
);
1262 val
= "value" + stringify(i
);
1263 ASSERT_EQ(0, rbd_metadata_get(image6
, key
.c_str(), value
, &value_len
));
1264 ASSERT_STREQ(val
.c_str(), value
);
1266 value_len
= sizeof(value
);
1270 TEST_F(TestLibRBD
, TestDeepCopyPP
)
1272 REQUIRE_FORMAT_V2();
1274 librados::IoCtx ioctx
;
1275 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1279 librbd::Image image
;
1280 librbd::Image image2
;
1281 librbd::Image image3
;
1283 std::string name
= get_temp_image_name();
1284 std::string name2
= get_temp_image_name();
1285 std::string name3
= get_temp_image_name();
1286 uint64_t size
= 2 << 20;
1287 librbd::ImageOptions opts
;
1290 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1291 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1295 for (int i
= 1; i
<= 70; i
++) {
1296 key
= "key" + stringify(i
);
1297 val
= "value" + stringify(i
);
1298 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1301 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1302 ASSERT_EQ(0, image
.deep_copy(ioctx
, name2
.c_str(), opts
));
1303 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1304 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1306 map
<string
, bufferlist
> pairs
;
1308 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1309 ASSERT_EQ(70U, pairs
.size());
1311 for (int i
= 1; i
<= 70; i
++) {
1312 key
= "key" + stringify(i
);
1313 val
= "value" + stringify(i
);
1314 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1315 ASSERT_STREQ(val
.c_str(), value
.c_str());
1318 ASSERT_EQ(0, image
.deep_copy_with_progress(ioctx
, name3
.c_str(), opts
, pp
));
1319 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1321 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1324 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1325 ASSERT_EQ(70U, pairs
.size());
1327 for (int i
= 1; i
<= 70; i
++) {
1328 key
= "key" + stringify(i
);
1329 val
= "value" + stringify(i
);
1330 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1331 ASSERT_STREQ(val
.c_str(), value
.c_str());
1338 int test_ls_snaps(rbd_image_t image
, int num_expected
, ...)
1340 int num_snaps
, i
, j
, max_size
= 10;
1342 rbd_snap_info_t snaps
[max_size
];
1343 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1344 printf("num snaps is: %d\nexpected: %d\n", num_snaps
, num_expected
);
1346 for (i
= 0; i
< num_snaps
; i
++) {
1347 printf("snap: %s\n", snaps
[i
].name
);
1350 va_start(ap
, num_expected
);
1351 for (i
= num_expected
; i
> 0; i
--) {
1352 char *expected
= va_arg(ap
, char *);
1353 uint64_t expected_size
= va_arg(ap
, uint64_t);
1355 for (j
= 0; j
< num_snaps
; j
++) {
1356 if (snaps
[j
].name
== NULL
)
1358 if (strcmp(snaps
[j
].name
, expected
) == 0) {
1359 printf("found %s with size %llu\n", snaps
[j
].name
, (unsigned long long) snaps
[j
].size
);
1360 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1361 free((void *) snaps
[j
].name
);
1362 snaps
[j
].name
= NULL
;
1371 for (i
= 0; i
< num_snaps
; i
++) {
1372 EXPECT_EQ((const char *)0, snaps
[i
].name
);
1378 TEST_F(TestLibRBD
, TestCreateLsDeleteSnap
)
1380 rados_ioctx_t ioctx
;
1381 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1385 std::string name
= get_temp_image_name();
1386 uint64_t size
= 2 << 20;
1387 uint64_t size2
= 4 << 20;
1389 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1390 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1392 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1393 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1394 ASSERT_EQ(0, rbd_resize(image
, size2
));
1395 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1396 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1397 ASSERT_EQ(0, rbd_snap_remove(image
, "snap1"));
1398 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1399 ASSERT_EQ(0, rbd_snap_remove(image
, "snap2"));
1400 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1402 ASSERT_EQ(0, rbd_close(image
));
1404 rados_ioctx_destroy(ioctx
);
1407 int test_get_snapshot_timestamp(rbd_image_t image
, uint64_t snap_id
)
1409 struct timespec timestamp
;
1410 EXPECT_EQ(0, rbd_snap_get_timestamp(image
, snap_id
, ×tamp
));
1411 EXPECT_LT(0, timestamp
.tv_sec
);
1415 TEST_F(TestLibRBD
, TestGetSnapShotTimeStamp
)
1417 REQUIRE_FORMAT_V2();
1419 rados_ioctx_t ioctx
;
1420 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1424 std::string name
= get_temp_image_name();
1425 uint64_t size
= 2 << 20;
1426 int num_snaps
, max_size
= 10;
1427 rbd_snap_info_t snaps
[max_size
];
1429 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1430 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1432 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1433 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1434 ASSERT_EQ(1, num_snaps
);
1435 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1436 free((void *)snaps
[0].name
);
1438 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1439 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1440 ASSERT_EQ(2, num_snaps
);
1441 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1442 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[1].id
));
1443 free((void *)snaps
[0].name
);
1444 free((void *)snaps
[1].name
);
1446 ASSERT_EQ(0, rbd_close(image
));
1448 rados_ioctx_destroy(ioctx
);
1452 int test_ls_snaps(librbd::Image
& image
, size_t num_expected
, ...)
1457 vector
<librbd::snap_info_t
> snaps
;
1458 r
= image
.snap_list(snaps
);
1459 EXPECT_TRUE(r
>= 0);
1460 cout
<< "num snaps is: " << snaps
.size() << std::endl
1461 << "expected: " << num_expected
<< std::endl
;
1463 for (i
= 0; i
< snaps
.size(); i
++) {
1464 cout
<< "snap: " << snaps
[i
].name
<< std::endl
;
1467 va_start(ap
, num_expected
);
1468 for (i
= num_expected
; i
> 0; i
--) {
1469 char *expected
= va_arg(ap
, char *);
1470 uint64_t expected_size
= va_arg(ap
, uint64_t);
1472 for (j
= 0; j
< snaps
.size(); j
++) {
1473 if (snaps
[j
].name
== "")
1475 if (strcmp(snaps
[j
].name
.c_str(), expected
) == 0) {
1476 cout
<< "found " << snaps
[j
].name
<< " with size " << snaps
[j
].size
1478 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1488 for (i
= 0; i
< snaps
.size(); i
++) {
1489 EXPECT_EQ("", snaps
[i
].name
);
1492 return snaps
.size();
1495 TEST_F(TestLibRBD
, TestCreateLsDeleteSnapPP
)
1497 librados::IoCtx ioctx
;
1498 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1502 librbd::Image image
;
1504 std::string name
= get_temp_image_name();
1505 uint64_t size
= 2 << 20;
1506 uint64_t size2
= 4 << 20;
1508 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1509 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1512 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1513 ASSERT_FALSE(exists
);
1514 ASSERT_EQ(0, image
.snap_create("snap1"));
1515 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1516 ASSERT_TRUE(exists
);
1517 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1518 ASSERT_EQ(0, image
.resize(size2
));
1519 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1520 ASSERT_FALSE(exists
);
1521 ASSERT_EQ(0, image
.snap_create("snap2"));
1522 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1523 ASSERT_TRUE(exists
);
1524 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1525 ASSERT_EQ(0, image
.snap_remove("snap1"));
1526 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1527 ASSERT_FALSE(exists
);
1528 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1529 ASSERT_EQ(0, image
.snap_remove("snap2"));
1530 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1531 ASSERT_FALSE(exists
);
1532 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1538 TEST_F(TestLibRBD
, TestGetNameIdSnapPP
)
1540 librados::IoCtx ioctx
;
1541 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1545 librbd::Image image
;
1547 std::string name
= get_temp_image_name();
1548 uint64_t size
= 2 << 20;
1550 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1551 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1553 ASSERT_EQ(0, image
.snap_create("snap1"));
1554 ASSERT_EQ(0, image
.snap_create("snap2"));
1555 ASSERT_EQ(0, image
.snap_create("snap3"));
1556 vector
<librbd::snap_info_t
> snaps
;
1557 int r
= image
.snap_list(snaps
);
1558 EXPECT_TRUE(r
>= 0);
1560 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
1561 std::string expected_snap_name
;
1562 image
.snap_get_name(snaps
[i
].id
, &expected_snap_name
);
1563 ASSERT_EQ(expected_snap_name
, snaps
[i
].name
);
1566 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
1567 uint64_t expected_snap_id
;
1568 image
.snap_get_id(snaps
[i
].name
, &expected_snap_id
);
1569 ASSERT_EQ(expected_snap_id
, snaps
[i
].id
);
1572 ASSERT_EQ(0, image
.snap_remove("snap1"));
1573 ASSERT_EQ(0, image
.snap_remove("snap2"));
1574 ASSERT_EQ(0, image
.snap_remove("snap3"));
1575 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1581 TEST_F(TestLibRBD
, TestCreateLsRenameSnapPP
)
1583 librados::IoCtx ioctx
;
1584 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1588 librbd::Image image
;
1590 std::string name
= get_temp_image_name();
1591 uint64_t size
= 2 << 20;
1592 uint64_t size2
= 4 << 20;
1594 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1595 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1598 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1599 ASSERT_FALSE(exists
);
1600 ASSERT_EQ(0, image
.snap_create("snap1"));
1601 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1602 ASSERT_TRUE(exists
);
1603 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1604 ASSERT_EQ(0, image
.resize(size2
));
1605 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1606 ASSERT_FALSE(exists
);
1607 ASSERT_EQ(0, image
.snap_create("snap2"));
1608 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1609 ASSERT_TRUE(exists
);
1610 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1611 ASSERT_EQ(0, image
.snap_rename("snap1","snap1-rename"));
1612 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1-rename", size
, "snap2", size2
));
1613 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1614 ASSERT_FALSE(exists
);
1615 ASSERT_EQ(0, image
.snap_exists2("snap1-rename", &exists
));
1616 ASSERT_TRUE(exists
);
1617 ASSERT_EQ(0, image
.snap_remove("snap1-rename"));
1618 ASSERT_EQ(0, image
.snap_rename("snap2","snap2-rename"));
1619 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2-rename", size2
));
1620 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1621 ASSERT_FALSE(exists
);
1622 ASSERT_EQ(0, image
.snap_exists2("snap2-rename", &exists
));
1623 ASSERT_TRUE(exists
);
1624 ASSERT_EQ(0, image
.snap_remove("snap2-rename"));
1625 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1631 void simple_write_cb(rbd_completion_t cb
, void *arg
)
1633 printf("write completion cb called!\n");
1636 void simple_read_cb(rbd_completion_t cb
, void *arg
)
1638 printf("read completion cb called!\n");
1641 void aio_write_test_data_and_poll(rbd_image_t image
, int fd
, const char *test_data
,
1642 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1644 rbd_completion_t comp
;
1645 uint64_t data
= 0x123;
1646 rbd_aio_create_completion((void*)&data
, (rbd_callback_t
) simple_write_cb
, &comp
);
1647 printf("created completion\n");
1648 printf("started write\n");
1650 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
1652 rbd_aio_write(image
, off
, len
, test_data
, comp
);
1656 pfd
.events
= POLLIN
;
1658 ASSERT_EQ(1, poll(&pfd
, 1, -1));
1659 ASSERT_TRUE(pfd
.revents
& POLLIN
);
1661 rbd_completion_t comps
[1];
1662 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
1664 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
1665 read(fd
, &count
, sizeof(count
)));
1666 int r
= rbd_aio_get_return_value(comps
[0]);
1667 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
1668 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps
[0]) == data
);
1669 printf("return value is: %d\n", r
);
1671 printf("finished write\n");
1672 rbd_aio_release(comps
[0]);
1676 void aio_write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1678 rbd_completion_t comp
;
1679 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1680 printf("created completion\n");
1682 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
1684 rbd_aio_write(image
, off
, len
, test_data
, comp
);
1685 printf("started write\n");
1686 rbd_aio_wait_for_complete(comp
);
1687 int r
= rbd_aio_get_return_value(comp
);
1688 printf("return value is: %d\n", r
);
1690 printf("finished write\n");
1691 rbd_aio_release(comp
);
1695 void write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1699 written
= rbd_write2(image
, off
, len
, test_data
, iohint
);
1701 written
= rbd_write(image
, off
, len
, test_data
);
1702 printf("wrote: %d\n", (int) written
);
1703 ASSERT_EQ(len
, static_cast<size_t>(written
));
1707 void aio_discard_test_data(rbd_image_t image
, uint64_t off
, uint64_t len
, bool *passed
)
1709 rbd_completion_t comp
;
1710 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1711 rbd_aio_discard(image
, off
, len
, comp
);
1712 rbd_aio_wait_for_complete(comp
);
1713 int r
= rbd_aio_get_return_value(comp
);
1715 printf("aio discard: %d~%d = %d\n", (int)off
, (int)len
, (int)r
);
1716 rbd_aio_release(comp
);
1720 void discard_test_data(rbd_image_t image
, uint64_t off
, size_t len
, bool *passed
)
1723 written
= rbd_discard(image
, off
, len
);
1724 printf("discard: %d~%d = %d\n", (int)off
, (int)len
, (int)written
);
1725 ASSERT_EQ(len
, static_cast<size_t>(written
));
1729 void aio_read_test_data_and_poll(rbd_image_t image
, int fd
, const char *expected
,
1730 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1732 rbd_completion_t comp
;
1733 char *result
= (char *)malloc(len
+ 1);
1735 ASSERT_NE(static_cast<char *>(NULL
), result
);
1736 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1737 printf("created completion\n");
1738 printf("started read\n");
1740 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
1742 rbd_aio_read(image
, off
, len
, result
, comp
);
1746 pfd
.events
= POLLIN
;
1748 ASSERT_EQ(1, poll(&pfd
, 1, -1));
1749 ASSERT_TRUE(pfd
.revents
& POLLIN
);
1751 rbd_completion_t comps
[1];
1752 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
1754 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
1755 read(fd
, &count
, sizeof(count
)));
1757 int r
= rbd_aio_get_return_value(comps
[0]);
1758 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
1759 printf("return value is: %d\n", r
);
1760 ASSERT_EQ(len
, static_cast<size_t>(r
));
1761 rbd_aio_release(comps
[0]);
1762 if (memcmp(result
, expected
, len
)) {
1763 printf("read: %s\nexpected: %s\n", result
, expected
);
1764 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1770 void aio_read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1772 rbd_completion_t comp
;
1773 char *result
= (char *)malloc(len
+ 1);
1775 ASSERT_NE(static_cast<char *>(NULL
), result
);
1776 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1777 printf("created completion\n");
1779 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
1781 rbd_aio_read(image
, off
, len
, result
, comp
);
1782 printf("started read\n");
1783 rbd_aio_wait_for_complete(comp
);
1784 int r
= rbd_aio_get_return_value(comp
);
1785 printf("return value is: %d\n", r
);
1786 ASSERT_EQ(len
, static_cast<size_t>(r
));
1787 rbd_aio_release(comp
);
1788 if (memcmp(result
, expected
, len
)) {
1789 printf("read: %s\nexpected: %s\n", result
, expected
);
1790 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1796 void read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1799 char *result
= (char *)malloc(len
+ 1);
1801 ASSERT_NE(static_cast<char *>(NULL
), result
);
1803 read
= rbd_read2(image
, off
, len
, result
, iohint
);
1805 read
= rbd_read(image
, off
, len
, result
);
1806 printf("read: %d\n", (int) read
);
1807 ASSERT_EQ(len
, static_cast<size_t>(read
));
1809 if (memcmp(result
, expected
, len
)) {
1810 printf("read: %s\nexpected: %s\n", result
, expected
);
1811 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1817 void aio_writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
1818 uint64_t data_len
, uint32_t iohint
, bool *passed
)
1820 rbd_completion_t comp
;
1821 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1822 printf("created completion\n");
1824 r
= rbd_aio_writesame(image
, off
, len
, test_data
, data_len
, comp
, iohint
);
1825 printf("started writesame\n");
1826 if (len
% data_len
) {
1827 ASSERT_EQ(-EINVAL
, r
);
1828 printf("expected fail, finished writesame\n");
1829 rbd_aio_release(comp
);
1834 rbd_aio_wait_for_complete(comp
);
1835 r
= rbd_aio_get_return_value(comp
);
1836 printf("return value is: %d\n", r
);
1838 printf("finished writesame\n");
1839 rbd_aio_release(comp
);
1842 printf("to verify the data\n");
1844 char *result
= (char *)malloc(data_len
+ 1);
1845 ASSERT_NE(static_cast<char *>(NULL
), result
);
1846 uint64_t left
= len
;
1848 read
= rbd_read(image
, off
, data_len
, result
);
1849 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
1850 result
[data_len
] = '\0';
1851 if (memcmp(result
, test_data
, data_len
)) {
1852 printf("read: %d ~ %d\n", (int) off
, (int) read
);
1853 printf("read: %s\nexpected: %s\n", result
, test_data
);
1854 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
1859 ASSERT_EQ(0U, left
);
1861 printf("verified\n");
1866 void writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
1867 uint64_t data_len
, uint32_t iohint
, bool *passed
)
1870 written
= rbd_writesame(image
, off
, len
, test_data
, data_len
, iohint
);
1871 if (len
% data_len
) {
1872 ASSERT_EQ(-EINVAL
, written
);
1873 printf("expected fail, finished writesame\n");
1877 ASSERT_EQ(len
, static_cast<size_t>(written
));
1878 printf("wrote: %d\n", (int) written
);
1881 printf("to verify the data\n");
1883 char *result
= (char *)malloc(data_len
+ 1);
1884 ASSERT_NE(static_cast<char *>(NULL
), result
);
1885 uint64_t left
= len
;
1887 read
= rbd_read(image
, off
, data_len
, result
);
1888 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
1889 result
[data_len
] = '\0';
1890 if (memcmp(result
, test_data
, data_len
)) {
1891 printf("read: %d ~ %d\n", (int) off
, (int) read
);
1892 printf("read: %s\nexpected: %s\n", result
, test_data
);
1893 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
1898 ASSERT_EQ(0U, left
);
1900 printf("verified\n");
1905 void aio_compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
1906 const char *test_data
, uint64_t off
,
1907 size_t len
, uint32_t iohint
, bool *passed
)
1909 rbd_completion_t comp
;
1910 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1911 printf("created completion\n");
1913 uint64_t mismatch_offset
;
1914 rbd_aio_compare_and_write(image
, off
, len
, cmp_data
, test_data
, comp
, &mismatch_offset
, iohint
);
1915 printf("started aio compare and write\n");
1916 rbd_aio_wait_for_complete(comp
);
1917 int r
= rbd_aio_get_return_value(comp
);
1918 printf("return value is: %d\n", r
);
1920 printf("finished aio compare and write\n");
1921 rbd_aio_release(comp
);
1925 void compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
1926 const char *test_data
, uint64_t off
, size_t len
,
1927 uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
1929 printf("start compare and write\n");
1931 written
= rbd_compare_and_write(image
, off
, len
, cmp_data
, test_data
, mismatch_off
, iohint
);
1932 printf("compare and wrote: %d\n", (int) written
);
1933 ASSERT_EQ(len
, static_cast<size_t>(written
));
1938 TEST_F(TestLibRBD
, TestIO
)
1940 rados_ioctx_t ioctx
;
1941 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1943 bool skip_discard
= is_skip_partial_discard_enabled();
1947 std::string name
= get_temp_image_name();
1948 uint64_t size
= 2 << 20;
1950 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1951 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_read_from_replica_policy", "balance"));
1952 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1954 char test_data
[TEST_IO_SIZE
+ 1];
1955 char zero_data
[TEST_IO_SIZE
+ 1];
1956 char mismatch_data
[TEST_IO_SIZE
+ 1];
1958 uint64_t mismatch_offset
;
1960 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
1961 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
1963 test_data
[TEST_IO_SIZE
] = '\0';
1964 memset(zero_data
, 0, sizeof(zero_data
));
1965 memset(mismatch_data
, 9, sizeof(mismatch_data
));
1967 for (i
= 0; i
< 5; ++i
)
1968 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1970 for (i
= 5; i
< 10; ++i
)
1971 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1973 for (i
= 0; i
< 5; ++i
)
1974 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, 0);
1976 for (i
= 5; i
< 10; ++i
)
1977 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1979 for (i
= 0; i
< 5; ++i
)
1980 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1982 for (i
= 5; i
< 10; ++i
)
1983 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1985 // discard 2nd, 4th sections.
1986 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
1987 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
1989 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
1990 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1991 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
1992 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
1993 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1994 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
1995 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
1997 for (i
= 0; i
< 15; ++i
) {
1999 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2000 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2001 } else if (i
% 3 == 1) {
2002 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2003 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2005 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2006 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2009 for (i
= 0; i
< 15; ++i
) {
2011 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2012 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2013 } else if (i
% 3 == 1) {
2014 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2015 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2017 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2018 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2022 rbd_image_info_t info
;
2023 rbd_completion_t comp
;
2024 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2025 // can't read or write starting past end
2026 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2027 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2028 // reading through end returns amount up to end
2029 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
2030 // writing through end returns amount up to end
2031 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
2033 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2034 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
2035 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2036 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2037 rbd_aio_release(comp
);
2039 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2040 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
2041 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2042 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2043 rbd_aio_release(comp
);
2045 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2046 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
, &mismatch_offset
, 0));
2047 ASSERT_EQ(0U, mismatch_offset
);
2048 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2049 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
, comp
, &mismatch_offset
, 0));
2050 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2051 ASSERT_EQ(0U, mismatch_offset
);
2052 rbd_aio_release(comp
);
2054 ASSERT_PASSED(validate_object_map
, image
);
2055 ASSERT_EQ(0, rbd_close(image
));
2057 rados_ioctx_destroy(ioctx
);
2060 TEST_F(TestLibRBD
, TestIOWithIOHint
)
2062 rados_ioctx_t ioctx
;
2063 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2065 bool skip_discard
= is_skip_partial_discard_enabled();
2069 std::string name
= get_temp_image_name();
2070 uint64_t size
= 2 << 20;
2072 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2073 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2075 char test_data
[TEST_IO_SIZE
+ 1];
2076 char zero_data
[TEST_IO_SIZE
+ 1];
2077 char mismatch_data
[TEST_IO_SIZE
+ 1];
2079 uint64_t mismatch_offset
;
2081 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2082 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2084 test_data
[TEST_IO_SIZE
] = '\0';
2085 memset(zero_data
, 0, sizeof(zero_data
));
2086 memset(mismatch_data
, 9, sizeof(mismatch_data
));
2088 for (i
= 0; i
< 5; ++i
)
2089 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2090 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2092 for (i
= 5; i
< 10; ++i
)
2093 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2094 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2096 for (i
= 0; i
< 5; ++i
)
2097 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
2098 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2100 for (i
= 5; i
< 10; ++i
)
2101 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
2102 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2104 for (i
= 0; i
< 5; ++i
)
2105 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
,
2106 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2108 for (i
= 5; i
< 10; ++i
)
2109 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2110 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2112 // discard 2nd, 4th sections.
2113 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2114 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2116 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
,
2117 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2118 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2119 TEST_IO_SIZE
, TEST_IO_SIZE
,
2120 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2121 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
,
2122 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2123 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2124 TEST_IO_SIZE
*3, TEST_IO_SIZE
,
2125 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2126 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2128 for (i
= 0; i
< 15; ++i
) {
2130 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2131 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2132 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2133 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2134 } else if (i
% 3 == 1) {
2135 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2136 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2137 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2138 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2140 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2141 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2142 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2143 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2146 for (i
= 0; i
< 15; ++i
) {
2148 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2149 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2150 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2151 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2152 } else if (i
% 3 == 1) {
2153 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2154 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2155 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2156 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2158 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2159 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2160 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2161 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2165 rbd_image_info_t info
;
2166 rbd_completion_t comp
;
2167 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2168 // can't read or write starting past end
2169 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2170 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2171 // reading through end returns amount up to end
2172 ASSERT_EQ(10, rbd_read2(image
, info
.size
- 10, 100, test_data
,
2173 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
));
2174 // writing through end returns amount up to end
2175 ASSERT_EQ(10, rbd_write2(image
, info
.size
- 10, 100, test_data
,
2176 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2178 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2179 ASSERT_EQ(0, rbd_aio_read2(image
, info
.size
, 1, test_data
, comp
,
2180 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2181 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2182 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2183 rbd_aio_release(comp
);
2185 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2186 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2187 &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2188 ASSERT_EQ(0U, mismatch_offset
);
2189 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2190 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2191 comp
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2192 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2193 ASSERT_EQ(0U, mismatch_offset
);
2194 rbd_aio_release(comp
);
2196 ASSERT_PASSED(validate_object_map
, image
);
2197 ASSERT_EQ(0, rbd_close(image
));
2199 rados_ioctx_destroy(ioctx
);
2202 TEST_F(TestLibRBD
, TestDataPoolIO
)
2204 REQUIRE_FORMAT_V2();
2206 rados_ioctx_t ioctx
;
2207 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2209 std::string data_pool_name
= create_pool(true);
2211 bool skip_discard
= is_skip_partial_discard_enabled();
2214 std::string name
= get_temp_image_name();
2215 uint64_t size
= 2 << 20;
2219 ASSERT_EQ(0, get_features(&old_format
, &features
));
2220 ASSERT_FALSE(old_format
);
2222 rbd_image_options_t image_options
;
2223 rbd_image_options_create(&image_options
);
2224 BOOST_SCOPE_EXIT( (&image_options
) ) {
2225 rbd_image_options_destroy(image_options
);
2226 } BOOST_SCOPE_EXIT_END
;
2228 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
2229 RBD_IMAGE_OPTION_FEATURES
,
2231 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
2232 RBD_IMAGE_OPTION_DATA_POOL
,
2233 data_pool_name
.c_str()));
2235 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
2236 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2237 ASSERT_NE(-1, rbd_get_data_pool_id(image
));
2239 char test_data
[TEST_IO_SIZE
+ 1];
2240 char zero_data
[TEST_IO_SIZE
+ 1];
2243 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2244 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2246 test_data
[TEST_IO_SIZE
] = '\0';
2247 memset(zero_data
, 0, sizeof(zero_data
));
2249 for (i
= 0; i
< 5; ++i
)
2250 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2252 for (i
= 5; i
< 10; ++i
)
2253 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2255 for (i
= 0; i
< 5; ++i
)
2256 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2258 for (i
= 5; i
< 10; ++i
)
2259 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2261 // discard 2nd, 4th sections.
2262 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2263 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2265 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
2266 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2267 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
2268 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
2269 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2270 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
2271 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2273 rbd_image_info_t info
;
2274 rbd_completion_t comp
;
2275 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2276 // can't read or write starting past end
2277 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2278 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2279 // reading through end returns amount up to end
2280 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
2281 // writing through end returns amount up to end
2282 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
2284 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2285 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
2286 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2287 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2288 rbd_aio_release(comp
);
2290 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2291 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
2292 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2293 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2294 rbd_aio_release(comp
);
2296 ASSERT_PASSED(validate_object_map
, image
);
2297 ASSERT_EQ(0, rbd_close(image
));
2299 rados_ioctx_destroy(ioctx
);
2302 TEST_F(TestLibRBD
, TestScatterGatherIO
)
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 size
= 20 << 20;
2312 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2313 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2315 std::string
write_buffer("This is a test");
2316 struct iovec bad_iovs
[] = {
2317 {.iov_base
= NULL
, .iov_len
= static_cast<size_t>(-1)}
2319 struct iovec write_iovs
[] = {
2320 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
2321 {.iov_base
= &write_buffer
[5], .iov_len
= 3},
2322 {.iov_base
= &write_buffer
[8], .iov_len
= 2},
2323 {.iov_base
= &write_buffer
[10], .iov_len
= 4}
2326 rbd_completion_t comp
;
2327 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2328 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, write_iovs
, 0, 0, comp
));
2329 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, bad_iovs
, 1, 0, comp
));
2330 ASSERT_EQ(0, rbd_aio_writev(image
, write_iovs
,
2331 sizeof(write_iovs
) / sizeof(struct iovec
),
2333 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2334 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
2335 rbd_aio_release(comp
);
2337 std::string
read_buffer(write_buffer
.size(), '1');
2338 struct iovec read_iovs
[] = {
2339 {.iov_base
= &read_buffer
[0], .iov_len
= 4},
2340 {.iov_base
= &read_buffer
[8], .iov_len
= 4},
2341 {.iov_base
= &read_buffer
[12], .iov_len
= 2}
2344 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2345 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, read_iovs
, 0, 0, comp
));
2346 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, bad_iovs
, 1, 0, comp
));
2347 ASSERT_EQ(0, rbd_aio_readv(image
, read_iovs
,
2348 sizeof(read_iovs
) / sizeof(struct iovec
),
2350 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2351 ASSERT_EQ(10, rbd_aio_get_return_value(comp
));
2352 rbd_aio_release(comp
);
2353 ASSERT_EQ("This1111 is a ", read_buffer
);
2355 std::string
linear_buffer(write_buffer
.size(), '1');
2356 struct iovec linear_iovs
[] = {
2357 {.iov_base
= &linear_buffer
[4], .iov_len
= 4}
2359 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2360 ASSERT_EQ(0, rbd_aio_readv(image
, linear_iovs
,
2361 sizeof(linear_iovs
) / sizeof(struct iovec
),
2363 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2364 ASSERT_EQ(4, rbd_aio_get_return_value(comp
));
2365 rbd_aio_release(comp
);
2366 ASSERT_EQ("1111This111111", linear_buffer
);
2368 ASSERT_PASSED(validate_object_map
, image
);
2369 ASSERT_EQ(0, rbd_close(image
));
2371 rados_ioctx_destroy(ioctx
);
2374 TEST_F(TestLibRBD
, TestEmptyDiscard
)
2376 rados_ioctx_t ioctx
;
2377 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2381 std::string name
= get_temp_image_name();
2382 uint64_t size
= 20 << 20;
2384 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2385 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2387 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 1*1024*1024);
2388 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 4*1024*1024);
2389 ASSERT_PASSED(aio_discard_test_data
, image
, 3*1024*1024, 1*1024*1024);
2391 ASSERT_PASSED(validate_object_map
, image
);
2392 ASSERT_EQ(0, rbd_close(image
));
2394 rados_ioctx_destroy(ioctx
);
2397 TEST_F(TestLibRBD
, TestFUA
)
2399 rados_ioctx_t ioctx
;
2400 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2402 rbd_image_t image_write
;
2403 rbd_image_t image_read
;
2405 std::string name
= get_temp_image_name();
2406 uint64_t size
= 2 << 20;
2408 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2409 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_write
, NULL
));
2410 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_read
, NULL
));
2412 // enable writeback cache
2413 rbd_flush(image_write
);
2415 char test_data
[TEST_IO_SIZE
+ 1];
2418 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2419 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2421 test_data
[TEST_IO_SIZE
] = '\0';
2422 for (i
= 0; i
< 5; ++i
)
2423 ASSERT_PASSED(write_test_data
, image_write
, test_data
,
2424 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2426 for (i
= 0; i
< 5; ++i
)
2427 ASSERT_PASSED(read_test_data
, image_read
, test_data
,
2428 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2430 for (i
= 5; i
< 10; ++i
)
2431 ASSERT_PASSED(aio_write_test_data
, image_write
, test_data
,
2432 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2434 for (i
= 5; i
< 10; ++i
)
2435 ASSERT_PASSED(aio_read_test_data
, image_read
, test_data
,
2436 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2438 ASSERT_PASSED(validate_object_map
, image_write
);
2439 ASSERT_PASSED(validate_object_map
, image_read
);
2440 ASSERT_EQ(0, rbd_close(image_write
));
2441 ASSERT_EQ(0, rbd_close(image_read
));
2442 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2443 rados_ioctx_destroy(ioctx
);
2446 void simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
2448 cout
<< "write completion cb called!" << std::endl
;
2451 void simple_read_cb_pp(librbd::completion_t cb
, void *arg
)
2453 cout
<< "read completion cb called!" << std::endl
;
2456 void aio_write_test_data(librbd::Image
& image
, const char *test_data
,
2457 off_t off
, uint32_t iohint
, bool *passed
)
2459 ceph::bufferlist bl
;
2460 bl
.append(test_data
, strlen(test_data
));
2461 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2462 printf("created completion\n");
2464 image
.aio_write2(off
, strlen(test_data
), bl
, comp
, iohint
);
2466 image
.aio_write(off
, strlen(test_data
), bl
, comp
);
2467 printf("started write\n");
2468 comp
->wait_for_complete();
2469 int r
= comp
->get_return_value();
2470 printf("return value is: %d\n", r
);
2472 printf("finished write\n");
2477 void aio_discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2479 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2480 image
.aio_discard(off
, len
, comp
);
2481 comp
->wait_for_complete();
2482 int r
= comp
->get_return_value();
2488 void write_test_data(librbd::Image
& image
, const char *test_data
, off_t off
, uint32_t iohint
, bool *passed
)
2491 size_t len
= strlen(test_data
);
2492 ceph::bufferlist bl
;
2493 bl
.append(test_data
, len
);
2495 written
= image
.write2(off
, len
, bl
, iohint
);
2497 written
= image
.write(off
, len
, bl
);
2498 printf("wrote: %u\n", (unsigned int) written
);
2499 ASSERT_EQ(bl
.length(), written
);
2503 void discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2506 written
= image
.discard(off
, len
);
2507 printf("discard: %u~%u\n", (unsigned)off
, (unsigned)len
);
2508 ASSERT_EQ(len
, written
);
2512 void aio_read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2514 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_read_cb_pp
);
2515 ceph::bufferlist bl
;
2516 printf("created completion\n");
2518 image
.aio_read2(off
, expected_len
, bl
, comp
, iohint
);
2520 image
.aio_read(off
, expected_len
, bl
, comp
);
2521 printf("started read\n");
2522 comp
->wait_for_complete();
2523 int r
= comp
->get_return_value();
2524 printf("return value is: %d\n", r
);
2525 ASSERT_EQ(TEST_IO_SIZE
, r
);
2526 ASSERT_EQ(0, memcmp(expected
, bl
.c_str(), TEST_IO_SIZE
));
2527 printf("finished read\n");
2532 void read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2535 size_t len
= expected_len
;
2536 ceph::bufferlist bl
;
2538 read
= image
.read2(off
, len
, bl
, iohint
);
2540 read
= image
.read(off
, len
, bl
);
2541 ASSERT_TRUE(read
>= 0);
2542 std::string
bl_str(bl
.c_str(), read
);
2544 printf("read: %u\n", (unsigned int) read
);
2545 int result
= memcmp(bl_str
.c_str(), expected
, expected_len
);
2547 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), expected
);
2548 ASSERT_EQ(0, result
);
2553 void aio_writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2554 size_t len
, size_t data_len
, uint32_t iohint
, bool *passed
)
2556 ceph::bufferlist bl
;
2557 bl
.append(test_data
, data_len
);
2558 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2559 printf("created completion\n");
2561 r
= image
.aio_writesame(off
, len
, bl
, comp
, iohint
);
2562 printf("started writesame\n");
2563 if (len
% data_len
) {
2564 ASSERT_EQ(-EINVAL
, r
);
2565 printf("expected fail, finished writesame\n");
2571 comp
->wait_for_complete();
2572 r
= comp
->get_return_value();
2573 printf("return value is: %d\n", r
);
2575 printf("finished writesame\n");
2579 printf("to verify the data\n");
2581 uint64_t left
= len
;
2583 ceph::bufferlist bl
;
2584 read
= image
.read(off
, data_len
, bl
);
2585 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2586 std::string
bl_str(bl
.c_str(), read
);
2587 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2589 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2590 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2591 ASSERT_EQ(0, result
);
2596 ASSERT_EQ(0U, left
);
2597 printf("verified\n");
2602 void writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2603 ssize_t len
, size_t data_len
, uint32_t iohint
,
2607 ceph::bufferlist bl
;
2608 bl
.append(test_data
, data_len
);
2609 written
= image
.writesame(off
, len
, bl
, iohint
);
2610 if (len
% data_len
) {
2611 ASSERT_EQ(-EINVAL
, written
);
2612 printf("expected fail, finished writesame\n");
2616 ASSERT_EQ(len
, written
);
2617 printf("wrote: %u\n", (unsigned int) written
);
2621 printf("to verify the data\n");
2623 uint64_t left
= len
;
2625 ceph::bufferlist bl
;
2626 read
= image
.read(off
, data_len
, bl
);
2627 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2628 std::string
bl_str(bl
.c_str(), read
);
2629 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2631 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2632 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2633 ASSERT_EQ(0, result
);
2638 ASSERT_EQ(0U, left
);
2639 printf("verified\n");
2644 void aio_compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
,
2645 const char *test_data
, off_t off
, ssize_t len
,
2646 uint32_t iohint
, bool *passed
)
2648 ceph::bufferlist cmp_bl
;
2649 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2650 ceph::bufferlist test_bl
;
2651 test_bl
.append(test_data
, strlen(test_data
));
2652 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2653 printf("created completion\n");
2655 uint64_t mismatch_offset
;
2656 image
.aio_compare_and_write(off
, len
, cmp_bl
, test_bl
, comp
, &mismatch_offset
, iohint
);
2657 printf("started aio compare and write\n");
2658 comp
->wait_for_complete();
2659 int r
= comp
->get_return_value();
2660 printf("return value is: %d\n", r
);
2662 printf("finished aio compare and write\n");
2667 void compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
, const char *test_data
,
2668 off_t off
, ssize_t len
, uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
2671 ceph::bufferlist cmp_bl
;
2672 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2673 ceph::bufferlist test_bl
;
2674 test_bl
.append(test_data
, strlen(test_data
));
2675 printf("start compare and write\n");
2676 written
= image
.compare_and_write(off
, len
, cmp_bl
, test_bl
, mismatch_off
, iohint
);
2677 printf("compare and wrote: %d\n", (int) written
);
2678 ASSERT_EQ(len
, static_cast<ssize_t
>(written
));
2682 TEST_F(TestLibRBD
, TestIOPP
)
2684 librados::IoCtx ioctx
;
2685 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2687 bool skip_discard
= is_skip_partial_discard_enabled();
2691 librbd::Image image
;
2693 std::string name
= get_temp_image_name();
2694 uint64_t size
= 2 << 20;
2696 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2697 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2699 char test_data
[TEST_IO_SIZE
+ 1];
2700 char zero_data
[TEST_IO_SIZE
+ 1];
2702 uint64_t mismatch_offset
;
2704 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2705 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2707 test_data
[TEST_IO_SIZE
] = '\0';
2708 memset(zero_data
, 0, sizeof(zero_data
));
2710 for (i
= 0; i
< 5; ++i
)
2711 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2713 for (i
= 5; i
< 10; ++i
)
2714 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2716 for (i
= 0; i
< 5; ++i
)
2717 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
2718 TEST_IO_SIZE
, &mismatch_offset
, 0);
2720 for (i
= 5; i
< 10; ++i
)
2721 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
2724 for (i
= 0; i
< 5; ++i
)
2725 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
2727 for (i
= 5; i
< 10; ++i
)
2728 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
2730 // discard 2nd, 4th sections.
2731 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2732 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2734 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
2735 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2736 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
2737 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
2738 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2739 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
2740 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2742 for (i
= 0; i
< 15; ++i
) {
2744 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2745 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2746 } else if (i
% 3 == 1) {
2747 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2748 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2750 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2751 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2754 for (i
= 0; i
< 15; ++i
) {
2756 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2757 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2758 } else if (i
% 3 == 1) {
2759 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2760 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2762 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2763 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2767 ASSERT_PASSED(validate_object_map
, image
);
2773 TEST_F(TestLibRBD
, TestIOPPWithIOHint
)
2775 librados::IoCtx ioctx
;
2776 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2780 librbd::Image image
;
2782 std::string name
= get_temp_image_name();
2783 uint64_t size
= 2 << 20;
2785 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2786 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2788 char test_data
[TEST_IO_SIZE
+ 1];
2789 char zero_data
[TEST_IO_SIZE
+ 1];
2790 test_data
[TEST_IO_SIZE
] = '\0';
2793 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2794 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2796 memset(zero_data
, 0, sizeof(zero_data
));
2798 for (i
= 0; i
< 5; ++i
)
2799 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
,
2800 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2802 for (i
= 5; i
< 10; ++i
)
2803 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
,
2804 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2806 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
),
2807 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_RANDOM
);
2809 for (i
= 5; i
< 10; ++i
)
2810 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
,
2811 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2813 for (i
= 0; i
< 15; ++i
) {
2815 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2816 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2817 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2818 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2819 } else if (i
% 3 == 1) {
2820 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
2821 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2822 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
2823 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2825 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2826 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2827 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2828 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2831 for (i
= 0; i
< 15; ++i
) {
2833 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2834 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2835 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2836 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2837 } else if (i
% 3 == 1) {
2838 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
2839 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2840 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
2841 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2843 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2844 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2845 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2846 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2850 ASSERT_PASSED(validate_object_map
, image
);
2858 TEST_F(TestLibRBD
, TestIOToSnapshot
)
2860 rados_ioctx_t ioctx
;
2861 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2865 std::string name
= get_temp_image_name();
2866 uint64_t isize
= 2 << 20;
2868 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
2869 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2872 rbd_image_t image_at_snap
;
2873 char orig_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
2874 char test_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
2876 for (i
= 0; i
< TEST_IO_TO_SNAP_SIZE
; ++i
)
2877 test_data
[i
] = (char) (i
+ 48);
2878 test_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
2879 orig_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
2881 r
= rbd_read(image
, 0, TEST_IO_TO_SNAP_SIZE
, orig_data
);
2882 ASSERT_EQ(r
, TEST_IO_TO_SNAP_SIZE
);
2884 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2885 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
2886 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
2887 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2889 printf("write test data!\n");
2890 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2891 ASSERT_EQ(0, rbd_snap_create(image
, "written"));
2892 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
2894 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2896 rbd_snap_set(image
, "orig");
2897 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2899 rbd_snap_set(image
, "written");
2900 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2902 rbd_snap_set(image
, "orig");
2904 r
= rbd_write(image
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
2905 printf("write to snapshot returned %d\n", r
);
2907 cout
<< strerror(-r
) << std::endl
;
2909 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2910 rbd_snap_set(image
, "written");
2911 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2913 r
= rbd_snap_rollback(image
, "orig");
2914 ASSERT_EQ(r
, -EROFS
);
2916 r
= rbd_snap_set(image
, NULL
);
2918 r
= rbd_snap_rollback(image
, "orig");
2921 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2925 printf("opening testimg@orig\n");
2926 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_at_snap
, "orig"));
2927 ASSERT_PASSED(read_test_data
, image_at_snap
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2928 r
= rbd_write(image_at_snap
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
2929 printf("write to snapshot returned %d\n", r
);
2931 cout
<< strerror(-r
) << std::endl
;
2932 ASSERT_EQ(0, rbd_close(image_at_snap
));
2934 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
2935 ASSERT_EQ(0, rbd_snap_remove(image
, "written"));
2936 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
2937 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
2938 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2940 ASSERT_PASSED(validate_object_map
, image
);
2941 ASSERT_EQ(0, rbd_close(image
));
2943 rados_ioctx_destroy(ioctx
);
2946 TEST_F(TestLibRBD
, TestClone
)
2948 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2949 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "1"));
2950 BOOST_SCOPE_EXIT_ALL(&) {
2951 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
2954 rados_ioctx_t ioctx
;
2955 rbd_image_info_t pinfo
, cinfo
;
2956 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2960 rbd_image_t parent
, child
;
2963 ASSERT_EQ(0, get_features(&old_format
, &features
));
2964 ASSERT_FALSE(old_format
);
2966 std::string parent_name
= get_temp_image_name();
2967 std::string child_name
= get_temp_image_name();
2969 // make a parent to clone from
2970 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
2972 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
2973 printf("made parent image \"parent\"\n");
2975 char *data
= (char *)"testdata";
2976 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
2978 // can't clone a non-snapshot, expect failure
2979 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
2980 child_name
.c_str(), features
, &order
));
2982 // verify that there is no parent info on "parent"
2983 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
2984 printf("parent has no parent info\n");
2986 // create 70 metadatas to verify we can clone all key/value pairs
2989 size_t sum_key_len
= 0;
2990 size_t sum_value_len
= 0;
2991 for (int i
= 1; i
<= 70; i
++) {
2992 key
= "key" + stringify(i
);
2993 val
= "value" + stringify(i
);
2994 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
2996 sum_key_len
+= (key
.size() + 1);
2997 sum_value_len
+= (val
.size() + 1);
3002 size_t keys_len
= sizeof(keys
);
3003 size_t vals_len
= sizeof(vals
);
3006 size_t value_len
= sizeof(value
);
3008 // create a snapshot, reopen as the parent we're interested in
3009 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3010 printf("made snapshot \"parent@parent_snap\"\n");
3011 ASSERT_EQ(0, rbd_close(parent
));
3012 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
3014 ASSERT_EQ(-EINVAL
, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3015 ioctx
, child_name
.c_str(), features
, &order
));
3017 // unprotected image should fail unprotect
3018 ASSERT_EQ(-EINVAL
, rbd_snap_unprotect(parent
, "parent_snap"));
3019 printf("can't unprotect an unprotected snap\n");
3021 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3022 // protecting again should fail
3023 ASSERT_EQ(-EBUSY
, rbd_snap_protect(parent
, "parent_snap"));
3024 printf("can't protect a protected snap\n");
3026 // This clone and open should work
3027 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3028 ioctx
, child_name
.c_str(), features
, &order
));
3029 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
3030 printf("made and opened clone \"child\"\n");
3033 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
3036 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(child
, 20, strlen(data
), data
));
3037 ASSERT_PASSED(read_test_data
, child
, data
, 20, strlen(data
), 0);
3038 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
3041 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
3042 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3043 EXPECT_EQ(cinfo
.size
, pinfo
.size
);
3045 rbd_get_overlap(child
, &overlap
);
3046 EXPECT_EQ(overlap
, pinfo
.size
);
3047 EXPECT_EQ(cinfo
.obj_size
, pinfo
.obj_size
);
3048 EXPECT_EQ(cinfo
.order
, pinfo
.order
);
3049 printf("sizes and overlaps are good between parent and child\n");
3051 // check key/value pairs in child image
3052 ASSERT_EQ(0, rbd_metadata_list(child
, "", 70, keys
, &keys_len
, vals
,
3054 ASSERT_EQ(sum_key_len
, keys_len
);
3055 ASSERT_EQ(sum_value_len
, vals_len
);
3057 for (int i
= 1; i
<= 70; i
++) {
3058 key
= "key" + stringify(i
);
3059 val
= "value" + stringify(i
);
3060 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3061 ASSERT_STREQ(val
.c_str(), value
);
3063 value_len
= sizeof(value
);
3065 printf("child image successfully cloned all image-meta pairs\n");
3067 // sizing down child results in changing overlap and size, not parent size
3068 ASSERT_EQ(0, rbd_resize(child
, 2UL<<20));
3069 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3070 rbd_get_overlap(child
, &overlap
);
3071 ASSERT_EQ(overlap
, 2UL<<20);
3072 ASSERT_EQ(cinfo
.size
, 2UL<<20);
3073 ASSERT_EQ(0, rbd_resize(child
, 4UL<<20));
3074 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3075 rbd_get_overlap(child
, &overlap
);
3076 ASSERT_EQ(overlap
, 2UL<<20);
3077 ASSERT_EQ(cinfo
.size
, 4UL<<20);
3078 printf("sized down clone, changed overlap\n");
3080 // sizing back up doesn't change that
3081 ASSERT_EQ(0, rbd_resize(child
, 5UL<<20));
3082 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3083 rbd_get_overlap(child
, &overlap
);
3084 ASSERT_EQ(overlap
, 2UL<<20);
3085 ASSERT_EQ(cinfo
.size
, 5UL<<20);
3086 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
3087 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
3088 (unsigned long long)pinfo
.size
, (unsigned long long)pinfo
.obj_size
,
3089 (unsigned long long)pinfo
.parent_pool
);
3090 ASSERT_EQ(pinfo
.size
, 4UL<<20);
3091 printf("sized up clone, changed size but not overlap or parent's size\n");
3093 ASSERT_PASSED(validate_object_map
, child
);
3094 ASSERT_EQ(0, rbd_close(child
));
3096 ASSERT_PASSED(validate_object_map
, parent
);
3097 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3098 printf("can't remove parent while child still exists\n");
3099 ASSERT_EQ(0, rbd_remove(ioctx
, child_name
.c_str()));
3100 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3101 printf("can't remove parent while still protected\n");
3102 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3103 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3104 printf("removed parent snap after unprotecting\n");
3106 ASSERT_EQ(0, rbd_close(parent
));
3107 rados_ioctx_destroy(ioctx
);
3110 TEST_F(TestLibRBD
, TestClone2
)
3112 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3113 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
3114 BOOST_SCOPE_EXIT_ALL(&) {
3115 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
3118 rados_ioctx_t ioctx
;
3119 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3123 rbd_image_t parent
, child
;
3126 ASSERT_EQ(0, get_features(&old_format
, &features
));
3127 ASSERT_FALSE(old_format
);
3129 std::string parent_name
= get_temp_image_name();
3130 std::string child_name
= get_temp_image_name();
3132 // make a parent to clone from
3133 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
3135 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
3136 printf("made parent image \"parent\"\n");
3138 char *data
= (char *)"testdata";
3139 char *childata
= (char *)"childata";
3140 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
3141 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
3143 // can't clone a non-snapshot, expect failure
3144 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
3145 child_name
.c_str(), features
, &order
));
3147 // verify that there is no parent info on "parent"
3148 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
3149 printf("parent has no parent info\n");
3151 // create 70 metadatas to verify we can clone all key/value pairs
3154 size_t sum_key_len
= 0;
3155 size_t sum_value_len
= 0;
3156 for (int i
= 1; i
<= 70; i
++) {
3157 key
= "key" + stringify(i
);
3158 val
= "value" + stringify(i
);
3159 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
3161 sum_key_len
+= (key
.size() + 1);
3162 sum_value_len
+= (val
.size() + 1);
3167 size_t keys_len
= sizeof(keys
);
3168 size_t vals_len
= sizeof(vals
);
3171 size_t value_len
= sizeof(value
);
3173 // create a snapshot, reopen as the parent we're interested in
3174 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3175 printf("made snapshot \"parent@parent_snap\"\n");
3176 ASSERT_EQ(0, rbd_close(parent
));
3177 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
3179 // This clone and open should work
3180 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3181 ioctx
, child_name
.c_str(), features
, &order
));
3182 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
3183 printf("made and opened clone \"child\"\n");
3185 // check key/value pairs in child image
3186 ASSERT_EQ(0, rbd_metadata_list(child
, "", 70, keys
, &keys_len
, vals
,
3188 ASSERT_EQ(sum_key_len
, keys_len
);
3189 ASSERT_EQ(sum_value_len
, vals_len
);
3191 for (int i
= 1; i
<= 70; i
++) {
3192 key
= "key" + stringify(i
);
3193 val
= "value" + stringify(i
);
3194 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3195 ASSERT_STREQ(val
.c_str(), value
);
3197 value_len
= sizeof(value
);
3199 printf("child image successfully cloned all image-meta pairs\n");
3201 // write something in
3202 ASSERT_EQ((ssize_t
)strlen(childata
), rbd_write(child
, 20, strlen(childata
), childata
));
3204 char test
[strlen(data
) * 2];
3205 ASSERT_EQ((ssize_t
)strlen(data
), rbd_read(child
, 20, strlen(data
), test
));
3206 ASSERT_EQ(0, memcmp(test
, childata
, strlen(childata
)));
3209 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 20 - strlen(data
), sizeof(test
), test
));
3210 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3211 ASSERT_EQ(0, memcmp(test
+ strlen(data
), childata
, strlen(childata
)));
3214 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 0, sizeof(test
), test
));
3215 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3217 ASSERT_PASSED(validate_object_map
, child
);
3218 ASSERT_PASSED(validate_object_map
, parent
);
3220 rbd_snap_info_t snaps
[2];
3222 ASSERT_EQ(1, rbd_snap_list(parent
, snaps
, &max_snaps
));
3223 rbd_snap_list_end(snaps
);
3225 ASSERT_EQ(0, rbd_snap_remove_by_id(parent
, snaps
[0].id
));
3227 rbd_snap_namespace_type_t snap_namespace_type
;
3228 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent
, snaps
[0].id
,
3229 &snap_namespace_type
));
3230 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH
, snap_namespace_type
);
3232 char original_name
[32];
3233 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent
, snaps
[0].id
,
3235 sizeof(original_name
)));
3236 ASSERT_EQ(0, strcmp("parent_snap", original_name
));
3238 ASSERT_EQ(0, rbd_close(child
));
3239 ASSERT_EQ(0, rbd_close(parent
));
3240 rados_ioctx_destroy(ioctx
);
3243 static void test_list_children(rbd_image_t image
, ssize_t num_expected
, ...)
3246 va_start(ap
, num_expected
);
3247 size_t pools_len
= 100;
3248 size_t children_len
= 100;
3250 char *children
= NULL
;
3251 ssize_t num_children
;
3256 pools
= (char *) malloc(pools_len
);
3257 children
= (char *) malloc(children_len
);
3258 num_children
= rbd_list_children(image
, pools
, &pools_len
,
3259 children
, &children_len
);
3260 } while (num_children
== -ERANGE
);
3262 ASSERT_EQ(num_expected
, num_children
);
3263 for (ssize_t i
= num_expected
; i
> 0; --i
) {
3264 char *expected_pool
= va_arg(ap
, char *);
3265 char *expected_image
= va_arg(ap
, char *);
3267 char *image
= children
;
3269 printf("\ntrying to find %s/%s\n", expected_pool
, expected_image
);
3270 for (ssize_t j
= 0; j
< num_children
; ++j
) {
3271 printf("checking %s/%s\n", pool
, image
);
3272 if (strcmp(expected_pool
, pool
) == 0 &&
3273 strcmp(expected_image
, image
) == 0) {
3274 printf("found child %s/%s\n\n", pool
, image
);
3278 pool
+= strlen(pool
) + 1;
3279 image
+= strlen(image
) + 1;
3280 if (j
== num_children
- 1) {
3281 ASSERT_EQ(pool
- pools
- 1, (ssize_t
) pools_len
);
3282 ASSERT_EQ(image
- children
- 1, (ssize_t
) children_len
);
3295 static void test_list_children2(rbd_image_t image
, int num_expected
, ...)
3297 int num_children
, i
, j
, max_size
= 10;
3299 rbd_child_info_t children
[max_size
];
3300 num_children
= rbd_list_children2(image
, children
, &max_size
);
3301 printf("num children is: %d\nexpected: %d\n", num_children
, num_expected
);
3303 for (i
= 0; i
< num_children
; i
++) {
3304 printf("child: %s\n", children
[i
].image_name
);
3307 va_start(ap
, num_expected
);
3308 for (i
= num_expected
; i
> 0; i
--) {
3309 char *expected_id
= va_arg(ap
, char *);
3310 char *expected_pool
= va_arg(ap
, char *);
3311 char *expected_image
= va_arg(ap
, char *);
3312 bool expected_trash
= va_arg(ap
, int);
3314 for (j
= 0; j
< num_children
; j
++) {
3315 if (children
[j
].pool_name
== NULL
||
3316 children
[j
].image_name
== NULL
||
3317 children
[j
].image_id
== NULL
)
3319 if (strcmp(children
[j
].image_id
, expected_id
) == 0 &&
3320 strcmp(children
[j
].pool_name
, expected_pool
) == 0 &&
3321 strcmp(children
[j
].image_name
, expected_image
) == 0 &&
3322 children
[j
].trash
== expected_trash
) {
3323 printf("found child %s/%s/%s\n\n", children
[j
].pool_name
, children
[j
].image_name
, children
[j
].image_id
);
3324 rbd_list_child_cleanup(&children
[j
]);
3325 children
[j
].pool_name
= NULL
;
3326 children
[j
].image_name
= NULL
;
3327 children
[j
].image_id
= NULL
;
3336 for (i
= 0; i
< num_children
; i
++) {
3337 EXPECT_EQ((const char *)0, children
[i
].pool_name
);
3338 EXPECT_EQ((const char *)0, children
[i
].image_name
);
3339 EXPECT_EQ((const char *)0, children
[i
].image_id
);
3343 TEST_F(TestLibRBD
, ListChildren
)
3345 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3348 rados_ioctx_t ioctx1
, ioctx2
;
3349 string pool_name1
= create_pool(true);
3350 string pool_name2
= create_pool(true);
3351 ASSERT_NE("", pool_name2
);
3353 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3354 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3366 ASSERT_EQ(0, get_features(&old_format
, &features
));
3367 ASSERT_FALSE(old_format
);
3369 std::string parent_name
= get_temp_image_name();
3370 std::string child_name1
= get_temp_image_name();
3371 std::string child_name2
= get_temp_image_name();
3372 std::string child_name3
= get_temp_image_name();
3373 std::string child_name4
= get_temp_image_name();
3375 char child_id1
[4096];
3376 char child_id2
[4096];
3377 char child_id3
[4096];
3378 char child_id4
[4096];
3380 // make a parent to clone from
3381 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3383 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3384 // create a snapshot, reopen as the parent we're interested in
3385 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3386 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3387 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3389 ASSERT_EQ(0, rbd_close(parent
));
3390 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3392 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3393 ioctx2
, child_name1
.c_str(), features
, &order
));
3394 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3395 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3396 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3397 test_list_children2(parent
, 1,
3398 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3400 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3401 ioctx1
, child_name2
.c_str(), features
, &order
));
3402 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3403 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3404 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3405 pool_name1
.c_str(), child_name2
.c_str());
3406 test_list_children2(parent
, 2,
3407 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3408 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3410 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3411 ioctx2
, child_name3
.c_str(), features
, &order
));
3412 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3413 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3414 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3415 pool_name1
.c_str(), child_name2
.c_str(),
3416 pool_name2
.c_str(), child_name3
.c_str());
3417 test_list_children2(parent
, 3,
3418 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3419 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3420 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3422 librados::IoCtx ioctx3
;
3423 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3424 ASSERT_EQ(0, rbd_close(image3
));
3425 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3426 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3427 pool_name1
.c_str(), child_name2
.c_str());
3428 test_list_children2(parent
, 3,
3429 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3430 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3431 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3433 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3434 ioctx2
, child_name4
.c_str(), features
, &order
));
3435 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3436 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3437 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3438 pool_name1
.c_str(), child_name2
.c_str(),
3439 pool_name2
.c_str(), child_name4
.c_str());
3440 test_list_children2(parent
, 4,
3441 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3442 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3443 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3444 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3446 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3447 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3448 pool_name1
.c_str(), child_name2
.c_str(),
3449 pool_name2
.c_str(), child_name3
.c_str(),
3450 pool_name2
.c_str(), child_name4
.c_str());
3451 test_list_children2(parent
, 4,
3452 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3453 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3454 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3455 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3457 ASSERT_EQ(0, rbd_close(image1
));
3458 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3459 test_list_children(parent
, 3,
3460 pool_name1
.c_str(), child_name2
.c_str(),
3461 pool_name2
.c_str(), child_name3
.c_str(),
3462 pool_name2
.c_str(), child_name4
.c_str());
3463 test_list_children2(parent
, 3,
3464 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3465 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3466 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3468 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3469 test_list_children(parent
, 2,
3470 pool_name1
.c_str(), child_name2
.c_str(),
3471 pool_name2
.c_str(), child_name4
.c_str());
3472 test_list_children2(parent
, 2,
3473 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3474 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3476 ASSERT_EQ(0, rbd_close(image4
));
3477 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3478 test_list_children(parent
, 1,
3479 pool_name1
.c_str(), child_name2
.c_str());
3480 test_list_children2(parent
, 1,
3481 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3484 ASSERT_EQ(0, rbd_close(image2
));
3485 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3486 test_list_children(parent
, 0);
3487 test_list_children2(parent
, 0);
3489 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3490 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3491 ASSERT_EQ(0, rbd_close(parent
));
3492 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3493 rados_ioctx_destroy(ioctx1
);
3494 rados_ioctx_destroy(ioctx2
);
3497 TEST_F(TestLibRBD
, ListChildrenTiered
)
3499 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3502 string pool_name1
= create_pool(true);
3503 string pool_name2
= create_pool(true);
3504 string pool_name3
= create_pool(true);
3505 ASSERT_NE("", pool_name1
);
3506 ASSERT_NE("", pool_name2
);
3507 ASSERT_NE("", pool_name3
);
3509 std::string cmdstr
= "{\"prefix\": \"osd tier add\", \"pool\": \"" +
3510 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\", \"force_nonempty\":\"\"}";
3512 cmd
[0] = (char *)cmdstr
.c_str();
3513 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3515 cmdstr
= "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
3516 pool_name3
+ "\", \"mode\":\"writeback\"}";
3517 cmd
[0] = (char *)cmdstr
.c_str();
3518 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3520 cmdstr
= "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
3521 pool_name1
+ "\", \"overlaypool\":\"" + pool_name3
+ "\"}";
3522 cmd
[0] = (char *)cmdstr
.c_str();
3523 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3525 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
3527 string parent_name
= get_temp_image_name();
3528 string child_name1
= get_temp_image_name();
3529 string child_name2
= get_temp_image_name();
3530 string child_name3
= get_temp_image_name();
3531 string child_name4
= get_temp_image_name();
3533 char child_id1
[4096];
3534 char child_id2
[4096];
3535 char child_id3
[4096];
3536 char child_id4
[4096];
3543 rados_ioctx_t ioctx1
, ioctx2
;
3544 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3545 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3552 ASSERT_EQ(0, get_features(&old_format
, &features
));
3553 ASSERT_FALSE(old_format
);
3555 // make a parent to clone from
3556 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3558 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3559 // create a snapshot, reopen as the parent we're interested in
3560 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3561 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3562 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3564 ASSERT_EQ(0, rbd_close(parent
));
3565 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3567 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3568 ioctx2
, child_name1
.c_str(), features
, &order
));
3569 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3570 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3571 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3572 test_list_children2(parent
, 1,
3573 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3575 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3576 ioctx1
, child_name2
.c_str(), features
, &order
));
3577 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3578 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3579 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3580 pool_name1
.c_str(), child_name2
.c_str());
3581 test_list_children2(parent
, 2,
3582 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3583 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3585 // read from the cache to populate it
3586 rbd_image_t tier_image
;
3587 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &tier_image
, NULL
));
3588 size_t len
= 4 * 1024 * 1024;
3589 char* buf
= (char*)malloc(len
);
3590 ssize_t size
= rbd_read(tier_image
, 0, len
, buf
);
3593 ASSERT_EQ(0, rbd_close(tier_image
));
3595 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3596 ioctx2
, child_name3
.c_str(), features
, &order
));
3597 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3598 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3599 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3600 pool_name1
.c_str(), child_name2
.c_str(),
3601 pool_name2
.c_str(), child_name3
.c_str());
3602 test_list_children2(parent
, 3,
3603 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3604 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3605 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3607 librados::IoCtx ioctx3
;
3608 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3609 ASSERT_EQ(0, rbd_close(image3
));
3610 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3611 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3612 pool_name1
.c_str(), child_name2
.c_str());
3613 test_list_children2(parent
, 3,
3614 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3615 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3616 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3618 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3619 ioctx2
, child_name4
.c_str(), features
, &order
));
3620 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3621 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3622 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3623 pool_name1
.c_str(), child_name2
.c_str(),
3624 pool_name2
.c_str(), child_name4
.c_str());
3625 test_list_children2(parent
, 4,
3626 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3627 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3628 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3629 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3631 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3632 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3633 pool_name1
.c_str(), child_name2
.c_str(),
3634 pool_name2
.c_str(), child_name3
.c_str(),
3635 pool_name2
.c_str(), child_name4
.c_str());
3636 test_list_children2(parent
, 4,
3637 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3638 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3639 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3640 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3642 ASSERT_EQ(0, rbd_close(image1
));
3643 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3644 test_list_children(parent
, 3,
3645 pool_name1
.c_str(), child_name2
.c_str(),
3646 pool_name2
.c_str(), child_name3
.c_str(),
3647 pool_name2
.c_str(), child_name4
.c_str());
3648 test_list_children2(parent
, 3,
3649 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3650 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3651 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3653 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3654 test_list_children(parent
, 2,
3655 pool_name1
.c_str(), child_name2
.c_str(),
3656 pool_name2
.c_str(), child_name4
.c_str());
3657 test_list_children2(parent
, 2,
3658 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3659 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3661 ASSERT_EQ(0, rbd_close(image4
));
3662 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3663 test_list_children(parent
, 1,
3664 pool_name1
.c_str(), child_name2
.c_str());
3665 test_list_children2(parent
, 1,
3666 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3668 ASSERT_EQ(0, rbd_close(image2
));
3669 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3670 test_list_children(parent
, 0);
3671 test_list_children2(parent
, 0);
3673 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3674 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3675 ASSERT_EQ(0, rbd_close(parent
));
3676 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3677 rados_ioctx_destroy(ioctx1
);
3678 rados_ioctx_destroy(ioctx2
);
3679 cmdstr
= "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
3681 cmd
[0] = (char *)cmdstr
.c_str();
3682 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3683 cmdstr
= "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
3684 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\"}";
3685 cmd
[0] = (char *)cmdstr
.c_str();
3686 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3689 TEST_F(TestLibRBD
, LockingPP
)
3691 librados::IoCtx ioctx
;
3692 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3696 librbd::Image image
;
3698 std::string name
= get_temp_image_name();
3699 uint64_t size
= 2 << 20;
3700 std::string cookie1
= "foo";
3701 std::string cookie2
= "bar";
3703 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3704 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3706 // no lockers initially
3707 std::list
<librbd::locker_t
> lockers
;
3710 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3711 ASSERT_EQ(0u, lockers
.size());
3714 // exclusive lock is exclusive
3715 ASSERT_EQ(0, image
.lock_exclusive(cookie1
));
3716 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
3717 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
3718 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
3719 ASSERT_EQ(-EBUSY
, image
.lock_shared(cookie1
, "test"));
3720 ASSERT_EQ(-EBUSY
, image
.lock_shared("", "test"));
3721 ASSERT_EQ(-EBUSY
, image
.lock_shared("", ""));
3724 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3725 ASSERT_TRUE(exclusive
);
3727 ASSERT_EQ(1u, lockers
.size());
3728 ASSERT_EQ(cookie1
, lockers
.front().cookie
);
3731 ASSERT_EQ(-ENOENT
, image
.unlock(""));
3732 ASSERT_EQ(-ENOENT
, image
.unlock(cookie2
));
3733 ASSERT_EQ(0, image
.unlock(cookie1
));
3734 ASSERT_EQ(-ENOENT
, image
.unlock(cookie1
));
3735 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3736 ASSERT_EQ(0u, lockers
.size());
3738 ASSERT_EQ(0, image
.lock_shared(cookie1
, ""));
3739 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
3740 ASSERT_EQ(0, image
.lock_shared(cookie2
, ""));
3741 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie2
, ""));
3742 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
3743 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie2
));
3744 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
3745 ASSERT_EQ(-EBUSY
, image
.lock_exclusive("test"));
3748 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3749 ASSERT_EQ(2u, lockers
.size());
3755 TEST_F(TestLibRBD
, FlushAio
)
3757 rados_ioctx_t ioctx
;
3758 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3762 std::string name
= get_temp_image_name();
3763 uint64_t size
= 2 << 20;
3764 size_t num_aios
= 256;
3766 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3767 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3769 char test_data
[TEST_IO_SIZE
+ 1];
3771 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3772 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3775 rbd_completion_t write_comps
[num_aios
];
3776 for (i
= 0; i
< num_aios
; ++i
) {
3777 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &write_comps
[i
]));
3778 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
3779 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
3783 rbd_completion_t flush_comp
;
3784 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &flush_comp
));
3785 ASSERT_EQ(0, rbd_aio_flush(image
, flush_comp
));
3786 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp
));
3787 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp
));
3788 rbd_aio_release(flush_comp
);
3790 for (i
= 0; i
< num_aios
; ++i
) {
3791 ASSERT_EQ(1, rbd_aio_is_complete(write_comps
[i
]));
3792 rbd_aio_release(write_comps
[i
]);
3795 ASSERT_PASSED(validate_object_map
, image
);
3796 ASSERT_EQ(0, rbd_close(image
));
3797 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
3798 rados_ioctx_destroy(ioctx
);
3801 TEST_F(TestLibRBD
, FlushAioPP
)
3803 librados::IoCtx ioctx
;
3804 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3808 librbd::Image image
;
3810 std::string name
= get_temp_image_name();
3811 uint64_t size
= 2 << 20;
3812 const size_t num_aios
= 256;
3814 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3815 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3817 char test_data
[TEST_IO_SIZE
+ 1];
3819 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3820 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3822 test_data
[TEST_IO_SIZE
] = '\0';
3824 librbd::RBD::AioCompletion
*write_comps
[num_aios
];
3825 ceph::bufferlist bls
[num_aios
];
3826 for (i
= 0; i
< num_aios
; ++i
) {
3827 bls
[i
].append(test_data
, strlen(test_data
));
3828 write_comps
[i
] = new librbd::RBD::AioCompletion(NULL
, NULL
);
3829 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
3830 ASSERT_EQ(0, image
.aio_write(offset
, TEST_IO_SIZE
, bls
[i
],
3834 librbd::RBD::AioCompletion
*flush_comp
=
3835 new librbd::RBD::AioCompletion(NULL
, NULL
);
3836 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
3837 ASSERT_EQ(0, flush_comp
->wait_for_complete());
3838 ASSERT_EQ(1, flush_comp
->is_complete());
3839 flush_comp
->release();
3841 for (i
= 0; i
< num_aios
; ++i
) {
3842 librbd::RBD::AioCompletion
*comp
= write_comps
[i
];
3843 ASSERT_EQ(1, comp
->is_complete());
3846 ASSERT_PASSED(validate_object_map
, image
);
3853 int iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3855 //cout << "iterate_cb " << off << "~" << len << std::endl;
3856 interval_set
<uint64_t> *diff
= static_cast<interval_set
<uint64_t> *>(arg
);
3857 diff
->insert(off
, len
);
3861 static int iterate_error_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3866 void scribble(librbd::Image
& image
, int n
, int max
, bool skip_discard
,
3867 interval_set
<uint64_t> *exists
,
3868 interval_set
<uint64_t> *what
)
3872 interval_set
<uint64_t> exists_at_start
= *exists
;
3874 for (int i
=0; i
<n
; i
++) {
3875 uint64_t off
= rand() % (size
- max
+ 1);
3876 uint64_t len
= 1 + rand() % max
;
3877 if (!skip_discard
&& rand() % 4 == 0) {
3878 ASSERT_EQ((int)len
, image
.discard(off
, len
));
3879 interval_set
<uint64_t> w
;
3882 // the zeroed bit no longer exists...
3883 w
.intersection_of(*exists
);
3884 exists
->subtract(w
);
3886 // the bits we discarded are no long written...
3887 interval_set
<uint64_t> w2
= w
;
3888 w2
.intersection_of(*what
);
3891 // except for the extents that existed at the start that we overwrote.
3892 interval_set
<uint64_t> w3
;
3893 w3
.insert(off
, len
);
3894 w3
.intersection_of(exists_at_start
);
3899 bl
.append(buffer::create(len
));
3901 ASSERT_EQ((int)len
, image
.write(off
, len
, bl
));
3902 interval_set
<uint64_t> w
;
3905 exists
->union_of(w
);
3910 interval_set
<uint64_t> round_diff_interval(const interval_set
<uint64_t>& diff
,
3911 uint64_t object_size
)
3913 if (object_size
== 0) {
3917 interval_set
<uint64_t> rounded_diff
;
3918 for (interval_set
<uint64_t>::const_iterator it
= diff
.begin();
3919 it
!= diff
.end(); ++it
) {
3920 uint64_t off
= it
.get_start();
3921 uint64_t len
= it
.get_len();
3922 off
-= off
% object_size
;
3923 len
+= (object_size
- (len
% object_size
));
3924 interval_set
<uint64_t> interval
;
3925 interval
.insert(off
, len
);
3926 rounded_diff
.union_of(interval
);
3928 return rounded_diff
;
3931 template <typename T
>
3932 class DiffIterateTest
: public TestLibRBD
{
3934 static const uint8_t whole_object
= T::whole_object
;
3937 template <bool _whole_object
>
3938 class DiffIterateParams
{
3940 static const uint8_t whole_object
= _whole_object
;
3943 typedef ::testing::Types
<DiffIterateParams
<false>,
3944 DiffIterateParams
<true> > DiffIterateTypes
;
3945 TYPED_TEST_SUITE(DiffIterateTest
, DiffIterateTypes
);
3947 TYPED_TEST(DiffIterateTest
, DiffIterate
)
3949 librados::IoCtx ioctx
;
3950 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3952 bool skip_discard
= this->is_skip_partial_discard_enabled();
3956 librbd::Image image
;
3958 std::string name
= this->get_temp_image_name();
3959 uint64_t size
= 20 << 20;
3961 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3962 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3964 uint64_t object_size
= 0;
3965 if (this->whole_object
) {
3966 object_size
= 1 << order
;
3969 interval_set
<uint64_t> exists
;
3970 interval_set
<uint64_t> one
, two
;
3971 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
3972 cout
<< " wrote " << one
<< std::endl
;
3973 ASSERT_EQ(0, image
.snap_create("one"));
3974 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
3976 two
= round_diff_interval(two
, object_size
);
3977 cout
<< " wrote " << two
<< std::endl
;
3979 interval_set
<uint64_t> diff
;
3980 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
3981 iterate_cb
, (void *)&diff
));
3982 cout
<< " diff was " << diff
<< std::endl
;
3983 if (!two
.subset_of(diff
)) {
3984 interval_set
<uint64_t> i
;
3985 i
.intersection_of(two
, diff
);
3986 interval_set
<uint64_t> l
= two
;
3988 cout
<< " ... two - (two*diff) = " << l
<< std::endl
;
3990 ASSERT_TRUE(two
.subset_of(diff
));
3995 struct diff_extent
{
3996 diff_extent(uint64_t _offset
, uint64_t _length
, bool _exists
,
3997 uint64_t object_size
) :
3998 offset(_offset
), length(_length
), exists(_exists
)
4000 if (object_size
!= 0) {
4001 offset
-= offset
% object_size
;
4002 length
= object_size
;
4008 bool operator==(const diff_extent
& o
) const {
4009 return offset
== o
.offset
&& length
== o
.length
&& exists
== o
.exists
;
4013 ostream
& operator<<(ostream
& o
, const diff_extent
& e
) {
4014 return o
<< '(' << e
.offset
<< '~' << e
.length
<< ' ' << (e
.exists
? "true" : "false") << ')';
4017 int vector_iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
4019 cout
<< "iterate_cb " << off
<< "~" << len
<< std::endl
;
4020 vector
<diff_extent
> *diff
= static_cast<vector
<diff_extent
> *>(arg
);
4021 diff
->push_back(diff_extent(off
, len
, exists
, 0));
4025 TYPED_TEST(DiffIterateTest
, DiffIterateDiscard
)
4027 librados::IoCtx ioctx
;
4028 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4031 librbd::Image image
;
4033 std::string name
= this->get_temp_image_name();
4034 uint64_t size
= 20 << 20;
4036 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4037 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4039 uint64_t object_size
= 0;
4040 if (this->whole_object
) {
4041 object_size
= 1 << order
;
4043 vector
<diff_extent
> extents
;
4044 ceph::bufferlist bl
;
4046 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4047 vector_iterate_cb
, (void *) &extents
));
4048 ASSERT_EQ(0u, extents
.size());
4051 memset(data
, 1, sizeof(data
));
4052 bl
.append(data
, 256);
4053 ASSERT_EQ(256, image
.write(0, 256, bl
));
4054 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4055 vector_iterate_cb
, (void *) &extents
));
4056 ASSERT_EQ(1u, extents
.size());
4057 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4060 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4063 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4064 vector_iterate_cb
, (void *) &extents
));
4065 ASSERT_EQ(0u, extents
.size());
4067 ASSERT_EQ(0, image
.snap_create("snap1"));
4068 ASSERT_EQ(256, image
.write(0, 256, bl
));
4069 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4070 vector_iterate_cb
, (void *) &extents
));
4071 ASSERT_EQ(1u, extents
.size());
4072 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4073 ASSERT_EQ(0, image
.snap_create("snap2"));
4075 ASSERT_EQ(obj_ofs
, image
.discard(0, obj_ofs
));
4078 ASSERT_EQ(0, image
.snap_set("snap2"));
4079 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4080 vector_iterate_cb
, (void *) &extents
));
4081 ASSERT_EQ(1u, extents
.size());
4082 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4084 ASSERT_EQ(0, image
.snap_set(NULL
));
4085 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4086 ASSERT_EQ(0, image
.snap_create("snap3"));
4087 ASSERT_EQ(0, image
.snap_set("snap3"));
4090 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4091 vector_iterate_cb
, (void *) &extents
));
4092 ASSERT_EQ(1u, extents
.size());
4093 ASSERT_EQ(diff_extent(0, 256, false, object_size
), extents
[0]);
4094 ASSERT_PASSED(this->validate_object_map
, image
);
4097 TYPED_TEST(DiffIterateTest
, DiffIterateStress
)
4099 librados::IoCtx ioctx
;
4100 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4102 bool skip_discard
= this->is_skip_partial_discard_enabled();
4105 librbd::Image image
;
4107 std::string name
= this->get_temp_image_name();
4108 uint64_t size
= 400 << 20;
4110 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4111 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4113 uint64_t object_size
= 0;
4114 if (this->whole_object
) {
4115 object_size
= 1 << order
;
4118 interval_set
<uint64_t> curexists
;
4119 vector
<interval_set
<uint64_t> > wrote
;
4120 vector
<interval_set
<uint64_t> > exists
;
4121 vector
<string
> snap
;
4123 for (int i
=0; i
<n
; i
++) {
4124 interval_set
<uint64_t> w
;
4125 scribble(image
, 10, 8192000, skip_discard
, &curexists
, &w
);
4126 cout
<< " i=" << i
<< " exists " << curexists
<< " wrote " << w
<< std::endl
;
4127 string s
= "snap" + stringify(i
);
4128 ASSERT_EQ(0, image
.snap_create(s
.c_str()));
4130 exists
.push_back(curexists
);
4134 for (int h
=0; h
<n
-1; h
++) {
4135 for (int i
=0; i
<n
-h
-1; i
++) {
4136 for (int j
=(h
==0 ? i
+1 : n
-1); j
<n
; j
++) {
4137 interval_set
<uint64_t> diff
, actual
, uex
;
4138 for (int k
=i
+1; k
<=j
; k
++)
4139 diff
.union_of(wrote
[k
]);
4140 cout
<< "from " << i
<< " to "
4141 << (h
!= 0 ? string("HEAD") : stringify(j
)) << " diff "
4142 << round_diff_interval(diff
, object_size
) << std::endl
;
4144 // limit to extents that exists both at the beginning and at the end
4145 uex
.union_of(exists
[i
], exists
[j
]);
4146 diff
.intersection_of(uex
);
4147 diff
= round_diff_interval(diff
, object_size
);
4148 cout
<< " limited diff " << diff
<< std::endl
;
4150 ASSERT_EQ(0, image
.snap_set(h
==0 ? snap
[j
].c_str() : NULL
));
4151 ASSERT_EQ(0, image
.diff_iterate2(snap
[i
].c_str(), 0, size
, true,
4152 this->whole_object
, iterate_cb
,
4154 cout
<< " actual was " << actual
<< std::endl
;
4155 if (!diff
.subset_of(actual
)) {
4156 interval_set
<uint64_t> i
;
4157 i
.intersection_of(diff
, actual
);
4158 interval_set
<uint64_t> l
= diff
;
4160 cout
<< " ... diff - (actual*diff) = " << l
<< std::endl
;
4162 ASSERT_TRUE(diff
.subset_of(actual
));
4165 ASSERT_EQ(0, image
.snap_set(NULL
));
4166 ASSERT_EQ(0, image
.snap_remove(snap
[n
-h
-1].c_str()));
4169 ASSERT_PASSED(this->validate_object_map
, image
);
4172 TYPED_TEST(DiffIterateTest
, DiffIterateRegression6926
)
4174 librados::IoCtx ioctx
;
4175 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4178 librbd::Image image
;
4180 std::string name
= this->get_temp_image_name();
4181 uint64_t size
= 20 << 20;
4183 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4184 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4186 uint64_t object_size
= 0;
4187 if (this->whole_object
) {
4188 object_size
= 1 << order
;
4190 vector
<diff_extent
> extents
;
4191 ceph::bufferlist bl
;
4193 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4194 vector_iterate_cb
, (void *) &extents
));
4195 ASSERT_EQ(0u, extents
.size());
4197 ASSERT_EQ(0, image
.snap_create("snap1"));
4199 memset(data
, 1, sizeof(data
));
4200 bl
.append(data
, 256);
4201 ASSERT_EQ(256, image
.write(0, 256, bl
));
4204 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4205 vector_iterate_cb
, (void *) &extents
));
4206 ASSERT_EQ(1u, extents
.size());
4207 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4209 ASSERT_EQ(0, image
.snap_set("snap1"));
4211 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4212 vector_iterate_cb
, (void *) &extents
));
4213 ASSERT_EQ(static_cast<size_t>(0), extents
.size());
4216 TYPED_TEST(DiffIterateTest
, DiffIterateIgnoreParent
)
4218 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4220 librados::IoCtx ioctx
;
4221 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4223 bool skip_discard
= this->is_skip_partial_discard_enabled();
4226 librbd::Image image
;
4227 std::string name
= this->get_temp_image_name();
4228 uint64_t size
= 20 << 20;
4231 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4232 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4234 uint64_t object_size
= 0;
4235 if (this->whole_object
) {
4236 object_size
= 1 << order
;
4240 bl
.append(buffer::create(size
));
4242 interval_set
<uint64_t> one
;
4243 one
.insert(0, size
);
4244 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
4245 ASSERT_EQ(0, image
.snap_create("one"));
4246 ASSERT_EQ(0, image
.snap_protect("one"));
4248 std::string clone_name
= this->get_temp_image_name();
4249 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
4250 RBD_FEATURE_LAYERING
, &order
));
4251 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4253 interval_set
<uint64_t> exists
;
4254 interval_set
<uint64_t> two
;
4255 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4256 two
= round_diff_interval(two
, object_size
);
4257 cout
<< " wrote " << two
<< " to clone" << std::endl
;
4259 interval_set
<uint64_t> diff
;
4260 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, false, this->whole_object
,
4261 iterate_cb
, (void *)&diff
));
4262 cout
<< " diff was " << diff
<< std::endl
;
4263 if (!this->whole_object
) {
4264 ASSERT_FALSE(one
.subset_of(diff
));
4266 ASSERT_TRUE(two
.subset_of(diff
));
4269 TYPED_TEST(DiffIterateTest
, DiffIterateCallbackError
)
4271 librados::IoCtx ioctx
;
4272 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4274 bool skip_discard
= this->is_skip_partial_discard_enabled();
4278 librbd::Image image
;
4280 std::string name
= this->get_temp_image_name();
4281 uint64_t size
= 20 << 20;
4283 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4284 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4286 interval_set
<uint64_t> exists
;
4287 interval_set
<uint64_t> one
;
4288 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4289 cout
<< " wrote " << one
<< std::endl
;
4291 interval_set
<uint64_t> diff
;
4292 ASSERT_EQ(-EINVAL
, image
.diff_iterate2(NULL
, 0, size
, true,
4294 iterate_error_cb
, NULL
));
4299 TYPED_TEST(DiffIterateTest
, DiffIterateParentDiscard
)
4301 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4303 librados::IoCtx ioctx
;
4304 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4306 bool skip_discard
= this->is_skip_partial_discard_enabled();
4309 librbd::Image image
;
4310 std::string name
= this->get_temp_image_name();
4311 uint64_t size
= 20 << 20;
4314 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4315 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4317 uint64_t object_size
= 0;
4318 if (this->whole_object
) {
4319 object_size
= 1 << order
;
4322 interval_set
<uint64_t> exists
;
4323 interval_set
<uint64_t> one
;
4324 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4325 ASSERT_EQ(0, image
.snap_create("one"));
4327 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4328 ASSERT_EQ(0, image
.snap_create("two"));
4329 ASSERT_EQ(0, image
.snap_protect("two"));
4333 std::string clone_name
= this->get_temp_image_name();
4334 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "two", ioctx
,
4335 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
4336 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4338 interval_set
<uint64_t> two
;
4339 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4340 two
= round_diff_interval(two
, object_size
);
4342 interval_set
<uint64_t> diff
;
4343 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4344 iterate_cb
, (void *)&diff
));
4345 ASSERT_TRUE(two
.subset_of(diff
));
4348 TEST_F(TestLibRBD
, ZeroLengthWrite
)
4350 rados_ioctx_t ioctx
;
4351 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4355 std::string name
= get_temp_image_name();
4356 uint64_t size
= 2 << 20;
4358 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4359 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4362 ASSERT_EQ(0, rbd_write(image
, 0, 0, NULL
));
4363 ASSERT_EQ(1, rbd_read(image
, 0, 1, read_data
));
4364 ASSERT_EQ('\0', read_data
[0]);
4366 ASSERT_PASSED(validate_object_map
, image
);
4367 ASSERT_EQ(0, rbd_close(image
));
4369 rados_ioctx_destroy(ioctx
);
4373 TEST_F(TestLibRBD
, ZeroLengthDiscard
)
4375 rados_ioctx_t ioctx
;
4376 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4380 std::string name
= get_temp_image_name();
4381 uint64_t size
= 2 << 20;
4383 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4384 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4386 const char data
[] = "blah";
4387 char read_data
[sizeof(data
)];
4388 ASSERT_EQ((int)strlen(data
), rbd_write(image
, 0, strlen(data
), data
));
4389 ASSERT_EQ(0, rbd_discard(image
, 0, 0));
4390 ASSERT_EQ((int)strlen(data
), rbd_read(image
, 0, strlen(data
), read_data
));
4391 ASSERT_EQ(0, memcmp(data
, read_data
, strlen(data
)));
4393 ASSERT_PASSED(validate_object_map
, image
);
4394 ASSERT_EQ(0, rbd_close(image
));
4396 rados_ioctx_destroy(ioctx
);
4399 TEST_F(TestLibRBD
, ZeroLengthRead
)
4401 rados_ioctx_t ioctx
;
4402 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4406 std::string name
= get_temp_image_name();
4407 uint64_t size
= 2 << 20;
4409 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4410 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4413 ASSERT_EQ(0, rbd_read(image
, 0, 0, read_data
));
4415 ASSERT_EQ(0, rbd_close(image
));
4417 rados_ioctx_destroy(ioctx
);
4420 TEST_F(TestLibRBD
, LargeCacheRead
)
4422 std::string config_value
;
4423 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", config_value
));
4424 if (config_value
== "false") {
4425 std::cout
<< "SKIPPING due to disabled cache" << std::endl
;
4429 rados_ioctx_t ioctx
;
4430 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4432 uint32_t new_cache_size
= 1 << 20;
4433 std::string orig_cache_size
;
4434 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", orig_cache_size
));
4435 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size",
4436 stringify(new_cache_size
).c_str()));
4437 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", config_value
));
4438 ASSERT_EQ(stringify(new_cache_size
), config_value
);
4439 BOOST_SCOPE_EXIT( (orig_cache_size
) ) {
4440 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size", orig_cache_size
.c_str()));
4441 } BOOST_SCOPE_EXIT_END
;
4445 std::string name
= get_temp_image_name();
4446 uint64_t size
= 1 << order
;
4448 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4449 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4451 std::string
buffer(1 << order
, '1');
4453 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
4454 rbd_write(image
, 0, buffer
.size(), buffer
.c_str()));
4456 ASSERT_EQ(0, rbd_invalidate_cache(image
));
4458 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
4459 rbd_read(image
, 0, buffer
.size(), &buffer
[0]));
4461 ASSERT_EQ(0, rbd_close(image
));
4463 rados_ioctx_destroy(ioctx
);
4466 TEST_F(TestLibRBD
, TestPendingAio
)
4468 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4470 rados_ioctx_t ioctx
;
4471 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4478 ASSERT_EQ(0, get_features(&old_format
, &features
));
4479 ASSERT_FALSE(old_format
);
4481 std::string name
= get_temp_image_name();
4483 uint64_t size
= 4 << 20;
4484 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
4486 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4488 char test_data
[TEST_IO_SIZE
];
4489 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4490 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4493 size_t num_aios
= 256;
4494 rbd_completion_t comps
[num_aios
];
4495 for (size_t i
= 0; i
< num_aios
; ++i
) {
4496 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
4497 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4498 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
4501 for (size_t i
= 0; i
< num_aios
; ++i
) {
4502 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps
[i
]));
4503 rbd_aio_release(comps
[i
]);
4505 ASSERT_EQ(0, rbd_invalidate_cache(image
));
4507 for (size_t i
= 0; i
< num_aios
; ++i
) {
4508 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
4509 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4510 ASSERT_LE(0, rbd_aio_read(image
, offset
, TEST_IO_SIZE
, test_data
,
4514 ASSERT_PASSED(validate_object_map
, image
);
4515 ASSERT_EQ(0, rbd_close(image
));
4516 for (size_t i
= 0; i
< num_aios
; ++i
) {
4517 ASSERT_EQ(1, rbd_aio_is_complete(comps
[i
]));
4518 rbd_aio_release(comps
[i
]);
4521 rados_ioctx_destroy(ioctx
);
4524 void compare_and_write_copyup(librados::IoCtx
&ioctx
, bool deep_copyup
,
4528 std::string parent_name
= TestLibRBD::get_temp_image_name();
4529 uint64_t size
= 2 << 20;
4531 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4533 librbd::Image parent_image
;
4534 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4537 bl
.append(std::string(4096, '1'));
4538 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
4540 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4541 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4544 ASSERT_EQ(0, parent_image
.features(&features
));
4546 std::string clone_name
= TestLibRBD::get_temp_image_name();
4547 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4548 clone_name
.c_str(), features
, &order
));
4550 librbd::Image clone_image
;
4551 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
4553 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
4557 cmp_bl
.append(std::string(96, '1'));
4558 bufferlist write_bl
;
4559 write_bl
.append(std::string(512, '2'));
4560 uint64_t mismatch_off
;
4561 ASSERT_EQ((ssize_t
)write_bl
.length(),
4562 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
4563 write_bl
, &mismatch_off
, 0));
4566 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
4568 bufferlist expected_bl
;
4569 expected_bl
.append(std::string(512, '1'));
4570 expected_bl
.append(std::string(512, '2'));
4571 expected_bl
.append(std::string(3072, '1'));
4572 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
4576 TEST_F(TestLibRBD
, CompareAndWriteCopyup
)
4578 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4580 librados::IoCtx ioctx
;
4581 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4583 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, false);
4584 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, true);
4587 void compare_and_write_copyup_mismatch(librados::IoCtx
&ioctx
,
4588 bool deep_copyup
, bool *passed
)
4591 std::string parent_name
= TestLibRBD::get_temp_image_name();
4592 uint64_t size
= 2 << 20;
4594 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4596 librbd::Image parent_image
;
4597 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4600 bl
.append(std::string(4096, '1'));
4601 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
4603 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4604 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4607 ASSERT_EQ(0, parent_image
.features(&features
));
4609 std::string clone_name
= TestLibRBD::get_temp_image_name();
4610 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4611 clone_name
.c_str(), features
, &order
));
4613 librbd::Image clone_image
;
4614 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
4616 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
4620 cmp_bl
.append(std::string(48, '1'));
4621 cmp_bl
.append(std::string(48, '3'));
4622 bufferlist write_bl
;
4623 write_bl
.append(std::string(512, '2'));
4624 uint64_t mismatch_off
;
4626 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
4627 write_bl
, &mismatch_off
, 0));
4628 ASSERT_EQ(48U, mismatch_off
);
4631 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
4633 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4637 TEST_F(TestLibRBD
, CompareAndWriteCopyupMismatch
)
4639 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4641 librados::IoCtx ioctx
;
4642 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4644 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, false);
4645 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, true);
4648 TEST_F(TestLibRBD
, Flatten
)
4650 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4652 librados::IoCtx ioctx
;
4653 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4656 std::string parent_name
= get_temp_image_name();
4657 uint64_t size
= 2 << 20;
4659 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4661 librbd::Image parent_image
;
4662 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4665 bl
.append(std::string(4096, '1'));
4666 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
4668 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4669 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4672 ASSERT_EQ(0, parent_image
.features(&features
));
4674 std::string clone_name
= get_temp_image_name();
4675 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4676 clone_name
.c_str(), features
, &order
));
4678 librbd::Image clone_image
;
4679 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
4680 ASSERT_EQ(0, clone_image
.flatten());
4682 librbd::RBD::AioCompletion
*read_comp
=
4683 new librbd::RBD::AioCompletion(NULL
, NULL
);
4685 clone_image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
4686 ASSERT_EQ(0, read_comp
->wait_for_complete());
4687 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
4688 read_comp
->release();
4689 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4691 ASSERT_PASSED(validate_object_map
, clone_image
);
4694 TEST_F(TestLibRBD
, Sparsify
)
4696 rados_ioctx_t ioctx
;
4697 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
4698 BOOST_SCOPE_EXIT_ALL(&ioctx
) {
4699 rados_ioctx_destroy(ioctx
);
4702 const size_t CHUNK_SIZE
= 4096 * 2;
4705 std::string name
= get_temp_image_name();
4706 uint64_t size
= CHUNK_SIZE
* 1024;
4708 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4709 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4710 BOOST_SCOPE_EXIT_ALL(&image
) {
4714 char test_data
[4 * CHUNK_SIZE
+ 1];
4715 for (size_t i
= 0; i
< 4 ; ++i
) {
4716 for (size_t j
= 0; j
< CHUNK_SIZE
; j
++) {
4718 test_data
[i
* CHUNK_SIZE
+ j
] = (char)(rand() % (126 - 33) + 33);
4720 test_data
[i
* CHUNK_SIZE
+ j
] = '\0';
4724 test_data
[4 * CHUNK_SIZE
] = '\0';
4726 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
4727 ASSERT_EQ(0, rbd_flush(image
));
4729 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 16));
4730 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 1 << (order
+ 1)));
4731 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 4096 + 1));
4732 ASSERT_EQ(0, rbd_sparsify(image
, 4096));
4734 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
4737 TEST_F(TestLibRBD
, SparsifyPP
)
4739 librados::IoCtx ioctx
;
4740 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4743 std::string name
= get_temp_image_name();
4744 uint64_t size
= 12 * 1024 * 1024;
4746 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4748 librbd::Image image
;
4749 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
4752 bl
.append(std::string(4096, '\0'));
4753 bl
.append(std::string(4096, '1'));
4754 bl
.append(std::string(4096, '\0'));
4755 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
4756 ASSERT_EQ(0, image
.flush());
4758 ASSERT_EQ(-EINVAL
, image
.sparsify(16));
4759 ASSERT_EQ(-EINVAL
, image
.sparsify(1 << (order
+ 1)));
4760 ASSERT_EQ(-EINVAL
, image
.sparsify(4096 + 1));
4761 ASSERT_EQ(0, image
.sparsify(4096));
4764 ASSERT_EQ((ssize_t
)bl
.length(), image
.read(0, bl
.length(), read_bl
));
4765 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4767 ASSERT_PASSED(validate_object_map
, image
);
4770 TEST_F(TestLibRBD
, SnapshotLimit
)
4772 rados_ioctx_t ioctx
;
4773 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4777 std::string name
= get_temp_image_name();
4778 uint64_t size
= 2 << 20;
4781 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4782 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4784 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
4785 ASSERT_EQ(UINT64_MAX
, limit
);
4786 ASSERT_EQ(0, rbd_snap_set_limit(image
, 2));
4787 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
4788 ASSERT_EQ(2U, limit
);
4790 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
4791 ASSERT_EQ(-ERANGE
, rbd_snap_set_limit(image
, 0));
4792 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
4793 ASSERT_EQ(-EDQUOT
, rbd_snap_create(image
, "snap3"));
4794 ASSERT_EQ(0, rbd_snap_set_limit(image
, UINT64_MAX
));
4795 ASSERT_EQ(0, rbd_snap_create(image
, "snap3"));
4796 ASSERT_EQ(0, rbd_close(image
));
4798 rados_ioctx_destroy(ioctx
);
4802 TEST_F(TestLibRBD
, SnapshotLimitPP
)
4804 librados::IoCtx ioctx
;
4805 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4809 librbd::Image image
;
4810 std::string name
= get_temp_image_name();
4811 uint64_t size
= 2 << 20;
4815 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4816 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4818 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
4819 ASSERT_EQ(UINT64_MAX
, limit
);
4820 ASSERT_EQ(0, image
.snap_set_limit(2));
4821 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
4822 ASSERT_EQ(2U, limit
);
4824 ASSERT_EQ(0, image
.snap_create("snap1"));
4825 ASSERT_EQ(-ERANGE
, image
.snap_set_limit(0));
4826 ASSERT_EQ(0, image
.snap_create("snap2"));
4827 ASSERT_EQ(-EDQUOT
, image
.snap_create("snap3"));
4828 ASSERT_EQ(0, image
.snap_set_limit(UINT64_MAX
));
4829 ASSERT_EQ(0, image
.snap_create("snap3"));
4835 TEST_F(TestLibRBD
, RebuildObjectMapViaLockOwner
)
4837 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_OBJECT_MAP
);
4839 librados::IoCtx ioctx
;
4840 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4843 std::string name
= get_temp_image_name();
4844 uint64_t size
= 2 << 20;
4846 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4848 std::string object_map_oid
;
4850 librbd::Image image
;
4851 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4853 std::string image_id
;
4854 ASSERT_EQ(0, get_image_id(image
, &image_id
));
4855 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
4858 // corrupt the object map
4861 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
4863 librbd::Image image1
;
4864 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4868 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4869 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4870 ASSERT_TRUE(lock_owner
);
4873 ASSERT_EQ(0, image1
.get_flags(&flags
));
4874 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
4876 librbd::Image image2
;
4877 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4878 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4879 ASSERT_FALSE(lock_owner
);
4881 PrintProgress prog_ctx
;
4882 ASSERT_EQ(0, image2
.rebuild_object_map(prog_ctx
));
4883 ASSERT_PASSED(validate_object_map
, image1
);
4884 ASSERT_PASSED(validate_object_map
, image2
);
4887 TEST_F(TestLibRBD
, RenameViaLockOwner
)
4889 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
4891 librados::IoCtx ioctx
;
4892 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4895 std::string name
= get_temp_image_name();
4896 uint64_t size
= 2 << 20;
4898 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4900 librbd::Image image1
;
4901 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4904 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4907 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4908 ASSERT_TRUE(lock_owner
);
4910 std::string new_name
= get_temp_image_name();
4911 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
4912 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4913 ASSERT_TRUE(lock_owner
);
4915 librbd::Image image2
;
4916 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, new_name
.c_str(), NULL
));
4919 TEST_F(TestLibRBD
, SnapCreateViaLockOwner
)
4921 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
4923 librados::IoCtx ioctx
;
4924 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4927 std::string name
= get_temp_image_name();
4928 uint64_t size
= 2 << 20;
4930 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4932 librbd::Image image1
;
4933 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4935 // switch to writeback cache
4936 ASSERT_EQ(0, image1
.flush());
4939 bl
.append(std::string(4096, '1'));
4940 ASSERT_EQ((ssize_t
)bl
.length(), image1
.write(0, bl
.length(), bl
));
4943 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4944 ASSERT_TRUE(lock_owner
);
4946 librbd::Image image2
;
4947 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4949 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4950 ASSERT_FALSE(lock_owner
);
4952 ASSERT_EQ(0, image2
.snap_create("snap1"));
4954 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
4955 ASSERT_TRUE(exists
);
4956 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
4957 ASSERT_TRUE(exists
);
4959 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4960 ASSERT_TRUE(lock_owner
);
4963 TEST_F(TestLibRBD
, SnapRemoveViaLockOwner
)
4965 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
4967 librados::IoCtx ioctx
;
4968 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4971 std::string name
= get_temp_image_name();
4972 uint64_t size
= 2 << 20;
4974 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4976 librbd::Image image1
;
4977 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4980 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4981 ASSERT_EQ(0, image1
.snap_create("snap1"));
4984 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4985 ASSERT_TRUE(lock_owner
);
4987 librbd::Image image2
;
4988 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4990 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4991 ASSERT_FALSE(lock_owner
);
4993 ASSERT_EQ(0, image2
.snap_remove("snap1"));
4995 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
4996 ASSERT_FALSE(exists
);
4997 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
4998 ASSERT_FALSE(exists
);
5000 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5001 ASSERT_TRUE(lock_owner
);
5004 TEST_F(TestLibRBD
, EnableJournalingViaLockOwner
)
5006 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
5008 librados::IoCtx ioctx
;
5009 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5012 std::string name
= get_temp_image_name();
5013 uint64_t size
= 2 << 20;
5015 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5017 librbd::Image image1
;
5018 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5021 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5024 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5025 ASSERT_TRUE(lock_owner
);
5027 librbd::Image image2
;
5028 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5030 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, false));
5032 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5033 ASSERT_TRUE(lock_owner
);
5034 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5035 ASSERT_FALSE(lock_owner
);
5037 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, true));
5039 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5040 ASSERT_FALSE(lock_owner
);
5041 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5042 ASSERT_TRUE(lock_owner
);
5045 TEST_F(TestLibRBD
, SnapRemove2
)
5047 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5049 librados::IoCtx ioctx
;
5050 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5053 std::string name
= get_temp_image_name();
5054 uint64_t size
= 2 << 20;
5056 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5058 librbd::Image image1
;
5059 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5062 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5063 ASSERT_EQ(0, image1
.snap_create("snap1"));
5065 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5066 ASSERT_TRUE(exists
);
5067 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5069 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5070 ASSERT_TRUE(is_protected
);
5073 ASSERT_EQ(0, image1
.features(&features
));
5075 std::string child_name
= get_temp_image_name();
5076 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5077 child_name
.c_str(), features
, &order
));
5079 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5080 ASSERT_TRUE(exists
);
5081 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5082 ASSERT_TRUE(is_protected
);
5084 ASSERT_EQ(-EBUSY
, image1
.snap_remove("snap1"));
5086 ASSERT_EQ(0, image1
.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE
, pp
));
5087 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5088 ASSERT_FALSE(exists
);
5091 TEST_F(TestLibRBD
, SnapRenameViaLockOwner
)
5093 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5095 librados::IoCtx ioctx
;
5096 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5099 std::string name
= get_temp_image_name();
5100 uint64_t size
= 2 << 20;
5102 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5104 librbd::Image image1
;
5105 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5108 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5109 ASSERT_EQ(0, image1
.snap_create("snap1"));
5112 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5113 ASSERT_TRUE(lock_owner
);
5115 librbd::Image image2
;
5116 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5118 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5119 ASSERT_FALSE(lock_owner
);
5121 ASSERT_EQ(0, image2
.snap_rename("snap1", "snap1-rename"));
5123 ASSERT_EQ(0, image1
.snap_exists2("snap1-rename", &exists
));
5124 ASSERT_TRUE(exists
);
5125 ASSERT_EQ(0, image2
.snap_exists2("snap1-rename", &exists
));
5126 ASSERT_TRUE(exists
);
5128 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5129 ASSERT_TRUE(lock_owner
);
5132 TEST_F(TestLibRBD
, SnapProtectViaLockOwner
)
5134 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5136 librados::IoCtx ioctx
;
5137 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5140 std::string name
= get_temp_image_name();
5141 uint64_t size
= 2 << 20;
5143 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5145 librbd::Image image1
;
5146 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5149 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5152 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5153 ASSERT_TRUE(lock_owner
);
5154 ASSERT_EQ(0, image1
.snap_create("snap1"));
5156 librbd::Image image2
;
5157 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5159 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5160 ASSERT_FALSE(lock_owner
);
5162 ASSERT_EQ(0, image2
.snap_protect("snap1"));
5164 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5165 ASSERT_TRUE(is_protected
);
5166 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5167 ASSERT_TRUE(is_protected
);
5169 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5170 ASSERT_TRUE(lock_owner
);
5173 TEST_F(TestLibRBD
, SnapUnprotectViaLockOwner
)
5175 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5177 librados::IoCtx ioctx
;
5178 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5181 std::string name
= get_temp_image_name();
5182 uint64_t size
= 2 << 20;
5184 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5186 librbd::Image image1
;
5187 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5190 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5193 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5194 ASSERT_TRUE(lock_owner
);
5195 ASSERT_EQ(0, image1
.snap_create("snap1"));
5196 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5198 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5199 ASSERT_TRUE(is_protected
);
5201 librbd::Image image2
;
5202 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5204 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5205 ASSERT_FALSE(lock_owner
);
5207 ASSERT_EQ(0, image2
.snap_unprotect("snap1"));
5208 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5209 ASSERT_FALSE(is_protected
);
5210 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5211 ASSERT_FALSE(is_protected
);
5213 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5214 ASSERT_TRUE(lock_owner
);
5217 TEST_F(TestLibRBD
, FlattenViaLockOwner
)
5219 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5221 librados::IoCtx ioctx
;
5222 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5225 std::string parent_name
= get_temp_image_name();
5226 uint64_t size
= 2 << 20;
5228 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5230 librbd::Image parent_image
;
5231 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5232 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5233 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5236 ASSERT_EQ(0, parent_image
.features(&features
));
5238 std::string name
= get_temp_image_name();
5239 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5240 name
.c_str(), features
, &order
));
5242 librbd::Image image1
;
5243 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5246 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5249 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5250 ASSERT_TRUE(lock_owner
);
5252 librbd::Image image2
;
5253 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5255 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5256 ASSERT_FALSE(lock_owner
);
5258 ASSERT_EQ(0, image2
.flatten());
5260 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5261 ASSERT_TRUE(lock_owner
);
5262 ASSERT_PASSED(validate_object_map
, image1
);
5265 TEST_F(TestLibRBD
, ResizeViaLockOwner
)
5267 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5269 librados::IoCtx ioctx
;
5270 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5273 std::string name
= get_temp_image_name();
5274 uint64_t size
= 2 << 20;
5276 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5278 librbd::Image image1
;
5279 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5282 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5285 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5286 ASSERT_TRUE(lock_owner
);
5288 librbd::Image image2
;
5289 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5291 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5292 ASSERT_FALSE(lock_owner
);
5294 ASSERT_EQ(0, image2
.resize(0));
5296 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5297 ASSERT_TRUE(lock_owner
);
5298 ASSERT_PASSED(validate_object_map
, image1
);
5301 TEST_F(TestLibRBD
, SparsifyViaLockOwner
)
5303 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5305 librados::IoCtx ioctx
;
5306 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5309 std::string name
= get_temp_image_name();
5310 uint64_t size
= 2 << 20;
5312 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5314 librbd::Image image1
;
5315 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5318 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5321 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5322 ASSERT_TRUE(lock_owner
);
5324 librbd::Image image2
;
5325 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5327 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5328 ASSERT_FALSE(lock_owner
);
5330 ASSERT_EQ(0, image2
.sparsify(4096));
5332 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5333 ASSERT_TRUE(lock_owner
);
5334 ASSERT_PASSED(validate_object_map
, image1
);
5337 TEST_F(TestLibRBD
, ObjectMapConsistentSnap
)
5339 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5341 librados::IoCtx ioctx
;
5342 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5345 std::string name
= get_temp_image_name();
5346 uint64_t size
= 1 << 20;
5348 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5350 librbd::Image image1
;
5351 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5354 for (int i
= 0; i
< num_snaps
; ++i
) {
5355 std::string snap_name
= "snap" + stringify(i
);
5356 ASSERT_EQ(0, image1
.snap_create(snap_name
.c_str()));
5360 thread
writer([&image1
](){
5361 librbd::image_info_t info
;
5362 int r
= image1
.stat(info
, sizeof(info
));
5363 ceph_assert(r
== 0);
5366 for (unsigned i
= 0; i
< info
.num_objs
; ++i
) {
5367 r
= image1
.write((1 << info
.order
) * i
, bl
.length(), bl
);
5368 ceph_assert(r
== (int) bl
.length());
5373 for (int i
= 0; i
< num_snaps
; ++i
) {
5374 std::string snap_name
= "snap" + stringify(i
);
5375 ASSERT_EQ(0, image1
.snap_set(snap_name
.c_str()));
5376 ASSERT_PASSED(validate_object_map
, image1
);
5379 ASSERT_EQ(0, image1
.snap_set(NULL
));
5380 ASSERT_PASSED(validate_object_map
, image1
);
5383 void memset_rand(char *buf
, size_t len
) {
5384 for (size_t i
= 0; i
< len
; ++i
) {
5385 buf
[i
] = (char) (rand() % (126 - 33) + 33);
5389 TEST_F(TestLibRBD
, Metadata
)
5391 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5393 rados_ioctx_t ioctx
;
5394 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5396 std::string name
= get_temp_image_name();
5397 uint64_t size
= 2 << 20;
5399 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5402 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5405 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
5409 size_t keys_len
= sizeof(keys
);
5410 size_t vals_len
= sizeof(vals
);
5412 memset_rand(keys
, keys_len
);
5413 memset_rand(vals
, vals_len
);
5415 ASSERT_EQ(0, rbd_metadata_list(image
, "", 0, keys
, &keys_len
, vals
,
5417 ASSERT_EQ(0U, keys_len
);
5418 ASSERT_EQ(0U, vals_len
);
5421 size_t value_len
= sizeof(value
);
5422 memset_rand(value
, value_len
);
5424 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
5425 ASSERT_EQ(0, rbd_metadata_set(image1
, "key2", "value2"));
5426 ASSERT_EQ(0, rbd_metadata_get(image1
, "key1", value
, &value_len
));
5427 ASSERT_STREQ(value
, "value1");
5429 ASSERT_EQ(-ERANGE
, rbd_metadata_get(image1
, "key1", value
, &value_len
));
5430 ASSERT_EQ(value_len
, strlen("value1") + 1);
5432 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5434 keys_len
= sizeof(keys
);
5435 vals_len
= sizeof(vals
);
5436 memset_rand(keys
, keys_len
);
5437 memset_rand(vals
, vals_len
);
5438 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5440 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
5441 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
5442 ASSERT_STREQ(keys
, "key1");
5443 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
5444 ASSERT_STREQ(vals
, "value1");
5445 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
5447 ASSERT_EQ(0, rbd_metadata_remove(image1
, "key1"));
5448 ASSERT_EQ(-ENOENT
, rbd_metadata_remove(image1
, "key3"));
5449 value_len
= sizeof(value
);
5450 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key3", value
, &value_len
));
5451 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5453 ASSERT_EQ(keys_len
, strlen("key2") + 1);
5454 ASSERT_EQ(vals_len
, strlen("value2") + 1);
5455 ASSERT_STREQ(keys
, "key2");
5456 ASSERT_STREQ(vals
, "value2");
5458 // test config setting
5459 ASSERT_EQ(0, rbd_metadata_set(image1
, "conf_rbd_cache", "false"));
5460 ASSERT_EQ(-EINVAL
, rbd_metadata_set(image1
, "conf_rbd_cache", "INVALID_VAL"));
5461 ASSERT_EQ(0, rbd_metadata_remove(image1
, "conf_rbd_cache"));
5463 // test metadata with snapshot adding
5464 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
5465 ASSERT_EQ(0, rbd_snap_protect(image1
, "snap1"));
5466 ASSERT_EQ(0, rbd_snap_set(image1
, "snap1"));
5468 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
5469 ASSERT_EQ(0, rbd_metadata_set(image1
, "key3", "value3"));
5471 keys_len
= sizeof(keys
);
5472 vals_len
= sizeof(vals
);
5473 memset_rand(keys
, keys_len
);
5474 memset_rand(vals
, vals_len
);
5475 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5478 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5480 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5481 ASSERT_STREQ(keys
, "key1");
5482 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
5483 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
5484 ASSERT_STREQ(vals
, "value1");
5485 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
5486 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
5488 ASSERT_EQ(0, rbd_snap_set(image1
, NULL
));
5489 keys_len
= sizeof(keys
);
5490 vals_len
= sizeof(vals
);
5491 memset_rand(keys
, keys_len
);
5492 memset_rand(vals
, vals_len
);
5493 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5496 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5498 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5499 ASSERT_STREQ(keys
, "key1");
5500 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
5501 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
5502 ASSERT_STREQ(vals
, "value1");
5503 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
5504 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
5506 // test metadata with cloning
5508 ASSERT_EQ(0, rbd_get_features(image1
, &features
));
5510 string cname
= get_temp_image_name();
5511 EXPECT_EQ(0, rbd_clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5512 cname
.c_str(), features
, &order
));
5514 ASSERT_EQ(0, rbd_open(ioctx
, cname
.c_str(), &image2
, NULL
));
5515 ASSERT_EQ(0, rbd_metadata_set(image2
, "key4", "value4"));
5517 keys_len
= sizeof(keys
);
5518 vals_len
= sizeof(vals
);
5519 memset_rand(keys
, keys_len
);
5520 memset_rand(vals
, vals_len
);
5521 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 0, keys
, &keys_len
, vals
,
5523 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5524 1 + strlen("key4") + 1);
5525 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
5526 strlen("value3") + 1 + strlen("value4") + 1);
5527 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5529 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1 +
5530 strlen("value3") + 1, "value4");
5532 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5535 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5537 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5538 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key4", value
, &value_len
));
5540 // test short buffer cases
5541 keys_len
= strlen("key1") + 1;
5542 vals_len
= strlen("value1") + 1;
5543 memset_rand(keys
, keys_len
);
5544 memset_rand(vals
, vals_len
);
5545 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 1, keys
, &keys_len
, vals
,
5547 ASSERT_EQ(keys_len
, strlen("key1") + 1);
5548 ASSERT_EQ(vals_len
, strlen("value1") + 1);
5549 ASSERT_STREQ(keys
, "key1");
5550 ASSERT_STREQ(vals
, "value1");
5552 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "", 2, keys
, &keys_len
, vals
,
5554 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
5555 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
5557 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "", 0, keys
, &keys_len
, vals
,
5559 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5560 1 + strlen("key4") + 1);
5561 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
5562 strlen("value3") + 1 + strlen("value4") + 1);
5564 // test `start` param
5565 keys_len
= sizeof(keys
);
5566 vals_len
= sizeof(vals
);
5567 memset_rand(keys
, keys_len
);
5568 memset_rand(vals
, vals_len
);
5569 ASSERT_EQ(0, rbd_metadata_list(image2
, "key2", 0, keys
, &keys_len
, vals
,
5571 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
5572 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
5573 ASSERT_STREQ(keys
, "key3");
5574 ASSERT_STREQ(vals
, "value3");
5576 ASSERT_EQ(0, rbd_close(image
));
5577 ASSERT_EQ(0, rbd_close(image1
));
5578 ASSERT_EQ(0, rbd_close(image2
));
5579 rados_ioctx_destroy(ioctx
);
5582 TEST_F(TestLibRBD
, MetadataPP
)
5584 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5586 librados::IoCtx ioctx
;
5587 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5590 string name
= get_temp_image_name();
5591 uint64_t size
= 2 << 20;
5595 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5597 librbd::Image image1
;
5598 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5599 map
<string
, bufferlist
> pairs
;
5600 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5601 ASSERT_TRUE(pairs
.empty());
5603 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
5604 ASSERT_EQ(0, image1
.metadata_set("key2", "value2"));
5605 ASSERT_EQ(0, image1
.metadata_get("key1", &value
));
5606 ASSERT_EQ(0, strcmp("value1", value
.c_str()));
5607 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5608 ASSERT_EQ(2U, pairs
.size());
5609 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
5610 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5613 ASSERT_EQ(0, image1
.metadata_remove("key1"));
5614 ASSERT_EQ(-ENOENT
, image1
.metadata_remove("key3"));
5615 ASSERT_TRUE(image1
.metadata_get("key3", &value
) < 0);
5616 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5617 ASSERT_EQ(1U, pairs
.size());
5618 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5620 // test config setting
5621 ASSERT_EQ(0, image1
.metadata_set("conf_rbd_cache", "false"));
5622 ASSERT_EQ(-EINVAL
, image1
.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
5623 ASSERT_EQ(0, image1
.metadata_remove("conf_rbd_cache"));
5625 // test metadata with snapshot adding
5626 ASSERT_EQ(0, image1
.snap_create("snap1"));
5627 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5628 ASSERT_EQ(0, image1
.snap_set("snap1"));
5631 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
5632 ASSERT_EQ(0, image1
.metadata_set("key3", "value3"));
5633 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5634 ASSERT_EQ(3U, pairs
.size());
5635 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
5636 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5637 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
5639 ASSERT_EQ(0, image1
.snap_set(NULL
));
5640 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5641 ASSERT_EQ(3U, pairs
.size());
5642 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
5643 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5644 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
5646 // test metadata with cloning
5647 string cname
= get_temp_image_name();
5648 librbd::Image image2
;
5649 ASSERT_EQ(0, image1
.features(&features
));
5650 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5651 cname
.c_str(), features
, &order
));
5652 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, cname
.c_str(), NULL
));
5653 ASSERT_EQ(0, image2
.metadata_set("key4", "value4"));
5655 ASSERT_EQ(0, image2
.metadata_list("", 0, &pairs
));
5656 ASSERT_EQ(4U, pairs
.size());
5658 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5659 ASSERT_EQ(3U, pairs
.size());
5660 ASSERT_EQ(-ENOENT
, image1
.metadata_get("key4", &value
));
5663 TEST_F(TestLibRBD
, UpdateFeatures
)
5665 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5667 librados::IoCtx ioctx
;
5668 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5671 std::string name
= get_temp_image_name();
5672 uint64_t size
= 1 << 20;
5674 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5676 librbd::Image image
;
5677 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5680 ASSERT_EQ(0, image
.old_format(&old_format
));
5682 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
5687 ASSERT_EQ(0, image
.features(&features
));
5689 // must provide a single feature
5690 ASSERT_EQ(-EINVAL
, image
.update_features(0, true));
5692 uint64_t disable_features
;
5693 disable_features
= features
& (RBD_FEATURE_EXCLUSIVE_LOCK
|
5694 RBD_FEATURE_OBJECT_MAP
|
5695 RBD_FEATURE_FAST_DIFF
|
5696 RBD_FEATURE_JOURNALING
);
5697 if (disable_features
!= 0) {
5698 ASSERT_EQ(0, image
.update_features(disable_features
, false));
5701 ASSERT_EQ(0, image
.features(&features
));
5702 ASSERT_EQ(0U, features
& disable_features
);
5704 // cannot enable object map nor journaling w/o exclusive lock
5705 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5706 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_JOURNALING
, true));
5707 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
5709 ASSERT_EQ(0, image
.features(&features
));
5710 ASSERT_NE(0U, features
& RBD_FEATURE_EXCLUSIVE_LOCK
);
5712 // can enable fast diff w/o object map
5713 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_FAST_DIFF
, true));
5714 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5715 ASSERT_EQ(0, image
.features(&features
));
5716 ASSERT_NE(0U, features
& RBD_FEATURE_OBJECT_MAP
);
5718 uint64_t expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
|
5719 RBD_FLAG_FAST_DIFF_INVALID
;
5721 ASSERT_EQ(0, image
.get_flags(&flags
));
5722 ASSERT_EQ(expected_flags
, flags
);
5724 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5725 ASSERT_EQ(0, image
.features(&features
));
5726 ASSERT_EQ(0U, features
& RBD_FEATURE_OBJECT_MAP
);
5728 // can disable object map w/ fast diff
5729 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5730 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5731 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_FAST_DIFF
, false));
5732 ASSERT_EQ(0, image
.features(&features
));
5733 ASSERT_EQ(0U, features
& RBD_FEATURE_FAST_DIFF
);
5735 ASSERT_EQ(0, image
.get_flags(&flags
));
5736 ASSERT_EQ(0U, flags
);
5738 // cannot disable exclusive lock w/ object map
5739 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5740 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
5741 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5743 // cannot disable exclusive lock w/ journaling
5744 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, true));
5745 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
5746 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, false));
5748 ASSERT_EQ(0, image
.get_flags(&flags
));
5749 ASSERT_EQ(0U, flags
);
5751 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
5753 ASSERT_EQ(0, image
.features(&features
));
5754 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0) {
5755 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, false));
5757 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, true));
5760 TEST_F(TestLibRBD
, FeaturesBitmaskString
)
5763 uint64_t features
= RBD_FEATURES_DEFAULT
;
5765 std::string features_str
;
5766 std::string expected_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
5767 rbd
.features_to_string(features
, &features_str
);
5768 ASSERT_EQ(expected_str
, features_str
);
5770 features
= RBD_FEATURE_LAYERING
;
5772 expected_str
= "layering";
5773 rbd
.features_to_string(features
, &features_str
);
5774 ASSERT_EQ(expected_str
, features_str
);
5776 uint64_t features_bitmask
;
5777 features_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
5778 rbd
.features_from_string(features_str
, &features_bitmask
);
5779 ASSERT_EQ(features_bitmask
, RBD_FEATURES_DEFAULT
);
5781 features_str
= "layering";
5782 features_bitmask
= 0;
5783 rbd
.features_from_string(features_str
, &features_bitmask
);
5784 ASSERT_EQ(features_bitmask
, RBD_FEATURE_LAYERING
);
5787 TEST_F(TestLibRBD
, RebuildObjectMap
)
5789 librados::IoCtx ioctx
;
5790 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5793 std::string name
= get_temp_image_name();
5794 uint64_t size
= 1 << 20;
5796 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5798 PrintProgress prog_ctx
;
5799 std::string object_map_oid
;
5803 librbd::Image image
;
5804 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5807 ASSERT_EQ(0, image
.features(&features
));
5808 if ((features
& RBD_FEATURE_OBJECT_MAP
) == 0) {
5809 ASSERT_EQ(-EINVAL
, image
.rebuild_object_map(prog_ctx
));
5813 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
5815 ASSERT_EQ(0, image
.snap_create("snap1"));
5816 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(1<<order
, bl
.length(), bl
));
5818 std::string image_id
;
5819 ASSERT_EQ(0, get_image_id(image
, &image_id
));
5820 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
5823 // corrupt the object map
5824 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
5826 librbd::Image image1
;
5827 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5831 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5832 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5833 ASSERT_TRUE(lock_owner
);
5836 ASSERT_EQ(0, image1
.get_flags(&flags
));
5837 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
5839 ASSERT_EQ(0, image1
.rebuild_object_map(prog_ctx
));
5841 librbd::Image image2
;
5842 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5845 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(0, bl
.length(), read_bl
));
5846 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5849 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(1<<order
, bl
.length(), read_bl
));
5850 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5852 ASSERT_PASSED(validate_object_map
, image1
);
5853 ASSERT_PASSED(validate_object_map
, image2
);
5856 TEST_F(TestLibRBD
, RebuildNewObjectMap
)
5858 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5860 rados_ioctx_t ioctx
;
5861 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5863 std::string name
= get_temp_image_name();
5864 uint64_t size
= 1 << 20;
5866 uint64_t features
= RBD_FEATURE_EXCLUSIVE_LOCK
;
5867 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
5871 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5872 ASSERT_EQ(0, rbd_update_features(image
, RBD_FEATURE_OBJECT_MAP
, true));
5873 ASSERT_EQ(0, rbd_rebuild_object_map(image
, print_progress_percent
, NULL
));
5875 ASSERT_PASSED(validate_object_map
, image
);
5877 ASSERT_EQ(0, rbd_close(image
));
5878 rados_ioctx_destroy(ioctx
);
5881 TEST_F(TestLibRBD
, CheckObjectMap
)
5883 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5885 librados::IoCtx ioctx
;
5886 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5889 std::string name
= get_temp_image_name();
5890 uint64_t size
= 1 << 20;
5892 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5894 PrintProgress prog_ctx
;
5899 librbd::Image image
;
5900 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5903 ASSERT_EQ(0, image
.features(&features
));
5905 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(0, bl1
.length(), bl1
));
5907 ASSERT_EQ(0, image
.snap_create("snap1"));
5908 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(1<<order
, bl1
.length(), bl1
));
5911 librbd::Image image1
;
5912 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5914 std::string image_id
;
5915 ASSERT_EQ(0, get_image_id(image1
, &image_id
));
5917 std::string object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
5919 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl2
, 1024, 0));
5922 ASSERT_EQ((ssize_t
)bl1
.length(), image1
.write(3 * (1 << 18), bl1
.length(), bl1
));
5923 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5924 ASSERT_TRUE(lock_owner
);
5926 //reopen image to reread now corrupt object map from disk
5930 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl1
, 1024, 0));
5931 ASSERT_FALSE(bl1
.contents_equal(bl2
));
5933 ASSERT_EQ(0, ioctx
.write_full(object_map_oid
, bl2
));
5934 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5937 ASSERT_EQ(0, image1
.get_flags(&flags
));
5938 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
5940 ASSERT_EQ(0, image1
.check_object_map(prog_ctx
));
5942 ASSERT_EQ(0, image1
.get_flags(&flags
));
5943 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
5946 TEST_F(TestLibRBD
, BlockingAIO
)
5948 librados::IoCtx ioctx
;
5949 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5951 bool skip_discard
= is_skip_partial_discard_enabled();
5954 std::string name
= get_temp_image_name();
5955 uint64_t size
= 1 << 20;
5957 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5959 std::string non_blocking_aio
;
5960 ASSERT_EQ(0, _rados
.conf_get("rbd_non_blocking_aio", non_blocking_aio
));
5961 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio", "0"));
5962 BOOST_SCOPE_EXIT( (non_blocking_aio
) ) {
5963 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio",
5964 non_blocking_aio
.c_str()));
5965 } BOOST_SCOPE_EXIT_END
;
5967 librbd::Image image
;
5968 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5971 ASSERT_EQ(0, image
.write(0, bl
.length(), bl
));
5973 bl
.append(std::string(256, '1'));
5974 librbd::RBD::AioCompletion
*write_comp
=
5975 new librbd::RBD::AioCompletion(NULL
, NULL
);
5976 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
5978 librbd::RBD::AioCompletion
*flush_comp
=
5979 new librbd::RBD::AioCompletion(NULL
, NULL
);
5980 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
5981 ASSERT_EQ(0, flush_comp
->wait_for_complete());
5982 ASSERT_EQ(0, flush_comp
->get_return_value());
5983 flush_comp
->release();
5985 ASSERT_EQ(1, write_comp
->is_complete());
5986 ASSERT_EQ(0, write_comp
->get_return_value());
5987 write_comp
->release();
5989 librbd::RBD::AioCompletion
*discard_comp
=
5990 new librbd::RBD::AioCompletion(NULL
, NULL
);
5991 ASSERT_EQ(0, image
.aio_discard(128, 128, discard_comp
));
5992 ASSERT_EQ(0, discard_comp
->wait_for_complete());
5993 discard_comp
->release();
5995 librbd::RBD::AioCompletion
*read_comp
=
5996 new librbd::RBD::AioCompletion(NULL
, NULL
);
5998 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
5999 ASSERT_EQ(0, read_comp
->wait_for_complete());
6000 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
6001 read_comp
->release();
6003 bufferlist expected_bl
;
6004 expected_bl
.append(std::string(128, '1'));
6005 expected_bl
.append(std::string(128, skip_discard
? '1' : '\0'));
6006 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
6009 TEST_F(TestLibRBD
, ExclusiveLockTransition
)
6011 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
6013 librados::IoCtx ioctx
;
6014 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6017 std::string name
= get_temp_image_name();
6019 uint64_t size
= 1 << 18;
6021 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6023 librbd::Image image1
;
6024 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6026 librbd::Image image2
;
6027 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6029 std::list
<librbd::RBD::AioCompletion
*> comps
;
6030 ceph::bufferlist bl
;
6031 bl
.append(std::string(1 << order
, '1'));
6032 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6033 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
6035 comps
.push_back(comp
);
6036 if (object_no
% 2 == 0) {
6037 ASSERT_EQ(0, image1
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
6039 ASSERT_EQ(0, image2
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
6043 while (!comps
.empty()) {
6044 librbd::RBD::AioCompletion
*comp
= comps
.front();
6046 ASSERT_EQ(0, comp
->wait_for_complete());
6047 ASSERT_EQ(1, comp
->is_complete());
6051 librbd::Image image3
;
6052 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
6053 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6055 ASSERT_EQ((ssize_t
)bl
.length(), image3
.read(object_no
<< order
, bl
.length(),
6057 ASSERT_TRUE(bl
.contents_equal(read_bl
));
6060 ASSERT_PASSED(validate_object_map
, image1
);
6061 ASSERT_PASSED(validate_object_map
, image2
);
6062 ASSERT_PASSED(validate_object_map
, image3
);
6065 TEST_F(TestLibRBD
, ExclusiveLockReadTransition
)
6067 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
6069 librados::IoCtx ioctx
;
6070 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6073 std::string name
= get_temp_image_name();
6075 uint64_t size
= 1 << 18;
6077 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6079 librbd::Image image1
;
6080 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6083 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6084 ASSERT_FALSE(lock_owner
);
6086 // journaling should force read ops to acquire the lock
6088 ASSERT_EQ(0, image1
.read(0, 0, read_bl
));
6090 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6091 ASSERT_TRUE(lock_owner
);
6093 librbd::Image image2
;
6094 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6096 std::list
<librbd::RBD::AioCompletion
*> comps
;
6097 std::list
<bufferlist
> read_bls
;
6098 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6099 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
6101 comps
.push_back(comp
);
6102 read_bls
.emplace_back();
6103 if (object_no
% 2 == 0) {
6104 ASSERT_EQ(0, image1
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6106 ASSERT_EQ(0, image2
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6110 while (!comps
.empty()) {
6111 librbd::RBD::AioCompletion
*comp
= comps
.front();
6113 ASSERT_EQ(0, comp
->wait_for_complete());
6114 ASSERT_EQ(1, comp
->is_complete());
6119 TEST_F(TestLibRBD
, CacheMayCopyOnWrite
) {
6120 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6122 librados::IoCtx ioctx
;
6123 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6126 std::string name
= get_temp_image_name();
6128 uint64_t size
= 1 << 18;
6130 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6132 librbd::Image image
;
6133 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6134 ASSERT_EQ(0, image
.snap_create("one"));
6135 ASSERT_EQ(0, image
.snap_protect("one"));
6137 std::string clone_name
= this->get_temp_image_name();
6138 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
6139 RBD_FEATURE_LAYERING
, &order
));
6141 librbd::Image clone
;
6142 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
6143 ASSERT_EQ(0, clone
.flush());
6145 bufferlist expect_bl
;
6146 expect_bl
.append(std::string(1024, '\0'));
6148 // test double read path
6150 uint64_t offset
= 0;
6151 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6152 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6154 bufferlist write_bl
;
6155 write_bl
.append(std::string(1024, '1'));
6156 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6159 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6160 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6162 // test read retry path
6163 offset
= 1 << order
;
6164 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6167 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6168 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6171 TEST_F(TestLibRBD
, FlushEmptyOpsOnExternalSnapshot
) {
6172 std::string cache_enabled
;
6173 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", cache_enabled
));
6174 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", "false"));
6175 BOOST_SCOPE_EXIT( (cache_enabled
) ) {
6176 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", cache_enabled
.c_str()));
6177 } BOOST_SCOPE_EXIT_END
;
6179 librados::IoCtx ioctx
;
6180 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6183 std::string name
= get_temp_image_name();
6184 uint64_t size
= 1 << 18;
6186 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6188 librbd::Image image1
;
6189 librbd::Image image2
;
6190 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6191 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6192 ASSERT_EQ(0, image1
.snap_create("snap1"));
6194 librbd::RBD::AioCompletion
*read_comp
=
6195 new librbd::RBD::AioCompletion(NULL
, NULL
);
6197 image2
.aio_read(0, 1024, read_bl
, read_comp
);
6198 ASSERT_EQ(0, read_comp
->wait_for_complete());
6199 read_comp
->release();
6202 TEST_F(TestLibRBD
, TestImageOptions
)
6204 rados_ioctx_t ioctx
;
6205 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6207 //make create image options
6208 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6210 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6211 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6212 rbd_image_options_t opts
;
6213 rbd_image_options_create(&opts
);
6216 ASSERT_EQ(-EINVAL
, rbd_image_options_is_set(opts
, 12345, &is_set
));
6217 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6219 ASSERT_FALSE(is_set
);
6221 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FORMAT
,
6223 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FEATURES
,
6225 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6227 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_UNIT
,
6229 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_COUNT
,
6232 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6234 ASSERT_TRUE(is_set
);
6236 std::string parent_name
= get_temp_image_name();
6239 ASSERT_EQ(0, rbd_create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6241 // check order is returned in opts
6242 ASSERT_EQ(0, rbd_image_options_get_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6244 ASSERT_NE((uint64_t)0, order
);
6246 // write some data to parent
6248 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
6249 char *data
= (char *)"testdata";
6250 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
6251 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
6253 // create a snapshot, reopen as the parent we're interested in
6254 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6255 ASSERT_EQ(0, rbd_close(parent
));
6256 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
6259 std::string child_name
= get_temp_image_name();
6260 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
6261 ASSERT_EQ(0, rbd_clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6262 child_name
.c_str(), opts
));
6265 std::string copy1_name
= get_temp_image_name();
6266 ASSERT_EQ(0, rbd_copy3(parent
, ioctx
, copy1_name
.c_str(), opts
));
6267 std::string copy2_name
= get_temp_image_name();
6268 ASSERT_EQ(0, rbd_copy_with_progress3(parent
, ioctx
, copy2_name
.c_str(), opts
,
6269 print_progress_percent
, NULL
));
6271 ASSERT_EQ(0, rbd_close(parent
));
6273 rbd_image_options_destroy(opts
);
6275 rados_ioctx_destroy(ioctx
);
6278 TEST_F(TestLibRBD
, TestImageOptionsPP
)
6280 librados::IoCtx ioctx
;
6281 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6283 //make create image options
6284 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6286 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6287 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6288 librbd::ImageOptions opts
;
6289 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FORMAT
, static_cast<uint64_t>(2)));
6290 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FEATURES
, features
));
6291 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_ORDER
, order
));
6292 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
));
6293 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
));
6296 std::string parent_name
= get_temp_image_name();
6299 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6301 // check order is returned in opts
6302 ASSERT_EQ(0, opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
));
6303 ASSERT_NE((uint64_t)0, order
);
6305 // write some data to parent
6306 librbd::Image parent
;
6307 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
6311 bl
.append(buffer::create(len
));
6313 ASSERT_EQ(len
, parent
.write(0, len
, bl
));
6314 ASSERT_EQ(len
, parent
.write(len
, len
, bl
));
6316 // create a snapshot, reopen as the parent we're interested in
6317 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
6318 ASSERT_EQ(0, parent
.close());
6319 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
6322 std::string child_name
= get_temp_image_name();
6323 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
6324 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6325 child_name
.c_str(), opts
));
6328 std::string copy1_name
= get_temp_image_name();
6329 ASSERT_EQ(0, parent
.copy3(ioctx
, copy1_name
.c_str(), opts
));
6330 std::string copy2_name
= get_temp_image_name();
6332 ASSERT_EQ(0, parent
.copy_with_progress3(ioctx
, copy2_name
.c_str(), opts
, pp
));
6334 ASSERT_EQ(0, parent
.close());
6337 TEST_F(TestLibRBD
, EventSocketPipe
)
6339 EventSocket event_sock
;
6340 int pipe_fd
[2]; // read and write fd
6343 ASSERT_EQ(0, pipe(pipe_fd
));
6345 ASSERT_FALSE(event_sock
.is_valid());
6347 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_NONE
));
6348 ASSERT_FALSE(event_sock
.is_valid());
6350 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], 44));
6351 ASSERT_FALSE(event_sock
.is_valid());
6353 #ifndef HAVE_EVENTFD
6354 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_EVENTFD
));
6355 ASSERT_FALSE(event_sock
.is_valid());
6358 ASSERT_EQ(0, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_PIPE
));
6359 ASSERT_TRUE(event_sock
.is_valid());
6360 ASSERT_EQ(0, event_sock
.notify());
6361 ASSERT_EQ(1, read(pipe_fd
[0], buf
, 32));
6362 ASSERT_EQ('i', buf
[0]);
6368 TEST_F(TestLibRBD
, EventSocketEventfd
)
6371 EventSocket event_sock
;
6373 struct pollfd poll_fd
;
6376 event_fd
= eventfd(0, EFD_NONBLOCK
);
6377 ASSERT_NE(-1, event_fd
);
6379 ASSERT_FALSE(event_sock
.is_valid());
6381 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_NONE
));
6382 ASSERT_FALSE(event_sock
.is_valid());
6384 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, 44));
6385 ASSERT_FALSE(event_sock
.is_valid());
6387 ASSERT_EQ(0, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_EVENTFD
));
6388 ASSERT_TRUE(event_sock
.is_valid());
6389 ASSERT_EQ(0, event_sock
.notify());
6391 poll_fd
.fd
= event_fd
;
6392 poll_fd
.events
= POLLIN
;
6393 ASSERT_EQ(1, poll(&poll_fd
, 1, -1));
6394 ASSERT_TRUE(poll_fd
.revents
& POLLIN
);
6396 ASSERT_EQ(static_cast<ssize_t
>(sizeof(uint64_t)), read(event_fd
, buf
, 32));
6397 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf
));
6403 TEST_F(TestLibRBD
, ImagePollIO
)
6406 rados_ioctx_t ioctx
;
6407 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6411 std::string name
= get_temp_image_name();
6412 uint64_t size
= 2 << 20;
6413 int fd
= eventfd(0, EFD_NONBLOCK
);
6415 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6416 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6418 ASSERT_EQ(0, rbd_set_image_notification(image
, fd
, EVENT_SOCKET_TYPE_EVENTFD
));
6420 char test_data
[TEST_IO_SIZE
+ 1];
6421 char zero_data
[TEST_IO_SIZE
+ 1];
6424 for (i
= 0; i
< TEST_IO_SIZE
; ++i
)
6425 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
6426 test_data
[TEST_IO_SIZE
] = '\0';
6427 memset(zero_data
, 0, sizeof(zero_data
));
6429 for (i
= 0; i
< 5; ++i
)
6430 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6432 for (i
= 5; i
< 10; ++i
)
6433 ASSERT_PASSED(aio_write_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6435 for (i
= 5; i
< 10; ++i
)
6436 ASSERT_PASSED(aio_read_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6438 ASSERT_EQ(0, rbd_close(image
));
6439 rados_ioctx_destroy(ioctx
);
6445 static bool operator==(const image_spec_t
&lhs
, const image_spec_t
&rhs
) {
6446 return (lhs
.id
== rhs
.id
&& lhs
.name
== rhs
.name
);
6449 static bool operator==(const linked_image_spec_t
&lhs
,
6450 const linked_image_spec_t
&rhs
) {
6451 return (lhs
.pool_id
== rhs
.pool_id
&&
6452 lhs
.pool_name
== rhs
.pool_name
&&
6453 lhs
.pool_namespace
== rhs
.pool_namespace
&&
6454 lhs
.image_id
== rhs
.image_id
&&
6455 lhs
.image_name
== rhs
.image_name
&&
6456 lhs
.trash
== rhs
.trash
);
6459 static bool operator==(const mirror_peer_t
&lhs
, const mirror_peer_t
&rhs
) {
6460 return (lhs
.uuid
== rhs
.uuid
&&
6461 lhs
.cluster_name
== rhs
.cluster_name
&&
6462 lhs
.client_name
== rhs
.client_name
);
6465 static std::ostream
& operator<<(std::ostream
&os
, const mirror_peer_t
&peer
) {
6466 os
<< "uuid=" << peer
.uuid
<< ", "
6467 << "cluster=" << peer
.cluster_name
<< ", "
6468 << "client=" << peer
.client_name
;
6472 } // namespace librbd
6474 TEST_F(TestLibRBD
, Mirror
) {
6475 librados::IoCtx ioctx
;
6476 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6480 std::vector
<librbd::mirror_peer_t
> expected_peers
;
6481 std::vector
<librbd::mirror_peer_t
> peers
;
6482 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
6483 ASSERT_EQ(expected_peers
, peers
);
6486 ASSERT_EQ(-EINVAL
, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
6488 rbd_mirror_mode_t mirror_mode
;
6489 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6490 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED
, mirror_mode
);
6492 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
6493 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6495 // Add some images to the pool
6497 std::string parent_name
= get_temp_image_name();
6498 std::string child_name
= get_temp_image_name();
6499 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), 2 << 20,
6503 ASSERT_EQ(0, get_features(&old_format
, &features
));
6504 if ((features
& RBD_FEATURE_LAYERING
) != 0) {
6505 librbd::Image parent
;
6506 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
6507 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
6508 ASSERT_EQ(0, parent
.close());
6509 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
6510 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
6511 ASSERT_EQ(0, parent
.close());
6512 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6513 child_name
.c_str(), features
, &order
));
6516 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE
, mirror_mode
);
6518 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_POOL
));
6519 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6520 ASSERT_EQ(RBD_MIRROR_MODE_POOL
, mirror_mode
);
6524 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
6525 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid2
, "cluster2", "admin"));
6526 ASSERT_EQ(-EEXIST
, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster1", "foo"));
6527 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster3", "admin"));
6529 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
6530 auto sort_peers
= [](const librbd::mirror_peer_t
&lhs
,
6531 const librbd::mirror_peer_t
&rhs
) {
6532 return lhs
.uuid
< rhs
.uuid
;
6535 {uuid1
, "cluster1", "client"},
6536 {uuid2
, "cluster2", "admin"},
6537 {uuid3
, "cluster3", "admin"}};
6538 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
6539 ASSERT_EQ(expected_peers
, peers
);
6541 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, "uuid4"));
6542 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid2
));
6544 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_client(ioctx
, "uuid4", "new client"));
6545 ASSERT_EQ(0, rbd
.mirror_peer_set_client(ioctx
, uuid1
, "new client"));
6547 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_cluster(ioctx
, "uuid4",
6549 ASSERT_EQ(0, rbd
.mirror_peer_set_cluster(ioctx
, uuid3
, "new cluster"));
6551 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
6553 {uuid1
, "cluster1", "new client"},
6554 {uuid3
, "new cluster", "admin"}};
6555 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
6556 ASSERT_EQ(expected_peers
, peers
);
6558 ASSERT_EQ(-EBUSY
, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
6559 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid1
));
6560 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid3
));
6561 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
6564 TEST_F(TestLibRBD
, MirrorPeerAttributes
) {
6565 REQUIRE(!is_librados_test_stub(_rados
));
6567 librados::IoCtx ioctx
;
6568 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6571 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
6574 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid
, "remote_cluster", "client"));
6576 std::map
<std::string
, std::string
> attributes
;
6577 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_get_attributes(ioctx
, uuid
, &attributes
));
6578 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_attributes(ioctx
, "missing uuid",
6581 std::map
<std::string
, std::string
> expected_attributes
{
6582 {"mon_host", "1.2.3.4"},
6584 ASSERT_EQ(0, rbd
.mirror_peer_set_attributes(ioctx
, uuid
,
6585 expected_attributes
));
6587 ASSERT_EQ(0, rbd
.mirror_peer_get_attributes(ioctx
, uuid
,
6589 ASSERT_EQ(expected_attributes
, attributes
);
6591 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid
));
6592 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
6595 TEST_F(TestLibRBD
, CreateWithMirrorEnabled
) {
6596 REQUIRE_FORMAT_V2();
6598 librados::IoCtx ioctx
;
6599 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6602 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
6604 librbd::ImageOptions image_options
;
6605 ASSERT_EQ(0, image_options
.set(
6606 RBD_IMAGE_OPTION_MIRROR_IMAGE_MODE
,
6607 static_cast<uint64_t>(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
)));
6609 std::string parent_name
= get_temp_image_name();
6610 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 2<<20, image_options
));
6612 librbd::Image parent_image
;
6613 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
6615 librbd::mirror_image_mode_t mirror_image_mode
;
6616 ASSERT_EQ(0, parent_image
.mirror_image_get_mode(&mirror_image_mode
));
6617 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
6619 ASSERT_EQ(0, parent_image
.snap_create("parent_snap"));
6620 ASSERT_EQ(0, parent_image
.snap_protect("parent_snap"));
6622 std::string child_name
= get_temp_image_name();
6623 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6624 child_name
.c_str(), image_options
));
6626 librbd::Image child_image
;
6627 ASSERT_EQ(0, rbd
.open(ioctx
, child_image
, child_name
.c_str(), NULL
));
6629 ASSERT_EQ(0, child_image
.mirror_image_get_mode(&mirror_image_mode
));
6630 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
6632 ASSERT_EQ(0, child_image
.mirror_image_disable(true));
6633 ASSERT_EQ(0, parent_image
.mirror_image_disable(true));
6634 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
6637 TEST_F(TestLibRBD
, FlushCacheWithCopyupOnExternalSnapshot
) {
6638 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6640 librados::IoCtx ioctx
;
6641 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6644 librbd::Image image
;
6645 std::string name
= get_temp_image_name();
6647 uint64_t size
= 1 << 18;
6650 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6651 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6654 bl
.append(std::string(size
, '1'));
6655 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
6656 ASSERT_EQ(0, image
.snap_create("one"));
6657 ASSERT_EQ(0, image
.snap_protect("one"));
6659 std::string clone_name
= this->get_temp_image_name();
6660 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
6661 RBD_FEATURE_LAYERING
, &order
));
6662 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
6664 librbd::Image image2
;
6665 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, clone_name
.c_str(), NULL
));
6667 // prepare CoW writeback that will be flushed on next op
6669 bl
.append(std::string(1, '1'));
6670 ASSERT_EQ(0, image
.flush());
6671 ASSERT_EQ(1, image
.write(0, 1, bl
));
6672 ASSERT_EQ(0, image2
.snap_create("snap1"));
6674 librbd::RBD::AioCompletion
*read_comp
=
6675 new librbd::RBD::AioCompletion(NULL
, NULL
);
6677 image
.aio_read(0, 1024, read_bl
, read_comp
);
6678 ASSERT_EQ(0, read_comp
->wait_for_complete());
6679 read_comp
->release();
6682 TEST_F(TestLibRBD
, ExclusiveLock
)
6684 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
6686 static char buf
[10];
6688 rados_ioctx_t ioctx
;
6689 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6691 std::string name
= get_temp_image_name();
6692 uint64_t size
= 2 << 20;
6694 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6697 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
6700 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
6701 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6702 ASSERT_TRUE(lock_owner
);
6704 rbd_lock_mode_t lock_mode
;
6705 char *lock_owners
[1];
6706 size_t max_lock_owners
= 0;
6707 ASSERT_EQ(-ERANGE
, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
6709 ASSERT_EQ(1U, max_lock_owners
);
6711 ASSERT_EQ(0, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
6713 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
6714 ASSERT_STRNE("", lock_owners
[0]);
6715 ASSERT_EQ(1U, max_lock_owners
);
6718 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
6720 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6721 ASSERT_FALSE(lock_owner
);
6723 ASSERT_EQ(-EOPNOTSUPP
, rbd_lock_break(image1
, RBD_LOCK_MODE_SHARED
, ""));
6724 ASSERT_EQ(-EBUSY
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
6727 ASSERT_EQ(0, rbd_lock_release(image1
));
6728 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6729 ASSERT_FALSE(lock_owner
);
6731 ASSERT_EQ(-ENOENT
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
6733 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
6735 ASSERT_EQ(-EROFS
, rbd_write(image1
, 0, sizeof(buf
), buf
));
6736 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image2
, 0, sizeof(buf
), buf
));
6738 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
6739 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6740 ASSERT_TRUE(lock_owner
);
6742 ASSERT_EQ(0, rbd_lock_release(image2
));
6743 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6744 ASSERT_FALSE(lock_owner
);
6746 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
6747 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6748 ASSERT_TRUE(lock_owner
);
6750 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image1
, 0, sizeof(buf
), buf
));
6751 ASSERT_EQ(-EROFS
, rbd_write(image2
, 0, sizeof(buf
), buf
));
6753 ASSERT_EQ(0, rbd_lock_release(image1
));
6754 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6755 ASSERT_FALSE(lock_owner
);
6759 const auto pingpong
= [&](int m_id
, rbd_image_t
&m_image
) {
6760 for (int i
= 0; i
< 10; i
++) {
6762 lock_guard
<mutex
> locker(lock
);
6763 if (owner_id
== m_id
) {
6764 std::cout
<< m_id
<< ": releasing exclusive lock" << std::endl
;
6765 EXPECT_EQ(0, rbd_lock_release(m_image
));
6767 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
6768 EXPECT_FALSE(lock_owner
);
6770 std::cout
<< m_id
<< ": exclusive lock released" << std::endl
;
6775 std::cout
<< m_id
<< ": acquiring exclusive lock" << std::endl
;
6778 r
= rbd_lock_acquire(m_image
, RBD_LOCK_MODE_EXCLUSIVE
);
6782 } while (r
== -EROFS
);
6786 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
6787 EXPECT_TRUE(lock_owner
);
6788 std::cout
<< m_id
<< ": exclusive lock acquired" << std::endl
;
6790 lock_guard
<mutex
> locker(lock
);
6793 usleep(rand() % 50000);
6796 lock_guard
<mutex
> locker(lock
);
6797 if (owner_id
== m_id
) {
6798 EXPECT_EQ(0, rbd_lock_release(m_image
));
6800 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
6801 EXPECT_FALSE(lock_owner
);
6805 thread
ping(bind(pingpong
, 1, ref(image1
)));
6806 thread
pong(bind(pingpong
, 2, ref(image2
)));
6811 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
6812 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6813 ASSERT_TRUE(lock_owner
);
6815 ASSERT_EQ(0, rbd_close(image2
));
6817 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
6818 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6819 ASSERT_TRUE(lock_owner
);
6821 ASSERT_EQ(0, rbd_close(image1
));
6822 rados_ioctx_destroy(ioctx
);
6825 TEST_F(TestLibRBD
, BreakLock
)
6827 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
6829 static char buf
[10];
6831 rados_t blacklist_cluster
;
6832 ASSERT_EQ("", connect_cluster(&blacklist_cluster
));
6834 rados_ioctx_t ioctx
, blacklist_ioctx
;
6835 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
6836 ASSERT_EQ(0, rados_ioctx_create(blacklist_cluster
, m_pool_name
.c_str(),
6839 std::string name
= get_temp_image_name();
6840 uint64_t size
= 2 << 20;
6842 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6844 rbd_image_t image
, blacklist_image
;
6845 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6846 ASSERT_EQ(0, rbd_open(blacklist_ioctx
, name
.c_str(), &blacklist_image
, NULL
));
6848 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_blacklist_on_break_lock", "true"));
6849 ASSERT_EQ(0, rbd_lock_acquire(blacklist_image
, RBD_LOCK_MODE_EXCLUSIVE
));
6851 rbd_lock_mode_t lock_mode
;
6852 char *lock_owners
[1];
6853 size_t max_lock_owners
= 1;
6854 ASSERT_EQ(0, rbd_lock_get_owners(image
, &lock_mode
, lock_owners
,
6856 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
6857 ASSERT_STRNE("", lock_owners
[0]);
6858 ASSERT_EQ(1U, max_lock_owners
);
6860 ASSERT_EQ(0, rbd_lock_break(image
, RBD_LOCK_MODE_EXCLUSIVE
, lock_owners
[0]));
6861 ASSERT_EQ(0, rbd_lock_acquire(image
, RBD_LOCK_MODE_EXCLUSIVE
));
6862 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blacklist_cluster
));
6864 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image
, 0, sizeof(buf
), buf
));
6865 ASSERT_EQ(-EBLACKLISTED
, rbd_write(blacklist_image
, 0, sizeof(buf
), buf
));
6867 ASSERT_EQ(0, rbd_close(image
));
6868 ASSERT_EQ(0, rbd_close(blacklist_image
));
6870 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
6872 rados_ioctx_destroy(ioctx
);
6873 rados_ioctx_destroy(blacklist_ioctx
);
6874 rados_shutdown(blacklist_cluster
);
6877 TEST_F(TestLibRBD
, DiscardAfterWrite
)
6879 REQUIRE(!is_skip_partial_discard_enabled());
6881 librados::IoCtx ioctx
;
6882 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6885 std::string name
= get_temp_image_name();
6886 uint64_t size
= 1 << 20;
6888 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6890 librbd::Image image
;
6891 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6893 // enable writeback cache
6894 ASSERT_EQ(0, image
.flush());
6897 bl
.append(std::string(256, '1'));
6899 librbd::RBD::AioCompletion
*write_comp
=
6900 new librbd::RBD::AioCompletion(NULL
, NULL
);
6901 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
6902 ASSERT_EQ(0, write_comp
->wait_for_complete());
6903 write_comp
->release();
6905 librbd::RBD::AioCompletion
*discard_comp
=
6906 new librbd::RBD::AioCompletion(NULL
, NULL
);
6907 ASSERT_EQ(0, image
.aio_discard(0, 256, discard_comp
));
6908 ASSERT_EQ(0, discard_comp
->wait_for_complete());
6909 discard_comp
->release();
6911 librbd::RBD::AioCompletion
*read_comp
=
6912 new librbd::RBD::AioCompletion(NULL
, NULL
);
6914 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
6915 ASSERT_EQ(0, read_comp
->wait_for_complete());
6916 ASSERT_EQ(bl
.length(), read_comp
->get_return_value());
6917 ASSERT_TRUE(read_bl
.is_zero());
6918 read_comp
->release();
6921 TEST_F(TestLibRBD
, DefaultFeatures
) {
6922 std::string orig_default_features
;
6923 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", orig_default_features
));
6924 BOOST_SCOPE_EXIT_ALL(orig_default_features
) {
6925 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features",
6926 orig_default_features
.c_str()));
6929 std::list
<std::pair
<std::string
, std::string
> > feature_names_to_bitmask
= {
6930 {"", orig_default_features
},
6932 {"layering, exclusive-lock", "5"},
6933 {"exclusive-lock,journaling", "68"},
6937 for (auto &pair
: feature_names_to_bitmask
) {
6938 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features", pair
.first
.c_str()));
6939 std::string features
;
6940 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", features
));
6941 ASSERT_EQ(pair
.second
, features
);
6945 TEST_F(TestLibRBD
, TestTrashMoveAndPurge
) {
6946 REQUIRE_FORMAT_V2();
6948 librados::IoCtx ioctx
;
6949 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6952 std::string name
= get_temp_image_name();
6954 uint64_t size
= 1 << 18;
6956 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6958 librbd::Image image
;
6959 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
6961 std::string image_id
;
6962 ASSERT_EQ(0, image
.get_id(&image_id
));
6965 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 0));
6967 std::vector
<std::string
> images
;
6968 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
6969 for (const auto& image
: images
) {
6970 ASSERT_TRUE(image
!= name
);
6973 librbd::trash_image_info_t info
;
6974 ASSERT_EQ(-ENOENT
, rbd
.trash_get(ioctx
, "dummy image id", &info
));
6975 ASSERT_EQ(0, rbd
.trash_get(ioctx
, image_id
.c_str(), &info
));
6976 ASSERT_EQ(image_id
, info
.id
);
6978 std::vector
<librbd::trash_image_info_t
> entries
;
6979 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
6980 ASSERT_FALSE(entries
.empty());
6981 ASSERT_EQ(entries
.begin()->id
, image_id
);
6985 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
6987 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
6988 ASSERT_TRUE(entries
.empty());
6991 TEST_F(TestLibRBD
, TestTrashMoveAndPurgeNonExpiredDelay
) {
6992 REQUIRE_FORMAT_V2();
6994 librados::IoCtx ioctx
;
6995 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6998 std::string name
= get_temp_image_name();
7000 uint64_t size
= 1 << 18;
7002 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7004 librbd::Image image
;
7005 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7007 std::string image_id
;
7008 ASSERT_EQ(0, image
.get_id(&image_id
));
7011 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 100));
7014 ASSERT_EQ(-EPERM
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7018 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7022 TEST_F(TestLibRBD
, TestTrashPurge
) {
7023 REQUIRE_FORMAT_V2();
7025 librados::IoCtx ioctx
;
7026 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7029 std::string name1
= get_temp_image_name();
7030 std::string name2
= get_temp_image_name();
7032 uint64_t size
= 1 << 18;
7034 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name1
.c_str(), size
, &order
));
7035 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
7037 librbd::Image image1
;
7038 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name1
.c_str(), nullptr));
7040 std::string image_id1
;
7041 ASSERT_EQ(0, image1
.get_id(&image_id1
));
7044 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name1
.c_str(), 0));
7046 librbd::Image image2
;
7047 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), nullptr));
7048 ceph::bufferlist bl
;
7049 bl
.append(std::string(1024, '0'));
7050 ASSERT_EQ(1024, image2
.write(0, 1024, bl
));
7052 std::string image_id2
;
7053 ASSERT_EQ(0, image2
.get_id(&image_id2
));
7056 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name2
.c_str(), 100));
7057 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, 0, -1));
7059 std::vector
<librbd::trash_image_info_t
> entries
;
7060 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7061 ASSERT_EQ(1U, entries
.size());
7062 ASSERT_EQ(image_id2
, entries
[0].id
);
7063 ASSERT_EQ(name2
, entries
[0].name
);
7066 struct timespec now
;
7067 clock_gettime(CLOCK_REALTIME
, &now
);
7068 float threshold
= 0.0;
7069 if (!is_librados_test_stub(_rados
)) {
7070 // real cluster usage reports have a long latency to update
7074 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, now
.tv_sec
+1000, threshold
));
7075 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7076 ASSERT_EQ(0U, entries
.size());
7079 TEST_F(TestLibRBD
, TestTrashMoveAndRestore
) {
7080 REQUIRE_FORMAT_V2();
7082 librados::IoCtx ioctx
;
7083 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7086 std::string name
= get_temp_image_name();
7088 uint64_t size
= 1 << 18;
7090 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7092 librbd::Image image
;
7093 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7095 std::string image_id
;
7096 ASSERT_EQ(0, image
.get_id(&image_id
));
7099 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 10));
7101 std::vector
<std::string
> images
;
7102 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7103 for (const auto& image
: images
) {
7104 ASSERT_TRUE(image
!= name
);
7107 std::vector
<librbd::trash_image_info_t
> entries
;
7108 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7109 ASSERT_FALSE(entries
.empty());
7110 ASSERT_EQ(entries
.begin()->id
, image_id
);
7113 ASSERT_EQ(0, rbd
.trash_restore(ioctx
, image_id
.c_str(), ""));
7114 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7115 ASSERT_FALSE(images
.empty());
7117 for (const auto& image
: images
) {
7118 if (image
== name
) {
7126 TEST_F(TestLibRBD
, TestListWatchers
) {
7127 librados::IoCtx ioctx
;
7128 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7131 std::string name
= get_temp_image_name();
7133 uint64_t size
= 1 << 18;
7135 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7137 librbd::Image image
;
7138 std::list
<librbd::image_watcher_t
> watchers
;
7141 ASSERT_EQ(0, rbd
.open_read_only(ioctx
, image
, name
.c_str(), nullptr));
7142 ASSERT_EQ(0, image
.list_watchers(watchers
));
7143 ASSERT_EQ(0U, watchers
.size());
7144 ASSERT_EQ(0, image
.close());
7147 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7148 ASSERT_EQ(0, image
.list_watchers(watchers
));
7149 ASSERT_EQ(1U, watchers
.size());
7150 ASSERT_EQ(0, image
.close());
7153 TEST_F(TestLibRBD
, TestSetSnapById
) {
7154 librados::IoCtx ioctx
;
7155 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7158 std::string name
= get_temp_image_name();
7160 uint64_t size
= 1 << 18;
7162 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7164 librbd::Image image
;
7165 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7166 ASSERT_EQ(0, image
.snap_create("snap"));
7168 vector
<librbd::snap_info_t
> snaps
;
7169 ASSERT_EQ(0, image
.snap_list(snaps
));
7170 ASSERT_EQ(1U, snaps
.size());
7172 ASSERT_EQ(0, image
.snap_set_by_id(snaps
[0].id
));
7173 ASSERT_EQ(0, image
.snap_set_by_id(CEPH_NOSNAP
));
7176 TEST_F(TestLibRBD
, Namespaces
) {
7177 rados_ioctx_t ioctx
;
7178 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
7179 rados_remove(ioctx
, RBD_NAMESPACE
);
7181 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name1"));
7182 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name2"));
7183 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name3"));
7184 ASSERT_EQ(0, rbd_namespace_remove(ioctx
, "name2"));
7187 size_t max_size
= sizeof(names
);
7188 int len
= rbd_namespace_list(ioctx
, names
, &max_size
);
7190 std::vector
<std::string
> cpp_names
;
7191 for (char* cur_name
= names
; cur_name
< names
+ len
; ) {
7192 cpp_names
.push_back(cur_name
);
7193 cur_name
+= strlen(cur_name
) + 1;
7195 ASSERT_EQ(2U, cpp_names
.size());
7196 ASSERT_EQ("name1", cpp_names
[0]);
7197 ASSERT_EQ("name3", cpp_names
[1]);
7199 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name2", &exists
));
7200 ASSERT_FALSE(exists
);
7201 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name3", &exists
));
7202 ASSERT_TRUE(exists
);
7203 rados_ioctx_destroy(ioctx
);
7206 TEST_F(TestLibRBD
, NamespacesPP
) {
7207 librados::IoCtx ioctx
;
7208 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7209 ioctx
.remove(RBD_NAMESPACE
);
7212 ASSERT_EQ(-EINVAL
, rbd
.namespace_create(ioctx
, ""));
7213 ASSERT_EQ(-EINVAL
, rbd
.namespace_remove(ioctx
, ""));
7215 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name1"));
7216 ASSERT_EQ(-EEXIST
, rbd
.namespace_create(ioctx
, "name1"));
7217 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name2"));
7218 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name3"));
7219 ASSERT_EQ(0, rbd
.namespace_remove(ioctx
, "name2"));
7220 ASSERT_EQ(-ENOENT
, rbd
.namespace_remove(ioctx
, "name2"));
7222 std::vector
<std::string
> names
;
7223 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7224 ASSERT_EQ(2U, names
.size());
7225 ASSERT_EQ("name1", names
[0]);
7226 ASSERT_EQ("name3", names
[1]);
7228 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name2", &exists
));
7229 ASSERT_FALSE(exists
);
7230 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name3", &exists
));
7231 ASSERT_TRUE(exists
);
7233 librados::IoCtx ns_io_ctx
;
7234 ns_io_ctx
.dup(ioctx
);
7236 std::string name
= get_temp_image_name();
7238 uint64_t features
= 0;
7239 if (!get_features(&features
)) {
7240 // old format doesn't support namespaces
7241 ns_io_ctx
.set_namespace("name1");
7242 ASSERT_EQ(-EINVAL
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0,
7247 ns_io_ctx
.set_namespace("missing");
7248 ASSERT_EQ(-ENOENT
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7250 ns_io_ctx
.set_namespace("name1");
7251 ASSERT_EQ(0, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7252 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7254 std::string image_id
;
7256 librbd::Image image
;
7257 ASSERT_EQ(-ENOENT
, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7258 ASSERT_EQ(0, rbd
.open(ns_io_ctx
, image
, name
.c_str(), NULL
));
7259 ASSERT_EQ(0, get_image_id(image
, &image_id
));
7262 ASSERT_EQ(-ENOENT
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7263 ASSERT_EQ(0, rbd
.trash_move(ns_io_ctx
, name
.c_str(), 0));
7264 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7267 ASSERT_EQ(-ENOENT
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7269 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ns_io_ctx
, image_id
.c_str(),
7271 ASSERT_EQ(0, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7274 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7275 ASSERT_EQ(1U, names
.size());
7276 ASSERT_EQ("name3", names
[0]);
7279 TEST_F(TestLibRBD
, Migration
) {
7282 ASSERT_EQ(0, get_features(&old_format
, &features
));
7284 rados_ioctx_t ioctx
;
7285 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7286 BOOST_SCOPE_EXIT(&ioctx
) {
7287 rados_ioctx_destroy(ioctx
);
7288 } BOOST_SCOPE_EXIT_END
;
7291 std::string name
= get_temp_image_name();
7292 uint64_t size
= 2 << 20;
7293 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7295 rbd_image_options_t image_options
;
7296 rbd_image_options_create(&image_options
);
7297 BOOST_SCOPE_EXIT(&image_options
) {
7298 rbd_image_options_destroy(image_options
);
7299 } BOOST_SCOPE_EXIT_END
;
7301 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7304 rbd_image_migration_status_t status
;
7305 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7307 ASSERT_EQ(status
.source_pool_id
, rados_ioctx_get_id(ioctx
));
7308 ASSERT_EQ(status
.source_image_name
, name
);
7310 ASSERT_EQ(status
.source_image_id
, string());
7312 ASSERT_NE(status
.source_image_id
, string());
7313 ASSERT_EQ(-EROFS
, rbd_trash_remove(ioctx
, status
.source_image_id
, false));
7314 ASSERT_EQ(-EINVAL
, rbd_trash_restore(ioctx
, status
.source_image_id
, name
.c_str()));
7316 ASSERT_EQ(status
.dest_pool_id
, rados_ioctx_get_id(ioctx
));
7317 ASSERT_EQ(status
.dest_image_name
, name
);
7318 ASSERT_NE(status
.dest_image_id
, string());
7319 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
7320 rbd_migration_status_cleanup(&status
);
7322 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, name
.c_str()));
7323 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, name
.c_str(), 0));
7325 ASSERT_EQ(0, rbd_migration_execute(ioctx
, name
.c_str()));
7327 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7329 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
7330 rbd_migration_status_cleanup(&status
);
7332 ASSERT_EQ(0, rbd_migration_commit(ioctx
, name
.c_str()));
7334 std::string new_name
= get_temp_image_name();
7336 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
,
7337 new_name
.c_str(), image_options
));
7339 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, new_name
.c_str()));
7340 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, new_name
.c_str(), 0));
7342 ASSERT_EQ(0, rbd_migration_abort(ioctx
, name
.c_str()));
7345 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7346 EXPECT_EQ(0, rbd_close(image
));
7349 TEST_F(TestLibRBD
, MigrationPP
) {
7352 ASSERT_EQ(0, get_features(&old_format
, &features
));
7354 librados::IoCtx ioctx
;
7355 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7358 std::string name
= get_temp_image_name();
7359 uint64_t size
= 2 << 20;
7361 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7363 librbd::ImageOptions image_options
;
7365 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7368 librbd::image_migration_status_t status
;
7369 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
7371 ASSERT_EQ(status
.source_pool_id
, ioctx
.get_id());
7372 ASSERT_EQ(status
.source_image_name
, name
);
7374 ASSERT_EQ(status
.source_image_id
, "");
7376 ASSERT_NE(status
.source_image_id
, "");
7377 ASSERT_EQ(-EROFS
, rbd
.trash_remove(ioctx
, status
.source_image_id
.c_str(), false));
7378 ASSERT_EQ(-EINVAL
, rbd
.trash_restore(ioctx
, status
.source_image_id
.c_str(), name
.c_str()));
7380 ASSERT_EQ(status
.dest_pool_id
, ioctx
.get_id());
7381 ASSERT_EQ(status
.dest_image_name
, name
);
7382 ASSERT_NE(status
.dest_image_id
, "");
7383 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
7385 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, name
.c_str()));
7386 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7388 ASSERT_EQ(0, rbd
.migration_execute(ioctx
, name
.c_str()));
7390 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
7392 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
7394 ASSERT_EQ(0, rbd
.migration_commit(ioctx
, name
.c_str()));
7396 std::string new_name
= get_temp_image_name();
7398 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
,
7399 new_name
.c_str(), image_options
));
7401 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, new_name
.c_str()));
7402 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, new_name
.c_str(), 0));
7404 ASSERT_EQ(0, rbd
.migration_abort(ioctx
, name
.c_str()));
7406 librbd::Image image
;
7407 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7410 TEST_F(TestLibRBD
, TestGetAccessTimestamp
)
7412 REQUIRE_FORMAT_V2();
7414 rados_ioctx_t ioctx
;
7415 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7419 std::string name
= get_temp_image_name();
7420 uint64_t size
= 2 << 20;
7421 struct timespec timestamp
;
7423 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7424 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7426 ASSERT_EQ(0, rbd_get_access_timestamp(image
, ×tamp
));
7427 ASSERT_LT(0, timestamp
.tv_sec
);
7429 ASSERT_PASSED(validate_object_map
, image
);
7430 ASSERT_EQ(0, rbd_close(image
));
7432 rados_ioctx_destroy(ioctx
);
7435 TEST_F(TestLibRBD
, TestGetModifyTimestamp
)
7437 REQUIRE_FORMAT_V2();
7439 rados_ioctx_t ioctx
;
7440 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7444 std::string name
= get_temp_image_name();
7445 uint64_t size
= 2 << 20;
7446 struct timespec timestamp
;
7448 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7449 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7450 ASSERT_EQ(0, rbd_get_modify_timestamp(image
, ×tamp
));
7451 ASSERT_LT(0, timestamp
.tv_sec
);
7453 ASSERT_PASSED(validate_object_map
, image
);
7454 ASSERT_EQ(0, rbd_close(image
));
7456 rados_ioctx_destroy(ioctx
);
7459 TEST_F(TestLibRBD
, ZeroOverlapFlatten
) {
7460 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7462 librados::IoCtx ioctx
;
7463 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7466 librbd::Image parent_image
;
7467 std::string name
= get_temp_image_name();
7472 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7473 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
7476 ASSERT_EQ(0, parent_image
.features(&features
));
7478 ASSERT_EQ(0, parent_image
.snap_create("snap"));
7479 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
7481 std::string clone_name
= this->get_temp_image_name();
7482 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
7485 librbd::Image clone_image
;
7486 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
7487 ASSERT_EQ(0, clone_image
.resize(0));
7488 ASSERT_EQ(0, clone_image
.flatten());
7491 TEST_F(TestLibRBD
, PoolMetadata
)
7493 REQUIRE_FORMAT_V2();
7495 rados_ioctx_t ioctx
;
7496 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7500 size_t keys_len
= sizeof(keys
);
7501 size_t vals_len
= sizeof(vals
);
7503 memset_rand(keys
, keys_len
);
7504 memset_rand(vals
, vals_len
);
7506 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7508 ASSERT_EQ(0U, keys_len
);
7509 ASSERT_EQ(0U, vals_len
);
7512 size_t value_len
= sizeof(value
);
7513 memset_rand(value
, value_len
);
7515 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
7516 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key2", "value2"));
7517 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
7518 ASSERT_STREQ(value
, "value1");
7520 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
7521 ASSERT_EQ(value_len
, strlen("value1") + 1);
7523 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7525 keys_len
= sizeof(keys
);
7526 vals_len
= sizeof(vals
);
7527 memset_rand(keys
, keys_len
);
7528 memset_rand(vals
, vals_len
);
7529 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7531 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
7532 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
7533 ASSERT_STREQ(keys
, "key1");
7534 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
7535 ASSERT_STREQ(vals
, "value1");
7536 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
7538 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
7539 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_remove(ioctx
, "key3"));
7540 value_len
= sizeof(value
);
7541 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_get(ioctx
, "key3", value
, &value_len
));
7542 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7544 ASSERT_EQ(keys_len
, strlen("key2") + 1);
7545 ASSERT_EQ(vals_len
, strlen("value2") + 1);
7546 ASSERT_STREQ(keys
, "key2");
7547 ASSERT_STREQ(vals
, "value2");
7549 // test config setting
7550 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
7551 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7552 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
7553 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7555 // test short buffer cases
7556 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
7557 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key3", "value3"));
7558 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key4", "value4"));
7560 keys_len
= strlen("key1") + 1;
7561 vals_len
= strlen("value1") + 1;
7562 memset_rand(keys
, keys_len
);
7563 memset_rand(vals
, vals_len
);
7564 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 1, keys
, &keys_len
, vals
,
7566 ASSERT_EQ(keys_len
, strlen("key1") + 1);
7567 ASSERT_EQ(vals_len
, strlen("value1") + 1);
7568 ASSERT_STREQ(keys
, "key1");
7569 ASSERT_STREQ(vals
, "value1");
7571 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 2, keys
, &keys_len
, vals
,
7573 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
7574 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
7576 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7578 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
7579 1 + strlen("key4") + 1);
7580 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
7581 strlen("value3") + 1 + strlen("value4") + 1);
7583 // test `start` param
7584 keys_len
= sizeof(keys
);
7585 vals_len
= sizeof(vals
);
7586 memset_rand(keys
, keys_len
);
7587 memset_rand(vals
, vals_len
);
7588 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "key2", 0, keys
, &keys_len
, vals
,
7590 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
7591 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
7592 ASSERT_STREQ(keys
, "key3");
7593 ASSERT_STREQ(vals
, "value3");
7596 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
7597 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key2"));
7598 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key3"));
7599 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key4"));
7600 rados_ioctx_destroy(ioctx
);
7603 TEST_F(TestLibRBD
, PoolMetadataPP
)
7605 REQUIRE_FORMAT_V2();
7609 map
<string
, bufferlist
> pairs
;
7611 librados::IoCtx ioctx
;
7612 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7614 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
7615 ASSERT_TRUE(pairs
.empty());
7617 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
7618 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key2", "value2"));
7619 ASSERT_EQ(0, rbd
.pool_metadata_get(ioctx
, "key1", &value
));
7620 ASSERT_EQ(value
, "value1");
7621 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
7622 ASSERT_EQ(2U, pairs
.size());
7623 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
7624 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
7626 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
7627 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_remove(ioctx
, "key3"));
7628 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_get(ioctx
, "key3", &value
));
7630 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
7631 ASSERT_EQ(1U, pairs
.size());
7632 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
7634 // test `start` param
7635 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
7636 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key3", "value3"));
7639 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "key2", 0, &pairs
));
7640 ASSERT_EQ(1U, pairs
.size());
7641 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
7643 // test config setting
7644 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
7645 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7646 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
7647 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7650 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
7651 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key2"));
7652 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key3"));
7655 TEST_F(TestLibRBD
, Config
)
7657 REQUIRE_FORMAT_V2();
7659 rados_ioctx_t ioctx
;
7660 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7662 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7664 rbd_config_option_t options
[1024];
7665 int max_options
= 0;
7666 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
7667 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
7668 ASSERT_GT(max_options
, 0);
7669 ASSERT_LT(max_options
, 1024);
7670 for (int i
= 0; i
< max_options
; i
++) {
7671 if (options
[i
].name
== std::string("rbd_cache")) {
7672 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
7673 ASSERT_STREQ("false", options
[i
].value
);
7675 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7678 rbd_config_pool_list_cleanup(options
, max_options
);
7682 std::string name
= get_temp_image_name();
7683 uint64_t size
= 2 << 20;
7685 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7686 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7688 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
7689 for (int i
= 0; i
< max_options
; i
++) {
7690 if (options
[i
].name
== std::string("rbd_cache")) {
7691 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
7692 ASSERT_STREQ("false", options
[i
].value
);
7694 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7697 rbd_config_image_list_cleanup(options
, max_options
);
7699 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_cache", "true"));
7701 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
7702 for (int i
= 0; i
< max_options
; i
++) {
7703 if (options
[i
].name
== std::string("rbd_cache")) {
7704 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_IMAGE
);
7705 ASSERT_STREQ("true", options
[i
].value
);
7707 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7710 rbd_config_image_list_cleanup(options
, max_options
);
7712 ASSERT_EQ(0, rbd_metadata_remove(image
, "conf_rbd_cache"));
7714 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
7715 for (int i
= 0; i
< max_options
; i
++) {
7716 if (options
[i
].name
== std::string("rbd_cache")) {
7717 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
7718 ASSERT_STREQ("false", options
[i
].value
);
7720 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7723 rbd_config_image_list_cleanup(options
, max_options
);
7725 ASSERT_EQ(0, rbd_close(image
));
7727 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7729 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
7730 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
7731 for (int i
= 0; i
< max_options
; i
++) {
7732 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7734 rbd_config_pool_list_cleanup(options
, max_options
);
7736 rados_ioctx_destroy(ioctx
);
7739 TEST_F(TestLibRBD
, ConfigPP
)
7741 REQUIRE_FORMAT_V2();
7746 librados::IoCtx ioctx
;
7747 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7749 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7751 std::vector
<librbd::config_option_t
> options
;
7752 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
7753 for (auto &option
: options
) {
7754 if (option
.name
== std::string("rbd_cache")) {
7755 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
7756 ASSERT_EQ("false", option
.value
);
7758 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7763 std::string name
= get_temp_image_name();
7764 uint64_t size
= 2 << 20;
7765 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7767 librbd::Image image
;
7768 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7771 ASSERT_EQ(0, image
.config_list(&options
));
7772 for (auto &option
: options
) {
7773 if (option
.name
== std::string("rbd_cache")) {
7774 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
7775 ASSERT_EQ("false", option
.value
);
7777 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7781 ASSERT_EQ(0, image
.metadata_set("conf_rbd_cache", "true"));
7784 ASSERT_EQ(0, image
.config_list(&options
));
7785 for (auto &option
: options
) {
7786 if (option
.name
== std::string("rbd_cache")) {
7787 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_IMAGE
);
7788 ASSERT_EQ("true", option
.value
);
7790 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7794 ASSERT_EQ(0, image
.metadata_remove("conf_rbd_cache"));
7797 ASSERT_EQ(0, image
.config_list(&options
));
7798 for (auto &option
: options
) {
7799 if (option
.name
== std::string("rbd_cache")) {
7800 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
7801 ASSERT_EQ("false", option
.value
);
7803 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7807 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7810 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
7811 for (auto &option
: options
) {
7812 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7816 TEST_F(TestLibRBD
, PoolStatsPP
)
7818 REQUIRE_FORMAT_V2();
7820 librados::IoCtx ioctx
;
7821 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
7824 std::string image_name
;
7825 uint64_t size
= 2 << 20;
7826 uint64_t expected_size
= 0;
7827 for (size_t idx
= 0; idx
< 4; ++idx
) {
7828 image_name
= get_temp_image_name();
7831 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, image_name
.c_str(), size
, &order
));
7832 expected_size
+= size
;
7835 librbd::Image image
;
7836 ASSERT_EQ(0, rbd
.open(ioctx
, image
, image_name
.c_str(), NULL
));
7837 ASSERT_EQ(0, image
.snap_create("snap1"));
7838 ASSERT_EQ(0, image
.resize(0));
7839 ASSERT_EQ(0, image
.close());
7840 uint64_t expect_head_size
= (expected_size
- size
);
7842 uint64_t image_count
;
7843 uint64_t provisioned_bytes
;
7844 uint64_t max_provisioned_bytes
;
7845 uint64_t snap_count
;
7846 uint64_t trash_image_count
;
7847 uint64_t trash_provisioned_bytes
;
7848 uint64_t trash_max_provisioned_bytes
;
7849 uint64_t trash_snap_count
;
7851 librbd::PoolStats pool_stats1
;
7852 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGES
, &image_count
);
7853 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
,
7854 &provisioned_bytes
);
7855 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
7857 ASSERT_EQ(4U, image_count
);
7858 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
7860 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
,
7861 &max_provisioned_bytes
);
7862 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
7863 ASSERT_EQ(4U, image_count
);
7864 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
7865 ASSERT_EQ(expected_size
, max_provisioned_bytes
);
7867 librbd::PoolStats pool_stats2
;
7868 pool_stats2
.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
, &snap_count
);
7869 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
7870 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
7871 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats2
));
7872 ASSERT_EQ(1U, snap_count
);
7873 ASSERT_EQ(0U, trash_image_count
);
7874 ASSERT_EQ(0U, trash_snap_count
);
7876 ASSERT_EQ(0, rbd
.trash_move(ioctx
, image_name
.c_str(), 0));
7878 librbd::PoolStats pool_stats3
;
7879 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
7880 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
,
7881 &trash_provisioned_bytes
);
7882 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
,
7883 &trash_max_provisioned_bytes
);
7884 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
7885 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats3
));
7886 ASSERT_EQ(1U, trash_image_count
);
7887 ASSERT_EQ(0U, trash_provisioned_bytes
);
7888 ASSERT_EQ(size
, trash_max_provisioned_bytes
);
7889 ASSERT_EQ(1U, trash_snap_count
);
7892 TEST_F(TestLibRBD
, ImageSpec
) {
7893 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7895 librados::IoCtx ioctx
;
7896 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
7899 librbd::Image parent_image
;
7900 std::string name
= get_temp_image_name();
7905 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7906 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
7908 std::string parent_id
;
7909 ASSERT_EQ(0, parent_image
.get_id(&parent_id
));
7912 ASSERT_EQ(0, parent_image
.features(&features
));
7914 ASSERT_EQ(0, parent_image
.snap_create("snap"));
7915 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
7917 std::string clone_name
= this->get_temp_image_name();
7918 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
7921 librbd::Image clone_image
;
7922 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
7924 std::string clone_id
;
7925 ASSERT_EQ(0, clone_image
.get_id(&clone_id
));
7927 std::vector
<librbd::image_spec_t
> images
;
7928 ASSERT_EQ(0, rbd
.list2(ioctx
, &images
));
7930 std::vector
<librbd::image_spec_t
> expected_images
{
7931 {.id
= parent_id
, .name
= name
},
7932 {.id
= clone_id
, .name
= clone_name
}
7934 std::sort(expected_images
.begin(), expected_images
.end(),
7935 [](const librbd::image_spec_t
& lhs
, const librbd::image_spec_t
&rhs
) {
7936 return lhs
.name
< rhs
.name
;
7938 ASSERT_EQ(expected_images
, images
);
7940 librbd::linked_image_spec_t parent_image_spec
;
7941 librbd::snap_spec_t parent_snap_spec
;
7942 ASSERT_EQ(0, clone_image
.get_parent(&parent_image_spec
, &parent_snap_spec
));
7944 librbd::linked_image_spec_t expected_parent_image_spec
{
7945 .pool_id
= ioctx
.get_id(),
7946 .pool_name
= ioctx
.get_pool_name(),
7947 .pool_namespace
= ioctx
.get_namespace(),
7948 .image_id
= parent_id
,
7952 ASSERT_EQ(expected_parent_image_spec
, parent_image_spec
);
7953 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER
, parent_snap_spec
.namespace_type
);
7954 ASSERT_EQ("snap", parent_snap_spec
.name
);
7956 std::vector
<librbd::linked_image_spec_t
> children
;
7957 ASSERT_EQ(0, parent_image
.list_children3(&children
));
7959 std::vector
<librbd::linked_image_spec_t
> expected_children
{
7961 .pool_id
= ioctx
.get_id(),
7962 .pool_name
= ioctx
.get_pool_name(),
7963 .pool_namespace
= ioctx
.get_namespace(),
7964 .image_id
= clone_id
,
7965 .image_name
= clone_name
,
7969 ASSERT_EQ(expected_children
, children
);
7972 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
7973 ASSERT_EQ(expected_children
, children
);
7975 ASSERT_EQ(0, clone_image
.snap_create("snap"));
7976 ASSERT_EQ(0, clone_image
.snap_protect("snap"));
7978 auto grand_clone_name
= this->get_temp_image_name();
7979 ASSERT_EQ(0, rbd
.clone(ioctx
, clone_name
.c_str(), "snap", ioctx
,
7980 grand_clone_name
.c_str(), features
, &order
));
7981 librbd::Image grand_clone_image
;
7982 ASSERT_EQ(0, rbd
.open(ioctx
, grand_clone_image
, grand_clone_name
.c_str(),
7984 std::string grand_clone_id
;
7985 ASSERT_EQ(0, grand_clone_image
.get_id(&grand_clone_id
));
7988 ASSERT_EQ(0, parent_image
.list_children3(&children
));
7989 ASSERT_EQ(expected_children
, children
);
7992 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
7993 expected_children
.push_back(
7995 .pool_id
= ioctx
.get_id(),
7996 .pool_name
= ioctx
.get_pool_name(),
7997 .pool_namespace
= ioctx
.get_namespace(),
7998 .image_id
= grand_clone_id
,
7999 .image_name
= grand_clone_name
,
8003 ASSERT_EQ(expected_children
, children
);
8006 void super_simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
8010 TEST_F(TestLibRBD
, DISABLED_TestSeqWriteAIOPP
)
8012 librados::IoCtx ioctx
;
8013 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8017 librbd::Image image
;
8019 std::string name
= get_temp_image_name();
8020 uint64_t size
= 5 * (1 << order
);
8022 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8023 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8025 char test_data
[(TEST_IO_SIZE
+ 1) * 10];
8027 for (int i
= 0; i
< 10; i
++) {
8028 for (uint64_t j
= 0; j
< TEST_IO_SIZE
; j
++) {
8029 test_data
[(TEST_IO_SIZE
+ 1) * i
+ j
] = (char)(rand() % (126 - 33) + 33);
8031 test_data
[(TEST_IO_SIZE
+ 1) * i
+ TEST_IO_SIZE
] = '\0';
8034 struct timespec start_time
;
8035 clock_gettime(CLOCK_REALTIME
, &start_time
);
8037 std::list
<librbd::RBD::AioCompletion
*> comps
;
8038 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
8039 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
8040 ceph::bufferlist bl
;
8041 bl
.append(p
, strlen(p
));
8042 auto comp
= new librbd::RBD::AioCompletion(
8043 NULL
, (librbd::callback_t
) super_simple_write_cb_pp
);
8044 image
.aio_write(strlen(p
) * i
, strlen(p
), bl
, comp
);
8045 comps
.push_back(comp
);
8046 if (i
% 1000 == 0) {
8047 cout
<< i
<< " reqs sent" << std::endl
;
8049 for (auto comp
: comps
) {
8050 comp
->wait_for_complete();
8051 ASSERT_EQ(0, comp
->get_return_value());
8058 for (auto comp
: comps
) {
8059 comp
->wait_for_complete();
8060 ASSERT_EQ(0, comp
->get_return_value());
8062 if (i
% 1000 == 0) {
8063 std::cout
<< i
<< " reqs completed" << std::endl
;
8069 struct timespec end_time
;
8070 clock_gettime(CLOCK_REALTIME
, &end_time
);
8071 int duration
= end_time
.tv_sec
* 1000 + end_time
.tv_nsec
/ 1000000 -
8072 start_time
.tv_sec
* 1000 - start_time
.tv_nsec
/ 1000000;
8073 std::cout
<< "duration: " << duration
<< " msec" << std::endl
;
8075 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
8076 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
8077 ASSERT_PASSED(read_test_data
, image
, p
, strlen(p
) * i
, TEST_IO_SIZE
, 0);
8080 ASSERT_PASSED(validate_object_map
, image
);
8086 TEST_F(TestLibRBD
, SnapRemoveWithChildMissing
)
8088 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8089 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
8090 BOOST_SCOPE_EXIT_ALL(&) {
8091 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
8095 rados_ioctx_t ioctx1
, ioctx2
;
8096 string pool_name1
= create_pool(true);
8097 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
8098 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx2
));
8102 rbd_image_t parent
, child1
, child2
, child3
;
8104 char child_id1
[4096];
8105 char child_id2
[4096];
8106 char child_id3
[4096];
8108 ASSERT_EQ(0, get_features(&old_format
, &features
));
8109 ASSERT_FALSE(old_format
);
8110 std::string parent_name
= get_temp_image_name();
8111 std::string child_name1
= get_temp_image_name();
8112 std::string child_name2
= get_temp_image_name();
8113 std::string child_name3
= get_temp_image_name();
8114 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
8116 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
8117 ASSERT_EQ(0, rbd_snap_create(parent
, "snap1"));
8118 ASSERT_EQ(0, rbd_snap_create(parent
, "snap2"));
8120 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap1",
8121 ioctx2
, child_name1
.c_str(), features
, &order
));
8122 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
8123 ioctx1
, child_name2
.c_str(), features
, &order
));
8124 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
8125 ioctx2
, child_name3
.c_str(), features
, &order
));
8127 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &child1
, NULL
));
8128 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &child2
, NULL
));
8129 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &child3
, NULL
));
8130 ASSERT_EQ(0, rbd_get_id(child1
, child_id1
, sizeof(child_id1
)));
8131 ASSERT_EQ(0, rbd_get_id(child2
, child_id2
, sizeof(child_id2
)));
8132 ASSERT_EQ(0, rbd_get_id(child3
, child_id3
, sizeof(child_id3
)));
8133 test_list_children2(parent
, 3,
8134 child_id1
, m_pool_name
.c_str(), child_name1
.c_str(), false,
8135 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
8136 child_id3
, m_pool_name
.c_str(), child_name3
.c_str(), false);
8138 size_t max_size
= 10;
8139 rbd_linked_image_spec_t children
[max_size
];
8140 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8141 ASSERT_EQ(3, static_cast<int>(max_size
));
8142 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8144 ASSERT_EQ(0, rbd_close(child1
));
8145 ASSERT_EQ(0, rbd_close(child2
));
8146 ASSERT_EQ(0, rbd_close(child3
));
8147 rados_ioctx_destroy(ioctx2
);
8148 ASSERT_EQ(0, rados_pool_delete(_cluster
, m_pool_name
.c_str()));
8149 _pool_names
.erase(std::remove(_pool_names
.begin(),
8150 _pool_names
.end(), m_pool_name
),
8152 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
8154 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8155 ASSERT_EQ(3, static_cast<int>(max_size
));
8156 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8157 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap1"));
8158 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8159 ASSERT_EQ(2, static_cast<int>(max_size
));
8160 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8162 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
8163 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8164 ASSERT_EQ(1, static_cast<int>(max_size
));
8165 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8167 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap2"));
8168 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8169 ASSERT_EQ(0, static_cast<int>(max_size
));
8170 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8171 test_list_children2(parent
, 0);
8172 ASSERT_EQ(0, test_ls_snaps(parent
, 0));
8174 ASSERT_EQ(0, rbd_close(parent
));
8175 rados_ioctx_destroy(ioctx1
);
8178 // poorman's ceph_assert()
8180 void __ceph_assert_fail(const char *assertion
, const char *file
, int line
,
8186 #pragma GCC diagnostic pop
8187 #pragma GCC diagnostic warning "-Wpragmas"