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
, TestCreateLsRenameSnapPP
)
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;
1549 uint64_t size2
= 4 << 20;
1551 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1552 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1555 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1556 ASSERT_FALSE(exists
);
1557 ASSERT_EQ(0, image
.snap_create("snap1"));
1558 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1559 ASSERT_TRUE(exists
);
1560 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1561 ASSERT_EQ(0, image
.resize(size2
));
1562 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1563 ASSERT_FALSE(exists
);
1564 ASSERT_EQ(0, image
.snap_create("snap2"));
1565 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1566 ASSERT_TRUE(exists
);
1567 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1568 ASSERT_EQ(0, image
.snap_rename("snap1","snap1-rename"));
1569 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1-rename", size
, "snap2", size2
));
1570 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1571 ASSERT_FALSE(exists
);
1572 ASSERT_EQ(0, image
.snap_exists2("snap1-rename", &exists
));
1573 ASSERT_TRUE(exists
);
1574 ASSERT_EQ(0, image
.snap_remove("snap1-rename"));
1575 ASSERT_EQ(0, image
.snap_rename("snap2","snap2-rename"));
1576 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2-rename", size2
));
1577 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1578 ASSERT_FALSE(exists
);
1579 ASSERT_EQ(0, image
.snap_exists2("snap2-rename", &exists
));
1580 ASSERT_TRUE(exists
);
1581 ASSERT_EQ(0, image
.snap_remove("snap2-rename"));
1582 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1588 void simple_write_cb(rbd_completion_t cb
, void *arg
)
1590 printf("write completion cb called!\n");
1593 void simple_read_cb(rbd_completion_t cb
, void *arg
)
1595 printf("read completion cb called!\n");
1598 void aio_write_test_data_and_poll(rbd_image_t image
, int fd
, const char *test_data
,
1599 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1601 rbd_completion_t comp
;
1602 uint64_t data
= 0x123;
1603 rbd_aio_create_completion((void*)&data
, (rbd_callback_t
) simple_write_cb
, &comp
);
1604 printf("created completion\n");
1605 printf("started write\n");
1607 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
1609 rbd_aio_write(image
, off
, len
, test_data
, comp
);
1613 pfd
.events
= POLLIN
;
1615 ASSERT_EQ(1, poll(&pfd
, 1, -1));
1616 ASSERT_TRUE(pfd
.revents
& POLLIN
);
1618 rbd_completion_t comps
[1];
1619 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
1621 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
1622 read(fd
, &count
, sizeof(count
)));
1623 int r
= rbd_aio_get_return_value(comps
[0]);
1624 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
1625 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps
[0]) == data
);
1626 printf("return value is: %d\n", r
);
1628 printf("finished write\n");
1629 rbd_aio_release(comps
[0]);
1633 void aio_write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1635 rbd_completion_t comp
;
1636 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1637 printf("created completion\n");
1639 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
1641 rbd_aio_write(image
, off
, len
, test_data
, comp
);
1642 printf("started write\n");
1643 rbd_aio_wait_for_complete(comp
);
1644 int r
= rbd_aio_get_return_value(comp
);
1645 printf("return value is: %d\n", r
);
1647 printf("finished write\n");
1648 rbd_aio_release(comp
);
1652 void write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1656 written
= rbd_write2(image
, off
, len
, test_data
, iohint
);
1658 written
= rbd_write(image
, off
, len
, test_data
);
1659 printf("wrote: %d\n", (int) written
);
1660 ASSERT_EQ(len
, static_cast<size_t>(written
));
1664 void aio_discard_test_data(rbd_image_t image
, uint64_t off
, uint64_t len
, bool *passed
)
1666 rbd_completion_t comp
;
1667 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1668 rbd_aio_discard(image
, off
, len
, comp
);
1669 rbd_aio_wait_for_complete(comp
);
1670 int r
= rbd_aio_get_return_value(comp
);
1672 printf("aio discard: %d~%d = %d\n", (int)off
, (int)len
, (int)r
);
1673 rbd_aio_release(comp
);
1677 void discard_test_data(rbd_image_t image
, uint64_t off
, size_t len
, bool *passed
)
1680 written
= rbd_discard(image
, off
, len
);
1681 printf("discard: %d~%d = %d\n", (int)off
, (int)len
, (int)written
);
1682 ASSERT_EQ(len
, static_cast<size_t>(written
));
1686 void aio_read_test_data_and_poll(rbd_image_t image
, int fd
, const char *expected
,
1687 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1689 rbd_completion_t comp
;
1690 char *result
= (char *)malloc(len
+ 1);
1692 ASSERT_NE(static_cast<char *>(NULL
), result
);
1693 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1694 printf("created completion\n");
1695 printf("started read\n");
1697 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
1699 rbd_aio_read(image
, off
, len
, result
, comp
);
1703 pfd
.events
= POLLIN
;
1705 ASSERT_EQ(1, poll(&pfd
, 1, -1));
1706 ASSERT_TRUE(pfd
.revents
& POLLIN
);
1708 rbd_completion_t comps
[1];
1709 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
1711 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
1712 read(fd
, &count
, sizeof(count
)));
1714 int r
= rbd_aio_get_return_value(comps
[0]);
1715 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
1716 printf("return value is: %d\n", r
);
1717 ASSERT_EQ(len
, static_cast<size_t>(r
));
1718 rbd_aio_release(comps
[0]);
1719 if (memcmp(result
, expected
, len
)) {
1720 printf("read: %s\nexpected: %s\n", result
, expected
);
1721 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1727 void aio_read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1729 rbd_completion_t comp
;
1730 char *result
= (char *)malloc(len
+ 1);
1732 ASSERT_NE(static_cast<char *>(NULL
), result
);
1733 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1734 printf("created completion\n");
1736 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
1738 rbd_aio_read(image
, off
, len
, result
, comp
);
1739 printf("started read\n");
1740 rbd_aio_wait_for_complete(comp
);
1741 int r
= rbd_aio_get_return_value(comp
);
1742 printf("return value is: %d\n", r
);
1743 ASSERT_EQ(len
, static_cast<size_t>(r
));
1744 rbd_aio_release(comp
);
1745 if (memcmp(result
, expected
, len
)) {
1746 printf("read: %s\nexpected: %s\n", result
, expected
);
1747 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1753 void read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
1756 char *result
= (char *)malloc(len
+ 1);
1758 ASSERT_NE(static_cast<char *>(NULL
), result
);
1760 read
= rbd_read2(image
, off
, len
, result
, iohint
);
1762 read
= rbd_read(image
, off
, len
, result
);
1763 printf("read: %d\n", (int) read
);
1764 ASSERT_EQ(len
, static_cast<size_t>(read
));
1766 if (memcmp(result
, expected
, len
)) {
1767 printf("read: %s\nexpected: %s\n", result
, expected
);
1768 ASSERT_EQ(0, memcmp(result
, expected
, len
));
1774 void aio_writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
1775 uint64_t data_len
, uint32_t iohint
, bool *passed
)
1777 rbd_completion_t comp
;
1778 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1779 printf("created completion\n");
1781 r
= rbd_aio_writesame(image
, off
, len
, test_data
, data_len
, comp
, iohint
);
1782 printf("started writesame\n");
1783 if (len
% data_len
) {
1784 ASSERT_EQ(-EINVAL
, r
);
1785 printf("expected fail, finished writesame\n");
1786 rbd_aio_release(comp
);
1791 rbd_aio_wait_for_complete(comp
);
1792 r
= rbd_aio_get_return_value(comp
);
1793 printf("return value is: %d\n", r
);
1795 printf("finished writesame\n");
1796 rbd_aio_release(comp
);
1799 printf("to verify the data\n");
1801 char *result
= (char *)malloc(data_len
+ 1);
1802 ASSERT_NE(static_cast<char *>(NULL
), result
);
1803 uint64_t left
= len
;
1805 read
= rbd_read(image
, off
, data_len
, result
);
1806 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
1807 result
[data_len
] = '\0';
1808 if (memcmp(result
, test_data
, data_len
)) {
1809 printf("read: %d ~ %d\n", (int) off
, (int) read
);
1810 printf("read: %s\nexpected: %s\n", result
, test_data
);
1811 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
1816 ASSERT_EQ(0U, left
);
1818 printf("verified\n");
1823 void writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
1824 uint64_t data_len
, uint32_t iohint
, bool *passed
)
1827 written
= rbd_writesame(image
, off
, len
, test_data
, data_len
, iohint
);
1828 if (len
% data_len
) {
1829 ASSERT_EQ(-EINVAL
, written
);
1830 printf("expected fail, finished writesame\n");
1834 ASSERT_EQ(len
, static_cast<size_t>(written
));
1835 printf("wrote: %d\n", (int) written
);
1838 printf("to verify the data\n");
1840 char *result
= (char *)malloc(data_len
+ 1);
1841 ASSERT_NE(static_cast<char *>(NULL
), result
);
1842 uint64_t left
= len
;
1844 read
= rbd_read(image
, off
, data_len
, result
);
1845 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
1846 result
[data_len
] = '\0';
1847 if (memcmp(result
, test_data
, data_len
)) {
1848 printf("read: %d ~ %d\n", (int) off
, (int) read
);
1849 printf("read: %s\nexpected: %s\n", result
, test_data
);
1850 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
1855 ASSERT_EQ(0U, left
);
1857 printf("verified\n");
1862 void aio_compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
1863 const char *test_data
, uint64_t off
,
1864 size_t len
, uint32_t iohint
, bool *passed
)
1866 rbd_completion_t comp
;
1867 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
1868 printf("created completion\n");
1870 uint64_t mismatch_offset
;
1871 rbd_aio_compare_and_write(image
, off
, len
, cmp_data
, test_data
, comp
, &mismatch_offset
, iohint
);
1872 printf("started aio compare and write\n");
1873 rbd_aio_wait_for_complete(comp
);
1874 int r
= rbd_aio_get_return_value(comp
);
1875 printf("return value is: %d\n", r
);
1877 printf("finished aio compare and write\n");
1878 rbd_aio_release(comp
);
1882 void compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
1883 const char *test_data
, uint64_t off
, size_t len
,
1884 uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
1886 printf("start compare and write\n");
1888 written
= rbd_compare_and_write(image
, off
, len
, cmp_data
, test_data
, mismatch_off
, iohint
);
1889 printf("compare and wrote: %d\n", (int) written
);
1890 ASSERT_EQ(len
, static_cast<size_t>(written
));
1895 TEST_F(TestLibRBD
, TestIO
)
1897 rados_ioctx_t ioctx
;
1898 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1900 bool skip_discard
= is_skip_partial_discard_enabled();
1904 std::string name
= get_temp_image_name();
1905 uint64_t size
= 2 << 20;
1907 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1908 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1910 char test_data
[TEST_IO_SIZE
+ 1];
1911 char zero_data
[TEST_IO_SIZE
+ 1];
1912 char mismatch_data
[TEST_IO_SIZE
+ 1];
1914 uint64_t mismatch_offset
;
1916 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
1917 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
1919 test_data
[TEST_IO_SIZE
] = '\0';
1920 memset(zero_data
, 0, sizeof(zero_data
));
1921 memset(mismatch_data
, 9, sizeof(mismatch_data
));
1923 for (i
= 0; i
< 5; ++i
)
1924 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1926 for (i
= 5; i
< 10; ++i
)
1927 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1929 for (i
= 0; i
< 5; ++i
)
1930 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, 0);
1932 for (i
= 5; i
< 10; ++i
)
1933 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1935 for (i
= 0; i
< 5; ++i
)
1936 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1938 for (i
= 5; i
< 10; ++i
)
1939 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
1941 // discard 2nd, 4th sections.
1942 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
1943 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
1945 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
1946 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1947 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
1948 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
1949 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
1950 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
1951 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
1953 for (i
= 0; i
< 15; ++i
) {
1955 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1956 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1957 } else if (i
% 3 == 1) {
1958 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1959 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1961 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1962 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1965 for (i
= 0; i
< 15; ++i
) {
1967 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1968 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
1969 } else if (i
% 3 == 1) {
1970 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1971 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1973 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1974 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
1978 rbd_image_info_t info
;
1979 rbd_completion_t comp
;
1980 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1981 // can't read or write starting past end
1982 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
1983 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
1984 // reading through end returns amount up to end
1985 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
1986 // writing through end returns amount up to end
1987 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
1989 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1990 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
1991 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1992 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
1993 rbd_aio_release(comp
);
1995 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
1996 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
1997 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
1998 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
1999 rbd_aio_release(comp
);
2001 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2002 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
, &mismatch_offset
, 0));
2003 ASSERT_EQ(0U, mismatch_offset
);
2004 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2005 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
, comp
, &mismatch_offset
, 0));
2006 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2007 ASSERT_EQ(0U, mismatch_offset
);
2008 rbd_aio_release(comp
);
2010 ASSERT_PASSED(validate_object_map
, image
);
2011 ASSERT_EQ(0, rbd_close(image
));
2013 rados_ioctx_destroy(ioctx
);
2016 TEST_F(TestLibRBD
, TestIOWithIOHint
)
2018 rados_ioctx_t ioctx
;
2019 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2021 bool skip_discard
= is_skip_partial_discard_enabled();
2025 std::string name
= get_temp_image_name();
2026 uint64_t size
= 2 << 20;
2028 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2029 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2031 char test_data
[TEST_IO_SIZE
+ 1];
2032 char zero_data
[TEST_IO_SIZE
+ 1];
2033 char mismatch_data
[TEST_IO_SIZE
+ 1];
2035 uint64_t mismatch_offset
;
2037 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2038 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2040 test_data
[TEST_IO_SIZE
] = '\0';
2041 memset(zero_data
, 0, sizeof(zero_data
));
2042 memset(mismatch_data
, 9, sizeof(mismatch_data
));
2044 for (i
= 0; i
< 5; ++i
)
2045 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2046 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2048 for (i
= 5; i
< 10; ++i
)
2049 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2050 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2052 for (i
= 0; i
< 5; ++i
)
2053 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
2054 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2056 for (i
= 5; i
< 10; ++i
)
2057 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
2058 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2060 for (i
= 0; i
< 5; ++i
)
2061 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
,
2062 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2064 for (i
= 5; i
< 10; ++i
)
2065 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2066 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2068 // discard 2nd, 4th sections.
2069 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2070 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2072 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
,
2073 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2074 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2075 TEST_IO_SIZE
, TEST_IO_SIZE
,
2076 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2077 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
,
2078 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2079 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2080 TEST_IO_SIZE
*3, TEST_IO_SIZE
,
2081 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2082 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2084 for (i
= 0; i
< 15; ++i
) {
2086 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2087 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2088 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2089 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2090 } else if (i
% 3 == 1) {
2091 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2092 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2093 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2094 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2096 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2097 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2098 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2099 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2102 for (i
= 0; i
< 15; ++i
) {
2104 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2105 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2106 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2107 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2108 } else if (i
% 3 == 1) {
2109 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2110 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2111 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2112 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2114 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2115 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2116 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2117 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2121 rbd_image_info_t info
;
2122 rbd_completion_t comp
;
2123 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2124 // can't read or write starting past end
2125 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2126 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2127 // reading through end returns amount up to end
2128 ASSERT_EQ(10, rbd_read2(image
, info
.size
- 10, 100, test_data
,
2129 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
));
2130 // writing through end returns amount up to end
2131 ASSERT_EQ(10, rbd_write2(image
, info
.size
- 10, 100, test_data
,
2132 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2134 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2135 ASSERT_EQ(0, rbd_aio_read2(image
, info
.size
, 1, test_data
, comp
,
2136 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2137 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2138 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2139 rbd_aio_release(comp
);
2141 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2142 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2143 &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2144 ASSERT_EQ(0U, mismatch_offset
);
2145 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2146 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2147 comp
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2148 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2149 ASSERT_EQ(0U, mismatch_offset
);
2150 rbd_aio_release(comp
);
2152 ASSERT_PASSED(validate_object_map
, image
);
2153 ASSERT_EQ(0, rbd_close(image
));
2155 rados_ioctx_destroy(ioctx
);
2158 TEST_F(TestLibRBD
, TestDataPoolIO
)
2160 REQUIRE_FORMAT_V2();
2162 rados_ioctx_t ioctx
;
2163 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2165 std::string data_pool_name
= create_pool(true);
2167 bool skip_discard
= is_skip_partial_discard_enabled();
2170 std::string name
= get_temp_image_name();
2171 uint64_t size
= 2 << 20;
2175 ASSERT_EQ(0, get_features(&old_format
, &features
));
2176 ASSERT_FALSE(old_format
);
2178 rbd_image_options_t image_options
;
2179 rbd_image_options_create(&image_options
);
2180 BOOST_SCOPE_EXIT( (&image_options
) ) {
2181 rbd_image_options_destroy(image_options
);
2182 } BOOST_SCOPE_EXIT_END
;
2184 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
2185 RBD_IMAGE_OPTION_FEATURES
,
2187 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
2188 RBD_IMAGE_OPTION_DATA_POOL
,
2189 data_pool_name
.c_str()));
2191 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
2192 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2193 ASSERT_NE(-1, rbd_get_data_pool_id(image
));
2195 char test_data
[TEST_IO_SIZE
+ 1];
2196 char zero_data
[TEST_IO_SIZE
+ 1];
2199 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2200 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2202 test_data
[TEST_IO_SIZE
] = '\0';
2203 memset(zero_data
, 0, sizeof(zero_data
));
2205 for (i
= 0; i
< 5; ++i
)
2206 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2208 for (i
= 5; i
< 10; ++i
)
2209 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2211 for (i
= 0; i
< 5; ++i
)
2212 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2214 for (i
= 5; i
< 10; ++i
)
2215 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2217 // discard 2nd, 4th sections.
2218 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2219 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2221 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
2222 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2223 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
2224 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
2225 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2226 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
2227 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2229 rbd_image_info_t info
;
2230 rbd_completion_t comp
;
2231 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2232 // can't read or write starting past end
2233 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2234 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2235 // reading through end returns amount up to end
2236 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
2237 // writing through end returns amount up to end
2238 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
2240 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2241 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
2242 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2243 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2244 rbd_aio_release(comp
);
2246 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2247 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
2248 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2249 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2250 rbd_aio_release(comp
);
2252 ASSERT_PASSED(validate_object_map
, image
);
2253 ASSERT_EQ(0, rbd_close(image
));
2255 rados_ioctx_destroy(ioctx
);
2258 TEST_F(TestLibRBD
, TestScatterGatherIO
)
2260 rados_ioctx_t ioctx
;
2261 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2265 std::string name
= get_temp_image_name();
2266 uint64_t size
= 20 << 20;
2268 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2269 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2271 std::string
write_buffer("This is a test");
2272 struct iovec bad_iovs
[] = {
2273 {.iov_base
= NULL
, .iov_len
= static_cast<size_t>(-1)}
2275 struct iovec write_iovs
[] = {
2276 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
2277 {.iov_base
= &write_buffer
[5], .iov_len
= 3},
2278 {.iov_base
= &write_buffer
[8], .iov_len
= 2},
2279 {.iov_base
= &write_buffer
[10], .iov_len
= 4}
2282 rbd_completion_t comp
;
2283 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2284 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, write_iovs
, 0, 0, comp
));
2285 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, bad_iovs
, 1, 0, comp
));
2286 ASSERT_EQ(0, rbd_aio_writev(image
, write_iovs
,
2287 sizeof(write_iovs
) / sizeof(struct iovec
),
2289 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2290 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
2291 rbd_aio_release(comp
);
2293 std::string
read_buffer(write_buffer
.size(), '1');
2294 struct iovec read_iovs
[] = {
2295 {.iov_base
= &read_buffer
[0], .iov_len
= 4},
2296 {.iov_base
= &read_buffer
[8], .iov_len
= 4},
2297 {.iov_base
= &read_buffer
[12], .iov_len
= 2}
2300 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2301 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, read_iovs
, 0, 0, comp
));
2302 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, bad_iovs
, 1, 0, comp
));
2303 ASSERT_EQ(0, rbd_aio_readv(image
, read_iovs
,
2304 sizeof(read_iovs
) / sizeof(struct iovec
),
2306 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2307 ASSERT_EQ(10, rbd_aio_get_return_value(comp
));
2308 rbd_aio_release(comp
);
2309 ASSERT_EQ("This1111 is a ", read_buffer
);
2311 std::string
linear_buffer(write_buffer
.size(), '1');
2312 struct iovec linear_iovs
[] = {
2313 {.iov_base
= &linear_buffer
[4], .iov_len
= 4}
2315 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2316 ASSERT_EQ(0, rbd_aio_readv(image
, linear_iovs
,
2317 sizeof(linear_iovs
) / sizeof(struct iovec
),
2319 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2320 ASSERT_EQ(4, rbd_aio_get_return_value(comp
));
2321 rbd_aio_release(comp
);
2322 ASSERT_EQ("1111This111111", linear_buffer
);
2324 ASSERT_PASSED(validate_object_map
, image
);
2325 ASSERT_EQ(0, rbd_close(image
));
2327 rados_ioctx_destroy(ioctx
);
2330 TEST_F(TestLibRBD
, TestEmptyDiscard
)
2332 rados_ioctx_t ioctx
;
2333 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2337 std::string name
= get_temp_image_name();
2338 uint64_t size
= 20 << 20;
2340 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2341 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2343 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 1*1024*1024);
2344 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 4*1024*1024);
2345 ASSERT_PASSED(aio_discard_test_data
, image
, 3*1024*1024, 1*1024*1024);
2347 ASSERT_PASSED(validate_object_map
, image
);
2348 ASSERT_EQ(0, rbd_close(image
));
2350 rados_ioctx_destroy(ioctx
);
2353 TEST_F(TestLibRBD
, TestFUA
)
2355 rados_ioctx_t ioctx
;
2356 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2358 rbd_image_t image_write
;
2359 rbd_image_t image_read
;
2361 std::string name
= get_temp_image_name();
2362 uint64_t size
= 2 << 20;
2364 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2365 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_write
, NULL
));
2366 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_read
, NULL
));
2368 // enable writeback cache
2369 rbd_flush(image_write
);
2371 char test_data
[TEST_IO_SIZE
+ 1];
2374 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2375 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2377 test_data
[TEST_IO_SIZE
] = '\0';
2378 for (i
= 0; i
< 5; ++i
)
2379 ASSERT_PASSED(write_test_data
, image_write
, test_data
,
2380 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2382 for (i
= 0; i
< 5; ++i
)
2383 ASSERT_PASSED(read_test_data
, image_read
, test_data
,
2384 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2386 for (i
= 5; i
< 10; ++i
)
2387 ASSERT_PASSED(aio_write_test_data
, image_write
, test_data
,
2388 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2390 for (i
= 5; i
< 10; ++i
)
2391 ASSERT_PASSED(aio_read_test_data
, image_read
, test_data
,
2392 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2394 ASSERT_PASSED(validate_object_map
, image_write
);
2395 ASSERT_PASSED(validate_object_map
, image_read
);
2396 ASSERT_EQ(0, rbd_close(image_write
));
2397 ASSERT_EQ(0, rbd_close(image_read
));
2398 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2399 rados_ioctx_destroy(ioctx
);
2402 void simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
2404 cout
<< "write completion cb called!" << std::endl
;
2407 void simple_read_cb_pp(librbd::completion_t cb
, void *arg
)
2409 cout
<< "read completion cb called!" << std::endl
;
2412 void aio_write_test_data(librbd::Image
& image
, const char *test_data
,
2413 off_t off
, uint32_t iohint
, bool *passed
)
2415 ceph::bufferlist bl
;
2416 bl
.append(test_data
, strlen(test_data
));
2417 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2418 printf("created completion\n");
2420 image
.aio_write2(off
, strlen(test_data
), bl
, comp
, iohint
);
2422 image
.aio_write(off
, strlen(test_data
), bl
, comp
);
2423 printf("started write\n");
2424 comp
->wait_for_complete();
2425 int r
= comp
->get_return_value();
2426 printf("return value is: %d\n", r
);
2428 printf("finished write\n");
2433 void aio_discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2435 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2436 image
.aio_discard(off
, len
, comp
);
2437 comp
->wait_for_complete();
2438 int r
= comp
->get_return_value();
2444 void write_test_data(librbd::Image
& image
, const char *test_data
, off_t off
, uint32_t iohint
, bool *passed
)
2447 size_t len
= strlen(test_data
);
2448 ceph::bufferlist bl
;
2449 bl
.append(test_data
, len
);
2451 written
= image
.write2(off
, len
, bl
, iohint
);
2453 written
= image
.write(off
, len
, bl
);
2454 printf("wrote: %u\n", (unsigned int) written
);
2455 ASSERT_EQ(bl
.length(), written
);
2459 void discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2462 written
= image
.discard(off
, len
);
2463 printf("discard: %u~%u\n", (unsigned)off
, (unsigned)len
);
2464 ASSERT_EQ(len
, written
);
2468 void aio_read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2470 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_read_cb_pp
);
2471 ceph::bufferlist bl
;
2472 printf("created completion\n");
2474 image
.aio_read2(off
, expected_len
, bl
, comp
, iohint
);
2476 image
.aio_read(off
, expected_len
, bl
, comp
);
2477 printf("started read\n");
2478 comp
->wait_for_complete();
2479 int r
= comp
->get_return_value();
2480 printf("return value is: %d\n", r
);
2481 ASSERT_EQ(TEST_IO_SIZE
, r
);
2482 ASSERT_EQ(0, memcmp(expected
, bl
.c_str(), TEST_IO_SIZE
));
2483 printf("finished read\n");
2488 void read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2491 size_t len
= expected_len
;
2492 ceph::bufferlist bl
;
2494 read
= image
.read2(off
, len
, bl
, iohint
);
2496 read
= image
.read(off
, len
, bl
);
2497 ASSERT_TRUE(read
>= 0);
2498 std::string
bl_str(bl
.c_str(), read
);
2500 printf("read: %u\n", (unsigned int) read
);
2501 int result
= memcmp(bl_str
.c_str(), expected
, expected_len
);
2503 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), expected
);
2504 ASSERT_EQ(0, result
);
2509 void aio_writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2510 size_t len
, size_t data_len
, uint32_t iohint
, bool *passed
)
2512 ceph::bufferlist bl
;
2513 bl
.append(test_data
, data_len
);
2514 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2515 printf("created completion\n");
2517 r
= image
.aio_writesame(off
, len
, bl
, comp
, iohint
);
2518 printf("started writesame\n");
2519 if (len
% data_len
) {
2520 ASSERT_EQ(-EINVAL
, r
);
2521 printf("expected fail, finished writesame\n");
2527 comp
->wait_for_complete();
2528 r
= comp
->get_return_value();
2529 printf("return value is: %d\n", r
);
2531 printf("finished writesame\n");
2535 printf("to verify the data\n");
2537 uint64_t left
= len
;
2539 ceph::bufferlist bl
;
2540 read
= image
.read(off
, data_len
, bl
);
2541 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2542 std::string
bl_str(bl
.c_str(), read
);
2543 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2545 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2546 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2547 ASSERT_EQ(0, result
);
2552 ASSERT_EQ(0U, left
);
2553 printf("verified\n");
2558 void writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2559 ssize_t len
, size_t data_len
, uint32_t iohint
,
2563 ceph::bufferlist bl
;
2564 bl
.append(test_data
, data_len
);
2565 written
= image
.writesame(off
, len
, bl
, iohint
);
2566 if (len
% data_len
) {
2567 ASSERT_EQ(-EINVAL
, written
);
2568 printf("expected fail, finished writesame\n");
2572 ASSERT_EQ(len
, written
);
2573 printf("wrote: %u\n", (unsigned int) written
);
2577 printf("to verify the data\n");
2579 uint64_t left
= len
;
2581 ceph::bufferlist bl
;
2582 read
= image
.read(off
, data_len
, bl
);
2583 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2584 std::string
bl_str(bl
.c_str(), read
);
2585 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2587 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2588 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2589 ASSERT_EQ(0, result
);
2594 ASSERT_EQ(0U, left
);
2595 printf("verified\n");
2600 void aio_compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
,
2601 const char *test_data
, off_t off
, ssize_t len
,
2602 uint32_t iohint
, bool *passed
)
2604 ceph::bufferlist cmp_bl
;
2605 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2606 ceph::bufferlist test_bl
;
2607 test_bl
.append(test_data
, strlen(test_data
));
2608 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2609 printf("created completion\n");
2611 uint64_t mismatch_offset
;
2612 image
.aio_compare_and_write(off
, len
, cmp_bl
, test_bl
, comp
, &mismatch_offset
, iohint
);
2613 printf("started aio compare and write\n");
2614 comp
->wait_for_complete();
2615 int r
= comp
->get_return_value();
2616 printf("return value is: %d\n", r
);
2618 printf("finished aio compare and write\n");
2623 void compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
, const char *test_data
,
2624 off_t off
, ssize_t len
, uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
2627 ceph::bufferlist cmp_bl
;
2628 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2629 ceph::bufferlist test_bl
;
2630 test_bl
.append(test_data
, strlen(test_data
));
2631 printf("start compare and write\n");
2632 written
= image
.compare_and_write(off
, len
, cmp_bl
, test_bl
, mismatch_off
, iohint
);
2633 printf("compare and wrote: %d\n", (int) written
);
2634 ASSERT_EQ(len
, static_cast<ssize_t
>(written
));
2638 TEST_F(TestLibRBD
, TestIOPP
)
2640 librados::IoCtx ioctx
;
2641 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2643 bool skip_discard
= is_skip_partial_discard_enabled();
2647 librbd::Image image
;
2649 std::string name
= get_temp_image_name();
2650 uint64_t size
= 2 << 20;
2652 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2653 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2655 char test_data
[TEST_IO_SIZE
+ 1];
2656 char zero_data
[TEST_IO_SIZE
+ 1];
2658 uint64_t mismatch_offset
;
2660 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2661 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2663 test_data
[TEST_IO_SIZE
] = '\0';
2664 memset(zero_data
, 0, sizeof(zero_data
));
2666 for (i
= 0; i
< 5; ++i
)
2667 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2669 for (i
= 5; i
< 10; ++i
)
2670 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2672 for (i
= 0; i
< 5; ++i
)
2673 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
2674 TEST_IO_SIZE
, &mismatch_offset
, 0);
2676 for (i
= 5; i
< 10; ++i
)
2677 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
2680 for (i
= 0; i
< 5; ++i
)
2681 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
2683 for (i
= 5; i
< 10; ++i
)
2684 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
2686 // discard 2nd, 4th sections.
2687 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2688 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2690 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
2691 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2692 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
2693 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
2694 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2695 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
2696 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2698 for (i
= 0; i
< 15; ++i
) {
2700 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2701 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2702 } else if (i
% 3 == 1) {
2703 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2704 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2706 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2707 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2710 for (i
= 0; i
< 15; ++i
) {
2712 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2713 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
2714 } else if (i
% 3 == 1) {
2715 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2716 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2718 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2719 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
2723 ASSERT_PASSED(validate_object_map
, image
);
2729 TEST_F(TestLibRBD
, TestIOPPWithIOHint
)
2731 librados::IoCtx ioctx
;
2732 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2736 librbd::Image image
;
2738 std::string name
= get_temp_image_name();
2739 uint64_t size
= 2 << 20;
2741 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2742 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2744 char test_data
[TEST_IO_SIZE
+ 1];
2745 char zero_data
[TEST_IO_SIZE
+ 1];
2746 test_data
[TEST_IO_SIZE
] = '\0';
2749 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2750 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2752 memset(zero_data
, 0, sizeof(zero_data
));
2754 for (i
= 0; i
< 5; ++i
)
2755 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
,
2756 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2758 for (i
= 5; i
< 10; ++i
)
2759 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
,
2760 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2762 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
),
2763 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_RANDOM
);
2765 for (i
= 5; i
< 10; ++i
)
2766 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
,
2767 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2769 for (i
= 0; i
< 15; ++i
) {
2771 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2772 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2773 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2774 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2775 } else if (i
% 3 == 1) {
2776 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
2777 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2778 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
2779 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2781 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2782 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2783 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2784 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2787 for (i
= 0; i
< 15; ++i
) {
2789 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2790 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2791 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2792 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2793 } else if (i
% 3 == 1) {
2794 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
2795 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2796 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
2797 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2799 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2800 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2801 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
2802 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2806 ASSERT_PASSED(validate_object_map
, image
);
2814 TEST_F(TestLibRBD
, TestIOToSnapshot
)
2816 rados_ioctx_t ioctx
;
2817 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2821 std::string name
= get_temp_image_name();
2822 uint64_t isize
= 2 << 20;
2824 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
2825 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2828 rbd_image_t image_at_snap
;
2829 char orig_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
2830 char test_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
2832 for (i
= 0; i
< TEST_IO_TO_SNAP_SIZE
; ++i
)
2833 test_data
[i
] = (char) (i
+ 48);
2834 test_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
2835 orig_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
2837 r
= rbd_read(image
, 0, TEST_IO_TO_SNAP_SIZE
, orig_data
);
2838 ASSERT_EQ(r
, TEST_IO_TO_SNAP_SIZE
);
2840 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2841 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
2842 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
2843 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2845 printf("write test data!\n");
2846 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2847 ASSERT_EQ(0, rbd_snap_create(image
, "written"));
2848 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
2850 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2852 rbd_snap_set(image
, "orig");
2853 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2855 rbd_snap_set(image
, "written");
2856 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2858 rbd_snap_set(image
, "orig");
2860 r
= rbd_write(image
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
2861 printf("write to snapshot returned %d\n", r
);
2863 cout
<< strerror(-r
) << std::endl
;
2865 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2866 rbd_snap_set(image
, "written");
2867 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2869 r
= rbd_snap_rollback(image
, "orig");
2870 ASSERT_EQ(r
, -EROFS
);
2872 r
= rbd_snap_set(image
, NULL
);
2874 r
= rbd_snap_rollback(image
, "orig");
2877 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2881 printf("opening testimg@orig\n");
2882 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_at_snap
, "orig"));
2883 ASSERT_PASSED(read_test_data
, image_at_snap
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
2884 r
= rbd_write(image_at_snap
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
2885 printf("write to snapshot returned %d\n", r
);
2887 cout
<< strerror(-r
) << std::endl
;
2888 ASSERT_EQ(0, rbd_close(image_at_snap
));
2890 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
2891 ASSERT_EQ(0, rbd_snap_remove(image
, "written"));
2892 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
2893 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
2894 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2896 ASSERT_PASSED(validate_object_map
, image
);
2897 ASSERT_EQ(0, rbd_close(image
));
2899 rados_ioctx_destroy(ioctx
);
2902 TEST_F(TestLibRBD
, TestClone
)
2904 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2905 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "1"));
2906 BOOST_SCOPE_EXIT_ALL(&) {
2907 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
2910 rados_ioctx_t ioctx
;
2911 rbd_image_info_t pinfo
, cinfo
;
2912 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2916 rbd_image_t parent
, child
;
2919 ASSERT_EQ(0, get_features(&old_format
, &features
));
2920 ASSERT_FALSE(old_format
);
2922 std::string parent_name
= get_temp_image_name();
2923 std::string child_name
= get_temp_image_name();
2925 // make a parent to clone from
2926 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
2928 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
2929 printf("made parent image \"parent\"\n");
2931 char *data
= (char *)"testdata";
2932 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
2934 // can't clone a non-snapshot, expect failure
2935 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
2936 child_name
.c_str(), features
, &order
));
2938 // verify that there is no parent info on "parent"
2939 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
2940 printf("parent has no parent info\n");
2942 // create 70 metadatas to verify we can clone all key/value pairs
2945 size_t sum_key_len
= 0;
2946 size_t sum_value_len
= 0;
2947 for (int i
= 1; i
<= 70; i
++) {
2948 key
= "key" + stringify(i
);
2949 val
= "value" + stringify(i
);
2950 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
2952 sum_key_len
+= (key
.size() + 1);
2953 sum_value_len
+= (val
.size() + 1);
2958 size_t keys_len
= sizeof(keys
);
2959 size_t vals_len
= sizeof(vals
);
2962 size_t value_len
= sizeof(value
);
2964 // create a snapshot, reopen as the parent we're interested in
2965 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
2966 printf("made snapshot \"parent@parent_snap\"\n");
2967 ASSERT_EQ(0, rbd_close(parent
));
2968 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
2970 ASSERT_EQ(-EINVAL
, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
2971 ioctx
, child_name
.c_str(), features
, &order
));
2973 // unprotected image should fail unprotect
2974 ASSERT_EQ(-EINVAL
, rbd_snap_unprotect(parent
, "parent_snap"));
2975 printf("can't unprotect an unprotected snap\n");
2977 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
2978 // protecting again should fail
2979 ASSERT_EQ(-EBUSY
, rbd_snap_protect(parent
, "parent_snap"));
2980 printf("can't protect a protected snap\n");
2982 // This clone and open should work
2983 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
2984 ioctx
, child_name
.c_str(), features
, &order
));
2985 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
2986 printf("made and opened clone \"child\"\n");
2989 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
2992 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(child
, 20, strlen(data
), data
));
2993 ASSERT_PASSED(read_test_data
, child
, data
, 20, strlen(data
), 0);
2994 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
2997 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
2998 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
2999 EXPECT_EQ(cinfo
.size
, pinfo
.size
);
3001 rbd_get_overlap(child
, &overlap
);
3002 EXPECT_EQ(overlap
, pinfo
.size
);
3003 EXPECT_EQ(cinfo
.obj_size
, pinfo
.obj_size
);
3004 EXPECT_EQ(cinfo
.order
, pinfo
.order
);
3005 printf("sizes and overlaps are good between parent and child\n");
3007 // check key/value pairs in child image
3008 ASSERT_EQ(0, rbd_metadata_list(child
, "", 70, keys
, &keys_len
, vals
,
3010 ASSERT_EQ(sum_key_len
, keys_len
);
3011 ASSERT_EQ(sum_value_len
, vals_len
);
3013 for (int i
= 1; i
<= 70; i
++) {
3014 key
= "key" + stringify(i
);
3015 val
= "value" + stringify(i
);
3016 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3017 ASSERT_STREQ(val
.c_str(), value
);
3019 value_len
= sizeof(value
);
3021 printf("child image successfully cloned all image-meta pairs\n");
3023 // sizing down child results in changing overlap and size, not parent size
3024 ASSERT_EQ(0, rbd_resize(child
, 2UL<<20));
3025 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3026 rbd_get_overlap(child
, &overlap
);
3027 ASSERT_EQ(overlap
, 2UL<<20);
3028 ASSERT_EQ(cinfo
.size
, 2UL<<20);
3029 ASSERT_EQ(0, rbd_resize(child
, 4UL<<20));
3030 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3031 rbd_get_overlap(child
, &overlap
);
3032 ASSERT_EQ(overlap
, 2UL<<20);
3033 ASSERT_EQ(cinfo
.size
, 4UL<<20);
3034 printf("sized down clone, changed overlap\n");
3036 // sizing back up doesn't change that
3037 ASSERT_EQ(0, rbd_resize(child
, 5UL<<20));
3038 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3039 rbd_get_overlap(child
, &overlap
);
3040 ASSERT_EQ(overlap
, 2UL<<20);
3041 ASSERT_EQ(cinfo
.size
, 5UL<<20);
3042 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
3043 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
3044 (unsigned long long)pinfo
.size
, (unsigned long long)pinfo
.obj_size
,
3045 (unsigned long long)pinfo
.parent_pool
);
3046 ASSERT_EQ(pinfo
.size
, 4UL<<20);
3047 printf("sized up clone, changed size but not overlap or parent's size\n");
3049 ASSERT_PASSED(validate_object_map
, child
);
3050 ASSERT_EQ(0, rbd_close(child
));
3052 ASSERT_PASSED(validate_object_map
, parent
);
3053 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3054 printf("can't remove parent while child still exists\n");
3055 ASSERT_EQ(0, rbd_remove(ioctx
, child_name
.c_str()));
3056 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3057 printf("can't remove parent while still protected\n");
3058 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3059 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3060 printf("removed parent snap after unprotecting\n");
3062 ASSERT_EQ(0, rbd_close(parent
));
3063 rados_ioctx_destroy(ioctx
);
3066 TEST_F(TestLibRBD
, TestClone2
)
3068 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3069 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
3070 BOOST_SCOPE_EXIT_ALL(&) {
3071 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
3074 rados_ioctx_t ioctx
;
3075 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3079 rbd_image_t parent
, child
;
3082 ASSERT_EQ(0, get_features(&old_format
, &features
));
3083 ASSERT_FALSE(old_format
);
3085 std::string parent_name
= get_temp_image_name();
3086 std::string child_name
= get_temp_image_name();
3088 // make a parent to clone from
3089 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
3091 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
3092 printf("made parent image \"parent\"\n");
3094 char *data
= (char *)"testdata";
3095 char *childata
= (char *)"childata";
3096 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
3097 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
3099 // can't clone a non-snapshot, expect failure
3100 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
3101 child_name
.c_str(), features
, &order
));
3103 // verify that there is no parent info on "parent"
3104 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
3105 printf("parent has no parent info\n");
3107 // create 70 metadatas to verify we can clone all key/value pairs
3110 size_t sum_key_len
= 0;
3111 size_t sum_value_len
= 0;
3112 for (int i
= 1; i
<= 70; i
++) {
3113 key
= "key" + stringify(i
);
3114 val
= "value" + stringify(i
);
3115 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
3117 sum_key_len
+= (key
.size() + 1);
3118 sum_value_len
+= (val
.size() + 1);
3123 size_t keys_len
= sizeof(keys
);
3124 size_t vals_len
= sizeof(vals
);
3127 size_t value_len
= sizeof(value
);
3129 // create a snapshot, reopen as the parent we're interested in
3130 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3131 printf("made snapshot \"parent@parent_snap\"\n");
3132 ASSERT_EQ(0, rbd_close(parent
));
3133 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
3135 // This clone and open should work
3136 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3137 ioctx
, child_name
.c_str(), features
, &order
));
3138 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
3139 printf("made and opened clone \"child\"\n");
3141 // check key/value pairs in child image
3142 ASSERT_EQ(0, rbd_metadata_list(child
, "", 70, keys
, &keys_len
, vals
,
3144 ASSERT_EQ(sum_key_len
, keys_len
);
3145 ASSERT_EQ(sum_value_len
, vals_len
);
3147 for (int i
= 1; i
<= 70; i
++) {
3148 key
= "key" + stringify(i
);
3149 val
= "value" + stringify(i
);
3150 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3151 ASSERT_STREQ(val
.c_str(), value
);
3153 value_len
= sizeof(value
);
3155 printf("child image successfully cloned all image-meta pairs\n");
3157 // write something in
3158 ASSERT_EQ((ssize_t
)strlen(childata
), rbd_write(child
, 20, strlen(childata
), childata
));
3160 char test
[strlen(data
) * 2];
3161 ASSERT_EQ((ssize_t
)strlen(data
), rbd_read(child
, 20, strlen(data
), test
));
3162 ASSERT_EQ(0, memcmp(test
, childata
, strlen(childata
)));
3165 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 20 - strlen(data
), sizeof(test
), test
));
3166 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3167 ASSERT_EQ(0, memcmp(test
+ strlen(data
), childata
, strlen(childata
)));
3170 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 0, sizeof(test
), test
));
3171 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3173 ASSERT_PASSED(validate_object_map
, child
);
3174 ASSERT_PASSED(validate_object_map
, parent
);
3176 rbd_snap_info_t snaps
[2];
3178 ASSERT_EQ(1, rbd_snap_list(parent
, snaps
, &max_snaps
));
3179 rbd_snap_list_end(snaps
);
3181 ASSERT_EQ(0, rbd_snap_remove_by_id(parent
, snaps
[0].id
));
3183 rbd_snap_namespace_type_t snap_namespace_type
;
3184 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent
, snaps
[0].id
,
3185 &snap_namespace_type
));
3186 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH
, snap_namespace_type
);
3188 char original_name
[32];
3189 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent
, snaps
[0].id
,
3191 sizeof(original_name
)));
3192 ASSERT_EQ(0, strcmp("parent_snap", original_name
));
3194 ASSERT_EQ(0, rbd_close(child
));
3195 ASSERT_EQ(0, rbd_close(parent
));
3196 rados_ioctx_destroy(ioctx
);
3199 static void test_list_children(rbd_image_t image
, ssize_t num_expected
, ...)
3202 va_start(ap
, num_expected
);
3203 size_t pools_len
= 100;
3204 size_t children_len
= 100;
3206 char *children
= NULL
;
3207 ssize_t num_children
;
3212 pools
= (char *) malloc(pools_len
);
3213 children
= (char *) malloc(children_len
);
3214 num_children
= rbd_list_children(image
, pools
, &pools_len
,
3215 children
, &children_len
);
3216 } while (num_children
== -ERANGE
);
3218 ASSERT_EQ(num_expected
, num_children
);
3219 for (ssize_t i
= num_expected
; i
> 0; --i
) {
3220 char *expected_pool
= va_arg(ap
, char *);
3221 char *expected_image
= va_arg(ap
, char *);
3223 char *image
= children
;
3225 printf("\ntrying to find %s/%s\n", expected_pool
, expected_image
);
3226 for (ssize_t j
= 0; j
< num_children
; ++j
) {
3227 printf("checking %s/%s\n", pool
, image
);
3228 if (strcmp(expected_pool
, pool
) == 0 &&
3229 strcmp(expected_image
, image
) == 0) {
3230 printf("found child %s/%s\n\n", pool
, image
);
3234 pool
+= strlen(pool
) + 1;
3235 image
+= strlen(image
) + 1;
3236 if (j
== num_children
- 1) {
3237 ASSERT_EQ(pool
- pools
- 1, (ssize_t
) pools_len
);
3238 ASSERT_EQ(image
- children
- 1, (ssize_t
) children_len
);
3251 static void test_list_children2(rbd_image_t image
, int num_expected
, ...)
3253 int num_children
, i
, j
, max_size
= 10;
3255 rbd_child_info_t children
[max_size
];
3256 num_children
= rbd_list_children2(image
, children
, &max_size
);
3257 printf("num children is: %d\nexpected: %d\n", num_children
, num_expected
);
3259 for (i
= 0; i
< num_children
; i
++) {
3260 printf("child: %s\n", children
[i
].image_name
);
3263 va_start(ap
, num_expected
);
3264 for (i
= num_expected
; i
> 0; i
--) {
3265 char *expected_id
= va_arg(ap
, char *);
3266 char *expected_pool
= va_arg(ap
, char *);
3267 char *expected_image
= va_arg(ap
, char *);
3268 bool expected_trash
= va_arg(ap
, int);
3270 for (j
= 0; j
< num_children
; j
++) {
3271 if (children
[j
].pool_name
== NULL
||
3272 children
[j
].image_name
== NULL
||
3273 children
[j
].image_id
== NULL
)
3275 if (strcmp(children
[j
].image_id
, expected_id
) == 0 &&
3276 strcmp(children
[j
].pool_name
, expected_pool
) == 0 &&
3277 strcmp(children
[j
].image_name
, expected_image
) == 0 &&
3278 children
[j
].trash
== expected_trash
) {
3279 printf("found child %s/%s/%s\n\n", children
[j
].pool_name
, children
[j
].image_name
, children
[j
].image_id
);
3280 rbd_list_child_cleanup(&children
[j
]);
3281 children
[j
].pool_name
= NULL
;
3282 children
[j
].image_name
= NULL
;
3283 children
[j
].image_id
= NULL
;
3292 for (i
= 0; i
< num_children
; i
++) {
3293 EXPECT_EQ((const char *)0, children
[i
].pool_name
);
3294 EXPECT_EQ((const char *)0, children
[i
].image_name
);
3295 EXPECT_EQ((const char *)0, children
[i
].image_id
);
3299 TEST_F(TestLibRBD
, ListChildren
)
3301 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3304 rados_ioctx_t ioctx1
, ioctx2
;
3305 string pool_name1
= create_pool(true);
3306 string pool_name2
= create_pool(true);
3307 ASSERT_NE("", pool_name2
);
3309 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3310 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3322 ASSERT_EQ(0, get_features(&old_format
, &features
));
3323 ASSERT_FALSE(old_format
);
3325 std::string parent_name
= get_temp_image_name();
3326 std::string child_name1
= get_temp_image_name();
3327 std::string child_name2
= get_temp_image_name();
3328 std::string child_name3
= get_temp_image_name();
3329 std::string child_name4
= get_temp_image_name();
3331 char child_id1
[4096];
3332 char child_id2
[4096];
3333 char child_id3
[4096];
3334 char child_id4
[4096];
3336 // make a parent to clone from
3337 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3339 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3340 // create a snapshot, reopen as the parent we're interested in
3341 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3342 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3343 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3345 ASSERT_EQ(0, rbd_close(parent
));
3346 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3348 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3349 ioctx2
, child_name1
.c_str(), features
, &order
));
3350 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3351 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3352 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3353 test_list_children2(parent
, 1,
3354 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3356 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3357 ioctx1
, child_name2
.c_str(), features
, &order
));
3358 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3359 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3360 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3361 pool_name1
.c_str(), child_name2
.c_str());
3362 test_list_children2(parent
, 2,
3363 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3364 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3366 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3367 ioctx2
, child_name3
.c_str(), features
, &order
));
3368 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3369 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3370 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3371 pool_name1
.c_str(), child_name2
.c_str(),
3372 pool_name2
.c_str(), child_name3
.c_str());
3373 test_list_children2(parent
, 3,
3374 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3375 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3376 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3378 librados::IoCtx ioctx3
;
3379 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3380 ASSERT_EQ(0, rbd_close(image3
));
3381 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3382 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3383 pool_name1
.c_str(), child_name2
.c_str());
3384 test_list_children2(parent
, 3,
3385 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3386 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3387 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3389 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3390 ioctx2
, child_name4
.c_str(), features
, &order
));
3391 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3392 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3393 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3394 pool_name1
.c_str(), child_name2
.c_str(),
3395 pool_name2
.c_str(), child_name4
.c_str());
3396 test_list_children2(parent
, 4,
3397 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3398 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3399 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3400 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3402 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3403 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3404 pool_name1
.c_str(), child_name2
.c_str(),
3405 pool_name2
.c_str(), child_name3
.c_str(),
3406 pool_name2
.c_str(), child_name4
.c_str());
3407 test_list_children2(parent
, 4,
3408 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3409 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3410 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3411 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3413 ASSERT_EQ(0, rbd_close(image1
));
3414 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3415 test_list_children(parent
, 3,
3416 pool_name1
.c_str(), child_name2
.c_str(),
3417 pool_name2
.c_str(), child_name3
.c_str(),
3418 pool_name2
.c_str(), child_name4
.c_str());
3419 test_list_children2(parent
, 3,
3420 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3421 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3422 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3424 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3425 test_list_children(parent
, 2,
3426 pool_name1
.c_str(), child_name2
.c_str(),
3427 pool_name2
.c_str(), child_name4
.c_str());
3428 test_list_children2(parent
, 2,
3429 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3430 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3432 ASSERT_EQ(0, rbd_close(image4
));
3433 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3434 test_list_children(parent
, 1,
3435 pool_name1
.c_str(), child_name2
.c_str());
3436 test_list_children2(parent
, 1,
3437 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3440 ASSERT_EQ(0, rbd_close(image2
));
3441 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3442 test_list_children(parent
, 0);
3443 test_list_children2(parent
, 0);
3445 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3446 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3447 ASSERT_EQ(0, rbd_close(parent
));
3448 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3449 rados_ioctx_destroy(ioctx1
);
3450 rados_ioctx_destroy(ioctx2
);
3453 TEST_F(TestLibRBD
, ListChildrenTiered
)
3455 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3458 string pool_name1
= create_pool(true);
3459 string pool_name2
= create_pool(true);
3460 string pool_name3
= create_pool(true);
3461 ASSERT_NE("", pool_name1
);
3462 ASSERT_NE("", pool_name2
);
3463 ASSERT_NE("", pool_name3
);
3465 std::string cmdstr
= "{\"prefix\": \"osd tier add\", \"pool\": \"" +
3466 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\", \"force_nonempty\":\"\"}";
3468 cmd
[0] = (char *)cmdstr
.c_str();
3469 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3471 cmdstr
= "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
3472 pool_name3
+ "\", \"mode\":\"writeback\"}";
3473 cmd
[0] = (char *)cmdstr
.c_str();
3474 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3476 cmdstr
= "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
3477 pool_name1
+ "\", \"overlaypool\":\"" + pool_name3
+ "\"}";
3478 cmd
[0] = (char *)cmdstr
.c_str();
3479 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3481 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
3483 string parent_name
= get_temp_image_name();
3484 string child_name1
= get_temp_image_name();
3485 string child_name2
= get_temp_image_name();
3486 string child_name3
= get_temp_image_name();
3487 string child_name4
= get_temp_image_name();
3489 char child_id1
[4096];
3490 char child_id2
[4096];
3491 char child_id3
[4096];
3492 char child_id4
[4096];
3499 rados_ioctx_t ioctx1
, ioctx2
;
3500 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3501 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3508 ASSERT_EQ(0, get_features(&old_format
, &features
));
3509 ASSERT_FALSE(old_format
);
3511 // make a parent to clone from
3512 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3514 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3515 // create a snapshot, reopen as the parent we're interested in
3516 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3517 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3518 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3520 ASSERT_EQ(0, rbd_close(parent
));
3521 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3523 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3524 ioctx2
, child_name1
.c_str(), features
, &order
));
3525 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3526 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3527 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3528 test_list_children2(parent
, 1,
3529 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3531 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3532 ioctx1
, child_name2
.c_str(), features
, &order
));
3533 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3534 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3535 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3536 pool_name1
.c_str(), child_name2
.c_str());
3537 test_list_children2(parent
, 2,
3538 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3539 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3541 // read from the cache to populate it
3542 rbd_image_t tier_image
;
3543 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &tier_image
, NULL
));
3544 size_t len
= 4 * 1024 * 1024;
3545 char* buf
= (char*)malloc(len
);
3546 ssize_t size
= rbd_read(tier_image
, 0, len
, buf
);
3549 ASSERT_EQ(0, rbd_close(tier_image
));
3551 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3552 ioctx2
, child_name3
.c_str(), features
, &order
));
3553 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3554 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3555 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3556 pool_name1
.c_str(), child_name2
.c_str(),
3557 pool_name2
.c_str(), child_name3
.c_str());
3558 test_list_children2(parent
, 3,
3559 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3560 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3561 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3563 librados::IoCtx ioctx3
;
3564 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3565 ASSERT_EQ(0, rbd_close(image3
));
3566 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3567 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3568 pool_name1
.c_str(), child_name2
.c_str());
3569 test_list_children2(parent
, 3,
3570 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3571 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3572 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3574 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3575 ioctx2
, child_name4
.c_str(), features
, &order
));
3576 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3577 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3578 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3579 pool_name1
.c_str(), child_name2
.c_str(),
3580 pool_name2
.c_str(), child_name4
.c_str());
3581 test_list_children2(parent
, 4,
3582 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3583 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3584 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3585 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3587 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3588 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3589 pool_name1
.c_str(), child_name2
.c_str(),
3590 pool_name2
.c_str(), child_name3
.c_str(),
3591 pool_name2
.c_str(), child_name4
.c_str());
3592 test_list_children2(parent
, 4,
3593 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3594 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3595 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3596 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3598 ASSERT_EQ(0, rbd_close(image1
));
3599 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3600 test_list_children(parent
, 3,
3601 pool_name1
.c_str(), child_name2
.c_str(),
3602 pool_name2
.c_str(), child_name3
.c_str(),
3603 pool_name2
.c_str(), child_name4
.c_str());
3604 test_list_children2(parent
, 3,
3605 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3606 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3607 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3609 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3610 test_list_children(parent
, 2,
3611 pool_name1
.c_str(), child_name2
.c_str(),
3612 pool_name2
.c_str(), child_name4
.c_str());
3613 test_list_children2(parent
, 2,
3614 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3615 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3617 ASSERT_EQ(0, rbd_close(image4
));
3618 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3619 test_list_children(parent
, 1,
3620 pool_name1
.c_str(), child_name2
.c_str());
3621 test_list_children2(parent
, 1,
3622 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3624 ASSERT_EQ(0, rbd_close(image2
));
3625 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3626 test_list_children(parent
, 0);
3627 test_list_children2(parent
, 0);
3629 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3630 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3631 ASSERT_EQ(0, rbd_close(parent
));
3632 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3633 rados_ioctx_destroy(ioctx1
);
3634 rados_ioctx_destroy(ioctx2
);
3635 cmdstr
= "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
3637 cmd
[0] = (char *)cmdstr
.c_str();
3638 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3639 cmdstr
= "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
3640 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\"}";
3641 cmd
[0] = (char *)cmdstr
.c_str();
3642 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3645 TEST_F(TestLibRBD
, LockingPP
)
3647 librados::IoCtx ioctx
;
3648 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3652 librbd::Image image
;
3654 std::string name
= get_temp_image_name();
3655 uint64_t size
= 2 << 20;
3656 std::string cookie1
= "foo";
3657 std::string cookie2
= "bar";
3659 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3660 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3662 // no lockers initially
3663 std::list
<librbd::locker_t
> lockers
;
3666 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3667 ASSERT_EQ(0u, lockers
.size());
3670 // exclusive lock is exclusive
3671 ASSERT_EQ(0, image
.lock_exclusive(cookie1
));
3672 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
3673 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
3674 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
3675 ASSERT_EQ(-EBUSY
, image
.lock_shared(cookie1
, "test"));
3676 ASSERT_EQ(-EBUSY
, image
.lock_shared("", "test"));
3677 ASSERT_EQ(-EBUSY
, image
.lock_shared("", ""));
3680 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3681 ASSERT_TRUE(exclusive
);
3683 ASSERT_EQ(1u, lockers
.size());
3684 ASSERT_EQ(cookie1
, lockers
.front().cookie
);
3687 ASSERT_EQ(-ENOENT
, image
.unlock(""));
3688 ASSERT_EQ(-ENOENT
, image
.unlock(cookie2
));
3689 ASSERT_EQ(0, image
.unlock(cookie1
));
3690 ASSERT_EQ(-ENOENT
, image
.unlock(cookie1
));
3691 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3692 ASSERT_EQ(0u, lockers
.size());
3694 ASSERT_EQ(0, image
.lock_shared(cookie1
, ""));
3695 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
3696 ASSERT_EQ(0, image
.lock_shared(cookie2
, ""));
3697 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie2
, ""));
3698 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
3699 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie2
));
3700 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
3701 ASSERT_EQ(-EBUSY
, image
.lock_exclusive("test"));
3704 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
3705 ASSERT_EQ(2u, lockers
.size());
3711 TEST_F(TestLibRBD
, FlushAio
)
3713 rados_ioctx_t ioctx
;
3714 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3718 std::string name
= get_temp_image_name();
3719 uint64_t size
= 2 << 20;
3720 size_t num_aios
= 256;
3722 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3723 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3725 char test_data
[TEST_IO_SIZE
+ 1];
3727 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3728 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3731 rbd_completion_t write_comps
[num_aios
];
3732 for (i
= 0; i
< num_aios
; ++i
) {
3733 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &write_comps
[i
]));
3734 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
3735 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
3739 rbd_completion_t flush_comp
;
3740 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &flush_comp
));
3741 ASSERT_EQ(0, rbd_aio_flush(image
, flush_comp
));
3742 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp
));
3743 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp
));
3744 rbd_aio_release(flush_comp
);
3746 for (i
= 0; i
< num_aios
; ++i
) {
3747 ASSERT_EQ(1, rbd_aio_is_complete(write_comps
[i
]));
3748 rbd_aio_release(write_comps
[i
]);
3751 ASSERT_PASSED(validate_object_map
, image
);
3752 ASSERT_EQ(0, rbd_close(image
));
3753 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
3754 rados_ioctx_destroy(ioctx
);
3757 TEST_F(TestLibRBD
, FlushAioPP
)
3759 librados::IoCtx ioctx
;
3760 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3764 librbd::Image image
;
3766 std::string name
= get_temp_image_name();
3767 uint64_t size
= 2 << 20;
3768 const size_t num_aios
= 256;
3770 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3771 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3773 char test_data
[TEST_IO_SIZE
+ 1];
3775 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3776 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3778 test_data
[TEST_IO_SIZE
] = '\0';
3780 librbd::RBD::AioCompletion
*write_comps
[num_aios
];
3781 ceph::bufferlist bls
[num_aios
];
3782 for (i
= 0; i
< num_aios
; ++i
) {
3783 bls
[i
].append(test_data
, strlen(test_data
));
3784 write_comps
[i
] = new librbd::RBD::AioCompletion(NULL
, NULL
);
3785 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
3786 ASSERT_EQ(0, image
.aio_write(offset
, TEST_IO_SIZE
, bls
[i
],
3790 librbd::RBD::AioCompletion
*flush_comp
=
3791 new librbd::RBD::AioCompletion(NULL
, NULL
);
3792 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
3793 ASSERT_EQ(0, flush_comp
->wait_for_complete());
3794 ASSERT_EQ(1, flush_comp
->is_complete());
3795 flush_comp
->release();
3797 for (i
= 0; i
< num_aios
; ++i
) {
3798 librbd::RBD::AioCompletion
*comp
= write_comps
[i
];
3799 ASSERT_EQ(1, comp
->is_complete());
3802 ASSERT_PASSED(validate_object_map
, image
);
3809 int iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3811 //cout << "iterate_cb " << off << "~" << len << std::endl;
3812 interval_set
<uint64_t> *diff
= static_cast<interval_set
<uint64_t> *>(arg
);
3813 diff
->insert(off
, len
);
3817 static int iterate_error_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3822 void scribble(librbd::Image
& image
, int n
, int max
, bool skip_discard
,
3823 interval_set
<uint64_t> *exists
,
3824 interval_set
<uint64_t> *what
)
3828 interval_set
<uint64_t> exists_at_start
= *exists
;
3830 for (int i
=0; i
<n
; i
++) {
3831 uint64_t off
= rand() % (size
- max
+ 1);
3832 uint64_t len
= 1 + rand() % max
;
3833 if (!skip_discard
&& rand() % 4 == 0) {
3834 ASSERT_EQ((int)len
, image
.discard(off
, len
));
3835 interval_set
<uint64_t> w
;
3838 // the zeroed bit no longer exists...
3839 w
.intersection_of(*exists
);
3840 exists
->subtract(w
);
3842 // the bits we discarded are no long written...
3843 interval_set
<uint64_t> w2
= w
;
3844 w2
.intersection_of(*what
);
3847 // except for the extents that existed at the start that we overwrote.
3848 interval_set
<uint64_t> w3
;
3849 w3
.insert(off
, len
);
3850 w3
.intersection_of(exists_at_start
);
3855 bl
.append(buffer::create(len
));
3857 ASSERT_EQ((int)len
, image
.write(off
, len
, bl
));
3858 interval_set
<uint64_t> w
;
3861 exists
->union_of(w
);
3866 interval_set
<uint64_t> round_diff_interval(const interval_set
<uint64_t>& diff
,
3867 uint64_t object_size
)
3869 if (object_size
== 0) {
3873 interval_set
<uint64_t> rounded_diff
;
3874 for (interval_set
<uint64_t>::const_iterator it
= diff
.begin();
3875 it
!= diff
.end(); ++it
) {
3876 uint64_t off
= it
.get_start();
3877 uint64_t len
= it
.get_len();
3878 off
-= off
% object_size
;
3879 len
+= (object_size
- (len
% object_size
));
3880 interval_set
<uint64_t> interval
;
3881 interval
.insert(off
, len
);
3882 rounded_diff
.union_of(interval
);
3884 return rounded_diff
;
3887 template <typename T
>
3888 class DiffIterateTest
: public TestLibRBD
{
3890 static const uint8_t whole_object
= T::whole_object
;
3893 template <bool _whole_object
>
3894 class DiffIterateParams
{
3896 static const uint8_t whole_object
= _whole_object
;
3899 typedef ::testing::Types
<DiffIterateParams
<false>,
3900 DiffIterateParams
<true> > DiffIterateTypes
;
3901 TYPED_TEST_CASE(DiffIterateTest
, DiffIterateTypes
);
3903 TYPED_TEST(DiffIterateTest
, DiffIterate
)
3905 librados::IoCtx ioctx
;
3906 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3908 bool skip_discard
= this->is_skip_partial_discard_enabled();
3912 librbd::Image image
;
3914 std::string name
= this->get_temp_image_name();
3915 uint64_t size
= 20 << 20;
3917 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3918 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3920 uint64_t object_size
= 0;
3921 if (this->whole_object
) {
3922 object_size
= 1 << order
;
3925 interval_set
<uint64_t> exists
;
3926 interval_set
<uint64_t> one
, two
;
3927 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
3928 cout
<< " wrote " << one
<< std::endl
;
3929 ASSERT_EQ(0, image
.snap_create("one"));
3930 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
3932 two
= round_diff_interval(two
, object_size
);
3933 cout
<< " wrote " << two
<< std::endl
;
3935 interval_set
<uint64_t> diff
;
3936 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
3937 iterate_cb
, (void *)&diff
));
3938 cout
<< " diff was " << diff
<< std::endl
;
3939 if (!two
.subset_of(diff
)) {
3940 interval_set
<uint64_t> i
;
3941 i
.intersection_of(two
, diff
);
3942 interval_set
<uint64_t> l
= two
;
3944 cout
<< " ... two - (two*diff) = " << l
<< std::endl
;
3946 ASSERT_TRUE(two
.subset_of(diff
));
3951 struct diff_extent
{
3952 diff_extent(uint64_t _offset
, uint64_t _length
, bool _exists
,
3953 uint64_t object_size
) :
3954 offset(_offset
), length(_length
), exists(_exists
)
3956 if (object_size
!= 0) {
3957 offset
-= offset
% object_size
;
3958 length
= object_size
;
3964 bool operator==(const diff_extent
& o
) const {
3965 return offset
== o
.offset
&& length
== o
.length
&& exists
== o
.exists
;
3969 ostream
& operator<<(ostream
& o
, const diff_extent
& e
) {
3970 return o
<< '(' << e
.offset
<< '~' << e
.length
<< ' ' << (e
.exists
? "true" : "false") << ')';
3973 int vector_iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
3975 cout
<< "iterate_cb " << off
<< "~" << len
<< std::endl
;
3976 vector
<diff_extent
> *diff
= static_cast<vector
<diff_extent
> *>(arg
);
3977 diff
->push_back(diff_extent(off
, len
, exists
, 0));
3981 TYPED_TEST(DiffIterateTest
, DiffIterateDiscard
)
3983 librados::IoCtx ioctx
;
3984 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
3987 librbd::Image image
;
3989 std::string name
= this->get_temp_image_name();
3990 uint64_t size
= 20 << 20;
3992 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3993 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3995 uint64_t object_size
= 0;
3996 if (this->whole_object
) {
3997 object_size
= 1 << order
;
3999 vector
<diff_extent
> extents
;
4000 ceph::bufferlist bl
;
4002 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4003 vector_iterate_cb
, (void *) &extents
));
4004 ASSERT_EQ(0u, extents
.size());
4007 memset(data
, 1, sizeof(data
));
4008 bl
.append(data
, 256);
4009 ASSERT_EQ(256, image
.write(0, 256, bl
));
4010 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4011 vector_iterate_cb
, (void *) &extents
));
4012 ASSERT_EQ(1u, extents
.size());
4013 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4016 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4019 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4020 vector_iterate_cb
, (void *) &extents
));
4021 ASSERT_EQ(0u, extents
.size());
4023 ASSERT_EQ(0, image
.snap_create("snap1"));
4024 ASSERT_EQ(256, image
.write(0, 256, bl
));
4025 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4026 vector_iterate_cb
, (void *) &extents
));
4027 ASSERT_EQ(1u, extents
.size());
4028 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4029 ASSERT_EQ(0, image
.snap_create("snap2"));
4031 ASSERT_EQ(obj_ofs
, image
.discard(0, obj_ofs
));
4034 ASSERT_EQ(0, image
.snap_set("snap2"));
4035 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4036 vector_iterate_cb
, (void *) &extents
));
4037 ASSERT_EQ(1u, extents
.size());
4038 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4040 ASSERT_EQ(0, image
.snap_set(NULL
));
4041 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4042 ASSERT_EQ(0, image
.snap_create("snap3"));
4043 ASSERT_EQ(0, image
.snap_set("snap3"));
4046 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4047 vector_iterate_cb
, (void *) &extents
));
4048 ASSERT_EQ(1u, extents
.size());
4049 ASSERT_EQ(diff_extent(0, 256, false, object_size
), extents
[0]);
4050 ASSERT_PASSED(this->validate_object_map
, image
);
4053 TYPED_TEST(DiffIterateTest
, DiffIterateStress
)
4055 librados::IoCtx ioctx
;
4056 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4058 bool skip_discard
= this->is_skip_partial_discard_enabled();
4061 librbd::Image image
;
4063 std::string name
= this->get_temp_image_name();
4064 uint64_t size
= 400 << 20;
4066 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4067 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4069 uint64_t object_size
= 0;
4070 if (this->whole_object
) {
4071 object_size
= 1 << order
;
4074 interval_set
<uint64_t> curexists
;
4075 vector
<interval_set
<uint64_t> > wrote
;
4076 vector
<interval_set
<uint64_t> > exists
;
4077 vector
<string
> snap
;
4079 for (int i
=0; i
<n
; i
++) {
4080 interval_set
<uint64_t> w
;
4081 scribble(image
, 10, 8192000, skip_discard
, &curexists
, &w
);
4082 cout
<< " i=" << i
<< " exists " << curexists
<< " wrote " << w
<< std::endl
;
4083 string s
= "snap" + stringify(i
);
4084 ASSERT_EQ(0, image
.snap_create(s
.c_str()));
4086 exists
.push_back(curexists
);
4090 for (int h
=0; h
<n
-1; h
++) {
4091 for (int i
=0; i
<n
-h
-1; i
++) {
4092 for (int j
=(h
==0 ? i
+1 : n
-1); j
<n
; j
++) {
4093 interval_set
<uint64_t> diff
, actual
, uex
;
4094 for (int k
=i
+1; k
<=j
; k
++)
4095 diff
.union_of(wrote
[k
]);
4096 cout
<< "from " << i
<< " to "
4097 << (h
!= 0 ? string("HEAD") : stringify(j
)) << " diff "
4098 << round_diff_interval(diff
, object_size
) << std::endl
;
4100 // limit to extents that exists both at the beginning and at the end
4101 uex
.union_of(exists
[i
], exists
[j
]);
4102 diff
.intersection_of(uex
);
4103 diff
= round_diff_interval(diff
, object_size
);
4104 cout
<< " limited diff " << diff
<< std::endl
;
4106 ASSERT_EQ(0, image
.snap_set(h
==0 ? snap
[j
].c_str() : NULL
));
4107 ASSERT_EQ(0, image
.diff_iterate2(snap
[i
].c_str(), 0, size
, true,
4108 this->whole_object
, iterate_cb
,
4110 cout
<< " actual was " << actual
<< std::endl
;
4111 if (!diff
.subset_of(actual
)) {
4112 interval_set
<uint64_t> i
;
4113 i
.intersection_of(diff
, actual
);
4114 interval_set
<uint64_t> l
= diff
;
4116 cout
<< " ... diff - (actual*diff) = " << l
<< std::endl
;
4118 ASSERT_TRUE(diff
.subset_of(actual
));
4121 ASSERT_EQ(0, image
.snap_set(NULL
));
4122 ASSERT_EQ(0, image
.snap_remove(snap
[n
-h
-1].c_str()));
4125 ASSERT_PASSED(this->validate_object_map
, image
);
4128 TYPED_TEST(DiffIterateTest
, DiffIterateRegression6926
)
4130 librados::IoCtx ioctx
;
4131 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4134 librbd::Image image
;
4136 std::string name
= this->get_temp_image_name();
4137 uint64_t size
= 20 << 20;
4139 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4140 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4142 uint64_t object_size
= 0;
4143 if (this->whole_object
) {
4144 object_size
= 1 << order
;
4146 vector
<diff_extent
> extents
;
4147 ceph::bufferlist bl
;
4149 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4150 vector_iterate_cb
, (void *) &extents
));
4151 ASSERT_EQ(0u, extents
.size());
4153 ASSERT_EQ(0, image
.snap_create("snap1"));
4155 memset(data
, 1, sizeof(data
));
4156 bl
.append(data
, 256);
4157 ASSERT_EQ(256, image
.write(0, 256, bl
));
4160 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4161 vector_iterate_cb
, (void *) &extents
));
4162 ASSERT_EQ(1u, extents
.size());
4163 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4165 ASSERT_EQ(0, image
.snap_set("snap1"));
4167 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4168 vector_iterate_cb
, (void *) &extents
));
4169 ASSERT_EQ(static_cast<size_t>(0), extents
.size());
4172 TYPED_TEST(DiffIterateTest
, DiffIterateIgnoreParent
)
4174 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4176 librados::IoCtx ioctx
;
4177 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4179 bool skip_discard
= this->is_skip_partial_discard_enabled();
4182 librbd::Image image
;
4183 std::string name
= this->get_temp_image_name();
4184 uint64_t size
= 20 << 20;
4187 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4188 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4190 uint64_t object_size
= 0;
4191 if (this->whole_object
) {
4192 object_size
= 1 << order
;
4196 bl
.append(buffer::create(size
));
4198 interval_set
<uint64_t> one
;
4199 one
.insert(0, size
);
4200 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
4201 ASSERT_EQ(0, image
.snap_create("one"));
4202 ASSERT_EQ(0, image
.snap_protect("one"));
4204 std::string clone_name
= this->get_temp_image_name();
4205 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
4206 RBD_FEATURE_LAYERING
, &order
));
4207 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4209 interval_set
<uint64_t> exists
;
4210 interval_set
<uint64_t> two
;
4211 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4212 two
= round_diff_interval(two
, object_size
);
4213 cout
<< " wrote " << two
<< " to clone" << std::endl
;
4215 interval_set
<uint64_t> diff
;
4216 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, false, this->whole_object
,
4217 iterate_cb
, (void *)&diff
));
4218 cout
<< " diff was " << diff
<< std::endl
;
4219 if (!this->whole_object
) {
4220 ASSERT_FALSE(one
.subset_of(diff
));
4222 ASSERT_TRUE(two
.subset_of(diff
));
4225 TYPED_TEST(DiffIterateTest
, DiffIterateCallbackError
)
4227 librados::IoCtx ioctx
;
4228 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4230 bool skip_discard
= this->is_skip_partial_discard_enabled();
4234 librbd::Image image
;
4236 std::string name
= this->get_temp_image_name();
4237 uint64_t size
= 20 << 20;
4239 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4240 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4242 interval_set
<uint64_t> exists
;
4243 interval_set
<uint64_t> one
;
4244 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4245 cout
<< " wrote " << one
<< std::endl
;
4247 interval_set
<uint64_t> diff
;
4248 ASSERT_EQ(-EINVAL
, image
.diff_iterate2(NULL
, 0, size
, true,
4250 iterate_error_cb
, NULL
));
4255 TYPED_TEST(DiffIterateTest
, DiffIterateParentDiscard
)
4257 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4259 librados::IoCtx ioctx
;
4260 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4262 bool skip_discard
= this->is_skip_partial_discard_enabled();
4265 librbd::Image image
;
4266 std::string name
= this->get_temp_image_name();
4267 uint64_t size
= 20 << 20;
4270 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4271 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4273 uint64_t object_size
= 0;
4274 if (this->whole_object
) {
4275 object_size
= 1 << order
;
4278 interval_set
<uint64_t> exists
;
4279 interval_set
<uint64_t> one
;
4280 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4281 ASSERT_EQ(0, image
.snap_create("one"));
4283 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4284 ASSERT_EQ(0, image
.snap_create("two"));
4285 ASSERT_EQ(0, image
.snap_protect("two"));
4289 std::string clone_name
= this->get_temp_image_name();
4290 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "two", ioctx
,
4291 clone_name
.c_str(), RBD_FEATURE_LAYERING
, &order
));
4292 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4294 interval_set
<uint64_t> two
;
4295 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4296 two
= round_diff_interval(two
, object_size
);
4298 interval_set
<uint64_t> diff
;
4299 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4300 iterate_cb
, (void *)&diff
));
4301 ASSERT_TRUE(two
.subset_of(diff
));
4304 TEST_F(TestLibRBD
, ZeroLengthWrite
)
4306 rados_ioctx_t ioctx
;
4307 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4311 std::string name
= get_temp_image_name();
4312 uint64_t size
= 2 << 20;
4314 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4315 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4318 ASSERT_EQ(0, rbd_write(image
, 0, 0, NULL
));
4319 ASSERT_EQ(1, rbd_read(image
, 0, 1, read_data
));
4320 ASSERT_EQ('\0', read_data
[0]);
4322 ASSERT_PASSED(validate_object_map
, image
);
4323 ASSERT_EQ(0, rbd_close(image
));
4325 rados_ioctx_destroy(ioctx
);
4329 TEST_F(TestLibRBD
, ZeroLengthDiscard
)
4331 rados_ioctx_t ioctx
;
4332 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4336 std::string name
= get_temp_image_name();
4337 uint64_t size
= 2 << 20;
4339 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4340 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4342 const char data
[] = "blah";
4343 char read_data
[sizeof(data
)];
4344 ASSERT_EQ((int)strlen(data
), rbd_write(image
, 0, strlen(data
), data
));
4345 ASSERT_EQ(0, rbd_discard(image
, 0, 0));
4346 ASSERT_EQ((int)strlen(data
), rbd_read(image
, 0, strlen(data
), read_data
));
4347 ASSERT_EQ(0, memcmp(data
, read_data
, strlen(data
)));
4349 ASSERT_PASSED(validate_object_map
, image
);
4350 ASSERT_EQ(0, rbd_close(image
));
4352 rados_ioctx_destroy(ioctx
);
4355 TEST_F(TestLibRBD
, ZeroLengthRead
)
4357 rados_ioctx_t ioctx
;
4358 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4362 std::string name
= get_temp_image_name();
4363 uint64_t size
= 2 << 20;
4365 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4366 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4369 ASSERT_EQ(0, rbd_read(image
, 0, 0, read_data
));
4371 ASSERT_EQ(0, rbd_close(image
));
4373 rados_ioctx_destroy(ioctx
);
4376 TEST_F(TestLibRBD
, LargeCacheRead
)
4378 std::string config_value
;
4379 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", config_value
));
4380 if (config_value
== "false") {
4381 std::cout
<< "SKIPPING due to disabled cache" << std::endl
;
4385 rados_ioctx_t ioctx
;
4386 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4388 uint32_t new_cache_size
= 1 << 20;
4389 std::string orig_cache_size
;
4390 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", orig_cache_size
));
4391 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size",
4392 stringify(new_cache_size
).c_str()));
4393 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", config_value
));
4394 ASSERT_EQ(stringify(new_cache_size
), config_value
);
4395 BOOST_SCOPE_EXIT( (orig_cache_size
) ) {
4396 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size", orig_cache_size
.c_str()));
4397 } BOOST_SCOPE_EXIT_END
;
4401 std::string name
= get_temp_image_name();
4402 uint64_t size
= 1 << order
;
4404 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4405 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4407 std::string
buffer(1 << order
, '1');
4409 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
4410 rbd_write(image
, 0, buffer
.size(), buffer
.c_str()));
4412 ASSERT_EQ(0, rbd_invalidate_cache(image
));
4414 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
4415 rbd_read(image
, 0, buffer
.size(), &buffer
[0]));
4417 ASSERT_EQ(0, rbd_close(image
));
4419 rados_ioctx_destroy(ioctx
);
4422 TEST_F(TestLibRBD
, TestPendingAio
)
4424 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4426 rados_ioctx_t ioctx
;
4427 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4434 ASSERT_EQ(0, get_features(&old_format
, &features
));
4435 ASSERT_FALSE(old_format
);
4437 std::string name
= get_temp_image_name();
4439 uint64_t size
= 4 << 20;
4440 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
4442 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4444 char test_data
[TEST_IO_SIZE
];
4445 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4446 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4449 size_t num_aios
= 256;
4450 rbd_completion_t comps
[num_aios
];
4451 for (size_t i
= 0; i
< num_aios
; ++i
) {
4452 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
4453 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4454 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
4457 for (size_t i
= 0; i
< num_aios
; ++i
) {
4458 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps
[i
]));
4459 rbd_aio_release(comps
[i
]);
4461 ASSERT_EQ(0, rbd_invalidate_cache(image
));
4463 for (size_t i
= 0; i
< num_aios
; ++i
) {
4464 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
4465 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4466 ASSERT_LE(0, rbd_aio_read(image
, offset
, TEST_IO_SIZE
, test_data
,
4470 ASSERT_PASSED(validate_object_map
, image
);
4471 ASSERT_EQ(0, rbd_close(image
));
4472 for (size_t i
= 0; i
< num_aios
; ++i
) {
4473 ASSERT_EQ(1, rbd_aio_is_complete(comps
[i
]));
4474 rbd_aio_release(comps
[i
]);
4477 rados_ioctx_destroy(ioctx
);
4480 void compare_and_write_copyup(librados::IoCtx
&ioctx
, bool deep_copyup
,
4484 std::string parent_name
= TestLibRBD::get_temp_image_name();
4485 uint64_t size
= 2 << 20;
4487 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4489 librbd::Image parent_image
;
4490 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4493 bl
.append(std::string(4096, '1'));
4494 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
4496 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4497 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4500 ASSERT_EQ(0, parent_image
.features(&features
));
4502 std::string clone_name
= TestLibRBD::get_temp_image_name();
4503 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4504 clone_name
.c_str(), features
, &order
));
4506 librbd::Image clone_image
;
4507 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
4509 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
4513 cmp_bl
.append(std::string(96, '1'));
4514 bufferlist write_bl
;
4515 write_bl
.append(std::string(512, '2'));
4516 uint64_t mismatch_off
;
4517 ASSERT_EQ((ssize_t
)write_bl
.length(),
4518 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
4519 write_bl
, &mismatch_off
, 0));
4522 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
4524 bufferlist expected_bl
;
4525 expected_bl
.append(std::string(512, '1'));
4526 expected_bl
.append(std::string(512, '2'));
4527 expected_bl
.append(std::string(3072, '1'));
4528 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
4532 TEST_F(TestLibRBD
, CompareAndWriteCopyup
)
4534 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4536 librados::IoCtx ioctx
;
4537 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4539 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, false);
4540 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, true);
4543 void compare_and_write_copyup_mismatch(librados::IoCtx
&ioctx
,
4544 bool deep_copyup
, bool *passed
)
4547 std::string parent_name
= TestLibRBD::get_temp_image_name();
4548 uint64_t size
= 2 << 20;
4550 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4552 librbd::Image parent_image
;
4553 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4556 bl
.append(std::string(4096, '1'));
4557 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
4559 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4560 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4563 ASSERT_EQ(0, parent_image
.features(&features
));
4565 std::string clone_name
= TestLibRBD::get_temp_image_name();
4566 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4567 clone_name
.c_str(), features
, &order
));
4569 librbd::Image clone_image
;
4570 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
4572 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
4576 cmp_bl
.append(std::string(48, '1'));
4577 cmp_bl
.append(std::string(48, '3'));
4578 bufferlist write_bl
;
4579 write_bl
.append(std::string(512, '2'));
4580 uint64_t mismatch_off
;
4582 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
4583 write_bl
, &mismatch_off
, 0));
4584 ASSERT_EQ(48U, mismatch_off
);
4587 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
4589 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4593 TEST_F(TestLibRBD
, CompareAndWriteCopyupMismatch
)
4595 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4597 librados::IoCtx ioctx
;
4598 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4600 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, false);
4601 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, true);
4604 TEST_F(TestLibRBD
, Flatten
)
4606 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4608 librados::IoCtx ioctx
;
4609 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4612 std::string parent_name
= get_temp_image_name();
4613 uint64_t size
= 2 << 20;
4615 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4617 librbd::Image parent_image
;
4618 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4621 bl
.append(std::string(4096, '1'));
4622 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
4624 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4625 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4628 ASSERT_EQ(0, parent_image
.features(&features
));
4630 std::string clone_name
= get_temp_image_name();
4631 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4632 clone_name
.c_str(), features
, &order
));
4634 librbd::Image clone_image
;
4635 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
4636 ASSERT_EQ(0, clone_image
.flatten());
4638 librbd::RBD::AioCompletion
*read_comp
=
4639 new librbd::RBD::AioCompletion(NULL
, NULL
);
4641 clone_image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
4642 ASSERT_EQ(0, read_comp
->wait_for_complete());
4643 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
4644 read_comp
->release();
4645 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4647 ASSERT_PASSED(validate_object_map
, clone_image
);
4650 TEST_F(TestLibRBD
, Sparsify
)
4652 rados_ioctx_t ioctx
;
4653 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
4654 BOOST_SCOPE_EXIT_ALL(&ioctx
) {
4655 rados_ioctx_destroy(ioctx
);
4658 const size_t CHUNK_SIZE
= 4096 * 2;
4661 std::string name
= get_temp_image_name();
4662 uint64_t size
= CHUNK_SIZE
* 1024;
4664 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4665 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4666 BOOST_SCOPE_EXIT_ALL(&image
) {
4670 char test_data
[4 * CHUNK_SIZE
+ 1];
4671 for (size_t i
= 0; i
< 4 ; ++i
) {
4672 for (size_t j
= 0; j
< CHUNK_SIZE
; j
++) {
4674 test_data
[i
* CHUNK_SIZE
+ j
] = (char)(rand() % (126 - 33) + 33);
4676 test_data
[i
* CHUNK_SIZE
+ j
] = '\0';
4680 test_data
[4 * CHUNK_SIZE
] = '\0';
4682 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
4683 ASSERT_EQ(0, rbd_flush(image
));
4685 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 16));
4686 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 1 << (order
+ 1)));
4687 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 4096 + 1));
4688 ASSERT_EQ(0, rbd_sparsify(image
, 4096));
4690 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
4693 TEST_F(TestLibRBD
, SparsifyPP
)
4695 librados::IoCtx ioctx
;
4696 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4699 std::string name
= get_temp_image_name();
4700 uint64_t size
= 12 * 1024 * 1024;
4702 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4704 librbd::Image image
;
4705 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
4708 bl
.append(std::string(4096, '\0'));
4709 bl
.append(std::string(4096, '1'));
4710 bl
.append(std::string(4096, '\0'));
4711 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
4712 ASSERT_EQ(0, image
.flush());
4714 ASSERT_EQ(-EINVAL
, image
.sparsify(16));
4715 ASSERT_EQ(-EINVAL
, image
.sparsify(1 << (order
+ 1)));
4716 ASSERT_EQ(-EINVAL
, image
.sparsify(4096 + 1));
4717 ASSERT_EQ(0, image
.sparsify(4096));
4720 ASSERT_EQ((ssize_t
)bl
.length(), image
.read(0, bl
.length(), read_bl
));
4721 ASSERT_TRUE(bl
.contents_equal(read_bl
));
4723 ASSERT_PASSED(validate_object_map
, image
);
4726 TEST_F(TestLibRBD
, SnapshotLimit
)
4728 rados_ioctx_t ioctx
;
4729 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4733 std::string name
= get_temp_image_name();
4734 uint64_t size
= 2 << 20;
4737 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4738 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4740 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
4741 ASSERT_EQ(UINT64_MAX
, limit
);
4742 ASSERT_EQ(0, rbd_snap_set_limit(image
, 2));
4743 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
4744 ASSERT_EQ(2U, limit
);
4746 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
4747 ASSERT_EQ(-ERANGE
, rbd_snap_set_limit(image
, 0));
4748 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
4749 ASSERT_EQ(-EDQUOT
, rbd_snap_create(image
, "snap3"));
4750 ASSERT_EQ(0, rbd_snap_set_limit(image
, UINT64_MAX
));
4751 ASSERT_EQ(0, rbd_snap_create(image
, "snap3"));
4752 ASSERT_EQ(0, rbd_close(image
));
4754 rados_ioctx_destroy(ioctx
);
4758 TEST_F(TestLibRBD
, SnapshotLimitPP
)
4760 librados::IoCtx ioctx
;
4761 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4765 librbd::Image image
;
4766 std::string name
= get_temp_image_name();
4767 uint64_t size
= 2 << 20;
4771 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4772 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4774 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
4775 ASSERT_EQ(UINT64_MAX
, limit
);
4776 ASSERT_EQ(0, image
.snap_set_limit(2));
4777 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
4778 ASSERT_EQ(2U, limit
);
4780 ASSERT_EQ(0, image
.snap_create("snap1"));
4781 ASSERT_EQ(-ERANGE
, image
.snap_set_limit(0));
4782 ASSERT_EQ(0, image
.snap_create("snap2"));
4783 ASSERT_EQ(-EDQUOT
, image
.snap_create("snap3"));
4784 ASSERT_EQ(0, image
.snap_set_limit(UINT64_MAX
));
4785 ASSERT_EQ(0, image
.snap_create("snap3"));
4791 TEST_F(TestLibRBD
, RebuildObjectMapViaLockOwner
)
4793 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_OBJECT_MAP
);
4795 librados::IoCtx ioctx
;
4796 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4799 std::string name
= get_temp_image_name();
4800 uint64_t size
= 2 << 20;
4802 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4804 std::string object_map_oid
;
4806 librbd::Image image
;
4807 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4809 std::string image_id
;
4810 ASSERT_EQ(0, get_image_id(image
, &image_id
));
4811 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
4814 // corrupt the object map
4817 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
4819 librbd::Image image1
;
4820 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4824 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4825 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4826 ASSERT_TRUE(lock_owner
);
4829 ASSERT_EQ(0, image1
.get_flags(&flags
));
4830 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
4832 librbd::Image image2
;
4833 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4834 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4835 ASSERT_FALSE(lock_owner
);
4837 PrintProgress prog_ctx
;
4838 ASSERT_EQ(0, image2
.rebuild_object_map(prog_ctx
));
4839 ASSERT_PASSED(validate_object_map
, image1
);
4840 ASSERT_PASSED(validate_object_map
, image2
);
4843 TEST_F(TestLibRBD
, RenameViaLockOwner
)
4845 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
4847 librados::IoCtx ioctx
;
4848 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4851 std::string name
= get_temp_image_name();
4852 uint64_t size
= 2 << 20;
4854 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4856 librbd::Image image1
;
4857 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4860 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4863 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4864 ASSERT_TRUE(lock_owner
);
4866 std::string new_name
= get_temp_image_name();
4867 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
4868 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4869 ASSERT_TRUE(lock_owner
);
4871 librbd::Image image2
;
4872 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, new_name
.c_str(), NULL
));
4875 TEST_F(TestLibRBD
, SnapCreateViaLockOwner
)
4877 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
4879 librados::IoCtx ioctx
;
4880 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4883 std::string name
= get_temp_image_name();
4884 uint64_t size
= 2 << 20;
4886 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4888 librbd::Image image1
;
4889 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4891 // switch to writeback cache
4892 ASSERT_EQ(0, image1
.flush());
4895 bl
.append(std::string(4096, '1'));
4896 ASSERT_EQ((ssize_t
)bl
.length(), image1
.write(0, bl
.length(), bl
));
4899 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4900 ASSERT_TRUE(lock_owner
);
4902 librbd::Image image2
;
4903 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4905 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4906 ASSERT_FALSE(lock_owner
);
4908 ASSERT_EQ(0, image2
.snap_create("snap1"));
4910 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
4911 ASSERT_TRUE(exists
);
4912 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
4913 ASSERT_TRUE(exists
);
4915 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4916 ASSERT_TRUE(lock_owner
);
4919 TEST_F(TestLibRBD
, SnapRemoveViaLockOwner
)
4921 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
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
));
4936 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4937 ASSERT_EQ(0, image1
.snap_create("snap1"));
4940 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4941 ASSERT_TRUE(lock_owner
);
4943 librbd::Image image2
;
4944 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4946 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4947 ASSERT_FALSE(lock_owner
);
4949 ASSERT_EQ(0, image2
.snap_remove("snap1"));
4951 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
4952 ASSERT_FALSE(exists
);
4953 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
4954 ASSERT_FALSE(exists
);
4956 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4957 ASSERT_TRUE(lock_owner
);
4960 TEST_F(TestLibRBD
, EnableJournalingViaLockOwner
)
4962 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
4964 librados::IoCtx ioctx
;
4965 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4968 std::string name
= get_temp_image_name();
4969 uint64_t size
= 2 << 20;
4971 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4973 librbd::Image image1
;
4974 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
4977 ASSERT_EQ(0, image1
.write(0, 0, bl
));
4980 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4981 ASSERT_TRUE(lock_owner
);
4983 librbd::Image image2
;
4984 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
4986 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, false));
4988 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4989 ASSERT_TRUE(lock_owner
);
4990 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4991 ASSERT_FALSE(lock_owner
);
4993 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, true));
4995 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
4996 ASSERT_FALSE(lock_owner
);
4997 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
4998 ASSERT_TRUE(lock_owner
);
5001 TEST_F(TestLibRBD
, SnapRemove2
)
5003 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5005 librados::IoCtx ioctx
;
5006 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5009 std::string name
= get_temp_image_name();
5010 uint64_t size
= 2 << 20;
5012 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5014 librbd::Image image1
;
5015 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5018 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5019 ASSERT_EQ(0, image1
.snap_create("snap1"));
5021 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5022 ASSERT_TRUE(exists
);
5023 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5025 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5026 ASSERT_TRUE(is_protected
);
5029 ASSERT_EQ(0, image1
.features(&features
));
5031 std::string child_name
= get_temp_image_name();
5032 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5033 child_name
.c_str(), features
, &order
));
5035 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5036 ASSERT_TRUE(exists
);
5037 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5038 ASSERT_TRUE(is_protected
);
5040 ASSERT_EQ(-EBUSY
, image1
.snap_remove("snap1"));
5042 ASSERT_EQ(0, image1
.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE
, pp
));
5043 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5044 ASSERT_FALSE(exists
);
5047 TEST_F(TestLibRBD
, SnapRenameViaLockOwner
)
5049 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5051 librados::IoCtx ioctx
;
5052 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5055 std::string name
= get_temp_image_name();
5056 uint64_t size
= 2 << 20;
5058 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5060 librbd::Image image1
;
5061 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5064 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5065 ASSERT_EQ(0, image1
.snap_create("snap1"));
5068 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5069 ASSERT_TRUE(lock_owner
);
5071 librbd::Image image2
;
5072 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5074 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5075 ASSERT_FALSE(lock_owner
);
5077 ASSERT_EQ(0, image2
.snap_rename("snap1", "snap1-rename"));
5079 ASSERT_EQ(0, image1
.snap_exists2("snap1-rename", &exists
));
5080 ASSERT_TRUE(exists
);
5081 ASSERT_EQ(0, image2
.snap_exists2("snap1-rename", &exists
));
5082 ASSERT_TRUE(exists
);
5084 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5085 ASSERT_TRUE(lock_owner
);
5088 TEST_F(TestLibRBD
, SnapProtectViaLockOwner
)
5090 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5092 librados::IoCtx ioctx
;
5093 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5096 std::string name
= get_temp_image_name();
5097 uint64_t size
= 2 << 20;
5099 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5101 librbd::Image image1
;
5102 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5105 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5108 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5109 ASSERT_TRUE(lock_owner
);
5110 ASSERT_EQ(0, image1
.snap_create("snap1"));
5112 librbd::Image image2
;
5113 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5115 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5116 ASSERT_FALSE(lock_owner
);
5118 ASSERT_EQ(0, image2
.snap_protect("snap1"));
5120 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5121 ASSERT_TRUE(is_protected
);
5122 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5123 ASSERT_TRUE(is_protected
);
5125 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5126 ASSERT_TRUE(lock_owner
);
5129 TEST_F(TestLibRBD
, SnapUnprotectViaLockOwner
)
5131 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5133 librados::IoCtx ioctx
;
5134 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5137 std::string name
= get_temp_image_name();
5138 uint64_t size
= 2 << 20;
5140 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5142 librbd::Image image1
;
5143 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5146 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5149 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5150 ASSERT_TRUE(lock_owner
);
5151 ASSERT_EQ(0, image1
.snap_create("snap1"));
5152 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5154 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5155 ASSERT_TRUE(is_protected
);
5157 librbd::Image image2
;
5158 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5160 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5161 ASSERT_FALSE(lock_owner
);
5163 ASSERT_EQ(0, image2
.snap_unprotect("snap1"));
5164 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5165 ASSERT_FALSE(is_protected
);
5166 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5167 ASSERT_FALSE(is_protected
);
5169 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5170 ASSERT_TRUE(lock_owner
);
5173 TEST_F(TestLibRBD
, FlattenViaLockOwner
)
5175 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5177 librados::IoCtx ioctx
;
5178 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5181 std::string parent_name
= get_temp_image_name();
5182 uint64_t size
= 2 << 20;
5184 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5186 librbd::Image parent_image
;
5187 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5188 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5189 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5192 ASSERT_EQ(0, parent_image
.features(&features
));
5194 std::string name
= get_temp_image_name();
5195 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5196 name
.c_str(), features
, &order
));
5198 librbd::Image image1
;
5199 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5202 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5205 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5206 ASSERT_TRUE(lock_owner
);
5208 librbd::Image image2
;
5209 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5211 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5212 ASSERT_FALSE(lock_owner
);
5214 ASSERT_EQ(0, image2
.flatten());
5216 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5217 ASSERT_TRUE(lock_owner
);
5218 ASSERT_PASSED(validate_object_map
, image1
);
5221 TEST_F(TestLibRBD
, ResizeViaLockOwner
)
5223 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5225 librados::IoCtx ioctx
;
5226 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5229 std::string name
= get_temp_image_name();
5230 uint64_t size
= 2 << 20;
5232 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5234 librbd::Image image1
;
5235 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5238 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5241 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5242 ASSERT_TRUE(lock_owner
);
5244 librbd::Image image2
;
5245 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5247 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5248 ASSERT_FALSE(lock_owner
);
5250 ASSERT_EQ(0, image2
.resize(0));
5252 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5253 ASSERT_TRUE(lock_owner
);
5254 ASSERT_PASSED(validate_object_map
, image1
);
5257 TEST_F(TestLibRBD
, SparsifyViaLockOwner
)
5259 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5261 librados::IoCtx ioctx
;
5262 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5265 std::string name
= get_temp_image_name();
5266 uint64_t size
= 2 << 20;
5268 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5270 librbd::Image image1
;
5271 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5274 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5277 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5278 ASSERT_TRUE(lock_owner
);
5280 librbd::Image image2
;
5281 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5283 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5284 ASSERT_FALSE(lock_owner
);
5286 ASSERT_EQ(0, image2
.sparsify(4096));
5288 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5289 ASSERT_TRUE(lock_owner
);
5290 ASSERT_PASSED(validate_object_map
, image1
);
5293 TEST_F(TestLibRBD
, ObjectMapConsistentSnap
)
5295 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5297 librados::IoCtx ioctx
;
5298 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5301 std::string name
= get_temp_image_name();
5302 uint64_t size
= 1 << 20;
5304 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5306 librbd::Image image1
;
5307 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5310 for (int i
= 0; i
< num_snaps
; ++i
) {
5311 std::string snap_name
= "snap" + stringify(i
);
5312 ASSERT_EQ(0, image1
.snap_create(snap_name
.c_str()));
5316 thread
writer([&image1
](){
5317 librbd::image_info_t info
;
5318 int r
= image1
.stat(info
, sizeof(info
));
5319 ceph_assert(r
== 0);
5322 for (unsigned i
= 0; i
< info
.num_objs
; ++i
) {
5323 r
= image1
.write((1 << info
.order
) * i
, bl
.length(), bl
);
5324 ceph_assert(r
== (int) bl
.length());
5329 for (int i
= 0; i
< num_snaps
; ++i
) {
5330 std::string snap_name
= "snap" + stringify(i
);
5331 ASSERT_EQ(0, image1
.snap_set(snap_name
.c_str()));
5332 ASSERT_PASSED(validate_object_map
, image1
);
5335 ASSERT_EQ(0, image1
.snap_set(NULL
));
5336 ASSERT_PASSED(validate_object_map
, image1
);
5339 void memset_rand(char *buf
, size_t len
) {
5340 for (size_t i
= 0; i
< len
; ++i
) {
5341 buf
[i
] = (char) (rand() % (126 - 33) + 33);
5345 TEST_F(TestLibRBD
, Metadata
)
5347 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5349 rados_ioctx_t ioctx
;
5350 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5352 std::string name
= get_temp_image_name();
5353 uint64_t size
= 2 << 20;
5355 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5358 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5361 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
5365 size_t keys_len
= sizeof(keys
);
5366 size_t vals_len
= sizeof(vals
);
5368 memset_rand(keys
, keys_len
);
5369 memset_rand(vals
, vals_len
);
5371 ASSERT_EQ(0, rbd_metadata_list(image
, "", 0, keys
, &keys_len
, vals
,
5373 ASSERT_EQ(0U, keys_len
);
5374 ASSERT_EQ(0U, vals_len
);
5377 size_t value_len
= sizeof(value
);
5378 memset_rand(value
, value_len
);
5380 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
5381 ASSERT_EQ(0, rbd_metadata_set(image1
, "key2", "value2"));
5382 ASSERT_EQ(0, rbd_metadata_get(image1
, "key1", value
, &value_len
));
5383 ASSERT_STREQ(value
, "value1");
5385 ASSERT_EQ(-ERANGE
, rbd_metadata_get(image1
, "key1", value
, &value_len
));
5386 ASSERT_EQ(value_len
, strlen("value1") + 1);
5388 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5390 keys_len
= sizeof(keys
);
5391 vals_len
= sizeof(vals
);
5392 memset_rand(keys
, keys_len
);
5393 memset_rand(vals
, vals_len
);
5394 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5396 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
5397 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
5398 ASSERT_STREQ(keys
, "key1");
5399 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
5400 ASSERT_STREQ(vals
, "value1");
5401 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
5403 ASSERT_EQ(0, rbd_metadata_remove(image1
, "key1"));
5404 ASSERT_EQ(-ENOENT
, rbd_metadata_remove(image1
, "key3"));
5405 value_len
= sizeof(value
);
5406 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key3", value
, &value_len
));
5407 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5409 ASSERT_EQ(keys_len
, strlen("key2") + 1);
5410 ASSERT_EQ(vals_len
, strlen("value2") + 1);
5411 ASSERT_STREQ(keys
, "key2");
5412 ASSERT_STREQ(vals
, "value2");
5414 // test config setting
5415 ASSERT_EQ(0, rbd_metadata_set(image1
, "conf_rbd_cache", "false"));
5416 ASSERT_EQ(-EINVAL
, rbd_metadata_set(image1
, "conf_rbd_cache", "INVALID_VAL"));
5417 ASSERT_EQ(0, rbd_metadata_remove(image1
, "conf_rbd_cache"));
5419 // test metadata with snapshot adding
5420 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
5421 ASSERT_EQ(0, rbd_snap_protect(image1
, "snap1"));
5422 ASSERT_EQ(0, rbd_snap_set(image1
, "snap1"));
5424 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
5425 ASSERT_EQ(0, rbd_metadata_set(image1
, "key3", "value3"));
5427 keys_len
= sizeof(keys
);
5428 vals_len
= sizeof(vals
);
5429 memset_rand(keys
, keys_len
);
5430 memset_rand(vals
, vals_len
);
5431 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5434 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5436 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5437 ASSERT_STREQ(keys
, "key1");
5438 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
5439 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
5440 ASSERT_STREQ(vals
, "value1");
5441 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
5442 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
5444 ASSERT_EQ(0, rbd_snap_set(image1
, NULL
));
5445 keys_len
= sizeof(keys
);
5446 vals_len
= sizeof(vals
);
5447 memset_rand(keys
, keys_len
);
5448 memset_rand(vals
, vals_len
);
5449 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5452 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5454 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5455 ASSERT_STREQ(keys
, "key1");
5456 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
5457 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
5458 ASSERT_STREQ(vals
, "value1");
5459 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
5460 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
5462 // test metadata with cloning
5464 ASSERT_EQ(0, rbd_get_features(image1
, &features
));
5466 string cname
= get_temp_image_name();
5467 EXPECT_EQ(0, rbd_clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5468 cname
.c_str(), features
, &order
));
5470 ASSERT_EQ(0, rbd_open(ioctx
, cname
.c_str(), &image2
, NULL
));
5471 ASSERT_EQ(0, rbd_metadata_set(image2
, "key4", "value4"));
5473 keys_len
= sizeof(keys
);
5474 vals_len
= sizeof(vals
);
5475 memset_rand(keys
, keys_len
);
5476 memset_rand(vals
, vals_len
);
5477 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 0, keys
, &keys_len
, vals
,
5479 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5480 1 + strlen("key4") + 1);
5481 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
5482 strlen("value3") + 1 + strlen("value4") + 1);
5483 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5485 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1 +
5486 strlen("value3") + 1, "value4");
5488 ASSERT_EQ(0, rbd_metadata_list(image1
, "", 0, keys
, &keys_len
, vals
,
5491 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5493 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5494 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key4", value
, &value_len
));
5496 // test short buffer cases
5497 keys_len
= strlen("key1") + 1;
5498 vals_len
= strlen("value1") + 1;
5499 memset_rand(keys
, keys_len
);
5500 memset_rand(vals
, vals_len
);
5501 ASSERT_EQ(0, rbd_metadata_list(image2
, "", 1, keys
, &keys_len
, vals
,
5503 ASSERT_EQ(keys_len
, strlen("key1") + 1);
5504 ASSERT_EQ(vals_len
, strlen("value1") + 1);
5505 ASSERT_STREQ(keys
, "key1");
5506 ASSERT_STREQ(vals
, "value1");
5508 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "", 2, keys
, &keys_len
, vals
,
5510 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
5511 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
5513 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "", 0, keys
, &keys_len
, vals
,
5515 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5516 1 + strlen("key4") + 1);
5517 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
5518 strlen("value3") + 1 + strlen("value4") + 1);
5520 // test `start` param
5521 keys_len
= sizeof(keys
);
5522 vals_len
= sizeof(vals
);
5523 memset_rand(keys
, keys_len
);
5524 memset_rand(vals
, vals_len
);
5525 ASSERT_EQ(0, rbd_metadata_list(image2
, "key2", 0, keys
, &keys_len
, vals
,
5527 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
5528 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
5529 ASSERT_STREQ(keys
, "key3");
5530 ASSERT_STREQ(vals
, "value3");
5532 ASSERT_EQ(0, rbd_close(image
));
5533 ASSERT_EQ(0, rbd_close(image1
));
5534 ASSERT_EQ(0, rbd_close(image2
));
5535 rados_ioctx_destroy(ioctx
);
5538 TEST_F(TestLibRBD
, MetadataPP
)
5540 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5542 librados::IoCtx ioctx
;
5543 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5546 string name
= get_temp_image_name();
5547 uint64_t size
= 2 << 20;
5551 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5553 librbd::Image image1
;
5554 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5555 map
<string
, bufferlist
> pairs
;
5556 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5557 ASSERT_TRUE(pairs
.empty());
5559 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
5560 ASSERT_EQ(0, image1
.metadata_set("key2", "value2"));
5561 ASSERT_EQ(0, image1
.metadata_get("key1", &value
));
5562 ASSERT_EQ(0, strcmp("value1", value
.c_str()));
5563 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5564 ASSERT_EQ(2U, pairs
.size());
5565 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
5566 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5569 ASSERT_EQ(0, image1
.metadata_remove("key1"));
5570 ASSERT_EQ(-ENOENT
, image1
.metadata_remove("key3"));
5571 ASSERT_TRUE(image1
.metadata_get("key3", &value
) < 0);
5572 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5573 ASSERT_EQ(1U, pairs
.size());
5574 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5576 // test config setting
5577 ASSERT_EQ(0, image1
.metadata_set("conf_rbd_cache", "false"));
5578 ASSERT_EQ(-EINVAL
, image1
.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
5579 ASSERT_EQ(0, image1
.metadata_remove("conf_rbd_cache"));
5581 // test metadata with snapshot adding
5582 ASSERT_EQ(0, image1
.snap_create("snap1"));
5583 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5584 ASSERT_EQ(0, image1
.snap_set("snap1"));
5587 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
5588 ASSERT_EQ(0, image1
.metadata_set("key3", "value3"));
5589 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5590 ASSERT_EQ(3U, pairs
.size());
5591 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
5592 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5593 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
5595 ASSERT_EQ(0, image1
.snap_set(NULL
));
5596 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5597 ASSERT_EQ(3U, pairs
.size());
5598 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
5599 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
5600 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
5602 // test metadata with cloning
5603 string cname
= get_temp_image_name();
5604 librbd::Image image2
;
5605 ASSERT_EQ(0, image1
.features(&features
));
5606 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5607 cname
.c_str(), features
, &order
));
5608 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, cname
.c_str(), NULL
));
5609 ASSERT_EQ(0, image2
.metadata_set("key4", "value4"));
5611 ASSERT_EQ(0, image2
.metadata_list("", 0, &pairs
));
5612 ASSERT_EQ(4U, pairs
.size());
5614 ASSERT_EQ(0, image1
.metadata_list("", 0, &pairs
));
5615 ASSERT_EQ(3U, pairs
.size());
5616 ASSERT_EQ(-ENOENT
, image1
.metadata_get("key4", &value
));
5619 TEST_F(TestLibRBD
, UpdateFeatures
)
5621 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5623 librados::IoCtx ioctx
;
5624 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5627 std::string name
= get_temp_image_name();
5628 uint64_t size
= 1 << 20;
5630 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5632 librbd::Image image
;
5633 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5636 ASSERT_EQ(0, image
.old_format(&old_format
));
5638 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
5643 ASSERT_EQ(0, image
.features(&features
));
5645 // must provide a single feature
5646 ASSERT_EQ(-EINVAL
, image
.update_features(0, true));
5648 uint64_t disable_features
;
5649 disable_features
= features
& (RBD_FEATURE_EXCLUSIVE_LOCK
|
5650 RBD_FEATURE_OBJECT_MAP
|
5651 RBD_FEATURE_FAST_DIFF
|
5652 RBD_FEATURE_JOURNALING
);
5653 if (disable_features
!= 0) {
5654 ASSERT_EQ(0, image
.update_features(disable_features
, false));
5657 ASSERT_EQ(0, image
.features(&features
));
5658 ASSERT_EQ(0U, features
& disable_features
);
5660 // cannot enable object map nor journaling w/o exclusive lock
5661 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5662 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_JOURNALING
, true));
5663 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
5665 ASSERT_EQ(0, image
.features(&features
));
5666 ASSERT_NE(0U, features
& RBD_FEATURE_EXCLUSIVE_LOCK
);
5668 // can enable fast diff w/o object map
5669 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_FAST_DIFF
, true));
5670 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5671 ASSERT_EQ(0, image
.features(&features
));
5672 ASSERT_NE(0U, features
& RBD_FEATURE_OBJECT_MAP
);
5674 uint64_t expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
|
5675 RBD_FLAG_FAST_DIFF_INVALID
;
5677 ASSERT_EQ(0, image
.get_flags(&flags
));
5678 ASSERT_EQ(expected_flags
, flags
);
5680 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5681 ASSERT_EQ(0, image
.features(&features
));
5682 ASSERT_EQ(0U, features
& RBD_FEATURE_OBJECT_MAP
);
5684 // can disable object map w/ fast diff
5685 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5686 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5687 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_FAST_DIFF
, false));
5688 ASSERT_EQ(0, image
.features(&features
));
5689 ASSERT_EQ(0U, features
& RBD_FEATURE_FAST_DIFF
);
5691 ASSERT_EQ(0, image
.get_flags(&flags
));
5692 ASSERT_EQ(0U, flags
);
5694 // cannot disable exclusive lock w/ object map
5695 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5696 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
5697 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5699 // cannot disable exclusive lock w/ journaling
5700 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, true));
5701 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
5702 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, false));
5704 ASSERT_EQ(0, image
.get_flags(&flags
));
5705 ASSERT_EQ(0U, flags
);
5707 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
5709 ASSERT_EQ(0, image
.features(&features
));
5710 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0) {
5711 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, false));
5713 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, true));
5716 TEST_F(TestLibRBD
, RebuildObjectMap
)
5718 librados::IoCtx ioctx
;
5719 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5722 std::string name
= get_temp_image_name();
5723 uint64_t size
= 1 << 20;
5725 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5727 PrintProgress prog_ctx
;
5728 std::string object_map_oid
;
5732 librbd::Image image
;
5733 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5736 ASSERT_EQ(0, image
.features(&features
));
5737 if ((features
& RBD_FEATURE_OBJECT_MAP
) == 0) {
5738 ASSERT_EQ(-EINVAL
, image
.rebuild_object_map(prog_ctx
));
5742 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
5744 ASSERT_EQ(0, image
.snap_create("snap1"));
5745 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(1<<order
, bl
.length(), bl
));
5747 std::string image_id
;
5748 ASSERT_EQ(0, get_image_id(image
, &image_id
));
5749 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
5752 // corrupt the object map
5753 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
5755 librbd::Image image1
;
5756 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5760 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5761 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5762 ASSERT_TRUE(lock_owner
);
5765 ASSERT_EQ(0, image1
.get_flags(&flags
));
5766 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
5768 ASSERT_EQ(0, image1
.rebuild_object_map(prog_ctx
));
5770 librbd::Image image2
;
5771 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5774 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(0, bl
.length(), read_bl
));
5775 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5778 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(1<<order
, bl
.length(), read_bl
));
5779 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5781 ASSERT_PASSED(validate_object_map
, image1
);
5782 ASSERT_PASSED(validate_object_map
, image2
);
5785 TEST_F(TestLibRBD
, RebuildNewObjectMap
)
5787 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5789 rados_ioctx_t ioctx
;
5790 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5792 std::string name
= get_temp_image_name();
5793 uint64_t size
= 1 << 20;
5795 uint64_t features
= RBD_FEATURE_EXCLUSIVE_LOCK
;
5796 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
5800 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5801 ASSERT_EQ(0, rbd_update_features(image
, RBD_FEATURE_OBJECT_MAP
, true));
5802 ASSERT_EQ(0, rbd_rebuild_object_map(image
, print_progress_percent
, NULL
));
5804 ASSERT_PASSED(validate_object_map
, image
);
5806 ASSERT_EQ(0, rbd_close(image
));
5807 rados_ioctx_destroy(ioctx
);
5810 TEST_F(TestLibRBD
, CheckObjectMap
)
5812 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5814 librados::IoCtx ioctx
;
5815 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5818 std::string name
= get_temp_image_name();
5819 uint64_t size
= 1 << 20;
5821 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5823 PrintProgress prog_ctx
;
5828 librbd::Image image
;
5829 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5832 ASSERT_EQ(0, image
.features(&features
));
5834 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(0, bl1
.length(), bl1
));
5836 ASSERT_EQ(0, image
.snap_create("snap1"));
5837 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(1<<order
, bl1
.length(), bl1
));
5840 librbd::Image image1
;
5841 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5843 std::string image_id
;
5844 ASSERT_EQ(0, get_image_id(image1
, &image_id
));
5846 std::string object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
5848 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl2
, 1024, 0));
5851 ASSERT_EQ((ssize_t
)bl1
.length(), image1
.write(3 * (1 << 18), bl1
.length(), bl1
));
5852 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5853 ASSERT_TRUE(lock_owner
);
5855 //reopen image to reread now corrupt object map from disk
5859 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl1
, 1024, 0));
5860 ASSERT_FALSE(bl1
.contents_equal(bl2
));
5862 ASSERT_EQ(0, ioctx
.write_full(object_map_oid
, bl2
));
5863 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5866 ASSERT_EQ(0, image1
.get_flags(&flags
));
5867 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
5869 ASSERT_EQ(0, image1
.check_object_map(prog_ctx
));
5871 ASSERT_EQ(0, image1
.get_flags(&flags
));
5872 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
5875 TEST_F(TestLibRBD
, BlockingAIO
)
5877 librados::IoCtx ioctx
;
5878 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5880 bool skip_discard
= is_skip_partial_discard_enabled();
5883 std::string name
= get_temp_image_name();
5884 uint64_t size
= 1 << 20;
5886 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5888 std::string non_blocking_aio
;
5889 ASSERT_EQ(0, _rados
.conf_get("rbd_non_blocking_aio", non_blocking_aio
));
5890 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio", "0"));
5891 BOOST_SCOPE_EXIT( (non_blocking_aio
) ) {
5892 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio",
5893 non_blocking_aio
.c_str()));
5894 } BOOST_SCOPE_EXIT_END
;
5896 librbd::Image image
;
5897 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5900 ASSERT_EQ(0, image
.write(0, bl
.length(), bl
));
5902 bl
.append(std::string(256, '1'));
5903 librbd::RBD::AioCompletion
*write_comp
=
5904 new librbd::RBD::AioCompletion(NULL
, NULL
);
5905 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
5907 librbd::RBD::AioCompletion
*flush_comp
=
5908 new librbd::RBD::AioCompletion(NULL
, NULL
);
5909 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
5910 ASSERT_EQ(0, flush_comp
->wait_for_complete());
5911 ASSERT_EQ(0, flush_comp
->get_return_value());
5912 flush_comp
->release();
5914 ASSERT_EQ(1, write_comp
->is_complete());
5915 ASSERT_EQ(0, write_comp
->get_return_value());
5916 write_comp
->release();
5918 librbd::RBD::AioCompletion
*discard_comp
=
5919 new librbd::RBD::AioCompletion(NULL
, NULL
);
5920 ASSERT_EQ(0, image
.aio_discard(128, 128, discard_comp
));
5921 ASSERT_EQ(0, discard_comp
->wait_for_complete());
5922 discard_comp
->release();
5924 librbd::RBD::AioCompletion
*read_comp
=
5925 new librbd::RBD::AioCompletion(NULL
, NULL
);
5927 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
5928 ASSERT_EQ(0, read_comp
->wait_for_complete());
5929 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
5930 read_comp
->release();
5932 bufferlist expected_bl
;
5933 expected_bl
.append(std::string(128, '1'));
5934 expected_bl
.append(std::string(128, skip_discard
? '1' : '\0'));
5935 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
5938 TEST_F(TestLibRBD
, ExclusiveLockTransition
)
5940 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5942 librados::IoCtx ioctx
;
5943 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5946 std::string name
= get_temp_image_name();
5948 uint64_t size
= 1 << 18;
5950 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5952 librbd::Image image1
;
5953 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5955 librbd::Image image2
;
5956 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5958 std::list
<librbd::RBD::AioCompletion
*> comps
;
5959 ceph::bufferlist bl
;
5960 bl
.append(std::string(1 << order
, '1'));
5961 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
5962 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
5964 comps
.push_back(comp
);
5965 if (object_no
% 2 == 0) {
5966 ASSERT_EQ(0, image1
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
5968 ASSERT_EQ(0, image2
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
5972 while (!comps
.empty()) {
5973 librbd::RBD::AioCompletion
*comp
= comps
.front();
5975 ASSERT_EQ(0, comp
->wait_for_complete());
5976 ASSERT_EQ(1, comp
->is_complete());
5980 librbd::Image image3
;
5981 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
5982 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
5984 ASSERT_EQ((ssize_t
)bl
.length(), image3
.read(object_no
<< order
, bl
.length(),
5986 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5989 ASSERT_PASSED(validate_object_map
, image1
);
5990 ASSERT_PASSED(validate_object_map
, image2
);
5991 ASSERT_PASSED(validate_object_map
, image3
);
5994 TEST_F(TestLibRBD
, ExclusiveLockReadTransition
)
5996 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
5998 librados::IoCtx ioctx
;
5999 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6002 std::string name
= get_temp_image_name();
6004 uint64_t size
= 1 << 18;
6006 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6008 librbd::Image image1
;
6009 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6012 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6013 ASSERT_FALSE(lock_owner
);
6015 // journaling should force read ops to acquire the lock
6017 ASSERT_EQ(0, image1
.read(0, 0, read_bl
));
6019 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6020 ASSERT_TRUE(lock_owner
);
6022 librbd::Image image2
;
6023 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6025 std::list
<librbd::RBD::AioCompletion
*> comps
;
6026 std::list
<bufferlist
> read_bls
;
6027 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6028 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
6030 comps
.push_back(comp
);
6031 read_bls
.emplace_back();
6032 if (object_no
% 2 == 0) {
6033 ASSERT_EQ(0, image1
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6035 ASSERT_EQ(0, image2
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6039 while (!comps
.empty()) {
6040 librbd::RBD::AioCompletion
*comp
= comps
.front();
6042 ASSERT_EQ(0, comp
->wait_for_complete());
6043 ASSERT_EQ(1, comp
->is_complete());
6048 TEST_F(TestLibRBD
, CacheMayCopyOnWrite
) {
6049 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6051 librados::IoCtx ioctx
;
6052 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6055 std::string name
= get_temp_image_name();
6057 uint64_t size
= 1 << 18;
6059 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6061 librbd::Image image
;
6062 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6063 ASSERT_EQ(0, image
.snap_create("one"));
6064 ASSERT_EQ(0, image
.snap_protect("one"));
6066 std::string clone_name
= this->get_temp_image_name();
6067 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
6068 RBD_FEATURE_LAYERING
, &order
));
6070 librbd::Image clone
;
6071 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
6072 ASSERT_EQ(0, clone
.flush());
6074 bufferlist expect_bl
;
6075 expect_bl
.append(std::string(1024, '\0'));
6077 // test double read path
6079 uint64_t offset
= 0;
6080 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6081 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6083 bufferlist write_bl
;
6084 write_bl
.append(std::string(1024, '1'));
6085 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6088 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6089 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6091 // test read retry path
6092 offset
= 1 << order
;
6093 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6096 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6097 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6100 TEST_F(TestLibRBD
, FlushEmptyOpsOnExternalSnapshot
) {
6101 std::string cache_enabled
;
6102 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", cache_enabled
));
6103 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", "false"));
6104 BOOST_SCOPE_EXIT( (cache_enabled
) ) {
6105 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", cache_enabled
.c_str()));
6106 } BOOST_SCOPE_EXIT_END
;
6108 librados::IoCtx ioctx
;
6109 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6112 std::string name
= get_temp_image_name();
6113 uint64_t size
= 1 << 18;
6115 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6117 librbd::Image image1
;
6118 librbd::Image image2
;
6119 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6120 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6121 ASSERT_EQ(0, image1
.snap_create("snap1"));
6123 librbd::RBD::AioCompletion
*read_comp
=
6124 new librbd::RBD::AioCompletion(NULL
, NULL
);
6126 image2
.aio_read(0, 1024, read_bl
, read_comp
);
6127 ASSERT_EQ(0, read_comp
->wait_for_complete());
6128 read_comp
->release();
6131 TEST_F(TestLibRBD
, TestImageOptions
)
6133 rados_ioctx_t ioctx
;
6134 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6136 //make create image options
6137 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6139 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6140 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6141 rbd_image_options_t opts
;
6142 rbd_image_options_create(&opts
);
6145 ASSERT_EQ(-EINVAL
, rbd_image_options_is_set(opts
, 12345, &is_set
));
6146 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6148 ASSERT_FALSE(is_set
);
6150 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FORMAT
,
6152 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FEATURES
,
6154 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6156 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_UNIT
,
6158 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_COUNT
,
6161 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6163 ASSERT_TRUE(is_set
);
6165 std::string parent_name
= get_temp_image_name();
6168 ASSERT_EQ(0, rbd_create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6170 // check order is returned in opts
6171 ASSERT_EQ(0, rbd_image_options_get_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6173 ASSERT_NE((uint64_t)0, order
);
6175 // write some data to parent
6177 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
6178 char *data
= (char *)"testdata";
6179 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
6180 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
6182 // create a snapshot, reopen as the parent we're interested in
6183 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6184 ASSERT_EQ(0, rbd_close(parent
));
6185 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
6188 std::string child_name
= get_temp_image_name();
6189 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
6190 ASSERT_EQ(0, rbd_clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6191 child_name
.c_str(), opts
));
6194 std::string copy1_name
= get_temp_image_name();
6195 ASSERT_EQ(0, rbd_copy3(parent
, ioctx
, copy1_name
.c_str(), opts
));
6196 std::string copy2_name
= get_temp_image_name();
6197 ASSERT_EQ(0, rbd_copy_with_progress3(parent
, ioctx
, copy2_name
.c_str(), opts
,
6198 print_progress_percent
, NULL
));
6200 ASSERT_EQ(0, rbd_close(parent
));
6202 rbd_image_options_destroy(opts
);
6204 rados_ioctx_destroy(ioctx
);
6207 TEST_F(TestLibRBD
, TestImageOptionsPP
)
6209 librados::IoCtx ioctx
;
6210 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6212 //make create image options
6213 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6215 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6216 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6217 librbd::ImageOptions opts
;
6218 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FORMAT
, static_cast<uint64_t>(2)));
6219 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FEATURES
, features
));
6220 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_ORDER
, order
));
6221 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
));
6222 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
));
6225 std::string parent_name
= get_temp_image_name();
6228 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6230 // check order is returned in opts
6231 ASSERT_EQ(0, opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
));
6232 ASSERT_NE((uint64_t)0, order
);
6234 // write some data to parent
6235 librbd::Image parent
;
6236 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
6240 bl
.append(buffer::create(len
));
6242 ASSERT_EQ(len
, parent
.write(0, len
, bl
));
6243 ASSERT_EQ(len
, parent
.write(len
, len
, bl
));
6245 // create a snapshot, reopen as the parent we're interested in
6246 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
6247 ASSERT_EQ(0, parent
.close());
6248 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
6251 std::string child_name
= get_temp_image_name();
6252 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
6253 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6254 child_name
.c_str(), opts
));
6257 std::string copy1_name
= get_temp_image_name();
6258 ASSERT_EQ(0, parent
.copy3(ioctx
, copy1_name
.c_str(), opts
));
6259 std::string copy2_name
= get_temp_image_name();
6261 ASSERT_EQ(0, parent
.copy_with_progress3(ioctx
, copy2_name
.c_str(), opts
, pp
));
6263 ASSERT_EQ(0, parent
.close());
6266 TEST_F(TestLibRBD
, EventSocketPipe
)
6268 EventSocket event_sock
;
6269 int pipe_fd
[2]; // read and write fd
6272 ASSERT_EQ(0, pipe(pipe_fd
));
6274 ASSERT_FALSE(event_sock
.is_valid());
6276 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_NONE
));
6277 ASSERT_FALSE(event_sock
.is_valid());
6279 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], 44));
6280 ASSERT_FALSE(event_sock
.is_valid());
6282 #ifndef HAVE_EVENTFD
6283 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_EVENTFD
));
6284 ASSERT_FALSE(event_sock
.is_valid());
6287 ASSERT_EQ(0, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_PIPE
));
6288 ASSERT_TRUE(event_sock
.is_valid());
6289 ASSERT_EQ(0, event_sock
.notify());
6290 ASSERT_EQ(1, read(pipe_fd
[0], buf
, 32));
6291 ASSERT_EQ('i', buf
[0]);
6297 TEST_F(TestLibRBD
, EventSocketEventfd
)
6300 EventSocket event_sock
;
6302 struct pollfd poll_fd
;
6305 event_fd
= eventfd(0, EFD_NONBLOCK
);
6306 ASSERT_NE(-1, event_fd
);
6308 ASSERT_FALSE(event_sock
.is_valid());
6310 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_NONE
));
6311 ASSERT_FALSE(event_sock
.is_valid());
6313 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, 44));
6314 ASSERT_FALSE(event_sock
.is_valid());
6316 ASSERT_EQ(0, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_EVENTFD
));
6317 ASSERT_TRUE(event_sock
.is_valid());
6318 ASSERT_EQ(0, event_sock
.notify());
6320 poll_fd
.fd
= event_fd
;
6321 poll_fd
.events
= POLLIN
;
6322 ASSERT_EQ(1, poll(&poll_fd
, 1, -1));
6323 ASSERT_TRUE(poll_fd
.revents
& POLLIN
);
6325 ASSERT_EQ(static_cast<ssize_t
>(sizeof(uint64_t)), read(event_fd
, buf
, 32));
6326 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf
));
6332 TEST_F(TestLibRBD
, ImagePollIO
)
6335 rados_ioctx_t ioctx
;
6336 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6340 std::string name
= get_temp_image_name();
6341 uint64_t size
= 2 << 20;
6342 int fd
= eventfd(0, EFD_NONBLOCK
);
6344 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6345 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6347 ASSERT_EQ(0, rbd_set_image_notification(image
, fd
, EVENT_SOCKET_TYPE_EVENTFD
));
6349 char test_data
[TEST_IO_SIZE
+ 1];
6350 char zero_data
[TEST_IO_SIZE
+ 1];
6353 for (i
= 0; i
< TEST_IO_SIZE
; ++i
)
6354 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
6355 test_data
[TEST_IO_SIZE
] = '\0';
6356 memset(zero_data
, 0, sizeof(zero_data
));
6358 for (i
= 0; i
< 5; ++i
)
6359 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6361 for (i
= 5; i
< 10; ++i
)
6362 ASSERT_PASSED(aio_write_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6364 for (i
= 5; i
< 10; ++i
)
6365 ASSERT_PASSED(aio_read_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6367 ASSERT_EQ(0, rbd_close(image
));
6368 rados_ioctx_destroy(ioctx
);
6374 static bool operator==(const image_spec_t
&lhs
, const image_spec_t
&rhs
) {
6375 return (lhs
.id
== rhs
.id
&& lhs
.name
== rhs
.name
);
6378 static bool operator==(const linked_image_spec_t
&lhs
,
6379 const linked_image_spec_t
&rhs
) {
6380 return (lhs
.pool_id
== rhs
.pool_id
&&
6381 lhs
.pool_name
== rhs
.pool_name
&&
6382 lhs
.pool_namespace
== rhs
.pool_namespace
&&
6383 lhs
.image_id
== rhs
.image_id
&&
6384 lhs
.image_name
== rhs
.image_name
&&
6385 lhs
.trash
== rhs
.trash
);
6388 static bool operator==(const mirror_peer_t
&lhs
, const mirror_peer_t
&rhs
) {
6389 return (lhs
.uuid
== rhs
.uuid
&&
6390 lhs
.cluster_name
== rhs
.cluster_name
&&
6391 lhs
.client_name
== rhs
.client_name
);
6394 static std::ostream
& operator<<(std::ostream
&os
, const mirror_peer_t
&peer
) {
6395 os
<< "uuid=" << peer
.uuid
<< ", "
6396 << "cluster=" << peer
.cluster_name
<< ", "
6397 << "client=" << peer
.client_name
;
6401 } // namespace librbd
6403 TEST_F(TestLibRBD
, Mirror
) {
6404 librados::IoCtx ioctx
;
6405 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6409 std::vector
<librbd::mirror_peer_t
> expected_peers
;
6410 std::vector
<librbd::mirror_peer_t
> peers
;
6411 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
6412 ASSERT_EQ(expected_peers
, peers
);
6415 ASSERT_EQ(-EINVAL
, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
6417 rbd_mirror_mode_t mirror_mode
;
6418 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6419 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED
, mirror_mode
);
6421 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
6422 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6424 // Add some images to the pool
6426 std::string parent_name
= get_temp_image_name();
6427 std::string child_name
= get_temp_image_name();
6428 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), 2 << 20,
6432 ASSERT_EQ(0, get_features(&old_format
, &features
));
6433 if ((features
& RBD_FEATURE_LAYERING
) != 0) {
6434 librbd::Image parent
;
6435 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
6436 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
6437 ASSERT_EQ(0, parent
.close());
6438 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
6439 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
6440 ASSERT_EQ(0, parent
.close());
6441 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6442 child_name
.c_str(), features
, &order
));
6445 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE
, mirror_mode
);
6447 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_POOL
));
6448 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6449 ASSERT_EQ(RBD_MIRROR_MODE_POOL
, mirror_mode
);
6453 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
6454 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid2
, "cluster2", "admin"));
6455 ASSERT_EQ(-EEXIST
, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster1", "foo"));
6456 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster3", "admin"));
6458 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
6459 auto sort_peers
= [](const librbd::mirror_peer_t
&lhs
,
6460 const librbd::mirror_peer_t
&rhs
) {
6461 return lhs
.uuid
< rhs
.uuid
;
6464 {uuid1
, "cluster1", "client"},
6465 {uuid2
, "cluster2", "admin"},
6466 {uuid3
, "cluster3", "admin"}};
6467 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
6468 ASSERT_EQ(expected_peers
, peers
);
6470 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, "uuid4"));
6471 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid2
));
6473 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_client(ioctx
, "uuid4", "new client"));
6474 ASSERT_EQ(0, rbd
.mirror_peer_set_client(ioctx
, uuid1
, "new client"));
6476 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_cluster(ioctx
, "uuid4",
6478 ASSERT_EQ(0, rbd
.mirror_peer_set_cluster(ioctx
, uuid3
, "new cluster"));
6480 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
6482 {uuid1
, "cluster1", "new client"},
6483 {uuid3
, "new cluster", "admin"}};
6484 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
6485 ASSERT_EQ(expected_peers
, peers
);
6487 ASSERT_EQ(-EBUSY
, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
6488 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid1
));
6489 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid3
));
6490 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
6493 TEST_F(TestLibRBD
, MirrorPeerAttributes
) {
6494 REQUIRE(!is_librados_test_stub(_rados
));
6496 librados::IoCtx ioctx
;
6497 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6500 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
6503 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid
, "remote_cluster", "client"));
6505 std::map
<std::string
, std::string
> attributes
;
6506 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_get_attributes(ioctx
, uuid
, &attributes
));
6507 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_attributes(ioctx
, "missing uuid",
6510 std::map
<std::string
, std::string
> expected_attributes
{
6511 {"mon_host", "1.2.3.4"},
6513 ASSERT_EQ(0, rbd
.mirror_peer_set_attributes(ioctx
, uuid
,
6514 expected_attributes
));
6516 ASSERT_EQ(0, rbd
.mirror_peer_get_attributes(ioctx
, uuid
,
6518 ASSERT_EQ(expected_attributes
, attributes
);
6520 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid
));
6521 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
6524 TEST_F(TestLibRBD
, FlushCacheWithCopyupOnExternalSnapshot
) {
6525 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6527 librados::IoCtx ioctx
;
6528 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6531 librbd::Image image
;
6532 std::string name
= get_temp_image_name();
6534 uint64_t size
= 1 << 18;
6537 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6538 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6541 bl
.append(std::string(size
, '1'));
6542 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
6543 ASSERT_EQ(0, image
.snap_create("one"));
6544 ASSERT_EQ(0, image
.snap_protect("one"));
6546 std::string clone_name
= this->get_temp_image_name();
6547 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
6548 RBD_FEATURE_LAYERING
, &order
));
6549 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
6551 librbd::Image image2
;
6552 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, clone_name
.c_str(), NULL
));
6554 // prepare CoW writeback that will be flushed on next op
6556 bl
.append(std::string(1, '1'));
6557 ASSERT_EQ(0, image
.flush());
6558 ASSERT_EQ(1, image
.write(0, 1, bl
));
6559 ASSERT_EQ(0, image2
.snap_create("snap1"));
6561 librbd::RBD::AioCompletion
*read_comp
=
6562 new librbd::RBD::AioCompletion(NULL
, NULL
);
6564 image
.aio_read(0, 1024, read_bl
, read_comp
);
6565 ASSERT_EQ(0, read_comp
->wait_for_complete());
6566 read_comp
->release();
6569 TEST_F(TestLibRBD
, ExclusiveLock
)
6571 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
6573 static char buf
[10];
6575 rados_ioctx_t ioctx
;
6576 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6578 std::string name
= get_temp_image_name();
6579 uint64_t size
= 2 << 20;
6581 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6584 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
6587 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
6588 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6589 ASSERT_TRUE(lock_owner
);
6591 rbd_lock_mode_t lock_mode
;
6592 char *lock_owners
[1];
6593 size_t max_lock_owners
= 0;
6594 ASSERT_EQ(-ERANGE
, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
6596 ASSERT_EQ(1U, max_lock_owners
);
6598 ASSERT_EQ(0, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
6600 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
6601 ASSERT_STRNE("", lock_owners
[0]);
6602 ASSERT_EQ(1U, max_lock_owners
);
6605 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
6607 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6608 ASSERT_FALSE(lock_owner
);
6610 ASSERT_EQ(-EOPNOTSUPP
, rbd_lock_break(image1
, RBD_LOCK_MODE_SHARED
, ""));
6611 ASSERT_EQ(-EBUSY
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
6614 ASSERT_EQ(0, rbd_lock_release(image1
));
6615 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6616 ASSERT_FALSE(lock_owner
);
6618 ASSERT_EQ(-ENOENT
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
6620 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
6622 ASSERT_EQ(-EROFS
, rbd_write(image1
, 0, sizeof(buf
), buf
));
6623 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image2
, 0, sizeof(buf
), buf
));
6625 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
6626 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6627 ASSERT_TRUE(lock_owner
);
6629 ASSERT_EQ(0, rbd_lock_release(image2
));
6630 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6631 ASSERT_FALSE(lock_owner
);
6633 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
6634 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6635 ASSERT_TRUE(lock_owner
);
6637 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image1
, 0, sizeof(buf
), buf
));
6638 ASSERT_EQ(-EROFS
, rbd_write(image2
, 0, sizeof(buf
), buf
));
6640 ASSERT_EQ(0, rbd_lock_release(image1
));
6641 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6642 ASSERT_FALSE(lock_owner
);
6646 const auto pingpong
= [&](int m_id
, rbd_image_t
&m_image
) {
6647 for (int i
= 0; i
< 10; i
++) {
6649 lock_guard
<mutex
> locker(lock
);
6650 if (owner_id
== m_id
) {
6651 std::cout
<< m_id
<< ": releasing exclusive lock" << std::endl
;
6652 EXPECT_EQ(0, rbd_lock_release(m_image
));
6654 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
6655 EXPECT_FALSE(lock_owner
);
6657 std::cout
<< m_id
<< ": exclusive lock released" << std::endl
;
6662 std::cout
<< m_id
<< ": acquiring exclusive lock" << std::endl
;
6665 r
= rbd_lock_acquire(m_image
, RBD_LOCK_MODE_EXCLUSIVE
);
6669 } while (r
== -EROFS
);
6673 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
6674 EXPECT_TRUE(lock_owner
);
6675 std::cout
<< m_id
<< ": exclusive lock acquired" << std::endl
;
6677 lock_guard
<mutex
> locker(lock
);
6680 usleep(rand() % 50000);
6683 lock_guard
<mutex
> locker(lock
);
6684 if (owner_id
== m_id
) {
6685 EXPECT_EQ(0, rbd_lock_release(m_image
));
6687 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
6688 EXPECT_FALSE(lock_owner
);
6692 thread
ping(bind(pingpong
, 1, ref(image1
)));
6693 thread
pong(bind(pingpong
, 2, ref(image2
)));
6698 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
6699 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
6700 ASSERT_TRUE(lock_owner
);
6702 ASSERT_EQ(0, rbd_close(image2
));
6704 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
6705 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
6706 ASSERT_TRUE(lock_owner
);
6708 ASSERT_EQ(0, rbd_close(image1
));
6709 rados_ioctx_destroy(ioctx
);
6712 TEST_F(TestLibRBD
, BreakLock
)
6714 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
6716 static char buf
[10];
6718 rados_t blacklist_cluster
;
6719 ASSERT_EQ("", connect_cluster(&blacklist_cluster
));
6721 rados_ioctx_t ioctx
, blacklist_ioctx
;
6722 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
6723 ASSERT_EQ(0, rados_ioctx_create(blacklist_cluster
, m_pool_name
.c_str(),
6726 std::string name
= get_temp_image_name();
6727 uint64_t size
= 2 << 20;
6729 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6731 rbd_image_t image
, blacklist_image
;
6732 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6733 ASSERT_EQ(0, rbd_open(blacklist_ioctx
, name
.c_str(), &blacklist_image
, NULL
));
6735 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_blacklist_on_break_lock", "true"));
6736 ASSERT_EQ(0, rbd_lock_acquire(blacklist_image
, RBD_LOCK_MODE_EXCLUSIVE
));
6738 rbd_lock_mode_t lock_mode
;
6739 char *lock_owners
[1];
6740 size_t max_lock_owners
= 1;
6741 ASSERT_EQ(0, rbd_lock_get_owners(image
, &lock_mode
, lock_owners
,
6743 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
6744 ASSERT_STRNE("", lock_owners
[0]);
6745 ASSERT_EQ(1U, max_lock_owners
);
6747 ASSERT_EQ(0, rbd_lock_break(image
, RBD_LOCK_MODE_EXCLUSIVE
, lock_owners
[0]));
6748 ASSERT_EQ(0, rbd_lock_acquire(image
, RBD_LOCK_MODE_EXCLUSIVE
));
6749 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blacklist_cluster
));
6751 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image
, 0, sizeof(buf
), buf
));
6752 ASSERT_EQ(-EBLACKLISTED
, rbd_write(blacklist_image
, 0, sizeof(buf
), buf
));
6754 ASSERT_EQ(0, rbd_close(image
));
6755 ASSERT_EQ(0, rbd_close(blacklist_image
));
6757 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
6759 rados_ioctx_destroy(ioctx
);
6760 rados_ioctx_destroy(blacklist_ioctx
);
6761 rados_shutdown(blacklist_cluster
);
6764 TEST_F(TestLibRBD
, DiscardAfterWrite
)
6766 REQUIRE(!is_skip_partial_discard_enabled());
6768 librados::IoCtx ioctx
;
6769 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6772 std::string name
= get_temp_image_name();
6773 uint64_t size
= 1 << 20;
6775 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6777 librbd::Image image
;
6778 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6780 // enable writeback cache
6781 ASSERT_EQ(0, image
.flush());
6784 bl
.append(std::string(256, '1'));
6786 librbd::RBD::AioCompletion
*write_comp
=
6787 new librbd::RBD::AioCompletion(NULL
, NULL
);
6788 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
6789 ASSERT_EQ(0, write_comp
->wait_for_complete());
6790 write_comp
->release();
6792 librbd::RBD::AioCompletion
*discard_comp
=
6793 new librbd::RBD::AioCompletion(NULL
, NULL
);
6794 ASSERT_EQ(0, image
.aio_discard(0, 256, discard_comp
));
6795 ASSERT_EQ(0, discard_comp
->wait_for_complete());
6796 discard_comp
->release();
6798 librbd::RBD::AioCompletion
*read_comp
=
6799 new librbd::RBD::AioCompletion(NULL
, NULL
);
6801 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
6802 ASSERT_EQ(0, read_comp
->wait_for_complete());
6803 ASSERT_EQ(bl
.length(), read_comp
->get_return_value());
6804 ASSERT_TRUE(read_bl
.is_zero());
6805 read_comp
->release();
6808 TEST_F(TestLibRBD
, DefaultFeatures
) {
6809 std::string orig_default_features
;
6810 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", orig_default_features
));
6811 BOOST_SCOPE_EXIT_ALL(orig_default_features
) {
6812 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features",
6813 orig_default_features
.c_str()));
6816 std::list
<std::pair
<std::string
, std::string
> > feature_names_to_bitmask
= {
6817 {"", orig_default_features
},
6819 {"layering, exclusive-lock", "5"},
6820 {"exclusive-lock,journaling", "68"},
6824 for (auto &pair
: feature_names_to_bitmask
) {
6825 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features", pair
.first
.c_str()));
6826 std::string features
;
6827 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", features
));
6828 ASSERT_EQ(pair
.second
, features
);
6832 TEST_F(TestLibRBD
, TestTrashMoveAndPurge
) {
6833 REQUIRE_FORMAT_V2();
6835 librados::IoCtx ioctx
;
6836 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6839 std::string name
= get_temp_image_name();
6841 uint64_t size
= 1 << 18;
6843 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6845 librbd::Image image
;
6846 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
6848 std::string image_id
;
6849 ASSERT_EQ(0, image
.get_id(&image_id
));
6852 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 0));
6854 std::vector
<std::string
> images
;
6855 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
6856 for (const auto& image
: images
) {
6857 ASSERT_TRUE(image
!= name
);
6860 librbd::trash_image_info_t info
;
6861 ASSERT_EQ(-ENOENT
, rbd
.trash_get(ioctx
, "dummy image id", &info
));
6862 ASSERT_EQ(0, rbd
.trash_get(ioctx
, image_id
.c_str(), &info
));
6863 ASSERT_EQ(image_id
, info
.id
);
6865 std::vector
<librbd::trash_image_info_t
> entries
;
6866 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
6867 ASSERT_FALSE(entries
.empty());
6868 ASSERT_EQ(entries
.begin()->id
, image_id
);
6872 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
6874 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
6875 ASSERT_TRUE(entries
.empty());
6878 TEST_F(TestLibRBD
, TestTrashMoveAndPurgeNonExpiredDelay
) {
6879 REQUIRE_FORMAT_V2();
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();
6887 uint64_t size
= 1 << 18;
6889 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6891 librbd::Image image
;
6892 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
6894 std::string image_id
;
6895 ASSERT_EQ(0, image
.get_id(&image_id
));
6898 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 100));
6901 ASSERT_EQ(-EPERM
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
6905 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
6909 TEST_F(TestLibRBD
, TestTrashPurge
) {
6910 REQUIRE_FORMAT_V2();
6912 librados::IoCtx ioctx
;
6913 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6916 std::string name1
= get_temp_image_name();
6917 std::string name2
= get_temp_image_name();
6919 uint64_t size
= 1 << 18;
6921 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name1
.c_str(), size
, &order
));
6922 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
6924 librbd::Image image1
;
6925 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name1
.c_str(), nullptr));
6927 std::string image_id1
;
6928 ASSERT_EQ(0, image1
.get_id(&image_id1
));
6931 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name1
.c_str(), 0));
6933 librbd::Image image2
;
6934 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), nullptr));
6935 ceph::bufferlist bl
;
6936 bl
.append(std::string(1024, '0'));
6937 ASSERT_EQ(1024, image2
.write(0, 1024, bl
));
6939 std::string image_id2
;
6940 ASSERT_EQ(0, image2
.get_id(&image_id2
));
6943 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name2
.c_str(), 100));
6944 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, 0, -1));
6946 std::vector
<librbd::trash_image_info_t
> entries
;
6947 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
6948 ASSERT_EQ(1U, entries
.size());
6949 ASSERT_EQ(image_id2
, entries
[0].id
);
6950 ASSERT_EQ(name2
, entries
[0].name
);
6953 struct timespec now
;
6954 clock_gettime(CLOCK_REALTIME
, &now
);
6955 float threshold
= 0.0;
6956 if (!is_librados_test_stub(_rados
)) {
6957 // real cluster usage reports have a long latency to update
6961 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, now
.tv_sec
+1000, threshold
));
6962 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
6963 ASSERT_EQ(0U, entries
.size());
6966 TEST_F(TestLibRBD
, TestTrashMoveAndRestore
) {
6967 REQUIRE_FORMAT_V2();
6969 librados::IoCtx ioctx
;
6970 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6973 std::string name
= get_temp_image_name();
6975 uint64_t size
= 1 << 18;
6977 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6979 librbd::Image image
;
6980 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
6982 std::string image_id
;
6983 ASSERT_EQ(0, image
.get_id(&image_id
));
6986 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 10));
6988 std::vector
<std::string
> images
;
6989 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
6990 for (const auto& image
: images
) {
6991 ASSERT_TRUE(image
!= name
);
6994 std::vector
<librbd::trash_image_info_t
> entries
;
6995 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
6996 ASSERT_FALSE(entries
.empty());
6997 ASSERT_EQ(entries
.begin()->id
, image_id
);
7000 ASSERT_EQ(0, rbd
.trash_restore(ioctx
, image_id
.c_str(), ""));
7001 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7002 ASSERT_FALSE(images
.empty());
7004 for (const auto& image
: images
) {
7005 if (image
== name
) {
7013 TEST_F(TestLibRBD
, TestListWatchers
) {
7014 librados::IoCtx ioctx
;
7015 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7018 std::string name
= get_temp_image_name();
7020 uint64_t size
= 1 << 18;
7022 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7024 librbd::Image image
;
7025 std::list
<librbd::image_watcher_t
> watchers
;
7028 ASSERT_EQ(0, rbd
.open_read_only(ioctx
, image
, name
.c_str(), nullptr));
7029 ASSERT_EQ(0, image
.list_watchers(watchers
));
7030 ASSERT_EQ(0U, watchers
.size());
7031 ASSERT_EQ(0, image
.close());
7034 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7035 ASSERT_EQ(0, image
.list_watchers(watchers
));
7036 ASSERT_EQ(1U, watchers
.size());
7037 ASSERT_EQ(0, image
.close());
7040 TEST_F(TestLibRBD
, TestSetSnapById
) {
7041 librados::IoCtx ioctx
;
7042 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7045 std::string name
= get_temp_image_name();
7047 uint64_t size
= 1 << 18;
7049 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7051 librbd::Image image
;
7052 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7053 ASSERT_EQ(0, image
.snap_create("snap"));
7055 vector
<librbd::snap_info_t
> snaps
;
7056 ASSERT_EQ(0, image
.snap_list(snaps
));
7057 ASSERT_EQ(1U, snaps
.size());
7059 ASSERT_EQ(0, image
.snap_set_by_id(snaps
[0].id
));
7060 ASSERT_EQ(0, image
.snap_set_by_id(CEPH_NOSNAP
));
7063 TEST_F(TestLibRBD
, Namespaces
) {
7064 rados_ioctx_t ioctx
;
7065 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
7066 rados_remove(ioctx
, RBD_NAMESPACE
);
7068 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name1"));
7069 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name2"));
7070 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name3"));
7071 ASSERT_EQ(0, rbd_namespace_remove(ioctx
, "name2"));
7074 size_t max_size
= sizeof(names
);
7075 int len
= rbd_namespace_list(ioctx
, names
, &max_size
);
7077 std::vector
<std::string
> cpp_names
;
7078 for (char* cur_name
= names
; cur_name
< names
+ len
; ) {
7079 cpp_names
.push_back(cur_name
);
7080 cur_name
+= strlen(cur_name
) + 1;
7082 ASSERT_EQ(2U, cpp_names
.size());
7083 ASSERT_EQ("name1", cpp_names
[0]);
7084 ASSERT_EQ("name3", cpp_names
[1]);
7086 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name2", &exists
));
7087 ASSERT_FALSE(exists
);
7088 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name3", &exists
));
7089 ASSERT_TRUE(exists
);
7090 rados_ioctx_destroy(ioctx
);
7093 TEST_F(TestLibRBD
, NamespacesPP
) {
7094 librados::IoCtx ioctx
;
7095 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7096 ioctx
.remove(RBD_NAMESPACE
);
7099 ASSERT_EQ(-EINVAL
, rbd
.namespace_create(ioctx
, ""));
7100 ASSERT_EQ(-EINVAL
, rbd
.namespace_remove(ioctx
, ""));
7102 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name1"));
7103 ASSERT_EQ(-EEXIST
, rbd
.namespace_create(ioctx
, "name1"));
7104 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name2"));
7105 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name3"));
7106 ASSERT_EQ(0, rbd
.namespace_remove(ioctx
, "name2"));
7107 ASSERT_EQ(-ENOENT
, rbd
.namespace_remove(ioctx
, "name2"));
7109 std::vector
<std::string
> names
;
7110 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7111 ASSERT_EQ(2U, names
.size());
7112 ASSERT_EQ("name1", names
[0]);
7113 ASSERT_EQ("name3", names
[1]);
7115 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name2", &exists
));
7116 ASSERT_FALSE(exists
);
7117 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name3", &exists
));
7118 ASSERT_TRUE(exists
);
7120 librados::IoCtx ns_io_ctx
;
7121 ns_io_ctx
.dup(ioctx
);
7123 std::string name
= get_temp_image_name();
7125 uint64_t features
= 0;
7126 if (!get_features(&features
)) {
7127 // old format doesn't support namespaces
7128 ns_io_ctx
.set_namespace("name1");
7129 ASSERT_EQ(-EINVAL
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0,
7134 ns_io_ctx
.set_namespace("missing");
7135 ASSERT_EQ(-ENOENT
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7137 ns_io_ctx
.set_namespace("name1");
7138 ASSERT_EQ(0, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7139 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7141 std::string image_id
;
7143 librbd::Image image
;
7144 ASSERT_EQ(-ENOENT
, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7145 ASSERT_EQ(0, rbd
.open(ns_io_ctx
, image
, name
.c_str(), NULL
));
7146 ASSERT_EQ(0, get_image_id(image
, &image_id
));
7149 ASSERT_EQ(-ENOENT
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7150 ASSERT_EQ(0, rbd
.trash_move(ns_io_ctx
, name
.c_str(), 0));
7151 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7154 ASSERT_EQ(-ENOENT
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7156 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ns_io_ctx
, image_id
.c_str(),
7158 ASSERT_EQ(0, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7161 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7162 ASSERT_EQ(1U, names
.size());
7163 ASSERT_EQ("name3", names
[0]);
7166 TEST_F(TestLibRBD
, Migration
) {
7169 ASSERT_EQ(0, get_features(&old_format
, &features
));
7171 rados_ioctx_t ioctx
;
7172 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7173 BOOST_SCOPE_EXIT(&ioctx
) {
7174 rados_ioctx_destroy(ioctx
);
7175 } BOOST_SCOPE_EXIT_END
;
7178 std::string name
= get_temp_image_name();
7179 uint64_t size
= 2 << 20;
7180 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7182 rbd_image_options_t image_options
;
7183 rbd_image_options_create(&image_options
);
7184 BOOST_SCOPE_EXIT(&image_options
) {
7185 rbd_image_options_destroy(image_options
);
7186 } BOOST_SCOPE_EXIT_END
;
7188 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7191 rbd_image_migration_status_t status
;
7192 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7194 ASSERT_EQ(status
.source_pool_id
, rados_ioctx_get_id(ioctx
));
7195 ASSERT_EQ(status
.source_image_name
, name
);
7197 ASSERT_EQ(status
.source_image_id
, string());
7199 ASSERT_NE(status
.source_image_id
, string());
7200 ASSERT_EQ(-EROFS
, rbd_trash_remove(ioctx
, status
.source_image_id
, false));
7201 ASSERT_EQ(-EINVAL
, rbd_trash_restore(ioctx
, status
.source_image_id
, name
.c_str()));
7203 ASSERT_EQ(status
.dest_pool_id
, rados_ioctx_get_id(ioctx
));
7204 ASSERT_EQ(status
.dest_image_name
, name
);
7205 ASSERT_NE(status
.dest_image_id
, string());
7206 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
7207 rbd_migration_status_cleanup(&status
);
7209 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, name
.c_str()));
7210 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, name
.c_str(), 0));
7212 ASSERT_EQ(0, rbd_migration_execute(ioctx
, name
.c_str()));
7214 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7216 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
7217 rbd_migration_status_cleanup(&status
);
7219 ASSERT_EQ(0, rbd_migration_commit(ioctx
, name
.c_str()));
7221 std::string new_name
= get_temp_image_name();
7223 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
,
7224 new_name
.c_str(), image_options
));
7226 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, new_name
.c_str()));
7227 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, new_name
.c_str(), 0));
7229 ASSERT_EQ(0, rbd_migration_abort(ioctx
, name
.c_str()));
7232 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7233 EXPECT_EQ(0, rbd_close(image
));
7236 TEST_F(TestLibRBD
, MigrationPP
) {
7239 ASSERT_EQ(0, get_features(&old_format
, &features
));
7241 librados::IoCtx ioctx
;
7242 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7245 std::string name
= get_temp_image_name();
7246 uint64_t size
= 2 << 20;
7248 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7250 librbd::ImageOptions image_options
;
7252 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7255 librbd::image_migration_status_t status
;
7256 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
7258 ASSERT_EQ(status
.source_pool_id
, ioctx
.get_id());
7259 ASSERT_EQ(status
.source_image_name
, name
);
7261 ASSERT_EQ(status
.source_image_id
, "");
7263 ASSERT_NE(status
.source_image_id
, "");
7264 ASSERT_EQ(-EROFS
, rbd
.trash_remove(ioctx
, status
.source_image_id
.c_str(), false));
7265 ASSERT_EQ(-EINVAL
, rbd
.trash_restore(ioctx
, status
.source_image_id
.c_str(), name
.c_str()));
7267 ASSERT_EQ(status
.dest_pool_id
, ioctx
.get_id());
7268 ASSERT_EQ(status
.dest_image_name
, name
);
7269 ASSERT_NE(status
.dest_image_id
, "");
7270 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
7272 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, name
.c_str()));
7273 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7275 ASSERT_EQ(0, rbd
.migration_execute(ioctx
, name
.c_str()));
7277 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
7279 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
7281 ASSERT_EQ(0, rbd
.migration_commit(ioctx
, name
.c_str()));
7283 std::string new_name
= get_temp_image_name();
7285 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
,
7286 new_name
.c_str(), image_options
));
7288 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, new_name
.c_str()));
7289 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, new_name
.c_str(), 0));
7291 ASSERT_EQ(0, rbd
.migration_abort(ioctx
, name
.c_str()));
7293 librbd::Image image
;
7294 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7297 TEST_F(TestLibRBD
, TestGetAccessTimestamp
)
7299 REQUIRE_FORMAT_V2();
7301 rados_ioctx_t ioctx
;
7302 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7306 std::string name
= get_temp_image_name();
7307 uint64_t size
= 2 << 20;
7308 struct timespec timestamp
;
7310 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7311 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7313 ASSERT_EQ(0, rbd_get_access_timestamp(image
, ×tamp
));
7314 ASSERT_LT(0, timestamp
.tv_sec
);
7316 ASSERT_PASSED(validate_object_map
, image
);
7317 ASSERT_EQ(0, rbd_close(image
));
7319 rados_ioctx_destroy(ioctx
);
7322 TEST_F(TestLibRBD
, TestGetModifyTimestamp
)
7324 REQUIRE_FORMAT_V2();
7326 rados_ioctx_t ioctx
;
7327 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7331 std::string name
= get_temp_image_name();
7332 uint64_t size
= 2 << 20;
7333 struct timespec timestamp
;
7335 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7336 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7337 ASSERT_EQ(0, rbd_get_modify_timestamp(image
, ×tamp
));
7338 ASSERT_LT(0, timestamp
.tv_sec
);
7340 ASSERT_PASSED(validate_object_map
, image
);
7341 ASSERT_EQ(0, rbd_close(image
));
7343 rados_ioctx_destroy(ioctx
);
7346 TEST_F(TestLibRBD
, ZeroOverlapFlatten
) {
7347 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7349 librados::IoCtx ioctx
;
7350 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7353 librbd::Image parent_image
;
7354 std::string name
= get_temp_image_name();
7359 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7360 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
7363 ASSERT_EQ(0, parent_image
.features(&features
));
7365 ASSERT_EQ(0, parent_image
.snap_create("snap"));
7366 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
7368 std::string clone_name
= this->get_temp_image_name();
7369 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
7372 librbd::Image clone_image
;
7373 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
7374 ASSERT_EQ(0, clone_image
.resize(0));
7375 ASSERT_EQ(0, clone_image
.flatten());
7378 TEST_F(TestLibRBD
, PoolMetadata
)
7380 REQUIRE_FORMAT_V2();
7382 rados_ioctx_t ioctx
;
7383 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7387 size_t keys_len
= sizeof(keys
);
7388 size_t vals_len
= sizeof(vals
);
7390 memset_rand(keys
, keys_len
);
7391 memset_rand(vals
, vals_len
);
7393 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7395 ASSERT_EQ(0U, keys_len
);
7396 ASSERT_EQ(0U, vals_len
);
7399 size_t value_len
= sizeof(value
);
7400 memset_rand(value
, value_len
);
7402 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
7403 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key2", "value2"));
7404 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
7405 ASSERT_STREQ(value
, "value1");
7407 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
7408 ASSERT_EQ(value_len
, strlen("value1") + 1);
7410 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7412 keys_len
= sizeof(keys
);
7413 vals_len
= sizeof(vals
);
7414 memset_rand(keys
, keys_len
);
7415 memset_rand(vals
, vals_len
);
7416 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7418 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
7419 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
7420 ASSERT_STREQ(keys
, "key1");
7421 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
7422 ASSERT_STREQ(vals
, "value1");
7423 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
7425 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
7426 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_remove(ioctx
, "key3"));
7427 value_len
= sizeof(value
);
7428 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_get(ioctx
, "key3", value
, &value_len
));
7429 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7431 ASSERT_EQ(keys_len
, strlen("key2") + 1);
7432 ASSERT_EQ(vals_len
, strlen("value2") + 1);
7433 ASSERT_STREQ(keys
, "key2");
7434 ASSERT_STREQ(vals
, "value2");
7436 // test config setting
7437 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
7438 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7439 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
7440 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7442 // test short buffer cases
7443 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
7444 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key3", "value3"));
7445 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key4", "value4"));
7447 keys_len
= strlen("key1") + 1;
7448 vals_len
= strlen("value1") + 1;
7449 memset_rand(keys
, keys_len
);
7450 memset_rand(vals
, vals_len
);
7451 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 1, keys
, &keys_len
, vals
,
7453 ASSERT_EQ(keys_len
, strlen("key1") + 1);
7454 ASSERT_EQ(vals_len
, strlen("value1") + 1);
7455 ASSERT_STREQ(keys
, "key1");
7456 ASSERT_STREQ(vals
, "value1");
7458 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 2, keys
, &keys_len
, vals
,
7460 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
7461 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
7463 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
7465 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
7466 1 + strlen("key4") + 1);
7467 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
7468 strlen("value3") + 1 + strlen("value4") + 1);
7470 // test `start` param
7471 keys_len
= sizeof(keys
);
7472 vals_len
= sizeof(vals
);
7473 memset_rand(keys
, keys_len
);
7474 memset_rand(vals
, vals_len
);
7475 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "key2", 0, keys
, &keys_len
, vals
,
7477 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
7478 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
7479 ASSERT_STREQ(keys
, "key3");
7480 ASSERT_STREQ(vals
, "value3");
7483 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
7484 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key2"));
7485 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key3"));
7486 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key4"));
7487 rados_ioctx_destroy(ioctx
);
7490 TEST_F(TestLibRBD
, PoolMetadataPP
)
7492 REQUIRE_FORMAT_V2();
7496 map
<string
, bufferlist
> pairs
;
7498 librados::IoCtx ioctx
;
7499 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7501 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
7502 ASSERT_TRUE(pairs
.empty());
7504 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
7505 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key2", "value2"));
7506 ASSERT_EQ(0, rbd
.pool_metadata_get(ioctx
, "key1", &value
));
7507 ASSERT_EQ(value
, "value1");
7508 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
7509 ASSERT_EQ(2U, pairs
.size());
7510 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
7511 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
7513 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
7514 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_remove(ioctx
, "key3"));
7515 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_get(ioctx
, "key3", &value
));
7517 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
7518 ASSERT_EQ(1U, pairs
.size());
7519 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
7521 // test `start` param
7522 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
7523 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key3", "value3"));
7526 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "key2", 0, &pairs
));
7527 ASSERT_EQ(1U, pairs
.size());
7528 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
7530 // test config setting
7531 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
7532 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7533 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
7534 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7537 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
7538 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key2"));
7539 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key3"));
7542 TEST_F(TestLibRBD
, Config
)
7544 REQUIRE_FORMAT_V2();
7546 rados_ioctx_t ioctx
;
7547 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7549 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7551 rbd_config_option_t options
[1024];
7552 int max_options
= 0;
7553 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
7554 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
7555 ASSERT_GT(max_options
, 0);
7556 ASSERT_LT(max_options
, 1024);
7557 for (int i
= 0; i
< max_options
; i
++) {
7558 if (options
[i
].name
== std::string("rbd_cache")) {
7559 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
7560 ASSERT_STREQ("false", options
[i
].value
);
7562 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7565 rbd_config_pool_list_cleanup(options
, max_options
);
7569 std::string name
= get_temp_image_name();
7570 uint64_t size
= 2 << 20;
7572 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7573 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7575 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
7576 for (int i
= 0; i
< max_options
; i
++) {
7577 if (options
[i
].name
== std::string("rbd_cache")) {
7578 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
7579 ASSERT_STREQ("false", options
[i
].value
);
7581 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7584 rbd_config_image_list_cleanup(options
, max_options
);
7586 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_cache", "true"));
7588 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
7589 for (int i
= 0; i
< max_options
; i
++) {
7590 if (options
[i
].name
== std::string("rbd_cache")) {
7591 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_IMAGE
);
7592 ASSERT_STREQ("true", options
[i
].value
);
7594 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7597 rbd_config_image_list_cleanup(options
, max_options
);
7599 ASSERT_EQ(0, rbd_metadata_remove(image
, "conf_rbd_cache"));
7601 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
7602 for (int i
= 0; i
< max_options
; i
++) {
7603 if (options
[i
].name
== std::string("rbd_cache")) {
7604 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
7605 ASSERT_STREQ("false", options
[i
].value
);
7607 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7610 rbd_config_image_list_cleanup(options
, max_options
);
7612 ASSERT_EQ(0, rbd_close(image
));
7614 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7616 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
7617 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
7618 for (int i
= 0; i
< max_options
; i
++) {
7619 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
7621 rbd_config_pool_list_cleanup(options
, max_options
);
7623 rados_ioctx_destroy(ioctx
);
7626 TEST_F(TestLibRBD
, ConfigPP
)
7628 REQUIRE_FORMAT_V2();
7633 librados::IoCtx ioctx
;
7634 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7636 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
7638 std::vector
<librbd::config_option_t
> options
;
7639 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
7640 for (auto &option
: options
) {
7641 if (option
.name
== std::string("rbd_cache")) {
7642 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
7643 ASSERT_EQ("false", option
.value
);
7645 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7650 std::string name
= get_temp_image_name();
7651 uint64_t size
= 2 << 20;
7652 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7654 librbd::Image image
;
7655 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7658 ASSERT_EQ(0, image
.config_list(&options
));
7659 for (auto &option
: options
) {
7660 if (option
.name
== std::string("rbd_cache")) {
7661 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
7662 ASSERT_EQ("false", option
.value
);
7664 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7668 ASSERT_EQ(0, image
.metadata_set("conf_rbd_cache", "true"));
7671 ASSERT_EQ(0, image
.config_list(&options
));
7672 for (auto &option
: options
) {
7673 if (option
.name
== std::string("rbd_cache")) {
7674 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_IMAGE
);
7675 ASSERT_EQ("true", option
.value
);
7677 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7681 ASSERT_EQ(0, image
.metadata_remove("conf_rbd_cache"));
7684 ASSERT_EQ(0, image
.config_list(&options
));
7685 for (auto &option
: options
) {
7686 if (option
.name
== std::string("rbd_cache")) {
7687 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
7688 ASSERT_EQ("false", option
.value
);
7690 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7694 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
7697 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
7698 for (auto &option
: options
) {
7699 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
7703 TEST_F(TestLibRBD
, PoolStatsPP
)
7705 REQUIRE_FORMAT_V2();
7707 librados::IoCtx ioctx
;
7708 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
7711 std::string image_name
;
7712 uint64_t size
= 2 << 20;
7713 uint64_t expected_size
= 0;
7714 for (size_t idx
= 0; idx
< 4; ++idx
) {
7715 image_name
= get_temp_image_name();
7718 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, image_name
.c_str(), size
, &order
));
7719 expected_size
+= size
;
7722 librbd::Image image
;
7723 ASSERT_EQ(0, rbd
.open(ioctx
, image
, image_name
.c_str(), NULL
));
7724 ASSERT_EQ(0, image
.snap_create("snap1"));
7725 ASSERT_EQ(0, image
.resize(0));
7726 ASSERT_EQ(0, image
.close());
7727 uint64_t expect_head_size
= (expected_size
- size
);
7729 uint64_t image_count
;
7730 uint64_t provisioned_bytes
;
7731 uint64_t max_provisioned_bytes
;
7732 uint64_t snap_count
;
7733 uint64_t trash_image_count
;
7734 uint64_t trash_provisioned_bytes
;
7735 uint64_t trash_max_provisioned_bytes
;
7736 uint64_t trash_snap_count
;
7738 librbd::PoolStats pool_stats1
;
7739 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGES
, &image_count
);
7740 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
,
7741 &provisioned_bytes
);
7742 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
7744 ASSERT_EQ(4U, image_count
);
7745 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
7747 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
,
7748 &max_provisioned_bytes
);
7749 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
7750 ASSERT_EQ(4U, image_count
);
7751 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
7752 ASSERT_EQ(expected_size
, max_provisioned_bytes
);
7754 librbd::PoolStats pool_stats2
;
7755 pool_stats2
.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
, &snap_count
);
7756 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
7757 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
7758 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats2
));
7759 ASSERT_EQ(1U, snap_count
);
7760 ASSERT_EQ(0U, trash_image_count
);
7761 ASSERT_EQ(0U, trash_snap_count
);
7763 ASSERT_EQ(0, rbd
.trash_move(ioctx
, image_name
.c_str(), 0));
7765 librbd::PoolStats pool_stats3
;
7766 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
7767 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
,
7768 &trash_provisioned_bytes
);
7769 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
,
7770 &trash_max_provisioned_bytes
);
7771 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
7772 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats3
));
7773 ASSERT_EQ(1U, trash_image_count
);
7774 ASSERT_EQ(0U, trash_provisioned_bytes
);
7775 ASSERT_EQ(size
, trash_max_provisioned_bytes
);
7776 ASSERT_EQ(1U, trash_snap_count
);
7779 TEST_F(TestLibRBD
, ImageSpec
) {
7780 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7782 librados::IoCtx ioctx
;
7783 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
7786 librbd::Image parent_image
;
7787 std::string name
= get_temp_image_name();
7792 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7793 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
7795 std::string parent_id
;
7796 ASSERT_EQ(0, parent_image
.get_id(&parent_id
));
7799 ASSERT_EQ(0, parent_image
.features(&features
));
7801 ASSERT_EQ(0, parent_image
.snap_create("snap"));
7802 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
7804 std::string clone_name
= this->get_temp_image_name();
7805 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
7808 librbd::Image clone_image
;
7809 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
7811 std::string clone_id
;
7812 ASSERT_EQ(0, clone_image
.get_id(&clone_id
));
7814 std::vector
<librbd::image_spec_t
> images
;
7815 ASSERT_EQ(0, rbd
.list2(ioctx
, &images
));
7817 std::vector
<librbd::image_spec_t
> expected_images
{
7818 {.id
= parent_id
, .name
= name
},
7819 {.id
= clone_id
, .name
= clone_name
}
7821 std::sort(expected_images
.begin(), expected_images
.end(),
7822 [](const librbd::image_spec_t
& lhs
, const librbd::image_spec_t
&rhs
) {
7823 return lhs
.name
< rhs
.name
;
7825 ASSERT_EQ(expected_images
, images
);
7827 librbd::linked_image_spec_t parent_image_spec
;
7828 librbd::snap_spec_t parent_snap_spec
;
7829 ASSERT_EQ(0, clone_image
.get_parent(&parent_image_spec
, &parent_snap_spec
));
7831 librbd::linked_image_spec_t expected_parent_image_spec
{
7832 .pool_id
= ioctx
.get_id(),
7833 .pool_name
= ioctx
.get_pool_name(),
7834 .pool_namespace
= ioctx
.get_namespace(),
7835 .image_id
= parent_id
,
7839 ASSERT_EQ(expected_parent_image_spec
, parent_image_spec
);
7840 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER
, parent_snap_spec
.namespace_type
);
7841 ASSERT_EQ("snap", parent_snap_spec
.name
);
7843 std::vector
<librbd::linked_image_spec_t
> children
;
7844 ASSERT_EQ(0, parent_image
.list_children3(&children
));
7846 std::vector
<librbd::linked_image_spec_t
> expected_children
{
7848 .pool_id
= ioctx
.get_id(),
7849 .pool_name
= ioctx
.get_pool_name(),
7850 .pool_namespace
= ioctx
.get_namespace(),
7851 .image_id
= clone_id
,
7852 .image_name
= clone_name
,
7856 ASSERT_EQ(expected_children
, children
);
7859 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
7860 ASSERT_EQ(expected_children
, children
);
7862 ASSERT_EQ(0, clone_image
.snap_create("snap"));
7863 ASSERT_EQ(0, clone_image
.snap_protect("snap"));
7865 auto grand_clone_name
= this->get_temp_image_name();
7866 ASSERT_EQ(0, rbd
.clone(ioctx
, clone_name
.c_str(), "snap", ioctx
,
7867 grand_clone_name
.c_str(), features
, &order
));
7868 librbd::Image grand_clone_image
;
7869 ASSERT_EQ(0, rbd
.open(ioctx
, grand_clone_image
, grand_clone_name
.c_str(),
7871 std::string grand_clone_id
;
7872 ASSERT_EQ(0, grand_clone_image
.get_id(&grand_clone_id
));
7875 ASSERT_EQ(0, parent_image
.list_children3(&children
));
7876 ASSERT_EQ(expected_children
, children
);
7879 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
7880 expected_children
.push_back(
7882 .pool_id
= ioctx
.get_id(),
7883 .pool_name
= ioctx
.get_pool_name(),
7884 .pool_namespace
= ioctx
.get_namespace(),
7885 .image_id
= grand_clone_id
,
7886 .image_name
= grand_clone_name
,
7890 ASSERT_EQ(expected_children
, children
);
7893 TEST_F(TestLibRBD
, SnapRemoveWithChildMissing
)
7895 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7896 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
7897 BOOST_SCOPE_EXIT_ALL(&) {
7898 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
7902 rados_ioctx_t ioctx1
, ioctx2
;
7903 string pool_name1
= create_pool(true);
7904 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
7905 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx2
));
7909 rbd_image_t parent
, child1
, child2
, child3
;
7911 char child_id1
[4096];
7912 char child_id2
[4096];
7913 char child_id3
[4096];
7915 ASSERT_EQ(0, get_features(&old_format
, &features
));
7916 ASSERT_FALSE(old_format
);
7917 std::string parent_name
= get_temp_image_name();
7918 std::string child_name1
= get_temp_image_name();
7919 std::string child_name2
= get_temp_image_name();
7920 std::string child_name3
= get_temp_image_name();
7921 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
7923 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
7924 ASSERT_EQ(0, rbd_snap_create(parent
, "snap1"));
7925 ASSERT_EQ(0, rbd_snap_create(parent
, "snap2"));
7927 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap1",
7928 ioctx2
, child_name1
.c_str(), features
, &order
));
7929 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
7930 ioctx1
, child_name2
.c_str(), features
, &order
));
7931 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
7932 ioctx2
, child_name3
.c_str(), features
, &order
));
7934 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &child1
, NULL
));
7935 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &child2
, NULL
));
7936 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &child3
, NULL
));
7937 ASSERT_EQ(0, rbd_get_id(child1
, child_id1
, sizeof(child_id1
)));
7938 ASSERT_EQ(0, rbd_get_id(child2
, child_id2
, sizeof(child_id2
)));
7939 ASSERT_EQ(0, rbd_get_id(child3
, child_id3
, sizeof(child_id3
)));
7940 test_list_children2(parent
, 3,
7941 child_id1
, m_pool_name
.c_str(), child_name1
.c_str(), false,
7942 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
7943 child_id3
, m_pool_name
.c_str(), child_name3
.c_str(), false);
7945 size_t max_size
= 10;
7946 rbd_linked_image_spec_t children
[max_size
];
7947 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
7948 ASSERT_EQ(3, static_cast<int>(max_size
));
7949 rbd_linked_image_spec_list_cleanup(children
, max_size
);
7951 ASSERT_EQ(0, rbd_close(child1
));
7952 ASSERT_EQ(0, rbd_close(child2
));
7953 ASSERT_EQ(0, rbd_close(child3
));
7954 rados_ioctx_destroy(ioctx2
);
7955 ASSERT_EQ(0, rados_pool_delete(_cluster
, m_pool_name
.c_str()));
7956 _pool_names
.erase(std::remove(_pool_names
.begin(),
7957 _pool_names
.end(), m_pool_name
),
7959 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
7961 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
7962 ASSERT_EQ(3, static_cast<int>(max_size
));
7963 rbd_linked_image_spec_list_cleanup(children
, max_size
);
7964 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap1"));
7965 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
7966 ASSERT_EQ(2, static_cast<int>(max_size
));
7967 rbd_linked_image_spec_list_cleanup(children
, max_size
);
7969 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
7970 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
7971 ASSERT_EQ(1, static_cast<int>(max_size
));
7972 rbd_linked_image_spec_list_cleanup(children
, max_size
);
7974 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap2"));
7975 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
7976 ASSERT_EQ(0, static_cast<int>(max_size
));
7977 rbd_linked_image_spec_list_cleanup(children
, max_size
);
7978 test_list_children2(parent
, 0);
7979 ASSERT_EQ(0, test_ls_snaps(parent
, 0));
7981 ASSERT_EQ(0, rbd_close(parent
));
7982 rados_ioctx_destroy(ioctx1
);
7985 // poorman's ceph_assert()
7987 void __ceph_assert_fail(const char *assertion
, const char *file
, int line
,
7993 #pragma GCC diagnostic pop
7994 #pragma GCC diagnostic warning "-Wpragmas"