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/librbd/test_support.h"
45 #include "common/event_socket.h"
46 #include "include/interval_set.h"
47 #include "include/stringify.h"
49 #include <boost/assign/list_of.hpp>
50 #include <boost/scope_exit.hpp>
53 #include <sys/eventfd.h>
58 using std::chrono::seconds;
60 #define ASSERT_PASSED(x, args...) \
62 bool passed = false; \
64 ASSERT_TRUE(passed); \
67 void register_test_librbd() {
70 static int get_features(bool *old_format, uint64_t *features)
72 const char *c = getenv("RBD_FEATURES");
80 cout << "using new format!" << std::endl;
84 cout << "using old format" << std::endl;
90 static int create_image_full(rados_ioctx_t ioctx, const char *name,
91 uint64_t size, int *order, int old_format,
95 // ensure old-format tests actually use the old format
96 int r = rados_conf_set(rados_ioctx_get_cluster(ioctx),
97 "rbd_default_format", "1");
101 return rbd_create(ioctx, name, size, order);
102 } else if ((features & RBD_FEATURE_STRIPINGV2) != 0) {
103 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
105 // use a conservative stripe_unit for non default order
106 stripe_unit = (1ull << (*order-1));
109 printf("creating image with stripe unit: %" PRIu64 ", "
110 "stripe count: %" PRIu64 "\n",
111 stripe_unit, IMAGE_STRIPE_COUNT);
112 return rbd_create3(ioctx, name, size, features, order,
113 stripe_unit, IMAGE_STRIPE_COUNT);
115 return rbd_create2(ioctx, name, size, features, order);
119 static int clone_image(rados_ioctx_t p_ioctx,
120 rbd_image_t p_image, const char *p_name,
121 const char *p_snap_name, rados_ioctx_t c_ioctx,
122 const char *c_name, uint64_t features, int *c_order)
124 uint64_t stripe_unit, stripe_count;
127 r = rbd_get_stripe_unit(p_image, &stripe_unit);
132 r = rbd_get_stripe_count(p_image, &stripe_count);
137 return rbd_clone2(p_ioctx, p_name, p_snap_name, c_ioctx,
138 c_name, features, c_order, stripe_unit, stripe_count);
142 static int create_image(rados_ioctx_t ioctx, const char *name,
143 uint64_t size, int *order)
148 int r = get_features(&old_format, &features);
151 return create_image_full(ioctx, name, size, order, old_format, features);
154 static int create_image_pp(librbd::RBD &rbd,
155 librados::IoCtx &ioctx,
157 uint64_t size, int *order) {
160 int r = get_features(&old_format, &features);
164 librados::Rados rados(ioctx);
165 int r = rados.conf_set("rbd_default_format", "1");
169 return rbd.create(ioctx, name, size, order);
171 return rbd.create2(ioctx, name, size, features, order);
175 class TestLibRBD : public ::testing::Test {
178 TestLibRBD() : m_pool_number() {
181 static void SetUpTestCase() {
182 static bool seeded = false;
186 cout << "seed " << seed << std::endl;
191 _unique_pool_names.clear();
193 ASSERT_EQ("", connect_cluster(&_cluster));
194 ASSERT_EQ("", connect_cluster_pp(_rados));
196 create_optional_data_pool();
199 static void TearDownTestCase() {
200 rados_shutdown(_cluster);
201 _rados.wait_for_latest_osdmap();
202 _pool_names.insert(_pool_names.end(), _unique_pool_names.begin(),
203 _unique_pool_names.end());
204 for (size_t i = 1; i < _pool_names.size(); ++i) {
205 ASSERT_EQ(0, _rados.pool_delete(_pool_names[i].c_str()));
207 if (!_pool_names.empty()) {
208 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names[0], _rados));
212 void SetUp() override {
213 ASSERT_NE("", m_pool_name = create_pool());
216 bool is_skip_partial_discard_enabled() {
218 EXPECT_EQ(0, _rados.conf_get("rbd_skip_partial_discard", value));
219 return value == "true";
222 void validate_object_map(rbd_image_t image, bool *passed) {
224 ASSERT_EQ(0, rbd_get_flags(image, &flags));
225 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
228 void validate_object_map(librbd::Image &image, bool *passed) {
230 ASSERT_EQ(0, image.get_flags(&flags));
231 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
234 std::string get_temp_image_name() {
236 return "image" + stringify(_image_number);
239 static void create_optional_data_pool() {
240 bool created = false;
241 std::string data_pool;
242 ASSERT_EQ(0, create_image_data_pool(_rados, data_pool, &created));
243 if (!data_pool.empty()) {
244 printf("using image data pool: %s\n", data_pool.c_str());
246 _unique_pool_names.push_back(data_pool);
251 std::string create_pool(bool unique = false) {
252 librados::Rados rados;
253 std::string pool_name;
255 pool_name = get_temp_pool_name("test-librbd-");
256 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
257 _unique_pool_names.push_back(pool_name);
258 } else if (m_pool_number < _pool_names.size()) {
259 pool_name = _pool_names[m_pool_number];
261 pool_name = get_temp_pool_name("test-librbd-");
262 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
263 _pool_names.push_back(pool_name);
269 static std::vector<std::string> _pool_names;
270 static std::vector<std::string> _unique_pool_names;
271 static rados_t _cluster;
272 static librados::Rados _rados;
273 static uint64_t _image_number;
275 std::string m_pool_name;
276 uint32_t m_pool_number;
280 std::vector<std::string> TestLibRBD::_pool_names;
281 std::vector<std::string> TestLibRBD::_unique_pool_names;
282 rados_t TestLibRBD::_cluster;
283 librados::Rados TestLibRBD::_rados;
284 uint64_t TestLibRBD::_image_number = 0;
286 TEST_F(TestLibRBD, CreateAndStat)
289 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
291 rbd_image_info_t info;
294 std::string name = get_temp_image_name();
295 uint64_t size = 2 << 20;
297 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
298 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
299 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
300 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
301 ASSERT_EQ(info.size, size);
302 ASSERT_EQ(info.order, order);
303 ASSERT_EQ(0, rbd_close(image));
305 rados_ioctx_destroy(ioctx);
308 TEST_F(TestLibRBD, CreateWithSameDataPool)
313 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
316 std::string name = get_temp_image_name();
317 uint64_t size = 2 << 20;
321 ASSERT_EQ(0, get_features(&old_format, &features));
322 ASSERT_FALSE(old_format);
324 rbd_image_options_t image_options;
325 rbd_image_options_create(&image_options);
326 BOOST_SCOPE_EXIT( (&image_options) ) {
327 rbd_image_options_destroy(image_options);
328 } BOOST_SCOPE_EXIT_END;
330 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
331 RBD_IMAGE_OPTION_FEATURES,
333 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
334 RBD_IMAGE_OPTION_DATA_POOL,
335 m_pool_name.c_str()));
337 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
338 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
340 ASSERT_EQ(0, rbd_close(image));
342 rados_ioctx_destroy(ioctx);
345 TEST_F(TestLibRBD, CreateAndStatPP)
347 librados::IoCtx ioctx;
348 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
352 librbd::image_info_t info;
355 std::string name = get_temp_image_name();
356 uint64_t size = 2 << 20;
358 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
359 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
360 ASSERT_EQ(0, image.stat(info, sizeof(info)));
361 ASSERT_EQ(info.size, size);
362 ASSERT_EQ(info.order, order);
368 TEST_F(TestLibRBD, GetId)
371 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
375 std::string name = get_temp_image_name();
377 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
378 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
381 if (!is_feature_enabled(0)) {
383 ASSERT_EQ(-EINVAL, rbd_get_id(image, id, sizeof(id)));
385 ASSERT_EQ(-ERANGE, rbd_get_id(image, id, 0));
386 ASSERT_EQ(0, rbd_get_id(image, id, sizeof(id)));
387 ASSERT_LT(0U, strlen(id));
390 ASSERT_EQ(0, rbd_close(image));
391 rados_ioctx_destroy(ioctx);
394 TEST_F(TestLibRBD, GetIdPP)
396 librados::IoCtx ioctx;
397 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
402 std::string name = get_temp_image_name();
405 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
406 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
407 if (!is_feature_enabled(0)) {
409 ASSERT_EQ(-EINVAL, image.get_id(&id));
411 ASSERT_EQ(0, image.get_id(&id));
412 ASSERT_LT(0U, id.size());
416 TEST_F(TestLibRBD, GetBlockNamePrefix)
419 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
423 std::string name = get_temp_image_name();
425 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
426 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
429 ASSERT_EQ(-ERANGE, rbd_get_block_name_prefix(image, prefix, 0));
430 ASSERT_EQ(0, rbd_get_block_name_prefix(image, prefix, sizeof(prefix)));
431 ASSERT_LT(0U, strlen(prefix));
433 ASSERT_EQ(0, rbd_close(image));
434 rados_ioctx_destroy(ioctx);
437 TEST_F(TestLibRBD, GetBlockNamePrefixPP)
439 librados::IoCtx ioctx;
440 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
445 std::string name = get_temp_image_name();
447 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
448 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
449 ASSERT_LT(0U, image.get_block_name_prefix().size());
452 TEST_F(TestLibRBD, TestGetCreateTimestamp)
457 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
461 std::string name = get_temp_image_name();
463 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
464 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
466 struct timespec timestamp;
467 ASSERT_EQ(0, rbd_get_create_timestamp(image, ×tamp));
468 ASSERT_LT(0, timestamp.tv_sec);
470 ASSERT_EQ(0, rbd_close(image));
472 rados_ioctx_destroy(ioctx);
475 TEST_F(TestLibRBD, GetCreateTimestampPP)
479 librados::IoCtx ioctx;
480 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
485 std::string name = get_temp_image_name();
487 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
488 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
490 struct timespec timestamp;
491 ASSERT_EQ(0, image.get_create_timestamp(×tamp));
492 ASSERT_LT(0, timestamp.tv_sec);
495 TEST_F(TestLibRBD, OpenAio)
498 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
500 rbd_image_info_t info;
503 std::string name = get_temp_image_name();
504 uint64_t size = 2 << 20;
506 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
508 rbd_completion_t open_comp;
509 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
510 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
511 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
512 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
513 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp));
514 rbd_aio_release(open_comp);
516 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
517 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
518 ASSERT_EQ(info.size, size);
519 ASSERT_EQ(info.order, order);
521 rbd_completion_t close_comp;
522 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &close_comp));
523 ASSERT_EQ(0, rbd_aio_close(image, close_comp));
524 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp));
525 ASSERT_EQ(1, rbd_aio_is_complete(close_comp));
526 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp));
527 rbd_aio_release(close_comp);
529 rados_ioctx_destroy(ioctx);
532 TEST_F(TestLibRBD, OpenAioFail)
535 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
537 std::string name = get_temp_image_name();
539 rbd_completion_t open_comp;
540 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
541 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
542 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
543 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
544 ASSERT_EQ(-ENOENT, rbd_aio_get_return_value(open_comp));
545 rbd_aio_release(open_comp);
547 rados_ioctx_destroy(ioctx);
550 TEST_F(TestLibRBD, OpenAioPP)
552 librados::IoCtx ioctx;
553 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
556 librbd::image_info_t info;
559 std::string name = get_temp_image_name();
560 uint64_t size = 2 << 20;
562 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
564 librbd::RBD::AioCompletion *open_comp =
565 new librbd::RBD::AioCompletion(NULL, NULL);
566 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
567 ASSERT_EQ(0, open_comp->wait_for_complete());
568 ASSERT_EQ(1, open_comp->is_complete());
569 ASSERT_EQ(0, open_comp->get_return_value());
570 open_comp->release();
572 ASSERT_EQ(0, image.stat(info, sizeof(info)));
573 ASSERT_EQ(info.size, size);
574 ASSERT_EQ(info.order, order);
577 open_comp = 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();
585 librbd::RBD::AioCompletion *close_comp =
586 new librbd::RBD::AioCompletion(NULL, NULL);
587 ASSERT_EQ(0, image.aio_close(close_comp));
588 ASSERT_EQ(0, close_comp->wait_for_complete());
589 ASSERT_EQ(1, close_comp->is_complete());
590 ASSERT_EQ(0, close_comp->get_return_value());
591 close_comp->release();
593 // close closed image
594 close_comp = new librbd::RBD::AioCompletion(NULL, NULL);
595 ASSERT_EQ(-EINVAL, image.aio_close(close_comp));
596 close_comp->release();
601 TEST_F(TestLibRBD, OpenAioFailPP)
603 librados::IoCtx ioctx;
604 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
609 std::string name = get_temp_image_name();
611 librbd::RBD::AioCompletion *open_comp =
612 new librbd::RBD::AioCompletion(NULL, NULL);
613 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
614 ASSERT_EQ(0, open_comp->wait_for_complete());
615 ASSERT_EQ(1, open_comp->is_complete());
616 ASSERT_EQ(-ENOENT, open_comp->get_return_value());
617 open_comp->release();
623 TEST_F(TestLibRBD, ResizeAndStat)
626 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
628 rbd_image_info_t info;
631 std::string name = get_temp_image_name();
632 uint64_t size = 2 << 20;
634 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
635 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
637 ASSERT_EQ(0, rbd_resize(image, size * 4));
638 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
639 ASSERT_EQ(info.size, size * 4);
641 ASSERT_EQ(0, rbd_resize(image, size / 2));
642 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
643 ASSERT_EQ(info.size, size / 2);
645 // downsizing without allowing shrink should fail
646 // and image size should not change
647 ASSERT_EQ(-EINVAL, rbd_resize2(image, size / 4, false, NULL, NULL));
648 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
649 ASSERT_EQ(info.size, size / 2);
651 ASSERT_EQ(0, rbd_resize2(image, size / 4, true, NULL, NULL));
652 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
653 ASSERT_EQ(info.size, size / 4);
655 ASSERT_PASSED(validate_object_map, image);
656 ASSERT_EQ(0, rbd_close(image));
658 rados_ioctx_destroy(ioctx);
661 TEST_F(TestLibRBD, ResizeAndStatPP)
663 librados::IoCtx ioctx;
664 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
668 librbd::image_info_t info;
671 std::string name = get_temp_image_name();
672 uint64_t size = 2 << 20;
674 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
675 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
677 ASSERT_EQ(0, image.resize(size * 4));
678 ASSERT_EQ(0, image.stat(info, sizeof(info)));
679 ASSERT_EQ(info.size, size * 4);
681 ASSERT_EQ(0, image.resize(size / 2));
682 ASSERT_EQ(0, image.stat(info, sizeof(info)));
683 ASSERT_EQ(info.size, size / 2);
684 ASSERT_PASSED(validate_object_map, image);
690 TEST_F(TestLibRBD, UpdateWatchAndResize)
693 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
697 std::string name = get_temp_image_name();
698 uint64_t size = 2 << 20;
700 rbd_image_t &m_image;
702 condition_variable m_cond;
704 static void cb(void *arg) {
705 Watcher *watcher = static_cast<Watcher *>(arg);
706 watcher->handle_notify();
708 Watcher(rbd_image_t &image) : m_image(image) {}
709 void handle_notify() {
710 rbd_image_info_t info;
711 ASSERT_EQ(0, rbd_stat(m_image, &info, sizeof(info)));
712 lock_guard<mutex> locker(m_lock);
716 void wait_for_size(size_t size) {
717 unique_lock<mutex> locker(m_lock);
718 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
720 return this->m_size == size;}));
725 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
726 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
728 ASSERT_EQ(0, rbd_update_watch(image, &handle, Watcher::cb, &watcher));
730 ASSERT_EQ(0, rbd_resize(image, size * 4));
731 watcher.wait_for_size(size * 4);
733 ASSERT_EQ(0, rbd_resize(image, size / 2));
734 watcher.wait_for_size(size / 2);
736 ASSERT_EQ(0, rbd_update_unwatch(image, handle));
738 ASSERT_EQ(0, rbd_close(image));
739 rados_ioctx_destroy(ioctx);
742 TEST_F(TestLibRBD, UpdateWatchAndResizePP)
744 librados::IoCtx ioctx;
745 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
751 std::string name = get_temp_image_name();
752 uint64_t size = 2 << 20;
753 struct Watcher : public librbd::UpdateWatchCtx {
754 Watcher(librbd::Image &image) : m_image(image) {
756 void handle_notify() override {
757 librbd::image_info_t info;
758 ASSERT_EQ(0, m_image.stat(info, sizeof(info)));
759 lock_guard<mutex> locker(m_lock);
763 void wait_for_size(size_t size) {
764 unique_lock<mutex> locker(m_lock);
765 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
767 return this->m_size == size;}));
769 librbd::Image &m_image;
771 condition_variable m_cond;
776 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
777 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
779 ASSERT_EQ(0, image.update_watch(&watcher, &handle));
781 ASSERT_EQ(0, image.resize(size * 4));
782 watcher.wait_for_size(size * 4);
784 ASSERT_EQ(0, image.resize(size / 2));
785 watcher.wait_for_size(size / 2);
787 ASSERT_EQ(0, image.update_unwatch(handle));
793 int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
796 char *names, *cur_name;
798 size_t max_size = 1024;
800 names = (char *) malloc(sizeof(char) * 1024);
801 int len = rbd_list(io_ctx, names, &max_size);
803 std::set<std::string> image_names;
804 for (i = 0, num_images = 0, cur_name = names; cur_name < names + len; i++) {
805 printf("image: %s\n", cur_name);
806 image_names.insert(cur_name);
807 cur_name += strlen(cur_name) + 1;
812 va_start(ap, num_expected);
813 for (i = num_expected; i > 0; i--) {
814 char *expected = va_arg(ap, char *);
815 printf("expected = %s\n", expected);
816 std::set<std::string>::iterator it = image_names.find(expected);
817 if (it != image_names.end()) {
818 printf("found %s\n", expected);
819 image_names.erase(it);
820 printf("erased %s\n", expected);
822 ADD_FAILURE() << "Unable to find image " << expected;
829 if (!image_names.empty()) {
830 ADD_FAILURE() << "Unexpected images discovered";
836 TEST_F(TestLibRBD, TestCreateLsDelete)
839 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
842 std::string name = get_temp_image_name();
843 std::string name2 = get_temp_image_name();
844 uint64_t size = 2 << 20;
846 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
847 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
848 ASSERT_EQ(0, create_image(ioctx, name2.c_str(), size, &order));
849 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
850 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
851 ASSERT_EQ(1, test_ls(ioctx, 1, name2.c_str()));
853 ASSERT_EQ(-ENOENT, rbd_remove(ioctx, name.c_str()));
855 rados_ioctx_destroy(ioctx);
858 int test_ls_pp(librbd::RBD& rbd, librados::IoCtx& io_ctx, size_t num_expected, ...)
863 vector<string> names;
864 r = rbd.list(io_ctx, names);
868 cout << "num images is: " << names.size() << std::endl
869 << "expected: " << num_expected << std::endl;
870 int num = names.size();
872 for (i = 0; i < names.size(); i++) {
873 cout << "image: " << names[i] << std::endl;
876 va_start(ap, num_expected);
877 for (i = num_expected; i > 0; i--) {
878 char *expected = va_arg(ap, char *);
879 cout << "expected = " << expected << std::endl;
880 vector<string>::iterator listed_name = find(names.begin(), names.end(), string(expected));
881 if (listed_name == names.end()) {
882 ADD_FAILURE() << "Unable to find image " << expected;
886 names.erase(listed_name);
890 if (!names.empty()) {
891 ADD_FAILURE() << "Unexpected images discovered";
897 TEST_F(TestLibRBD, TestCreateLsDeletePP)
899 librados::IoCtx ioctx;
900 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
906 std::string name = get_temp_image_name();
907 std::string name2 = get_temp_image_name();
908 uint64_t size = 2 << 20;
910 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
911 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
912 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
913 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
914 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
915 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name2.c_str()));
922 static int print_progress_percent(uint64_t offset, uint64_t src_size,
925 float percent = ((float)offset * 100) / src_size;
926 printf("%3.2f%% done\n", percent);
930 TEST_F(TestLibRBD, TestCopy)
933 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
937 std::string name = get_temp_image_name();
938 std::string name2 = get_temp_image_name();
939 std::string name3 = get_temp_image_name();
941 uint64_t size = 2 << 20;
943 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
944 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
945 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
946 ASSERT_EQ(0, rbd_copy(image, ioctx, name2.c_str()));
947 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
948 ASSERT_EQ(0, rbd_copy_with_progress(image, ioctx, name3.c_str(),
949 print_progress_percent, NULL));
950 ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
952 ASSERT_EQ(0, rbd_close(image));
953 rados_ioctx_destroy(ioctx);
956 class PrintProgress : public librbd::ProgressContext
959 int update_progress(uint64_t offset, uint64_t src_size) override
961 float percent = ((float)offset * 100) / src_size;
962 printf("%3.2f%% done\n", percent);
967 TEST_F(TestLibRBD, TestCopyPP)
969 librados::IoCtx ioctx;
970 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
976 std::string name = get_temp_image_name();
977 std::string name2 = get_temp_image_name();
978 std::string name3 = get_temp_image_name();
979 uint64_t size = 2 << 20;
982 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
983 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
984 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
985 ASSERT_EQ(0, image.copy(ioctx, name2.c_str()));
986 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
987 ASSERT_EQ(0, image.copy_with_progress(ioctx, name3.c_str(), pp));
988 ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name.c_str(), name2.c_str(),
995 int test_ls_snaps(rbd_image_t image, int num_expected, ...)
997 int num_snaps, i, j, max_size = 10;
999 rbd_snap_info_t snaps[max_size];
1000 num_snaps = rbd_snap_list(image, snaps, &max_size);
1001 printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected);
1003 for (i = 0; i < num_snaps; i++) {
1004 printf("snap: %s\n", snaps[i].name);
1007 va_start(ap, num_expected);
1008 for (i = num_expected; i > 0; i--) {
1009 char *expected = va_arg(ap, char *);
1010 uint64_t expected_size = va_arg(ap, uint64_t);
1012 for (j = 0; j < num_snaps; j++) {
1013 if (snaps[j].name == NULL)
1015 if (strcmp(snaps[j].name, expected) == 0) {
1016 printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size);
1017 EXPECT_EQ(expected_size, snaps[j].size);
1018 free((void *) snaps[j].name);
1019 snaps[j].name = NULL;
1028 for (i = 0; i < num_snaps; i++) {
1029 EXPECT_EQ((const char *)0, snaps[i].name);
1035 TEST_F(TestLibRBD, TestCreateLsDeleteSnap)
1037 rados_ioctx_t ioctx;
1038 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1042 std::string name = get_temp_image_name();
1043 uint64_t size = 2 << 20;
1044 uint64_t size2 = 4 << 20;
1046 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1047 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1049 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1050 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1051 ASSERT_EQ(0, rbd_resize(image, size2));
1052 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1053 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1054 ASSERT_EQ(0, rbd_snap_remove(image, "snap1"));
1055 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
1056 ASSERT_EQ(0, rbd_snap_remove(image, "snap2"));
1057 ASSERT_EQ(0, test_ls_snaps(image, 0));
1059 ASSERT_EQ(0, rbd_close(image));
1061 rados_ioctx_destroy(ioctx);
1064 int test_get_snapshot_timestamp(rbd_image_t image, uint64_t snap_id)
1066 struct timespec timestamp;
1067 EXPECT_EQ(0, rbd_snap_get_timestamp(image, snap_id, ×tamp));
1068 EXPECT_LT(0, timestamp.tv_sec);
1072 TEST_F(TestLibRBD, TestGetSnapShotTimeStamp)
1074 REQUIRE_FORMAT_V2();
1076 rados_ioctx_t ioctx;
1077 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1081 std::string name = get_temp_image_name();
1082 uint64_t size = 2 << 20;
1083 int num_snaps, max_size = 10;
1084 rbd_snap_info_t snaps[max_size];
1086 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1087 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1089 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1090 num_snaps = rbd_snap_list(image, snaps, &max_size);
1091 ASSERT_EQ(1, num_snaps);
1092 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1093 free((void *)snaps[0].name);
1095 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1096 num_snaps = rbd_snap_list(image, snaps, &max_size);
1097 ASSERT_EQ(2, num_snaps);
1098 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1099 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[1].id));
1100 free((void *)snaps[0].name);
1101 free((void *)snaps[1].name);
1103 ASSERT_EQ(0, rbd_close(image));
1105 rados_ioctx_destroy(ioctx);
1109 int test_ls_snaps(librbd::Image& image, size_t num_expected, ...)
1114 vector<librbd::snap_info_t> snaps;
1115 r = image.snap_list(snaps);
1116 EXPECT_TRUE(r >= 0);
1117 cout << "num snaps is: " << snaps.size() << std::endl
1118 << "expected: " << num_expected << std::endl;
1120 for (i = 0; i < snaps.size(); i++) {
1121 cout << "snap: " << snaps[i].name << std::endl;
1124 va_start(ap, num_expected);
1125 for (i = num_expected; i > 0; i--) {
1126 char *expected = va_arg(ap, char *);
1127 uint64_t expected_size = va_arg(ap, uint64_t);
1129 for (j = 0; j < snaps.size(); j++) {
1130 if (snaps[j].name == "")
1132 if (strcmp(snaps[j].name.c_str(), expected) == 0) {
1133 cout << "found " << snaps[j].name << " with size " << snaps[j].size
1135 EXPECT_EQ(expected_size, snaps[j].size);
1145 for (i = 0; i < snaps.size(); i++) {
1146 EXPECT_EQ("", snaps[i].name);
1149 return snaps.size();
1152 TEST_F(TestLibRBD, TestCreateLsDeleteSnapPP)
1154 librados::IoCtx ioctx;
1155 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1159 librbd::Image image;
1161 std::string name = get_temp_image_name();
1162 uint64_t size = 2 << 20;
1163 uint64_t size2 = 4 << 20;
1165 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1166 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1169 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1170 ASSERT_FALSE(exists);
1171 ASSERT_EQ(0, image.snap_create("snap1"));
1172 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1173 ASSERT_TRUE(exists);
1174 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1175 ASSERT_EQ(0, image.resize(size2));
1176 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1177 ASSERT_FALSE(exists);
1178 ASSERT_EQ(0, image.snap_create("snap2"));
1179 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1180 ASSERT_TRUE(exists);
1181 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1182 ASSERT_EQ(0, image.snap_remove("snap1"));
1183 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1184 ASSERT_FALSE(exists);
1185 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
1186 ASSERT_EQ(0, image.snap_remove("snap2"));
1187 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1188 ASSERT_FALSE(exists);
1189 ASSERT_EQ(0, test_ls_snaps(image, 0));
1195 TEST_F(TestLibRBD, TestCreateLsRenameSnapPP)
1197 librados::IoCtx ioctx;
1198 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1202 librbd::Image image;
1204 std::string name = get_temp_image_name();
1205 uint64_t size = 2 << 20;
1206 uint64_t size2 = 4 << 20;
1208 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1209 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1212 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1213 ASSERT_FALSE(exists);
1214 ASSERT_EQ(0, image.snap_create("snap1"));
1215 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1216 ASSERT_TRUE(exists);
1217 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1218 ASSERT_EQ(0, image.resize(size2));
1219 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1220 ASSERT_FALSE(exists);
1221 ASSERT_EQ(0, image.snap_create("snap2"));
1222 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1223 ASSERT_TRUE(exists);
1224 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1225 ASSERT_EQ(0, image.snap_rename("snap1","snap1-rename"));
1226 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1-rename", size, "snap2", size2));
1227 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1228 ASSERT_FALSE(exists);
1229 ASSERT_EQ(0, image.snap_exists2("snap1-rename", &exists));
1230 ASSERT_TRUE(exists);
1231 ASSERT_EQ(0, image.snap_remove("snap1-rename"));
1232 ASSERT_EQ(0, image.snap_rename("snap2","snap2-rename"));
1233 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2-rename", size2));
1234 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1235 ASSERT_FALSE(exists);
1236 ASSERT_EQ(0, image.snap_exists2("snap2-rename", &exists));
1237 ASSERT_TRUE(exists);
1238 ASSERT_EQ(0, image.snap_remove("snap2-rename"));
1239 ASSERT_EQ(0, test_ls_snaps(image, 0));
1245 void simple_write_cb(rbd_completion_t cb, void *arg)
1247 printf("write completion cb called!\n");
1250 void simple_read_cb(rbd_completion_t cb, void *arg)
1252 printf("read completion cb called!\n");
1255 void aio_write_test_data_and_poll(rbd_image_t image, int fd, const char *test_data,
1256 uint64_t off, size_t len, uint32_t iohint, bool *passed)
1258 rbd_completion_t comp;
1259 uint64_t data = 0x123;
1260 rbd_aio_create_completion((void*)&data, (rbd_callback_t) simple_write_cb, &comp);
1261 printf("created completion\n");
1262 printf("started write\n");
1264 rbd_aio_write2(image, off, len, test_data, comp, iohint);
1266 rbd_aio_write(image, off, len, test_data, comp);
1270 pfd.events = POLLIN;
1272 ASSERT_EQ(1, poll(&pfd, 1, -1));
1273 ASSERT_TRUE(pfd.revents & POLLIN);
1275 rbd_completion_t comps[1];
1276 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
1278 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
1279 read(fd, &count, sizeof(count)));
1280 int r = rbd_aio_get_return_value(comps[0]);
1281 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
1282 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps[0]) == data);
1283 printf("return value is: %d\n", r);
1285 printf("finished write\n");
1286 rbd_aio_release(comps[0]);
1290 void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1292 rbd_completion_t comp;
1293 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1294 printf("created completion\n");
1296 rbd_aio_write2(image, off, len, test_data, comp, iohint);
1298 rbd_aio_write(image, off, len, test_data, comp);
1299 printf("started write\n");
1300 rbd_aio_wait_for_complete(comp);
1301 int r = rbd_aio_get_return_value(comp);
1302 printf("return value is: %d\n", r);
1304 printf("finished write\n");
1305 rbd_aio_release(comp);
1309 void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1313 written = rbd_write2(image, off, len, test_data, iohint);
1315 written = rbd_write(image, off, len, test_data);
1316 printf("wrote: %d\n", (int) written);
1317 ASSERT_EQ(len, static_cast<size_t>(written));
1321 void aio_discard_test_data(rbd_image_t image, uint64_t off, uint64_t len, bool *passed)
1323 rbd_completion_t comp;
1324 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1325 rbd_aio_discard(image, off, len, comp);
1326 rbd_aio_wait_for_complete(comp);
1327 int r = rbd_aio_get_return_value(comp);
1329 printf("aio discard: %d~%d = %d\n", (int)off, (int)len, (int)r);
1330 rbd_aio_release(comp);
1334 void discard_test_data(rbd_image_t image, uint64_t off, size_t len, bool *passed)
1337 written = rbd_discard(image, off, len);
1338 printf("discard: %d~%d = %d\n", (int)off, (int)len, (int)written);
1339 ASSERT_EQ(len, static_cast<size_t>(written));
1343 void aio_read_test_data_and_poll(rbd_image_t image, int fd, const char *expected,
1344 uint64_t off, size_t len, uint32_t iohint, bool *passed)
1346 rbd_completion_t comp;
1347 char *result = (char *)malloc(len + 1);
1349 ASSERT_NE(static_cast<char *>(NULL), result);
1350 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1351 printf("created completion\n");
1352 printf("started read\n");
1354 rbd_aio_read2(image, off, len, result, comp, iohint);
1356 rbd_aio_read(image, off, len, result, comp);
1360 pfd.events = POLLIN;
1362 ASSERT_EQ(1, poll(&pfd, 1, -1));
1363 ASSERT_TRUE(pfd.revents & POLLIN);
1365 rbd_completion_t comps[1];
1366 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
1368 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
1369 read(fd, &count, sizeof(count)));
1371 int r = rbd_aio_get_return_value(comps[0]);
1372 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
1373 printf("return value is: %d\n", r);
1374 ASSERT_EQ(len, static_cast<size_t>(r));
1375 rbd_aio_release(comps[0]);
1376 if (memcmp(result, expected, len)) {
1377 printf("read: %s\nexpected: %s\n", result, expected);
1378 ASSERT_EQ(0, memcmp(result, expected, len));
1384 void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1386 rbd_completion_t comp;
1387 char *result = (char *)malloc(len + 1);
1389 ASSERT_NE(static_cast<char *>(NULL), result);
1390 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1391 printf("created completion\n");
1393 rbd_aio_read2(image, off, len, result, comp, iohint);
1395 rbd_aio_read(image, off, len, result, comp);
1396 printf("started read\n");
1397 rbd_aio_wait_for_complete(comp);
1398 int r = rbd_aio_get_return_value(comp);
1399 printf("return value is: %d\n", r);
1400 ASSERT_EQ(len, static_cast<size_t>(r));
1401 rbd_aio_release(comp);
1402 if (memcmp(result, expected, len)) {
1403 printf("read: %s\nexpected: %s\n", result, expected);
1404 ASSERT_EQ(0, memcmp(result, expected, len));
1410 void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1413 char *result = (char *)malloc(len + 1);
1415 ASSERT_NE(static_cast<char *>(NULL), result);
1417 read = rbd_read2(image, off, len, result, iohint);
1419 read = rbd_read(image, off, len, result);
1420 printf("read: %d\n", (int) read);
1421 ASSERT_EQ(len, static_cast<size_t>(read));
1423 if (memcmp(result, expected, len)) {
1424 printf("read: %s\nexpected: %s\n", result, expected);
1425 ASSERT_EQ(0, memcmp(result, expected, len));
1431 void aio_writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
1432 uint64_t data_len, uint32_t iohint, bool *passed)
1434 rbd_completion_t comp;
1435 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1436 printf("created completion\n");
1438 r = rbd_aio_writesame(image, off, len, test_data, data_len, comp, iohint);
1439 printf("started writesame\n");
1440 if (len % data_len) {
1441 ASSERT_EQ(-EINVAL, r);
1442 printf("expected fail, finished writesame\n");
1443 rbd_aio_release(comp);
1448 rbd_aio_wait_for_complete(comp);
1449 r = rbd_aio_get_return_value(comp);
1450 printf("return value is: %d\n", r);
1452 printf("finished writesame\n");
1453 rbd_aio_release(comp);
1456 printf("to verify the data\n");
1458 char *result = (char *)malloc(data_len+ 1);
1459 ASSERT_NE(static_cast<char *>(NULL), result);
1460 uint64_t left = len;
1462 read = rbd_read(image, off, data_len, result);
1463 ASSERT_EQ(data_len, static_cast<size_t>(read));
1464 result[data_len] = '\0';
1465 if (memcmp(result, test_data, data_len)) {
1466 printf("read: %d ~ %d\n", (int) off, (int) read);
1467 printf("read: %s\nexpected: %s\n", result, test_data);
1468 ASSERT_EQ(0, memcmp(result, test_data, data_len));
1473 ASSERT_EQ(0U, left);
1475 printf("verified\n");
1480 void writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
1481 uint64_t data_len, uint32_t iohint, bool *passed)
1484 written = rbd_writesame(image, off, len, test_data, data_len, iohint);
1485 if (len % data_len) {
1486 ASSERT_EQ(-EINVAL, written);
1487 printf("expected fail, finished writesame\n");
1491 ASSERT_EQ(len, static_cast<size_t>(written));
1492 printf("wrote: %d\n", (int) written);
1495 printf("to verify the data\n");
1497 char *result = (char *)malloc(data_len+ 1);
1498 ASSERT_NE(static_cast<char *>(NULL), result);
1499 uint64_t left = len;
1501 read = rbd_read(image, off, data_len, result);
1502 ASSERT_EQ(data_len, static_cast<size_t>(read));
1503 result[data_len] = '\0';
1504 if (memcmp(result, test_data, data_len)) {
1505 printf("read: %d ~ %d\n", (int) off, (int) read);
1506 printf("read: %s\nexpected: %s\n", result, test_data);
1507 ASSERT_EQ(0, memcmp(result, test_data, data_len));
1512 ASSERT_EQ(0U, left);
1514 printf("verified\n");
1519 void aio_compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
1520 const char *test_data, uint64_t off,
1521 size_t len, uint32_t iohint, bool *passed)
1523 rbd_completion_t comp;
1524 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1525 printf("created completion\n");
1527 uint64_t mismatch_offset;
1528 rbd_aio_compare_and_write(image, off, len, cmp_data, test_data, comp, &mismatch_offset, iohint);
1529 printf("started aio compare and write\n");
1530 rbd_aio_wait_for_complete(comp);
1531 int r = rbd_aio_get_return_value(comp);
1532 printf("return value is: %d\n", r);
1534 printf("finished aio compare and write\n");
1535 rbd_aio_release(comp);
1539 void compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
1540 const char *test_data, uint64_t off, size_t len,
1541 uint64_t *mismatch_off, uint32_t iohint, bool *passed)
1543 printf("start compare and write\n");
1545 written = rbd_compare_and_write(image, off, len, cmp_data, test_data, mismatch_off, iohint);
1546 printf("compare and wrote: %d\n", (int) written);
1547 ASSERT_EQ(len, static_cast<size_t>(written));
1552 TEST_F(TestLibRBD, TestIO)
1554 rados_ioctx_t ioctx;
1555 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1557 bool skip_discard = is_skip_partial_discard_enabled();
1561 std::string name = get_temp_image_name();
1562 uint64_t size = 2 << 20;
1564 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1565 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1567 char test_data[TEST_IO_SIZE + 1];
1568 char zero_data[TEST_IO_SIZE + 1];
1569 char mismatch_data[TEST_IO_SIZE + 1];
1571 uint64_t mismatch_offset;
1573 for (i = 0; i < TEST_IO_SIZE; ++i) {
1574 test_data[i] = (char) (rand() % (126 - 33) + 33);
1576 test_data[TEST_IO_SIZE] = '\0';
1577 memset(zero_data, 0, sizeof(zero_data));
1578 memset(mismatch_data, 9, sizeof(mismatch_data));
1580 for (i = 0; i < 5; ++i)
1581 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1583 for (i = 5; i < 10; ++i)
1584 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1586 for (i = 0; i < 5; ++i)
1587 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, 0);
1589 for (i = 5; i < 10; ++i)
1590 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1592 for (i = 0; i < 5; ++i)
1593 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1595 for (i = 5; i < 10; ++i)
1596 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1598 // discard 2nd, 4th sections.
1599 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
1600 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
1602 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
1603 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1604 TEST_IO_SIZE, TEST_IO_SIZE, 0);
1605 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
1606 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1607 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
1608 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
1610 for (i = 0; i < 15; ++i) {
1612 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1613 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1614 } else if (i % 3 == 1) {
1615 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1616 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1618 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1619 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1622 for (i = 0; i < 15; ++i) {
1624 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1625 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1626 } else if (i % 3 == 1) {
1627 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1628 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1630 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1631 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1635 rbd_image_info_t info;
1636 rbd_completion_t comp;
1637 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1638 // can't read or write starting past end
1639 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
1640 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
1641 // reading through end returns amount up to end
1642 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
1643 // writing through end returns amount up to end
1644 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
1646 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1647 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
1648 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1649 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1650 rbd_aio_release(comp);
1652 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1653 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
1654 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1655 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1656 rbd_aio_release(comp);
1658 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1659 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data, &mismatch_offset, 0));
1660 ASSERT_EQ(0U, mismatch_offset);
1661 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1662 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data, comp, &mismatch_offset, 0));
1663 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1664 ASSERT_EQ(0U, mismatch_offset);
1665 rbd_aio_release(comp);
1667 ASSERT_PASSED(validate_object_map, image);
1668 ASSERT_EQ(0, rbd_close(image));
1670 rados_ioctx_destroy(ioctx);
1673 TEST_F(TestLibRBD, TestIOWithIOHint)
1675 rados_ioctx_t ioctx;
1676 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1678 bool skip_discard = is_skip_partial_discard_enabled();
1682 std::string name = get_temp_image_name();
1683 uint64_t size = 2 << 20;
1685 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1686 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1688 char test_data[TEST_IO_SIZE + 1];
1689 char zero_data[TEST_IO_SIZE + 1];
1690 char mismatch_data[TEST_IO_SIZE + 1];
1692 uint64_t mismatch_offset;
1694 for (i = 0; i < TEST_IO_SIZE; ++i) {
1695 test_data[i] = (char) (rand() % (126 - 33) + 33);
1697 test_data[TEST_IO_SIZE] = '\0';
1698 memset(zero_data, 0, sizeof(zero_data));
1699 memset(mismatch_data, 9, sizeof(mismatch_data));
1701 for (i = 0; i < 5; ++i)
1702 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
1703 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1705 for (i = 5; i < 10; ++i)
1706 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
1707 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1709 for (i = 0; i < 5; ++i)
1710 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
1711 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1713 for (i = 5; i < 10; ++i)
1714 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
1715 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1717 for (i = 0; i < 5; ++i)
1718 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE,
1719 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1721 for (i = 5; i < 10; ++i)
1722 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
1723 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1725 // discard 2nd, 4th sections.
1726 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
1727 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
1729 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE,
1730 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1731 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1732 TEST_IO_SIZE, TEST_IO_SIZE,
1733 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1734 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE,
1735 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1736 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1737 TEST_IO_SIZE*3, TEST_IO_SIZE,
1738 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1739 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
1741 for (i = 0; i < 15; ++i) {
1743 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1744 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1745 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1746 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1747 } else if (i % 3 == 1) {
1748 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1749 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1750 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1751 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1753 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1754 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1755 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1756 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1759 for (i = 0; i < 15; ++i) {
1761 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1762 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1763 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1764 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1765 } else if (i % 3 == 1) {
1766 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1767 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1768 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1769 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1771 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1772 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1773 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1774 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1778 rbd_image_info_t info;
1779 rbd_completion_t comp;
1780 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1781 // can't read or write starting past end
1782 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
1783 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
1784 // reading through end returns amount up to end
1785 ASSERT_EQ(10, rbd_read2(image, info.size - 10, 100, test_data,
1786 LIBRADOS_OP_FLAG_FADVISE_NOCACHE));
1787 // writing through end returns amount up to end
1788 ASSERT_EQ(10, rbd_write2(image, info.size - 10, 100, test_data,
1789 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1791 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1792 ASSERT_EQ(0, rbd_aio_read2(image, info.size, 1, test_data, comp,
1793 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1794 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1795 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1796 rbd_aio_release(comp);
1798 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1799 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
1800 &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1801 ASSERT_EQ(0U, mismatch_offset);
1802 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1803 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
1804 comp, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1805 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1806 ASSERT_EQ(0U, mismatch_offset);
1807 rbd_aio_release(comp);
1809 ASSERT_PASSED(validate_object_map, image);
1810 ASSERT_EQ(0, rbd_close(image));
1812 rados_ioctx_destroy(ioctx);
1815 TEST_F(TestLibRBD, TestDataPoolIO)
1817 REQUIRE_FORMAT_V2();
1819 rados_ioctx_t ioctx;
1820 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1822 std::string data_pool_name = create_pool(true);
1824 bool skip_discard = is_skip_partial_discard_enabled();
1827 std::string name = get_temp_image_name();
1828 uint64_t size = 2 << 20;
1832 ASSERT_EQ(0, get_features(&old_format, &features));
1833 ASSERT_FALSE(old_format);
1835 rbd_image_options_t image_options;
1836 rbd_image_options_create(&image_options);
1837 BOOST_SCOPE_EXIT( (&image_options) ) {
1838 rbd_image_options_destroy(image_options);
1839 } BOOST_SCOPE_EXIT_END;
1841 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
1842 RBD_IMAGE_OPTION_FEATURES,
1844 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
1845 RBD_IMAGE_OPTION_DATA_POOL,
1846 data_pool_name.c_str()));
1848 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
1849 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1850 ASSERT_NE(-1, rbd_get_data_pool_id(image));
1852 char test_data[TEST_IO_SIZE + 1];
1853 char zero_data[TEST_IO_SIZE + 1];
1856 for (i = 0; i < TEST_IO_SIZE; ++i) {
1857 test_data[i] = (char) (rand() % (126 - 33) + 33);
1859 test_data[TEST_IO_SIZE] = '\0';
1860 memset(zero_data, 0, sizeof(zero_data));
1862 for (i = 0; i < 5; ++i)
1863 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1865 for (i = 5; i < 10; ++i)
1866 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1868 for (i = 0; i < 5; ++i)
1869 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1871 for (i = 5; i < 10; ++i)
1872 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1874 // discard 2nd, 4th sections.
1875 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
1876 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
1878 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
1879 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1880 TEST_IO_SIZE, TEST_IO_SIZE, 0);
1881 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
1882 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1883 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
1884 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
1886 rbd_image_info_t info;
1887 rbd_completion_t comp;
1888 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1889 // can't read or write starting past end
1890 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
1891 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
1892 // reading through end returns amount up to end
1893 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
1894 // writing through end returns amount up to end
1895 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
1897 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1898 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
1899 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1900 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1901 rbd_aio_release(comp);
1903 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1904 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
1905 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1906 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1907 rbd_aio_release(comp);
1909 ASSERT_PASSED(validate_object_map, image);
1910 ASSERT_EQ(0, rbd_close(image));
1912 rados_ioctx_destroy(ioctx);
1915 TEST_F(TestLibRBD, TestScatterGatherIO)
1917 rados_ioctx_t ioctx;
1918 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1922 std::string name = get_temp_image_name();
1923 uint64_t size = 20 << 20;
1925 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1926 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1928 std::string write_buffer("This is a test");
1929 struct iovec bad_iovs[] = {
1930 {.iov_base = NULL, .iov_len = static_cast<size_t>(-1)}
1932 struct iovec write_iovs[] = {
1933 {.iov_base = &write_buffer[0], .iov_len = 5},
1934 {.iov_base = &write_buffer[5], .iov_len = 3},
1935 {.iov_base = &write_buffer[8], .iov_len = 2},
1936 {.iov_base = &write_buffer[10], .iov_len = 4}
1939 rbd_completion_t comp;
1940 rbd_aio_create_completion(NULL, NULL, &comp);
1941 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, write_iovs, 0, 0, comp));
1942 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 1, 0, comp));
1943 ASSERT_EQ(0, rbd_aio_writev(image, write_iovs,
1944 sizeof(write_iovs) / sizeof(struct iovec),
1946 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1947 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
1948 rbd_aio_release(comp);
1950 std::string read_buffer(write_buffer.size(), '1');
1951 struct iovec read_iovs[] = {
1952 {.iov_base = &read_buffer[0], .iov_len = 4},
1953 {.iov_base = &read_buffer[8], .iov_len = 4},
1954 {.iov_base = &read_buffer[12], .iov_len = 2}
1957 rbd_aio_create_completion(NULL, NULL, &comp);
1958 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, read_iovs, 0, 0, comp));
1959 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 1, 0, comp));
1960 ASSERT_EQ(0, rbd_aio_readv(image, read_iovs,
1961 sizeof(read_iovs) / sizeof(struct iovec),
1963 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1964 ASSERT_EQ(10, rbd_aio_get_return_value(comp));
1965 rbd_aio_release(comp);
1966 ASSERT_EQ("This1111 is a ", read_buffer);
1968 std::string linear_buffer(write_buffer.size(), '1');
1969 struct iovec linear_iovs[] = {
1970 {.iov_base = &linear_buffer[4], .iov_len = 4}
1972 rbd_aio_create_completion(NULL, NULL, &comp);
1973 ASSERT_EQ(0, rbd_aio_readv(image, linear_iovs,
1974 sizeof(linear_iovs) / sizeof(struct iovec),
1976 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1977 ASSERT_EQ(4, rbd_aio_get_return_value(comp));
1978 rbd_aio_release(comp);
1979 ASSERT_EQ("1111This111111", linear_buffer);
1981 ASSERT_PASSED(validate_object_map, image);
1982 ASSERT_EQ(0, rbd_close(image));
1984 rados_ioctx_destroy(ioctx);
1987 TEST_F(TestLibRBD, TestEmptyDiscard)
1989 rados_ioctx_t ioctx;
1990 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1994 std::string name = get_temp_image_name();
1995 uint64_t size = 20 << 20;
1997 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1998 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2000 ASSERT_PASSED(aio_discard_test_data, image, 0, 1*1024*1024);
2001 ASSERT_PASSED(aio_discard_test_data, image, 0, 4*1024*1024);
2002 ASSERT_PASSED(aio_discard_test_data, image, 3*1024*1024, 1*1024*1024);
2004 ASSERT_PASSED(validate_object_map, image);
2005 ASSERT_EQ(0, rbd_close(image));
2007 rados_ioctx_destroy(ioctx);
2011 void simple_write_cb_pp(librbd::completion_t cb, void *arg)
2013 cout << "write completion cb called!" << std::endl;
2016 void simple_read_cb_pp(librbd::completion_t cb, void *arg)
2018 cout << "read completion cb called!" << std::endl;
2021 void aio_write_test_data(librbd::Image& image, const char *test_data,
2022 off_t off, uint32_t iohint, bool *passed)
2024 ceph::bufferlist bl;
2025 bl.append(test_data, strlen(test_data));
2026 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2027 printf("created completion\n");
2029 image.aio_write2(off, strlen(test_data), bl, comp, iohint);
2031 image.aio_write(off, strlen(test_data), bl, comp);
2032 printf("started write\n");
2033 comp->wait_for_complete();
2034 int r = comp->get_return_value();
2035 printf("return value is: %d\n", r);
2037 printf("finished write\n");
2042 void aio_discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2044 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2045 image.aio_discard(off, len, comp);
2046 comp->wait_for_complete();
2047 int r = comp->get_return_value();
2053 void write_test_data(librbd::Image& image, const char *test_data, off_t off, uint32_t iohint, bool *passed)
2056 size_t len = strlen(test_data);
2057 ceph::bufferlist bl;
2058 bl.append(test_data, len);
2060 written = image.write2(off, len, bl, iohint);
2062 written = image.write(off, len, bl);
2063 printf("wrote: %u\n", (unsigned int) written);
2064 ASSERT_EQ(bl.length(), written);
2068 void discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2071 written = image.discard(off, len);
2072 printf("discard: %u~%u\n", (unsigned)off, (unsigned)len);
2073 ASSERT_EQ(len, written);
2077 void aio_read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2079 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_read_cb_pp);
2080 ceph::bufferlist bl;
2081 printf("created completion\n");
2083 image.aio_read2(off, expected_len, bl, comp, iohint);
2085 image.aio_read(off, expected_len, bl, comp);
2086 printf("started read\n");
2087 comp->wait_for_complete();
2088 int r = comp->get_return_value();
2089 printf("return value is: %d\n", r);
2090 ASSERT_EQ(TEST_IO_SIZE, r);
2091 ASSERT_EQ(0, memcmp(expected, bl.c_str(), TEST_IO_SIZE));
2092 printf("finished read\n");
2097 void read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2100 size_t len = expected_len;
2101 ceph::bufferlist bl;
2103 read = image.read2(off, len, bl, iohint);
2105 read = image.read(off, len, bl);
2106 ASSERT_TRUE(read >= 0);
2107 std::string bl_str(bl.c_str(), read);
2109 printf("read: %u\n", (unsigned int) read);
2110 int result = memcmp(bl_str.c_str(), expected, expected_len);
2112 printf("read: %s\nexpected: %s\n", bl_str.c_str(), expected);
2113 ASSERT_EQ(0, result);
2118 void aio_writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2119 size_t len, size_t data_len, uint32_t iohint, bool *passed)
2121 ceph::bufferlist bl;
2122 bl.append(test_data, data_len);
2123 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2124 printf("created completion\n");
2126 r = image.aio_writesame(off, len, bl, comp, iohint);
2127 printf("started writesame\n");
2128 if (len % data_len) {
2129 ASSERT_EQ(-EINVAL, r);
2130 printf("expected fail, finished writesame\n");
2136 comp->wait_for_complete();
2137 r = comp->get_return_value();
2138 printf("return value is: %d\n", r);
2140 printf("finished writesame\n");
2144 printf("to verify the data\n");
2146 uint64_t left = len;
2148 ceph::bufferlist bl;
2149 read = image.read(off, data_len, bl);
2150 ASSERT_EQ(data_len, static_cast<size_t>(read));
2151 std::string bl_str(bl.c_str(), read);
2152 int result = memcmp(bl_str.c_str(), test_data, data_len);
2154 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2155 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2156 ASSERT_EQ(0, result);
2161 ASSERT_EQ(0U, left);
2162 printf("verified\n");
2167 void writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2168 ssize_t len, size_t data_len, uint32_t iohint,
2172 ceph::bufferlist bl;
2173 bl.append(test_data, data_len);
2174 written = image.writesame(off, len, bl, iohint);
2175 if (len % data_len) {
2176 ASSERT_EQ(-EINVAL, written);
2177 printf("expected fail, finished writesame\n");
2181 ASSERT_EQ(len, written);
2182 printf("wrote: %u\n", (unsigned int) written);
2186 printf("to verify the data\n");
2188 uint64_t left = len;
2190 ceph::bufferlist bl;
2191 read = image.read(off, data_len, bl);
2192 ASSERT_EQ(data_len, static_cast<size_t>(read));
2193 std::string bl_str(bl.c_str(), read);
2194 int result = memcmp(bl_str.c_str(), test_data, data_len);
2196 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2197 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2198 ASSERT_EQ(0, result);
2203 ASSERT_EQ(0U, left);
2204 printf("verified\n");
2209 void aio_compare_and_write_test_data(librbd::Image& image, const char *cmp_data,
2210 const char *test_data, off_t off, ssize_t len,
2211 uint32_t iohint, bool *passed)
2213 ceph::bufferlist cmp_bl;
2214 cmp_bl.append(cmp_data, strlen(cmp_data));
2215 ceph::bufferlist test_bl;
2216 test_bl.append(test_data, strlen(test_data));
2217 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2218 printf("created completion\n");
2220 uint64_t mismatch_offset;
2221 image.aio_compare_and_write(off, len, cmp_bl, test_bl, comp, &mismatch_offset, iohint);
2222 printf("started aio compare and write\n");
2223 comp->wait_for_complete();
2224 int r = comp->get_return_value();
2225 printf("return value is: %d\n", r);
2227 printf("finished aio compare and write\n");
2232 void compare_and_write_test_data(librbd::Image& image, const char *cmp_data, const char *test_data,
2233 off_t off, ssize_t len, uint64_t *mismatch_off, uint32_t iohint, bool *passed)
2236 ceph::bufferlist cmp_bl;
2237 cmp_bl.append(cmp_data, strlen(cmp_data));
2238 ceph::bufferlist test_bl;
2239 test_bl.append(test_data, strlen(test_data));
2240 printf("start compare and write\n");
2241 written = image.compare_and_write(off, len, cmp_bl, test_bl, mismatch_off, iohint);
2242 printf("compare and wrote: %d\n", (int) written);
2243 ASSERT_EQ(len, static_cast<ssize_t>(written));
2247 TEST_F(TestLibRBD, TestIOPP)
2249 librados::IoCtx ioctx;
2250 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2252 bool skip_discard = is_skip_partial_discard_enabled();
2256 librbd::Image image;
2258 std::string name = get_temp_image_name();
2259 uint64_t size = 2 << 20;
2261 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2262 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2264 char test_data[TEST_IO_SIZE + 1];
2265 char zero_data[TEST_IO_SIZE + 1];
2267 uint64_t mismatch_offset;
2269 for (i = 0; i < TEST_IO_SIZE; ++i) {
2270 test_data[i] = (char) (rand() % (126 - 33) + 33);
2272 test_data[TEST_IO_SIZE] = '\0';
2273 memset(zero_data, 0, sizeof(zero_data));
2275 for (i = 0; i < 5; ++i)
2276 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i, 0);
2278 for (i = 5; i < 10; ++i)
2279 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i, 0);
2281 for (i = 0; i < 5; ++i)
2282 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2283 TEST_IO_SIZE, &mismatch_offset, 0);
2285 for (i = 5; i < 10; ++i)
2286 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2289 for (i = 0; i < 5; ++i)
2290 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2292 for (i = 5; i < 10; ++i)
2293 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2295 // discard 2nd, 4th sections.
2296 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2297 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2299 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
2300 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2301 TEST_IO_SIZE, TEST_IO_SIZE, 0);
2302 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
2303 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2304 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
2305 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2307 for (i = 0; i < 15; ++i) {
2309 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2310 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2311 } else if (i % 3 == 1) {
2312 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2313 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2315 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2316 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2319 for (i = 0; i < 15; ++i) {
2321 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2322 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2323 } else if (i % 3 == 1) {
2324 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2325 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2327 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2328 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2332 ASSERT_PASSED(validate_object_map, image);
2338 TEST_F(TestLibRBD, TestIOPPWithIOHint)
2340 librados::IoCtx ioctx;
2341 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2345 librbd::Image image;
2347 std::string name = get_temp_image_name();
2348 uint64_t size = 2 << 20;
2350 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2351 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2353 char test_data[TEST_IO_SIZE + 1];
2354 char zero_data[TEST_IO_SIZE + 1];
2355 test_data[TEST_IO_SIZE] = '\0';
2358 for (i = 0; i < TEST_IO_SIZE; ++i) {
2359 test_data[i] = (char) (rand() % (126 - 33) + 33);
2361 memset(zero_data, 0, sizeof(zero_data));
2363 for (i = 0; i < 5; ++i)
2364 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i,
2365 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2367 for (i = 5; i < 10; ++i)
2368 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i,
2369 LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2371 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data),
2372 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_RANDOM);
2374 for (i = 5; i < 10; ++i)
2375 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i,
2376 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2378 for (i = 0; i < 15; ++i) {
2380 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2381 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2382 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2383 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2384 } else if (i % 3 == 1) {
2385 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2386 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2387 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2388 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2390 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2391 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2392 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2393 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2396 for (i = 0; i < 15; ++i) {
2398 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2399 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2400 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2401 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2402 } else if (i % 3 == 1) {
2403 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2404 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2405 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2406 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2408 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2409 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2410 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2411 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2415 ASSERT_PASSED(validate_object_map, image);
2423 TEST_F(TestLibRBD, TestIOToSnapshot)
2425 rados_ioctx_t ioctx;
2426 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2430 std::string name = get_temp_image_name();
2431 uint64_t isize = 2 << 20;
2433 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
2434 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2437 rbd_image_t image_at_snap;
2438 char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
2439 char test_data[TEST_IO_TO_SNAP_SIZE + 1];
2441 for (i = 0; i < TEST_IO_TO_SNAP_SIZE; ++i)
2442 test_data[i] = (char) (i + 48);
2443 test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
2444 orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
2446 r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
2447 ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE);
2449 ASSERT_EQ(0, test_ls_snaps(image, 0));
2450 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
2451 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
2452 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2454 printf("write test data!\n");
2455 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2456 ASSERT_EQ(0, rbd_snap_create(image, "written"));
2457 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
2459 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2461 rbd_snap_set(image, "orig");
2462 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2464 rbd_snap_set(image, "written");
2465 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2467 rbd_snap_set(image, "orig");
2469 r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
2470 printf("write to snapshot returned %d\n", r);
2472 cout << strerror(-r) << std::endl;
2474 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2475 rbd_snap_set(image, "written");
2476 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2478 r = rbd_snap_rollback(image, "orig");
2479 ASSERT_EQ(r, -EROFS);
2481 r = rbd_snap_set(image, NULL);
2483 r = rbd_snap_rollback(image, "orig");
2486 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2490 printf("opening testimg@orig\n");
2491 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_at_snap, "orig"));
2492 ASSERT_PASSED(read_test_data, image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2493 r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
2494 printf("write to snapshot returned %d\n", r);
2496 cout << strerror(-r) << std::endl;
2497 ASSERT_EQ(0, rbd_close(image_at_snap));
2499 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
2500 ASSERT_EQ(0, rbd_snap_remove(image, "written"));
2501 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
2502 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
2503 ASSERT_EQ(0, test_ls_snaps(image, 0));
2505 ASSERT_PASSED(validate_object_map, image);
2506 ASSERT_EQ(0, rbd_close(image));
2508 rados_ioctx_destroy(ioctx);
2511 TEST_F(TestLibRBD, TestClone)
2513 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2515 rados_ioctx_t ioctx;
2516 rbd_image_info_t pinfo, cinfo;
2517 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2521 rbd_image_t parent, child;
2524 ASSERT_EQ(0, get_features(&old_format, &features));
2525 ASSERT_FALSE(old_format);
2527 std::string parent_name = get_temp_image_name();
2528 std::string child_name = get_temp_image_name();
2530 // make a parent to clone from
2531 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
2533 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
2534 printf("made parent image \"parent\"\n");
2536 char *data = (char *)"testdata";
2537 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
2539 // can't clone a non-snapshot, expect failure
2540 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
2541 child_name.c_str(), features, &order));
2543 // verify that there is no parent info on "parent"
2544 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
2545 printf("parent has no parent info\n");
2547 // create a snapshot, reopen as the parent we're interested in
2548 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2549 printf("made snapshot \"parent@parent_snap\"\n");
2550 ASSERT_EQ(0, rbd_close(parent));
2551 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
2553 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2554 ioctx, child_name.c_str(), features, &order));
2556 // unprotected image should fail unprotect
2557 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
2558 printf("can't unprotect an unprotected snap\n");
2560 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2561 // protecting again should fail
2562 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
2563 printf("can't protect a protected snap\n");
2565 // This clone and open should work
2566 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2567 ioctx, child_name.c_str(), features, &order));
2568 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
2569 printf("made and opened clone \"child\"\n");
2572 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
2575 ASSERT_EQ((ssize_t)strlen(data), rbd_write(child, 20, strlen(data), data));
2576 ASSERT_PASSED(read_test_data, child, data, 20, strlen(data), 0);
2577 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
2580 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
2581 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2582 EXPECT_EQ(cinfo.size, pinfo.size);
2584 rbd_get_overlap(child, &overlap);
2585 EXPECT_EQ(overlap, pinfo.size);
2586 EXPECT_EQ(cinfo.obj_size, pinfo.obj_size);
2587 EXPECT_EQ(cinfo.order, pinfo.order);
2588 printf("sizes and overlaps are good between parent and child\n");
2590 // sizing down child results in changing overlap and size, not parent size
2591 ASSERT_EQ(0, rbd_resize(child, 2UL<<20));
2592 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2593 rbd_get_overlap(child, &overlap);
2594 ASSERT_EQ(overlap, 2UL<<20);
2595 ASSERT_EQ(cinfo.size, 2UL<<20);
2596 ASSERT_EQ(0, rbd_resize(child, 4UL<<20));
2597 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2598 rbd_get_overlap(child, &overlap);
2599 ASSERT_EQ(overlap, 2UL<<20);
2600 ASSERT_EQ(cinfo.size, 4UL<<20);
2601 printf("sized down clone, changed overlap\n");
2603 // sizing back up doesn't change that
2604 ASSERT_EQ(0, rbd_resize(child, 5UL<<20));
2605 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2606 rbd_get_overlap(child, &overlap);
2607 ASSERT_EQ(overlap, 2UL<<20);
2608 ASSERT_EQ(cinfo.size, 5UL<<20);
2609 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
2610 printf("parent info: size %lld obj_size %lld parent_pool %lld\n",
2611 (unsigned long long)pinfo.size, (unsigned long long)pinfo.obj_size,
2612 (unsigned long long)pinfo.parent_pool);
2613 ASSERT_EQ(pinfo.size, 4UL<<20);
2614 printf("sized up clone, changed size but not overlap or parent's size\n");
2616 ASSERT_PASSED(validate_object_map, child);
2617 ASSERT_EQ(0, rbd_close(child));
2619 ASSERT_PASSED(validate_object_map, parent);
2620 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
2621 printf("can't remove parent while child still exists\n");
2622 ASSERT_EQ(0, rbd_remove(ioctx, child_name.c_str()));
2623 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
2624 printf("can't remove parent while still protected\n");
2625 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
2626 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
2627 printf("removed parent snap after unprotecting\n");
2629 ASSERT_EQ(0, rbd_close(parent));
2630 rados_ioctx_destroy(ioctx);
2633 TEST_F(TestLibRBD, TestClone2)
2635 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2637 rados_ioctx_t ioctx;
2638 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2642 rbd_image_t parent, child;
2645 ASSERT_EQ(0, get_features(&old_format, &features));
2646 ASSERT_FALSE(old_format);
2648 std::string parent_name = get_temp_image_name();
2649 std::string child_name = get_temp_image_name();
2651 // make a parent to clone from
2652 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
2654 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
2655 printf("made parent image \"parent\"\n");
2657 char *data = (char *)"testdata";
2658 char *childata = (char *)"childata";
2659 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
2660 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
2662 // can't clone a non-snapshot, expect failure
2663 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
2664 child_name.c_str(), features, &order));
2666 // verify that there is no parent info on "parent"
2667 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
2668 printf("parent has no parent info\n");
2670 // create a snapshot, reopen as the parent we're interested in
2671 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2672 printf("made snapshot \"parent@parent_snap\"\n");
2673 ASSERT_EQ(0, rbd_close(parent));
2674 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
2676 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2677 ioctx, child_name.c_str(), features, &order));
2679 // unprotected image should fail unprotect
2680 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
2681 printf("can't unprotect an unprotected snap\n");
2683 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2684 // protecting again should fail
2685 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
2686 printf("can't protect a protected snap\n");
2688 // This clone and open should work
2689 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2690 ioctx, child_name.c_str(), features, &order));
2691 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
2692 printf("made and opened clone \"child\"\n");
2694 // write something in
2695 ASSERT_EQ((ssize_t)strlen(childata), rbd_write(child, 20, strlen(childata), childata));
2697 char test[strlen(data) * 2];
2698 ASSERT_EQ((ssize_t)strlen(data), rbd_read(child, 20, strlen(data), test));
2699 ASSERT_EQ(0, memcmp(test, childata, strlen(childata)));
2702 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 20 - strlen(data), sizeof(test), test));
2703 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
2704 ASSERT_EQ(0, memcmp(test + strlen(data), childata, strlen(childata)));
2707 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 0, sizeof(test), test));
2708 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
2710 ASSERT_PASSED(validate_object_map, child);
2711 ASSERT_PASSED(validate_object_map, parent);
2713 ASSERT_EQ(0, rbd_close(child));
2714 ASSERT_EQ(0, rbd_close(parent));
2715 rados_ioctx_destroy(ioctx);
2718 static void test_list_children(rbd_image_t image, ssize_t num_expected, ...)
2721 va_start(ap, num_expected);
2722 size_t pools_len = 100;
2723 size_t children_len = 100;
2725 char *children = NULL;
2726 ssize_t num_children;
2731 pools = (char *) malloc(pools_len);
2732 children = (char *) malloc(children_len);
2733 num_children = rbd_list_children(image, pools, &pools_len,
2734 children, &children_len);
2735 } while (num_children == -ERANGE);
2737 ASSERT_EQ(num_expected, num_children);
2738 for (ssize_t i = num_expected; i > 0; --i) {
2739 char *expected_pool = va_arg(ap, char *);
2740 char *expected_image = va_arg(ap, char *);
2742 char *image = children;
2744 printf("\ntrying to find %s/%s\n", expected_pool, expected_image);
2745 for (ssize_t j = 0; j < num_children; ++j) {
2746 printf("checking %s/%s\n", pool, image);
2747 if (strcmp(expected_pool, pool) == 0 &&
2748 strcmp(expected_image, image) == 0) {
2749 printf("found child %s/%s\n\n", pool, image);
2753 pool += strlen(pool) + 1;
2754 image += strlen(image) + 1;
2755 if (j == num_children - 1) {
2756 ASSERT_EQ(pool - pools - 1, (ssize_t) pools_len);
2757 ASSERT_EQ(image - children - 1, (ssize_t) children_len);
2770 TEST_F(TestLibRBD, ListChildren)
2772 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2774 rados_ioctx_t ioctx1, ioctx2;
2775 string pool_name1 = create_pool(true);
2776 string pool_name2 = create_pool(true);
2777 ASSERT_NE("", pool_name2);
2779 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
2780 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
2787 ASSERT_EQ(0, get_features(&old_format, &features));
2788 ASSERT_FALSE(old_format);
2790 std::string parent_name = get_temp_image_name();
2791 std::string child_name1 = get_temp_image_name();
2792 std::string child_name2 = get_temp_image_name();
2793 std::string child_name3 = get_temp_image_name();
2794 std::string child_name4 = get_temp_image_name();
2796 // make a parent to clone from
2797 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
2799 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
2800 // create a snapshot, reopen as the parent we're interested in
2801 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2802 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
2803 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2805 ASSERT_EQ(0, rbd_close(parent));
2806 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
2808 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2809 ioctx2, child_name1.c_str(), features, &order));
2810 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
2812 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2813 ioctx1, child_name2.c_str(), features, &order));
2814 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
2815 pool_name1.c_str(), child_name2.c_str());
2817 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2818 ioctx2, child_name3.c_str(), features, &order));
2819 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
2820 pool_name1.c_str(), child_name2.c_str(),
2821 pool_name2.c_str(), child_name3.c_str());
2823 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2824 ioctx2, child_name4.c_str(), features, &order));
2825 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
2826 pool_name1.c_str(), child_name2.c_str(),
2827 pool_name2.c_str(), child_name3.c_str(),
2828 pool_name2.c_str(), child_name4.c_str());
2830 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
2831 test_list_children(parent, 3,
2832 pool_name1.c_str(), child_name2.c_str(),
2833 pool_name2.c_str(), child_name3.c_str(),
2834 pool_name2.c_str(), child_name4.c_str());
2836 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
2837 test_list_children(parent, 2,
2838 pool_name1.c_str(), child_name2.c_str(),
2839 pool_name2.c_str(), child_name4.c_str());
2841 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
2842 test_list_children(parent, 1,
2843 pool_name1.c_str(), child_name2.c_str());
2845 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
2846 test_list_children(parent, 0);
2848 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
2849 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
2850 ASSERT_EQ(0, rbd_close(parent));
2851 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
2852 rados_ioctx_destroy(ioctx1);
2853 rados_ioctx_destroy(ioctx2);
2856 TEST_F(TestLibRBD, ListChildrenTiered)
2858 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2860 string pool_name1 = m_pool_name;
2861 string pool_name2 = create_pool(true);
2862 string pool_name3 = create_pool(true);
2863 ASSERT_NE("", pool_name2);
2864 ASSERT_NE("", pool_name3);
2866 std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" +
2867 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\", \"force_nonempty\":\"\"}";
2869 cmd[0] = (char *)cmdstr.c_str();
2870 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
2872 cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
2873 pool_name3 + "\", \"mode\":\"writeback\"}";
2874 cmd[0] = (char *)cmdstr.c_str();
2875 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
2877 cmdstr = "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
2878 pool_name1 + "\", \"overlaypool\":\"" + pool_name3 + "\"}";
2879 cmd[0] = (char *)cmdstr.c_str();
2880 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
2882 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
2884 string parent_name = get_temp_image_name();
2885 string child_name1 = get_temp_image_name();
2886 string child_name2 = get_temp_image_name();
2887 string child_name3 = get_temp_image_name();
2888 string child_name4 = get_temp_image_name();
2890 rados_ioctx_t ioctx1, ioctx2;
2891 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
2892 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
2899 ASSERT_EQ(0, get_features(&old_format, &features));
2900 ASSERT_FALSE(old_format);
2902 // make a parent to clone from
2903 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
2905 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
2906 // create a snapshot, reopen as the parent we're interested in
2907 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2908 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
2909 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2911 ASSERT_EQ(0, rbd_close(parent));
2912 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
2914 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2915 ioctx2, child_name1.c_str(), features, &order));
2916 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
2918 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2919 ioctx1, child_name2.c_str(), features, &order));
2920 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
2921 pool_name1.c_str(), child_name2.c_str());
2923 // read from the cache to populate it
2924 rbd_image_t tier_image;
2925 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &tier_image, NULL));
2926 size_t len = 4 * 1024 * 1024;
2927 char* buf = (char*)malloc(len);
2928 ssize_t size = rbd_read(tier_image, 0, len, buf);
2931 ASSERT_EQ(0, rbd_close(tier_image));
2933 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2934 ioctx2, child_name3.c_str(), features, &order));
2935 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
2936 pool_name1.c_str(), child_name2.c_str(),
2937 pool_name2.c_str(), child_name3.c_str());
2939 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2940 ioctx2, child_name4.c_str(), features, &order));
2941 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
2942 pool_name1.c_str(), child_name2.c_str(),
2943 pool_name2.c_str(), child_name3.c_str(),
2944 pool_name2.c_str(), child_name4.c_str());
2946 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
2947 test_list_children(parent, 3,
2948 pool_name1.c_str(), child_name2.c_str(),
2949 pool_name2.c_str(), child_name3.c_str(),
2950 pool_name2.c_str(), child_name4.c_str());
2952 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
2953 test_list_children(parent, 2,
2954 pool_name1.c_str(), child_name2.c_str(),
2955 pool_name2.c_str(), child_name4.c_str());
2957 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
2958 test_list_children(parent, 1,
2959 pool_name1.c_str(), child_name2.c_str());
2961 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
2962 test_list_children(parent, 0);
2964 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
2965 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
2966 ASSERT_EQ(0, rbd_close(parent));
2967 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
2968 rados_ioctx_destroy(ioctx1);
2969 rados_ioctx_destroy(ioctx2);
2970 cmdstr = "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
2972 cmd[0] = (char *)cmdstr.c_str();
2973 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
2974 cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
2975 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\"}";
2976 cmd[0] = (char *)cmdstr.c_str();
2977 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
2980 TEST_F(TestLibRBD, LockingPP)
2982 librados::IoCtx ioctx;
2983 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2987 librbd::Image image;
2989 std::string name = get_temp_image_name();
2990 uint64_t size = 2 << 20;
2991 std::string cookie1 = "foo";
2992 std::string cookie2 = "bar";
2994 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2995 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2997 // no lockers initially
2998 std::list<librbd::locker_t> lockers;
3001 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3002 ASSERT_EQ(0u, lockers.size());
3005 // exclusive lock is exclusive
3006 ASSERT_EQ(0, image.lock_exclusive(cookie1));
3007 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3008 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3009 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3010 ASSERT_EQ(-EBUSY, image.lock_shared(cookie1, "test"));
3011 ASSERT_EQ(-EBUSY, image.lock_shared("", "test"));
3012 ASSERT_EQ(-EBUSY, image.lock_shared("", ""));
3015 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3016 ASSERT_TRUE(exclusive);
3018 ASSERT_EQ(1u, lockers.size());
3019 ASSERT_EQ(cookie1, lockers.front().cookie);
3022 ASSERT_EQ(-ENOENT, image.unlock(""));
3023 ASSERT_EQ(-ENOENT, image.unlock(cookie2));
3024 ASSERT_EQ(0, image.unlock(cookie1));
3025 ASSERT_EQ(-ENOENT, image.unlock(cookie1));
3026 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3027 ASSERT_EQ(0u, lockers.size());
3029 ASSERT_EQ(0, image.lock_shared(cookie1, ""));
3030 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3031 ASSERT_EQ(0, image.lock_shared(cookie2, ""));
3032 ASSERT_EQ(-EEXIST, image.lock_shared(cookie2, ""));
3033 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3034 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie2));
3035 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3036 ASSERT_EQ(-EBUSY, image.lock_exclusive("test"));
3039 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3040 ASSERT_EQ(2u, lockers.size());
3046 TEST_F(TestLibRBD, FlushAio)
3048 rados_ioctx_t ioctx;
3049 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3053 std::string name = get_temp_image_name();
3054 uint64_t size = 2 << 20;
3055 size_t num_aios = 256;
3057 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3058 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3060 char test_data[TEST_IO_SIZE + 1];
3062 for (i = 0; i < TEST_IO_SIZE; ++i) {
3063 test_data[i] = (char) (rand() % (126 - 33) + 33);
3066 rbd_completion_t write_comps[num_aios];
3067 for (i = 0; i < num_aios; ++i) {
3068 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &write_comps[i]));
3069 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3070 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
3074 rbd_completion_t flush_comp;
3075 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &flush_comp));
3076 ASSERT_EQ(0, rbd_aio_flush(image, flush_comp));
3077 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp));
3078 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp));
3079 rbd_aio_release(flush_comp);
3081 for (i = 0; i < num_aios; ++i) {
3082 ASSERT_EQ(1, rbd_aio_is_complete(write_comps[i]));
3083 rbd_aio_release(write_comps[i]);
3086 ASSERT_PASSED(validate_object_map, image);
3087 ASSERT_EQ(0, rbd_close(image));
3088 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
3089 rados_ioctx_destroy(ioctx);
3092 TEST_F(TestLibRBD, FlushAioPP)
3094 librados::IoCtx ioctx;
3095 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3099 librbd::Image image;
3101 std::string name = get_temp_image_name();
3102 uint64_t size = 2 << 20;
3103 const size_t num_aios = 256;
3105 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3106 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3108 char test_data[TEST_IO_SIZE + 1];
3110 for (i = 0; i < TEST_IO_SIZE; ++i) {
3111 test_data[i] = (char) (rand() % (126 - 33) + 33);
3113 test_data[TEST_IO_SIZE] = '\0';
3115 librbd::RBD::AioCompletion *write_comps[num_aios];
3116 ceph::bufferlist bls[num_aios];
3117 for (i = 0; i < num_aios; ++i) {
3118 bls[i].append(test_data, strlen(test_data));
3119 write_comps[i] = new librbd::RBD::AioCompletion(NULL, NULL);
3120 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3121 ASSERT_EQ(0, image.aio_write(offset, TEST_IO_SIZE, bls[i],
3125 librbd::RBD::AioCompletion *flush_comp =
3126 new librbd::RBD::AioCompletion(NULL, NULL);
3127 ASSERT_EQ(0, image.aio_flush(flush_comp));
3128 ASSERT_EQ(0, flush_comp->wait_for_complete());
3129 ASSERT_EQ(1, flush_comp->is_complete());
3130 flush_comp->release();
3132 for (i = 0; i < num_aios; ++i) {
3133 librbd::RBD::AioCompletion *comp = write_comps[i];
3134 ASSERT_EQ(1, comp->is_complete());
3137 ASSERT_PASSED(validate_object_map, image);
3144 int iterate_cb(uint64_t off, size_t len, int exists, void *arg)
3146 //cout << "iterate_cb " << off << "~" << len << std::endl;
3147 interval_set<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
3148 diff->insert(off, len);
3152 static int iterate_error_cb(uint64_t off, size_t len, int exists, void *arg)
3157 void scribble(librbd::Image& image, int n, int max, bool skip_discard,
3158 interval_set<uint64_t> *exists,
3159 interval_set<uint64_t> *what)
3163 interval_set<uint64_t> exists_at_start = *exists;
3165 for (int i=0; i<n; i++) {
3166 uint64_t off = rand() % (size - max + 1);
3167 uint64_t len = 1 + rand() % max;
3168 if (!skip_discard && rand() % 4 == 0) {
3169 ASSERT_EQ((int)len, image.discard(off, len));
3170 interval_set<uint64_t> w;
3173 // the zeroed bit no longer exists...
3174 w.intersection_of(*exists);
3175 exists->subtract(w);
3177 // the bits we discarded are no long written...
3178 interval_set<uint64_t> w2 = w;
3179 w2.intersection_of(*what);
3182 // except for the extents that existed at the start that we overwrote.
3183 interval_set<uint64_t> w3;
3184 w3.insert(off, len);
3185 w3.intersection_of(exists_at_start);
3190 bl.append(buffer::create(len));
3192 ASSERT_EQ((int)len, image.write(off, len, bl));
3193 interval_set<uint64_t> w;
3196 exists->union_of(w);
3201 interval_set<uint64_t> round_diff_interval(const interval_set<uint64_t>& diff,
3202 uint64_t object_size)
3204 if (object_size == 0) {
3208 interval_set<uint64_t> rounded_diff;
3209 for (interval_set<uint64_t>::const_iterator it = diff.begin();
3210 it != diff.end(); ++it) {
3211 uint64_t off = it.get_start();
3212 uint64_t len = it.get_len();
3213 off -= off % object_size;
3214 len += (object_size - (len % object_size));
3215 interval_set<uint64_t> interval;
3216 interval.insert(off, len);
3217 rounded_diff.union_of(interval);
3219 return rounded_diff;
3222 template <typename T>
3223 class DiffIterateTest : public TestLibRBD {
3225 static const uint8_t whole_object = T::whole_object;
3228 template <bool _whole_object>
3229 class DiffIterateParams {
3231 static const uint8_t whole_object = _whole_object;
3234 typedef ::testing::Types<DiffIterateParams<false>,
3235 DiffIterateParams<true> > DiffIterateTypes;
3236 TYPED_TEST_CASE(DiffIterateTest, DiffIterateTypes);
3238 TYPED_TEST(DiffIterateTest, DiffIterate)
3240 librados::IoCtx ioctx;
3241 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3243 bool skip_discard = this->is_skip_partial_discard_enabled();
3247 librbd::Image image;
3249 std::string name = this->get_temp_image_name();
3250 uint64_t size = 20 << 20;
3252 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3253 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3255 uint64_t object_size = 0;
3256 if (this->whole_object) {
3257 object_size = 1 << order;
3260 interval_set<uint64_t> exists;
3261 interval_set<uint64_t> one, two;
3262 scribble(image, 10, 102400, skip_discard, &exists, &one);
3263 cout << " wrote " << one << std::endl;
3264 ASSERT_EQ(0, image.snap_create("one"));
3265 scribble(image, 10, 102400, skip_discard, &exists, &two);
3267 two = round_diff_interval(two, object_size);
3268 cout << " wrote " << two << std::endl;
3270 interval_set<uint64_t> diff;
3271 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
3272 iterate_cb, (void *)&diff));
3273 cout << " diff was " << diff << std::endl;
3274 if (!two.subset_of(diff)) {
3275 interval_set<uint64_t> i;
3276 i.intersection_of(two, diff);
3277 interval_set<uint64_t> l = two;
3279 cout << " ... two - (two*diff) = " << l << std::endl;
3281 ASSERT_TRUE(two.subset_of(diff));
3286 struct diff_extent {
3287 diff_extent(uint64_t _offset, uint64_t _length, bool _exists,
3288 uint64_t object_size) :
3289 offset(_offset), length(_length), exists(_exists)
3291 if (object_size != 0) {
3292 offset -= offset % object_size;
3293 length = object_size;
3299 bool operator==(const diff_extent& o) const {
3300 return offset == o.offset && length == o.length && exists == o.exists;
3304 ostream& operator<<(ostream & o, const diff_extent& e) {
3305 return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')';
3308 int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg)
3310 cout << "iterate_cb " << off << "~" << len << std::endl;
3311 vector<diff_extent> *diff = static_cast<vector<diff_extent> *>(arg);
3312 diff->push_back(diff_extent(off, len, exists, 0));
3316 TYPED_TEST(DiffIterateTest, DiffIterateDiscard)
3318 librados::IoCtx ioctx;
3319 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3322 librbd::Image image;
3324 std::string name = this->get_temp_image_name();
3325 uint64_t size = 20 << 20;
3327 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3328 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3330 uint64_t object_size = 0;
3331 if (this->whole_object) {
3332 object_size = 1 << order;
3334 vector<diff_extent> extents;
3335 ceph::bufferlist bl;
3337 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3338 vector_iterate_cb, (void *) &extents));
3339 ASSERT_EQ(0u, extents.size());
3342 memset(data, 1, sizeof(data));
3343 bl.append(data, 256);
3344 ASSERT_EQ(256, image.write(0, 256, bl));
3345 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3346 vector_iterate_cb, (void *) &extents));
3347 ASSERT_EQ(1u, extents.size());
3348 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3351 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
3354 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3355 vector_iterate_cb, (void *) &extents));
3356 ASSERT_EQ(0u, extents.size());
3358 ASSERT_EQ(0, image.snap_create("snap1"));
3359 ASSERT_EQ(256, image.write(0, 256, bl));
3360 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3361 vector_iterate_cb, (void *) &extents));
3362 ASSERT_EQ(1u, extents.size());
3363 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3364 ASSERT_EQ(0, image.snap_create("snap2"));
3366 ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs));
3369 ASSERT_EQ(0, image.snap_set("snap2"));
3370 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
3371 vector_iterate_cb, (void *) &extents));
3372 ASSERT_EQ(1u, extents.size());
3373 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3375 ASSERT_EQ(0, image.snap_set(NULL));
3376 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
3377 ASSERT_EQ(0, image.snap_create("snap3"));
3378 ASSERT_EQ(0, image.snap_set("snap3"));
3381 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
3382 vector_iterate_cb, (void *) &extents));
3383 ASSERT_EQ(1u, extents.size());
3384 ASSERT_EQ(diff_extent(0, 256, false, object_size), extents[0]);
3385 ASSERT_PASSED(this->validate_object_map, image);
3388 TYPED_TEST(DiffIterateTest, DiffIterateStress)
3390 librados::IoCtx ioctx;
3391 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3393 bool skip_discard = this->is_skip_partial_discard_enabled();
3396 librbd::Image image;
3398 std::string name = this->get_temp_image_name();
3399 uint64_t size = 400 << 20;
3401 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3402 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3404 uint64_t object_size = 0;
3405 if (this->whole_object) {
3406 object_size = 1 << order;
3409 interval_set<uint64_t> curexists;
3410 vector<interval_set<uint64_t> > wrote;
3411 vector<interval_set<uint64_t> > exists;
3412 vector<string> snap;
3414 for (int i=0; i<n; i++) {
3415 interval_set<uint64_t> w;
3416 scribble(image, 10, 8192000, skip_discard, &curexists, &w);
3417 cout << " i=" << i << " exists " << curexists << " wrote " << w << std::endl;
3418 string s = "snap" + stringify(i);
3419 ASSERT_EQ(0, image.snap_create(s.c_str()));
3421 exists.push_back(curexists);
3425 for (int h=0; h<n-1; h++) {
3426 for (int i=0; i<n-h-1; i++) {
3427 for (int j=(h==0 ? i+1 : n-1); j<n; j++) {
3428 interval_set<uint64_t> diff, actual, uex;
3429 for (int k=i+1; k<=j; k++)
3430 diff.union_of(wrote[k]);
3431 cout << "from " << i << " to "
3432 << (h != 0 ? string("HEAD") : stringify(j)) << " diff "
3433 << round_diff_interval(diff, object_size) << std::endl;
3435 // limit to extents that exists both at the beginning and at the end
3436 uex.union_of(exists[i], exists[j]);
3437 diff.intersection_of(uex);
3438 diff = round_diff_interval(diff, object_size);
3439 cout << " limited diff " << diff << std::endl;
3441 ASSERT_EQ(0, image.snap_set(h==0 ? snap[j].c_str() : NULL));
3442 ASSERT_EQ(0, image.diff_iterate2(snap[i].c_str(), 0, size, true,
3443 this->whole_object, iterate_cb,
3445 cout << " actual was " << actual << std::endl;
3446 if (!diff.subset_of(actual)) {
3447 interval_set<uint64_t> i;
3448 i.intersection_of(diff, actual);
3449 interval_set<uint64_t> l = diff;
3451 cout << " ... diff - (actual*diff) = " << l << std::endl;
3453 ASSERT_TRUE(diff.subset_of(actual));
3456 ASSERT_EQ(0, image.snap_set(NULL));
3457 ASSERT_EQ(0, image.snap_remove(snap[n-h-1].c_str()));
3460 ASSERT_PASSED(this->validate_object_map, image);
3463 TYPED_TEST(DiffIterateTest, DiffIterateRegression6926)
3465 librados::IoCtx ioctx;
3466 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3469 librbd::Image image;
3471 std::string name = this->get_temp_image_name();
3472 uint64_t size = 20 << 20;
3474 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3475 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3477 uint64_t object_size = 0;
3478 if (this->whole_object) {
3479 object_size = 1 << order;
3481 vector<diff_extent> extents;
3482 ceph::bufferlist bl;
3484 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3485 vector_iterate_cb, (void *) &extents));
3486 ASSERT_EQ(0u, extents.size());
3488 ASSERT_EQ(0, image.snap_create("snap1"));
3490 memset(data, 1, sizeof(data));
3491 bl.append(data, 256);
3492 ASSERT_EQ(256, image.write(0, 256, bl));
3495 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3496 vector_iterate_cb, (void *) &extents));
3497 ASSERT_EQ(1u, extents.size());
3498 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3500 ASSERT_EQ(0, image.snap_set("snap1"));
3502 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3503 vector_iterate_cb, (void *) &extents));
3504 ASSERT_EQ(static_cast<size_t>(0), extents.size());
3507 TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
3509 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3511 librados::IoCtx ioctx;
3512 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3514 bool skip_discard = this->is_skip_partial_discard_enabled();
3517 librbd::Image image;
3518 std::string name = this->get_temp_image_name();
3519 uint64_t size = 20 << 20;
3522 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3523 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3525 uint64_t object_size = 0;
3526 if (this->whole_object) {
3527 object_size = 1 << order;
3531 bl.append(buffer::create(size));
3533 interval_set<uint64_t> one;
3534 one.insert(0, size);
3535 ASSERT_EQ((int)size, image.write(0, size, bl));
3536 ASSERT_EQ(0, image.snap_create("one"));
3537 ASSERT_EQ(0, image.snap_protect("one"));
3539 std::string clone_name = this->get_temp_image_name();
3540 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
3541 RBD_FEATURE_LAYERING, &order));
3542 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
3544 interval_set<uint64_t> exists;
3545 interval_set<uint64_t> two;
3546 scribble(image, 10, 102400, skip_discard, &exists, &two);
3547 two = round_diff_interval(two, object_size);
3548 cout << " wrote " << two << " to clone" << std::endl;
3550 interval_set<uint64_t> diff;
3551 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, false, this->whole_object,
3552 iterate_cb, (void *)&diff));
3553 cout << " diff was " << diff << std::endl;
3554 if (!this->whole_object) {
3555 ASSERT_FALSE(one.subset_of(diff));
3557 ASSERT_TRUE(two.subset_of(diff));
3560 TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
3562 librados::IoCtx ioctx;
3563 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3565 bool skip_discard = this->is_skip_partial_discard_enabled();
3569 librbd::Image image;
3571 std::string name = this->get_temp_image_name();
3572 uint64_t size = 20 << 20;
3574 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3575 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3577 interval_set<uint64_t> exists;
3578 interval_set<uint64_t> one;
3579 scribble(image, 10, 102400, skip_discard, &exists, &one);
3580 cout << " wrote " << one << std::endl;
3582 interval_set<uint64_t> diff;
3583 ASSERT_EQ(-EINVAL, image.diff_iterate2(NULL, 0, size, true,
3585 iterate_error_cb, NULL));
3590 TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
3592 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3594 librados::IoCtx ioctx;
3595 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3597 bool skip_discard = this->is_skip_partial_discard_enabled();
3600 librbd::Image image;
3601 std::string name = this->get_temp_image_name();
3602 uint64_t size = 20 << 20;
3605 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3606 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3608 uint64_t object_size = 0;
3609 if (this->whole_object) {
3610 object_size = 1 << order;
3613 interval_set<uint64_t> exists;
3614 interval_set<uint64_t> one;
3615 scribble(image, 10, 102400, skip_discard, &exists, &one);
3616 ASSERT_EQ(0, image.snap_create("one"));
3618 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
3619 ASSERT_EQ(0, image.snap_create("two"));
3620 ASSERT_EQ(0, image.snap_protect("two"));
3624 std::string clone_name = this->get_temp_image_name();
3625 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "two", ioctx,
3626 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
3627 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
3629 interval_set<uint64_t> two;
3630 scribble(image, 10, 102400, skip_discard, &exists, &two);
3631 two = round_diff_interval(two, object_size);
3633 interval_set<uint64_t> diff;
3634 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3635 iterate_cb, (void *)&diff));
3636 ASSERT_TRUE(two.subset_of(diff));
3639 TEST_F(TestLibRBD, ZeroLengthWrite)
3641 rados_ioctx_t ioctx;
3642 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3646 std::string name = get_temp_image_name();
3647 uint64_t size = 2 << 20;
3649 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3650 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3653 ASSERT_EQ(0, rbd_write(image, 0, 0, NULL));
3654 ASSERT_EQ(1, rbd_read(image, 0, 1, read_data));
3655 ASSERT_EQ('\0', read_data[0]);
3657 ASSERT_PASSED(validate_object_map, image);
3658 ASSERT_EQ(0, rbd_close(image));
3660 rados_ioctx_destroy(ioctx);
3664 TEST_F(TestLibRBD, ZeroLengthDiscard)
3666 rados_ioctx_t ioctx;
3667 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3671 std::string name = get_temp_image_name();
3672 uint64_t size = 2 << 20;
3674 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3675 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3677 const char data[] = "blah";
3678 char read_data[sizeof(data)];
3679 ASSERT_EQ((int)strlen(data), rbd_write(image, 0, strlen(data), data));
3680 ASSERT_EQ(0, rbd_discard(image, 0, 0));
3681 ASSERT_EQ((int)strlen(data), rbd_read(image, 0, strlen(data), read_data));
3682 ASSERT_EQ(0, memcmp(data, read_data, strlen(data)));
3684 ASSERT_PASSED(validate_object_map, image);
3685 ASSERT_EQ(0, rbd_close(image));
3687 rados_ioctx_destroy(ioctx);
3690 TEST_F(TestLibRBD, ZeroLengthRead)
3692 rados_ioctx_t ioctx;
3693 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3697 std::string name = get_temp_image_name();
3698 uint64_t size = 2 << 20;
3700 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3701 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3704 ASSERT_EQ(0, rbd_read(image, 0, 0, read_data));
3706 ASSERT_EQ(0, rbd_close(image));
3708 rados_ioctx_destroy(ioctx);
3711 TEST_F(TestLibRBD, LargeCacheRead)
3713 std::string config_value;
3714 ASSERT_EQ(0, _rados.conf_get("rbd_cache", config_value));
3715 if (config_value == "false") {
3716 std::cout << "SKIPPING due to disabled cache" << std::endl;
3720 rados_ioctx_t ioctx;
3721 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3723 uint32_t new_cache_size = 1 << 20;
3724 std::string orig_cache_size;
3725 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", orig_cache_size));
3726 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size",
3727 stringify(new_cache_size).c_str()));
3728 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", config_value));
3729 ASSERT_EQ(stringify(new_cache_size), config_value);
3730 BOOST_SCOPE_EXIT( (orig_cache_size) ) {
3731 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size", orig_cache_size.c_str()));
3732 } BOOST_SCOPE_EXIT_END;
3736 std::string name = get_temp_image_name();
3737 uint64_t size = 1 << order;
3739 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3740 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3742 std::string buffer(1 << order, '1');
3744 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
3745 rbd_write(image, 0, buffer.size(), buffer.c_str()));
3747 ASSERT_EQ(0, rbd_invalidate_cache(image));
3749 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
3750 rbd_read(image, 0, buffer.size(), &buffer[0]));
3752 ASSERT_EQ(0, rbd_close(image));
3754 rados_ioctx_destroy(ioctx);
3757 TEST_F(TestLibRBD, TestPendingAio)
3759 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3761 rados_ioctx_t ioctx;
3762 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3769 ASSERT_EQ(0, get_features(&old_format, &features));
3770 ASSERT_FALSE(old_format);
3772 std::string name = get_temp_image_name();
3774 uint64_t size = 4 << 20;
3775 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
3777 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3779 char test_data[TEST_IO_SIZE];
3780 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
3781 test_data[i] = (char) (rand() % (126 - 33) + 33);
3784 size_t num_aios = 256;
3785 rbd_completion_t comps[num_aios];
3786 for (size_t i = 0; i < num_aios; ++i) {
3787 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
3788 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3789 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
3792 for (size_t i = 0; i < num_aios; ++i) {
3793 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps[i]));
3794 rbd_aio_release(comps[i]);
3796 ASSERT_EQ(0, rbd_invalidate_cache(image));
3798 for (size_t i = 0; i < num_aios; ++i) {
3799 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
3800 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3801 ASSERT_LE(0, rbd_aio_read(image, offset, TEST_IO_SIZE, test_data,
3805 ASSERT_PASSED(validate_object_map, image);
3806 ASSERT_EQ(0, rbd_close(image));
3807 for (size_t i = 0; i < num_aios; ++i) {
3808 ASSERT_EQ(1, rbd_aio_is_complete(comps[i]));
3809 rbd_aio_release(comps[i]);
3812 rados_ioctx_destroy(ioctx);
3815 TEST_F(TestLibRBD, Flatten)
3817 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3819 librados::IoCtx ioctx;
3820 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3823 std::string parent_name = get_temp_image_name();
3824 uint64_t size = 2 << 20;
3826 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
3828 librbd::Image parent_image;
3829 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
3832 bl.append(std::string(4096, '1'));
3833 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
3835 ASSERT_EQ(0, parent_image.snap_create("snap1"));
3836 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
3839 ASSERT_EQ(0, parent_image.features(&features));
3841 std::string clone_name = get_temp_image_name();
3842 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
3843 clone_name.c_str(), features, &order));
3845 librbd::Image clone_image;
3846 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
3847 ASSERT_EQ(0, clone_image.flatten());
3849 librbd::RBD::AioCompletion *read_comp =
3850 new librbd::RBD::AioCompletion(NULL, NULL);
3852 clone_image.aio_read(0, bl.length(), read_bl, read_comp);
3853 ASSERT_EQ(0, read_comp->wait_for_complete());
3854 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
3855 read_comp->release();
3856 ASSERT_TRUE(bl.contents_equal(read_bl));
3858 ASSERT_PASSED(validate_object_map, clone_image);
3861 TEST_F(TestLibRBD, SnapshotLimit)
3863 rados_ioctx_t ioctx;
3864 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3868 std::string name = get_temp_image_name();
3869 uint64_t size = 2 << 20;
3872 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3873 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3875 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
3876 ASSERT_EQ(UINT64_MAX, limit);
3877 ASSERT_EQ(0, rbd_snap_set_limit(image, 2));
3878 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
3879 ASSERT_EQ(2U, limit);
3881 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
3882 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
3883 ASSERT_EQ(-EDQUOT, rbd_snap_create(image, "snap3"));
3884 ASSERT_EQ(0, rbd_snap_set_limit(image, UINT64_MAX));
3885 ASSERT_EQ(0, rbd_snap_create(image, "snap3"));
3886 ASSERT_EQ(0, rbd_close(image));
3888 rados_ioctx_destroy(ioctx);
3892 TEST_F(TestLibRBD, SnapshotLimitPP)
3894 librados::IoCtx ioctx;
3895 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3899 librbd::Image image;
3900 std::string name = get_temp_image_name();
3901 uint64_t size = 2 << 20;
3905 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3906 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3908 ASSERT_EQ(0, image.snap_get_limit(&limit));
3909 ASSERT_EQ(UINT64_MAX, limit);
3910 ASSERT_EQ(0, image.snap_set_limit(2));
3911 ASSERT_EQ(0, image.snap_get_limit(&limit));
3912 ASSERT_EQ(2U, limit);
3914 ASSERT_EQ(0, image.snap_create("snap1"));
3915 ASSERT_EQ(0, image.snap_create("snap2"));
3916 ASSERT_EQ(-EDQUOT, image.snap_create("snap3"));
3917 ASSERT_EQ(0, image.snap_set_limit(UINT64_MAX));
3918 ASSERT_EQ(0, image.snap_create("snap3"));
3924 TEST_F(TestLibRBD, RebuildObjectMapViaLockOwner)
3926 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
3928 librados::IoCtx ioctx;
3929 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3932 std::string name = get_temp_image_name();
3933 uint64_t size = 2 << 20;
3935 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3937 std::string object_map_oid;
3939 librbd::Image image;
3940 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3942 std::string image_id;
3943 ASSERT_EQ(0, get_image_id(image, &image_id));
3944 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
3947 // corrupt the object map
3950 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
3952 librbd::Image image1;
3953 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
3957 ASSERT_EQ(0, image1.write(0, 0, bl));
3958 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
3959 ASSERT_TRUE(lock_owner);
3962 ASSERT_EQ(0, image1.get_flags(&flags));
3963 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
3965 librbd::Image image2;
3966 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
3967 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
3968 ASSERT_FALSE(lock_owner);
3970 PrintProgress prog_ctx;
3971 ASSERT_EQ(0, image2.rebuild_object_map(prog_ctx));
3972 ASSERT_PASSED(validate_object_map, image1);
3973 ASSERT_PASSED(validate_object_map, image2);
3976 TEST_F(TestLibRBD, RenameViaLockOwner)
3978 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
3980 librados::IoCtx ioctx;
3981 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3984 std::string name = get_temp_image_name();
3985 uint64_t size = 2 << 20;
3987 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3989 librbd::Image image1;
3990 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
3993 ASSERT_EQ(0, image1.write(0, 0, bl));
3996 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
3997 ASSERT_TRUE(lock_owner);
3999 std::string new_name = get_temp_image_name();
4000 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
4001 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4002 ASSERT_TRUE(lock_owner);
4004 librbd::Image image2;
4005 ASSERT_EQ(0, rbd.open(ioctx, image2, new_name.c_str(), NULL));
4008 TEST_F(TestLibRBD, SnapCreateViaLockOwner)
4010 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4012 librados::IoCtx ioctx;
4013 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4016 std::string name = get_temp_image_name();
4017 uint64_t size = 2 << 20;
4019 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4021 librbd::Image image1;
4022 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4024 // switch to writeback cache
4025 ASSERT_EQ(0, image1.flush());
4028 bl.append(std::string(4096, '1'));
4029 ASSERT_EQ((ssize_t)bl.length(), image1.write(0, bl.length(), bl));
4032 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4033 ASSERT_TRUE(lock_owner);
4035 librbd::Image image2;
4036 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4038 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4039 ASSERT_FALSE(lock_owner);
4041 ASSERT_EQ(0, image2.snap_create("snap1"));
4043 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4044 ASSERT_TRUE(exists);
4045 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
4046 ASSERT_TRUE(exists);
4048 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4049 ASSERT_TRUE(lock_owner);
4052 TEST_F(TestLibRBD, SnapRemoveViaLockOwner)
4054 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4056 librados::IoCtx ioctx;
4057 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4060 std::string name = get_temp_image_name();
4061 uint64_t size = 2 << 20;
4063 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4065 librbd::Image image1;
4066 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4069 ASSERT_EQ(0, image1.write(0, 0, bl));
4070 ASSERT_EQ(0, image1.snap_create("snap1"));
4073 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4074 ASSERT_TRUE(lock_owner);
4076 librbd::Image image2;
4077 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4079 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4080 ASSERT_FALSE(lock_owner);
4082 ASSERT_EQ(0, image2.snap_remove("snap1"));
4084 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4085 ASSERT_FALSE(exists);
4086 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
4087 ASSERT_FALSE(exists);
4089 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4090 ASSERT_TRUE(lock_owner);
4093 TEST_F(TestLibRBD, SnapRemove2)
4095 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4097 librados::IoCtx ioctx;
4098 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4101 std::string name = get_temp_image_name();
4102 uint64_t size = 2 << 20;
4104 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4106 librbd::Image image1;
4107 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4110 ASSERT_EQ(0, image1.write(0, 0, bl));
4111 ASSERT_EQ(0, image1.snap_create("snap1"));
4113 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4114 ASSERT_TRUE(exists);
4115 ASSERT_EQ(0, image1.snap_protect("snap1"));
4117 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4118 ASSERT_TRUE(is_protected);
4121 ASSERT_EQ(0, image1.features(&features));
4123 std::string child_name = get_temp_image_name();
4124 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
4125 child_name.c_str(), features, &order));
4127 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4128 ASSERT_TRUE(exists);
4129 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4130 ASSERT_TRUE(is_protected);
4132 ASSERT_EQ(-EBUSY, image1.snap_remove("snap1"));
4134 ASSERT_EQ(0, image1.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE, pp));
4135 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4136 ASSERT_FALSE(exists);
4139 TEST_F(TestLibRBD, SnapRenameViaLockOwner)
4141 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4143 librados::IoCtx ioctx;
4144 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4147 std::string name = get_temp_image_name();
4148 uint64_t size = 2 << 20;
4150 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4152 librbd::Image image1;
4153 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4156 ASSERT_EQ(0, image1.write(0, 0, bl));
4157 ASSERT_EQ(0, image1.snap_create("snap1"));
4160 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4161 ASSERT_TRUE(lock_owner);
4163 librbd::Image image2;
4164 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4166 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4167 ASSERT_FALSE(lock_owner);
4169 ASSERT_EQ(0, image2.snap_rename("snap1", "snap1-rename"));
4171 ASSERT_EQ(0, image1.snap_exists2("snap1-rename", &exists));
4172 ASSERT_TRUE(exists);
4173 ASSERT_EQ(0, image2.snap_exists2("snap1-rename", &exists));
4174 ASSERT_TRUE(exists);
4176 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4177 ASSERT_TRUE(lock_owner);
4180 TEST_F(TestLibRBD, SnapProtectViaLockOwner)
4182 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4184 librados::IoCtx ioctx;
4185 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4188 std::string name = get_temp_image_name();
4189 uint64_t size = 2 << 20;
4191 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4193 librbd::Image image1;
4194 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4197 ASSERT_EQ(0, image1.write(0, 0, bl));
4200 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4201 ASSERT_TRUE(lock_owner);
4202 ASSERT_EQ(0, image1.snap_create("snap1"));
4204 librbd::Image image2;
4205 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4207 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4208 ASSERT_FALSE(lock_owner);
4210 ASSERT_EQ(0, image2.snap_protect("snap1"));
4212 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
4213 ASSERT_TRUE(is_protected);
4214 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4215 ASSERT_TRUE(is_protected);
4217 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4218 ASSERT_TRUE(lock_owner);
4221 TEST_F(TestLibRBD, SnapUnprotectViaLockOwner)
4223 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4225 librados::IoCtx ioctx;
4226 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4229 std::string name = get_temp_image_name();
4230 uint64_t size = 2 << 20;
4232 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4234 librbd::Image image1;
4235 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4238 ASSERT_EQ(0, image1.write(0, 0, bl));
4241 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4242 ASSERT_TRUE(lock_owner);
4243 ASSERT_EQ(0, image1.snap_create("snap1"));
4244 ASSERT_EQ(0, image1.snap_protect("snap1"));
4246 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4247 ASSERT_TRUE(is_protected);
4249 librbd::Image image2;
4250 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4252 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4253 ASSERT_FALSE(lock_owner);
4255 ASSERT_EQ(0, image2.snap_unprotect("snap1"));
4256 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
4257 ASSERT_FALSE(is_protected);
4258 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4259 ASSERT_FALSE(is_protected);
4261 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4262 ASSERT_TRUE(lock_owner);
4265 TEST_F(TestLibRBD, FlattenViaLockOwner)
4267 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
4269 librados::IoCtx ioctx;
4270 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4273 std::string parent_name = get_temp_image_name();
4274 uint64_t size = 2 << 20;
4276 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4278 librbd::Image parent_image;
4279 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4280 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4281 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4284 ASSERT_EQ(0, parent_image.features(&features));
4286 std::string name = get_temp_image_name();
4287 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4288 name.c_str(), features, &order));
4290 librbd::Image image1;
4291 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4294 ASSERT_EQ(0, image1.write(0, 0, bl));
4297 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4298 ASSERT_TRUE(lock_owner);
4300 librbd::Image image2;
4301 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4303 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4304 ASSERT_FALSE(lock_owner);
4306 ASSERT_EQ(0, image2.flatten());
4308 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4309 ASSERT_TRUE(lock_owner);
4310 ASSERT_PASSED(validate_object_map, image1);
4313 TEST_F(TestLibRBD, ResizeViaLockOwner)
4315 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
4317 librados::IoCtx ioctx;
4318 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4321 std::string name = get_temp_image_name();
4322 uint64_t size = 2 << 20;
4324 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4326 librbd::Image image1;
4327 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4330 ASSERT_EQ(0, image1.write(0, 0, bl));
4333 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4334 ASSERT_TRUE(lock_owner);
4336 librbd::Image image2;
4337 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4339 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4340 ASSERT_FALSE(lock_owner);
4342 ASSERT_EQ(0, image2.resize(0));
4344 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4345 ASSERT_TRUE(lock_owner);
4346 ASSERT_PASSED(validate_object_map, image1);
4349 TEST_F(TestLibRBD, ObjectMapConsistentSnap)
4351 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
4353 librados::IoCtx ioctx;
4354 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4357 std::string name = get_temp_image_name();
4358 uint64_t size = 1 << 20;
4360 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4362 librbd::Image image1;
4363 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4366 for (int i = 0; i < num_snaps; ++i) {
4367 std::string snap_name = "snap" + stringify(i);
4368 ASSERT_EQ(0, image1.snap_create(snap_name.c_str()));
4372 thread writer([&image1](){
4373 librbd::image_info_t info;
4374 int r = image1.stat(info, sizeof(info));
4378 for (unsigned i = 0; i < info.num_objs; ++i) {
4379 r = image1.write((1 << info.order) * i, bl.length(), bl);
4380 assert(r == (int) bl.length());
4385 for (int i = 0; i < num_snaps; ++i) {
4386 std::string snap_name = "snap" + stringify(i);
4387 ASSERT_EQ(0, image1.snap_set(snap_name.c_str()));
4388 ASSERT_PASSED(validate_object_map, image1);
4391 ASSERT_EQ(0, image1.snap_set(NULL));
4392 ASSERT_PASSED(validate_object_map, image1);
4395 void memset_rand(char *buf, size_t len) {
4396 for (size_t i = 0; i < len; ++i) {
4397 buf[i] = (char) (rand() % (126 - 33) + 33);
4401 TEST_F(TestLibRBD, Metadata)
4403 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4405 rados_ioctx_t ioctx;
4406 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4408 std::string name = get_temp_image_name();
4409 uint64_t size = 2 << 20;
4411 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4414 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4417 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
4421 size_t keys_len = sizeof(keys);
4422 size_t vals_len = sizeof(vals);
4424 memset_rand(keys, keys_len);
4425 memset_rand(vals, vals_len);
4427 ASSERT_EQ(0, rbd_metadata_list(image, "", 0, keys, &keys_len, vals,
4429 ASSERT_EQ(0U, keys_len);
4430 ASSERT_EQ(0U, vals_len);
4433 size_t value_len = sizeof(value);
4434 memset_rand(value, value_len);
4436 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
4437 ASSERT_EQ(0, rbd_metadata_set(image1, "key2", "value2"));
4438 ASSERT_EQ(0, rbd_metadata_get(image1, "key1", value, &value_len));
4439 ASSERT_STREQ(value, "value1");
4441 ASSERT_EQ(-ERANGE, rbd_metadata_get(image1, "key1", value, &value_len));
4442 ASSERT_EQ(value_len, strlen("value1") + 1);
4444 ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4446 keys_len = sizeof(keys);
4447 vals_len = sizeof(vals);
4448 memset_rand(keys, keys_len);
4449 memset_rand(vals, vals_len);
4450 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4452 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
4453 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
4454 ASSERT_STREQ(keys, "key1");
4455 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
4456 ASSERT_STREQ(vals, "value1");
4457 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
4459 ASSERT_EQ(0, rbd_metadata_remove(image1, "key1"));
4460 ASSERT_EQ(-ENOENT, rbd_metadata_remove(image1, "key3"));
4461 value_len = sizeof(value);
4462 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key3", value, &value_len));
4463 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4465 ASSERT_EQ(keys_len, strlen("key2") + 1);
4466 ASSERT_EQ(vals_len, strlen("value2") + 1);
4467 ASSERT_STREQ(keys, "key2");
4468 ASSERT_STREQ(vals, "value2");
4470 // test config setting
4471 ASSERT_EQ(0, rbd_metadata_set(image1, "conf_rbd_cache", "false"));
4472 ASSERT_EQ(-EINVAL, rbd_metadata_set(image1, "conf_rbd_cache", "INVALID_VAL"));
4473 ASSERT_EQ(0, rbd_metadata_remove(image1, "conf_rbd_cache"));
4475 // test metadata with snapshot adding
4476 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
4477 ASSERT_EQ(0, rbd_snap_protect(image1, "snap1"));
4478 ASSERT_EQ(0, rbd_snap_set(image1, "snap1"));
4480 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
4481 ASSERT_EQ(0, rbd_metadata_set(image1, "key3", "value3"));
4483 keys_len = sizeof(keys);
4484 vals_len = sizeof(vals);
4485 memset_rand(keys, keys_len);
4486 memset_rand(vals, vals_len);
4487 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4490 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4492 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4493 ASSERT_STREQ(keys, "key1");
4494 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
4495 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
4496 ASSERT_STREQ(vals, "value1");
4497 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
4498 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
4500 ASSERT_EQ(0, rbd_snap_set(image1, NULL));
4501 keys_len = sizeof(keys);
4502 vals_len = sizeof(vals);
4503 memset_rand(keys, keys_len);
4504 memset_rand(vals, vals_len);
4505 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4508 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4510 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4511 ASSERT_STREQ(keys, "key1");
4512 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
4513 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
4514 ASSERT_STREQ(vals, "value1");
4515 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
4516 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
4518 // test metadata with cloning
4520 ASSERT_EQ(0, rbd_get_features(image1, &features));
4522 string cname = get_temp_image_name();
4523 EXPECT_EQ(0, rbd_clone(ioctx, name.c_str(), "snap1", ioctx,
4524 cname.c_str(), features, &order));
4526 ASSERT_EQ(0, rbd_open(ioctx, cname.c_str(), &image2, NULL));
4527 ASSERT_EQ(0, rbd_metadata_set(image2, "key4", "value4"));
4529 keys_len = sizeof(keys);
4530 vals_len = sizeof(vals);
4531 memset_rand(keys, keys_len);
4532 memset_rand(vals, vals_len);
4533 ASSERT_EQ(0, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
4535 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4536 1 + strlen("key4") + 1);
4537 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
4538 strlen("value3") + 1 + strlen("value4") + 1);
4539 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4541 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1 +
4542 strlen("value3") + 1, "value4");
4544 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4547 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4549 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4550 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key4", value, &value_len));
4552 // test short buffer cases
4553 keys_len = strlen("key1") + 1;
4554 vals_len = strlen("value1") + 1;
4555 memset_rand(keys, keys_len);
4556 memset_rand(vals, vals_len);
4557 ASSERT_EQ(0, rbd_metadata_list(image2, "", 1, keys, &keys_len, vals,
4559 ASSERT_EQ(keys_len, strlen("key1") + 1);
4560 ASSERT_EQ(vals_len, strlen("value1") + 1);
4561 ASSERT_STREQ(keys, "key1");
4562 ASSERT_STREQ(vals, "value1");
4564 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 2, keys, &keys_len, vals,
4566 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
4567 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
4569 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
4571 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4572 1 + strlen("key4") + 1);
4573 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
4574 strlen("value3") + 1 + strlen("value4") + 1);
4576 // test `start` param
4577 keys_len = sizeof(keys);
4578 vals_len = sizeof(vals);
4579 memset_rand(keys, keys_len);
4580 memset_rand(vals, vals_len);
4581 ASSERT_EQ(0, rbd_metadata_list(image2, "key2", 0, keys, &keys_len, vals,
4583 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
4584 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
4585 ASSERT_STREQ(keys, "key3");
4586 ASSERT_STREQ(vals, "value3");
4588 ASSERT_EQ(0, rbd_close(image));
4589 ASSERT_EQ(0, rbd_close(image1));
4590 ASSERT_EQ(0, rbd_close(image2));
4591 rados_ioctx_destroy(ioctx);
4594 TEST_F(TestLibRBD, MetadataPP)
4596 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4598 librados::IoCtx ioctx;
4599 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4602 string name = get_temp_image_name();
4603 uint64_t size = 2 << 20;
4607 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4609 librbd::Image image1;
4610 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4611 map<string, bufferlist> pairs;
4612 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4613 ASSERT_TRUE(pairs.empty());
4615 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
4616 ASSERT_EQ(0, image1.metadata_set("key2", "value2"));
4617 ASSERT_EQ(0, image1.metadata_get("key1", &value));
4618 ASSERT_EQ(0, strcmp("value1", value.c_str()));
4619 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4620 ASSERT_EQ(2U, pairs.size());
4621 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
4622 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4625 ASSERT_EQ(0, image1.metadata_remove("key1"));
4626 ASSERT_EQ(-ENOENT, image1.metadata_remove("key3"));
4627 ASSERT_TRUE(image1.metadata_get("key3", &value) < 0);
4628 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4629 ASSERT_EQ(1U, pairs.size());
4630 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4632 // test config setting
4633 ASSERT_EQ(0, image1.metadata_set("conf_rbd_cache", "false"));
4634 ASSERT_EQ(-EINVAL, image1.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
4635 ASSERT_EQ(0, image1.metadata_remove("conf_rbd_cache"));
4637 // test metadata with snapshot adding
4638 ASSERT_EQ(0, image1.snap_create("snap1"));
4639 ASSERT_EQ(0, image1.snap_protect("snap1"));
4640 ASSERT_EQ(0, image1.snap_set("snap1"));
4643 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
4644 ASSERT_EQ(0, image1.metadata_set("key3", "value3"));
4645 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4646 ASSERT_EQ(3U, pairs.size());
4647 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
4648 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4649 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
4651 ASSERT_EQ(0, image1.snap_set(NULL));
4652 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4653 ASSERT_EQ(3U, pairs.size());
4654 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
4655 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4656 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
4658 // test metadata with cloning
4659 string cname = get_temp_image_name();
4660 librbd::Image image2;
4661 ASSERT_EQ(0, image1.features(&features));
4662 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
4663 cname.c_str(), features, &order));
4664 ASSERT_EQ(0, rbd.open(ioctx, image2, cname.c_str(), NULL));
4665 ASSERT_EQ(0, image2.metadata_set("key4", "value4"));
4667 ASSERT_EQ(0, image2.metadata_list("", 0, &pairs));
4668 ASSERT_EQ(4U, pairs.size());
4670 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4671 ASSERT_EQ(3U, pairs.size());
4672 ASSERT_EQ(-ENOENT, image1.metadata_get("key4", &value));
4675 TEST_F(TestLibRBD, UpdateFeatures)
4677 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4679 librados::IoCtx ioctx;
4680 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4683 std::string name = get_temp_image_name();
4684 uint64_t size = 1 << 20;
4686 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4688 librbd::Image image;
4689 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4692 ASSERT_EQ(0, image.old_format(&old_format));
4694 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
4699 ASSERT_EQ(0, image.features(&features));
4701 // must provide a single feature
4702 ASSERT_EQ(-EINVAL, image.update_features(0, true));
4704 uint64_t disable_features;
4705 disable_features = features & (RBD_FEATURE_EXCLUSIVE_LOCK |
4706 RBD_FEATURE_OBJECT_MAP |
4707 RBD_FEATURE_FAST_DIFF |
4708 RBD_FEATURE_JOURNALING);
4709 if (disable_features != 0) {
4710 ASSERT_EQ(0, image.update_features(disable_features, false));
4713 ASSERT_EQ(0, image.features(&features));
4714 ASSERT_EQ(0U, features & disable_features);
4716 // cannot enable object map nor journaling w/o exclusive lock
4717 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
4718 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_JOURNALING, true));
4719 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
4721 ASSERT_EQ(0, image.features(&features));
4722 ASSERT_NE(0U, features & RBD_FEATURE_EXCLUSIVE_LOCK);
4724 // cannot enable fast diff w/o object map
4725 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_FAST_DIFF, true));
4726 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
4727 ASSERT_EQ(0, image.features(&features));
4728 ASSERT_NE(0U, features & RBD_FEATURE_OBJECT_MAP);
4730 uint64_t expected_flags = RBD_FLAG_OBJECT_MAP_INVALID;
4732 ASSERT_EQ(0, image.get_flags(&flags));
4733 ASSERT_EQ(expected_flags, flags);
4735 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
4736 ASSERT_EQ(0, image.features(&features));
4737 ASSERT_EQ(0U, features & RBD_FEATURE_OBJECT_MAP);
4739 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP |
4740 RBD_FEATURE_FAST_DIFF |
4741 RBD_FEATURE_JOURNALING, true));
4743 expected_flags = RBD_FLAG_OBJECT_MAP_INVALID | RBD_FLAG_FAST_DIFF_INVALID;
4744 ASSERT_EQ(0, image.get_flags(&flags));
4745 ASSERT_EQ(expected_flags, flags);
4747 // cannot disable object map w/ fast diff
4748 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
4749 ASSERT_EQ(0, image.update_features(RBD_FEATURE_FAST_DIFF, false));
4750 ASSERT_EQ(0, image.features(&features));
4751 ASSERT_EQ(0U, features & RBD_FEATURE_FAST_DIFF);
4753 expected_flags = RBD_FLAG_OBJECT_MAP_INVALID;
4754 ASSERT_EQ(0, image.get_flags(&flags));
4755 ASSERT_EQ(expected_flags, flags);
4757 // cannot disable exclusive lock w/ object map
4758 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
4759 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
4761 // cannot disable exclusive lock w/ journaling
4762 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
4763 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, false));
4765 ASSERT_EQ(0, image.get_flags(&flags));
4766 ASSERT_EQ(0U, flags);
4768 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
4770 ASSERT_EQ(0, image.features(&features));
4771 if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0) {
4772 ASSERT_EQ(0, image.update_features(RBD_FEATURE_DEEP_FLATTEN, false));
4774 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_DEEP_FLATTEN, true));
4777 TEST_F(TestLibRBD, RebuildObjectMap)
4779 librados::IoCtx ioctx;
4780 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4783 std::string name = get_temp_image_name();
4784 uint64_t size = 1 << 20;
4786 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4788 PrintProgress prog_ctx;
4789 std::string object_map_oid;
4793 librbd::Image image;
4794 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4797 ASSERT_EQ(0, image.features(&features));
4798 if ((features & RBD_FEATURE_OBJECT_MAP) == 0) {
4799 ASSERT_EQ(-EINVAL, image.rebuild_object_map(prog_ctx));
4803 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
4805 ASSERT_EQ(0, image.snap_create("snap1"));
4806 ASSERT_EQ((ssize_t)bl.length(), image.write(1<<order, bl.length(), bl));
4808 std::string image_id;
4809 ASSERT_EQ(0, get_image_id(image, &image_id));
4810 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
4813 // corrupt the object map
4814 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
4816 librbd::Image image1;
4817 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4821 ASSERT_EQ(0, image1.write(0, 0, bl));
4822 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4823 ASSERT_TRUE(lock_owner);
4826 ASSERT_EQ(0, image1.get_flags(&flags));
4827 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
4829 ASSERT_EQ(0, image1.rebuild_object_map(prog_ctx));
4831 librbd::Image image2;
4832 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4835 ASSERT_EQ((ssize_t)bl.length(), image2.read(0, bl.length(), read_bl));
4836 ASSERT_TRUE(bl.contents_equal(read_bl));
4839 ASSERT_EQ((ssize_t)bl.length(), image2.read(1<<order, bl.length(), read_bl));
4840 ASSERT_TRUE(bl.contents_equal(read_bl));
4842 ASSERT_PASSED(validate_object_map, image1);
4843 ASSERT_PASSED(validate_object_map, image2);
4846 TEST_F(TestLibRBD, RebuildNewObjectMap)
4848 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
4850 rados_ioctx_t ioctx;
4851 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4853 std::string name = get_temp_image_name();
4854 uint64_t size = 1 << 20;
4856 uint64_t features = RBD_FEATURE_EXCLUSIVE_LOCK;
4857 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
4861 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4862 ASSERT_EQ(0, rbd_update_features(image, RBD_FEATURE_OBJECT_MAP, true));
4863 ASSERT_EQ(0, rbd_rebuild_object_map(image, print_progress_percent, NULL));
4865 ASSERT_PASSED(validate_object_map, image);
4867 ASSERT_EQ(0, rbd_close(image));
4868 rados_ioctx_destroy(ioctx);
4871 TEST_F(TestLibRBD, CheckObjectMap)
4873 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
4875 librados::IoCtx ioctx;
4876 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4879 std::string name = get_temp_image_name();
4880 uint64_t size = 1 << 20;
4882 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4884 PrintProgress prog_ctx;
4889 librbd::Image image;
4890 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4893 ASSERT_EQ(0, image.features(&features));
4895 ASSERT_EQ((ssize_t)bl1.length(), image.write(0, bl1.length(), bl1));
4897 ASSERT_EQ(0, image.snap_create("snap1"));
4898 ASSERT_EQ((ssize_t)bl1.length(), image.write(1<<order, bl1.length(), bl1));
4901 librbd::Image image1;
4902 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4904 std::string image_id;
4905 ASSERT_EQ(0, get_image_id(image1, &image_id));
4907 std::string object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
4909 ASSERT_LT(0, ioctx.read(object_map_oid, bl2, 1024, 0));
4912 ASSERT_EQ((ssize_t)bl1.length(), image1.write(3 * (1 << 18), bl1.length(), bl1));
4913 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4914 ASSERT_TRUE(lock_owner);
4916 //reopen image to reread now corrupt object map from disk
4920 ASSERT_LT(0, ioctx.read(object_map_oid, bl1, 1024, 0));
4921 ASSERT_FALSE(bl1.contents_equal(bl2));
4923 ASSERT_EQ(0, ioctx.write_full(object_map_oid, bl2));
4924 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4927 ASSERT_EQ(0, image1.get_flags(&flags));
4928 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
4930 ASSERT_EQ(0, image1.check_object_map(prog_ctx));
4932 ASSERT_EQ(0, image1.get_flags(&flags));
4933 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
4936 TEST_F(TestLibRBD, BlockingAIO)
4938 librados::IoCtx ioctx;
4939 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4941 bool skip_discard = is_skip_partial_discard_enabled();
4944 std::string name = get_temp_image_name();
4945 uint64_t size = 1 << 20;
4947 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4949 std::string non_blocking_aio;
4950 ASSERT_EQ(0, _rados.conf_get("rbd_non_blocking_aio", non_blocking_aio));
4951 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio", "0"));
4952 BOOST_SCOPE_EXIT( (non_blocking_aio) ) {
4953 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio",
4954 non_blocking_aio.c_str()));
4955 } BOOST_SCOPE_EXIT_END;
4957 librbd::Image image;
4958 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4961 ASSERT_EQ(0, image.write(0, bl.length(), bl));
4963 bl.append(std::string(256, '1'));
4964 librbd::RBD::AioCompletion *write_comp =
4965 new librbd::RBD::AioCompletion(NULL, NULL);
4966 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
4968 librbd::RBD::AioCompletion *flush_comp =
4969 new librbd::RBD::AioCompletion(NULL, NULL);
4970 ASSERT_EQ(0, image.aio_flush(flush_comp));
4971 ASSERT_EQ(0, flush_comp->wait_for_complete());
4972 ASSERT_EQ(0, flush_comp->get_return_value());
4973 flush_comp->release();
4975 ASSERT_EQ(1, write_comp->is_complete());
4976 ASSERT_EQ(0, write_comp->get_return_value());
4977 write_comp->release();
4979 librbd::RBD::AioCompletion *discard_comp =
4980 new librbd::RBD::AioCompletion(NULL, NULL);
4981 ASSERT_EQ(0, image.aio_discard(128, 128, discard_comp));
4982 ASSERT_EQ(0, discard_comp->wait_for_complete());
4983 discard_comp->release();
4985 librbd::RBD::AioCompletion *read_comp =
4986 new librbd::RBD::AioCompletion(NULL, NULL);
4988 image.aio_read(0, bl.length(), read_bl, read_comp);
4989 ASSERT_EQ(0, read_comp->wait_for_complete());
4990 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
4991 read_comp->release();
4993 bufferlist expected_bl;
4994 expected_bl.append(std::string(128, '1'));
4995 expected_bl.append(std::string(128, skip_discard ? '1' : '\0'));
4996 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
4999 TEST_F(TestLibRBD, ExclusiveLockTransition)
5001 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5003 librados::IoCtx ioctx;
5004 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5007 std::string name = get_temp_image_name();
5009 uint64_t size = 1 << 18;
5011 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5013 librbd::Image image1;
5014 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5016 librbd::Image image2;
5017 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5019 std::list<librbd::RBD::AioCompletion *> comps;
5020 ceph::bufferlist bl;
5021 bl.append(std::string(1 << order, '1'));
5022 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5023 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
5025 comps.push_back(comp);
5026 if (object_no % 2 == 0) {
5027 ASSERT_EQ(0, image1.aio_write(object_no << order, bl.length(), bl, comp));
5029 ASSERT_EQ(0, image2.aio_write(object_no << order, bl.length(), bl, comp));
5033 while (!comps.empty()) {
5034 librbd::RBD::AioCompletion *comp = comps.front();
5036 ASSERT_EQ(0, comp->wait_for_complete());
5037 ASSERT_EQ(1, comp->is_complete());
5041 librbd::Image image3;
5042 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
5043 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5045 ASSERT_EQ((ssize_t)bl.length(), image3.read(object_no << order, bl.length(),
5047 ASSERT_TRUE(bl.contents_equal(read_bl));
5050 ASSERT_PASSED(validate_object_map, image1);
5051 ASSERT_PASSED(validate_object_map, image2);
5052 ASSERT_PASSED(validate_object_map, image3);
5055 TEST_F(TestLibRBD, ExclusiveLockReadTransition)
5057 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
5059 librados::IoCtx ioctx;
5060 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5063 std::string name = get_temp_image_name();
5065 uint64_t size = 1 << 18;
5067 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5069 librbd::Image image1;
5070 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5073 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5074 ASSERT_FALSE(lock_owner);
5076 // journaling should force read ops to acquire the lock
5078 ASSERT_EQ(0, image1.read(0, 0, read_bl));
5080 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5081 ASSERT_TRUE(lock_owner);
5083 librbd::Image image2;
5084 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5086 std::list<librbd::RBD::AioCompletion *> comps;
5087 std::list<bufferlist> read_bls;
5088 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5089 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
5091 comps.push_back(comp);
5092 read_bls.emplace_back();
5093 if (object_no % 2 == 0) {
5094 ASSERT_EQ(0, image1.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
5096 ASSERT_EQ(0, image2.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
5100 while (!comps.empty()) {
5101 librbd::RBD::AioCompletion *comp = comps.front();
5103 ASSERT_EQ(0, comp->wait_for_complete());
5104 ASSERT_EQ(1, comp->is_complete());
5109 TEST_F(TestLibRBD, CacheMayCopyOnWrite) {
5110 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5112 librados::IoCtx ioctx;
5113 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5116 std::string name = get_temp_image_name();
5118 uint64_t size = 1 << 18;
5120 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5122 librbd::Image image;
5123 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5124 ASSERT_EQ(0, image.snap_create("one"));
5125 ASSERT_EQ(0, image.snap_protect("one"));
5127 std::string clone_name = this->get_temp_image_name();
5128 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
5129 RBD_FEATURE_LAYERING, &order));
5131 librbd::Image clone;
5132 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
5133 ASSERT_EQ(0, clone.flush());
5135 bufferlist expect_bl;
5136 expect_bl.append(std::string(1024, '\0'));
5138 // test double read path
5140 uint64_t offset = 0;
5141 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
5142 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
5144 bufferlist write_bl;
5145 write_bl.append(std::string(1024, '1'));
5146 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
5149 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
5150 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
5152 // test read retry path
5153 offset = 1 << order;
5154 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
5157 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
5158 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
5161 TEST_F(TestLibRBD, FlushEmptyOpsOnExternalSnapshot) {
5162 std::string cache_enabled;
5163 ASSERT_EQ(0, _rados.conf_get("rbd_cache", cache_enabled));
5164 ASSERT_EQ(0, _rados.conf_set("rbd_cache", "false"));
5165 BOOST_SCOPE_EXIT( (cache_enabled) ) {
5166 ASSERT_EQ(0, _rados.conf_set("rbd_cache", cache_enabled.c_str()));
5167 } BOOST_SCOPE_EXIT_END;
5169 librados::IoCtx ioctx;
5170 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5173 std::string name = get_temp_image_name();
5174 uint64_t size = 1 << 18;
5176 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5178 librbd::Image image1;
5179 librbd::Image image2;
5180 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5181 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5182 ASSERT_EQ(0, image1.snap_create("snap1"));
5184 librbd::RBD::AioCompletion *read_comp =
5185 new librbd::RBD::AioCompletion(NULL, NULL);
5187 image2.aio_read(0, 1024, read_bl, read_comp);
5188 ASSERT_EQ(0, read_comp->wait_for_complete());
5189 read_comp->release();
5192 TEST_F(TestLibRBD, TestImageOptions)
5194 rados_ioctx_t ioctx;
5195 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5197 //make create image options
5198 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
5200 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
5201 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
5202 rbd_image_options_t opts;
5203 rbd_image_options_create(&opts);
5206 ASSERT_EQ(-EINVAL, rbd_image_options_is_set(opts, 12345, &is_set));
5207 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
5209 ASSERT_FALSE(is_set);
5211 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
5213 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
5215 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
5217 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
5219 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
5222 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
5224 ASSERT_TRUE(is_set);
5226 std::string parent_name = get_temp_image_name();
5229 ASSERT_EQ(0, rbd_create4(ioctx, parent_name.c_str(), 4<<20, opts));
5231 // check order is returned in opts
5232 ASSERT_EQ(0, rbd_image_options_get_uint64(opts, RBD_IMAGE_OPTION_ORDER,
5234 ASSERT_NE((uint64_t)0, order);
5236 // write some data to parent
5238 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
5239 char *data = (char *)"testdata";
5240 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
5241 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
5243 // create a snapshot, reopen as the parent we're interested in
5244 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
5245 ASSERT_EQ(0, rbd_close(parent));
5246 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
5249 std::string child_name = get_temp_image_name();
5250 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
5251 ASSERT_EQ(0, rbd_clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
5252 child_name.c_str(), opts));
5255 std::string copy1_name = get_temp_image_name();
5256 ASSERT_EQ(0, rbd_copy3(parent, ioctx, copy1_name.c_str(), opts));
5257 std::string copy2_name = get_temp_image_name();
5258 ASSERT_EQ(0, rbd_copy_with_progress3(parent, ioctx, copy2_name.c_str(), opts,
5259 print_progress_percent, NULL));
5261 ASSERT_EQ(0, rbd_close(parent));
5263 rbd_image_options_destroy(opts);
5265 rados_ioctx_destroy(ioctx);
5268 TEST_F(TestLibRBD, TestImageOptionsPP)
5270 librados::IoCtx ioctx;
5271 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5273 //make create image options
5274 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
5276 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
5277 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
5278 librbd::ImageOptions opts;
5279 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2)));
5280 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FEATURES, features));
5281 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_ORDER, order));
5282 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
5283 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
5286 std::string parent_name = get_temp_image_name();
5289 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 4<<20, opts));
5291 // check order is returned in opts
5292 ASSERT_EQ(0, opts.get(RBD_IMAGE_OPTION_ORDER, &order));
5293 ASSERT_NE((uint64_t)0, order);
5295 // write some data to parent
5296 librbd::Image parent;
5297 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
5301 bl.append(buffer::create(len));
5303 ASSERT_EQ(len, parent.write(0, len, bl));
5304 ASSERT_EQ(len, parent.write(len, len, bl));
5306 // create a snapshot, reopen as the parent we're interested in
5307 ASSERT_EQ(0, parent.snap_create("parent_snap"));
5308 ASSERT_EQ(0, parent.close());
5309 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
5312 std::string child_name = get_temp_image_name();
5313 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
5314 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
5315 child_name.c_str(), opts));
5318 std::string copy1_name = get_temp_image_name();
5319 ASSERT_EQ(0, parent.copy3(ioctx, copy1_name.c_str(), opts));
5320 std::string copy2_name = get_temp_image_name();
5322 ASSERT_EQ(0, parent.copy_with_progress3(ioctx, copy2_name.c_str(), opts, pp));
5324 ASSERT_EQ(0, parent.close());
5327 TEST_F(TestLibRBD, EventSocketPipe)
5329 EventSocket event_sock;
5330 int pipe_fd[2]; // read and write fd
5333 ASSERT_EQ(0, pipe(pipe_fd));
5335 ASSERT_FALSE(event_sock.is_valid());
5337 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_NONE));
5338 ASSERT_FALSE(event_sock.is_valid());
5340 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], 44));
5341 ASSERT_FALSE(event_sock.is_valid());
5343 #ifndef HAVE_EVENTFD
5344 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_EVENTFD));
5345 ASSERT_FALSE(event_sock.is_valid());
5348 ASSERT_EQ(0, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_PIPE));
5349 ASSERT_TRUE(event_sock.is_valid());
5350 ASSERT_EQ(0, event_sock.notify());
5351 ASSERT_EQ(1, read(pipe_fd[0], buf, 32));
5352 ASSERT_EQ('i', buf[0]);
5358 TEST_F(TestLibRBD, EventSocketEventfd)
5361 EventSocket event_sock;
5363 struct pollfd poll_fd;
5366 event_fd = eventfd(0, EFD_NONBLOCK);
5367 ASSERT_NE(-1, event_fd);
5369 ASSERT_FALSE(event_sock.is_valid());
5371 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, EVENT_SOCKET_TYPE_NONE));
5372 ASSERT_FALSE(event_sock.is_valid());
5374 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, 44));
5375 ASSERT_FALSE(event_sock.is_valid());
5377 ASSERT_EQ(0, event_sock.init(event_fd, EVENT_SOCKET_TYPE_EVENTFD));
5378 ASSERT_TRUE(event_sock.is_valid());
5379 ASSERT_EQ(0, event_sock.notify());
5381 poll_fd.fd = event_fd;
5382 poll_fd.events = POLLIN;
5383 ASSERT_EQ(1, poll(&poll_fd, 1, -1));
5384 ASSERT_TRUE(poll_fd.revents & POLLIN);
5386 ASSERT_EQ(static_cast<ssize_t>(sizeof(uint64_t)), read(event_fd, buf, 32));
5387 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf));
5393 TEST_F(TestLibRBD, ImagePollIO)
5396 rados_ioctx_t ioctx;
5397 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5401 std::string name = get_temp_image_name();
5402 uint64_t size = 2 << 20;
5403 int fd = eventfd(0, EFD_NONBLOCK);
5405 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5406 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5408 ASSERT_EQ(0, rbd_set_image_notification(image, fd, EVENT_SOCKET_TYPE_EVENTFD));
5410 char test_data[TEST_IO_SIZE + 1];
5411 char zero_data[TEST_IO_SIZE + 1];
5414 for (i = 0; i < TEST_IO_SIZE; ++i)
5415 test_data[i] = (char) (rand() % (126 - 33) + 33);
5416 test_data[TEST_IO_SIZE] = '\0';
5417 memset(zero_data, 0, sizeof(zero_data));
5419 for (i = 0; i < 5; ++i)
5420 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
5422 for (i = 5; i < 10; ++i)
5423 ASSERT_PASSED(aio_write_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
5425 for (i = 5; i < 10; ++i)
5426 ASSERT_PASSED(aio_read_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
5428 ASSERT_EQ(0, rbd_close(image));
5429 rados_ioctx_destroy(ioctx);
5435 static bool operator==(const mirror_peer_t &lhs, const mirror_peer_t &rhs) {
5436 return (lhs.uuid == rhs.uuid &&
5437 lhs.cluster_name == rhs.cluster_name &&
5438 lhs.client_name == rhs.client_name);
5441 static std::ostream& operator<<(std::ostream &os, const mirror_peer_t &peer) {
5442 os << "uuid=" << peer.uuid << ", "
5443 << "cluster=" << peer.cluster_name << ", "
5444 << "client=" << peer.client_name;
5448 } // namespace librbd
5450 TEST_F(TestLibRBD, Mirror) {
5451 librados::IoCtx ioctx;
5452 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5456 std::vector<librbd::mirror_peer_t> expected_peers;
5457 std::vector<librbd::mirror_peer_t> peers;
5458 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
5459 ASSERT_EQ(expected_peers, peers);
5462 ASSERT_EQ(-EINVAL, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
5464 rbd_mirror_mode_t mirror_mode;
5465 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
5466 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED, mirror_mode);
5468 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
5469 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
5471 // Add some images to the pool
5473 std::string parent_name = get_temp_image_name();
5474 std::string child_name = get_temp_image_name();
5475 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), 2 << 20,
5479 ASSERT_EQ(0, get_features(&old_format, &features));
5480 if ((features & RBD_FEATURE_LAYERING) != 0) {
5481 librbd::Image parent;
5482 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
5483 ASSERT_EQ(0, parent.snap_create("parent_snap"));
5484 ASSERT_EQ(0, parent.close());
5485 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
5486 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
5487 ASSERT_EQ(0, parent.close());
5488 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "parent_snap", ioctx,
5489 child_name.c_str(), features, &order));
5492 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE, mirror_mode);
5494 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_POOL));
5495 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
5496 ASSERT_EQ(RBD_MIRROR_MODE_POOL, mirror_mode);
5500 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
5501 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid2, "cluster2", "admin"));
5502 ASSERT_EQ(-EEXIST, rbd.mirror_peer_add(ioctx, &uuid3, "cluster1", "foo"));
5503 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid3, "cluster3", "admin"));
5505 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
5506 auto sort_peers = [](const librbd::mirror_peer_t &lhs,
5507 const librbd::mirror_peer_t &rhs) {
5508 return lhs.uuid < rhs.uuid;
5511 {uuid1, "cluster1", "client"},
5512 {uuid2, "cluster2", "admin"},
5513 {uuid3, "cluster3", "admin"}};
5514 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
5515 ASSERT_EQ(expected_peers, peers);
5517 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, "uuid4"));
5518 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid2));
5520 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_client(ioctx, "uuid4", "new client"));
5521 ASSERT_EQ(0, rbd.mirror_peer_set_client(ioctx, uuid1, "new client"));
5523 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_cluster(ioctx, "uuid4",
5525 ASSERT_EQ(0, rbd.mirror_peer_set_cluster(ioctx, uuid3, "new cluster"));
5527 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
5529 {uuid1, "cluster1", "new client"},
5530 {uuid3, "new cluster", "admin"}};
5531 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
5532 ASSERT_EQ(expected_peers, peers);
5534 ASSERT_EQ(-EBUSY, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
5537 TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {
5538 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5540 librados::IoCtx ioctx;
5541 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5544 librbd::Image image;
5545 std::string name = get_temp_image_name();
5547 uint64_t size = 1 << 18;
5550 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5551 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5554 bl.append(std::string(size, '1'));
5555 ASSERT_EQ((int)size, image.write(0, size, bl));
5556 ASSERT_EQ(0, image.snap_create("one"));
5557 ASSERT_EQ(0, image.snap_protect("one"));
5559 std::string clone_name = this->get_temp_image_name();
5560 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
5561 RBD_FEATURE_LAYERING, &order));
5562 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
5564 librbd::Image image2;
5565 ASSERT_EQ(0, rbd.open(ioctx, image2, clone_name.c_str(), NULL));
5567 // prepare CoW writeback that will be flushed on next op
5569 bl.append(std::string(1, '1'));
5570 ASSERT_EQ(0, image.flush());
5571 ASSERT_EQ(1, image.write(0, 1, bl));
5572 ASSERT_EQ(0, image2.snap_create("snap1"));
5574 librbd::RBD::AioCompletion *read_comp =
5575 new librbd::RBD::AioCompletion(NULL, NULL);
5577 image.aio_read(0, 1024, read_bl, read_comp);
5578 ASSERT_EQ(0, read_comp->wait_for_complete());
5579 read_comp->release();
5582 TEST_F(TestLibRBD, ExclusiveLock)
5584 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5586 static char buf[10];
5588 rados_ioctx_t ioctx;
5589 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5591 std::string name = get_temp_image_name();
5592 uint64_t size = 2 << 20;
5594 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5597 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
5600 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
5601 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5602 ASSERT_TRUE(lock_owner);
5604 rbd_lock_mode_t lock_mode;
5605 char *lock_owners[1];
5606 size_t max_lock_owners = 0;
5607 ASSERT_EQ(-ERANGE, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
5609 ASSERT_EQ(1U, max_lock_owners);
5611 max_lock_owners = 2;
5612 ASSERT_EQ(0, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
5614 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
5615 ASSERT_STRNE("", lock_owners[0]);
5616 ASSERT_EQ(1U, max_lock_owners);
5619 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
5621 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5622 ASSERT_FALSE(lock_owner);
5624 ASSERT_EQ(-EOPNOTSUPP, rbd_lock_break(image1, RBD_LOCK_MODE_SHARED, ""));
5625 ASSERT_EQ(-EBUSY, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
5628 ASSERT_EQ(0, rbd_lock_release(image1));
5629 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5630 ASSERT_FALSE(lock_owner);
5632 ASSERT_EQ(-ENOENT, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
5634 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
5636 ASSERT_EQ(-EROFS, rbd_write(image1, 0, sizeof(buf), buf));
5637 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image2, 0, sizeof(buf), buf));
5639 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
5640 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5641 ASSERT_TRUE(lock_owner);
5643 ASSERT_EQ(0, rbd_lock_release(image2));
5644 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5645 ASSERT_FALSE(lock_owner);
5647 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
5648 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5649 ASSERT_TRUE(lock_owner);
5651 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image1, 0, sizeof(buf), buf));
5652 ASSERT_EQ(-EROFS, rbd_write(image2, 0, sizeof(buf), buf));
5654 ASSERT_EQ(0, rbd_lock_release(image1));
5655 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5656 ASSERT_FALSE(lock_owner);
5660 const auto pingpong = [&,this](int m_id, rbd_image_t &m_image) {
5661 for (int i = 0; i < 10; i++) {
5663 lock_guard<mutex> locker(lock);
5664 if (owner_id == m_id) {
5665 std::cout << m_id << ": releasing exclusive lock" << std::endl;
5666 EXPECT_EQ(0, rbd_lock_release(m_image));
5668 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
5669 EXPECT_FALSE(lock_owner);
5671 std::cout << m_id << ": exclusive lock released" << std::endl;
5676 std::cout << m_id << ": acquiring exclusive lock" << std::endl;
5679 r = rbd_lock_acquire(m_image, RBD_LOCK_MODE_EXCLUSIVE);
5683 } while (r == -EROFS);
5687 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
5688 EXPECT_TRUE(lock_owner);
5689 std::cout << m_id << ": exclusive lock acquired" << std::endl;
5691 lock_guard<mutex> locker(lock);
5694 usleep(rand() % 50000);
5697 lock_guard<mutex> locker(lock);
5698 if (owner_id == m_id) {
5699 EXPECT_EQ(0, rbd_lock_release(m_image));
5701 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
5702 EXPECT_FALSE(lock_owner);
5706 thread ping(bind(pingpong, 1, ref(image1)));
5707 thread pong(bind(pingpong, 2, ref(image2)));
5712 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
5713 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5714 ASSERT_TRUE(lock_owner);
5716 ASSERT_EQ(0, rbd_close(image2));
5718 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
5719 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5720 ASSERT_TRUE(lock_owner);
5722 ASSERT_EQ(0, rbd_close(image1));
5723 rados_ioctx_destroy(ioctx);
5726 TEST_F(TestLibRBD, BreakLock)
5728 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5730 static char buf[10];
5732 rados_t blacklist_cluster;
5733 ASSERT_EQ("", connect_cluster(&blacklist_cluster));
5735 rados_ioctx_t ioctx, blacklist_ioctx;
5736 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
5737 ASSERT_EQ(0, rados_ioctx_create(blacklist_cluster, m_pool_name.c_str(),
5740 std::string name = get_temp_image_name();
5741 uint64_t size = 2 << 20;
5743 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5745 rbd_image_t image, blacklist_image;
5746 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5747 ASSERT_EQ(0, rbd_open(blacklist_ioctx, name.c_str(), &blacklist_image, NULL));
5749 ASSERT_EQ(0, rbd_metadata_set(image, "rbd_blacklist_on_break_lock", "true"));
5750 ASSERT_EQ(0, rbd_lock_acquire(blacklist_image, RBD_LOCK_MODE_EXCLUSIVE));
5752 rbd_lock_mode_t lock_mode;
5753 char *lock_owners[1];
5754 size_t max_lock_owners = 1;
5755 ASSERT_EQ(0, rbd_lock_get_owners(image, &lock_mode, lock_owners,
5757 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
5758 ASSERT_STRNE("", lock_owners[0]);
5759 ASSERT_EQ(1U, max_lock_owners);
5761 ASSERT_EQ(0, rbd_lock_break(image, RBD_LOCK_MODE_EXCLUSIVE, lock_owners[0]));
5762 ASSERT_EQ(0, rbd_lock_acquire(image, RBD_LOCK_MODE_EXCLUSIVE));
5763 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blacklist_cluster));
5765 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image, 0, sizeof(buf), buf));
5766 ASSERT_EQ(-EBLACKLISTED, rbd_write(blacklist_image, 0, sizeof(buf), buf));
5768 ASSERT_EQ(0, rbd_close(image));
5769 ASSERT_EQ(0, rbd_close(blacklist_image));
5771 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
5773 rados_ioctx_destroy(ioctx);
5774 rados_ioctx_destroy(blacklist_ioctx);
5775 rados_shutdown(blacklist_cluster);
5778 TEST_F(TestLibRBD, DiscardAfterWrite)
5780 REQUIRE(!is_skip_partial_discard_enabled());
5782 librados::IoCtx ioctx;
5783 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5786 std::string name = get_temp_image_name();
5787 uint64_t size = 1 << 20;
5789 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5791 librbd::Image image;
5792 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5794 // enable writeback cache
5795 ASSERT_EQ(0, image.flush());
5798 bl.append(std::string(256, '1'));
5800 librbd::RBD::AioCompletion *write_comp =
5801 new librbd::RBD::AioCompletion(NULL, NULL);
5802 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
5803 ASSERT_EQ(0, write_comp->wait_for_complete());
5804 write_comp->release();
5806 librbd::RBD::AioCompletion *discard_comp =
5807 new librbd::RBD::AioCompletion(NULL, NULL);
5808 ASSERT_EQ(0, image.aio_discard(0, 256, discard_comp));
5809 ASSERT_EQ(0, discard_comp->wait_for_complete());
5810 discard_comp->release();
5812 librbd::RBD::AioCompletion *read_comp =
5813 new librbd::RBD::AioCompletion(NULL, NULL);
5815 image.aio_read(0, bl.length(), read_bl, read_comp);
5816 ASSERT_EQ(0, read_comp->wait_for_complete());
5817 ASSERT_EQ(bl.length(), read_comp->get_return_value());
5818 ASSERT_TRUE(read_bl.is_zero());
5819 read_comp->release();
5822 TEST_F(TestLibRBD, DefaultFeatures) {
5823 std::string orig_default_features;
5824 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", orig_default_features));
5825 BOOST_SCOPE_EXIT_ALL(orig_default_features) {
5826 ASSERT_EQ(0, _rados.conf_set("rbd_default_features",
5827 orig_default_features.c_str()));
5830 std::list<std::pair<std::string, std::string> > feature_names_to_bitmask = {
5831 {"", orig_default_features},
5833 {"layering, exclusive-lock", "5"},
5834 {"exclusive-lock,journaling", "68"},
5838 for (auto &pair : feature_names_to_bitmask) {
5839 ASSERT_EQ(0, _rados.conf_set("rbd_default_features", pair.first.c_str()));
5840 std::string features;
5841 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", features));
5842 ASSERT_EQ(pair.second, features);
5846 TEST_F(TestLibRBD, TestTrashMoveAndPurge) {
5847 librados::IoCtx ioctx;
5848 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5851 std::string name = get_temp_image_name();
5853 uint64_t size = 1 << 18;
5855 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5857 librbd::Image image;
5858 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
5860 ASSERT_EQ(0, image.old_format(&old_format));
5863 ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
5867 std::string image_id;
5868 ASSERT_EQ(0, image.get_id(&image_id));
5871 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 0));
5873 std::vector<std::string> images;
5874 ASSERT_EQ(0, rbd.list(ioctx, images));
5875 for (const auto& image : images) {
5876 ASSERT_TRUE(image != name);
5879 librbd::trash_image_info_t info;
5880 ASSERT_EQ(-ENOENT, rbd.trash_get(ioctx, "dummy image id", &info));
5881 ASSERT_EQ(0, rbd.trash_get(ioctx, image_id.c_str(), &info));
5882 ASSERT_EQ(image_id, info.id);
5884 std::vector<librbd::trash_image_info_t> entries;
5885 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
5886 ASSERT_FALSE(entries.empty());
5887 ASSERT_EQ(entries.begin()->id, image_id);
5891 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
5893 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
5894 ASSERT_TRUE(entries.empty());
5897 TEST_F(TestLibRBD, TestTrashMoveAndPurgeNonExpiredDelay) {
5898 librados::IoCtx ioctx;
5899 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5902 std::string name = get_temp_image_name();
5904 uint64_t size = 1 << 18;
5906 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5908 librbd::Image image;
5909 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
5911 ASSERT_EQ(0, image.old_format(&old_format));
5914 ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
5918 std::string image_id;
5919 ASSERT_EQ(0, image.get_id(&image_id));
5922 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 100));
5925 ASSERT_EQ(-EPERM, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
5929 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
5933 TEST_F(TestLibRBD, TestTrashMoveAndRestore) {
5934 librados::IoCtx ioctx;
5935 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5938 std::string name = get_temp_image_name();
5940 uint64_t size = 1 << 18;
5942 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5944 librbd::Image image;
5945 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
5947 ASSERT_EQ(0, image.old_format(&old_format));
5950 ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
5954 std::string image_id;
5955 ASSERT_EQ(0, image.get_id(&image_id));
5958 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 10));
5960 std::vector<std::string> images;
5961 ASSERT_EQ(0, rbd.list(ioctx, images));
5962 for (const auto& image : images) {
5963 ASSERT_TRUE(image != name);
5966 std::vector<librbd::trash_image_info_t> entries;
5967 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
5968 ASSERT_FALSE(entries.empty());
5969 ASSERT_EQ(entries.begin()->id, image_id);
5972 ASSERT_EQ(0, rbd.trash_restore(ioctx, image_id.c_str(), ""));
5973 ASSERT_EQ(0, rbd.list(ioctx, images));
5974 ASSERT_FALSE(images.empty());
5976 for (const auto& image : images) {
5977 if (image == name) {
5985 // poorman's assert()
5987 void __ceph_assert_fail(const char *assertion, const char *file, int line,