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"
22 #include "common/ceph_mutex.h"
23 #include "json_spirit/json_spirit.h"
24 #include "test/librados/crimson_utils.h"
26 #include "gtest/gtest.h"
32 #include <sys/types.h>
38 #include <condition_variable>
47 #include "test/librados/test.h"
48 #include "test/librados/test_cxx.h"
49 #include "test/librbd/test_support.h"
50 #include "common/event_socket.h"
51 #include "include/interval_set.h"
52 #include "include/stringify.h"
54 #include <boost/assign/list_of.hpp>
55 #include <boost/scope_exit.hpp>
58 #include <sys/eventfd.h>
61 #pragma GCC diagnostic ignored "-Wpragmas"
62 #pragma GCC diagnostic push
63 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
67 using std::chrono::seconds
;
69 #define ASSERT_PASSED0(x) \
71 bool passed = false; \
73 ASSERT_TRUE(passed); \
76 #define ASSERT_PASSED(x, args...) \
78 bool passed = false; \
80 ASSERT_TRUE(passed); \
83 void register_test_librbd() {
86 static int get_features(bool *old_format
, uint64_t *features
)
88 const char *c
= getenv("RBD_FEATURES");
89 if (c
&& strlen(c
) > 0) {
96 cout
<< "using new format!" << std::endl
;
100 cout
<< "using old format" << std::endl
;
106 static int create_image_full(rados_ioctx_t ioctx
, const char *name
,
107 uint64_t size
, int *order
, int old_format
,
111 // ensure old-format tests actually use the old format
112 int r
= rados_conf_set(rados_ioctx_get_cluster(ioctx
),
113 "rbd_default_format", "1");
117 return rbd_create(ioctx
, name
, size
, order
);
118 } else if ((features
& RBD_FEATURE_STRIPINGV2
) != 0) {
119 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
121 // use a conservative stripe_unit for non default order
122 stripe_unit
= (1ull << (*order
-1));
125 printf("creating image with stripe unit: %" PRIu64
", "
126 "stripe count: %" PRIu64
"\n",
127 stripe_unit
, IMAGE_STRIPE_COUNT
);
128 return rbd_create3(ioctx
, name
, size
, features
, order
,
129 stripe_unit
, IMAGE_STRIPE_COUNT
);
131 return rbd_create2(ioctx
, name
, size
, features
, order
);
135 static int clone_image(rados_ioctx_t p_ioctx
,
136 rbd_image_t p_image
, const char *p_name
,
137 const char *p_snap_name
, rados_ioctx_t c_ioctx
,
138 const char *c_name
, uint64_t features
, int *c_order
)
140 uint64_t stripe_unit
, stripe_count
;
143 r
= rbd_get_stripe_unit(p_image
, &stripe_unit
);
148 r
= rbd_get_stripe_count(p_image
, &stripe_count
);
153 return rbd_clone2(p_ioctx
, p_name
, p_snap_name
, c_ioctx
,
154 c_name
, features
, c_order
, stripe_unit
, stripe_count
);
158 static int create_image(rados_ioctx_t ioctx
, const char *name
,
159 uint64_t size
, int *order
)
164 int r
= get_features(&old_format
, &features
);
167 return create_image_full(ioctx
, name
, size
, order
, old_format
, features
);
170 static int create_image_pp(librbd::RBD
&rbd
,
171 librados::IoCtx
&ioctx
,
173 uint64_t size
, int *order
) {
176 int r
= get_features(&old_format
, &features
);
180 librados::Rados
rados(ioctx
);
181 int r
= rados
.conf_set("rbd_default_format", "1");
185 return rbd
.create(ioctx
, name
, size
, order
);
187 return rbd
.create2(ioctx
, name
, size
, features
, order
);
193 void simple_write_cb(rbd_completion_t cb
, void *arg
)
195 printf("write completion cb called!\n");
198 void simple_read_cb(rbd_completion_t cb
, void *arg
)
200 printf("read completion cb called!\n");
203 void aio_write_test_data_and_poll(rbd_image_t image
, int fd
, const char *test_data
,
204 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
206 rbd_completion_t comp
;
207 uint64_t data
= 0x123;
208 rbd_aio_create_completion((void*)&data
, (rbd_callback_t
) simple_write_cb
, &comp
);
209 printf("created completion\n");
210 printf("started write\n");
212 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
214 rbd_aio_write(image
, off
, len
, test_data
, comp
);
220 ASSERT_EQ(1, poll(&pfd
, 1, -1));
221 ASSERT_TRUE(pfd
.revents
& POLLIN
);
223 rbd_completion_t comps
[1];
224 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
226 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
227 read(fd
, &count
, sizeof(count
)));
228 int r
= rbd_aio_get_return_value(comps
[0]);
229 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
230 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps
[0]) == data
);
231 printf("return value is: %d\n", r
);
233 printf("finished write\n");
234 rbd_aio_release(comps
[0]);
238 void aio_write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
240 rbd_completion_t comp
;
241 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
242 printf("created completion\n");
244 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
246 rbd_aio_write(image
, off
, len
, test_data
, comp
);
247 printf("started write\n");
248 rbd_aio_wait_for_complete(comp
);
249 int r
= rbd_aio_get_return_value(comp
);
250 printf("return value is: %d\n", r
);
252 printf("finished write\n");
253 rbd_aio_release(comp
);
257 void write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
261 written
= rbd_write2(image
, off
, len
, test_data
, iohint
);
263 written
= rbd_write(image
, off
, len
, test_data
);
264 printf("wrote: %d\n", (int) written
);
265 ASSERT_EQ(len
, static_cast<size_t>(written
));
269 void aio_discard_test_data(rbd_image_t image
, uint64_t off
, uint64_t len
, bool *passed
)
271 rbd_completion_t comp
;
272 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
273 rbd_aio_discard(image
, off
, len
, comp
);
274 rbd_aio_wait_for_complete(comp
);
275 int r
= rbd_aio_get_return_value(comp
);
277 printf("aio discard: %d~%d = %d\n", (int)off
, (int)len
, (int)r
);
278 rbd_aio_release(comp
);
282 void discard_test_data(rbd_image_t image
, uint64_t off
, size_t len
, bool *passed
)
285 written
= rbd_discard(image
, off
, len
);
286 printf("discard: %d~%d = %d\n", (int)off
, (int)len
, (int)written
);
287 ASSERT_EQ(len
, static_cast<size_t>(written
));
291 void aio_read_test_data_and_poll(rbd_image_t image
, int fd
, const char *expected
,
292 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
294 rbd_completion_t comp
;
295 char *result
= (char *)malloc(len
+ 1);
297 ASSERT_NE(static_cast<char *>(NULL
), result
);
298 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
299 printf("created completion\n");
300 printf("started read\n");
302 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
304 rbd_aio_read(image
, off
, len
, result
, comp
);
310 ASSERT_EQ(1, poll(&pfd
, 1, -1));
311 ASSERT_TRUE(pfd
.revents
& POLLIN
);
313 rbd_completion_t comps
[1];
314 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
316 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
317 read(fd
, &count
, sizeof(count
)));
319 int r
= rbd_aio_get_return_value(comps
[0]);
320 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
321 printf("return value is: %d\n", r
);
322 ASSERT_EQ(len
, static_cast<size_t>(r
));
323 rbd_aio_release(comps
[0]);
324 if (memcmp(result
, expected
, len
)) {
325 printf("read: %s\nexpected: %s\n", result
, expected
);
326 ASSERT_EQ(0, memcmp(result
, expected
, len
));
332 void aio_read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
334 rbd_completion_t comp
;
335 char *result
= (char *)malloc(len
+ 1);
337 ASSERT_NE(static_cast<char *>(NULL
), result
);
338 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
339 printf("created completion\n");
341 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
343 rbd_aio_read(image
, off
, len
, result
, comp
);
344 printf("started read\n");
345 rbd_aio_wait_for_complete(comp
);
346 int r
= rbd_aio_get_return_value(comp
);
347 printf("return value is: %d\n", r
);
348 ASSERT_EQ(len
, static_cast<size_t>(r
));
349 rbd_aio_release(comp
);
350 if (memcmp(result
, expected
, len
)) {
351 printf("read: %s\nexpected: %s\n", result
, expected
);
352 ASSERT_EQ(0, memcmp(result
, expected
, len
));
358 void read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
361 char *result
= (char *)malloc(len
+ 1);
363 ASSERT_NE(static_cast<char *>(NULL
), result
);
365 read
= rbd_read2(image
, off
, len
, result
, iohint
);
367 read
= rbd_read(image
, off
, len
, result
);
368 printf("read: %d\n", (int) read
);
369 ASSERT_EQ(len
, static_cast<size_t>(read
));
371 if (memcmp(result
, expected
, len
)) {
372 printf("read: %s\nexpected: %s\n", result
, expected
);
373 ASSERT_EQ(0, memcmp(result
, expected
, len
));
379 void aio_writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
380 uint64_t data_len
, uint32_t iohint
, bool *passed
)
382 rbd_completion_t comp
;
383 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
384 printf("created completion\n");
386 r
= rbd_aio_writesame(image
, off
, len
, test_data
, data_len
, comp
, iohint
);
387 printf("started writesame\n");
388 if (len
% data_len
) {
389 ASSERT_EQ(-EINVAL
, r
);
390 printf("expected fail, finished writesame\n");
391 rbd_aio_release(comp
);
396 rbd_aio_wait_for_complete(comp
);
397 r
= rbd_aio_get_return_value(comp
);
398 printf("return value is: %d\n", r
);
400 printf("finished writesame\n");
401 rbd_aio_release(comp
);
404 printf("to verify the data\n");
406 char *result
= (char *)malloc(data_len
+ 1);
407 ASSERT_NE(static_cast<char *>(NULL
), result
);
410 read
= rbd_read(image
, off
, data_len
, result
);
411 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
412 result
[data_len
] = '\0';
413 if (memcmp(result
, test_data
, data_len
)) {
414 printf("read: %d ~ %d\n", (int) off
, (int) read
);
415 printf("read: %s\nexpected: %s\n", result
, test_data
);
416 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
423 printf("verified\n");
428 void writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
429 uint64_t data_len
, uint32_t iohint
, bool *passed
)
432 written
= rbd_writesame(image
, off
, len
, test_data
, data_len
, iohint
);
433 if (len
% data_len
) {
434 ASSERT_EQ(-EINVAL
, written
);
435 printf("expected fail, finished writesame\n");
439 ASSERT_EQ(len
, static_cast<size_t>(written
));
440 printf("wrote: %d\n", (int) written
);
443 printf("to verify the data\n");
445 char *result
= (char *)malloc(data_len
+ 1);
446 ASSERT_NE(static_cast<char *>(NULL
), result
);
449 read
= rbd_read(image
, off
, data_len
, result
);
450 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
451 result
[data_len
] = '\0';
452 if (memcmp(result
, test_data
, data_len
)) {
453 printf("read: %d ~ %d\n", (int) off
, (int) read
);
454 printf("read: %s\nexpected: %s\n", result
, test_data
);
455 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
462 printf("verified\n");
467 void aio_compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
468 const char *test_data
, uint64_t off
,
469 size_t len
, uint32_t iohint
, bool *passed
)
471 rbd_completion_t comp
;
472 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
473 printf("created completion\n");
475 uint64_t mismatch_offset
;
476 rbd_aio_compare_and_write(image
, off
, len
, cmp_data
, test_data
, comp
, &mismatch_offset
, iohint
);
477 printf("started aio compare and write\n");
478 rbd_aio_wait_for_complete(comp
);
479 int r
= rbd_aio_get_return_value(comp
);
480 printf("return value is: %d\n", r
);
482 printf("finished aio compare and write\n");
483 rbd_aio_release(comp
);
487 void compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
488 const char *test_data
, uint64_t off
, size_t len
,
489 uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
491 printf("start compare and write\n");
493 written
= rbd_compare_and_write(image
, off
, len
, cmp_data
, test_data
, mismatch_off
, iohint
);
494 printf("compare and wrote: %d\n", (int) written
);
495 ASSERT_EQ(len
, static_cast<size_t>(written
));
499 class TestLibRBD
: public ::testing::Test
{
502 TestLibRBD() : m_pool_number() {
505 static void SetUpTestCase() {
507 _unique_pool_names
.clear();
509 ASSERT_EQ("", connect_cluster(&_cluster
));
510 ASSERT_EQ("", connect_cluster_pp(_rados
));
512 create_optional_data_pool();
515 static void TearDownTestCase() {
516 rados_shutdown(_cluster
);
517 _rados
.wait_for_latest_osdmap();
518 _pool_names
.insert(_pool_names
.end(), _unique_pool_names
.begin(),
519 _unique_pool_names
.end());
520 for (size_t i
= 1; i
< _pool_names
.size(); ++i
) {
521 ASSERT_EQ(0, _rados
.pool_delete(_pool_names
[i
].c_str()));
523 if (!_pool_names
.empty()) {
524 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names
[0], _rados
));
528 void SetUp() override
{
529 ASSERT_NE("", m_pool_name
= create_pool());
532 bool is_skip_partial_discard_enabled() {
534 EXPECT_EQ(0, _rados
.conf_get("rbd_skip_partial_discard", value
));
535 return value
== "true";
538 bool is_skip_partial_discard_enabled(rbd_image_t image
) {
539 if (is_skip_partial_discard_enabled()) {
542 EXPECT_EQ(0, rbd_get_features(image
, &features
));
543 return !(features
& RBD_FEATURE_DIRTY_CACHE
);
548 bool is_skip_partial_discard_enabled(librbd::Image
& image
) {
549 if (is_skip_partial_discard_enabled()) {
552 EXPECT_EQ(0, image
.features(&features
));
553 return !(features
& RBD_FEATURE_DIRTY_CACHE
);
558 void validate_object_map(rbd_image_t image
, bool *passed
) {
560 ASSERT_EQ(0, rbd_get_flags(image
, &flags
));
561 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
564 void validate_object_map(librbd::Image
&image
, bool *passed
) {
566 ASSERT_EQ(0, image
.get_flags(&flags
));
567 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
570 static std::string
get_temp_image_name() {
572 return "image" + stringify(_image_number
);
575 static void create_optional_data_pool() {
576 bool created
= false;
577 std::string data_pool
;
578 ASSERT_EQ(0, create_image_data_pool(_rados
, data_pool
, &created
));
579 if (!data_pool
.empty()) {
580 printf("using image data pool: %s\n", data_pool
.c_str());
582 _unique_pool_names
.push_back(data_pool
);
587 std::string
create_pool(bool unique
= false) {
588 librados::Rados rados
;
589 std::string pool_name
;
591 pool_name
= get_temp_pool_name("test-librbd-");
592 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
593 _unique_pool_names
.push_back(pool_name
);
594 } else if (m_pool_number
< _pool_names
.size()) {
595 pool_name
= _pool_names
[m_pool_number
];
597 pool_name
= get_temp_pool_name("test-librbd-");
598 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
599 _pool_names
.push_back(pool_name
);
605 void test_io(rbd_image_t image
) {
606 bool skip_discard
= is_skip_partial_discard_enabled(image
);
608 char test_data
[TEST_IO_SIZE
+ 1];
609 char zero_data
[TEST_IO_SIZE
+ 1];
610 char mismatch_data
[TEST_IO_SIZE
+ 1];
612 uint64_t mismatch_offset
;
614 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
615 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
617 test_data
[TEST_IO_SIZE
] = '\0';
618 memset(zero_data
, 0, sizeof(zero_data
));
619 memset(mismatch_data
, 9, sizeof(mismatch_data
));
621 for (i
= 0; i
< 5; ++i
)
622 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
625 for (i
= 5; i
< 10; ++i
)
626 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
629 for (i
= 0; i
< 5; ++i
)
630 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
631 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, 0);
633 for (i
= 5; i
< 10; ++i
)
634 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
635 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
637 for (i
= 0; i
< 5; ++i
)
638 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
641 for (i
= 5; i
< 10; ++i
)
642 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
645 // discard 2nd, 4th sections.
646 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
647 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
649 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
650 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
651 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
652 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2,
654 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
655 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
656 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4,
659 for (i
= 0; i
< 15; ++i
) {
661 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
662 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
663 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
664 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
665 } else if (i
% 3 == 1) {
666 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
667 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
668 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
669 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
671 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
672 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
673 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
674 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
677 for (i
= 0; i
< 15; ++i
) {
679 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
680 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
,
682 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
683 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
,
685 } else if (i
% 3 == 1) {
686 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
687 TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
688 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
689 TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
691 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
692 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
693 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
694 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
698 rbd_image_info_t info
;
699 rbd_completion_t comp
;
700 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
701 // can't read or write starting past end
702 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
703 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
704 // reading through end returns amount up to end
705 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
706 // writing through end returns amount up to end
707 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
709 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
710 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
711 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
712 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
713 rbd_aio_release(comp
);
715 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
716 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
717 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
718 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
719 rbd_aio_release(comp
);
721 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
,
722 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
723 mismatch_offset
= 123;
724 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
,
725 mismatch_data
, mismatch_data
, &mismatch_offset
, 0));
726 ASSERT_EQ(0U, mismatch_offset
);
727 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
728 mismatch_offset
= 123;
729 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
,
730 mismatch_data
, comp
, &mismatch_offset
, 0));
731 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
732 ASSERT_EQ(-EILSEQ
, rbd_aio_get_return_value(comp
));
733 ASSERT_EQ(0U, mismatch_offset
);
734 rbd_aio_release(comp
);
736 ASSERT_PASSED(validate_object_map
, image
);
739 static std::vector
<std::string
> _pool_names
;
740 static std::vector
<std::string
> _unique_pool_names
;
741 static rados_t _cluster
;
742 static librados::Rados _rados
;
743 static uint64_t _image_number
;
745 std::string m_pool_name
;
746 uint32_t m_pool_number
;
750 std::vector
<std::string
> TestLibRBD::_pool_names
;
751 std::vector
<std::string
> TestLibRBD::_unique_pool_names
;
752 rados_t
TestLibRBD::_cluster
;
753 librados::Rados
TestLibRBD::_rados
;
754 uint64_t TestLibRBD::_image_number
= 0;
756 TEST_F(TestLibRBD
, CreateAndStat
)
759 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
761 rbd_image_info_t info
;
764 std::string name
= get_temp_image_name();
765 uint64_t size
= 2 << 20;
767 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
768 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
769 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
770 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
771 ASSERT_EQ(info
.size
, size
);
772 ASSERT_EQ(info
.order
, order
);
773 ASSERT_EQ(0, rbd_close(image
));
775 rados_ioctx_destroy(ioctx
);
778 TEST_F(TestLibRBD
, CreateWithSameDataPool
)
783 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
786 std::string name
= get_temp_image_name();
787 uint64_t size
= 2 << 20;
791 ASSERT_EQ(0, get_features(&old_format
, &features
));
792 ASSERT_FALSE(old_format
);
794 rbd_image_options_t image_options
;
795 rbd_image_options_create(&image_options
);
796 BOOST_SCOPE_EXIT( (&image_options
) ) {
797 rbd_image_options_destroy(image_options
);
798 } BOOST_SCOPE_EXIT_END
;
800 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
801 RBD_IMAGE_OPTION_FEATURES
,
803 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
804 RBD_IMAGE_OPTION_DATA_POOL
,
805 m_pool_name
.c_str()));
807 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
808 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
810 ASSERT_EQ(0, rbd_close(image
));
812 rados_ioctx_destroy(ioctx
);
815 TEST_F(TestLibRBD
, CreateAndStatPP
)
817 librados::IoCtx ioctx
;
818 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
822 librbd::image_info_t info
;
825 std::string name
= get_temp_image_name();
826 uint64_t size
= 2 << 20;
828 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
829 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
830 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
831 ASSERT_EQ(info
.size
, size
);
832 ASSERT_EQ(info
.order
, order
);
838 TEST_F(TestLibRBD
, GetId
)
841 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
845 std::string name
= get_temp_image_name();
847 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
848 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
851 if (!is_feature_enabled(0)) {
853 ASSERT_EQ(-EINVAL
, rbd_get_id(image
, id
, sizeof(id
)));
855 ASSERT_EQ(-ERANGE
, rbd_get_id(image
, id
, 0));
856 ASSERT_EQ(0, rbd_get_id(image
, id
, sizeof(id
)));
857 ASSERT_LT(0U, strlen(id
));
859 ASSERT_EQ(0, rbd_close(image
));
860 ASSERT_EQ(0, rbd_open_by_id(ioctx
, id
, &image
, NULL
));
862 ASSERT_EQ(-ERANGE
, rbd_get_name(image
, NULL
, &name_len
));
863 ASSERT_EQ(name_len
, name
.size() + 1);
864 char image_name
[name_len
];
865 ASSERT_EQ(0, rbd_get_name(image
, image_name
, &name_len
));
866 ASSERT_STREQ(name
.c_str(), image_name
);
869 ASSERT_EQ(0, rbd_close(image
));
870 rados_ioctx_destroy(ioctx
);
873 TEST_F(TestLibRBD
, GetIdPP
)
875 librados::IoCtx ioctx
;
876 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
881 std::string name
= get_temp_image_name();
884 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
885 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
886 if (!is_feature_enabled(0)) {
888 ASSERT_EQ(-EINVAL
, image
.get_id(&id
));
890 ASSERT_EQ(0, image
.get_id(&id
));
891 ASSERT_LT(0U, id
.size());
893 ASSERT_EQ(0, image
.close());
894 ASSERT_EQ(0, rbd
.open_by_id(ioctx
, image
, id
.c_str(), NULL
));
895 std::string image_name
;
896 ASSERT_EQ(0, image
.get_name(&image_name
));
897 ASSERT_EQ(name
, image_name
);
901 TEST_F(TestLibRBD
, GetBlockNamePrefix
)
904 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
908 std::string name
= get_temp_image_name();
910 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
911 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
914 ASSERT_EQ(-ERANGE
, rbd_get_block_name_prefix(image
, prefix
, 0));
915 ASSERT_EQ(0, rbd_get_block_name_prefix(image
, prefix
, sizeof(prefix
)));
916 ASSERT_LT(0U, strlen(prefix
));
918 ASSERT_EQ(0, rbd_close(image
));
919 rados_ioctx_destroy(ioctx
);
922 TEST_F(TestLibRBD
, GetBlockNamePrefixPP
)
924 librados::IoCtx ioctx
;
925 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
930 std::string name
= get_temp_image_name();
932 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
933 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
934 ASSERT_LT(0U, image
.get_block_name_prefix().size());
937 TEST_F(TestLibRBD
, TestGetCreateTimestamp
)
942 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
946 std::string name
= get_temp_image_name();
948 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
949 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
951 struct timespec timestamp
;
952 ASSERT_EQ(0, rbd_get_create_timestamp(image
, ×tamp
));
953 ASSERT_LT(0, timestamp
.tv_sec
);
955 ASSERT_EQ(0, rbd_close(image
));
957 rados_ioctx_destroy(ioctx
);
960 TEST_F(TestLibRBD
, GetCreateTimestampPP
)
964 librados::IoCtx ioctx
;
965 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
970 std::string name
= get_temp_image_name();
972 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
973 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
975 struct timespec timestamp
;
976 ASSERT_EQ(0, image
.get_create_timestamp(×tamp
));
977 ASSERT_LT(0, timestamp
.tv_sec
);
980 TEST_F(TestLibRBD
, OpenAio
)
983 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
985 rbd_image_info_t info
;
988 std::string name
= get_temp_image_name();
989 uint64_t size
= 2 << 20;
991 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
993 rbd_completion_t open_comp
;
994 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
995 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
996 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
997 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
998 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp
));
999 rbd_aio_release(open_comp
);
1001 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1002 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
1003 ASSERT_EQ(info
.size
, size
);
1004 ASSERT_EQ(info
.order
, order
);
1006 rbd_completion_t close_comp
;
1007 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &close_comp
));
1008 ASSERT_EQ(0, rbd_aio_close(image
, close_comp
));
1009 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp
));
1010 ASSERT_EQ(1, rbd_aio_is_complete(close_comp
));
1011 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp
));
1012 rbd_aio_release(close_comp
);
1014 rados_ioctx_destroy(ioctx
);
1017 TEST_F(TestLibRBD
, OpenAioFail
)
1019 rados_ioctx_t ioctx
;
1020 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
1022 std::string name
= get_temp_image_name();
1024 rbd_completion_t open_comp
;
1025 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
1026 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
1027 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
1028 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
1029 ASSERT_EQ(-ENOENT
, rbd_aio_get_return_value(open_comp
));
1030 rbd_aio_release(open_comp
);
1032 rados_ioctx_destroy(ioctx
);
1035 TEST_F(TestLibRBD
, OpenAioPP
)
1037 librados::IoCtx ioctx
;
1038 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1041 librbd::image_info_t info
;
1042 librbd::Image image
;
1044 std::string name
= get_temp_image_name();
1045 uint64_t size
= 2 << 20;
1047 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1049 librbd::RBD::AioCompletion
*open_comp
=
1050 new librbd::RBD::AioCompletion(NULL
, NULL
);
1051 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1052 ASSERT_EQ(0, open_comp
->wait_for_complete());
1053 ASSERT_EQ(1, open_comp
->is_complete());
1054 ASSERT_EQ(0, open_comp
->get_return_value());
1055 open_comp
->release();
1057 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1058 ASSERT_EQ(info
.size
, size
);
1059 ASSERT_EQ(info
.order
, order
);
1062 open_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
1063 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1064 ASSERT_EQ(0, open_comp
->wait_for_complete());
1065 ASSERT_EQ(1, open_comp
->is_complete());
1066 ASSERT_EQ(0, open_comp
->get_return_value());
1067 open_comp
->release();
1070 librbd::RBD::AioCompletion
*close_comp
=
1071 new librbd::RBD::AioCompletion(NULL
, NULL
);
1072 ASSERT_EQ(0, image
.aio_close(close_comp
));
1073 ASSERT_EQ(0, close_comp
->wait_for_complete());
1074 ASSERT_EQ(1, close_comp
->is_complete());
1075 ASSERT_EQ(0, close_comp
->get_return_value());
1076 close_comp
->release();
1078 // close closed image
1079 close_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
1080 ASSERT_EQ(-EINVAL
, image
.aio_close(close_comp
));
1081 close_comp
->release();
1086 TEST_F(TestLibRBD
, OpenAioFailPP
)
1088 librados::IoCtx ioctx
;
1089 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1093 librbd::Image image
;
1094 std::string name
= get_temp_image_name();
1096 librbd::RBD::AioCompletion
*open_comp
=
1097 new librbd::RBD::AioCompletion(NULL
, NULL
);
1098 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1099 ASSERT_EQ(0, open_comp
->wait_for_complete());
1100 ASSERT_EQ(1, open_comp
->is_complete());
1101 ASSERT_EQ(-ENOENT
, open_comp
->get_return_value());
1102 open_comp
->release();
1108 TEST_F(TestLibRBD
, ResizeAndStat
)
1110 rados_ioctx_t ioctx
;
1111 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1113 rbd_image_info_t info
;
1116 std::string name
= get_temp_image_name();
1117 uint64_t size
= 2 << 20;
1119 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1120 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1122 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
1123 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1124 ASSERT_EQ(info
.size
, size
* 4);
1126 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
1127 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1128 ASSERT_EQ(info
.size
, size
/ 2);
1130 // downsizing without allowing shrink should fail
1131 // and image size should not change
1132 ASSERT_EQ(-EINVAL
, rbd_resize2(image
, size
/ 4, false, NULL
, NULL
));
1133 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1134 ASSERT_EQ(info
.size
, size
/ 2);
1136 ASSERT_EQ(0, rbd_resize2(image
, size
/ 4, true, NULL
, NULL
));
1137 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1138 ASSERT_EQ(info
.size
, size
/ 4);
1140 ASSERT_PASSED(validate_object_map
, image
);
1141 ASSERT_EQ(0, rbd_close(image
));
1143 rados_ioctx_destroy(ioctx
);
1146 TEST_F(TestLibRBD
, ResizeAndStatPP
)
1148 librados::IoCtx ioctx
;
1149 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1153 librbd::image_info_t info
;
1154 librbd::Image image
;
1156 std::string name
= get_temp_image_name();
1157 uint64_t size
= 2 << 20;
1159 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1160 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1162 ASSERT_EQ(0, image
.resize(size
* 4));
1163 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1164 ASSERT_EQ(info
.size
, size
* 4);
1166 ASSERT_EQ(0, image
.resize(size
/ 2));
1167 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1168 ASSERT_EQ(info
.size
, size
/ 2);
1169 ASSERT_PASSED(validate_object_map
, image
);
1175 TEST_F(TestLibRBD
, UpdateWatchAndResize
)
1177 rados_ioctx_t ioctx
;
1178 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1182 std::string name
= get_temp_image_name();
1183 uint64_t size
= 2 << 20;
1185 rbd_image_t
&m_image
;
1187 std::condition_variable m_cond
;
1189 static void cb(void *arg
) {
1190 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
1191 watcher
->handle_notify();
1193 explicit Watcher(rbd_image_t
&image
) : m_image(image
) {}
1194 void handle_notify() {
1195 rbd_image_info_t info
;
1196 ASSERT_EQ(0, rbd_stat(m_image
, &info
, sizeof(info
)));
1197 std::lock_guard
<std::mutex
> locker(m_lock
);
1199 m_cond
.notify_one();
1201 void wait_for_size(size_t size
) {
1202 std::unique_lock
<std::mutex
> locker(m_lock
);
1203 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
1205 return this->m_size
== size
;}));
1210 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1211 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1213 ASSERT_EQ(0, rbd_update_watch(image
, &handle
, Watcher::cb
, &watcher
));
1215 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
1216 watcher
.wait_for_size(size
* 4);
1218 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
1219 watcher
.wait_for_size(size
/ 2);
1221 ASSERT_EQ(0, rbd_update_unwatch(image
, handle
));
1223 ASSERT_EQ(0, rbd_close(image
));
1224 rados_ioctx_destroy(ioctx
);
1227 TEST_F(TestLibRBD
, UpdateWatchAndResizePP
)
1229 librados::IoCtx ioctx
;
1230 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1234 librbd::Image image
;
1236 std::string name
= get_temp_image_name();
1237 uint64_t size
= 2 << 20;
1238 struct Watcher
: public librbd::UpdateWatchCtx
{
1239 explicit Watcher(librbd::Image
&image
) : m_image(image
) {
1241 void handle_notify() override
{
1242 librbd::image_info_t info
;
1243 ASSERT_EQ(0, m_image
.stat(info
, sizeof(info
)));
1244 std::lock_guard
<std::mutex
> locker(m_lock
);
1246 m_cond
.notify_one();
1248 void wait_for_size(size_t size
) {
1249 std::unique_lock
<std::mutex
> locker(m_lock
);
1250 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
1252 return this->m_size
== size
;}));
1254 librbd::Image
&m_image
;
1256 std::condition_variable m_cond
;
1261 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1262 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1264 ASSERT_EQ(0, image
.update_watch(&watcher
, &handle
));
1266 ASSERT_EQ(0, image
.resize(size
* 4));
1267 watcher
.wait_for_size(size
* 4);
1269 ASSERT_EQ(0, image
.resize(size
/ 2));
1270 watcher
.wait_for_size(size
/ 2);
1272 ASSERT_EQ(0, image
.update_unwatch(handle
));
1278 int test_ls(rados_ioctx_t io_ctx
, size_t num_expected
, ...)
1281 char *names
, *cur_name
;
1283 size_t max_size
= 1024;
1285 names
= (char *) malloc(sizeof(char) * 1024);
1286 int len
= rbd_list(io_ctx
, names
, &max_size
);
1288 std::set
<std::string
> image_names
;
1289 for (i
= 0, num_images
= 0, cur_name
= names
; cur_name
< names
+ len
; i
++) {
1290 printf("image: %s\n", cur_name
);
1291 image_names
.insert(cur_name
);
1292 cur_name
+= strlen(cur_name
) + 1;
1297 va_start(ap
, num_expected
);
1298 for (i
= num_expected
; i
> 0; i
--) {
1299 char *expected
= va_arg(ap
, char *);
1300 printf("expected = %s\n", expected
);
1301 std::set
<std::string
>::iterator it
= image_names
.find(expected
);
1302 if (it
!= image_names
.end()) {
1303 printf("found %s\n", expected
);
1304 image_names
.erase(it
);
1305 printf("erased %s\n", expected
);
1307 ADD_FAILURE() << "Unable to find image " << expected
;
1314 if (!image_names
.empty()) {
1315 ADD_FAILURE() << "Unexpected images discovered";
1321 TEST_F(TestLibRBD
, TestCreateLsDelete
)
1323 rados_ioctx_t ioctx
;
1324 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1327 std::string name
= get_temp_image_name();
1328 std::string name2
= get_temp_image_name();
1329 uint64_t size
= 2 << 20;
1331 ASSERT_EQ(0, test_ls(ioctx
, 0));
1332 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1333 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1334 ASSERT_EQ(0, create_image(ioctx
, name2
.c_str(), size
, &order
));
1335 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1336 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
1337 ASSERT_EQ(1, test_ls(ioctx
, 1, name2
.c_str()));
1339 ASSERT_EQ(-ENOENT
, rbd_remove(ioctx
, name
.c_str()));
1341 rados_ioctx_destroy(ioctx
);
1344 int test_ls_pp(librbd::RBD
& rbd
, librados::IoCtx
& io_ctx
, size_t num_expected
, ...)
1349 vector
<string
> names
;
1350 r
= rbd
.list(io_ctx
, names
);
1353 EXPECT_TRUE(r
>= 0);
1354 cout
<< "num images is: " << names
.size() << std::endl
1355 << "expected: " << num_expected
<< std::endl
;
1356 int num
= names
.size();
1358 for (i
= 0; i
< names
.size(); i
++) {
1359 cout
<< "image: " << names
[i
] << std::endl
;
1362 va_start(ap
, num_expected
);
1363 for (i
= num_expected
; i
> 0; i
--) {
1364 char *expected
= va_arg(ap
, char *);
1365 cout
<< "expected = " << expected
<< std::endl
;
1366 vector
<string
>::iterator listed_name
= find(names
.begin(), names
.end(), string(expected
));
1367 if (listed_name
== names
.end()) {
1368 ADD_FAILURE() << "Unable to find image " << expected
;
1372 names
.erase(listed_name
);
1376 if (!names
.empty()) {
1377 ADD_FAILURE() << "Unexpected images discovered";
1383 TEST_F(TestLibRBD
, TestCreateLsDeletePP
)
1385 librados::IoCtx ioctx
;
1386 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1390 librbd::Image image
;
1392 std::string name
= get_temp_image_name();
1393 std::string name2
= get_temp_image_name();
1394 uint64_t size
= 2 << 20;
1396 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1397 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1398 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
1399 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1400 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
1401 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name2
.c_str()));
1408 static int print_progress_percent(uint64_t offset
, uint64_t src_size
,
1411 float percent
= ((float)offset
* 100) / src_size
;
1412 printf("%3.2f%% done\n", percent
);
1416 TEST_F(TestLibRBD
, TestCopy
)
1418 rados_ioctx_t ioctx
;
1419 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1425 std::string name
= get_temp_image_name();
1426 std::string name2
= get_temp_image_name();
1427 std::string name3
= get_temp_image_name();
1429 uint64_t size
= 2 << 20;
1431 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1432 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1433 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1435 size_t sum_key_len
= 0;
1436 size_t sum_value_len
= 0;
1439 for (int i
= 1; i
<= 70; i
++) {
1440 key
= "key" + stringify(i
);
1441 val
= "value" + stringify(i
);
1442 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
1444 sum_key_len
+= (key
.size() + 1);
1445 sum_value_len
+= (val
.size() + 1);
1450 size_t keys_len
= sizeof(keys
);
1451 size_t vals_len
= sizeof(vals
);
1454 size_t value_len
= sizeof(value
);
1456 ASSERT_EQ(0, rbd_copy(image
, ioctx
, name2
.c_str()));
1457 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1458 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
1459 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 70, keys
, &keys_len
, vals
,
1461 ASSERT_EQ(keys_len
, sum_key_len
);
1462 ASSERT_EQ(vals_len
, sum_value_len
);
1464 for (int i
= 1; i
<= 70; i
++) {
1465 key
= "key" + stringify(i
);
1466 val
= "value" + stringify(i
);
1467 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
1468 ASSERT_STREQ(val
.c_str(), value
);
1470 value_len
= sizeof(value
);
1473 ASSERT_EQ(0, rbd_copy_with_progress(image
, ioctx
, name3
.c_str(),
1474 print_progress_percent
, NULL
));
1475 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1477 keys_len
= sizeof(keys
);
1478 vals_len
= sizeof(vals
);
1479 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1480 ASSERT_EQ(0, rbd_metadata_list(image3
, "key", 70, keys
, &keys_len
, vals
,
1482 ASSERT_EQ(keys_len
, sum_key_len
);
1483 ASSERT_EQ(vals_len
, sum_value_len
);
1485 for (int i
= 1; i
<= 70; i
++) {
1486 key
= "key" + stringify(i
);
1487 val
= "value" + stringify(i
);
1488 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1489 ASSERT_STREQ(val
.c_str(), value
);
1491 value_len
= sizeof(value
);
1494 ASSERT_EQ(0, rbd_close(image
));
1495 ASSERT_EQ(0, rbd_close(image2
));
1496 ASSERT_EQ(0, rbd_close(image3
));
1497 rados_ioctx_destroy(ioctx
);
1500 class PrintProgress
: public librbd::ProgressContext
1503 int update_progress(uint64_t offset
, uint64_t src_size
) override
1505 float percent
= ((float)offset
* 100) / src_size
;
1506 printf("%3.2f%% done\n", percent
);
1511 TEST_F(TestLibRBD
, TestCopyPP
)
1513 librados::IoCtx ioctx
;
1514 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1518 librbd::Image image
;
1519 librbd::Image image2
;
1520 librbd::Image image3
;
1522 std::string name
= get_temp_image_name();
1523 std::string name2
= get_temp_image_name();
1524 std::string name3
= get_temp_image_name();
1525 uint64_t size
= 2 << 20;
1528 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1529 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1533 for (int i
= 1; i
<= 70; i
++) {
1534 key
= "key" + stringify(i
);
1535 val
= "value" + stringify(i
);
1536 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1539 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1540 ASSERT_EQ(0, image
.copy(ioctx
, name2
.c_str()));
1541 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1542 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1544 map
<string
, bufferlist
> pairs
;
1546 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1547 ASSERT_EQ(70U, pairs
.size());
1549 for (int i
= 1; i
<= 70; i
++) {
1550 key
= "key" + stringify(i
);
1551 val
= "value" + stringify(i
);
1552 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1553 ASSERT_STREQ(val
.c_str(), value
.c_str());
1556 ASSERT_EQ(0, image
.copy_with_progress(ioctx
, name3
.c_str(), pp
));
1557 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1559 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1562 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1563 ASSERT_EQ(70U, pairs
.size());
1565 for (int i
= 1; i
<= 70; i
++) {
1566 key
= "key" + stringify(i
);
1567 val
= "value" + stringify(i
);
1568 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1569 ASSERT_STREQ(val
.c_str(), value
.c_str());
1576 TEST_F(TestLibRBD
, TestDeepCopy
)
1578 REQUIRE_FORMAT_V2();
1579 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1581 rados_ioctx_t ioctx
;
1582 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1583 BOOST_SCOPE_EXIT_ALL( (&ioctx
) ) {
1584 rados_ioctx_destroy(ioctx
);
1594 std::string name
= get_temp_image_name();
1595 std::string name2
= get_temp_image_name();
1596 std::string name3
= get_temp_image_name();
1597 std::string name4
= get_temp_image_name();
1598 std::string name5
= get_temp_image_name();
1599 std::string name6
= get_temp_image_name();
1601 uint64_t size
= 2 << 20;
1603 rbd_image_options_t opts
;
1604 rbd_image_options_create(&opts
);
1605 BOOST_SCOPE_EXIT_ALL( (&opts
) ) {
1606 rbd_image_options_destroy(opts
);
1609 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1610 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1611 BOOST_SCOPE_EXIT_ALL( (&image
) ) {
1612 ASSERT_EQ(0, rbd_close(image
));
1614 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1616 size_t sum_key_len
= 0;
1617 size_t sum_value_len
= 0;
1620 for (int i
= 1; i
<= 70; i
++) {
1621 key
= "key" + stringify(i
);
1622 val
= "value" + stringify(i
);
1623 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
1625 sum_key_len
+= (key
.size() + 1);
1626 sum_value_len
+= (val
.size() + 1);
1631 size_t keys_len
= sizeof(keys
);
1632 size_t vals_len
= sizeof(vals
);
1635 size_t value_len
= sizeof(value
);
1637 ASSERT_EQ(0, rbd_deep_copy(image
, ioctx
, name2
.c_str(), opts
));
1638 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1639 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
1640 BOOST_SCOPE_EXIT_ALL( (&image2
) ) {
1641 ASSERT_EQ(0, rbd_close(image2
));
1643 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 70, keys
, &keys_len
, vals
,
1645 ASSERT_EQ(keys_len
, sum_key_len
);
1646 ASSERT_EQ(vals_len
, sum_value_len
);
1648 for (int i
= 1; i
<= 70; i
++) {
1649 key
= "key" + stringify(i
);
1650 val
= "value" + stringify(i
);
1651 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
1652 ASSERT_STREQ(val
.c_str(), value
);
1654 value_len
= sizeof(value
);
1657 ASSERT_EQ(0, rbd_deep_copy_with_progress(image
, ioctx
, name3
.c_str(), opts
,
1658 print_progress_percent
, NULL
));
1659 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1661 keys_len
= sizeof(keys
);
1662 vals_len
= sizeof(vals
);
1663 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1664 BOOST_SCOPE_EXIT_ALL( (&image3
) ) {
1665 ASSERT_EQ(0, rbd_close(image3
));
1667 ASSERT_EQ(0, rbd_metadata_list(image3
, "key", 70, keys
, &keys_len
, vals
,
1669 ASSERT_EQ(keys_len
, sum_key_len
);
1670 ASSERT_EQ(vals_len
, sum_value_len
);
1672 for (int i
= 1; i
<= 70; i
++) {
1673 key
= "key" + stringify(i
);
1674 val
= "value" + stringify(i
);
1675 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1676 ASSERT_STREQ(val
.c_str(), value
);
1678 value_len
= sizeof(value
);
1681 ASSERT_EQ(0, rbd_snap_create(image
, "deep_snap"));
1682 ASSERT_EQ(0, rbd_close(image
));
1683 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, "deep_snap"));
1684 ASSERT_EQ(0, rbd_snap_protect(image
, "deep_snap"));
1685 ASSERT_EQ(0, rbd_clone3(ioctx
, name
.c_str(), "deep_snap", ioctx
,
1686 name4
.c_str(), opts
));
1688 ASSERT_EQ(4, test_ls(ioctx
, 4, name
.c_str(), name2
.c_str(), name3
.c_str(),
1690 ASSERT_EQ(0, rbd_open(ioctx
, name4
.c_str(), &image4
, NULL
));
1691 BOOST_SCOPE_EXIT_ALL( (&image4
) ) {
1692 ASSERT_EQ(0, rbd_close(image4
));
1694 ASSERT_EQ(0, rbd_snap_create(image4
, "deep_snap"));
1696 ASSERT_EQ(0, rbd_deep_copy(image4
, ioctx
, name5
.c_str(), opts
));
1697 ASSERT_EQ(5, test_ls(ioctx
, 5, name
.c_str(), name2
.c_str(), name3
.c_str(),
1698 name4
.c_str(), name5
.c_str()));
1699 ASSERT_EQ(0, rbd_open(ioctx
, name5
.c_str(), &image5
, NULL
));
1700 BOOST_SCOPE_EXIT_ALL( (&image5
) ) {
1701 ASSERT_EQ(0, rbd_close(image5
));
1703 ASSERT_EQ(0, rbd_metadata_list(image5
, "key", 70, keys
, &keys_len
, vals
,
1705 ASSERT_EQ(keys_len
, sum_key_len
);
1706 ASSERT_EQ(vals_len
, sum_value_len
);
1708 for (int i
= 1; i
<= 70; i
++) {
1709 key
= "key" + stringify(i
);
1710 val
= "value" + stringify(i
);
1711 ASSERT_EQ(0, rbd_metadata_get(image5
, key
.c_str(), value
, &value_len
));
1712 ASSERT_STREQ(val
.c_str(), value
);
1714 value_len
= sizeof(value
);
1717 ASSERT_EQ(0, rbd_deep_copy_with_progress(image4
, ioctx
, name6
.c_str(), opts
,
1718 print_progress_percent
, NULL
));
1719 ASSERT_EQ(6, test_ls(ioctx
, 6, name
.c_str(), name2
.c_str(), name3
.c_str(),
1720 name4
.c_str(), name5
.c_str(), name6
.c_str()));
1722 keys_len
= sizeof(keys
);
1723 vals_len
= sizeof(vals
);
1724 ASSERT_EQ(0, rbd_open(ioctx
, name6
.c_str(), &image6
, NULL
));
1725 BOOST_SCOPE_EXIT_ALL( (&image6
) ) {
1726 ASSERT_EQ(0, rbd_close(image6
));
1728 ASSERT_EQ(0, rbd_metadata_list(image6
, "key", 70, keys
, &keys_len
, vals
,
1730 ASSERT_EQ(keys_len
, sum_key_len
);
1731 ASSERT_EQ(vals_len
, sum_value_len
);
1733 for (int i
= 1; i
<= 70; i
++) {
1734 key
= "key" + stringify(i
);
1735 val
= "value" + stringify(i
);
1736 ASSERT_EQ(0, rbd_metadata_get(image6
, key
.c_str(), value
, &value_len
));
1737 ASSERT_STREQ(val
.c_str(), value
);
1739 value_len
= sizeof(value
);
1743 TEST_F(TestLibRBD
, TestDeepCopyPP
)
1745 REQUIRE_FORMAT_V2();
1747 librados::IoCtx ioctx
;
1748 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1752 librbd::Image image
;
1753 librbd::Image image2
;
1754 librbd::Image image3
;
1756 std::string name
= get_temp_image_name();
1757 std::string name2
= get_temp_image_name();
1758 std::string name3
= get_temp_image_name();
1759 uint64_t size
= 2 << 20;
1760 librbd::ImageOptions opts
;
1763 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1764 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1768 for (int i
= 1; i
<= 70; i
++) {
1769 key
= "key" + stringify(i
);
1770 val
= "value" + stringify(i
);
1771 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1774 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1775 ASSERT_EQ(0, image
.deep_copy(ioctx
, name2
.c_str(), opts
));
1776 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1777 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1779 map
<string
, bufferlist
> pairs
;
1781 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1782 ASSERT_EQ(70U, pairs
.size());
1784 for (int i
= 1; i
<= 70; i
++) {
1785 key
= "key" + stringify(i
);
1786 val
= "value" + stringify(i
);
1787 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1788 ASSERT_STREQ(val
.c_str(), value
.c_str());
1791 ASSERT_EQ(0, image
.deep_copy_with_progress(ioctx
, name3
.c_str(), opts
, pp
));
1792 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1794 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1797 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1798 ASSERT_EQ(70U, pairs
.size());
1800 for (int i
= 1; i
<= 70; i
++) {
1801 key
= "key" + stringify(i
);
1802 val
= "value" + stringify(i
);
1803 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1804 ASSERT_STREQ(val
.c_str(), value
.c_str());
1811 int test_ls_snaps(rbd_image_t image
, int num_expected
, ...)
1813 int num_snaps
, i
, j
, max_size
= 10;
1815 rbd_snap_info_t snaps
[max_size
];
1816 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1817 printf("num snaps is: %d\nexpected: %d\n", num_snaps
, num_expected
);
1819 for (i
= 0; i
< num_snaps
; i
++) {
1820 printf("snap: %s\n", snaps
[i
].name
);
1823 va_start(ap
, num_expected
);
1824 for (i
= num_expected
; i
> 0; i
--) {
1825 char *expected
= va_arg(ap
, char *);
1826 uint64_t expected_size
= va_arg(ap
, uint64_t);
1828 for (j
= 0; j
< num_snaps
; j
++) {
1829 if (snaps
[j
].name
== NULL
)
1831 if (strcmp(snaps
[j
].name
, expected
) == 0) {
1832 printf("found %s with size %llu\n", snaps
[j
].name
, (unsigned long long) snaps
[j
].size
);
1833 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1834 free((void *) snaps
[j
].name
);
1835 snaps
[j
].name
= NULL
;
1844 for (i
= 0; i
< num_snaps
; i
++) {
1845 EXPECT_EQ((const char *)0, snaps
[i
].name
);
1851 TEST_F(TestLibRBD
, TestCreateLsDeleteSnap
)
1853 rados_ioctx_t ioctx
;
1854 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1858 std::string name
= get_temp_image_name();
1859 uint64_t size
= 2 << 20;
1860 uint64_t size2
= 4 << 20;
1862 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1863 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1865 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1866 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1867 ASSERT_EQ(0, rbd_resize(image
, size2
));
1868 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1869 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1870 ASSERT_EQ(0, rbd_snap_remove(image
, "snap1"));
1871 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1872 ASSERT_EQ(0, rbd_snap_remove(image
, "snap2"));
1873 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1875 ASSERT_EQ(0, rbd_close(image
));
1877 rados_ioctx_destroy(ioctx
);
1880 int test_get_snapshot_timestamp(rbd_image_t image
, uint64_t snap_id
)
1882 struct timespec timestamp
;
1883 EXPECT_EQ(0, rbd_snap_get_timestamp(image
, snap_id
, ×tamp
));
1884 EXPECT_LT(0, timestamp
.tv_sec
);
1888 TEST_F(TestLibRBD
, TestGetSnapShotTimeStamp
)
1890 REQUIRE_FORMAT_V2();
1892 rados_ioctx_t ioctx
;
1893 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1897 std::string name
= get_temp_image_name();
1898 uint64_t size
= 2 << 20;
1899 int num_snaps
, max_size
= 10;
1900 rbd_snap_info_t snaps
[max_size
];
1902 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1903 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1905 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1906 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1907 ASSERT_EQ(1, num_snaps
);
1908 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1909 free((void *)snaps
[0].name
);
1911 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1912 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1913 ASSERT_EQ(2, num_snaps
);
1914 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1915 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[1].id
));
1916 free((void *)snaps
[0].name
);
1917 free((void *)snaps
[1].name
);
1919 ASSERT_EQ(0, rbd_close(image
));
1921 rados_ioctx_destroy(ioctx
);
1925 int test_ls_snaps(librbd::Image
& image
, size_t num_expected
, ...)
1930 vector
<librbd::snap_info_t
> snaps
;
1931 r
= image
.snap_list(snaps
);
1932 EXPECT_TRUE(r
>= 0);
1933 cout
<< "num snaps is: " << snaps
.size() << std::endl
1934 << "expected: " << num_expected
<< std::endl
;
1936 for (i
= 0; i
< snaps
.size(); i
++) {
1937 cout
<< "snap: " << snaps
[i
].name
<< std::endl
;
1940 va_start(ap
, num_expected
);
1941 for (i
= num_expected
; i
> 0; i
--) {
1942 char *expected
= va_arg(ap
, char *);
1943 uint64_t expected_size
= va_arg(ap
, uint64_t);
1945 for (j
= 0; j
< snaps
.size(); j
++) {
1946 if (snaps
[j
].name
== "")
1948 if (strcmp(snaps
[j
].name
.c_str(), expected
) == 0) {
1949 cout
<< "found " << snaps
[j
].name
<< " with size " << snaps
[j
].size
1951 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1961 for (i
= 0; i
< snaps
.size(); i
++) {
1962 EXPECT_EQ("", snaps
[i
].name
);
1965 return snaps
.size();
1968 TEST_F(TestLibRBD
, TestCreateLsDeleteSnapPP
)
1970 librados::IoCtx ioctx
;
1971 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1975 librbd::Image image
;
1977 std::string name
= get_temp_image_name();
1978 uint64_t size
= 2 << 20;
1979 uint64_t size2
= 4 << 20;
1981 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1982 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1985 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1986 ASSERT_FALSE(exists
);
1987 ASSERT_EQ(0, image
.snap_create("snap1"));
1988 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1989 ASSERT_TRUE(exists
);
1990 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1991 ASSERT_EQ(0, image
.resize(size2
));
1992 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1993 ASSERT_FALSE(exists
);
1994 ASSERT_EQ(0, image
.snap_create("snap2"));
1995 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1996 ASSERT_TRUE(exists
);
1997 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1998 ASSERT_EQ(0, image
.snap_remove("snap1"));
1999 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2000 ASSERT_FALSE(exists
);
2001 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
2002 ASSERT_EQ(0, image
.snap_remove("snap2"));
2003 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2004 ASSERT_FALSE(exists
);
2005 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2011 TEST_F(TestLibRBD
, TestGetNameIdSnapPP
)
2013 librados::IoCtx ioctx
;
2014 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2018 librbd::Image image
;
2020 std::string name
= get_temp_image_name();
2021 uint64_t size
= 2 << 20;
2023 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2024 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2026 ASSERT_EQ(0, image
.snap_create("snap1"));
2027 ASSERT_EQ(0, image
.snap_create("snap2"));
2028 ASSERT_EQ(0, image
.snap_create("snap3"));
2029 vector
<librbd::snap_info_t
> snaps
;
2030 int r
= image
.snap_list(snaps
);
2031 EXPECT_TRUE(r
>= 0);
2033 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
2034 std::string expected_snap_name
;
2035 image
.snap_get_name(snaps
[i
].id
, &expected_snap_name
);
2036 ASSERT_EQ(expected_snap_name
, snaps
[i
].name
);
2039 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
2040 uint64_t expected_snap_id
;
2041 image
.snap_get_id(snaps
[i
].name
, &expected_snap_id
);
2042 ASSERT_EQ(expected_snap_id
, snaps
[i
].id
);
2045 ASSERT_EQ(0, image
.snap_remove("snap1"));
2046 ASSERT_EQ(0, image
.snap_remove("snap2"));
2047 ASSERT_EQ(0, image
.snap_remove("snap3"));
2048 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2054 TEST_F(TestLibRBD
, TestCreateLsRenameSnapPP
)
2056 librados::IoCtx ioctx
;
2057 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2061 librbd::Image image
;
2063 std::string name
= get_temp_image_name();
2064 uint64_t size
= 2 << 20;
2065 uint64_t size2
= 4 << 20;
2067 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2068 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2071 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2072 ASSERT_FALSE(exists
);
2073 ASSERT_EQ(0, image
.snap_create("snap1"));
2074 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2075 ASSERT_TRUE(exists
);
2076 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
2077 ASSERT_EQ(0, image
.resize(size2
));
2078 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2079 ASSERT_FALSE(exists
);
2080 ASSERT_EQ(0, image
.snap_create("snap2"));
2081 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2082 ASSERT_TRUE(exists
);
2083 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
2084 ASSERT_EQ(0, image
.snap_rename("snap1","snap1-rename"));
2085 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1-rename", size
, "snap2", size2
));
2086 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2087 ASSERT_FALSE(exists
);
2088 ASSERT_EQ(0, image
.snap_exists2("snap1-rename", &exists
));
2089 ASSERT_TRUE(exists
);
2090 ASSERT_EQ(0, image
.snap_remove("snap1-rename"));
2091 ASSERT_EQ(0, image
.snap_rename("snap2","snap2-rename"));
2092 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2-rename", size2
));
2093 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2094 ASSERT_FALSE(exists
);
2095 ASSERT_EQ(0, image
.snap_exists2("snap2-rename", &exists
));
2096 ASSERT_TRUE(exists
);
2097 ASSERT_EQ(0, image
.snap_remove("snap2-rename"));
2098 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2104 TEST_F(TestLibRBD
, ConcurrentCreatesUnvalidatedPool
)
2106 rados_ioctx_t ioctx
;
2107 ASSERT_EQ(0, rados_ioctx_create(_cluster
, create_pool(true).c_str(),
2110 std::vector
<std::string
> names
;
2111 for (int i
= 0; i
< 4; i
++) {
2112 names
.push_back(get_temp_image_name());
2114 uint64_t size
= 2 << 20;
2116 std::vector
<std::thread
> threads
;
2117 for (const auto& name
: names
) {
2118 threads
.emplace_back([ioctx
, &name
, size
]() {
2120 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2123 for (auto& thread
: threads
) {
2127 for (const auto& name
: names
) {
2128 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2130 rados_ioctx_destroy(ioctx
);
2133 static void remove_full_try(rados_ioctx_t ioctx
, const std::string
& image_name
,
2134 const std::string
& data_pool_name
)
2137 uint64_t quota
= 10 << 20;
2138 uint64_t size
= 5 * quota
;
2139 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), size
, &order
));
2141 std::string cmdstr
= "{\"prefix\": \"osd pool set-quota\", \"pool\": \"" +
2142 data_pool_name
+ "\", \"field\": \"max_bytes\", \"val\": \"" +
2143 std::to_string(quota
) + "\"}";
2145 cmd
[0] = (char *)cmdstr
.c_str();
2146 ASSERT_EQ(0, rados_mon_command(rados_ioctx_get_cluster(ioctx
),
2147 (const char **)cmd
, 1, "", 0, nullptr, 0,
2150 rados_set_pool_full_try(ioctx
);
2153 ASSERT_EQ(0, rbd_open(ioctx
, image_name
.c_str(), &image
, nullptr));
2156 size_t len
= 1 << 20;
2158 for (off
= 0; off
< size
; off
+= len
) {
2159 ret
= rbd_write_zeroes(image
, off
, len
,
2160 RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
,
2161 LIBRADOS_OP_FLAG_FADVISE_FUA
);
2165 ASSERT_EQ(ret
, len
);
2168 ASSERT_TRUE(off
>= quota
&& off
< size
);
2169 ASSERT_EQ(ret
, -EDQUOT
);
2171 ASSERT_EQ(0, rbd_close(image
));
2173 // make sure we have latest map that marked the pool full
2174 ASSERT_EQ(0, rados_wait_for_latest_osdmap(rados_ioctx_get_cluster(ioctx
)));
2175 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
2178 TEST_F(TestLibRBD
, RemoveFullTry
)
2180 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
2181 REQUIRE(!is_librados_test_stub(_rados
));
2183 rados_ioctx_t ioctx
;
2184 auto pool_name
= create_pool(true);
2185 ASSERT_EQ(0, rados_ioctx_create(_cluster
, pool_name
.c_str(), &ioctx
));
2186 // cancel out rbd_default_data_pool -- we need an image without
2187 // a separate data pool
2188 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_default_data_pool",
2189 pool_name
.c_str()));
2192 auto image_name
= get_temp_image_name();
2193 // FIXME: this is a workaround for rbd_trash object being created
2194 // on the first remove -- pre-create it to avoid bumping into quota
2195 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), 0, &order
));
2196 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
2197 remove_full_try(ioctx
, image_name
, pool_name
);
2199 rados_ioctx_destroy(ioctx
);
2202 TEST_F(TestLibRBD
, RemoveFullTryDataPool
)
2204 REQUIRE_FORMAT_V2();
2205 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
2206 REQUIRE(!is_librados_test_stub(_rados
));
2208 rados_ioctx_t ioctx
;
2209 auto pool_name
= create_pool(true);
2210 auto data_pool_name
= create_pool(true);
2211 ASSERT_EQ(0, rados_ioctx_create(_cluster
, pool_name
.c_str(), &ioctx
));
2212 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_default_data_pool",
2213 data_pool_name
.c_str()));
2215 auto image_name
= get_temp_image_name();
2216 remove_full_try(ioctx
, image_name
, data_pool_name
);
2218 rados_ioctx_destroy(ioctx
);
2221 TEST_F(TestLibRBD
, TestIO
)
2223 rados_ioctx_t ioctx
;
2224 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2228 std::string name
= get_temp_image_name();
2229 uint64_t size
= 2 << 20;
2231 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2232 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_read_from_replica_policy", "balance"));
2233 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2237 ASSERT_EQ(0, rbd_close(image
));
2239 rados_ioctx_destroy(ioctx
);
2242 TEST_F(TestLibRBD
, TestEncryptionLUKS1
)
2244 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2246 rados_ioctx_t ioctx
;
2247 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2250 std::string name
= get_temp_image_name();
2251 uint64_t size
= 32 << 20;
2253 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2254 ASSERT_EQ(0, rados_conf_set(
2255 _cluster
, "rbd_read_from_replica_policy", "balance"));
2258 rbd_encryption_luks1_format_options_t luks1_opts
= {
2259 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2260 .passphrase
= "password",
2261 .passphrase_size
= 8,
2263 rbd_encryption_luks2_format_options_t luks2_opts
= {
2264 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2265 .passphrase
= "password",
2266 .passphrase_size
= 8,
2268 rbd_encryption_luks_format_options_t luks_opts
= {
2269 .passphrase
= "password",
2270 .passphrase_size
= 8,
2272 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2274 #ifndef HAVE_LIBCRYPTSETUP
2275 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2276 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2277 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2278 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2279 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2280 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2281 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2282 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2283 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2284 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2285 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2286 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2288 ASSERT_EQ(-EINVAL
, rbd_encryption_format(
2289 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2290 ASSERT_EQ(0, rbd_encryption_format(
2291 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2292 ASSERT_EQ(-EEXIST
, rbd_encryption_load(
2293 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2297 ASSERT_PASSED(write_test_data
, image
, "test", 0, 4, 0);
2298 ASSERT_EQ(0, rbd_close(image
));
2300 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2301 ASSERT_EQ(-EINVAL
, rbd_encryption_load(
2302 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2303 ASSERT_EQ(0, rbd_encryption_load(
2304 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2305 ASSERT_PASSED(read_test_data
, image
, "test", 0, 4, 0);
2306 ASSERT_EQ(0, rbd_close(image
));
2308 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2309 ASSERT_EQ(-EINVAL
, rbd_encryption_load(
2310 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2311 ASSERT_EQ(0, rbd_encryption_load(
2312 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2313 ASSERT_PASSED(read_test_data
, image
, "test", 0, 4, 0);
2316 ASSERT_EQ(0, rbd_close(image
));
2317 rados_ioctx_destroy(ioctx
);
2320 TEST_F(TestLibRBD
, TestEncryptionLUKS2
)
2322 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2324 rados_ioctx_t ioctx
;
2325 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2328 std::string name
= get_temp_image_name();
2329 uint64_t size
= 32 << 20;
2331 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2332 ASSERT_EQ(0, rados_conf_set(
2333 _cluster
, "rbd_read_from_replica_policy", "balance"));
2336 rbd_encryption_luks1_format_options_t luks1_opts
= {
2337 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2338 .passphrase
= "password",
2339 .passphrase_size
= 8,
2341 rbd_encryption_luks2_format_options_t luks2_opts
= {
2342 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2343 .passphrase
= "password",
2344 .passphrase_size
= 8,
2346 rbd_encryption_luks_format_options_t luks_opts
= {
2347 .passphrase
= "password",
2348 .passphrase_size
= 8,
2350 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2352 #ifndef HAVE_LIBCRYPTSETUP
2353 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2354 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2355 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2356 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2357 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2358 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2359 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2360 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2361 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2362 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2363 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2364 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2366 ASSERT_EQ(-EINVAL
, rbd_encryption_format(
2367 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2368 ASSERT_EQ(0, rbd_encryption_format(
2369 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2370 ASSERT_EQ(-EEXIST
, rbd_encryption_load(
2371 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2375 ASSERT_PASSED(write_test_data
, image
, "test", 0, 4, 0);
2376 ASSERT_EQ(0, rbd_close(image
));
2378 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2379 ASSERT_EQ(-EINVAL
, rbd_encryption_load(
2380 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2381 ASSERT_EQ(0, rbd_encryption_load(
2382 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &luks2_opts
, sizeof(luks2_opts
)));
2383 ASSERT_PASSED(read_test_data
, image
, "test", 0, 4, 0);
2384 ASSERT_EQ(0, rbd_close(image
));
2386 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2387 ASSERT_EQ(-EINVAL
, rbd_encryption_load(
2388 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &luks1_opts
, sizeof(luks1_opts
)));
2389 ASSERT_EQ(0, rbd_encryption_load(
2390 image
, RBD_ENCRYPTION_FORMAT_LUKS
, &luks_opts
, sizeof(luks_opts
)));
2391 ASSERT_PASSED(read_test_data
, image
, "test", 0, 4, 0);
2394 ASSERT_EQ(0, rbd_close(image
));
2395 rados_ioctx_destroy(ioctx
);
2398 #ifdef HAVE_LIBCRYPTSETUP
2400 TEST_F(TestLibRBD
, TestCloneEncryption
)
2402 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2403 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
2404 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2406 rados_ioctx_t ioctx
;
2407 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2408 ASSERT_EQ(0, rados_conf_set(
2409 _cluster
, "rbd_read_from_replica_policy", "balance"));
2411 // create base image, write 'a's
2413 std::string name
= get_temp_image_name();
2414 uint64_t size
= 256 << 20;
2415 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2418 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2419 ASSERT_PASSED(write_test_data
, image
, "aaaa", 0, 4, 0);
2420 ASSERT_EQ(0, rbd_flush(image
));
2422 // clone, encrypt with LUKS1, write 'b's
2423 ASSERT_EQ(0, rbd_snap_create(image
, "snap"));
2424 ASSERT_EQ(0, rbd_snap_protect(image
, "snap"));
2426 rbd_image_options_t image_opts
;
2427 rbd_image_options_create(&image_opts
);
2428 BOOST_SCOPE_EXIT_ALL( (&image_opts
) ) {
2429 rbd_image_options_destroy(image_opts
);
2431 std::string child1_name
= get_temp_image_name();
2432 ASSERT_EQ(0, rbd_clone3(ioctx
, name
.c_str(), "snap", ioctx
,
2433 child1_name
.c_str(), image_opts
));
2436 ASSERT_EQ(0, rbd_open(ioctx
, child1_name
.c_str(), &child1
, NULL
));
2438 rbd_encryption_luks1_format_options_t child1_opts
= {
2439 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2440 .passphrase
= "password",
2441 .passphrase_size
= 8,
2443 ASSERT_EQ(-EINVAL
, rbd_encryption_load(
2444 child1
, RBD_ENCRYPTION_FORMAT_LUKS1
, &child1_opts
,
2445 sizeof(child1_opts
)));
2446 ASSERT_EQ(0, rbd_encryption_format(
2447 child1
, RBD_ENCRYPTION_FORMAT_LUKS1
, &child1_opts
,
2448 sizeof(child1_opts
)));
2449 ASSERT_EQ(0, rbd_encryption_load(
2450 child1
, RBD_ENCRYPTION_FORMAT_LUKS1
, &child1_opts
,
2451 sizeof(child1_opts
)));
2452 ASSERT_PASSED(write_test_data
, child1
, "bbbb", 64 << 20, 4, 0);
2453 ASSERT_EQ(0, rbd_flush(child1
));
2455 // clone, encrypt with LUKS2 (same passphrase), write 'c's
2456 ASSERT_EQ(0, rbd_snap_create(child1
, "snap"));
2457 ASSERT_EQ(0, rbd_snap_protect(child1
, "snap"));
2459 std::string child2_name
= get_temp_image_name();
2460 ASSERT_EQ(0, rbd_clone3(ioctx
, child1_name
.c_str(), "snap", ioctx
,
2461 child2_name
.c_str(), image_opts
));
2464 ASSERT_EQ(0, rbd_open(ioctx
, child2_name
.c_str(), &child2
, NULL
));
2466 rbd_encryption_luks2_format_options_t child2_opts
= {
2467 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2468 .passphrase
= "password",
2469 .passphrase_size
= 8,
2471 ASSERT_EQ(0, rbd_encryption_format(
2472 child2
, RBD_ENCRYPTION_FORMAT_LUKS2
, &child2_opts
,
2473 sizeof(child2_opts
)));
2474 rbd_encryption_luks_format_options_t child2_lopts
= {
2475 .passphrase
= "password",
2476 .passphrase_size
= 8,
2478 ASSERT_EQ(0, rbd_encryption_load(
2479 child2
, RBD_ENCRYPTION_FORMAT_LUKS
, &child2_lopts
,
2480 sizeof(child2_lopts
)));
2481 ASSERT_PASSED(write_test_data
, child2
, "cccc", 128 << 20, 4, 0);
2482 ASSERT_EQ(0, rbd_flush(child2
));
2484 // clone, encrypt with LUKS2 (different passphrase)
2485 ASSERT_EQ(0, rbd_snap_create(child2
, "snap"));
2486 ASSERT_EQ(0, rbd_snap_protect(child2
, "snap"));
2488 std::string child3_name
= get_temp_image_name();
2489 ASSERT_EQ(0, rbd_clone3(ioctx
, child2_name
.c_str(), "snap", ioctx
,
2490 child3_name
.c_str(), image_opts
));
2493 ASSERT_EQ(0, rbd_open(ioctx
, child3_name
.c_str(), &child3
, NULL
));
2495 rbd_encryption_luks2_format_options_t child3_opts
= {
2496 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2497 .passphrase
= "12345678",
2498 .passphrase_size
= 8,
2500 ASSERT_EQ(0, rbd_encryption_format(
2501 child3
, RBD_ENCRYPTION_FORMAT_LUKS2
, &child3_opts
,
2502 sizeof(child3_opts
)));
2503 ASSERT_EQ(-EPERM
, rbd_encryption_load(
2504 child3
, RBD_ENCRYPTION_FORMAT_LUKS2
, &child3_opts
,
2505 sizeof(child3_opts
)));
2507 // verify child3 data
2508 rbd_encryption_spec_t specs
[] = {
2509 { .format
= RBD_ENCRYPTION_FORMAT_LUKS2
,
2510 .opts
= &child3_opts
,
2511 .opts_size
= sizeof(child3_opts
)},
2512 { .format
= RBD_ENCRYPTION_FORMAT_LUKS2
,
2513 .opts
= &child2_opts
,
2514 .opts_size
= sizeof(child2_opts
)},
2515 { .format
= RBD_ENCRYPTION_FORMAT_LUKS1
,
2516 .opts
= &child1_opts
,
2517 .opts_size
= sizeof(child1_opts
)}
2520 ASSERT_EQ(0, rbd_encryption_load2(child3
, specs
, 3));
2522 ASSERT_PASSED(read_test_data
, child3
, "aaaa", 0, 4, 0);
2523 ASSERT_PASSED(read_test_data
, child3
, "bbbb", 64 << 20, 4, 0);
2524 ASSERT_PASSED(read_test_data
, child3
, "cccc", 128 << 20, 4, 0);
2526 // clone without formatting
2527 ASSERT_EQ(0, rbd_snap_create(child3
, "snap"));
2528 ASSERT_EQ(0, rbd_snap_protect(child3
, "snap"));
2530 std::string child4_name
= get_temp_image_name();
2531 ASSERT_EQ(0, rbd_clone3(ioctx
, child3_name
.c_str(), "snap", ioctx
,
2532 child4_name
.c_str(), image_opts
));
2535 ASSERT_EQ(0, rbd_open(ioctx
, child4_name
.c_str(), &child4
, NULL
));
2537 rbd_encryption_spec_t child4_specs
[] = {
2538 { .format
= RBD_ENCRYPTION_FORMAT_LUKS2
,
2539 .opts
= &child3_opts
,
2540 .opts_size
= sizeof(child3_opts
)},
2541 { .format
= RBD_ENCRYPTION_FORMAT_LUKS2
,
2542 .opts
= &child3_opts
,
2543 .opts_size
= sizeof(child3_opts
)},
2544 { .format
= RBD_ENCRYPTION_FORMAT_LUKS2
,
2545 .opts
= &child2_opts
,
2546 .opts_size
= sizeof(child2_opts
)},
2547 { .format
= RBD_ENCRYPTION_FORMAT_LUKS1
,
2548 .opts
= &child1_opts
,
2549 .opts_size
= sizeof(child1_opts
)}
2552 ASSERT_EQ(0, rbd_encryption_load2(child4
, child4_specs
, 4));
2555 ASSERT_EQ(0, rbd_flatten(child4
));
2557 // reopen child4 and load encryption
2558 ASSERT_EQ(0, rbd_close(child4
));
2559 ASSERT_EQ(0, rbd_open(ioctx
, child4_name
.c_str(), &child4
, NULL
));
2560 ASSERT_EQ(0, rbd_encryption_load(
2561 child4
, RBD_ENCRYPTION_FORMAT_LUKS2
, &child3_opts
,
2562 sizeof(child3_opts
)));
2564 // verify flattend image
2565 ASSERT_PASSED(read_test_data
, child4
, "aaaa", 0, 4, 0);
2566 ASSERT_PASSED(read_test_data
, child4
, "bbbb", 64 << 20, 4, 0);
2567 ASSERT_PASSED(read_test_data
, child4
, "cccc", 128 << 20, 4, 0);
2569 ASSERT_EQ(0, rbd_close(child4
));
2570 ASSERT_EQ(0, rbd_remove(ioctx
, child4_name
.c_str()));
2571 ASSERT_EQ(0, rbd_snap_unprotect(child3
, "snap"));
2572 ASSERT_EQ(0, rbd_snap_remove(child3
, "snap"));
2573 ASSERT_EQ(0, rbd_close(child3
));
2574 ASSERT_EQ(0, rbd_remove(ioctx
, child3_name
.c_str()));
2575 ASSERT_EQ(0, rbd_snap_unprotect(child2
, "snap"));
2576 ASSERT_EQ(0, rbd_snap_remove(child2
, "snap"));
2577 ASSERT_EQ(0, rbd_close(child2
));
2578 ASSERT_EQ(0, rbd_remove(ioctx
, child2_name
.c_str()));
2579 ASSERT_EQ(0, rbd_snap_unprotect(child1
, "snap"));
2580 ASSERT_EQ(0, rbd_snap_remove(child1
, "snap"));
2581 ASSERT_EQ(0, rbd_close(child1
));
2582 ASSERT_EQ(0, rbd_remove(ioctx
, child1_name
.c_str()));
2583 ASSERT_EQ(0, rbd_snap_unprotect(image
, "snap"));
2584 ASSERT_EQ(0, rbd_snap_remove(image
, "snap"));
2585 ASSERT_EQ(0, rbd_close(image
));
2586 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2587 rados_ioctx_destroy(ioctx
);
2590 TEST_F(TestLibRBD
, LUKS1UnderLUKS2WithoutResize
)
2592 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2593 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
2594 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2596 librados::IoCtx ioctx
;
2597 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2600 std::string parent_name
= get_temp_image_name();
2601 std::string clone_name
= get_temp_image_name();
2602 uint64_t data_size
= 25 << 20;
2603 uint64_t luks1_meta_size
= 4 << 20;
2604 uint64_t luks2_meta_size
= 16 << 20;
2605 std::string parent_passphrase
= "parent passphrase";
2606 std::string clone_passphrase
= "clone passphrase";
2610 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(),
2611 luks1_meta_size
+ data_size
, &order
));
2612 librbd::Image parent
;
2613 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), nullptr));
2615 librbd::encryption_luks1_format_options_t fopts
= {
2616 RBD_ENCRYPTION_ALGORITHM_AES256
, parent_passphrase
};
2617 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
2620 ceph::bufferlist bl
;
2621 bl
.append(std::string(data_size
, 'a'));
2622 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
2624 ASSERT_EQ(0, parent
.snap_create("snap"));
2625 ASSERT_EQ(0, parent
.snap_protect("snap"));
2627 ASSERT_EQ(0, parent
.features(&features
));
2628 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap", ioctx
,
2629 clone_name
.c_str(), features
, &order
));
2633 librbd::Image clone
;
2634 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), nullptr));
2636 librbd::encryption_luks2_format_options_t fopts
=
2637 {RBD_ENCRYPTION_ALGORITHM_AES256
, clone_passphrase
};
2638 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
2641 librbd::encryption_luks_format_options_t opts1
= {parent_passphrase
};
2642 librbd::encryption_luks_format_options_t opts2
= {clone_passphrase
};
2643 librbd::encryption_spec_t specs
[] = {
2644 {RBD_ENCRYPTION_FORMAT_LUKS
, &opts2
, sizeof(opts2
)},
2645 {RBD_ENCRYPTION_FORMAT_LUKS
, &opts1
, sizeof(opts1
)}};
2646 ASSERT_EQ(0, clone
.encryption_load2(specs
, std::size(specs
)));
2649 ASSERT_EQ(0, clone
.size(&size
));
2650 EXPECT_EQ(data_size
+ luks1_meta_size
- luks2_meta_size
, size
);
2652 ASSERT_EQ(0, clone
.overlap(&overlap
));
2653 EXPECT_EQ(data_size
+ luks1_meta_size
- luks2_meta_size
, overlap
);
2655 ceph::bufferlist expected_bl
;
2656 expected_bl
.append(std::string(
2657 data_size
+ luks1_meta_size
- luks2_meta_size
, 'a'));
2659 ceph::bufferlist read_bl
;
2660 ASSERT_EQ(expected_bl
.length(),
2661 clone
.read(0, expected_bl
.length(), read_bl
));
2662 EXPECT_TRUE(expected_bl
.contents_equal(read_bl
));
2666 TEST_F(TestLibRBD
, LUKS2UnderLUKS1WithoutResize
)
2668 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2669 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
2670 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2672 librados::IoCtx ioctx
;
2673 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2676 std::string parent_name
= get_temp_image_name();
2677 std::string clone_name
= get_temp_image_name();
2678 uint64_t data_size
= 25 << 20;
2679 uint64_t luks1_meta_size
= 4 << 20;
2680 uint64_t luks2_meta_size
= 16 << 20;
2681 std::string parent_passphrase
= "parent passphrase";
2682 std::string clone_passphrase
= "clone passphrase";
2686 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(),
2687 luks2_meta_size
+ data_size
, &order
));
2688 librbd::Image parent
;
2689 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), nullptr));
2691 librbd::encryption_luks2_format_options_t fopts
= {
2692 RBD_ENCRYPTION_ALGORITHM_AES256
, parent_passphrase
};
2693 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
2696 ceph::bufferlist bl
;
2697 bl
.append(std::string(data_size
, 'a'));
2698 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
2700 ASSERT_EQ(0, parent
.snap_create("snap"));
2701 ASSERT_EQ(0, parent
.snap_protect("snap"));
2703 ASSERT_EQ(0, parent
.features(&features
));
2704 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap", ioctx
,
2705 clone_name
.c_str(), features
, &order
));
2709 librbd::Image clone
;
2710 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), nullptr));
2712 librbd::encryption_luks1_format_options_t fopts
=
2713 {RBD_ENCRYPTION_ALGORITHM_AES256
, clone_passphrase
};
2714 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
2717 librbd::encryption_luks_format_options_t opts1
= {parent_passphrase
};
2718 librbd::encryption_luks_format_options_t opts2
= {clone_passphrase
};
2719 librbd::encryption_spec_t specs
[] = {
2720 {RBD_ENCRYPTION_FORMAT_LUKS
, &opts2
, sizeof(opts2
)},
2721 {RBD_ENCRYPTION_FORMAT_LUKS
, &opts1
, sizeof(opts1
)}};
2722 ASSERT_EQ(0, clone
.encryption_load2(specs
, std::size(specs
)));
2725 ASSERT_EQ(0, clone
.size(&size
));
2726 EXPECT_EQ(data_size
+ luks2_meta_size
- luks1_meta_size
, size
);
2728 ASSERT_EQ(0, clone
.overlap(&overlap
));
2729 EXPECT_EQ(data_size
, overlap
);
2731 ceph::bufferlist expected_bl
;
2732 expected_bl
.append(std::string(data_size
, 'a'));
2733 expected_bl
.append_zero(luks2_meta_size
- luks1_meta_size
);
2735 ceph::bufferlist read_bl
;
2736 ASSERT_EQ(expected_bl
.length(),
2737 clone
.read(0, expected_bl
.length(), read_bl
));
2738 EXPECT_TRUE(expected_bl
.contents_equal(read_bl
));
2742 TEST_F(TestLibRBD
, EncryptionFormatNoData
)
2744 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2746 librados::IoCtx ioctx
;
2747 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2750 auto name
= get_temp_image_name();
2751 uint64_t luks1_meta_size
= 4 << 20;
2752 std::string passphrase
= "some passphrase";
2756 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), luks1_meta_size
- 1,
2758 librbd::Image image
;
2759 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
2761 librbd::encryption_luks1_format_options_t opts
= {
2762 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
2763 ASSERT_EQ(-ENOSPC
, image
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
,
2764 &opts
, sizeof(opts
)));
2766 ASSERT_EQ(0, image
.size(&size
));
2767 ASSERT_EQ(luks1_meta_size
- 1, size
);
2771 librbd::Image image
;
2772 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
2773 ASSERT_EQ(0, image
.resize(luks1_meta_size
));
2775 librbd::encryption_luks1_format_options_t opts
= {
2776 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
2777 ASSERT_EQ(0, image
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
,
2780 ASSERT_EQ(0, image
.size(&size
));
2785 TEST_F(TestLibRBD
, EncryptionLoadBadSize
)
2787 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2789 librados::IoCtx ioctx
;
2790 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2793 auto name
= get_temp_image_name();
2794 uint64_t luks1_meta_size
= 4 << 20;
2795 std::string passphrase
= "some passphrase";
2799 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), luks1_meta_size
,
2801 librbd::Image image
;
2802 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
2804 librbd::encryption_luks1_format_options_t opts
= {
2805 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
2806 ASSERT_EQ(0, image
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
,
2811 librbd::Image image
;
2812 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
2814 librbd::encryption_luks_format_options_t opts
= {passphrase
};
2815 ASSERT_EQ(0, image
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
2818 ASSERT_EQ(0, image
.size(&size
));
2823 librbd::Image image
;
2824 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
2825 ASSERT_EQ(0, image
.resize(luks1_meta_size
- 1));
2827 librbd::encryption_luks_format_options_t opts
= {passphrase
};
2828 ASSERT_EQ(-EINVAL
, image
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
2831 ASSERT_EQ(0, image
.size(&size
));
2832 ASSERT_EQ(luks1_meta_size
- 1, size
);
2836 TEST_F(TestLibRBD
, EncryptionLoadBadStripePattern
)
2838 REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2
);
2839 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2841 librados::IoCtx ioctx
;
2842 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2846 ASSERT_EQ(0, get_features(&old_format
, &features
));
2847 ASSERT_FALSE(old_format
);
2850 auto name1
= get_temp_image_name();
2851 auto name2
= get_temp_image_name();
2852 auto name3
= get_temp_image_name();
2853 std::string passphrase
= "some passphrase";
2857 ASSERT_EQ(0, rbd
.create3(ioctx
, name1
.c_str(), 20 << 20, features
, &order
,
2859 librbd::Image image
;
2860 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name1
.c_str(), nullptr));
2862 librbd::encryption_luks1_format_options_t opts
= {
2863 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
2864 ASSERT_EQ(0, image
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
,
2867 ASSERT_EQ(0, image
.size(&size
));
2868 ASSERT_EQ(12 << 20, size
);
2872 librbd::Image image
;
2873 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name1
.c_str(), nullptr));
2875 // different but compatible striping pattern
2876 librbd::ImageOptions image_opts
;
2877 ASSERT_EQ(0, image_opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, 1 << 20));
2878 ASSERT_EQ(0, image_opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, 2));
2879 ASSERT_EQ(0, image
.deep_copy(ioctx
, name2
.c_str(), image_opts
));
2882 librbd::Image image
;
2883 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name2
.c_str(), nullptr));
2885 librbd::encryption_luks_format_options_t opts
= {passphrase
};
2886 ASSERT_EQ(0, image
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
2889 ASSERT_EQ(0, image
.size(&size
));
2890 ASSERT_EQ(12 << 20, size
);
2894 librbd::Image image
;
2895 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name1
.c_str(), nullptr));
2897 // incompatible striping pattern
2898 librbd::ImageOptions image_opts
;
2899 ASSERT_EQ(0, image_opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, 1 << 20));
2900 ASSERT_EQ(0, image_opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, 3));
2901 ASSERT_EQ(0, image
.deep_copy(ioctx
, name3
.c_str(), image_opts
));
2904 librbd::Image image
;
2905 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name3
.c_str(), nullptr));
2907 librbd::encryption_luks_format_options_t opts
= {passphrase
};
2908 ASSERT_EQ(-EINVAL
, image
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
2911 ASSERT_EQ(0, image
.size(&size
));
2912 ASSERT_EQ(20 << 20, size
);
2916 TEST_F(TestLibRBD
, EncryptionLoadFormatMismatch
)
2918 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
2919 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2921 librados::IoCtx ioctx
;
2922 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2925 std::string name1
= get_temp_image_name();
2926 std::string name2
= get_temp_image_name();
2927 std::string name3
= get_temp_image_name();
2928 std::string passphrase
= "some passphrase";
2930 librbd::encryption_luks1_format_options_t luks1_opts
= {
2931 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
2932 librbd::encryption_luks2_format_options_t luks2_opts
= {
2933 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
2934 librbd::encryption_luks_format_options_t luks_opts
= {passphrase
};
2936 #define LUKS_ONE {RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)}
2937 #define LUKS_TWO {RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)}
2938 #define LUKS_ANY {RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)}
2940 const std::vector
<librbd::encryption_spec_t
> bad_specs
[] = {
2944 {LUKS_ONE
, LUKS_ONE
},
2945 {LUKS_ONE
, LUKS_TWO
},
2946 {LUKS_ONE
, LUKS_ANY
},
2947 {LUKS_TWO
, LUKS_TWO
},
2948 {LUKS_ANY
, LUKS_TWO
},
2949 {LUKS_ONE
, LUKS_ONE
, LUKS_ONE
},
2950 {LUKS_ONE
, LUKS_ONE
, LUKS_TWO
},
2951 {LUKS_ONE
, LUKS_ONE
, LUKS_ANY
},
2952 {LUKS_ONE
, LUKS_TWO
, LUKS_ONE
},
2953 {LUKS_ONE
, LUKS_TWO
, LUKS_TWO
},
2954 {LUKS_ONE
, LUKS_TWO
, LUKS_ANY
},
2955 {LUKS_ONE
, LUKS_ANY
, LUKS_ONE
},
2956 {LUKS_ONE
, LUKS_ANY
, LUKS_TWO
},
2957 {LUKS_ONE
, LUKS_ANY
, LUKS_ANY
},
2958 {LUKS_TWO
, LUKS_ONE
, LUKS_TWO
},
2959 {LUKS_TWO
, LUKS_TWO
, LUKS_ONE
},
2960 {LUKS_TWO
, LUKS_TWO
, LUKS_TWO
},
2961 {LUKS_TWO
, LUKS_TWO
, LUKS_ANY
},
2962 {LUKS_TWO
, LUKS_ANY
, LUKS_TWO
},
2963 {LUKS_ANY
, LUKS_ONE
, LUKS_TWO
},
2964 {LUKS_ANY
, LUKS_TWO
, LUKS_ONE
},
2965 {LUKS_ANY
, LUKS_TWO
, LUKS_TWO
},
2966 {LUKS_ANY
, LUKS_TWO
, LUKS_ANY
},
2967 {LUKS_ANY
, LUKS_ANY
, LUKS_TWO
},
2968 {LUKS_ANY
, LUKS_ANY
, LUKS_ANY
, LUKS_ANY
}};
2970 const std::vector
<librbd::encryption_spec_t
> good_specs
[] = {
2972 {LUKS_TWO
, LUKS_ONE
},
2973 {LUKS_TWO
, LUKS_ANY
},
2974 {LUKS_ANY
, LUKS_ONE
},
2975 {LUKS_ANY
, LUKS_ANY
},
2976 {LUKS_TWO
, LUKS_ONE
, LUKS_ONE
},
2977 {LUKS_TWO
, LUKS_ONE
, LUKS_ANY
},
2978 {LUKS_TWO
, LUKS_ANY
, LUKS_ONE
},
2979 {LUKS_TWO
, LUKS_ANY
, LUKS_ANY
},
2980 {LUKS_ANY
, LUKS_ONE
, LUKS_ONE
},
2981 {LUKS_ANY
, LUKS_ONE
, LUKS_ANY
},
2982 {LUKS_ANY
, LUKS_ANY
, LUKS_ONE
},
2983 {LUKS_ANY
, LUKS_ANY
, LUKS_ANY
}};
2985 static_assert(std::size(bad_specs
) + std::size(good_specs
) == 1 + 3 + 9 + 27 + 1);
2993 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name1
.c_str(), 20 << 20, &order
));
2994 librbd::Image image1
;
2995 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name1
.c_str(), nullptr));
2996 ASSERT_EQ(0, image1
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
,
2997 &luks1_opts
, sizeof(luks1_opts
)));
2999 ASSERT_EQ(0, image1
.snap_create("snap"));
3000 ASSERT_EQ(0, image1
.snap_protect("snap"));
3002 ASSERT_EQ(0, image1
.features(&features
));
3003 ASSERT_EQ(0, rbd
.clone(ioctx
, name1
.c_str(), "snap", ioctx
, name2
.c_str(),
3006 librbd::Image image2
;
3007 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), nullptr));
3008 ASSERT_EQ(0, image2
.snap_create("snap"));
3009 ASSERT_EQ(0, image2
.snap_protect("snap"));
3010 ASSERT_EQ(0, rbd
.clone(ioctx
, name2
.c_str(), "snap", ioctx
, name3
.c_str(),
3013 librbd::Image image3
;
3014 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), nullptr));
3015 ASSERT_EQ(0, image3
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
,
3016 &luks2_opts
, sizeof(luks2_opts
)));
3020 librbd::Image image3
;
3021 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), nullptr));
3022 for (auto& specs
: bad_specs
) {
3023 ASSERT_EQ(-EINVAL
, image3
.encryption_load2(specs
.data(), specs
.size()));
3027 for (auto& specs
: good_specs
) {
3028 librbd::Image image3
;
3029 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), nullptr));
3030 ASSERT_EQ(0, image3
.encryption_load2(specs
.data(), specs
.size()));
3034 TEST_F(TestLibRBD
, EncryptedResize
)
3036 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3038 librados::IoCtx ioctx
;
3039 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3042 auto name
= get_temp_image_name();
3043 uint64_t luks2_meta_size
= 16 << 20;
3044 uint64_t data_size
= 10 << 20;
3045 std::string passphrase
= "some passphrase";
3049 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(),
3050 luks2_meta_size
+ data_size
, &order
));
3051 librbd::Image image
;
3052 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
3055 ASSERT_EQ(0, image
.size(&size
));
3056 ASSERT_EQ(luks2_meta_size
+ data_size
, size
);
3058 librbd::encryption_luks2_format_options_t opts
= {
3059 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
3060 ASSERT_EQ(0, image
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
,
3062 ASSERT_EQ(0, image
.size(&size
));
3063 ASSERT_EQ(data_size
, size
);
3064 ASSERT_EQ(0, image
.resize(data_size
* 3));
3065 ASSERT_EQ(0, image
.size(&size
));
3066 ASSERT_EQ(data_size
* 3, size
);
3070 librbd::Image image
;
3071 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
3074 ASSERT_EQ(0, image
.size(&size
));
3075 ASSERT_EQ(luks2_meta_size
+ data_size
* 3, size
);
3077 librbd::encryption_luks_format_options_t opts
= {passphrase
};
3078 ASSERT_EQ(0, image
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
3080 ASSERT_EQ(0, image
.size(&size
));
3081 ASSERT_EQ(data_size
* 3, size
);
3082 ASSERT_EQ(0, image
.resize(data_size
/ 2));
3083 ASSERT_EQ(0, image
.size(&size
));
3084 ASSERT_EQ(data_size
/ 2, size
);
3088 librbd::Image image
;
3089 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
3092 ASSERT_EQ(0, image
.size(&size
));
3093 ASSERT_EQ(luks2_meta_size
+ data_size
/ 2, size
);
3095 librbd::encryption_luks_format_options_t opts
= {passphrase
};
3096 ASSERT_EQ(0, image
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
3098 ASSERT_EQ(0, image
.size(&size
));
3099 ASSERT_EQ(data_size
/ 2, size
);
3100 ASSERT_EQ(0, image
.resize(0));
3101 ASSERT_EQ(0, image
.size(&size
));
3106 librbd::Image image
;
3107 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
3110 ASSERT_EQ(0, image
.size(&size
));
3111 ASSERT_EQ(luks2_meta_size
, size
);
3113 librbd::encryption_luks_format_options_t opts
= {passphrase
};
3114 ASSERT_EQ(0, image
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
3116 ASSERT_EQ(0, image
.size(&size
));
3118 ASSERT_EQ(0, image
.resize(data_size
));
3119 ASSERT_EQ(0, image
.size(&size
));
3120 ASSERT_EQ(data_size
, size
);
3124 librbd::Image image
;
3125 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
3128 ASSERT_EQ(0, image
.size(&size
));
3129 ASSERT_EQ(luks2_meta_size
+ data_size
, size
);
3133 TEST_F(TestLibRBD
, EncryptedFlattenSmallData
)
3135 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3136 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3137 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3139 librados::IoCtx ioctx
;
3140 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3143 std::string parent_name
= get_temp_image_name();
3144 std::string clone_name
= get_temp_image_name();
3145 uint64_t data_size
= 5000;
3146 uint64_t luks2_meta_size
= 16 << 20;
3147 std::string passphrase
= "some passphrase";
3151 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(),
3152 luks2_meta_size
+ data_size
, &order
));
3153 librbd::Image parent
;
3154 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), nullptr));
3156 librbd::encryption_luks2_format_options_t opts
= {
3157 RBD_ENCRYPTION_ALGORITHM_AES256
, passphrase
};
3158 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
,
3161 ceph::bufferlist bl
;
3162 bl
.append(std::string(data_size
, 'a'));
3163 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3165 ASSERT_EQ(0, parent
.snap_create("snap"));
3166 ASSERT_EQ(0, parent
.snap_protect("snap"));
3168 ASSERT_EQ(0, parent
.features(&features
));
3169 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap", ioctx
,
3170 clone_name
.c_str(), features
, &order
));
3174 librbd::Image clone
;
3175 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), nullptr));
3177 librbd::encryption_luks_format_options_t opts
= {passphrase
};
3178 ASSERT_EQ(0, clone
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
3181 ASSERT_EQ(0, clone
.size(&size
));
3182 ASSERT_EQ(data_size
, size
);
3184 ASSERT_EQ(0, clone
.overlap(&overlap
));
3185 ASSERT_EQ(data_size
, overlap
);
3187 ceph::bufferlist expected_bl
;
3188 expected_bl
.append(std::string(data_size
, 'a'));
3190 ceph::bufferlist read_bl1
;
3191 ASSERT_EQ(data_size
, clone
.read(0, data_size
, read_bl1
));
3192 ASSERT_TRUE(expected_bl
.contents_equal(read_bl1
));
3194 ASSERT_EQ(0, clone
.flatten());
3196 ceph::bufferlist read_bl2
;
3197 ASSERT_EQ(data_size
, clone
.read(0, data_size
, read_bl2
));
3198 ASSERT_TRUE(expected_bl
.contents_equal(read_bl2
));
3202 librbd::Image clone
;
3203 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), nullptr));
3205 librbd::encryption_luks_format_options_t opts
= {passphrase
};
3206 ASSERT_EQ(0, clone
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
3209 ASSERT_EQ(0, clone
.size(&size
));
3210 ASSERT_EQ(data_size
, size
);
3212 ASSERT_EQ(0, clone
.overlap(&overlap
));
3213 ASSERT_EQ(0, overlap
);
3215 ceph::bufferlist expected_bl
;
3216 expected_bl
.append(std::string(data_size
, 'a'));
3218 ceph::bufferlist read_bl
;
3219 ASSERT_EQ(data_size
, clone
.read(0, data_size
, read_bl
));
3220 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
3224 struct LUKSOnePassphrase
{
3225 int load(librbd::Image
& clone
) {
3226 librbd::encryption_luks_format_options_t opts
= {m_passphrase
};
3227 return clone
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
3231 int load_flattened(librbd::Image
& clone
) {
3235 std::string m_passphrase
= "some passphrase";
3238 struct LUKSTwoPassphrases
{
3239 int load(librbd::Image
& clone
) {
3240 librbd::encryption_luks_format_options_t opts1
= {m_parent_passphrase
};
3241 librbd::encryption_luks_format_options_t opts2
= {m_clone_passphrase
};
3242 librbd::encryption_spec_t specs
[] = {
3243 {RBD_ENCRYPTION_FORMAT_LUKS
, &opts2
, sizeof(opts2
)},
3244 {RBD_ENCRYPTION_FORMAT_LUKS
, &opts1
, sizeof(opts1
)}};
3245 return clone
.encryption_load2(specs
, std::size(specs
));
3248 int load_flattened(librbd::Image
& clone
) {
3249 librbd::encryption_luks_format_options_t opts
= {m_clone_passphrase
};
3250 return clone
.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS
, &opts
,
3254 std::string m_parent_passphrase
= "parent passphrase";
3255 std::string m_clone_passphrase
= "clone passphrase";
3258 struct PlaintextUnderLUKS1
: LUKSOnePassphrase
{
3260 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3261 ceph::bufferlist bl
;
3262 bl
.append(std::string(data_size
, 'a'));
3263 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3265 // before taking a parent snapshot, (temporarily) add extra space
3266 // to the parent to account for upcoming LUKS1 header in the clone,
3267 // making the clone able to reach all parent data
3268 uint64_t luks1_meta_size
= 4 << 20;
3269 ASSERT_EQ(0, parent
.resize(data_size
+ luks1_meta_size
));
3273 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3274 librbd::encryption_luks1_format_options_t fopts
=
3275 {RBD_ENCRYPTION_ALGORITHM_AES256
, m_passphrase
};
3276 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
3282 struct PlaintextUnderLUKS2
: LUKSOnePassphrase
{
3283 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3284 ceph::bufferlist bl
;
3285 bl
.append(std::string(data_size
, 'a'));
3286 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3288 // before taking a parent snapshot, (temporarily) add extra space
3289 // to the parent to account for upcoming LUKS2 header in the clone,
3290 // making the clone able to reach all parent data
3291 uint64_t luks2_meta_size
= 16 << 20;
3292 ASSERT_EQ(0, parent
.resize(data_size
+ luks2_meta_size
));
3296 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3297 librbd::encryption_luks2_format_options_t fopts
=
3298 {RBD_ENCRYPTION_ALGORITHM_AES256
, m_passphrase
};
3299 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
3305 struct UnformattedLUKS1
: LUKSOnePassphrase
{
3306 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3307 uint64_t luks1_meta_size
= 4 << 20;
3308 ASSERT_EQ(0, parent
.resize(data_size
+ luks1_meta_size
));
3309 librbd::encryption_luks1_format_options_t fopts
= {
3310 RBD_ENCRYPTION_ALGORITHM_AES256
, m_passphrase
};
3311 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
3314 ceph::bufferlist bl
;
3315 bl
.append(std::string(data_size
, 'a'));
3316 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3320 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3325 struct LUKS1UnderLUKS1
: LUKSTwoPassphrases
{
3326 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3327 uint64_t luks1_meta_size
= 4 << 20;
3328 ASSERT_EQ(0, parent
.resize(data_size
+ luks1_meta_size
));
3329 librbd::encryption_luks1_format_options_t fopts
= {
3330 RBD_ENCRYPTION_ALGORITHM_AES256
, m_parent_passphrase
};
3331 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
3334 ceph::bufferlist bl
;
3335 bl
.append(std::string(data_size
, 'a'));
3336 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3340 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3341 librbd::encryption_luks1_format_options_t fopts
=
3342 {RBD_ENCRYPTION_ALGORITHM_AES256
, m_clone_passphrase
};
3343 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
3349 struct LUKS1UnderLUKS2
: LUKSTwoPassphrases
{
3350 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3351 uint64_t luks1_meta_size
= 4 << 20;
3352 ASSERT_EQ(0, parent
.resize(data_size
+ luks1_meta_size
));
3353 librbd::encryption_luks1_format_options_t fopts
= {
3354 RBD_ENCRYPTION_ALGORITHM_AES256
, m_parent_passphrase
};
3355 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
3358 ceph::bufferlist bl
;
3359 bl
.append(std::string(data_size
, 'a'));
3360 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3362 // before taking a parent snapshot, (temporarily) add extra space
3363 // to the parent to account for upcoming LUKS2 header in the clone,
3364 // making the clone able to reach all parent data
3365 // space taken by LUKS1 header in the parent would be reused
3366 uint64_t luks2_meta_size
= 16 << 20;
3367 ASSERT_EQ(0, parent
.resize(data_size
+ luks2_meta_size
- luks1_meta_size
));
3371 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3372 librbd::encryption_luks2_format_options_t fopts
=
3373 {RBD_ENCRYPTION_ALGORITHM_AES256
, m_clone_passphrase
};
3374 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
3380 struct UnformattedLUKS2
: LUKSOnePassphrase
{
3381 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3382 uint64_t luks2_meta_size
= 16 << 20;
3383 ASSERT_EQ(0, parent
.resize(data_size
+ luks2_meta_size
));
3384 librbd::encryption_luks2_format_options_t fopts
= {
3385 RBD_ENCRYPTION_ALGORITHM_AES256
, m_passphrase
};
3386 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
3389 ceph::bufferlist bl
;
3390 bl
.append(std::string(data_size
, 'a'));
3391 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3395 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3400 struct LUKS2UnderLUKS2
: LUKSTwoPassphrases
{
3401 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3402 uint64_t luks2_meta_size
= 16 << 20;
3403 ASSERT_EQ(0, parent
.resize(data_size
+ luks2_meta_size
));
3404 librbd::encryption_luks2_format_options_t fopts
= {
3405 RBD_ENCRYPTION_ALGORITHM_AES256
, m_parent_passphrase
};
3406 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
3409 ceph::bufferlist bl
;
3410 bl
.append(std::string(data_size
, 'a'));
3411 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3415 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3416 librbd::encryption_luks2_format_options_t fopts
=
3417 {RBD_ENCRYPTION_ALGORITHM_AES256
, m_clone_passphrase
};
3418 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
3424 struct LUKS2UnderLUKS1
: LUKSTwoPassphrases
{
3425 void setup_parent(librbd::Image
& parent
, uint64_t data_size
, bool* passed
) {
3426 uint64_t luks2_meta_size
= 16 << 20;
3427 ASSERT_EQ(0, parent
.resize(data_size
+ luks2_meta_size
));
3428 librbd::encryption_luks2_format_options_t fopts
= {
3429 RBD_ENCRYPTION_ALGORITHM_AES256
, m_parent_passphrase
};
3430 ASSERT_EQ(0, parent
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2
, &fopts
,
3433 ceph::bufferlist bl
;
3434 bl
.append(std::string(data_size
, 'a'));
3435 ASSERT_EQ(data_size
, parent
.write(0, data_size
, bl
));
3439 void setup_clone(librbd::Image
& clone
, uint64_t data_size
, bool* passed
) {
3440 librbd::encryption_luks1_format_options_t fopts
=
3441 {RBD_ENCRYPTION_ALGORITHM_AES256
, m_clone_passphrase
};
3442 ASSERT_EQ(0, clone
.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1
, &fopts
,
3445 // after loading encryption on the clone, one can get rid of
3446 // unneeded space allowance in the clone arising from LUKS2 header
3447 // in the parent being bigger than LUKS1 header in the clone
3448 ASSERT_EQ(0, load(clone
));
3449 ASSERT_EQ(0, clone
.resize(data_size
));
3454 template <typename FormatPolicy
>
3455 class EncryptedFlattenTest
: public TestLibRBD
, FormatPolicy
{
3457 void create_and_setup(bool* passed
) {
3458 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), m_ioctx
));
3461 ASSERT_EQ(0, create_image_pp(m_rbd
, m_ioctx
, m_parent_name
.c_str(),
3462 m_data_size
, &order
));
3463 librbd::Image parent
;
3464 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, parent
, m_parent_name
.c_str(), nullptr));
3465 ASSERT_PASSED(FormatPolicy::setup_parent
, parent
, m_data_size
);
3467 ASSERT_EQ(0, parent
.snap_create("snap"));
3468 ASSERT_EQ(0, parent
.snap_protect("snap"));
3470 ASSERT_EQ(0, parent
.features(&features
));
3471 ASSERT_EQ(0, m_rbd
.clone(m_ioctx
, m_parent_name
.c_str(), "snap", m_ioctx
,
3472 m_clone_name
.c_str(), features
, &order
));
3473 librbd::Image clone
;
3474 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, clone
, m_clone_name
.c_str(), nullptr));
3475 ASSERT_PASSED(FormatPolicy::setup_clone
, clone
, m_data_size
);
3480 void open_and_load(librbd::Image
& clone
, bool* passed
) {
3481 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, clone
, m_clone_name
.c_str(), nullptr));
3482 ASSERT_EQ(0, FormatPolicy::load(clone
));
3486 void open_and_load_flattened(librbd::Image
& clone
, bool* passed
) {
3487 ASSERT_EQ(0, m_rbd
.open(m_ioctx
, clone
, m_clone_name
.c_str(), nullptr));
3488 ASSERT_EQ(0, FormatPolicy::load_flattened(clone
));
3492 void verify_size_and_overlap(librbd::Image
& image
, uint64_t expected_size
,
3493 uint64_t expected_overlap
) {
3495 ASSERT_EQ(0, image
.size(&size
));
3496 EXPECT_EQ(expected_size
, size
);
3498 ASSERT_EQ(0, image
.overlap(&overlap
));
3499 EXPECT_EQ(expected_overlap
, overlap
);
3502 void verify_data(librbd::Image
& image
, const ceph::bufferlist
& expected_bl
) {
3503 ceph::bufferlist read_bl
;
3504 ASSERT_EQ(expected_bl
.length(),
3505 image
.read(0, expected_bl
.length(), read_bl
));
3506 EXPECT_TRUE(expected_bl
.contents_equal(read_bl
));
3509 librados::IoCtx m_ioctx
;
3511 std::string m_parent_name
= get_temp_image_name();
3512 std::string m_clone_name
= get_temp_image_name();
3513 uint64_t m_data_size
= 25 << 20;
3516 using EncryptedFlattenTestTypes
=
3517 ::testing::Types
<PlaintextUnderLUKS1
, PlaintextUnderLUKS2
,
3518 UnformattedLUKS1
, LUKS1UnderLUKS1
, LUKS1UnderLUKS2
,
3519 UnformattedLUKS2
, LUKS2UnderLUKS2
, LUKS2UnderLUKS1
>;
3520 TYPED_TEST_SUITE(EncryptedFlattenTest
, EncryptedFlattenTestTypes
);
3522 TYPED_TEST(EncryptedFlattenTest
, Simple
)
3524 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3525 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3526 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3528 ASSERT_PASSED0(this->create_and_setup
);
3530 ceph::bufferlist expected_bl
;
3531 expected_bl
.append(std::string(this->m_data_size
, 'a'));
3534 librbd::Image clone
;
3535 ASSERT_PASSED(this->open_and_load
, clone
);
3536 this->verify_size_and_overlap(clone
, this->m_data_size
, this->m_data_size
);
3537 this->verify_data(clone
, expected_bl
);
3538 ASSERT_EQ(0, clone
.flatten());
3539 this->verify_data(clone
, expected_bl
);
3543 librbd::Image clone
;
3544 ASSERT_PASSED(this->open_and_load_flattened
, clone
);
3545 this->verify_size_and_overlap(clone
, this->m_data_size
, 0);
3546 this->verify_data(clone
, expected_bl
);
3550 TYPED_TEST(EncryptedFlattenTest
, Grow
)
3552 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3553 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3554 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3556 ASSERT_PASSED0(this->create_and_setup
);
3558 ceph::bufferlist expected_bl
;
3559 expected_bl
.append(std::string(this->m_data_size
, 'a'));
3560 expected_bl
.append_zero(1);
3563 librbd::Image clone
;
3564 ASSERT_PASSED(this->open_and_load
, clone
);
3565 ASSERT_EQ(0, clone
.resize(this->m_data_size
+ 1));
3566 this->verify_size_and_overlap(clone
, this->m_data_size
+ 1,
3568 this->verify_data(clone
, expected_bl
);
3569 ASSERT_EQ(0, clone
.flatten());
3570 this->verify_data(clone
, expected_bl
);
3574 librbd::Image clone
;
3575 ASSERT_PASSED(this->open_and_load_flattened
, clone
);
3576 this->verify_size_and_overlap(clone
, this->m_data_size
+ 1, 0);
3577 this->verify_data(clone
, expected_bl
);
3581 TYPED_TEST(EncryptedFlattenTest
, Shrink
)
3583 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3584 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3585 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3587 ASSERT_PASSED0(this->create_and_setup
);
3589 ceph::bufferlist expected_bl
;
3590 expected_bl
.append(std::string(this->m_data_size
- 1, 'a'));
3593 librbd::Image clone
;
3594 ASSERT_PASSED(this->open_and_load
, clone
);
3595 ASSERT_EQ(0, clone
.resize(this->m_data_size
- 1));
3596 this->verify_size_and_overlap(clone
, this->m_data_size
- 1,
3597 this->m_data_size
- 1);
3598 this->verify_data(clone
, expected_bl
);
3599 ASSERT_EQ(0, clone
.flatten());
3600 this->verify_data(clone
, expected_bl
);
3604 librbd::Image clone
;
3605 ASSERT_PASSED(this->open_and_load_flattened
, clone
);
3606 this->verify_size_and_overlap(clone
, this->m_data_size
- 1, 0);
3607 this->verify_data(clone
, expected_bl
);
3611 TYPED_TEST(EncryptedFlattenTest
, ShrinkToOne
)
3613 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3614 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3615 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3617 ASSERT_PASSED0(this->create_and_setup
);
3619 ceph::bufferlist expected_bl
;
3620 expected_bl
.append(std::string(1, 'a'));
3623 librbd::Image clone
;
3624 ASSERT_PASSED(this->open_and_load
, clone
);
3625 ASSERT_EQ(0, clone
.resize(1));
3626 this->verify_size_and_overlap(clone
, 1, 1);
3627 this->verify_data(clone
, expected_bl
);
3628 ASSERT_EQ(0, clone
.flatten());
3629 this->verify_data(clone
, expected_bl
);
3633 librbd::Image clone
;
3634 ASSERT_PASSED(this->open_and_load_flattened
, clone
);
3635 this->verify_size_and_overlap(clone
, 1, 0);
3636 this->verify_data(clone
, expected_bl
);
3640 TYPED_TEST(EncryptedFlattenTest
, ShrinkToOneAfterSnapshot
)
3642 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3643 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3644 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3646 ASSERT_PASSED0(this->create_and_setup
);
3648 ceph::bufferlist expected_bl
;
3649 expected_bl
.append(std::string(1, 'a'));
3652 librbd::Image clone
;
3653 ASSERT_PASSED(this->open_and_load
, clone
);
3654 ASSERT_EQ(0, clone
.snap_create("snap"));
3655 ASSERT_EQ(0, clone
.resize(1));
3656 this->verify_size_and_overlap(clone
, 1, 1);
3657 this->verify_data(clone
, expected_bl
);
3658 ASSERT_EQ(0, clone
.flatten());
3659 this->verify_data(clone
, expected_bl
);
3663 librbd::Image clone
;
3664 ASSERT_PASSED(this->open_and_load_flattened
, clone
);
3665 this->verify_size_and_overlap(clone
, 1, 0);
3666 this->verify_data(clone
, expected_bl
);
3670 TYPED_TEST(EncryptedFlattenTest
, MinOverlap
)
3672 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3673 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3674 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3676 ASSERT_PASSED0(this->create_and_setup
);
3678 ceph::bufferlist expected_bl
;
3679 expected_bl
.append(std::string(1, 'a'));
3680 expected_bl
.append_zero(this->m_data_size
- 1);
3683 librbd::Image clone
;
3684 ASSERT_PASSED(this->open_and_load
, clone
);
3685 ASSERT_EQ(0, clone
.resize(1));
3686 ASSERT_EQ(0, clone
.resize(this->m_data_size
));
3687 this->verify_size_and_overlap(clone
, this->m_data_size
, 1);
3688 this->verify_data(clone
, expected_bl
);
3689 ASSERT_EQ(0, clone
.flatten());
3690 this->verify_data(clone
, expected_bl
);
3694 librbd::Image clone
;
3695 ASSERT_PASSED(this->open_and_load_flattened
, clone
);
3696 this->verify_size_and_overlap(clone
, this->m_data_size
, 0);
3697 this->verify_data(clone
, expected_bl
);
3701 TYPED_TEST(EncryptedFlattenTest
, ZeroOverlap
)
3703 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3704 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2
));
3705 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
3707 ASSERT_PASSED0(this->create_and_setup
);
3709 ceph::bufferlist expected_bl
;
3710 expected_bl
.append_zero(this->m_data_size
);
3713 librbd::Image clone
;
3714 ASSERT_PASSED(this->open_and_load
, clone
);
3715 ASSERT_EQ(0, clone
.resize(0));
3716 ASSERT_EQ(0, clone
.resize(this->m_data_size
));
3717 this->verify_size_and_overlap(clone
, this->m_data_size
, 0);
3718 this->verify_data(clone
, expected_bl
);
3719 ASSERT_EQ(0, clone
.flatten());
3720 this->verify_data(clone
, expected_bl
);
3724 librbd::Image clone
;
3725 ASSERT_PASSED(this->open_and_load_flattened
, clone
);
3726 this->verify_size_and_overlap(clone
, this->m_data_size
, 0);
3727 this->verify_data(clone
, expected_bl
);
3733 TEST_F(TestLibRBD
, TestIOWithIOHint
)
3735 rados_ioctx_t ioctx
;
3736 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3740 std::string name
= get_temp_image_name();
3741 uint64_t size
= 2 << 20;
3743 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3744 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3746 bool skip_discard
= is_skip_partial_discard_enabled(image
);
3748 char test_data
[TEST_IO_SIZE
+ 1];
3749 char zero_data
[TEST_IO_SIZE
+ 1];
3750 char mismatch_data
[TEST_IO_SIZE
+ 1];
3752 uint64_t mismatch_offset
;
3754 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3755 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3757 test_data
[TEST_IO_SIZE
] = '\0';
3758 memset(zero_data
, 0, sizeof(zero_data
));
3759 memset(mismatch_data
, 9, sizeof(mismatch_data
));
3761 for (i
= 0; i
< 5; ++i
)
3762 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3763 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3765 for (i
= 5; i
< 10; ++i
)
3766 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3767 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3769 for (i
= 0; i
< 5; ++i
)
3770 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
3771 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3773 for (i
= 5; i
< 10; ++i
)
3774 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
3775 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3777 for (i
= 0; i
< 5; ++i
)
3778 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
,
3779 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
3781 for (i
= 5; i
< 10; ++i
)
3782 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3783 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3785 // discard 2nd, 4th sections.
3786 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
3787 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
3789 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
,
3790 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
3791 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3792 TEST_IO_SIZE
, TEST_IO_SIZE
,
3793 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
3794 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
,
3795 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
3796 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3797 TEST_IO_SIZE
*3, TEST_IO_SIZE
,
3798 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
3799 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
3801 for (i
= 0; i
< 15; ++i
) {
3803 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
3804 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3805 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
3806 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3807 } else if (i
% 3 == 1) {
3808 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
3809 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3810 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
3811 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3813 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
3814 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3815 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
3816 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3819 for (i
= 0; i
< 15; ++i
) {
3821 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
3822 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3823 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
3824 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3825 } else if (i
% 3 == 1) {
3826 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
3827 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3828 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
3829 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3831 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
3832 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3833 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
3834 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3838 rbd_image_info_t info
;
3839 rbd_completion_t comp
;
3840 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
3841 // can't read or write starting past end
3842 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
3843 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
3844 // reading through end returns amount up to end
3845 ASSERT_EQ(10, rbd_read2(image
, info
.size
- 10, 100, test_data
,
3846 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
));
3847 // writing through end returns amount up to end
3848 ASSERT_EQ(10, rbd_write2(image
, info
.size
- 10, 100, test_data
,
3849 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
3851 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
3852 ASSERT_EQ(0, rbd_aio_read2(image
, info
.size
, 1, test_data
, comp
,
3853 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
3854 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
3855 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
3856 rbd_aio_release(comp
);
3858 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3859 mismatch_offset
= 123;
3860 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
3861 &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
3862 ASSERT_EQ(0U, mismatch_offset
);
3863 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
3864 mismatch_offset
= 123;
3865 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
3866 comp
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
3867 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
3868 ASSERT_EQ(-EILSEQ
, rbd_aio_get_return_value(comp
));
3869 ASSERT_EQ(0U, mismatch_offset
);
3870 rbd_aio_release(comp
);
3872 ASSERT_PASSED(validate_object_map
, image
);
3873 ASSERT_EQ(0, rbd_close(image
));
3875 rados_ioctx_destroy(ioctx
);
3878 TEST_F(TestLibRBD
, TestDataPoolIO
)
3880 REQUIRE_FORMAT_V2();
3882 rados_ioctx_t ioctx
;
3883 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3885 std::string data_pool_name
= create_pool(true);
3888 std::string name
= get_temp_image_name();
3889 uint64_t size
= 2 << 20;
3893 ASSERT_EQ(0, get_features(&old_format
, &features
));
3894 ASSERT_FALSE(old_format
);
3896 rbd_image_options_t image_options
;
3897 rbd_image_options_create(&image_options
);
3898 BOOST_SCOPE_EXIT( (&image_options
) ) {
3899 rbd_image_options_destroy(image_options
);
3900 } BOOST_SCOPE_EXIT_END
;
3902 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
3903 RBD_IMAGE_OPTION_FEATURES
,
3905 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
3906 RBD_IMAGE_OPTION_DATA_POOL
,
3907 data_pool_name
.c_str()));
3909 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
3910 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3911 ASSERT_NE(-1, rbd_get_data_pool_id(image
));
3913 bool skip_discard
= is_skip_partial_discard_enabled(image
);
3915 char test_data
[TEST_IO_SIZE
+ 1];
3916 char zero_data
[TEST_IO_SIZE
+ 1];
3919 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3920 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3922 test_data
[TEST_IO_SIZE
] = '\0';
3923 memset(zero_data
, 0, sizeof(zero_data
));
3925 for (i
= 0; i
< 5; ++i
)
3926 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
3928 for (i
= 5; i
< 10; ++i
)
3929 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
3931 for (i
= 0; i
< 5; ++i
)
3932 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
3934 for (i
= 5; i
< 10; ++i
)
3935 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
3937 // discard 2nd, 4th sections.
3938 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
3939 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
3941 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
3942 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3943 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
3944 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
3945 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3946 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
3947 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
3949 rbd_image_info_t info
;
3950 rbd_completion_t comp
;
3951 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
3952 // can't read or write starting past end
3953 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
3954 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
3955 // reading through end returns amount up to end
3956 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
3957 // writing through end returns amount up to end
3958 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
3960 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
3961 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
3962 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
3963 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
3964 rbd_aio_release(comp
);
3966 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
3967 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
3968 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
3969 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
3970 rbd_aio_release(comp
);
3972 ASSERT_PASSED(validate_object_map
, image
);
3973 ASSERT_EQ(0, rbd_close(image
));
3975 rados_ioctx_destroy(ioctx
);
3978 TEST_F(TestLibRBD
, TestCompareAndWriteMismatch
)
3980 rados_ioctx_t ioctx
;
3981 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3985 std::string name
= get_temp_image_name();
3986 uint64_t size
= 20 << 20; /* 20MiB */
3989 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
3990 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3992 // We only support to compare and write the same amount of (len) bytes
3993 std::string
cmp_buffer("This is a test");
3994 std::string
write_buffer("Write this !!!");
3995 std::string
mismatch_buffer("This will fail");
3996 std::string
read_buffer(cmp_buffer
.length(), '1');
3998 ssize_t written
= rbd_write(image
, off
, cmp_buffer
.length(),
4000 ASSERT_EQ(cmp_buffer
.length(), written
);
4002 // Compare should fail because of mismatch
4003 uint64_t mismatch_off
= 0;
4004 written
= rbd_compare_and_write(image
, off
, write_buffer
.length(),
4005 mismatch_buffer
.data(), write_buffer
.data(),
4007 ASSERT_EQ(-EILSEQ
, written
);
4008 ASSERT_EQ(5U, mismatch_off
);
4010 // check nothing was written
4011 ssize_t read
= rbd_read(image
, off
, read_buffer
.length(), read_buffer
.data());
4012 ASSERT_EQ(read_buffer
.length(), read
);
4013 ASSERT_EQ(cmp_buffer
, read_buffer
);
4015 ASSERT_PASSED(validate_object_map
, image
);
4016 ASSERT_EQ(0, rbd_close(image
));
4018 rados_ioctx_destroy(ioctx
);
4021 TEST_F(TestLibRBD
, TestAioCompareAndWriteMismatch
)
4023 rados_ioctx_t ioctx
;
4024 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4028 std::string name
= get_temp_image_name();
4029 uint64_t size
= 20 << 20; /* 20MiB */
4032 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4033 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4035 // We only support to compare and write the same amount of (len) bytes
4036 std::string
cmp_buffer("This is a test");
4037 std::string
write_buffer("Write this !!!");
4038 std::string
mismatch_buffer("This will fail");
4039 std::string
read_buffer(cmp_buffer
.length(), '1');
4041 ssize_t written
= rbd_write(image
, off
, cmp_buffer
.length(),
4043 ASSERT_EQ(cmp_buffer
.length(), written
);
4045 // Compare should fail because of mismatch
4046 rbd_completion_t comp
;
4047 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4048 uint64_t mismatch_off
= 0;
4049 int ret
= rbd_aio_compare_and_write(image
, off
, write_buffer
.length(),
4050 mismatch_buffer
.data(),
4051 write_buffer
.data(), comp
,
4054 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4055 ASSERT_EQ(-EILSEQ
, rbd_aio_get_return_value(comp
));
4056 ASSERT_EQ(5U, mismatch_off
);
4057 rbd_aio_release(comp
);
4059 // check nothing was written
4060 ssize_t read
= rbd_read(image
, off
, read_buffer
.length(), read_buffer
.data());
4061 ASSERT_EQ(read_buffer
.length(), read
);
4062 ASSERT_EQ(cmp_buffer
, read_buffer
);
4064 ASSERT_PASSED(validate_object_map
, image
);
4065 ASSERT_EQ(0, rbd_close(image
));
4067 rados_ioctx_destroy(ioctx
);
4070 TEST_F(TestLibRBD
, TestCompareAndWriteSuccess
)
4072 rados_ioctx_t ioctx
;
4073 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4077 std::string name
= get_temp_image_name();
4078 uint64_t size
= 20 << 20; /* 20MiB */
4081 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4082 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4084 // We only support to compare and write the same amount of (len) bytes
4085 std::string
cmp_buffer("This is a test");
4086 std::string
write_buffer("Write this !!!");
4087 std::string
read_buffer(cmp_buffer
.length(), '1');
4089 ssize_t written
= rbd_write(image
, off
, cmp_buffer
.length(),
4091 ASSERT_EQ(cmp_buffer
.length(), written
);
4094 * we compare against the written buffer (cmp_buffer) and write the buffer
4095 * We expect: len bytes written
4097 uint64_t mismatch_off
= 0;
4098 written
= rbd_compare_and_write(image
, off
, write_buffer
.length(),
4099 cmp_buffer
.data(), write_buffer
.data(),
4101 ASSERT_EQ(write_buffer
.length(), written
);
4102 ASSERT_EQ(0U, mismatch_off
);
4104 ssize_t read
= rbd_read(image
, off
, read_buffer
.length(), read_buffer
.data());
4105 ASSERT_EQ(read_buffer
.length(), read
);
4106 ASSERT_EQ(write_buffer
, read_buffer
);
4108 ASSERT_PASSED(validate_object_map
, image
);
4109 ASSERT_EQ(0, rbd_close(image
));
4111 rados_ioctx_destroy(ioctx
);
4114 TEST_F(TestLibRBD
, TestAioCompareAndWriteSuccess
)
4116 rados_ioctx_t ioctx
;
4117 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4121 std::string name
= get_temp_image_name();
4122 uint64_t size
= 20 << 20; /* 20MiB */
4125 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4126 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4128 // We only support to compare and write the same amount of (len) bytes
4129 std::string
cmp_buffer("This is a test");
4130 std::string
write_buffer("Write this !!!");
4131 std::string
read_buffer(cmp_buffer
.length(), '1');
4133 ssize_t written
= rbd_write(image
, off
, cmp_buffer
.length(),
4135 ASSERT_EQ(cmp_buffer
.length(), written
);
4138 * we compare against the written buffer (cmp_buffer) and write the buffer
4139 * We expect: len bytes written
4141 rbd_completion_t comp
;
4142 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4143 uint64_t mismatch_off
= 0;
4144 int ret
= rbd_aio_compare_and_write(image
, off
, write_buffer
.length(),
4145 cmp_buffer
.data(), write_buffer
.data(),
4146 comp
, &mismatch_off
, 0);
4148 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4149 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
4150 ASSERT_EQ(0U, mismatch_off
);
4151 rbd_aio_release(comp
);
4153 ssize_t read
= rbd_read(image
, off
, read_buffer
.length(), read_buffer
.data());
4154 ASSERT_EQ(read_buffer
.length(), read
);
4155 ASSERT_EQ(write_buffer
, read_buffer
);
4157 ASSERT_PASSED(validate_object_map
, image
);
4158 ASSERT_EQ(0, rbd_close(image
));
4160 rados_ioctx_destroy(ioctx
);
4164 TEST_F(TestLibRBD
, TestCompareAndWriteStripeUnitUnaligned
)
4166 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
4168 rados_ioctx_t ioctx
;
4169 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4173 std::string name
= get_temp_image_name();
4174 uint64_t size
= 20 << 20; /* 20MiB */
4176 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4177 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4179 // large write test => we allow stripe unit size writes (aligned)
4180 uint64_t stripe_unit
;
4181 rbd_get_stripe_unit(image
, &stripe_unit
);
4182 std::string
large_write_buffer(stripe_unit
, '2');
4183 std::string
large_cmp_buffer(stripe_unit
* 2, '4');
4185 ssize_t written
= rbd_write(image
, stripe_unit
, large_cmp_buffer
.length(),
4186 large_cmp_buffer
.data());
4187 ASSERT_EQ(large_cmp_buffer
.length(), written
);
4190 * compare and write at offset stripe_unit + 1 and stripe unit size
4191 * Expect fail because access exceeds stripe (unaligned)
4193 uint64_t mismatch_off
= 0;
4194 written
= rbd_compare_and_write(image
, stripe_unit
+ 1, stripe_unit
,
4195 large_cmp_buffer
.data(),
4196 large_write_buffer
.data(),
4198 ASSERT_EQ(-EINVAL
, written
);
4199 ASSERT_EQ(0U, mismatch_off
);
4201 // check nothing has been written
4202 std::string
large_read_buffer(large_cmp_buffer
.length(), '5');
4203 ssize_t read
= rbd_read(image
, stripe_unit
, large_read_buffer
.length(),
4204 large_read_buffer
.data());
4205 ASSERT_EQ(large_read_buffer
.length(), read
);
4206 auto buffer_mismatch
= std::mismatch(large_cmp_buffer
.begin(),
4207 large_cmp_buffer
.end(),
4208 large_read_buffer
.begin());
4209 ASSERT_EQ(large_read_buffer
.end(), buffer_mismatch
.second
);
4211 ASSERT_PASSED(validate_object_map
, image
);
4212 ASSERT_EQ(0, rbd_close(image
));
4214 rados_ioctx_destroy(ioctx
);
4217 TEST_F(TestLibRBD
, TestAioCompareAndWriteStripeUnitUnaligned
)
4219 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
4221 rados_ioctx_t ioctx
;
4222 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4226 std::string name
= get_temp_image_name();
4227 uint64_t size
= 20 << 20; /* 20MiB */
4229 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4230 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4232 // large write test => we allow stripe unit size writes (aligned)
4233 uint64_t stripe_unit
;
4234 rbd_get_stripe_unit(image
, &stripe_unit
);
4235 std::string
large_write_buffer(stripe_unit
, '2');
4236 std::string
large_cmp_buffer(stripe_unit
* 2, '4');
4238 ssize_t written
= rbd_write(image
, stripe_unit
, large_cmp_buffer
.length(),
4239 large_cmp_buffer
.data());
4240 ASSERT_EQ(large_cmp_buffer
.length(), written
);
4243 * compare and write at offset stripe_unit + 1 and stripe unit size
4244 * Expect fail because access spans stripe unit boundary (unaligned)
4246 rbd_completion_t comp
;
4247 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4248 uint64_t mismatch_off
= 0;
4249 int ret
= rbd_aio_compare_and_write(image
, stripe_unit
+ 1, stripe_unit
,
4250 large_cmp_buffer
.data(),
4251 large_write_buffer
.data(),
4252 comp
, &mismatch_off
, 0);
4254 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4255 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
4256 ASSERT_EQ(0U, mismatch_off
);
4257 rbd_aio_release(comp
);
4259 // check nothing has been written
4260 std::string
large_read_buffer(large_cmp_buffer
.length(), '5');
4261 ssize_t read
= rbd_read(image
, stripe_unit
, large_read_buffer
.length(),
4262 large_read_buffer
.data());
4263 ASSERT_EQ(large_read_buffer
.length(), read
);
4264 auto buffer_mismatch
= std::mismatch(large_cmp_buffer
.begin(),
4265 large_cmp_buffer
.end(),
4266 large_read_buffer
.begin());
4267 ASSERT_EQ(large_read_buffer
.end(), buffer_mismatch
.second
);
4269 ASSERT_PASSED(validate_object_map
, image
);
4270 ASSERT_EQ(0, rbd_close(image
));
4272 rados_ioctx_destroy(ioctx
);
4275 TEST_F(TestLibRBD
, TestCompareAndWriteTooLarge
)
4277 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
4279 rados_ioctx_t ioctx
;
4280 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4284 std::string name
= get_temp_image_name();
4285 uint64_t size
= 20 << 20; /* 20MiB */
4287 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4288 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4290 // large write test => we allow stripe unit size writes (aligned)
4291 uint64_t stripe_unit
;
4292 rbd_get_stripe_unit(image
, &stripe_unit
);
4293 std::string
large_write_buffer(stripe_unit
* 2, '2');
4294 std::string
large_cmp_buffer(large_write_buffer
.length(), '4');
4296 ssize_t written
= rbd_write(image
, stripe_unit
, large_cmp_buffer
.length(),
4297 large_cmp_buffer
.data());
4298 ASSERT_EQ(large_cmp_buffer
.length(), written
);
4301 * compare and write at offset stripe_unit and stripe unit size + 1
4302 * Expect fail because access is larger than stripe unit size
4304 uint64_t mismatch_off
= 0;
4305 written
= rbd_compare_and_write(image
, stripe_unit
, stripe_unit
+ 1,
4306 large_cmp_buffer
.data(),
4307 large_write_buffer
.data(),
4309 ASSERT_EQ(-EINVAL
, written
);
4310 ASSERT_EQ(0U, mismatch_off
);
4312 // check nothing has been written
4313 std::string
large_read_buffer(large_cmp_buffer
.length(), '5');
4314 ssize_t read
= rbd_read(image
, stripe_unit
, large_read_buffer
.length(),
4315 large_read_buffer
.data());
4316 ASSERT_EQ(large_read_buffer
.length(), read
);
4317 auto buffer_mismatch
= std::mismatch(large_cmp_buffer
.begin(),
4318 large_cmp_buffer
.end(),
4319 large_read_buffer
.begin());
4320 ASSERT_EQ(large_read_buffer
.end(), buffer_mismatch
.second
);
4322 ASSERT_PASSED(validate_object_map
, image
);
4323 ASSERT_EQ(0, rbd_close(image
));
4325 rados_ioctx_destroy(ioctx
);
4328 TEST_F(TestLibRBD
, TestAioCompareAndWriteTooLarge
)
4330 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
4332 rados_ioctx_t ioctx
;
4333 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4337 std::string name
= get_temp_image_name();
4338 uint64_t size
= 20 << 20; /* 20MiB */
4340 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4341 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4343 // large write test => we allow stripe unit size writes (aligned)
4344 uint64_t stripe_unit
;
4345 rbd_get_stripe_unit(image
, &stripe_unit
);
4346 std::string
large_write_buffer(stripe_unit
* 2, '2');
4347 std::string
large_cmp_buffer(large_write_buffer
.length(), '4');
4349 ssize_t written
= rbd_write(image
, stripe_unit
, large_cmp_buffer
.length(),
4350 large_cmp_buffer
.data());
4351 ASSERT_EQ(large_cmp_buffer
.length(), written
);
4354 * compare and write at offset stripe_unit and stripe unit size + 1
4355 * Expect fail because access is larger than stripe unit size
4357 rbd_completion_t comp
;
4358 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4359 uint64_t mismatch_off
= 0;
4360 int ret
= rbd_aio_compare_and_write(image
, stripe_unit
, stripe_unit
+ 1,
4361 large_cmp_buffer
.data(),
4362 large_write_buffer
.data(),
4363 comp
, &mismatch_off
, 0);
4365 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4366 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
4367 ASSERT_EQ(0U, mismatch_off
);
4368 rbd_aio_release(comp
);
4370 // check nothing has been written
4371 std::string
large_read_buffer(large_cmp_buffer
.length(), '5');
4372 ssize_t read
= rbd_read(image
, stripe_unit
, large_read_buffer
.length(),
4373 large_read_buffer
.data());
4374 ASSERT_EQ(large_read_buffer
.length(), read
);
4375 auto buffer_mismatch
= std::mismatch(large_cmp_buffer
.begin(),
4376 large_cmp_buffer
.end(),
4377 large_read_buffer
.begin());
4378 ASSERT_EQ(large_read_buffer
.end(), buffer_mismatch
.second
);
4380 ASSERT_PASSED(validate_object_map
, image
);
4381 ASSERT_EQ(0, rbd_close(image
));
4383 rados_ioctx_destroy(ioctx
);
4386 TEST_F(TestLibRBD
, TestCompareAndWriteStripeUnitSuccess
)
4388 rados_ioctx_t ioctx
;
4389 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4393 std::string name
= get_temp_image_name();
4394 uint64_t size
= 20 << 20; /* 20MiB */
4396 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4397 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4399 // large write test => we allow stripe unit size writes (aligned)
4400 uint64_t stripe_unit
;
4401 rbd_get_stripe_unit(image
, &stripe_unit
);
4402 std::string
large_write_buffer(stripe_unit
, '2');
4403 std::string
large_cmp_buffer(stripe_unit
* 2, '4');
4405 ssize_t written
= rbd_write(image
, stripe_unit
, large_cmp_buffer
.length(),
4406 large_cmp_buffer
.data());
4407 ASSERT_EQ(large_cmp_buffer
.length(), written
);
4409 // aligned stripe unit size access => expect success
4410 uint64_t mismatch_off
= 0;
4411 written
= rbd_compare_and_write(image
, stripe_unit
, stripe_unit
,
4412 large_cmp_buffer
.data(),
4413 large_write_buffer
.data(),
4415 ASSERT_EQ(stripe_unit
, written
);
4416 ASSERT_EQ(0U, mismatch_off
);
4418 // check stripe_unit bytes of large_write_buffer were written
4419 std::string
large_read_buffer(large_cmp_buffer
.length(), '5');
4420 ssize_t read
= rbd_read(image
, stripe_unit
, large_read_buffer
.length(),
4421 large_read_buffer
.data());
4422 ASSERT_EQ(large_read_buffer
.length(), read
);
4423 auto buffer_mismatch
= std::mismatch(large_read_buffer
.begin(),
4424 large_read_buffer
.begin() + stripe_unit
,
4425 large_write_buffer
.begin());
4426 ASSERT_EQ(large_write_buffer
.end(), buffer_mismatch
.second
);
4427 // check data beyond stripe_unit size was not overwritten
4428 buffer_mismatch
= std::mismatch(large_read_buffer
.begin() + stripe_unit
,
4429 large_read_buffer
.end(),
4430 large_cmp_buffer
.begin());
4431 ASSERT_EQ(large_cmp_buffer
.begin() + stripe_unit
, buffer_mismatch
.second
);
4433 ASSERT_PASSED(validate_object_map
, image
);
4434 ASSERT_EQ(0, rbd_close(image
));
4436 rados_ioctx_destroy(ioctx
);
4439 TEST_F(TestLibRBD
, TestAioCompareAndWriteStripeUnitSuccess
)
4441 rados_ioctx_t ioctx
;
4442 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4446 std::string name
= get_temp_image_name();
4447 uint64_t size
= 20 << 20; /* 20MiB */
4449 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4450 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4452 // large write test => we allow stripe unit size writes (aligned)
4453 uint64_t stripe_unit
;
4454 rbd_get_stripe_unit(image
, &stripe_unit
);
4455 std::string
large_write_buffer(stripe_unit
, '2');
4456 std::string
large_cmp_buffer(stripe_unit
* 2, '4');
4458 ssize_t written
= rbd_write(image
, stripe_unit
, large_cmp_buffer
.length(),
4459 large_cmp_buffer
.data());
4460 ASSERT_EQ(large_cmp_buffer
.length(), written
);
4462 // aligned stripe unit size access => expect success
4463 rbd_completion_t comp
;
4464 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4465 uint64_t mismatch_off
= 0;
4466 int ret
= rbd_aio_compare_and_write(image
, stripe_unit
, stripe_unit
,
4467 large_cmp_buffer
.data(),
4468 large_write_buffer
.data(),
4469 comp
, &mismatch_off
, 0);
4471 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4472 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
4473 ASSERT_EQ(0U, mismatch_off
);
4474 rbd_aio_release(comp
);
4476 // check stripe_unit bytes of large_write_buffer were written
4477 std::string
large_read_buffer(large_cmp_buffer
.length(), '5');
4478 ssize_t read
= rbd_read(image
, stripe_unit
, large_read_buffer
.length(),
4479 large_read_buffer
.data());
4480 ASSERT_EQ(large_read_buffer
.length(), read
);
4481 auto buffer_mismatch
= std::mismatch(large_read_buffer
.begin(),
4482 large_read_buffer
.begin() + stripe_unit
,
4483 large_write_buffer
.begin());
4484 ASSERT_EQ(large_write_buffer
.end(), buffer_mismatch
.second
);
4485 // check data beyond stripe_unit size was not overwritten
4486 buffer_mismatch
= std::mismatch(large_read_buffer
.begin() + stripe_unit
,
4487 large_read_buffer
.end(),
4488 large_cmp_buffer
.begin());
4489 ASSERT_EQ(large_cmp_buffer
.begin() + stripe_unit
, buffer_mismatch
.second
);
4491 ASSERT_PASSED(validate_object_map
, image
);
4492 ASSERT_EQ(0, rbd_close(image
));
4494 rados_ioctx_destroy(ioctx
);
4497 TEST_F(TestLibRBD
, TestAioCompareAndWriteVIovecLenDiffers
)
4499 rados_ioctx_t ioctx
;
4500 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4504 std::string name
= get_temp_image_name();
4505 uint64_t size
= 20 << 20; /* 20MiB */
4508 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4509 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4511 std::string
cmp_buffer("This is a test");
4512 size_t cmp_len
= cmp_buffer
.length();
4514 std::string
write_buffer("Write this !!!");
4515 struct iovec write_iovs
[] = {
4516 {.iov_base
= &write_buffer
[0], .iov_len
= 6},
4517 {.iov_base
= &write_buffer
[6], .iov_len
= 5},
4518 {.iov_base
= &write_buffer
[11], .iov_len
= 3}
4521 ASSERT_EQ(cmp_len
, rbd_write(image
, off
, cmp_len
, cmp_buffer
.data()));
4523 // should fail because compare iovec len cannot be different to write iovec len
4524 rbd_completion_t comp
;
4525 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4526 uint64_t mismatch_off
= 0;
4527 int ret
= rbd_aio_compare_and_writev(image
, off
,
4528 write_iovs
/* cmp_iovs */, 1,
4529 write_iovs
, std::size(write_iovs
),
4530 comp
, &mismatch_off
, 0);
4531 ASSERT_EQ(-EINVAL
, ret
);
4532 ASSERT_EQ(0U, mismatch_off
);
4533 rbd_aio_release(comp
);
4535 // check nothing was written
4536 std::string
read_buffer(cmp_buffer
.length(), '1');
4537 ssize_t read
= rbd_read(image
, off
, read_buffer
.length(), read_buffer
.data());
4538 ASSERT_EQ(read_buffer
.length(), read
);
4539 ASSERT_EQ(cmp_buffer
, read_buffer
);
4541 ASSERT_PASSED(validate_object_map
, image
);
4542 ASSERT_EQ(0, rbd_close(image
));
4544 rados_ioctx_destroy(ioctx
);
4547 TEST_F(TestLibRBD
, TestAioCompareAndWriteVMismatch
)
4549 rados_ioctx_t ioctx
;
4550 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4554 std::string name
= get_temp_image_name();
4555 uint64_t size
= 20 << 20; /* 20MiB */
4558 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4559 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4561 std::string
cmp_buffer("This is a test");
4562 int cmp_len
= cmp_buffer
.length();
4564 std::string
write_buffer("Write this !!!");
4565 struct iovec write_iovs
[] = {
4566 {.iov_base
= &write_buffer
[0], .iov_len
= 6},
4567 {.iov_base
= &write_buffer
[6], .iov_len
= 5},
4568 {.iov_base
= &write_buffer
[11], .iov_len
= 3}
4571 std::string
mismatch_buffer("This will fail");
4572 struct iovec mismatch_iovs
[] = {
4573 {.iov_base
= &mismatch_buffer
[0], .iov_len
= 5},
4574 {.iov_base
= &mismatch_buffer
[5], .iov_len
= 5},
4575 {.iov_base
= &mismatch_buffer
[10], .iov_len
= 4}
4578 ASSERT_EQ(cmp_len
, rbd_write(image
, off
, cmp_len
, cmp_buffer
.data()));
4580 // this should execute the compare but fail because of mismatch
4581 rbd_completion_t comp
;
4582 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4583 uint64_t mismatch_off
= 0;
4584 int ret
= rbd_aio_compare_and_writev(image
, off
,
4585 mismatch_iovs
/* cmp_iovs */,
4586 std::size(mismatch_iovs
),
4587 write_iovs
, std::size(write_iovs
),
4588 comp
, &mismatch_off
, 0);
4590 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4591 ASSERT_EQ(-EILSEQ
, rbd_aio_get_return_value(comp
));
4592 ASSERT_EQ(5U, mismatch_off
);
4593 rbd_aio_release(comp
);
4595 // check nothing was written
4596 std::string
read_buffer(cmp_buffer
.length(), '1');
4597 ssize_t read
= rbd_read(image
, off
, read_buffer
.length(), read_buffer
.data());
4598 ASSERT_EQ(read_buffer
.length(), read
);
4599 ASSERT_EQ(cmp_buffer
, read_buffer
);
4601 ASSERT_PASSED(validate_object_map
, image
);
4602 ASSERT_EQ(0, rbd_close(image
));
4604 rados_ioctx_destroy(ioctx
);
4607 TEST_F(TestLibRBD
, TestAioCompareAndWriteVSuccess
)
4609 rados_ioctx_t ioctx
;
4610 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4614 std::string name
= get_temp_image_name();
4615 uint64_t size
= 20 << 20; /* 20MiB */
4618 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4619 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4621 std::string
cmp_buffer("This is a test");
4622 struct iovec cmp_iovs
[] = {
4623 {.iov_base
= &cmp_buffer
[0], .iov_len
= 5},
4624 {.iov_base
= &cmp_buffer
[5], .iov_len
= 3},
4625 {.iov_base
= &cmp_buffer
[8], .iov_len
= 2},
4626 {.iov_base
= &cmp_buffer
[10], .iov_len
= 4}
4628 size_t cmp_len
= cmp_buffer
.length();
4630 std::string
write_buffer("Write this !!!");
4631 struct iovec write_iovs
[] = {
4632 {.iov_base
= &write_buffer
[0], .iov_len
= 6},
4633 {.iov_base
= &write_buffer
[6], .iov_len
= 5},
4634 {.iov_base
= &write_buffer
[11], .iov_len
= 3}
4637 ASSERT_EQ(cmp_len
, rbd_write(image
, off
, cmp_len
, cmp_buffer
.data()));
4639 // compare against the buffer written before => should succeed
4640 rbd_completion_t comp
;
4641 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4642 uint64_t mismatch_off
= 0;
4643 int ret
= rbd_aio_compare_and_writev(image
, off
,
4644 cmp_iovs
, std::size(cmp_iovs
),
4645 write_iovs
, std::size(write_iovs
),
4646 comp
, &mismatch_off
, 0);
4648 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4649 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
4650 ASSERT_EQ(0U, mismatch_off
);
4651 rbd_aio_release(comp
);
4653 // check data was successfully written
4654 std::string
read_buffer(cmp_buffer
.length(), '1');
4655 ssize_t read
= rbd_read(image
, off
, read_buffer
.length(), read_buffer
.data());
4656 ASSERT_EQ(read_buffer
.length(), read
);
4657 ASSERT_EQ(write_buffer
, read_buffer
);
4659 ASSERT_PASSED(validate_object_map
, image
);
4660 ASSERT_EQ(0, rbd_close(image
));
4662 rados_ioctx_destroy(ioctx
);
4665 TEST_F(TestLibRBD
, TestScatterGatherIO
)
4667 rados_ioctx_t ioctx
;
4668 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4672 std::string name
= get_temp_image_name();
4673 uint64_t size
= 20 << 20;
4675 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4676 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4678 std::string
write_buffer("This is a test");
4679 // These iovecs should produce a length overflow
4680 struct iovec bad_iovs
[] = {
4681 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
4682 {.iov_base
= NULL
, .iov_len
= std::numeric_limits
<size_t>::max()}
4684 struct iovec write_iovs
[] = {
4685 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
4686 {.iov_base
= &write_buffer
[5], .iov_len
= 3},
4687 {.iov_base
= &write_buffer
[8], .iov_len
= 2},
4688 {.iov_base
= &write_buffer
[10], .iov_len
= 4}
4691 rbd_completion_t comp
;
4692 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4693 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, write_iovs
, 0, 0, comp
));
4694 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, bad_iovs
, 2, 0, comp
));
4695 ASSERT_EQ(0, rbd_aio_writev(image
, write_iovs
,
4696 sizeof(write_iovs
) / sizeof(struct iovec
),
4698 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4699 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
4700 rbd_aio_release(comp
);
4702 std::string
read_buffer(write_buffer
.size(), '1');
4703 struct iovec read_iovs
[] = {
4704 {.iov_base
= &read_buffer
[0], .iov_len
= 4},
4705 {.iov_base
= &read_buffer
[8], .iov_len
= 4},
4706 {.iov_base
= &read_buffer
[12], .iov_len
= 2}
4709 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4710 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, read_iovs
, 0, 0, comp
));
4711 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, bad_iovs
, 2, 0, comp
));
4712 ASSERT_EQ(0, rbd_aio_readv(image
, read_iovs
,
4713 sizeof(read_iovs
) / sizeof(struct iovec
),
4715 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4716 ASSERT_EQ(10, rbd_aio_get_return_value(comp
));
4717 rbd_aio_release(comp
);
4718 ASSERT_EQ("This1111 is a ", read_buffer
);
4720 std::string
linear_buffer(write_buffer
.size(), '1');
4721 struct iovec linear_iovs
[] = {
4722 {.iov_base
= &linear_buffer
[4], .iov_len
= 4}
4724 rbd_aio_create_completion(NULL
, NULL
, &comp
);
4725 ASSERT_EQ(0, rbd_aio_readv(image
, linear_iovs
,
4726 sizeof(linear_iovs
) / sizeof(struct iovec
),
4728 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
4729 ASSERT_EQ(4, rbd_aio_get_return_value(comp
));
4730 rbd_aio_release(comp
);
4731 ASSERT_EQ("1111This111111", linear_buffer
);
4733 ASSERT_PASSED(validate_object_map
, image
);
4734 ASSERT_EQ(0, rbd_close(image
));
4736 rados_ioctx_destroy(ioctx
);
4739 TEST_F(TestLibRBD
, TestEmptyDiscard
)
4741 rados_ioctx_t ioctx
;
4742 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4746 std::string name
= get_temp_image_name();
4747 uint64_t size
= 20 << 20;
4749 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4750 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4752 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 1*1024*1024);
4753 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 4*1024*1024);
4754 ASSERT_PASSED(aio_discard_test_data
, image
, 3*1024*1024, 1*1024*1024);
4756 ASSERT_PASSED(validate_object_map
, image
);
4757 ASSERT_EQ(0, rbd_close(image
));
4759 rados_ioctx_destroy(ioctx
);
4762 TEST_F(TestLibRBD
, TestFUA
)
4764 rados_ioctx_t ioctx
;
4765 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4767 rbd_image_t image_write
;
4768 rbd_image_t image_read
;
4770 std::string name
= get_temp_image_name();
4771 uint64_t size
= 2 << 20;
4773 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4774 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_write
, NULL
));
4775 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_read
, NULL
));
4777 // enable writeback cache
4778 rbd_flush(image_write
);
4780 char test_data
[TEST_IO_SIZE
+ 1];
4783 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4784 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4786 test_data
[TEST_IO_SIZE
] = '\0';
4787 for (i
= 0; i
< 5; ++i
)
4788 ASSERT_PASSED(write_test_data
, image_write
, test_data
,
4789 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
4791 for (i
= 0; i
< 5; ++i
)
4792 ASSERT_PASSED(read_test_data
, image_read
, test_data
,
4793 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
4795 for (i
= 5; i
< 10; ++i
)
4796 ASSERT_PASSED(aio_write_test_data
, image_write
, test_data
,
4797 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
4799 for (i
= 5; i
< 10; ++i
)
4800 ASSERT_PASSED(aio_read_test_data
, image_read
, test_data
,
4801 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
4803 ASSERT_PASSED(validate_object_map
, image_write
);
4804 ASSERT_PASSED(validate_object_map
, image_read
);
4805 ASSERT_EQ(0, rbd_close(image_write
));
4806 ASSERT_EQ(0, rbd_close(image_read
));
4807 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
4808 rados_ioctx_destroy(ioctx
);
4811 void simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
4813 cout
<< "write completion cb called!" << std::endl
;
4816 void simple_read_cb_pp(librbd::completion_t cb
, void *arg
)
4818 cout
<< "read completion cb called!" << std::endl
;
4821 void aio_write_test_data(librbd::Image
& image
, const char *test_data
,
4822 off_t off
, uint32_t iohint
, bool *passed
)
4824 ceph::bufferlist bl
;
4825 bl
.append(test_data
, strlen(test_data
));
4826 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
4827 printf("created completion\n");
4829 image
.aio_write2(off
, strlen(test_data
), bl
, comp
, iohint
);
4831 image
.aio_write(off
, strlen(test_data
), bl
, comp
);
4832 printf("started write\n");
4833 comp
->wait_for_complete();
4834 int r
= comp
->get_return_value();
4835 printf("return value is: %d\n", r
);
4837 printf("finished write\n");
4842 void aio_discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
4844 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
4845 image
.aio_discard(off
, len
, comp
);
4846 comp
->wait_for_complete();
4847 int r
= comp
->get_return_value();
4853 void write_test_data(librbd::Image
& image
, const char *test_data
, off_t off
, uint32_t iohint
, bool *passed
)
4856 size_t len
= strlen(test_data
);
4857 ceph::bufferlist bl
;
4858 bl
.append(test_data
, len
);
4860 written
= image
.write2(off
, len
, bl
, iohint
);
4862 written
= image
.write(off
, len
, bl
);
4863 printf("wrote: %u\n", (unsigned int) written
);
4864 ASSERT_EQ(bl
.length(), written
);
4868 void discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
4871 written
= image
.discard(off
, len
);
4872 printf("discard: %u~%u\n", (unsigned)off
, (unsigned)len
);
4873 ASSERT_EQ(len
, written
);
4877 void aio_read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
4879 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_read_cb_pp
);
4880 ceph::bufferlist bl
;
4881 printf("created completion\n");
4883 image
.aio_read2(off
, expected_len
, bl
, comp
, iohint
);
4885 image
.aio_read(off
, expected_len
, bl
, comp
);
4886 printf("started read\n");
4887 comp
->wait_for_complete();
4888 int r
= comp
->get_return_value();
4889 printf("return value is: %d\n", r
);
4890 ASSERT_EQ(TEST_IO_SIZE
, r
);
4891 ASSERT_EQ(0, memcmp(expected
, bl
.c_str(), TEST_IO_SIZE
));
4892 printf("finished read\n");
4897 void read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
4900 size_t len
= expected_len
;
4901 ceph::bufferlist bl
;
4903 read
= image
.read2(off
, len
, bl
, iohint
);
4905 read
= image
.read(off
, len
, bl
);
4906 ASSERT_TRUE(read
>= 0);
4907 std::string
bl_str(bl
.c_str(), read
);
4909 printf("read: %u\n", (unsigned int) read
);
4910 int result
= memcmp(bl_str
.c_str(), expected
, expected_len
);
4912 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), expected
);
4913 ASSERT_EQ(0, result
);
4918 void aio_writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
4919 size_t len
, size_t data_len
, uint32_t iohint
, bool *passed
)
4921 ceph::bufferlist bl
;
4922 bl
.append(test_data
, data_len
);
4923 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
4924 printf("created completion\n");
4926 r
= image
.aio_writesame(off
, len
, bl
, comp
, iohint
);
4927 printf("started writesame\n");
4928 if (len
% data_len
) {
4929 ASSERT_EQ(-EINVAL
, r
);
4930 printf("expected fail, finished writesame\n");
4936 comp
->wait_for_complete();
4937 r
= comp
->get_return_value();
4938 printf("return value is: %d\n", r
);
4940 printf("finished writesame\n");
4944 printf("to verify the data\n");
4946 uint64_t left
= len
;
4948 ceph::bufferlist bl
;
4949 read
= image
.read(off
, data_len
, bl
);
4950 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
4951 std::string
bl_str(bl
.c_str(), read
);
4952 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
4954 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
4955 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
4956 ASSERT_EQ(0, result
);
4961 ASSERT_EQ(0U, left
);
4962 printf("verified\n");
4967 void writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
4968 ssize_t len
, size_t data_len
, uint32_t iohint
,
4972 ceph::bufferlist bl
;
4973 bl
.append(test_data
, data_len
);
4974 written
= image
.writesame(off
, len
, bl
, iohint
);
4975 if (len
% data_len
) {
4976 ASSERT_EQ(-EINVAL
, written
);
4977 printf("expected fail, finished writesame\n");
4981 ASSERT_EQ(len
, written
);
4982 printf("wrote: %u\n", (unsigned int) written
);
4986 printf("to verify the data\n");
4988 uint64_t left
= len
;
4990 ceph::bufferlist bl
;
4991 read
= image
.read(off
, data_len
, bl
);
4992 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
4993 std::string
bl_str(bl
.c_str(), read
);
4994 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
4996 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
4997 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
4998 ASSERT_EQ(0, result
);
5003 ASSERT_EQ(0U, left
);
5004 printf("verified\n");
5009 void aio_compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
,
5010 const char *test_data
, off_t off
, ssize_t len
,
5011 uint32_t iohint
, bool *passed
)
5013 ceph::bufferlist cmp_bl
;
5014 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
5015 ceph::bufferlist test_bl
;
5016 test_bl
.append(test_data
, strlen(test_data
));
5017 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5018 printf("created completion\n");
5020 uint64_t mismatch_offset
;
5021 image
.aio_compare_and_write(off
, len
, cmp_bl
, test_bl
, comp
, &mismatch_offset
, iohint
);
5022 printf("started aio compare and write\n");
5023 comp
->wait_for_complete();
5024 int r
= comp
->get_return_value();
5025 printf("return value is: %d\n", r
);
5027 printf("finished aio compare and write\n");
5032 void compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
, const char *test_data
,
5033 off_t off
, ssize_t len
, uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
5036 ceph::bufferlist cmp_bl
;
5037 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
5038 ceph::bufferlist test_bl
;
5039 test_bl
.append(test_data
, strlen(test_data
));
5040 printf("start compare and write\n");
5041 written
= image
.compare_and_write(off
, len
, cmp_bl
, test_bl
, mismatch_off
, iohint
);
5042 printf("compare and wrote: %d\n", (int) written
);
5043 ASSERT_EQ(len
, static_cast<ssize_t
>(written
));
5047 TEST_F(TestLibRBD
, TestIOPP
)
5049 librados::IoCtx ioctx
;
5050 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5054 librbd::Image image
;
5056 std::string name
= get_temp_image_name();
5057 uint64_t size
= 2 << 20;
5059 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5060 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5062 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
5064 char test_data
[TEST_IO_SIZE
+ 1];
5065 char zero_data
[TEST_IO_SIZE
+ 1];
5067 uint64_t mismatch_offset
;
5069 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
5070 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
5072 test_data
[TEST_IO_SIZE
] = '\0';
5073 memset(zero_data
, 0, sizeof(zero_data
));
5075 for (i
= 0; i
< 5; ++i
)
5076 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
5078 for (i
= 5; i
< 10; ++i
)
5079 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
5081 for (i
= 0; i
< 5; ++i
)
5082 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
5083 TEST_IO_SIZE
, &mismatch_offset
, 0);
5085 for (i
= 5; i
< 10; ++i
)
5086 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
5089 for (i
= 0; i
< 5; ++i
)
5090 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
5092 for (i
= 5; i
< 10; ++i
)
5093 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
5095 // discard 2nd, 4th sections.
5096 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
5097 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
5099 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
5100 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
5101 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
5102 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
5103 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
5104 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
5105 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
5107 for (i
= 0; i
< 15; ++i
) {
5109 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
5110 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
5111 } else if (i
% 3 == 1) {
5112 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5113 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5115 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5116 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5119 for (i
= 0; i
< 15; ++i
) {
5121 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
5122 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
5123 } else if (i
% 3 == 1) {
5124 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5125 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5127 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5128 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
5132 ASSERT_PASSED(validate_object_map
, image
);
5138 static void compare_written(librbd::Image
& image
, off_t off
, size_t len
,
5139 const std::string
& buffer
, bool *passed
)
5142 ssize_t read
= image
.read(off
, len
, read_bl
);
5143 ASSERT_EQ(len
, read
);
5144 std::string
read_buffer(read_bl
.c_str(), read
);
5145 ASSERT_EQ(buffer
.substr(0, len
), read_buffer
);
5149 TEST_F(TestLibRBD
, TestCompareAndWriteCompareTooSmallPP
)
5151 librados::IoCtx ioctx
;
5152 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5156 librbd::Image image
;
5158 std::string name
= get_temp_image_name();
5159 uint64_t size
= 20 << 20; /* 20MiB */
5162 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5163 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5165 std::string
cmp_buffer("This is a test");
5166 ceph::bufferlist cmp_bl
;
5167 cmp_bl
.append(&cmp_buffer
[0], 5);
5168 cmp_bl
.append(&cmp_buffer
[5], 3);
5169 cmp_bl
.append(&cmp_buffer
[8], 2);
5170 cmp_bl
.append(&cmp_buffer
[10], 4);
5172 std::string
write_buffer("Write this !!!");
5173 ceph::bufferlist write_bl
;
5174 write_bl
.append(&write_buffer
[0], 6);
5175 write_bl
.append(&write_buffer
[6], 5);
5176 write_bl
.append(&write_buffer
[11], 3);
5178 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5179 ASSERT_EQ(cmp_bl
.length(), written
);
5181 std::string
small_buffer("Too small");
5182 ceph::bufferlist small_bl
;
5183 small_bl
.append(&small_buffer
[0], 4);
5184 small_bl
.append(&small_buffer
[4], 4);
5186 // should fail because compare bufferlist cannot be smaller than len
5187 uint64_t mismatch_off
= 0;
5188 written
= image
.compare_and_write(off
, cmp_bl
.length(),
5189 small_bl
, /* cmp_bl */
5192 ASSERT_EQ(-EINVAL
, written
);
5193 ASSERT_EQ(0U, mismatch_off
);
5195 ASSERT_PASSED(validate_object_map
, image
);
5201 TEST_F(TestLibRBD
, TestAioCompareAndWriteCompareTooSmallPP
)
5203 librados::IoCtx ioctx
;
5204 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5208 librbd::Image image
;
5210 std::string name
= get_temp_image_name();
5211 uint64_t size
= 20 << 20; /* 20MiB */
5214 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5215 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5217 std::string
cmp_buffer("This is a test");
5218 ceph::bufferlist cmp_bl
;
5219 cmp_bl
.append(&cmp_buffer
[0], 5);
5220 cmp_bl
.append(&cmp_buffer
[5], 3);
5221 cmp_bl
.append(&cmp_buffer
[8], 2);
5222 cmp_bl
.append(&cmp_buffer
[10], 4);
5224 std::string
write_buffer("Write this !!!");
5225 ceph::bufferlist write_bl
;
5226 write_bl
.append(&write_buffer
[0], 6);
5227 write_bl
.append(&write_buffer
[6], 5);
5228 write_bl
.append(&write_buffer
[11], 3);
5230 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5231 ASSERT_EQ(cmp_bl
.length(), written
);
5233 std::string
small_buffer("Too small");
5234 ceph::bufferlist small_bl
;
5235 small_bl
.append(&small_buffer
[0], 4);
5236 small_bl
.append(&small_buffer
[4], 4);
5238 // should fail because compare bufferlist cannot be smaller than len
5239 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
5240 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5241 uint64_t mismatch_off
= 0;
5242 int ret
= image
.aio_compare_and_write(off
, cmp_bl
.length(),
5243 small_bl
, /* cmp_bl */
5245 comp
, &mismatch_off
, 0);
5246 ASSERT_EQ(-EINVAL
, ret
);
5247 ASSERT_EQ(0U, mismatch_off
);
5250 ASSERT_PASSED(validate_object_map
, image
);
5256 TEST_F(TestLibRBD
, TestCompareAndWriteWriteTooSmallPP
)
5258 librados::IoCtx ioctx
;
5259 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5263 librbd::Image image
;
5265 std::string name
= get_temp_image_name();
5266 uint64_t size
= 20 << 20; /* 20MiB */
5269 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5270 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5272 std::string
cmp_buffer("This is a test");
5273 ceph::bufferlist cmp_bl
;
5274 cmp_bl
.append(&cmp_buffer
[0], 5);
5275 cmp_bl
.append(&cmp_buffer
[5], 3);
5276 cmp_bl
.append(&cmp_buffer
[8], 2);
5277 cmp_bl
.append(&cmp_buffer
[10], 4);
5279 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5280 ASSERT_EQ(cmp_bl
.length(), written
);
5282 std::string
small_buffer("Too small");
5283 ceph::bufferlist small_bl
;
5284 small_bl
.append(&small_buffer
[0], 4);
5285 small_bl
.append(&small_buffer
[4], 4);
5287 // should fail because write bufferlist cannot be smaller than len
5288 uint64_t mismatch_off
= 0;
5289 written
= image
.compare_and_write(off
, cmp_bl
.length(),
5291 small_bl
, /* write_bl */
5293 ASSERT_EQ(-EINVAL
, written
);
5294 ASSERT_EQ(0U, mismatch_off
);
5296 ASSERT_PASSED(validate_object_map
, image
);
5302 TEST_F(TestLibRBD
, TestAioCompareAndWriteWriteTooSmallPP
)
5304 librados::IoCtx ioctx
;
5305 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5309 librbd::Image image
;
5311 std::string name
= get_temp_image_name();
5312 uint64_t size
= 20 << 20; /* 20MiB */
5315 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5316 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5318 std::string
cmp_buffer("This is a test");
5319 ceph::bufferlist cmp_bl
;
5320 cmp_bl
.append(&cmp_buffer
[0], 5);
5321 cmp_bl
.append(&cmp_buffer
[5], 3);
5322 cmp_bl
.append(&cmp_buffer
[8], 2);
5323 cmp_bl
.append(&cmp_buffer
[10], 4);
5325 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5326 ASSERT_EQ(cmp_bl
.length(), written
);
5328 std::string
small_buffer("Too small");
5329 ceph::bufferlist small_bl
;
5330 small_bl
.append(&small_buffer
[0], 4);
5331 small_bl
.append(&small_buffer
[4], 4);
5333 // should fail because write bufferlist cannot be smaller than len
5334 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
5335 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5336 uint64_t mismatch_off
= 0;
5337 int ret
= image
.aio_compare_and_write(off
, cmp_bl
.length(),
5339 small_bl
, /* write_bl */
5340 comp
, &mismatch_off
, 0);
5341 ASSERT_EQ(-EINVAL
, ret
);
5342 ASSERT_EQ(0U, mismatch_off
);
5345 ASSERT_PASSED(validate_object_map
, image
);
5351 TEST_F(TestLibRBD
, TestCompareAndWriteMismatchPP
)
5353 librados::IoCtx ioctx
;
5354 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5358 librbd::Image image
;
5360 std::string name
= get_temp_image_name();
5361 uint64_t size
= 20 << 20; /* 20MiB */
5364 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5365 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5367 std::string
cmp_buffer("This is a test");
5368 ceph::bufferlist cmp_bl
;
5369 cmp_bl
.append(&cmp_buffer
[0], 5);
5370 cmp_bl
.append(&cmp_buffer
[5], 3);
5371 cmp_bl
.append(&cmp_buffer
[8], 2);
5372 cmp_bl
.append(&cmp_buffer
[10], 4);
5374 std::string
write_buffer("Write this !!!");
5375 ceph::bufferlist write_bl
;
5376 write_bl
.append(&write_buffer
[0], 6);
5377 write_bl
.append(&write_buffer
[6], 5);
5378 write_bl
.append(&write_buffer
[11], 3);
5380 std::string
mismatch_buffer("This will fail");
5381 ceph::bufferlist mismatch_bl
;
5382 mismatch_bl
.append(&mismatch_buffer
[0], 5);
5383 mismatch_bl
.append(&mismatch_buffer
[5], 5);
5384 mismatch_bl
.append(&mismatch_buffer
[10], 4);
5386 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5387 ASSERT_EQ(cmp_bl
.length(), written
);
5389 // this should execute the compare but fail because of mismatch
5390 uint64_t mismatch_off
= 0;
5391 written
= image
.compare_and_write(off
, write_bl
.length(),
5392 mismatch_bl
, /* cmp_bl */
5395 ASSERT_EQ(-EILSEQ
, written
);
5396 ASSERT_EQ(5U, mismatch_off
);
5398 // check that nothing was written
5399 ASSERT_PASSED(compare_written
, image
, off
, cmp_bl
.length(), cmp_buffer
);
5401 ASSERT_PASSED(validate_object_map
, image
);
5407 TEST_F(TestLibRBD
, TestAioCompareAndWriteMismatchPP
)
5409 librados::IoCtx ioctx
;
5410 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5414 librbd::Image image
;
5416 std::string name
= get_temp_image_name();
5417 uint64_t size
= 20 << 20; /* 20MiB */
5420 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5421 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5423 std::string
cmp_buffer("This is a test");
5424 ceph::bufferlist cmp_bl
;
5425 cmp_bl
.append(&cmp_buffer
[0], 5);
5426 cmp_bl
.append(&cmp_buffer
[5], 3);
5427 cmp_bl
.append(&cmp_buffer
[8], 2);
5428 cmp_bl
.append(&cmp_buffer
[10], 4);
5430 std::string
write_buffer("Write this !!!");
5431 ceph::bufferlist write_bl
;
5432 write_bl
.append(&write_buffer
[0], 6);
5433 write_bl
.append(&write_buffer
[6], 5);
5434 write_bl
.append(&write_buffer
[11], 3);
5436 std::string
mismatch_buffer("This will fail");
5437 ceph::bufferlist mismatch_bl
;
5438 mismatch_bl
.append(&mismatch_buffer
[0], 5);
5439 mismatch_bl
.append(&mismatch_buffer
[5], 5);
5440 mismatch_bl
.append(&mismatch_buffer
[10], 4);
5442 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5443 ASSERT_EQ(cmp_bl
.length(), written
);
5445 // this should execute the compare but fail because of mismatch
5446 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
5447 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5448 uint64_t mismatch_off
= 0;
5449 int ret
= image
.aio_compare_and_write(off
, write_bl
.length(),
5450 mismatch_bl
, /* cmp_bl */
5452 comp
, &mismatch_off
, 0);
5454 comp
->wait_for_complete();
5455 ssize_t aio_ret
= comp
->get_return_value();
5456 ASSERT_EQ(-EILSEQ
, aio_ret
);
5457 ASSERT_EQ(5U, mismatch_off
);
5460 // check that nothing was written
5461 ASSERT_PASSED(compare_written
, image
, off
, cmp_bl
.length(), cmp_buffer
);
5463 ASSERT_PASSED(validate_object_map
, image
);
5469 TEST_F(TestLibRBD
, TestCompareAndWriteMismatchBufferlistGreaterLenPP
)
5471 librados::IoCtx ioctx
;
5472 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5476 librbd::Image image
;
5478 std::string name
= get_temp_image_name();
5479 uint64_t size
= 20 << 20; /* 20MiB */
5482 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5483 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5485 std::string
cmp_buffer("This is a test");
5486 ceph::bufferlist cmp_bl
;
5487 cmp_bl
.append(&cmp_buffer
[0], 5);
5488 cmp_bl
.append(&cmp_buffer
[5], 3);
5489 cmp_bl
.append(&cmp_buffer
[8], 2);
5490 cmp_bl
.append(&cmp_buffer
[10], 4);
5492 std::string
write_buffer("Write this !!!");
5493 ceph::bufferlist write_bl
;
5494 write_bl
.append(&write_buffer
[0], 6);
5495 write_bl
.append(&write_buffer
[6], 5);
5496 write_bl
.append(&write_buffer
[11], 3);
5498 std::string
mismatch_buffer("This will fail");
5499 ceph::bufferlist mismatch_bl
;
5500 mismatch_bl
.append(&mismatch_buffer
[0], 5);
5501 mismatch_bl
.append(&mismatch_buffer
[5], 5);
5502 mismatch_bl
.append(&mismatch_buffer
[10], 4);
5504 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5505 ASSERT_EQ(cmp_bl
.length(), written
);
5508 * we allow cmp_bl and write_bl to be greater than len so this
5509 * should execute the compare but fail because of mismatch
5511 uint64_t mismatch_off
= 0;
5512 written
= image
.compare_and_write(off
, cmp_bl
.length() - 1,
5513 mismatch_bl
, /* cmp_bl */
5516 ASSERT_EQ(-EILSEQ
, written
);
5517 ASSERT_EQ(5U, mismatch_off
);
5519 // check that nothing was written
5520 ASSERT_PASSED(compare_written
, image
, off
, cmp_bl
.length(), cmp_buffer
);
5522 ASSERT_PASSED(validate_object_map
, image
);
5528 TEST_F(TestLibRBD
, TestAioCompareAndWriteMismatchBufferlistGreaterLenPP
)
5530 librados::IoCtx ioctx
;
5531 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5535 librbd::Image image
;
5537 std::string name
= get_temp_image_name();
5538 uint64_t size
= 20 << 20; /* 20MiB */
5541 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5542 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5544 std::string
cmp_buffer("This is a test");
5545 ceph::bufferlist cmp_bl
;
5546 cmp_bl
.append(&cmp_buffer
[0], 5);
5547 cmp_bl
.append(&cmp_buffer
[5], 3);
5548 cmp_bl
.append(&cmp_buffer
[8], 2);
5549 cmp_bl
.append(&cmp_buffer
[10], 4);
5551 std::string
write_buffer("Write this !!!");
5552 ceph::bufferlist write_bl
;
5553 write_bl
.append(&write_buffer
[0], 6);
5554 write_bl
.append(&write_buffer
[6], 5);
5555 write_bl
.append(&write_buffer
[11], 3);
5557 std::string
mismatch_buffer("This will fail");
5558 ceph::bufferlist mismatch_bl
;
5559 mismatch_bl
.append(&mismatch_buffer
[0], 5);
5560 mismatch_bl
.append(&mismatch_buffer
[5], 5);
5561 mismatch_bl
.append(&mismatch_buffer
[10], 4);
5563 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5564 ASSERT_EQ(cmp_bl
.length(), written
);
5567 * we allow cmp_bl and write_bl to be greater than len so this
5568 * should execute the compare but fail because of mismatch
5570 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
5571 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5572 uint64_t mismatch_off
= 0;
5573 int ret
= image
.aio_compare_and_write(off
, cmp_bl
.length() - 1,
5574 mismatch_bl
, /* cmp_bl */
5576 comp
, &mismatch_off
, 0);
5578 comp
->wait_for_complete();
5579 ssize_t aio_ret
= comp
->get_return_value();
5580 ASSERT_EQ(-EILSEQ
, aio_ret
);
5581 ASSERT_EQ(5U, mismatch_off
);
5584 // check that nothing was written
5585 ASSERT_PASSED(compare_written
, image
, off
, cmp_bl
.length(), cmp_buffer
);
5587 ASSERT_PASSED(validate_object_map
, image
);
5593 TEST_F(TestLibRBD
, TestCompareAndWriteSuccessPP
)
5595 librados::IoCtx ioctx
;
5596 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5600 librbd::Image image
;
5602 std::string name
= get_temp_image_name();
5603 uint64_t size
= 20 << 20; /* 20MiB */
5606 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5607 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5609 std::string
cmp_buffer("This is a test");
5610 ceph::bufferlist cmp_bl
;
5611 cmp_bl
.append(&cmp_buffer
[0], 5);
5612 cmp_bl
.append(&cmp_buffer
[5], 3);
5613 cmp_bl
.append(&cmp_buffer
[8], 2);
5614 cmp_bl
.append(&cmp_buffer
[10], 4);
5616 std::string
write_buffer("Write this !!!");
5617 ceph::bufferlist write_bl
;
5618 write_bl
.append(&write_buffer
[0], 6);
5619 write_bl
.append(&write_buffer
[6], 5);
5620 write_bl
.append(&write_buffer
[11], 3);
5622 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5623 ASSERT_EQ(cmp_bl
.length(), written
);
5625 // compare against the buffer written before => should succeed
5626 uint64_t mismatch_off
= 0;
5627 written
= image
.compare_and_write(off
, cmp_bl
.length(),
5631 ASSERT_EQ(write_bl
.length(), written
);
5632 ASSERT_EQ(0U, mismatch_off
);
5634 // check write_bl was written
5635 ASSERT_PASSED(compare_written
, image
, off
, write_bl
.length(), write_buffer
);
5637 ASSERT_PASSED(validate_object_map
, image
);
5643 TEST_F(TestLibRBD
, TestAioCompareAndWriteSuccessPP
)
5645 librados::IoCtx ioctx
;
5646 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5650 librbd::Image image
;
5652 std::string name
= get_temp_image_name();
5653 uint64_t size
= 20 << 20; /* 20MiB */
5656 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5657 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5659 std::string
cmp_buffer("This is a test");
5660 ceph::bufferlist cmp_bl
;
5661 cmp_bl
.append(&cmp_buffer
[0], 5);
5662 cmp_bl
.append(&cmp_buffer
[5], 3);
5663 cmp_bl
.append(&cmp_buffer
[8], 2);
5664 cmp_bl
.append(&cmp_buffer
[10], 4);
5666 std::string
write_buffer("Write this !!!");
5667 ceph::bufferlist write_bl
;
5668 write_bl
.append(&write_buffer
[0], 6);
5669 write_bl
.append(&write_buffer
[6], 5);
5670 write_bl
.append(&write_buffer
[11], 3);
5672 ssize_t written
= image
.write(off
, cmp_bl
.length(), cmp_bl
);
5673 ASSERT_EQ(cmp_bl
.length(), written
);
5675 // compare against the buffer written before => should succeed
5676 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
5677 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5678 uint64_t mismatch_off
= 0;
5679 int ret
= image
.aio_compare_and_write(off
, write_bl
.length(),
5682 comp
, &mismatch_off
, 0);
5684 comp
->wait_for_complete();
5685 ssize_t aio_ret
= comp
->get_return_value();
5686 ASSERT_EQ(0, aio_ret
);
5687 ASSERT_EQ(0U, mismatch_off
);
5690 // check write_bl was written
5691 ASSERT_PASSED(compare_written
, image
, off
, write_bl
.length(), write_buffer
);
5693 ASSERT_PASSED(validate_object_map
, image
);
5699 TEST_F(TestLibRBD
, TestCompareAndWriteSuccessBufferlistGreaterLenPP
)
5701 librados::IoCtx ioctx
;
5702 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5706 librbd::Image image
;
5708 std::string name
= get_temp_image_name();
5709 uint64_t size
= 20 << 20; /* 20MiB */
5712 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5713 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5715 std::string
cmp_buffer("This is a test");
5716 ceph::bufferlist cmp_bl
;
5717 cmp_bl
.append(&cmp_buffer
[0], 5);
5718 cmp_bl
.append(&cmp_buffer
[5], 3);
5719 cmp_bl
.append(&cmp_buffer
[8], 2);
5720 cmp_bl
.append(&cmp_buffer
[10], 4);
5722 std::string
write_buffer("Write this !!!");
5723 ceph::bufferlist write_bl
;
5724 write_bl
.append(&write_buffer
[0], 6);
5725 write_bl
.append(&write_buffer
[6], 5);
5726 write_bl
.append(&write_buffer
[11], 3);
5728 std::string
mismatch_buffer("This will fail");
5729 ceph::bufferlist mismatch_bl
;
5730 mismatch_bl
.append(&mismatch_buffer
[0], 5);
5731 mismatch_bl
.append(&mismatch_buffer
[5], 5);
5732 mismatch_bl
.append(&mismatch_buffer
[10], 4);
5735 * Test len < cmp_bl & write_bl => should succeed but only compare
5736 * len bytes resp. only write len bytes
5738 ssize_t written
= image
.write(off
, mismatch_bl
.length(), mismatch_bl
);
5739 ASSERT_EQ(mismatch_bl
.length(), written
);
5741 size_t len_m1
= cmp_bl
.length() - 1;
5742 written
= image
.write(off
, len_m1
, cmp_bl
);
5743 ASSERT_EQ(len_m1
, written
);
5744 // the content of the image at off should now be "This is a tesl"
5746 uint64_t mismatch_off
= 0;
5747 written
= image
.compare_and_write(off
, len_m1
,
5751 ASSERT_EQ(len_m1
, written
);
5752 ASSERT_EQ(0U, mismatch_off
);
5754 // check that only write_bl.length() - 1 bytes were written
5755 ASSERT_PASSED(compare_written
, image
, off
, len_m1
, write_buffer
);
5756 ASSERT_PASSED(compare_written
, image
, off
+ len_m1
, 1, std::string("l"));
5758 ASSERT_PASSED(validate_object_map
, image
);
5764 TEST_F(TestLibRBD
, TestAioCompareAndWriteSuccessBufferlistGreaterLenPP
)
5766 librados::IoCtx ioctx
;
5767 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5771 librbd::Image image
;
5773 std::string name
= get_temp_image_name();
5774 uint64_t size
= 20 << 20; /* 20MiB */
5777 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5778 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5780 std::string
cmp_buffer("This is a test");
5781 ceph::bufferlist cmp_bl
;
5782 cmp_bl
.append(&cmp_buffer
[0], 5);
5783 cmp_bl
.append(&cmp_buffer
[5], 3);
5784 cmp_bl
.append(&cmp_buffer
[8], 2);
5785 cmp_bl
.append(&cmp_buffer
[10], 4);
5787 std::string
write_buffer("Write this !!!");
5788 ceph::bufferlist write_bl
;
5789 write_bl
.append(&write_buffer
[0], 6);
5790 write_bl
.append(&write_buffer
[6], 5);
5791 write_bl
.append(&write_buffer
[11], 3);
5793 std::string
mismatch_buffer("This will fail");
5794 ceph::bufferlist mismatch_bl
;
5795 mismatch_bl
.append(&mismatch_buffer
[0], 5);
5796 mismatch_bl
.append(&mismatch_buffer
[5], 5);
5797 mismatch_bl
.append(&mismatch_buffer
[10], 4);
5800 * Test len < cmp_bl & write_bl => should succeed but only compare
5801 * len bytes resp. only write len bytes
5803 ssize_t written
= image
.write(off
, mismatch_bl
.length(), mismatch_bl
);
5804 ASSERT_EQ(mismatch_bl
.length(), written
);
5806 size_t len_m1
= cmp_bl
.length() - 1;
5807 written
= image
.write(off
, len_m1
, cmp_bl
);
5808 ASSERT_EQ(len_m1
, written
);
5809 // the content of the image at off should now be "This is a tesl"
5811 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
5812 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5813 uint64_t mismatch_off
= 0;
5814 int ret
= image
.aio_compare_and_write(off
, len_m1
,
5817 comp
, &mismatch_off
, 0);
5819 comp
->wait_for_complete();
5820 ssize_t aio_ret
= comp
->get_return_value();
5821 ASSERT_EQ(0, aio_ret
);
5822 ASSERT_EQ(0U, mismatch_off
);
5825 // check that only write_bl.length() - 1 bytes were written
5826 ASSERT_PASSED(compare_written
, image
, off
, len_m1
, write_buffer
);
5827 ASSERT_PASSED(compare_written
, image
, off
+ len_m1
, 1, std::string("l"));
5829 ASSERT_PASSED(validate_object_map
, image
);
5835 TEST_F(TestLibRBD
, TestCompareAndWriteStripeUnitUnalignedPP
)
5837 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
5839 librados::IoCtx ioctx
;
5840 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5844 librbd::Image image
;
5846 std::string name
= get_temp_image_name();
5847 uint64_t size
= 20 << 20; /* 20MiB */
5849 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5850 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5852 // large write test => we allow stripe unit size writes (aligned)
5853 uint64_t stripe_unit
= image
.get_stripe_unit();
5854 std::string
large_write_buffer(stripe_unit
, '2');
5855 ceph::bufferlist large_write_bl
;
5856 large_write_bl
.append(large_write_buffer
.data(),
5857 large_write_buffer
.length());
5859 std::string
large_cmp_buffer(stripe_unit
* 2, '3');
5860 ceph::bufferlist large_cmp_bl
;
5861 large_cmp_bl
.append(large_cmp_buffer
.data(), large_cmp_buffer
.length());
5863 ssize_t written
= image
.write(stripe_unit
, large_cmp_bl
.length(),
5865 ASSERT_EQ(large_cmp_bl
.length(), written
);
5868 * compare and write at offset stripe_unit + 1 and stripe unit size
5869 * Expect fail because access exceeds stripe
5871 uint64_t mismatch_off
= 0;
5872 written
= image
.compare_and_write(stripe_unit
+ 1, stripe_unit
,
5876 ASSERT_EQ(-EINVAL
, written
);
5877 ASSERT_EQ(0U, mismatch_off
);
5879 // check nothing has been written
5880 ASSERT_PASSED(compare_written
, image
, stripe_unit
, large_cmp_bl
.length(),
5883 ASSERT_PASSED(validate_object_map
, image
);
5889 TEST_F(TestLibRBD
, TestAioCompareAndWriteStripeUnitUnalignedPP
)
5891 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
5893 librados::IoCtx ioctx
;
5894 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5898 librbd::Image image
;
5900 std::string name
= get_temp_image_name();
5901 uint64_t size
= 20 << 20; /* 20MiB */
5903 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5904 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5906 // large write test => we allow stripe unit size writes (aligned)
5907 uint64_t stripe_unit
= image
.get_stripe_unit();
5908 std::string
large_write_buffer(stripe_unit
, '2');
5909 ceph::bufferlist large_write_bl
;
5910 large_write_bl
.append(large_write_buffer
.data(),
5911 large_write_buffer
.length());
5913 std::string
large_cmp_buffer(stripe_unit
* 2, '3');
5914 ceph::bufferlist large_cmp_bl
;
5915 large_cmp_bl
.append(large_cmp_buffer
.data(), large_cmp_buffer
.length());
5917 ssize_t written
= image
.write(stripe_unit
, large_cmp_bl
.length(),
5919 ASSERT_EQ(large_cmp_bl
.length(), written
);
5922 * compare and write at offset stripe_unit + 1 and stripe unit size
5923 * Expect fail because access exceeds stripe
5925 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
5926 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
5927 uint64_t mismatch_off
= 0;
5928 int ret
= image
.aio_compare_and_write(stripe_unit
+ 1, stripe_unit
,
5931 comp
, &mismatch_off
, 0);
5933 comp
->wait_for_complete();
5934 ssize_t aio_ret
= comp
->get_return_value();
5935 ASSERT_EQ(-EINVAL
, aio_ret
);
5936 ASSERT_EQ(0U, mismatch_off
);
5939 // check nothing has been written
5940 ASSERT_PASSED(compare_written
, image
, stripe_unit
, large_cmp_bl
.length(),
5943 ASSERT_PASSED(validate_object_map
, image
);
5949 TEST_F(TestLibRBD
, TestCompareAndWriteTooLargePP
)
5951 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
5953 librados::IoCtx ioctx
;
5954 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5958 librbd::Image image
;
5960 std::string name
= get_temp_image_name();
5961 uint64_t size
= 20 << 20; /* 20MiB */
5963 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5964 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5966 // large write test => we allow stripe unit size writes (aligned)
5967 uint64_t stripe_unit
= image
.get_stripe_unit();
5968 std::string
large_write_buffer(stripe_unit
* 2, '2');
5969 ceph::bufferlist large_write_bl
;
5970 large_write_bl
.append(large_write_buffer
.data(),
5971 large_write_buffer
.length());
5973 std::string
large_cmp_buffer(stripe_unit
* 2, '3');
5974 ceph::bufferlist large_cmp_bl
;
5975 large_cmp_bl
.append(large_cmp_buffer
.data(), large_cmp_buffer
.length());
5977 ssize_t written
= image
.write(stripe_unit
, large_cmp_bl
.length(),
5979 ASSERT_EQ(large_cmp_bl
.length(), written
);
5982 * compare and write at offset stripe_unit and stripe unit size + 1
5983 * Expect fail because access is larger than stripe unit size
5985 uint64_t mismatch_off
= 0;
5986 written
= image
.compare_and_write(stripe_unit
, stripe_unit
+ 1,
5990 ASSERT_EQ(-EINVAL
, written
);
5991 ASSERT_EQ(0U, mismatch_off
);
5993 // check nothing has been written
5994 ASSERT_PASSED(compare_written
, image
, stripe_unit
, large_cmp_bl
.length(),
5997 ASSERT_PASSED(validate_object_map
, image
);
6003 TEST_F(TestLibRBD
, TestAioCompareAndWriteTooLargePP
)
6005 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
6007 librados::IoCtx ioctx
;
6008 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6012 librbd::Image image
;
6014 std::string name
= get_temp_image_name();
6015 uint64_t size
= 20 << 20; /* 20MiB */
6017 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6018 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6020 // large write test => we allow stripe unit size writes (aligned)
6021 uint64_t stripe_unit
= image
.get_stripe_unit();
6022 std::string
large_write_buffer(stripe_unit
* 2, '2');
6023 ceph::bufferlist large_write_bl
;
6024 large_write_bl
.append(large_write_buffer
.data(),
6025 large_write_buffer
.length());
6027 std::string
large_cmp_buffer(stripe_unit
* 2, '3');
6028 ceph::bufferlist large_cmp_bl
;
6029 large_cmp_bl
.append(large_cmp_buffer
.data(), large_cmp_buffer
.length());
6031 ssize_t written
= image
.write(stripe_unit
, large_cmp_bl
.length(),
6033 ASSERT_EQ(large_cmp_bl
.length(), written
);
6036 * compare and write at offset stripe_unit and stripe unit size + 1
6037 * Expect fail because access is larger than stripe unit size
6039 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
6040 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
6041 uint64_t mismatch_off
= 0;
6042 int ret
= image
.aio_compare_and_write(stripe_unit
, stripe_unit
+ 1,
6045 comp
, &mismatch_off
, 0);
6047 comp
->wait_for_complete();
6048 ssize_t aio_ret
= comp
->get_return_value();
6049 ASSERT_EQ(-EINVAL
, aio_ret
);
6050 ASSERT_EQ(0U, mismatch_off
);
6053 // check nothing has been written
6054 ASSERT_PASSED(compare_written
, image
, stripe_unit
, large_cmp_bl
.length(),
6057 ASSERT_PASSED(validate_object_map
, image
);
6063 TEST_F(TestLibRBD
, TestCompareAndWriteStripeUnitSuccessPP
)
6065 librados::IoCtx ioctx
;
6066 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6070 librbd::Image image
;
6072 std::string name
= get_temp_image_name();
6073 uint64_t size
= 20 << 20; /* 20MiB */
6075 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6076 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6078 // large write test => we allow stripe unit size writes (aligned)
6079 uint64_t stripe_unit
= image
.get_stripe_unit();
6080 std::string
large_write_buffer(stripe_unit
* 2, '2');
6081 ceph::bufferlist large_write_bl
;
6082 large_write_bl
.append(large_write_buffer
.data(),
6083 large_write_buffer
.length());
6085 std::string
large_cmp_buffer(stripe_unit
* 2, '3');
6086 ceph::bufferlist large_cmp_bl
;
6087 large_cmp_bl
.append(large_cmp_buffer
.data(), large_cmp_buffer
.length());
6089 ssize_t written
= image
.write(stripe_unit
, large_cmp_bl
.length(),
6091 ASSERT_EQ(large_cmp_bl
.length(), written
);
6093 // aligned stripe unit size access => expect success
6094 uint64_t mismatch_off
= 0;
6095 written
= image
.compare_and_write(stripe_unit
, stripe_unit
,
6099 ASSERT_EQ(stripe_unit
, written
);
6100 ASSERT_EQ(0U, mismatch_off
);
6102 // check large_write_bl was written and nothing beyond
6103 ASSERT_PASSED(compare_written
, image
, stripe_unit
, stripe_unit
,
6104 large_write_buffer
);
6105 ASSERT_PASSED(compare_written
, image
, stripe_unit
* 2, stripe_unit
,
6108 ASSERT_PASSED(validate_object_map
, image
);
6114 TEST_F(TestLibRBD
, TestAioCompareAndWriteStripeUnitSuccessPP
)
6116 librados::IoCtx ioctx
;
6117 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6121 librbd::Image image
;
6123 std::string name
= get_temp_image_name();
6124 uint64_t size
= 20 << 20; /* 20MiB */
6126 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6127 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6129 // large write test => we allow stripe unit size writes (aligned)
6130 uint64_t stripe_unit
= image
.get_stripe_unit();
6131 std::string
large_write_buffer(stripe_unit
* 2, '2');
6132 ceph::bufferlist large_write_bl
;
6133 large_write_bl
.append(large_write_buffer
.data(),
6134 large_write_buffer
.length());
6136 std::string
large_cmp_buffer(stripe_unit
* 2, '3');
6137 ceph::bufferlist large_cmp_bl
;
6138 large_cmp_bl
.append(large_cmp_buffer
.data(),
6139 large_cmp_buffer
.length());
6141 ssize_t written
= image
.write(stripe_unit
, large_cmp_bl
.length(),
6143 ASSERT_EQ(large_cmp_bl
.length(), written
);
6145 // aligned stripe unit size access => expect success
6146 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(
6147 NULL
, (librbd::callback_t
) simple_write_cb_pp
);
6148 uint64_t mismatch_off
= 0;
6149 int ret
= image
.aio_compare_and_write(stripe_unit
, stripe_unit
,
6152 comp
, &mismatch_off
, 0);
6154 comp
->wait_for_complete();
6155 ssize_t aio_ret
= comp
->get_return_value();
6156 ASSERT_EQ(0, aio_ret
);
6157 ASSERT_EQ(0U, mismatch_off
);
6160 // check large_write_bl was written and nothing beyond
6161 ASSERT_PASSED(compare_written
, image
, stripe_unit
, stripe_unit
,
6162 large_write_buffer
);
6163 ASSERT_PASSED(compare_written
, image
, stripe_unit
* 2, stripe_unit
,
6166 ASSERT_PASSED(validate_object_map
, image
);
6172 TEST_F(TestLibRBD
, TestIOPPWithIOHint
)
6174 librados::IoCtx ioctx
;
6175 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6179 librbd::Image image
;
6181 std::string name
= get_temp_image_name();
6182 uint64_t size
= 2 << 20;
6184 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6185 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6187 char test_data
[TEST_IO_SIZE
+ 1];
6188 char zero_data
[TEST_IO_SIZE
+ 1];
6189 test_data
[TEST_IO_SIZE
] = '\0';
6192 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
6193 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
6195 memset(zero_data
, 0, sizeof(zero_data
));
6197 for (i
= 0; i
< 5; ++i
)
6198 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
,
6199 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
6201 for (i
= 5; i
< 10; ++i
)
6202 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
,
6203 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6205 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
),
6206 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_RANDOM
);
6208 for (i
= 5; i
< 10; ++i
)
6209 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
,
6210 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6212 for (i
= 0; i
< 15; ++i
) {
6214 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
6215 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
6216 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
6217 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
6218 } else if (i
% 3 == 1) {
6219 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
6220 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
6221 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
6222 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
6224 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
6225 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
6226 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
6227 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
6230 for (i
= 0; i
< 15; ++i
) {
6232 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
6233 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6234 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
6235 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6236 } else if (i
% 3 == 1) {
6237 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
6238 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6239 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
6240 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6242 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
6243 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6244 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
6245 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
6249 ASSERT_PASSED(validate_object_map
, image
);
6257 TEST_F(TestLibRBD
, TestIOToSnapshot
)
6259 rados_ioctx_t ioctx
;
6260 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6264 std::string name
= get_temp_image_name();
6265 uint64_t isize
= 2 << 20;
6267 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
6268 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6271 rbd_image_t image_at_snap
;
6272 char orig_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
6273 char test_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
6275 for (i
= 0; i
< TEST_IO_TO_SNAP_SIZE
; ++i
)
6276 test_data
[i
] = (char) (i
+ 48);
6277 test_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
6278 orig_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
6280 r
= rbd_read(image
, 0, TEST_IO_TO_SNAP_SIZE
, orig_data
);
6281 ASSERT_EQ(r
, TEST_IO_TO_SNAP_SIZE
);
6283 ASSERT_EQ(0, test_ls_snaps(image
, 0));
6284 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
6285 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
6286 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6288 printf("write test data!\n");
6289 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6290 ASSERT_EQ(0, rbd_snap_create(image
, "written"));
6291 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
6293 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6295 rbd_snap_set(image
, "orig");
6296 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6298 rbd_snap_set(image
, "written");
6299 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6301 rbd_snap_set(image
, "orig");
6303 r
= rbd_write(image
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
6304 printf("write to snapshot returned %d\n", r
);
6306 cout
<< strerror(-r
) << std::endl
;
6308 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6309 rbd_snap_set(image
, "written");
6310 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6312 r
= rbd_snap_rollback(image
, "orig");
6313 ASSERT_EQ(r
, -EROFS
);
6315 r
= rbd_snap_set(image
, NULL
);
6317 r
= rbd_snap_rollback(image
, "orig");
6320 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6324 printf("opening testimg@orig\n");
6325 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_at_snap
, "orig"));
6326 ASSERT_PASSED(read_test_data
, image_at_snap
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
6327 r
= rbd_write(image_at_snap
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
6328 printf("write to snapshot returned %d\n", r
);
6330 cout
<< strerror(-r
) << std::endl
;
6331 ASSERT_EQ(0, rbd_close(image_at_snap
));
6333 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
6334 ASSERT_EQ(0, rbd_snap_remove(image
, "written"));
6335 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
6336 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
6337 ASSERT_EQ(0, test_ls_snaps(image
, 0));
6339 ASSERT_PASSED(validate_object_map
, image
);
6340 ASSERT_EQ(0, rbd_close(image
));
6342 rados_ioctx_destroy(ioctx
);
6345 TEST_F(TestLibRBD
, TestSnapshotDeletedIo
)
6347 rados_ioctx_t ioctx
;
6348 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6352 std::string name
= get_temp_image_name();
6353 uint64_t isize
= 2 << 20;
6357 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
6358 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6359 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
6361 r
= rbd_snap_set(image
, "orig");
6364 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
6366 ASSERT_EQ(-ENOENT
, rbd_read(image
, 20, 20, test
));
6368 r
= rbd_snap_set(image
, NULL
);
6371 ASSERT_EQ(0, rbd_close(image
));
6372 rados_ioctx_destroy(ioctx
);
6375 TEST_F(TestLibRBD
, TestClone
)
6377 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6378 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "1"));
6379 BOOST_SCOPE_EXIT_ALL(&) {
6380 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
6383 rados_ioctx_t ioctx
;
6384 rbd_image_info_t pinfo
, cinfo
;
6385 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6389 rbd_image_t parent
, child
;
6392 ASSERT_EQ(0, get_features(&old_format
, &features
));
6393 ASSERT_FALSE(old_format
);
6395 std::string parent_name
= get_temp_image_name();
6396 std::string child_name
= get_temp_image_name();
6398 // make a parent to clone from
6399 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
6401 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
6402 printf("made parent image \"parent\"\n");
6404 char *data
= (char *)"testdata";
6405 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
6407 // can't clone a non-snapshot, expect failure
6408 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
6409 child_name
.c_str(), features
, &order
));
6411 // verify that there is no parent info on "parent"
6412 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
6413 printf("parent has no parent info\n");
6415 // create 70 metadatas to verify we can clone all key/value pairs
6418 size_t sum_key_len
= 0;
6419 size_t sum_value_len
= 0;
6420 for (int i
= 1; i
<= 70; i
++) {
6421 key
= "key" + stringify(i
);
6422 val
= "value" + stringify(i
);
6423 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
6425 sum_key_len
+= (key
.size() + 1);
6426 sum_value_len
+= (val
.size() + 1);
6431 size_t keys_len
= sizeof(keys
);
6432 size_t vals_len
= sizeof(vals
);
6435 size_t value_len
= sizeof(value
);
6437 // create a snapshot, reopen as the parent we're interested in
6438 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6439 printf("made snapshot \"parent@parent_snap\"\n");
6440 ASSERT_EQ(0, rbd_close(parent
));
6441 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
6443 ASSERT_EQ(-EINVAL
, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
6444 ioctx
, child_name
.c_str(), features
, &order
));
6446 // unprotected image should fail unprotect
6447 ASSERT_EQ(-EINVAL
, rbd_snap_unprotect(parent
, "parent_snap"));
6448 printf("can't unprotect an unprotected snap\n");
6450 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
6451 // protecting again should fail
6452 ASSERT_EQ(-EBUSY
, rbd_snap_protect(parent
, "parent_snap"));
6453 printf("can't protect a protected snap\n");
6455 // This clone and open should work
6456 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
6457 ioctx
, child_name
.c_str(), features
, &order
));
6458 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
6459 printf("made and opened clone \"child\"\n");
6462 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
6465 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(child
, 20, strlen(data
), data
));
6466 ASSERT_PASSED(read_test_data
, child
, data
, 20, strlen(data
), 0);
6467 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
6470 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
6471 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
6472 EXPECT_EQ(cinfo
.size
, pinfo
.size
);
6474 rbd_get_overlap(child
, &overlap
);
6475 EXPECT_EQ(overlap
, pinfo
.size
);
6476 EXPECT_EQ(cinfo
.obj_size
, pinfo
.obj_size
);
6477 EXPECT_EQ(cinfo
.order
, pinfo
.order
);
6478 printf("sizes and overlaps are good between parent and child\n");
6480 // check key/value pairs in child image
6481 ASSERT_EQ(0, rbd_metadata_list(child
, "key", 70, keys
, &keys_len
, vals
,
6483 ASSERT_EQ(sum_key_len
, keys_len
);
6484 ASSERT_EQ(sum_value_len
, vals_len
);
6486 for (int i
= 1; i
<= 70; i
++) {
6487 key
= "key" + stringify(i
);
6488 val
= "value" + stringify(i
);
6489 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
6490 ASSERT_STREQ(val
.c_str(), value
);
6492 value_len
= sizeof(value
);
6494 printf("child image successfully cloned all image-meta pairs\n");
6496 // sizing down child results in changing overlap and size, not parent size
6497 ASSERT_EQ(0, rbd_resize(child
, 2UL<<20));
6498 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
6499 rbd_get_overlap(child
, &overlap
);
6500 ASSERT_EQ(overlap
, 2UL<<20);
6501 ASSERT_EQ(cinfo
.size
, 2UL<<20);
6502 ASSERT_EQ(0, rbd_resize(child
, 4UL<<20));
6503 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
6504 rbd_get_overlap(child
, &overlap
);
6505 ASSERT_EQ(overlap
, 2UL<<20);
6506 ASSERT_EQ(cinfo
.size
, 4UL<<20);
6507 printf("sized down clone, changed overlap\n");
6509 // sizing back up doesn't change that
6510 ASSERT_EQ(0, rbd_resize(child
, 5UL<<20));
6511 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
6512 rbd_get_overlap(child
, &overlap
);
6513 ASSERT_EQ(overlap
, 2UL<<20);
6514 ASSERT_EQ(cinfo
.size
, 5UL<<20);
6515 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
6516 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
6517 (unsigned long long)pinfo
.size
, (unsigned long long)pinfo
.obj_size
,
6518 (unsigned long long)pinfo
.parent_pool
);
6519 ASSERT_EQ(pinfo
.size
, 4UL<<20);
6520 printf("sized up clone, changed size but not overlap or parent's size\n");
6522 ASSERT_PASSED(validate_object_map
, child
);
6523 ASSERT_EQ(0, rbd_close(child
));
6525 ASSERT_PASSED(validate_object_map
, parent
);
6526 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
6527 printf("can't remove parent while child still exists\n");
6528 ASSERT_EQ(0, rbd_remove(ioctx
, child_name
.c_str()));
6529 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
6530 printf("can't remove parent while still protected\n");
6531 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
6532 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
6533 printf("removed parent snap after unprotecting\n");
6535 ASSERT_EQ(0, rbd_close(parent
));
6536 rados_ioctx_destroy(ioctx
);
6539 TEST_F(TestLibRBD
, TestClone2
)
6541 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6542 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
6543 BOOST_SCOPE_EXIT_ALL(&) {
6544 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
6547 rados_ioctx_t ioctx
;
6548 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6552 rbd_image_t parent
, child
;
6555 ASSERT_EQ(0, get_features(&old_format
, &features
));
6556 ASSERT_FALSE(old_format
);
6558 std::string parent_name
= get_temp_image_name();
6559 std::string child_name
= get_temp_image_name();
6561 // make a parent to clone from
6562 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
6564 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
6565 printf("made parent image \"parent\"\n");
6567 char *data
= (char *)"testdata";
6568 char *childata
= (char *)"childata";
6569 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
6570 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
6572 // can't clone a non-snapshot, expect failure
6573 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
6574 child_name
.c_str(), features
, &order
));
6576 // verify that there is no parent info on "parent"
6577 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
6578 printf("parent has no parent info\n");
6580 // create 70 metadatas to verify we can clone all key/value pairs
6583 size_t sum_key_len
= 0;
6584 size_t sum_value_len
= 0;
6585 for (int i
= 1; i
<= 70; i
++) {
6586 key
= "key" + stringify(i
);
6587 val
= "value" + stringify(i
);
6588 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
6590 sum_key_len
+= (key
.size() + 1);
6591 sum_value_len
+= (val
.size() + 1);
6596 size_t keys_len
= sizeof(keys
);
6597 size_t vals_len
= sizeof(vals
);
6600 size_t value_len
= sizeof(value
);
6602 // create a snapshot, reopen as the parent we're interested in
6603 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6604 printf("made snapshot \"parent@parent_snap\"\n");
6605 ASSERT_EQ(0, rbd_close(parent
));
6606 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
6608 // This clone and open should work
6609 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
6610 ioctx
, child_name
.c_str(), features
, &order
));
6611 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
6612 printf("made and opened clone \"child\"\n");
6614 // check key/value pairs in child image
6615 ASSERT_EQ(0, rbd_metadata_list(child
, "key", 70, keys
, &keys_len
, vals
,
6617 ASSERT_EQ(sum_key_len
, keys_len
);
6618 ASSERT_EQ(sum_value_len
, vals_len
);
6620 for (int i
= 1; i
<= 70; i
++) {
6621 key
= "key" + stringify(i
);
6622 val
= "value" + stringify(i
);
6623 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
6624 ASSERT_STREQ(val
.c_str(), value
);
6626 value_len
= sizeof(value
);
6628 printf("child image successfully cloned all image-meta pairs\n");
6630 // write something in
6631 ASSERT_EQ((ssize_t
)strlen(childata
), rbd_write(child
, 20, strlen(childata
), childata
));
6633 char test
[strlen(data
) * 2];
6634 ASSERT_EQ((ssize_t
)strlen(data
), rbd_read(child
, 20, strlen(data
), test
));
6635 ASSERT_EQ(0, memcmp(test
, childata
, strlen(childata
)));
6638 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 20 - strlen(data
), sizeof(test
), test
));
6639 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
6640 ASSERT_EQ(0, memcmp(test
+ strlen(data
), childata
, strlen(childata
)));
6643 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 0, sizeof(test
), test
));
6644 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
6646 ASSERT_PASSED(validate_object_map
, child
);
6647 ASSERT_PASSED(validate_object_map
, parent
);
6649 rbd_snap_info_t snaps
[2];
6651 ASSERT_EQ(1, rbd_snap_list(parent
, snaps
, &max_snaps
));
6652 rbd_snap_list_end(snaps
);
6654 ASSERT_EQ(0, rbd_snap_remove_by_id(parent
, snaps
[0].id
));
6656 rbd_snap_namespace_type_t snap_namespace_type
;
6657 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent
, snaps
[0].id
,
6658 &snap_namespace_type
));
6659 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH
, snap_namespace_type
);
6661 char original_name
[32];
6662 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent
, snaps
[0].id
,
6664 sizeof(original_name
)));
6665 ASSERT_EQ(0, strcmp("parent_snap", original_name
));
6667 ASSERT_EQ(0, rbd_close(child
));
6668 ASSERT_EQ(0, rbd_close(parent
));
6669 rados_ioctx_destroy(ioctx
);
6672 static void test_list_children(rbd_image_t image
, ssize_t num_expected
, ...)
6675 va_start(ap
, num_expected
);
6676 size_t pools_len
= 100;
6677 size_t children_len
= 100;
6679 char *children
= NULL
;
6680 ssize_t num_children
;
6685 pools
= (char *) malloc(pools_len
);
6686 children
= (char *) malloc(children_len
);
6687 num_children
= rbd_list_children(image
, pools
, &pools_len
,
6688 children
, &children_len
);
6689 } while (num_children
== -ERANGE
);
6691 ASSERT_EQ(num_expected
, num_children
);
6692 for (ssize_t i
= num_expected
; i
> 0; --i
) {
6693 char *expected_pool
= va_arg(ap
, char *);
6694 char *expected_image
= va_arg(ap
, char *);
6696 char *image
= children
;
6698 printf("\ntrying to find %s/%s\n", expected_pool
, expected_image
);
6699 for (ssize_t j
= 0; j
< num_children
; ++j
) {
6700 printf("checking %s/%s\n", pool
, image
);
6701 if (strcmp(expected_pool
, pool
) == 0 &&
6702 strcmp(expected_image
, image
) == 0) {
6703 printf("found child %s/%s\n\n", pool
, image
);
6707 pool
+= strlen(pool
) + 1;
6708 image
+= strlen(image
) + 1;
6709 if (j
== num_children
- 1) {
6710 ASSERT_EQ(pool
- pools
- 1, (ssize_t
) pools_len
);
6711 ASSERT_EQ(image
- children
- 1, (ssize_t
) children_len
);
6724 static void test_list_children2(rbd_image_t image
, int num_expected
, ...)
6726 int num_children
, i
, j
, max_size
= 10;
6728 rbd_child_info_t children
[max_size
];
6729 num_children
= rbd_list_children2(image
, children
, &max_size
);
6730 printf("num children is: %d\nexpected: %d\n", num_children
, num_expected
);
6732 for (i
= 0; i
< num_children
; i
++) {
6733 printf("child: %s\n", children
[i
].image_name
);
6736 va_start(ap
, num_expected
);
6737 for (i
= num_expected
; i
> 0; i
--) {
6738 char *expected_id
= va_arg(ap
, char *);
6739 char *expected_pool
= va_arg(ap
, char *);
6740 char *expected_image
= va_arg(ap
, char *);
6741 bool expected_trash
= va_arg(ap
, int);
6743 for (j
= 0; j
< num_children
; j
++) {
6744 if (children
[j
].pool_name
== NULL
||
6745 children
[j
].image_name
== NULL
||
6746 children
[j
].image_id
== NULL
)
6748 if (strcmp(children
[j
].image_id
, expected_id
) == 0 &&
6749 strcmp(children
[j
].pool_name
, expected_pool
) == 0 &&
6750 strcmp(children
[j
].image_name
, expected_image
) == 0 &&
6751 children
[j
].trash
== expected_trash
) {
6752 printf("found child %s/%s/%s\n\n", children
[j
].pool_name
, children
[j
].image_name
, children
[j
].image_id
);
6753 rbd_list_child_cleanup(&children
[j
]);
6754 children
[j
].pool_name
= NULL
;
6755 children
[j
].image_name
= NULL
;
6756 children
[j
].image_id
= NULL
;
6765 for (i
= 0; i
< num_children
; i
++) {
6766 EXPECT_EQ((const char *)0, children
[i
].pool_name
);
6767 EXPECT_EQ((const char *)0, children
[i
].image_name
);
6768 EXPECT_EQ((const char *)0, children
[i
].image_id
);
6772 TEST_F(TestLibRBD
, ListChildren
)
6774 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6777 rados_ioctx_t ioctx1
, ioctx2
;
6778 string pool_name1
= create_pool(true);
6779 string pool_name2
= create_pool(true);
6780 ASSERT_NE("", pool_name2
);
6782 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
6783 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
6795 ASSERT_EQ(0, get_features(&old_format
, &features
));
6796 ASSERT_FALSE(old_format
);
6798 std::string parent_name
= get_temp_image_name();
6799 std::string child_name1
= get_temp_image_name();
6800 std::string child_name2
= get_temp_image_name();
6801 std::string child_name3
= get_temp_image_name();
6802 std::string child_name4
= get_temp_image_name();
6804 char child_id1
[4096];
6805 char child_id2
[4096];
6806 char child_id3
[4096];
6807 char child_id4
[4096];
6809 // make a parent to clone from
6810 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
6812 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
6813 // create a snapshot, reopen as the parent we're interested in
6814 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6815 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
6816 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
6818 ASSERT_EQ(0, rbd_close(parent
));
6819 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
6821 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
6822 ioctx2
, child_name1
.c_str(), features
, &order
));
6823 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
6824 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
6825 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
6826 test_list_children2(parent
, 1,
6827 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
6829 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
6830 ioctx1
, child_name2
.c_str(), features
, &order
));
6831 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
6832 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
6833 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
6834 pool_name1
.c_str(), child_name2
.c_str());
6835 test_list_children2(parent
, 2,
6836 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
6837 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
6839 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
6840 ioctx2
, child_name3
.c_str(), features
, &order
));
6841 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
6842 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
6843 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
6844 pool_name1
.c_str(), child_name2
.c_str(),
6845 pool_name2
.c_str(), child_name3
.c_str());
6846 test_list_children2(parent
, 3,
6847 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
6848 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
6849 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
6851 librados::IoCtx ioctx3
;
6852 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
6853 ASSERT_EQ(0, rbd_close(image3
));
6854 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
6855 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
6856 pool_name1
.c_str(), child_name2
.c_str());
6857 test_list_children2(parent
, 3,
6858 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
6859 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
6860 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
6862 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
6863 ioctx2
, child_name4
.c_str(), features
, &order
));
6864 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
6865 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
6866 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
6867 pool_name1
.c_str(), child_name2
.c_str(),
6868 pool_name2
.c_str(), child_name4
.c_str());
6869 test_list_children2(parent
, 4,
6870 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
6871 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
6872 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
6873 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
6875 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
6876 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
6877 pool_name1
.c_str(), child_name2
.c_str(),
6878 pool_name2
.c_str(), child_name3
.c_str(),
6879 pool_name2
.c_str(), child_name4
.c_str());
6880 test_list_children2(parent
, 4,
6881 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
6882 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
6883 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
6884 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
6886 ASSERT_EQ(0, rbd_close(image1
));
6887 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
6888 test_list_children(parent
, 3,
6889 pool_name1
.c_str(), child_name2
.c_str(),
6890 pool_name2
.c_str(), child_name3
.c_str(),
6891 pool_name2
.c_str(), child_name4
.c_str());
6892 test_list_children2(parent
, 3,
6893 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
6894 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
6895 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
6897 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
6898 test_list_children(parent
, 2,
6899 pool_name1
.c_str(), child_name2
.c_str(),
6900 pool_name2
.c_str(), child_name4
.c_str());
6901 test_list_children2(parent
, 2,
6902 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
6903 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
6905 ASSERT_EQ(0, rbd_close(image4
));
6906 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
6907 test_list_children(parent
, 1,
6908 pool_name1
.c_str(), child_name2
.c_str());
6909 test_list_children2(parent
, 1,
6910 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
6913 ASSERT_EQ(0, rbd_close(image2
));
6914 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
6915 test_list_children(parent
, 0);
6916 test_list_children2(parent
, 0);
6918 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
6919 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
6920 ASSERT_EQ(0, rbd_close(parent
));
6921 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
6922 rados_ioctx_destroy(ioctx1
);
6923 rados_ioctx_destroy(ioctx2
);
6926 TEST_F(TestLibRBD
, ListChildrenTiered
)
6929 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6932 string pool_name1
= create_pool(true);
6933 string pool_name2
= create_pool(true);
6934 string pool_name3
= create_pool(true);
6935 ASSERT_NE("", pool_name1
);
6936 ASSERT_NE("", pool_name2
);
6937 ASSERT_NE("", pool_name3
);
6939 std::string cmdstr
= "{\"prefix\": \"osd tier add\", \"pool\": \"" +
6940 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\", \"force_nonempty\":\"\"}";
6942 cmd
[0] = (char *)cmdstr
.c_str();
6943 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
6945 cmdstr
= "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
6946 pool_name3
+ "\", \"mode\":\"writeback\"}";
6947 cmd
[0] = (char *)cmdstr
.c_str();
6948 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
6950 cmdstr
= "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
6951 pool_name1
+ "\", \"overlaypool\":\"" + pool_name3
+ "\"}";
6952 cmd
[0] = (char *)cmdstr
.c_str();
6953 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
6955 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
6957 string parent_name
= get_temp_image_name();
6958 string child_name1
= get_temp_image_name();
6959 string child_name2
= get_temp_image_name();
6960 string child_name3
= get_temp_image_name();
6961 string child_name4
= get_temp_image_name();
6963 char child_id1
[4096];
6964 char child_id2
[4096];
6965 char child_id3
[4096];
6966 char child_id4
[4096];
6973 rados_ioctx_t ioctx1
, ioctx2
;
6974 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
6975 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
6982 ASSERT_EQ(0, get_features(&old_format
, &features
));
6983 ASSERT_FALSE(old_format
);
6985 // make a parent to clone from
6986 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
6988 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
6989 // create a snapshot, reopen as the parent we're interested in
6990 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6991 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
6992 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
6994 ASSERT_EQ(0, rbd_close(parent
));
6995 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
6997 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
6998 ioctx2
, child_name1
.c_str(), features
, &order
));
6999 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
7000 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
7001 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
7002 test_list_children2(parent
, 1,
7003 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
7005 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
7006 ioctx1
, child_name2
.c_str(), features
, &order
));
7007 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
7008 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
7009 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
7010 pool_name1
.c_str(), child_name2
.c_str());
7011 test_list_children2(parent
, 2,
7012 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
7013 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
7015 // read from the cache to populate it
7016 rbd_image_t tier_image
;
7017 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &tier_image
, NULL
));
7018 size_t len
= 4 * 1024 * 1024;
7019 char* buf
= (char*)malloc(len
);
7020 ssize_t size
= rbd_read(tier_image
, 0, len
, buf
);
7023 ASSERT_EQ(0, rbd_close(tier_image
));
7025 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
7026 ioctx2
, child_name3
.c_str(), features
, &order
));
7027 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
7028 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
7029 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
7030 pool_name1
.c_str(), child_name2
.c_str(),
7031 pool_name2
.c_str(), child_name3
.c_str());
7032 test_list_children2(parent
, 3,
7033 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
7034 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
7035 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
7037 librados::IoCtx ioctx3
;
7038 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
7039 ASSERT_EQ(0, rbd_close(image3
));
7040 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
7041 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
7042 pool_name1
.c_str(), child_name2
.c_str());
7043 test_list_children2(parent
, 3,
7044 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
7045 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
7046 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
7048 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
7049 ioctx2
, child_name4
.c_str(), features
, &order
));
7050 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
7051 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
7052 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
7053 pool_name1
.c_str(), child_name2
.c_str(),
7054 pool_name2
.c_str(), child_name4
.c_str());
7055 test_list_children2(parent
, 4,
7056 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
7057 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
7058 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
7059 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
7061 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
7062 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
7063 pool_name1
.c_str(), child_name2
.c_str(),
7064 pool_name2
.c_str(), child_name3
.c_str(),
7065 pool_name2
.c_str(), child_name4
.c_str());
7066 test_list_children2(parent
, 4,
7067 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
7068 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
7069 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
7070 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
7072 ASSERT_EQ(0, rbd_close(image1
));
7073 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
7074 test_list_children(parent
, 3,
7075 pool_name1
.c_str(), child_name2
.c_str(),
7076 pool_name2
.c_str(), child_name3
.c_str(),
7077 pool_name2
.c_str(), child_name4
.c_str());
7078 test_list_children2(parent
, 3,
7079 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
7080 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
7081 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
7083 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
7084 test_list_children(parent
, 2,
7085 pool_name1
.c_str(), child_name2
.c_str(),
7086 pool_name2
.c_str(), child_name4
.c_str());
7087 test_list_children2(parent
, 2,
7088 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
7089 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
7091 ASSERT_EQ(0, rbd_close(image4
));
7092 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
7093 test_list_children(parent
, 1,
7094 pool_name1
.c_str(), child_name2
.c_str());
7095 test_list_children2(parent
, 1,
7096 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
7098 ASSERT_EQ(0, rbd_close(image2
));
7099 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
7100 test_list_children(parent
, 0);
7101 test_list_children2(parent
, 0);
7103 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
7104 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
7105 ASSERT_EQ(0, rbd_close(parent
));
7106 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
7107 rados_ioctx_destroy(ioctx1
);
7108 rados_ioctx_destroy(ioctx2
);
7109 cmdstr
= "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
7111 cmd
[0] = (char *)cmdstr
.c_str();
7112 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
7113 cmdstr
= "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
7114 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\"}";
7115 cmd
[0] = (char *)cmdstr
.c_str();
7116 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
7119 TEST_F(TestLibRBD
, LockingPP
)
7121 librados::IoCtx ioctx
;
7122 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7126 librbd::Image image
;
7128 std::string name
= get_temp_image_name();
7129 uint64_t size
= 2 << 20;
7130 std::string cookie1
= "foo";
7131 std::string cookie2
= "bar";
7133 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7134 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7136 // no lockers initially
7137 std::list
<librbd::locker_t
> lockers
;
7140 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
7141 ASSERT_EQ(0u, lockers
.size());
7144 // exclusive lock is exclusive
7145 ASSERT_EQ(0, image
.lock_exclusive(cookie1
));
7146 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
7147 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
7148 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
7149 ASSERT_EQ(-EBUSY
, image
.lock_shared(cookie1
, "test"));
7150 ASSERT_EQ(-EBUSY
, image
.lock_shared("", "test"));
7151 ASSERT_EQ(-EBUSY
, image
.lock_shared("", ""));
7154 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
7155 ASSERT_TRUE(exclusive
);
7157 ASSERT_EQ(1u, lockers
.size());
7158 ASSERT_EQ(cookie1
, lockers
.front().cookie
);
7161 ASSERT_EQ(-ENOENT
, image
.unlock(""));
7162 ASSERT_EQ(-ENOENT
, image
.unlock(cookie2
));
7163 ASSERT_EQ(0, image
.unlock(cookie1
));
7164 ASSERT_EQ(-ENOENT
, image
.unlock(cookie1
));
7165 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
7166 ASSERT_EQ(0u, lockers
.size());
7168 ASSERT_EQ(0, image
.lock_shared(cookie1
, ""));
7169 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
7170 ASSERT_EQ(0, image
.lock_shared(cookie2
, ""));
7171 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie2
, ""));
7172 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
7173 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie2
));
7174 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
7175 ASSERT_EQ(-EBUSY
, image
.lock_exclusive("test"));
7178 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
7179 ASSERT_EQ(2u, lockers
.size());
7185 TEST_F(TestLibRBD
, FlushAio
)
7187 rados_ioctx_t ioctx
;
7188 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7192 std::string name
= get_temp_image_name();
7193 uint64_t size
= 2 << 20;
7194 size_t num_aios
= 256;
7196 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7197 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7199 char test_data
[TEST_IO_SIZE
+ 1];
7201 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
7202 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
7205 rbd_completion_t write_comps
[num_aios
];
7206 for (i
= 0; i
< num_aios
; ++i
) {
7207 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &write_comps
[i
]));
7208 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
7209 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
7213 rbd_completion_t flush_comp
;
7214 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &flush_comp
));
7215 ASSERT_EQ(0, rbd_aio_flush(image
, flush_comp
));
7216 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp
));
7217 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp
));
7218 rbd_aio_release(flush_comp
);
7220 for (i
= 0; i
< num_aios
; ++i
) {
7221 ASSERT_EQ(1, rbd_aio_is_complete(write_comps
[i
]));
7222 rbd_aio_release(write_comps
[i
]);
7225 ASSERT_PASSED(validate_object_map
, image
);
7226 ASSERT_EQ(0, rbd_close(image
));
7227 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
7228 rados_ioctx_destroy(ioctx
);
7231 TEST_F(TestLibRBD
, FlushAioPP
)
7233 librados::IoCtx ioctx
;
7234 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7238 librbd::Image image
;
7240 std::string name
= get_temp_image_name();
7241 uint64_t size
= 2 << 20;
7242 const size_t num_aios
= 256;
7244 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7245 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7247 char test_data
[TEST_IO_SIZE
+ 1];
7249 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
7250 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
7252 test_data
[TEST_IO_SIZE
] = '\0';
7254 librbd::RBD::AioCompletion
*write_comps
[num_aios
];
7255 ceph::bufferlist bls
[num_aios
];
7256 for (i
= 0; i
< num_aios
; ++i
) {
7257 bls
[i
].append(test_data
, strlen(test_data
));
7258 write_comps
[i
] = new librbd::RBD::AioCompletion(NULL
, NULL
);
7259 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
7260 ASSERT_EQ(0, image
.aio_write(offset
, TEST_IO_SIZE
, bls
[i
],
7264 librbd::RBD::AioCompletion
*flush_comp
=
7265 new librbd::RBD::AioCompletion(NULL
, NULL
);
7266 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
7267 ASSERT_EQ(0, flush_comp
->wait_for_complete());
7268 ASSERT_EQ(1, flush_comp
->is_complete());
7269 flush_comp
->release();
7271 for (i
= 0; i
< num_aios
; ++i
) {
7272 librbd::RBD::AioCompletion
*comp
= write_comps
[i
];
7273 ASSERT_EQ(1, comp
->is_complete());
7276 ASSERT_PASSED(validate_object_map
, image
);
7283 int iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
7285 //cout << "iterate_cb " << off << "~" << len << std::endl;
7286 interval_set
<uint64_t> *diff
= static_cast<interval_set
<uint64_t> *>(arg
);
7287 diff
->insert(off
, len
);
7291 static int iterate_error_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
7296 void scribble(librbd::Image
& image
, int n
, int max
, bool skip_discard
,
7297 interval_set
<uint64_t> *exists
,
7298 interval_set
<uint64_t> *what
)
7302 interval_set
<uint64_t> exists_at_start
= *exists
;
7304 for (int i
=0; i
<n
; i
++) {
7305 uint64_t off
= rand() % (size
- max
+ 1);
7306 uint64_t len
= 1 + rand() % max
;
7307 if (!skip_discard
&& rand() % 4 == 0) {
7308 ASSERT_EQ((int)len
, image
.discard(off
, len
));
7309 interval_set
<uint64_t> w
;
7312 // the zeroed bit no longer exists...
7313 w
.intersection_of(*exists
);
7314 exists
->subtract(w
);
7316 // the bits we discarded are no long written...
7317 interval_set
<uint64_t> w2
= w
;
7318 w2
.intersection_of(*what
);
7321 // except for the extents that existed at the start that we overwrote.
7322 interval_set
<uint64_t> w3
;
7323 w3
.insert(off
, len
);
7324 w3
.intersection_of(exists_at_start
);
7329 bl
.append(buffer::create(len
));
7331 ASSERT_EQ((int)len
, image
.write(off
, len
, bl
));
7332 interval_set
<uint64_t> w
;
7335 exists
->union_of(w
);
7340 interval_set
<uint64_t> round_diff_interval(const interval_set
<uint64_t>& diff
,
7341 uint64_t object_size
)
7343 if (object_size
== 0) {
7347 interval_set
<uint64_t> rounded_diff
;
7348 for (interval_set
<uint64_t>::const_iterator it
= diff
.begin();
7349 it
!= diff
.end(); ++it
) {
7350 uint64_t off
= it
.get_start();
7351 uint64_t len
= it
.get_len();
7352 off
-= off
% object_size
;
7353 len
+= (object_size
- (len
% object_size
));
7354 interval_set
<uint64_t> interval
;
7355 interval
.insert(off
, len
);
7356 rounded_diff
.union_of(interval
);
7358 return rounded_diff
;
7361 TEST_F(TestLibRBD
, SnapDiff
)
7363 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
7365 rados_ioctx_t ioctx
;
7366 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7370 std::string image_name
= get_temp_image_name();
7371 uint64_t size
= 100 << 20;
7372 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), size
, &order
));
7373 ASSERT_EQ(0, rbd_open(ioctx
, image_name
.c_str(), &image
, nullptr));
7375 char test_data
[TEST_IO_SIZE
+ 1];
7376 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
7377 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
7379 test_data
[TEST_IO_SIZE
] = '\0';
7381 ASSERT_PASSED(write_test_data
, image
, test_data
, 0,
7382 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
7384 interval_set
<uint64_t> diff
;
7385 ASSERT_EQ(0, rbd_diff_iterate2(image
, nullptr, 0, size
, true, true,
7386 iterate_cb
, &diff
));
7387 EXPECT_EQ(1 << order
, diff
.size());
7389 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
7390 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
7393 ASSERT_EQ(0, rbd_diff_iterate2(image
, nullptr, 0, size
, true, true,
7394 iterate_cb
, &diff
));
7395 EXPECT_EQ(1 << order
, diff
.size());
7398 ASSERT_EQ(0, rbd_diff_iterate2(image
, "snap1", 0, size
, true, true,
7399 iterate_cb
, &diff
));
7400 EXPECT_EQ(0, diff
.size());
7403 ASSERT_EQ(0, rbd_diff_iterate2(image
, "snap2", 0, size
, true, true,
7404 iterate_cb
, &diff
));
7405 EXPECT_EQ(0, diff
.size());
7407 ASSERT_EQ(0, rbd_snap_remove(image
, "snap1"));
7408 ASSERT_EQ(0, rbd_snap_remove(image
, "snap2"));
7410 ASSERT_EQ(0, rbd_close(image
));
7411 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
7413 rados_ioctx_destroy(ioctx
);
7416 template <typename T
>
7417 class DiffIterateTest
: public TestLibRBD
{
7419 static const uint8_t whole_object
= T::whole_object
;
7422 template <bool _whole_object
>
7423 class DiffIterateParams
{
7425 static const uint8_t whole_object
= _whole_object
;
7428 typedef ::testing::Types
<DiffIterateParams
<false>,
7429 DiffIterateParams
<true> > DiffIterateTypes
;
7430 TYPED_TEST_SUITE(DiffIterateTest
, DiffIterateTypes
);
7432 TYPED_TEST(DiffIterateTest
, DiffIterate
)
7434 librados::IoCtx ioctx
;
7435 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7439 librbd::Image image
;
7441 std::string name
= this->get_temp_image_name();
7442 uint64_t size
= 20 << 20;
7444 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7445 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7447 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
7449 uint64_t object_size
= 0;
7450 if (this->whole_object
) {
7451 object_size
= 1 << order
;
7454 interval_set
<uint64_t> exists
;
7455 interval_set
<uint64_t> one
, two
;
7456 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
7457 cout
<< " wrote " << one
<< std::endl
;
7458 ASSERT_EQ(0, image
.snap_create("one"));
7459 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
7461 two
= round_diff_interval(two
, object_size
);
7462 cout
<< " wrote " << two
<< std::endl
;
7464 interval_set
<uint64_t> diff
;
7465 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
7466 iterate_cb
, (void *)&diff
));
7467 cout
<< " diff was " << diff
<< std::endl
;
7468 if (!two
.subset_of(diff
)) {
7469 interval_set
<uint64_t> i
;
7470 i
.intersection_of(two
, diff
);
7471 interval_set
<uint64_t> l
= two
;
7473 cout
<< " ... two - (two*diff) = " << l
<< std::endl
;
7475 ASSERT_TRUE(two
.subset_of(diff
));
7480 struct diff_extent
{
7481 diff_extent(uint64_t _offset
, uint64_t _length
, bool _exists
,
7482 uint64_t object_size
) :
7483 offset(_offset
), length(_length
), exists(_exists
)
7485 if (object_size
!= 0) {
7486 offset
-= offset
% object_size
;
7487 length
= object_size
;
7493 bool operator==(const diff_extent
& o
) const {
7494 return offset
== o
.offset
&& length
== o
.length
&& exists
== o
.exists
;
7498 ostream
& operator<<(ostream
& o
, const diff_extent
& e
) {
7499 return o
<< '(' << e
.offset
<< '~' << e
.length
<< ' ' << (e
.exists
? "true" : "false") << ')';
7502 int vector_iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
7504 cout
<< "iterate_cb " << off
<< "~" << len
<< std::endl
;
7505 vector
<diff_extent
> *diff
= static_cast<vector
<diff_extent
> *>(arg
);
7506 diff
->push_back(diff_extent(off
, len
, exists
, 0));
7510 TYPED_TEST(DiffIterateTest
, DiffIterateDiscard
)
7512 librados::IoCtx ioctx
;
7513 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7516 librbd::Image image
;
7518 std::string name
= this->get_temp_image_name();
7519 uint64_t size
= 20 << 20;
7521 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7522 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7524 uint64_t object_size
= 0;
7525 if (this->whole_object
) {
7526 object_size
= 1 << order
;
7528 vector
<diff_extent
> extents
;
7529 ceph::bufferlist bl
;
7531 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7532 vector_iterate_cb
, (void *) &extents
));
7533 ASSERT_EQ(0u, extents
.size());
7536 memset(data
, 1, sizeof(data
));
7537 bl
.append(data
, 256);
7538 ASSERT_EQ(256, image
.write(0, 256, bl
));
7539 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7540 vector_iterate_cb
, (void *) &extents
));
7541 ASSERT_EQ(1u, extents
.size());
7542 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
7545 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
7548 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7549 vector_iterate_cb
, (void *) &extents
));
7550 ASSERT_EQ(0u, extents
.size());
7552 ASSERT_EQ(0, image
.snap_create("snap1"));
7553 ASSERT_EQ(256, image
.write(0, 256, bl
));
7554 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7555 vector_iterate_cb
, (void *) &extents
));
7556 ASSERT_EQ(1u, extents
.size());
7557 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
7558 ASSERT_EQ(0, image
.snap_create("snap2"));
7560 ASSERT_EQ(obj_ofs
, image
.discard(0, obj_ofs
));
7563 ASSERT_EQ(0, image
.snap_set("snap2"));
7564 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
7565 vector_iterate_cb
, (void *) &extents
));
7566 ASSERT_EQ(1u, extents
.size());
7567 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
7569 ASSERT_EQ(0, image
.snap_set(NULL
));
7570 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
7571 ASSERT_EQ(0, image
.snap_create("snap3"));
7572 ASSERT_EQ(0, image
.snap_set("snap3"));
7575 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
7576 vector_iterate_cb
, (void *) &extents
));
7577 ASSERT_EQ(1u, extents
.size());
7578 ASSERT_EQ(diff_extent(0, 256, false, object_size
), extents
[0]);
7579 ASSERT_PASSED(this->validate_object_map
, image
);
7582 TYPED_TEST(DiffIterateTest
, DiffIterateStress
)
7584 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)this->_rados
.cct()));
7585 librados::IoCtx ioctx
;
7586 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7589 librbd::Image image
;
7591 std::string name
= this->get_temp_image_name();
7592 uint64_t size
= 400 << 20;
7594 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7595 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7597 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
7599 uint64_t object_size
= 0;
7600 if (this->whole_object
) {
7601 object_size
= 1 << order
;
7604 interval_set
<uint64_t> curexists
;
7605 vector
<interval_set
<uint64_t> > wrote
;
7606 vector
<interval_set
<uint64_t> > exists
;
7607 vector
<string
> snap
;
7609 for (int i
=0; i
<n
; i
++) {
7610 interval_set
<uint64_t> w
;
7611 scribble(image
, 10, 8192000, skip_discard
, &curexists
, &w
);
7612 cout
<< " i=" << i
<< " exists " << curexists
<< " wrote " << w
<< std::endl
;
7613 string s
= "snap" + stringify(i
);
7614 ASSERT_EQ(0, image
.snap_create(s
.c_str()));
7616 exists
.push_back(curexists
);
7620 for (int h
=0; h
<n
-1; h
++) {
7621 for (int i
=0; i
<n
-h
-1; i
++) {
7622 for (int j
=(h
==0 ? i
+1 : n
-1); j
<n
; j
++) {
7623 interval_set
<uint64_t> diff
, actual
, uex
;
7624 for (int k
=i
+1; k
<=j
; k
++)
7625 diff
.union_of(wrote
[k
]);
7626 cout
<< "from " << i
<< " to "
7627 << (h
!= 0 ? string("HEAD") : stringify(j
)) << " diff "
7628 << round_diff_interval(diff
, object_size
) << std::endl
;
7630 // limit to extents that exists both at the beginning and at the end
7631 uex
.union_of(exists
[i
], exists
[j
]);
7632 diff
.intersection_of(uex
);
7633 diff
= round_diff_interval(diff
, object_size
);
7634 cout
<< " limited diff " << diff
<< std::endl
;
7636 ASSERT_EQ(0, image
.snap_set(h
==0 ? snap
[j
].c_str() : NULL
));
7637 ASSERT_EQ(0, image
.diff_iterate2(snap
[i
].c_str(), 0, size
, true,
7638 this->whole_object
, iterate_cb
,
7640 cout
<< " actual was " << actual
<< std::endl
;
7641 if (!diff
.subset_of(actual
)) {
7642 interval_set
<uint64_t> i
;
7643 i
.intersection_of(diff
, actual
);
7644 interval_set
<uint64_t> l
= diff
;
7646 cout
<< " ... diff - (actual*diff) = " << l
<< std::endl
;
7648 ASSERT_TRUE(diff
.subset_of(actual
));
7651 ASSERT_EQ(0, image
.snap_set(NULL
));
7652 ASSERT_EQ(0, image
.snap_remove(snap
[n
-h
-1].c_str()));
7655 ASSERT_PASSED(this->validate_object_map
, image
);
7658 TYPED_TEST(DiffIterateTest
, DiffIterateRegression6926
)
7660 librados::IoCtx ioctx
;
7661 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7664 librbd::Image image
;
7666 std::string name
= this->get_temp_image_name();
7667 uint64_t size
= 20 << 20;
7669 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7670 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7672 uint64_t object_size
= 0;
7673 if (this->whole_object
) {
7674 object_size
= 1 << order
;
7676 vector
<diff_extent
> extents
;
7677 ceph::bufferlist bl
;
7679 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7680 vector_iterate_cb
, (void *) &extents
));
7681 ASSERT_EQ(0u, extents
.size());
7683 ASSERT_EQ(0, image
.snap_create("snap1"));
7685 memset(data
, 1, sizeof(data
));
7686 bl
.append(data
, 256);
7687 ASSERT_EQ(256, image
.write(0, 256, bl
));
7690 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7691 vector_iterate_cb
, (void *) &extents
));
7692 ASSERT_EQ(1u, extents
.size());
7693 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
7695 ASSERT_EQ(0, image
.snap_set("snap1"));
7697 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7698 vector_iterate_cb
, (void *) &extents
));
7699 ASSERT_EQ(static_cast<size_t>(0), extents
.size());
7702 TYPED_TEST(DiffIterateTest
, DiffIterateParent
)
7704 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7706 librados::IoCtx ioctx
;
7707 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7711 librbd::Image image
;
7713 std::string name
= this->get_temp_image_name();
7714 ssize_t size
= 20 << 20;
7716 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7717 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7720 ASSERT_EQ(0, image
.features(&features
));
7721 uint64_t object_size
= 0;
7722 if (this->whole_object
) {
7723 object_size
= 1 << order
;
7726 ceph::bufferlist bl
;
7727 bl
.append(std::string(size
, '1'));
7728 ASSERT_EQ(size
, image
.write(0, size
, bl
));
7729 ASSERT_EQ(0, image
.snap_create("snap"));
7730 ASSERT_EQ(0, image
.snap_protect("snap"));
7732 std::string clone_name
= this->get_temp_image_name();
7733 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
,
7734 clone_name
.c_str(), features
, &order
));
7735 librbd::Image clone
;
7736 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
7738 std::vector
<diff_extent
> extents
;
7739 ASSERT_EQ(0, clone
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7740 vector_iterate_cb
, &extents
));
7741 ASSERT_EQ(5u, extents
.size());
7742 ASSERT_EQ(diff_extent(0, 4194304, true, object_size
), extents
[0]);
7743 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size
), extents
[1]);
7744 ASSERT_EQ(diff_extent(8388608, 4194304, true, object_size
), extents
[2]);
7745 ASSERT_EQ(diff_extent(12582912, 4194304, true, object_size
), extents
[3]);
7746 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size
), extents
[4]);
7749 ASSERT_EQ(0, clone
.resize(size
/ 2));
7750 ASSERT_EQ(0, clone
.resize(size
));
7751 ASSERT_EQ(1, clone
.write(size
- 1, 1, bl
));
7753 ASSERT_EQ(0, clone
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7754 vector_iterate_cb
, &extents
));
7755 ASSERT_EQ(4u, extents
.size());
7756 ASSERT_EQ(diff_extent(0, 4194304, true, object_size
), extents
[0]);
7757 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size
), extents
[1]);
7758 ASSERT_EQ(diff_extent(8388608, 2097152, true, object_size
), extents
[2]);
7759 // hole (parent overlap = 10M) followed by copyup'ed object
7760 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size
), extents
[3]);
7762 ASSERT_PASSED(this->validate_object_map
, image
);
7763 ASSERT_PASSED(this->validate_object_map
, clone
);
7769 TYPED_TEST(DiffIterateTest
, DiffIterateIgnoreParent
)
7771 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7773 librados::IoCtx ioctx
;
7774 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7777 librbd::Image image
;
7778 std::string name
= this->get_temp_image_name();
7779 uint64_t size
= 20 << 20;
7782 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7783 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7785 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
7788 ASSERT_EQ(0, image
.features(&features
));
7789 uint64_t object_size
= 0;
7790 if (this->whole_object
) {
7791 object_size
= 1 << order
;
7795 bl
.append(buffer::create(size
));
7797 interval_set
<uint64_t> one
;
7798 one
.insert(0, size
);
7799 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
7800 ASSERT_EQ(0, image
.snap_create("one"));
7801 ASSERT_EQ(0, image
.snap_protect("one"));
7803 std::string clone_name
= this->get_temp_image_name();
7804 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
7806 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
7808 interval_set
<uint64_t> exists
;
7809 interval_set
<uint64_t> two
;
7810 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
7811 two
= round_diff_interval(two
, object_size
);
7812 cout
<< " wrote " << two
<< " to clone" << std::endl
;
7814 interval_set
<uint64_t> diff
;
7815 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, false, this->whole_object
,
7816 iterate_cb
, (void *)&diff
));
7817 cout
<< " diff was " << diff
<< std::endl
;
7818 if (!this->whole_object
) {
7819 ASSERT_FALSE(one
.subset_of(diff
));
7821 ASSERT_TRUE(two
.subset_of(diff
));
7824 TYPED_TEST(DiffIterateTest
, DiffIterateCallbackError
)
7826 librados::IoCtx ioctx
;
7827 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7831 librbd::Image image
;
7833 std::string name
= this->get_temp_image_name();
7834 uint64_t size
= 20 << 20;
7836 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7837 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7839 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
7841 interval_set
<uint64_t> exists
;
7842 interval_set
<uint64_t> one
;
7843 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
7844 cout
<< " wrote " << one
<< std::endl
;
7846 interval_set
<uint64_t> diff
;
7847 ASSERT_EQ(-EINVAL
, image
.diff_iterate2(NULL
, 0, size
, true,
7849 iterate_error_cb
, NULL
));
7854 TYPED_TEST(DiffIterateTest
, DiffIterateParentDiscard
)
7856 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7858 librados::IoCtx ioctx
;
7859 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7862 librbd::Image image
;
7863 std::string name
= this->get_temp_image_name();
7864 uint64_t size
= 20 << 20;
7867 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7868 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7870 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
7873 ASSERT_EQ(0, image
.features(&features
));
7874 uint64_t object_size
= 0;
7875 if (this->whole_object
) {
7876 object_size
= 1 << order
;
7879 interval_set
<uint64_t> exists
;
7880 interval_set
<uint64_t> one
;
7881 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
7882 ASSERT_EQ(0, image
.snap_create("one"));
7884 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
7885 ASSERT_EQ(0, image
.snap_create("two"));
7886 ASSERT_EQ(0, image
.snap_protect("two"));
7890 std::string clone_name
= this->get_temp_image_name();
7891 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "two", ioctx
,
7892 clone_name
.c_str(), features
, &order
));
7893 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
7895 interval_set
<uint64_t> two
;
7896 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
7897 two
= round_diff_interval(two
, object_size
);
7899 interval_set
<uint64_t> diff
;
7900 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
7901 iterate_cb
, (void *)&diff
));
7902 ASSERT_TRUE(two
.subset_of(diff
));
7905 TYPED_TEST(DiffIterateTest
, DiffIterateUnalignedSmall
)
7907 librados::IoCtx ioctx
;
7908 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7912 librbd::Image image
;
7914 std::string name
= this->get_temp_image_name();
7915 ssize_t size
= 10 << 20;
7917 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7918 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7920 ceph::bufferlist bl
;
7921 bl
.append(std::string(size
, '1'));
7922 ASSERT_EQ(size
, image
.write(0, size
, bl
));
7924 std::vector
<diff_extent
> extents
;
7925 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 5000005, 1234, true,
7926 this->whole_object
, vector_iterate_cb
,
7928 ASSERT_EQ(1u, extents
.size());
7929 ASSERT_EQ(diff_extent(5000005, 1234, true, 0), extents
[0]);
7931 ASSERT_PASSED(this->validate_object_map
, image
);
7937 TYPED_TEST(DiffIterateTest
, DiffIterateUnaligned
)
7939 librados::IoCtx ioctx
;
7940 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7944 librbd::Image image
;
7946 std::string name
= this->get_temp_image_name();
7947 ssize_t size
= 20 << 20;
7949 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7950 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7952 ceph::bufferlist bl
;
7953 bl
.append(std::string(size
, '1'));
7954 ASSERT_EQ(size
, image
.write(0, size
, bl
));
7956 std::vector
<diff_extent
> extents
;
7957 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 8376263, 4260970, true,
7958 this->whole_object
, vector_iterate_cb
,
7960 ASSERT_EQ(3u, extents
.size());
7961 ASSERT_EQ(diff_extent(8376263, 12345, true, 0), extents
[0]);
7962 ASSERT_EQ(diff_extent(8388608, 4194304, true, 0), extents
[1]);
7963 ASSERT_EQ(diff_extent(12582912, 54321, true, 0), extents
[2]);
7965 ASSERT_PASSED(this->validate_object_map
, image
);
7971 TYPED_TEST(DiffIterateTest
, DiffIterateStriping
)
7973 REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2
);
7975 librados::IoCtx ioctx
;
7976 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
7980 ASSERT_EQ(0, get_features(&old_format
, &features
));
7981 ASSERT_FALSE(old_format
);
7985 librbd::Image image
;
7987 std::string name
= this->get_temp_image_name();
7988 ssize_t size
= 24 << 20;
7990 ASSERT_EQ(0, rbd
.create3(ioctx
, name
.c_str(), size
, features
, &order
,
7992 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7994 ceph::bufferlist bl
;
7995 bl
.append(std::string(size
, '1'));
7996 ASSERT_EQ(size
, image
.write(0, size
, bl
));
7998 std::vector
<diff_extent
> extents
;
7999 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
8000 vector_iterate_cb
, &extents
));
8001 ASSERT_EQ(2u, extents
.size());
8002 ASSERT_EQ(diff_extent(0, 12 << 20, true, 0), extents
[0]);
8003 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents
[1]);
8006 ASSERT_EQ(0, image
.snap_create("one"));
8007 ASSERT_EQ(size
, image
.discard(0, size
));
8009 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
8010 vector_iterate_cb
, &extents
));
8011 ASSERT_EQ(2u, extents
.size());
8012 ASSERT_EQ(diff_extent(0, 12 << 20, false, 0), extents
[0]);
8013 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, false, 0), extents
[1]);
8016 ASSERT_EQ(1 << 20, image
.write(0, 1 << 20, bl
));
8017 ASSERT_EQ(2 << 20, image
.write(2 << 20, 2 << 20, bl
));
8018 ASSERT_EQ(2 << 20, image
.write(5 << 20, 2 << 20, bl
));
8019 ASSERT_EQ(2 << 20, image
.write(8 << 20, 2 << 20, bl
));
8020 ASSERT_EQ(13 << 20, image
.write(11 << 20, 13 << 20, bl
));
8022 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
8023 vector_iterate_cb
, &extents
));
8024 ASSERT_EQ(10u, extents
.size());
8025 ASSERT_EQ(diff_extent(0, 1 << 20, true, 0), extents
[0]);
8026 ASSERT_EQ(diff_extent(1 << 20, 1 << 20, false, 0), extents
[1]);
8027 ASSERT_EQ(diff_extent(2 << 20, 2 << 20, true, 0), extents
[2]);
8028 ASSERT_EQ(diff_extent(4 << 20, 1 << 20, false, 0), extents
[3]);
8029 ASSERT_EQ(diff_extent(5 << 20, 2 << 20, true, 0), extents
[4]);
8030 ASSERT_EQ(diff_extent(7 << 20, 1 << 20, false, 0), extents
[5]);
8031 ASSERT_EQ(diff_extent(8 << 20, 2 << 20, true, 0), extents
[6]);
8032 ASSERT_EQ(diff_extent(10 << 20, 1 << 20, false, 0), extents
[7]);
8033 ASSERT_EQ(diff_extent(11 << 20, 1 << 20, true, 0), extents
[8]);
8034 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents
[9]);
8036 ASSERT_PASSED(this->validate_object_map
, image
);
8042 TEST_F(TestLibRBD
, ZeroLengthWrite
)
8044 rados_ioctx_t ioctx
;
8045 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8049 std::string name
= get_temp_image_name();
8050 uint64_t size
= 2 << 20;
8052 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8053 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8056 ASSERT_EQ(0, rbd_write(image
, 0, 0, NULL
));
8057 ASSERT_EQ(1, rbd_read(image
, 0, 1, read_data
));
8058 ASSERT_EQ('\0', read_data
[0]);
8060 ASSERT_PASSED(validate_object_map
, image
);
8061 ASSERT_EQ(0, rbd_close(image
));
8063 rados_ioctx_destroy(ioctx
);
8067 TEST_F(TestLibRBD
, ZeroLengthDiscard
)
8069 rados_ioctx_t ioctx
;
8070 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8074 std::string name
= get_temp_image_name();
8075 uint64_t size
= 2 << 20;
8077 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8078 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8080 const char data
[] = "blah";
8081 char read_data
[sizeof(data
)];
8082 ASSERT_EQ((int)strlen(data
), rbd_write(image
, 0, strlen(data
), data
));
8083 ASSERT_EQ(0, rbd_discard(image
, 0, 0));
8084 ASSERT_EQ((int)strlen(data
), rbd_read(image
, 0, strlen(data
), read_data
));
8085 ASSERT_EQ(0, memcmp(data
, read_data
, strlen(data
)));
8087 ASSERT_PASSED(validate_object_map
, image
);
8088 ASSERT_EQ(0, rbd_close(image
));
8090 rados_ioctx_destroy(ioctx
);
8093 TEST_F(TestLibRBD
, ZeroLengthRead
)
8095 rados_ioctx_t ioctx
;
8096 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8100 std::string name
= get_temp_image_name();
8101 uint64_t size
= 2 << 20;
8103 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8104 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8107 ASSERT_EQ(0, rbd_read(image
, 0, 0, read_data
));
8109 ASSERT_EQ(0, rbd_close(image
));
8111 rados_ioctx_destroy(ioctx
);
8114 TEST_F(TestLibRBD
, LargeCacheRead
)
8116 std::string config_value
;
8117 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", config_value
));
8118 if (config_value
== "false") {
8119 GTEST_SKIP() << "Skipping due to disabled cache";
8122 rados_ioctx_t ioctx
;
8123 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8125 uint32_t new_cache_size
= 1 << 20;
8126 std::string orig_cache_size
;
8127 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", orig_cache_size
));
8128 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size",
8129 stringify(new_cache_size
).c_str()));
8130 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", config_value
));
8131 ASSERT_EQ(stringify(new_cache_size
), config_value
);
8132 BOOST_SCOPE_EXIT( (orig_cache_size
) ) {
8133 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size", orig_cache_size
.c_str()));
8134 } BOOST_SCOPE_EXIT_END
;
8138 std::string name
= get_temp_image_name();
8139 uint64_t size
= 1 << order
;
8141 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8142 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8144 std::string
buffer(1 << order
, '1');
8146 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
8147 rbd_write(image
, 0, buffer
.size(), buffer
.c_str()));
8149 ASSERT_EQ(0, rbd_invalidate_cache(image
));
8151 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
8152 rbd_read(image
, 0, buffer
.size(), &buffer
[0]));
8154 ASSERT_EQ(0, rbd_close(image
));
8156 rados_ioctx_destroy(ioctx
);
8159 TEST_F(TestLibRBD
, TestPendingAio
)
8161 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8163 rados_ioctx_t ioctx
;
8164 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8171 ASSERT_EQ(0, get_features(&old_format
, &features
));
8172 ASSERT_FALSE(old_format
);
8174 std::string name
= get_temp_image_name();
8176 uint64_t size
= 4 << 20;
8177 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
8179 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8181 ASSERT_EQ(0, rbd_invalidate_cache(image
));
8183 char test_data
[TEST_IO_SIZE
];
8184 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
8185 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
8188 size_t num_aios
= 256;
8189 rbd_completion_t comps
[num_aios
];
8190 for (size_t i
= 0; i
< num_aios
; ++i
) {
8191 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
8192 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
8193 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
8196 for (size_t i
= 0; i
< num_aios
; ++i
) {
8197 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps
[i
]));
8198 rbd_aio_release(comps
[i
]);
8200 ASSERT_EQ(0, rbd_invalidate_cache(image
));
8202 for (size_t i
= 0; i
< num_aios
; ++i
) {
8203 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
8204 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
8205 ASSERT_LE(0, rbd_aio_read(image
, offset
, TEST_IO_SIZE
, test_data
,
8209 ASSERT_PASSED(validate_object_map
, image
);
8210 ASSERT_EQ(0, rbd_close(image
));
8211 for (size_t i
= 0; i
< num_aios
; ++i
) {
8212 ASSERT_EQ(1, rbd_aio_is_complete(comps
[i
]));
8213 rbd_aio_release(comps
[i
]);
8216 rados_ioctx_destroy(ioctx
);
8219 void compare_and_write_copyup(librados::IoCtx
&ioctx
, bool deep_copyup
,
8223 std::string parent_name
= TestLibRBD::get_temp_image_name();
8224 uint64_t size
= 2 << 20;
8226 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
8228 librbd::Image parent_image
;
8229 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
8232 bl
.append(std::string(4096, '1'));
8233 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
8235 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
8236 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
8239 ASSERT_EQ(0, parent_image
.features(&features
));
8241 std::string clone_name
= TestLibRBD::get_temp_image_name();
8242 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
8243 clone_name
.c_str(), features
, &order
));
8245 librbd::Image clone_image
;
8246 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
8248 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
8252 cmp_bl
.append(std::string(512, '1'));
8253 bufferlist write_bl
;
8254 write_bl
.append(std::string(512, '2'));
8255 uint64_t mismatch_off
= 0;
8256 ASSERT_EQ((ssize_t
)write_bl
.length(),
8257 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
8258 write_bl
, &mismatch_off
, 0));
8259 ASSERT_EQ(0U, mismatch_off
);
8261 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
8263 bufferlist expected_bl
;
8264 expected_bl
.append(std::string(512, '1'));
8265 expected_bl
.append(std::string(512, '2'));
8266 expected_bl
.append(std::string(3072, '1'));
8267 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
8271 TEST_F(TestLibRBD
, CompareAndWriteCopyup
)
8273 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8275 librados::IoCtx ioctx
;
8276 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8278 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, false);
8279 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, true);
8282 void compare_and_write_copyup_mismatch(librados::IoCtx
&ioctx
,
8283 bool deep_copyup
, bool *passed
)
8286 std::string parent_name
= TestLibRBD::get_temp_image_name();
8287 uint64_t size
= 2 << 20;
8289 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
8291 librbd::Image parent_image
;
8292 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
8295 bl
.append(std::string(4096, '1'));
8296 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
8298 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
8299 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
8302 ASSERT_EQ(0, parent_image
.features(&features
));
8304 std::string clone_name
= TestLibRBD::get_temp_image_name();
8305 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
8306 clone_name
.c_str(), features
, &order
));
8308 librbd::Image clone_image
;
8309 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
8311 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
8315 cmp_bl
.append(std::string(48, '1'));
8316 cmp_bl
.append(std::string(464, '3'));
8317 bufferlist write_bl
;
8318 write_bl
.append(std::string(512, '2'));
8319 uint64_t mismatch_off
= 0;
8321 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
8322 write_bl
, &mismatch_off
, 0));
8323 ASSERT_EQ(48U, mismatch_off
);
8326 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
8328 ASSERT_TRUE(bl
.contents_equal(read_bl
));
8332 TEST_F(TestLibRBD
, CompareAndWriteCopyupMismatch
)
8334 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8336 librados::IoCtx ioctx
;
8337 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8339 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, false);
8340 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, true);
8343 TEST_F(TestLibRBD
, Flatten
)
8345 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8347 librados::IoCtx ioctx
;
8348 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8351 std::string parent_name
= get_temp_image_name();
8352 uint64_t size
= 2 << 20;
8354 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
8356 librbd::Image parent_image
;
8357 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
8360 bl
.append(std::string(4096, '1'));
8361 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
8363 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
8364 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
8367 ASSERT_EQ(0, parent_image
.features(&features
));
8369 std::string clone_name
= get_temp_image_name();
8370 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
8371 clone_name
.c_str(), features
, &order
));
8373 librbd::Image clone_image
;
8374 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
8375 ASSERT_EQ(0, clone_image
.flatten());
8377 librbd::RBD::AioCompletion
*read_comp
=
8378 new librbd::RBD::AioCompletion(NULL
, NULL
);
8380 clone_image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
8381 ASSERT_EQ(0, read_comp
->wait_for_complete());
8382 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
8383 read_comp
->release();
8384 ASSERT_TRUE(bl
.contents_equal(read_bl
));
8386 ASSERT_PASSED(validate_object_map
, clone_image
);
8389 TEST_F(TestLibRBD
, Sparsify
)
8391 rados_ioctx_t ioctx
;
8392 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
8393 BOOST_SCOPE_EXIT_ALL(&ioctx
) {
8394 rados_ioctx_destroy(ioctx
);
8397 const size_t CHUNK_SIZE
= 4096 * 2;
8400 std::string name
= get_temp_image_name();
8401 uint64_t size
= CHUNK_SIZE
* 1024;
8403 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8404 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8405 BOOST_SCOPE_EXIT_ALL(&image
) {
8409 char test_data
[4 * CHUNK_SIZE
+ 1];
8410 for (size_t i
= 0; i
< 4 ; ++i
) {
8411 for (size_t j
= 0; j
< CHUNK_SIZE
; j
++) {
8413 test_data
[i
* CHUNK_SIZE
+ j
] = (char)(rand() % (126 - 33) + 33);
8415 test_data
[i
* CHUNK_SIZE
+ j
] = '\0';
8419 test_data
[4 * CHUNK_SIZE
] = '\0';
8421 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
8422 ASSERT_EQ(0, rbd_flush(image
));
8424 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 16));
8425 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 1 << (order
+ 1)));
8426 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 4096 + 1));
8427 ASSERT_EQ(0, rbd_sparsify(image
, 4096));
8429 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
8432 TEST_F(TestLibRBD
, SparsifyPP
)
8434 librados::IoCtx ioctx
;
8435 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8438 std::string name
= get_temp_image_name();
8439 uint64_t size
= 12 * 1024 * 1024;
8441 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8443 librbd::Image image
;
8444 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
8447 bl
.append(std::string(4096, '\0'));
8448 bl
.append(std::string(4096, '1'));
8449 bl
.append(std::string(4096, '\0'));
8450 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
8451 ASSERT_EQ(0, image
.flush());
8453 ASSERT_EQ(-EINVAL
, image
.sparsify(16));
8454 ASSERT_EQ(-EINVAL
, image
.sparsify(1 << (order
+ 1)));
8455 ASSERT_EQ(-EINVAL
, image
.sparsify(4096 + 1));
8456 ASSERT_EQ(0, image
.sparsify(4096));
8459 ASSERT_EQ((ssize_t
)bl
.length(), image
.read(0, bl
.length(), read_bl
));
8460 ASSERT_TRUE(bl
.contents_equal(read_bl
));
8462 ASSERT_PASSED(validate_object_map
, image
);
8465 TEST_F(TestLibRBD
, SnapshotLimit
)
8467 rados_ioctx_t ioctx
;
8468 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8472 std::string name
= get_temp_image_name();
8473 uint64_t size
= 2 << 20;
8476 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8477 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8479 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
8480 ASSERT_EQ(UINT64_MAX
, limit
);
8481 ASSERT_EQ(0, rbd_snap_set_limit(image
, 2));
8482 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
8483 ASSERT_EQ(2U, limit
);
8485 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
8486 ASSERT_EQ(-ERANGE
, rbd_snap_set_limit(image
, 0));
8487 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
8488 ASSERT_EQ(-EDQUOT
, rbd_snap_create(image
, "snap3"));
8489 ASSERT_EQ(0, rbd_snap_set_limit(image
, UINT64_MAX
));
8490 ASSERT_EQ(0, rbd_snap_create(image
, "snap3"));
8491 ASSERT_EQ(0, rbd_close(image
));
8493 rados_ioctx_destroy(ioctx
);
8497 TEST_F(TestLibRBD
, SnapshotLimitPP
)
8499 librados::IoCtx ioctx
;
8500 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8504 librbd::Image image
;
8505 std::string name
= get_temp_image_name();
8506 uint64_t size
= 2 << 20;
8510 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8511 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8513 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
8514 ASSERT_EQ(UINT64_MAX
, limit
);
8515 ASSERT_EQ(0, image
.snap_set_limit(2));
8516 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
8517 ASSERT_EQ(2U, limit
);
8519 ASSERT_EQ(0, image
.snap_create("snap1"));
8520 ASSERT_EQ(-ERANGE
, image
.snap_set_limit(0));
8521 ASSERT_EQ(0, image
.snap_create("snap2"));
8522 ASSERT_EQ(-EDQUOT
, image
.snap_create("snap3"));
8523 ASSERT_EQ(0, image
.snap_set_limit(UINT64_MAX
));
8524 ASSERT_EQ(0, image
.snap_create("snap3"));
8530 TEST_F(TestLibRBD
, RebuildObjectMapViaLockOwner
)
8532 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_OBJECT_MAP
);
8534 librados::IoCtx ioctx
;
8535 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8538 std::string name
= get_temp_image_name();
8539 uint64_t size
= 2 << 20;
8541 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8543 std::string object_map_oid
;
8545 librbd::Image image
;
8546 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8548 std::string image_id
;
8549 ASSERT_EQ(0, get_image_id(image
, &image_id
));
8550 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
8553 // corrupt the object map
8556 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
8558 librbd::Image image1
;
8559 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8563 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8564 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8565 ASSERT_TRUE(lock_owner
);
8568 ASSERT_EQ(0, image1
.get_flags(&flags
));
8569 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
8571 librbd::Image image2
;
8572 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8573 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8574 ASSERT_FALSE(lock_owner
);
8576 PrintProgress prog_ctx
;
8577 ASSERT_EQ(0, image2
.rebuild_object_map(prog_ctx
));
8578 ASSERT_PASSED(validate_object_map
, image1
);
8579 ASSERT_PASSED(validate_object_map
, image2
);
8582 TEST_F(TestLibRBD
, RenameViaLockOwner
)
8584 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
8586 librados::IoCtx ioctx
;
8587 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8590 std::string name
= get_temp_image_name();
8591 uint64_t size
= 2 << 20;
8593 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8595 librbd::Image image1
;
8596 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8599 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8600 ASSERT_FALSE(lock_owner
);
8602 std::string new_name
= get_temp_image_name();
8603 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
8604 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8605 ASSERT_FALSE(lock_owner
);
8608 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8609 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8610 ASSERT_TRUE(lock_owner
);
8613 new_name
= get_temp_image_name();
8614 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
8615 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8616 ASSERT_TRUE(lock_owner
);
8618 librbd::Image image2
;
8619 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, new_name
.c_str(), NULL
));
8622 TEST_F(TestLibRBD
, SnapCreateViaLockOwner
)
8624 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
8626 librados::IoCtx ioctx
;
8627 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8630 std::string name
= get_temp_image_name();
8631 uint64_t size
= 2 << 20;
8633 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8635 librbd::Image image1
;
8636 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8638 // switch to writeback cache
8639 ASSERT_EQ(0, image1
.flush());
8642 bl
.append(std::string(4096, '1'));
8643 ASSERT_EQ((ssize_t
)bl
.length(), image1
.write(0, bl
.length(), bl
));
8646 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8647 ASSERT_TRUE(lock_owner
);
8649 librbd::Image image2
;
8650 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8652 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8653 ASSERT_FALSE(lock_owner
);
8655 ASSERT_EQ(0, image2
.snap_create("snap1"));
8657 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
8658 ASSERT_TRUE(exists
);
8659 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
8660 ASSERT_TRUE(exists
);
8662 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8663 ASSERT_TRUE(lock_owner
);
8666 TEST_F(TestLibRBD
, SnapRemoveViaLockOwner
)
8668 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
8670 librados::IoCtx ioctx
;
8671 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8674 std::string name
= get_temp_image_name();
8675 uint64_t size
= 2 << 20;
8677 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8679 librbd::Image image1
;
8680 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8683 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8684 ASSERT_EQ(0, image1
.snap_create("snap1"));
8687 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8688 ASSERT_TRUE(lock_owner
);
8690 librbd::Image image2
;
8691 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8693 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8694 ASSERT_FALSE(lock_owner
);
8696 ASSERT_EQ(0, image2
.snap_remove("snap1"));
8698 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
8699 ASSERT_FALSE(exists
);
8700 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
8701 ASSERT_FALSE(exists
);
8703 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8704 ASSERT_TRUE(lock_owner
);
8707 TEST_F(TestLibRBD
, UpdateFeaturesViaLockOwner
) {
8708 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
8710 librados::IoCtx ioctx
;
8711 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8713 std::string name
= get_temp_image_name();
8714 uint64_t size
= 2 << 20;
8717 //creates full with rbd default features
8718 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8721 librbd::Image image1
;
8722 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8724 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8725 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8726 ASSERT_TRUE(lock_owner
);
8728 librbd::Image image2
;
8729 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8730 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8731 ASSERT_FALSE(lock_owner
);
8733 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
8734 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8735 ASSERT_FALSE(lock_owner
);
8737 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
8738 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8739 ASSERT_FALSE(lock_owner
);
8743 TEST_F(TestLibRBD
, EnableJournalingViaLockOwner
)
8745 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
8747 librados::IoCtx ioctx
;
8748 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8751 std::string name
= get_temp_image_name();
8752 uint64_t size
= 2 << 20;
8754 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8756 librbd::Image image1
;
8757 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8760 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8763 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8764 ASSERT_TRUE(lock_owner
);
8766 librbd::Image image2
;
8767 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8769 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, false));
8771 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8772 ASSERT_TRUE(lock_owner
);
8773 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8774 ASSERT_FALSE(lock_owner
);
8776 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, true));
8778 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8779 ASSERT_FALSE(lock_owner
);
8780 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8781 ASSERT_TRUE(lock_owner
);
8784 TEST_F(TestLibRBD
, SnapRemove2
)
8786 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8788 librados::IoCtx ioctx
;
8789 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8792 std::string name
= get_temp_image_name();
8793 uint64_t size
= 2 << 20;
8795 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8797 librbd::Image image1
;
8798 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8801 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8802 ASSERT_EQ(0, image1
.snap_create("snap1"));
8804 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
8805 ASSERT_TRUE(exists
);
8806 ASSERT_EQ(0, image1
.snap_protect("snap1"));
8808 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
8809 ASSERT_TRUE(is_protected
);
8812 ASSERT_EQ(0, image1
.features(&features
));
8814 std::string child_name
= get_temp_image_name();
8815 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
8816 child_name
.c_str(), features
, &order
));
8818 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
8819 ASSERT_TRUE(exists
);
8820 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
8821 ASSERT_TRUE(is_protected
);
8823 ASSERT_EQ(-EBUSY
, image1
.snap_remove("snap1"));
8825 ASSERT_EQ(0, image1
.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE
, pp
));
8826 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
8827 ASSERT_FALSE(exists
);
8830 TEST_F(TestLibRBD
, SnapRenameViaLockOwner
)
8832 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
8834 librados::IoCtx ioctx
;
8835 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8838 std::string name
= get_temp_image_name();
8839 uint64_t size
= 2 << 20;
8841 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8843 librbd::Image image1
;
8844 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8847 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8848 ASSERT_EQ(0, image1
.snap_create("snap1"));
8851 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8852 ASSERT_TRUE(lock_owner
);
8854 librbd::Image image2
;
8855 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8857 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8858 ASSERT_FALSE(lock_owner
);
8860 ASSERT_EQ(0, image2
.snap_rename("snap1", "snap1-rename"));
8862 ASSERT_EQ(0, image1
.snap_exists2("snap1-rename", &exists
));
8863 ASSERT_TRUE(exists
);
8864 ASSERT_EQ(0, image2
.snap_exists2("snap1-rename", &exists
));
8865 ASSERT_TRUE(exists
);
8867 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8868 ASSERT_TRUE(lock_owner
);
8871 TEST_F(TestLibRBD
, SnapProtectViaLockOwner
)
8873 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
8875 librados::IoCtx ioctx
;
8876 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8879 std::string name
= get_temp_image_name();
8880 uint64_t size
= 2 << 20;
8882 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8884 librbd::Image image1
;
8885 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8888 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8891 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8892 ASSERT_TRUE(lock_owner
);
8893 ASSERT_EQ(0, image1
.snap_create("snap1"));
8895 librbd::Image image2
;
8896 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8898 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8899 ASSERT_FALSE(lock_owner
);
8901 ASSERT_EQ(0, image2
.snap_protect("snap1"));
8903 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
8904 ASSERT_TRUE(is_protected
);
8905 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
8906 ASSERT_TRUE(is_protected
);
8908 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8909 ASSERT_TRUE(lock_owner
);
8912 TEST_F(TestLibRBD
, SnapUnprotectViaLockOwner
)
8914 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
8916 librados::IoCtx ioctx
;
8917 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8920 std::string name
= get_temp_image_name();
8921 uint64_t size
= 2 << 20;
8923 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8925 librbd::Image image1
;
8926 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8929 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8932 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8933 ASSERT_TRUE(lock_owner
);
8934 ASSERT_EQ(0, image1
.snap_create("snap1"));
8935 ASSERT_EQ(0, image1
.snap_protect("snap1"));
8937 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
8938 ASSERT_TRUE(is_protected
);
8940 librbd::Image image2
;
8941 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8943 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8944 ASSERT_FALSE(lock_owner
);
8946 ASSERT_EQ(0, image2
.snap_unprotect("snap1"));
8947 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
8948 ASSERT_FALSE(is_protected
);
8949 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
8950 ASSERT_FALSE(is_protected
);
8952 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8953 ASSERT_TRUE(lock_owner
);
8956 TEST_F(TestLibRBD
, FlattenViaLockOwner
)
8958 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
8960 librados::IoCtx ioctx
;
8961 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8964 std::string parent_name
= get_temp_image_name();
8965 uint64_t size
= 2 << 20;
8967 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
8969 librbd::Image parent_image
;
8970 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
8971 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
8972 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
8975 ASSERT_EQ(0, parent_image
.features(&features
));
8977 std::string name
= get_temp_image_name();
8978 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
8979 name
.c_str(), features
, &order
));
8981 librbd::Image image1
;
8982 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8985 ASSERT_EQ(0, image1
.write(0, 0, bl
));
8988 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
8989 ASSERT_TRUE(lock_owner
);
8991 librbd::Image image2
;
8992 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8994 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
8995 ASSERT_FALSE(lock_owner
);
8997 ASSERT_EQ(0, image2
.flatten());
8999 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9000 ASSERT_TRUE(lock_owner
);
9001 ASSERT_PASSED(validate_object_map
, image1
);
9004 TEST_F(TestLibRBD
, ResizeViaLockOwner
)
9006 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
9008 librados::IoCtx ioctx
;
9009 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9012 std::string name
= get_temp_image_name();
9013 uint64_t size
= 2 << 20;
9015 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9017 librbd::Image image1
;
9018 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9021 ASSERT_EQ(0, image1
.write(0, 0, bl
));
9024 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9025 ASSERT_TRUE(lock_owner
);
9027 librbd::Image image2
;
9028 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9030 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
9031 ASSERT_FALSE(lock_owner
);
9033 ASSERT_EQ(0, image2
.resize(0));
9035 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9036 ASSERT_TRUE(lock_owner
);
9037 ASSERT_PASSED(validate_object_map
, image1
);
9040 TEST_F(TestLibRBD
, SparsifyViaLockOwner
)
9042 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
9044 librados::IoCtx ioctx
;
9045 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9048 std::string name
= get_temp_image_name();
9049 uint64_t size
= 2 << 20;
9051 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9053 librbd::Image image1
;
9054 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9057 ASSERT_EQ(0, image1
.write(0, 0, bl
));
9060 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9061 ASSERT_TRUE(lock_owner
);
9063 librbd::Image image2
;
9064 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9066 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
9067 ASSERT_FALSE(lock_owner
);
9069 ASSERT_EQ(0, image2
.sparsify(4096));
9071 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9072 ASSERT_TRUE(lock_owner
);
9073 ASSERT_PASSED(validate_object_map
, image1
);
9076 TEST_F(TestLibRBD
, ObjectMapConsistentSnap
)
9078 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
9080 librados::IoCtx ioctx
;
9081 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9084 std::string name
= get_temp_image_name();
9085 uint64_t size
= 1 << 20;
9087 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9089 librbd::Image image1
;
9090 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9093 for (int i
= 0; i
< num_snaps
; ++i
) {
9094 std::string snap_name
= "snap" + stringify(i
);
9095 ASSERT_EQ(0, image1
.snap_create(snap_name
.c_str()));
9099 thread
writer([&image1
](){
9100 librbd::image_info_t info
;
9101 int r
= image1
.stat(info
, sizeof(info
));
9102 ceph_assert(r
== 0);
9105 for (unsigned i
= 0; i
< info
.num_objs
; ++i
) {
9106 r
= image1
.write((1 << info
.order
) * i
, bl
.length(), bl
);
9107 ceph_assert(r
== (int) bl
.length());
9112 for (int i
= 0; i
< num_snaps
; ++i
) {
9113 std::string snap_name
= "snap" + stringify(i
);
9114 ASSERT_EQ(0, image1
.snap_set(snap_name
.c_str()));
9115 ASSERT_PASSED(validate_object_map
, image1
);
9118 ASSERT_EQ(0, image1
.snap_set(NULL
));
9119 ASSERT_PASSED(validate_object_map
, image1
);
9122 void memset_rand(char *buf
, size_t len
) {
9123 for (size_t i
= 0; i
< len
; ++i
) {
9124 buf
[i
] = (char) (rand() % (126 - 33) + 33);
9128 TEST_F(TestLibRBD
, Metadata
)
9130 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
9132 rados_ioctx_t ioctx
;
9133 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
9135 std::string name
= get_temp_image_name();
9136 uint64_t size
= 2 << 20;
9138 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
9141 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
9144 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
9148 size_t keys_len
= sizeof(keys
);
9149 size_t vals_len
= sizeof(vals
);
9151 memset_rand(keys
, keys_len
);
9152 memset_rand(vals
, vals_len
);
9154 ASSERT_EQ(0, rbd_metadata_list(image
, "key", 0, keys
, &keys_len
, vals
,
9156 ASSERT_EQ(0U, keys_len
);
9157 ASSERT_EQ(0U, vals_len
);
9160 size_t value_len
= sizeof(value
);
9161 memset_rand(value
, value_len
);
9163 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
9164 ASSERT_EQ(0, rbd_metadata_set(image1
, "key2", "value2"));
9165 ASSERT_EQ(0, rbd_metadata_get(image1
, "key1", value
, &value_len
));
9166 ASSERT_STREQ(value
, "value1");
9168 ASSERT_EQ(-ERANGE
, rbd_metadata_get(image1
, "key1", value
, &value_len
));
9169 ASSERT_EQ(value_len
, strlen("value1") + 1);
9171 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
9173 keys_len
= sizeof(keys
);
9174 vals_len
= sizeof(vals
);
9175 memset_rand(keys
, keys_len
);
9176 memset_rand(vals
, vals_len
);
9177 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
9179 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
9180 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
9181 ASSERT_STREQ(keys
, "key1");
9182 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
9183 ASSERT_STREQ(vals
, "value1");
9184 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
9186 ASSERT_EQ(0, rbd_metadata_remove(image1
, "key1"));
9187 ASSERT_EQ(-ENOENT
, rbd_metadata_remove(image1
, "key3"));
9188 value_len
= sizeof(value
);
9189 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key3", value
, &value_len
));
9190 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
9192 ASSERT_EQ(keys_len
, strlen("key2") + 1);
9193 ASSERT_EQ(vals_len
, strlen("value2") + 1);
9194 ASSERT_STREQ(keys
, "key2");
9195 ASSERT_STREQ(vals
, "value2");
9197 // test config setting
9198 ASSERT_EQ(0, rbd_metadata_set(image1
, "conf_rbd_cache", "false"));
9199 ASSERT_EQ(-EINVAL
, rbd_metadata_set(image1
, "conf_rbd_cache", "INVALID_VAL"));
9200 ASSERT_EQ(0, rbd_metadata_remove(image1
, "conf_rbd_cache"));
9202 // test metadata with snapshot adding
9203 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
9204 ASSERT_EQ(0, rbd_snap_protect(image1
, "snap1"));
9205 ASSERT_EQ(0, rbd_snap_set(image1
, "snap1"));
9207 ASSERT_EQ(-EROFS
, rbd_metadata_set(image1
, "key1", "value1"));
9208 ASSERT_EQ(-EROFS
, rbd_metadata_remove(image1
, "key2"));
9210 keys_len
= sizeof(keys
);
9211 vals_len
= sizeof(vals
);
9212 memset_rand(keys
, keys_len
);
9213 memset_rand(vals
, vals_len
);
9214 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
9216 ASSERT_EQ(keys_len
, strlen("key2") + 1);
9217 ASSERT_EQ(vals_len
, strlen("value2") + 1);
9218 ASSERT_STREQ(keys
, "key2");
9219 ASSERT_STREQ(vals
, "value2");
9221 ASSERT_EQ(0, rbd_snap_set(image1
, NULL
));
9222 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
9223 ASSERT_EQ(0, rbd_metadata_set(image1
, "key3", "value3"));
9224 keys_len
= sizeof(keys
);
9225 vals_len
= sizeof(vals
);
9226 memset_rand(keys
, keys_len
);
9227 memset_rand(vals
, vals_len
);
9228 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
9231 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
9233 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
9234 ASSERT_STREQ(keys
, "key1");
9235 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
9236 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
9237 ASSERT_STREQ(vals
, "value1");
9238 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
9239 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
9241 // test metadata with cloning
9243 ASSERT_EQ(0, rbd_get_features(image1
, &features
));
9245 string cname
= get_temp_image_name();
9246 EXPECT_EQ(0, rbd_clone(ioctx
, name
.c_str(), "snap1", ioctx
,
9247 cname
.c_str(), features
, &order
));
9249 ASSERT_EQ(0, rbd_open(ioctx
, cname
.c_str(), &image2
, NULL
));
9250 ASSERT_EQ(0, rbd_metadata_set(image2
, "key4", "value4"));
9252 keys_len
= sizeof(keys
);
9253 vals_len
= sizeof(vals
);
9254 memset_rand(keys
, keys_len
);
9255 memset_rand(vals
, vals_len
);
9256 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 0, keys
, &keys_len
, vals
,
9258 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
9259 1 + strlen("key4") + 1);
9260 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
9261 strlen("value3") + 1 + strlen("value4") + 1);
9262 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
9264 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1 +
9265 strlen("value3") + 1, "value4");
9267 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
9270 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
9272 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
9273 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key4", value
, &value_len
));
9275 // test short buffer cases
9276 keys_len
= strlen("key1") + 1;
9277 vals_len
= strlen("value1") + 1;
9278 memset_rand(keys
, keys_len
);
9279 memset_rand(vals
, vals_len
);
9280 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 1, keys
, &keys_len
, vals
,
9282 ASSERT_EQ(keys_len
, strlen("key1") + 1);
9283 ASSERT_EQ(vals_len
, strlen("value1") + 1);
9284 ASSERT_STREQ(keys
, "key1");
9285 ASSERT_STREQ(vals
, "value1");
9287 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "key", 2, keys
, &keys_len
, vals
,
9289 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
9290 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
9292 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "key", 0, keys
, &keys_len
, vals
,
9294 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
9295 1 + strlen("key4") + 1);
9296 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
9297 strlen("value3") + 1 + strlen("value4") + 1);
9299 // test `start` param
9300 keys_len
= sizeof(keys
);
9301 vals_len
= sizeof(vals
);
9302 memset_rand(keys
, keys_len
);
9303 memset_rand(vals
, vals_len
);
9304 ASSERT_EQ(0, rbd_metadata_list(image2
, "key2", 0, keys
, &keys_len
, vals
,
9306 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
9307 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
9308 ASSERT_STREQ(keys
, "key3");
9309 ASSERT_STREQ(vals
, "value3");
9311 ASSERT_EQ(0, rbd_close(image
));
9312 ASSERT_EQ(0, rbd_close(image1
));
9313 ASSERT_EQ(0, rbd_close(image2
));
9314 rados_ioctx_destroy(ioctx
);
9317 TEST_F(TestLibRBD
, MetadataPP
)
9319 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
9321 librados::IoCtx ioctx
;
9322 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9325 string name
= get_temp_image_name();
9326 uint64_t size
= 2 << 20;
9330 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9332 librbd::Image image1
;
9333 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9334 map
<string
, bufferlist
> pairs
;
9335 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
9336 ASSERT_TRUE(pairs
.empty());
9338 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
9339 ASSERT_EQ(0, image1
.metadata_set("key2", "value2"));
9340 ASSERT_EQ(0, image1
.metadata_get("key1", &value
));
9341 ASSERT_EQ(0, strcmp("value1", value
.c_str()));
9342 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
9343 ASSERT_EQ(2U, pairs
.size());
9344 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
9345 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
9348 ASSERT_EQ(0, image1
.metadata_remove("key1"));
9349 ASSERT_EQ(-ENOENT
, image1
.metadata_remove("key3"));
9350 ASSERT_TRUE(image1
.metadata_get("key3", &value
) < 0);
9351 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
9352 ASSERT_EQ(1U, pairs
.size());
9353 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
9355 // test config setting
9356 ASSERT_EQ(0, image1
.metadata_set("conf_rbd_cache", "false"));
9357 ASSERT_EQ(-EINVAL
, image1
.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
9358 ASSERT_EQ(0, image1
.metadata_remove("conf_rbd_cache"));
9360 // test metadata with snapshot adding
9361 ASSERT_EQ(0, image1
.snap_create("snap1"));
9362 ASSERT_EQ(0, image1
.snap_protect("snap1"));
9363 ASSERT_EQ(0, image1
.snap_set("snap1"));
9366 ASSERT_EQ(-EROFS
, image1
.metadata_set("key1", "value1"));
9367 ASSERT_EQ(-EROFS
, image1
.metadata_remove("key2"));
9368 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
9369 ASSERT_EQ(1U, pairs
.size());
9370 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
9372 ASSERT_EQ(0, image1
.snap_set(NULL
));
9373 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
9374 ASSERT_EQ(0, image1
.metadata_set("key3", "value3"));
9375 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
9376 ASSERT_EQ(3U, pairs
.size());
9377 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
9378 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
9379 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
9381 // test metadata with cloning
9382 string cname
= get_temp_image_name();
9383 librbd::Image image2
;
9384 ASSERT_EQ(0, image1
.features(&features
));
9385 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
9386 cname
.c_str(), features
, &order
));
9387 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, cname
.c_str(), NULL
));
9388 ASSERT_EQ(0, image2
.metadata_set("key4", "value4"));
9390 ASSERT_EQ(0, image2
.metadata_list("key", 0, &pairs
));
9391 ASSERT_EQ(4U, pairs
.size());
9393 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
9394 ASSERT_EQ(3U, pairs
.size());
9395 ASSERT_EQ(-ENOENT
, image1
.metadata_get("key4", &value
));
9398 TEST_F(TestLibRBD
, UpdateFeatures
)
9400 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
9402 librados::IoCtx ioctx
;
9403 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9406 std::string name
= get_temp_image_name();
9407 uint64_t size
= 1 << 20;
9409 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9411 librbd::Image image
;
9412 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9415 ASSERT_EQ(0, image
.old_format(&old_format
));
9417 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
9422 ASSERT_EQ(0, image
.features(&features
));
9424 // must provide a single feature
9425 ASSERT_EQ(-EINVAL
, image
.update_features(0, true));
9427 uint64_t disable_features
;
9428 disable_features
= features
& (RBD_FEATURE_EXCLUSIVE_LOCK
|
9429 RBD_FEATURE_OBJECT_MAP
|
9430 RBD_FEATURE_FAST_DIFF
|
9431 RBD_FEATURE_JOURNALING
);
9432 if (disable_features
!= 0) {
9433 ASSERT_EQ(0, image
.update_features(disable_features
, false));
9436 ASSERT_EQ(0, image
.features(&features
));
9437 ASSERT_EQ(0U, features
& disable_features
);
9439 // cannot enable object map nor journaling w/o exclusive lock
9440 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
9441 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_JOURNALING
, true));
9442 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
9444 ASSERT_EQ(0, image
.features(&features
));
9445 ASSERT_NE(0U, features
& RBD_FEATURE_EXCLUSIVE_LOCK
);
9447 // can enable fast diff w/o object map
9448 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_FAST_DIFF
, true));
9449 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
9450 ASSERT_EQ(0, image
.features(&features
));
9451 ASSERT_NE(0U, features
& RBD_FEATURE_OBJECT_MAP
);
9453 uint64_t expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
|
9454 RBD_FLAG_FAST_DIFF_INVALID
;
9456 ASSERT_EQ(0, image
.get_flags(&flags
));
9457 ASSERT_EQ(expected_flags
, flags
);
9459 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
9460 ASSERT_EQ(0, image
.features(&features
));
9461 ASSERT_EQ(0U, features
& RBD_FEATURE_OBJECT_MAP
);
9463 // can disable object map w/ fast diff
9464 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
9465 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
9466 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_FAST_DIFF
, false));
9467 ASSERT_EQ(0, image
.features(&features
));
9468 ASSERT_EQ(0U, features
& RBD_FEATURE_FAST_DIFF
);
9470 ASSERT_EQ(0, image
.get_flags(&flags
));
9471 ASSERT_EQ(0U, flags
);
9473 // cannot disable exclusive lock w/ object map
9474 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
9475 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
9476 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
9478 // cannot disable exclusive lock w/ journaling
9479 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, true));
9480 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
9481 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, false));
9483 ASSERT_EQ(0, image
.get_flags(&flags
));
9484 ASSERT_EQ(0U, flags
);
9486 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
9488 ASSERT_EQ(0, image
.features(&features
));
9489 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0) {
9490 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, false));
9492 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, true));
9495 TEST_F(TestLibRBD
, FeaturesBitmaskString
)
9498 uint64_t features
= RBD_FEATURES_DEFAULT
;
9500 std::string features_str
;
9501 std::string expected_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
9502 rbd
.features_to_string(features
, &features_str
);
9503 ASSERT_EQ(expected_str
, features_str
);
9505 features
= RBD_FEATURE_LAYERING
;
9507 expected_str
= "layering";
9508 rbd
.features_to_string(features
, &features_str
);
9509 ASSERT_EQ(expected_str
, features_str
);
9511 uint64_t features_bitmask
;
9512 features_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
9513 rbd
.features_from_string(features_str
, &features_bitmask
);
9514 ASSERT_EQ(features_bitmask
, RBD_FEATURES_DEFAULT
);
9516 features_str
= "layering";
9517 features_bitmask
= 0;
9518 rbd
.features_from_string(features_str
, &features_bitmask
);
9519 ASSERT_EQ(features_bitmask
, RBD_FEATURE_LAYERING
);
9522 TEST_F(TestLibRBD
, RebuildObjectMap
)
9524 librados::IoCtx ioctx
;
9525 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9528 std::string name
= get_temp_image_name();
9529 uint64_t size
= 1 << 20;
9531 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9533 PrintProgress prog_ctx
;
9534 std::string object_map_oid
;
9538 librbd::Image image
;
9539 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9542 ASSERT_EQ(0, image
.features(&features
));
9543 if ((features
& RBD_FEATURE_OBJECT_MAP
) == 0) {
9544 ASSERT_EQ(-EINVAL
, image
.rebuild_object_map(prog_ctx
));
9548 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
9550 ASSERT_EQ(0, image
.snap_create("snap1"));
9551 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(1<<order
, bl
.length(), bl
));
9553 std::string image_id
;
9554 ASSERT_EQ(0, get_image_id(image
, &image_id
));
9555 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
9558 // corrupt the object map
9559 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
9561 librbd::Image image1
;
9562 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9566 ASSERT_EQ(0, image1
.write(0, 0, bl
));
9567 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9568 ASSERT_TRUE(lock_owner
);
9571 ASSERT_EQ(0, image1
.get_flags(&flags
));
9572 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
9574 ASSERT_EQ(0, image1
.rebuild_object_map(prog_ctx
));
9576 librbd::Image image2
;
9577 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9580 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(0, bl
.length(), read_bl
));
9581 ASSERT_TRUE(bl
.contents_equal(read_bl
));
9584 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(1<<order
, bl
.length(), read_bl
));
9585 ASSERT_TRUE(bl
.contents_equal(read_bl
));
9587 ASSERT_PASSED(validate_object_map
, image1
);
9588 ASSERT_PASSED(validate_object_map
, image2
);
9591 TEST_F(TestLibRBD
, RebuildNewObjectMap
)
9593 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
9595 rados_ioctx_t ioctx
;
9596 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
9598 std::string name
= get_temp_image_name();
9599 uint64_t size
= 1 << 20;
9601 uint64_t features
= RBD_FEATURE_EXCLUSIVE_LOCK
;
9602 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
9606 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
9607 ASSERT_EQ(0, rbd_update_features(image
, RBD_FEATURE_OBJECT_MAP
, true));
9608 ASSERT_EQ(0, rbd_rebuild_object_map(image
, print_progress_percent
, NULL
));
9610 ASSERT_PASSED(validate_object_map
, image
);
9612 ASSERT_EQ(0, rbd_close(image
));
9613 rados_ioctx_destroy(ioctx
);
9616 TEST_F(TestLibRBD
, CheckObjectMap
)
9618 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
9620 librados::IoCtx ioctx
;
9621 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9624 std::string name
= get_temp_image_name();
9625 uint64_t size
= 1 << 20;
9627 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9629 PrintProgress prog_ctx
;
9634 librbd::Image image
;
9635 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9638 ASSERT_EQ(0, image
.features(&features
));
9640 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(0, bl1
.length(), bl1
));
9642 ASSERT_EQ(0, image
.snap_create("snap1"));
9643 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(1<<order
, bl1
.length(), bl1
));
9646 librbd::Image image1
;
9647 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9649 std::string image_id
;
9650 ASSERT_EQ(0, get_image_id(image1
, &image_id
));
9652 std::string object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
9654 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl2
, 1024, 0));
9657 ASSERT_EQ((ssize_t
)bl1
.length(), image1
.write(3 * (1 << 18), bl1
.length(), bl1
));
9658 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9659 ASSERT_TRUE(lock_owner
);
9661 //reopen image to reread now corrupt object map from disk
9665 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl1
, 1024, 0));
9666 ASSERT_FALSE(bl1
.contents_equal(bl2
));
9668 ASSERT_EQ(0, ioctx
.write_full(object_map_oid
, bl2
));
9669 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9672 ASSERT_EQ(0, image1
.get_flags(&flags
));
9673 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
9675 ASSERT_EQ(0, image1
.check_object_map(prog_ctx
));
9677 ASSERT_EQ(0, image1
.get_flags(&flags
));
9678 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
9681 TEST_F(TestLibRBD
, BlockingAIO
)
9683 librados::IoCtx ioctx
;
9684 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9687 std::string name
= get_temp_image_name();
9688 uint64_t size
= 1 << 20;
9690 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9692 std::string non_blocking_aio
;
9693 ASSERT_EQ(0, _rados
.conf_get("rbd_non_blocking_aio", non_blocking_aio
));
9694 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio", "0"));
9695 BOOST_SCOPE_EXIT( (non_blocking_aio
) ) {
9696 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio",
9697 non_blocking_aio
.c_str()));
9698 } BOOST_SCOPE_EXIT_END
;
9700 librbd::Image image
;
9701 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9703 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
9706 ASSERT_EQ(0, image
.write(0, bl
.length(), bl
));
9708 bl
.append(std::string(256, '1'));
9709 librbd::RBD::AioCompletion
*write_comp
=
9710 new librbd::RBD::AioCompletion(NULL
, NULL
);
9711 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
9713 librbd::RBD::AioCompletion
*flush_comp
=
9714 new librbd::RBD::AioCompletion(NULL
, NULL
);
9715 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
9716 ASSERT_EQ(0, flush_comp
->wait_for_complete());
9717 ASSERT_EQ(0, flush_comp
->get_return_value());
9718 flush_comp
->release();
9720 ASSERT_EQ(1, write_comp
->is_complete());
9721 ASSERT_EQ(0, write_comp
->get_return_value());
9722 write_comp
->release();
9724 librbd::RBD::AioCompletion
*discard_comp
=
9725 new librbd::RBD::AioCompletion(NULL
, NULL
);
9726 ASSERT_EQ(0, image
.aio_discard(128, 128, discard_comp
));
9727 ASSERT_EQ(0, discard_comp
->wait_for_complete());
9728 discard_comp
->release();
9730 librbd::RBD::AioCompletion
*read_comp
=
9731 new librbd::RBD::AioCompletion(NULL
, NULL
);
9733 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
9734 ASSERT_EQ(0, read_comp
->wait_for_complete());
9735 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
9736 read_comp
->release();
9738 bufferlist expected_bl
;
9739 expected_bl
.append(std::string(128, '1'));
9740 expected_bl
.append(std::string(128, skip_discard
? '1' : '\0'));
9741 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
9744 TEST_F(TestLibRBD
, ExclusiveLockTransition
)
9746 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
9748 librados::IoCtx ioctx
;
9749 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9752 std::string name
= get_temp_image_name();
9754 uint64_t size
= 1 << 18;
9756 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9758 librbd::Image image1
;
9759 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9761 librbd::Image image2
;
9762 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9764 std::list
<librbd::RBD::AioCompletion
*> comps
;
9765 ceph::bufferlist bl
;
9766 bl
.append(std::string(1 << order
, '1'));
9767 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
9768 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
9770 comps
.push_back(comp
);
9771 if (object_no
% 2 == 0) {
9772 ASSERT_EQ(0, image1
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
9774 ASSERT_EQ(0, image2
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
9778 while (!comps
.empty()) {
9779 librbd::RBD::AioCompletion
*comp
= comps
.front();
9781 ASSERT_EQ(0, comp
->wait_for_complete());
9782 ASSERT_EQ(1, comp
->is_complete());
9786 librbd::Image image3
;
9787 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
9788 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
9790 ASSERT_EQ((ssize_t
)bl
.length(), image3
.read(object_no
<< order
, bl
.length(),
9792 ASSERT_TRUE(bl
.contents_equal(read_bl
));
9795 ASSERT_PASSED(validate_object_map
, image1
);
9796 ASSERT_PASSED(validate_object_map
, image2
);
9797 ASSERT_PASSED(validate_object_map
, image3
);
9800 TEST_F(TestLibRBD
, ExclusiveLockReadTransition
)
9802 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
9804 librados::IoCtx ioctx
;
9805 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9808 std::string name
= get_temp_image_name();
9810 uint64_t size
= 1 << 18;
9812 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9814 librbd::Image image1
;
9815 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9818 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9819 ASSERT_FALSE(lock_owner
);
9821 // journaling should force read ops to acquire the lock
9823 ASSERT_EQ(0, image1
.read(0, 0, read_bl
));
9825 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
9826 ASSERT_TRUE(lock_owner
);
9828 librbd::Image image2
;
9829 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9831 std::list
<librbd::RBD::AioCompletion
*> comps
;
9832 std::list
<bufferlist
> read_bls
;
9833 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
9834 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
9836 comps
.push_back(comp
);
9837 read_bls
.emplace_back();
9838 if (object_no
% 2 == 0) {
9839 ASSERT_EQ(0, image1
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
9841 ASSERT_EQ(0, image2
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
9845 while (!comps
.empty()) {
9846 librbd::RBD::AioCompletion
*comp
= comps
.front();
9848 ASSERT_EQ(0, comp
->wait_for_complete());
9849 ASSERT_EQ(1, comp
->is_complete());
9854 TEST_F(TestLibRBD
, CacheMayCopyOnWrite
) {
9855 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
9857 librados::IoCtx ioctx
;
9858 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9861 std::string name
= get_temp_image_name();
9863 uint64_t size
= 1 << 18;
9865 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9867 librbd::Image image
;
9868 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9869 ASSERT_EQ(0, image
.snap_create("one"));
9870 ASSERT_EQ(0, image
.snap_protect("one"));
9872 std::string clone_name
= this->get_temp_image_name();
9873 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
9874 RBD_FEATURE_LAYERING
, &order
));
9876 librbd::Image clone
;
9877 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
9878 ASSERT_EQ(0, clone
.flush());
9880 bufferlist expect_bl
;
9881 expect_bl
.append(std::string(1024, '\0'));
9883 // test double read path
9885 uint64_t offset
= 0;
9886 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
9887 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
9889 bufferlist write_bl
;
9890 write_bl
.append(std::string(1024, '1'));
9891 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
9894 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
9895 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
9897 // test read retry path
9898 offset
= 1 << order
;
9899 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
9902 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
9903 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
9906 TEST_F(TestLibRBD
, FlushEmptyOpsOnExternalSnapshot
) {
9907 std::string cache_enabled
;
9908 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", cache_enabled
));
9909 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", "false"));
9910 BOOST_SCOPE_EXIT( (cache_enabled
) ) {
9911 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", cache_enabled
.c_str()));
9912 } BOOST_SCOPE_EXIT_END
;
9914 librados::IoCtx ioctx
;
9915 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9918 std::string name
= get_temp_image_name();
9919 uint64_t size
= 1 << 18;
9921 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9923 librbd::Image image1
;
9924 librbd::Image image2
;
9925 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9926 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9927 ASSERT_EQ(0, image1
.snap_create("snap1"));
9929 librbd::RBD::AioCompletion
*read_comp
=
9930 new librbd::RBD::AioCompletion(NULL
, NULL
);
9932 image2
.aio_read(0, 1024, read_bl
, read_comp
);
9933 ASSERT_EQ(0, read_comp
->wait_for_complete());
9934 read_comp
->release();
9937 TEST_F(TestLibRBD
, TestImageOptions
)
9939 rados_ioctx_t ioctx
;
9940 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
9942 //make create image options
9943 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
9945 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
9946 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
9947 rbd_image_options_t opts
;
9948 rbd_image_options_create(&opts
);
9951 ASSERT_EQ(-EINVAL
, rbd_image_options_is_set(opts
, 12345, &is_set
));
9952 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
9954 ASSERT_FALSE(is_set
);
9956 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FORMAT
,
9958 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FEATURES
,
9960 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
9962 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_UNIT
,
9964 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_COUNT
,
9967 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
9969 ASSERT_TRUE(is_set
);
9971 std::string parent_name
= get_temp_image_name();
9974 ASSERT_EQ(0, rbd_create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
9976 // check order is returned in opts
9977 ASSERT_EQ(0, rbd_image_options_get_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
9979 ASSERT_NE((uint64_t)0, order
);
9981 // write some data to parent
9983 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
9984 char *data
= (char *)"testdata";
9985 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
9986 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
9988 // create a snapshot, reopen as the parent we're interested in
9989 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
9990 ASSERT_EQ(0, rbd_close(parent
));
9991 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
9994 std::string child_name
= get_temp_image_name();
9995 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
9996 ASSERT_EQ(0, rbd_clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
9997 child_name
.c_str(), opts
));
10000 std::string copy1_name
= get_temp_image_name();
10001 ASSERT_EQ(0, rbd_copy3(parent
, ioctx
, copy1_name
.c_str(), opts
));
10002 std::string copy2_name
= get_temp_image_name();
10003 ASSERT_EQ(0, rbd_copy_with_progress3(parent
, ioctx
, copy2_name
.c_str(), opts
,
10004 print_progress_percent
, NULL
));
10006 ASSERT_EQ(0, rbd_close(parent
));
10008 rbd_image_options_destroy(opts
);
10010 rados_ioctx_destroy(ioctx
);
10013 TEST_F(TestLibRBD
, TestImageOptionsPP
)
10015 librados::IoCtx ioctx
;
10016 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10018 //make create image options
10019 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
10020 uint64_t order
= 0;
10021 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
10022 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
10023 librbd::ImageOptions opts
;
10024 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FORMAT
, static_cast<uint64_t>(2)));
10025 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FEATURES
, features
));
10026 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_ORDER
, order
));
10027 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
));
10028 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
));
10031 std::string parent_name
= get_temp_image_name();
10034 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
10036 // check order is returned in opts
10037 ASSERT_EQ(0, opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
));
10038 ASSERT_NE((uint64_t)0, order
);
10040 // write some data to parent
10041 librbd::Image parent
;
10042 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
10044 ssize_t len
= 1024;
10046 bl
.append(buffer::create(len
));
10048 ASSERT_EQ(len
, parent
.write(0, len
, bl
));
10049 ASSERT_EQ(len
, parent
.write(len
, len
, bl
));
10051 // create a snapshot, reopen as the parent we're interested in
10052 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
10053 ASSERT_EQ(0, parent
.close());
10054 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
10057 std::string child_name
= get_temp_image_name();
10058 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
10059 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
10060 child_name
.c_str(), opts
));
10063 std::string copy1_name
= get_temp_image_name();
10064 ASSERT_EQ(0, parent
.copy3(ioctx
, copy1_name
.c_str(), opts
));
10065 std::string copy2_name
= get_temp_image_name();
10067 ASSERT_EQ(0, parent
.copy_with_progress3(ioctx
, copy2_name
.c_str(), opts
, pp
));
10069 ASSERT_EQ(0, parent
.close());
10072 TEST_F(TestLibRBD
, EventSocketPipe
)
10074 EventSocket event_sock
;
10075 int pipe_fd
[2]; // read and write fd
10078 ASSERT_EQ(0, pipe(pipe_fd
));
10080 ASSERT_FALSE(event_sock
.is_valid());
10082 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_NONE
));
10083 ASSERT_FALSE(event_sock
.is_valid());
10085 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], 44));
10086 ASSERT_FALSE(event_sock
.is_valid());
10088 #ifndef HAVE_EVENTFD
10089 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_EVENTFD
));
10090 ASSERT_FALSE(event_sock
.is_valid());
10093 ASSERT_EQ(0, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_PIPE
));
10094 ASSERT_TRUE(event_sock
.is_valid());
10095 ASSERT_EQ(0, event_sock
.notify());
10096 ASSERT_EQ(1, read(pipe_fd
[0], buf
, 32));
10097 ASSERT_EQ('i', buf
[0]);
10103 TEST_F(TestLibRBD
, EventSocketEventfd
)
10105 #ifdef HAVE_EVENTFD
10106 EventSocket event_sock
;
10108 struct pollfd poll_fd
;
10111 event_fd
= eventfd(0, EFD_NONBLOCK
);
10112 ASSERT_NE(-1, event_fd
);
10114 ASSERT_FALSE(event_sock
.is_valid());
10116 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_NONE
));
10117 ASSERT_FALSE(event_sock
.is_valid());
10119 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, 44));
10120 ASSERT_FALSE(event_sock
.is_valid());
10122 ASSERT_EQ(0, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_EVENTFD
));
10123 ASSERT_TRUE(event_sock
.is_valid());
10124 ASSERT_EQ(0, event_sock
.notify());
10126 poll_fd
.fd
= event_fd
;
10127 poll_fd
.events
= POLLIN
;
10128 ASSERT_EQ(1, poll(&poll_fd
, 1, -1));
10129 ASSERT_TRUE(poll_fd
.revents
& POLLIN
);
10131 ASSERT_EQ(static_cast<ssize_t
>(sizeof(uint64_t)), read(event_fd
, buf
, 32));
10132 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf
));
10138 TEST_F(TestLibRBD
, ImagePollIO
)
10140 #ifdef HAVE_EVENTFD
10141 rados_ioctx_t ioctx
;
10142 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
10146 std::string name
= get_temp_image_name();
10147 uint64_t size
= 2 << 20;
10148 int fd
= eventfd(0, EFD_NONBLOCK
);
10150 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
10151 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
10153 ASSERT_EQ(0, rbd_set_image_notification(image
, fd
, EVENT_SOCKET_TYPE_EVENTFD
));
10155 char test_data
[TEST_IO_SIZE
+ 1];
10156 char zero_data
[TEST_IO_SIZE
+ 1];
10159 for (i
= 0; i
< TEST_IO_SIZE
; ++i
)
10160 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
10161 test_data
[TEST_IO_SIZE
] = '\0';
10162 memset(zero_data
, 0, sizeof(zero_data
));
10164 for (i
= 0; i
< 5; ++i
)
10165 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
10167 for (i
= 5; i
< 10; ++i
)
10168 ASSERT_PASSED(aio_write_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
10170 for (i
= 5; i
< 10; ++i
)
10171 ASSERT_PASSED(aio_read_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
10173 ASSERT_EQ(0, rbd_close(image
));
10174 rados_ioctx_destroy(ioctx
);
10180 static bool operator==(const image_spec_t
&lhs
, const image_spec_t
&rhs
) {
10181 return (lhs
.id
== rhs
.id
&& lhs
.name
== rhs
.name
);
10184 static bool operator==(const linked_image_spec_t
&lhs
,
10185 const linked_image_spec_t
&rhs
) {
10186 return (lhs
.pool_id
== rhs
.pool_id
&&
10187 lhs
.pool_name
== rhs
.pool_name
&&
10188 lhs
.pool_namespace
== rhs
.pool_namespace
&&
10189 lhs
.image_id
== rhs
.image_id
&&
10190 lhs
.image_name
== rhs
.image_name
&&
10191 lhs
.trash
== rhs
.trash
);
10194 static bool operator==(const mirror_peer_t
&lhs
, const mirror_peer_t
&rhs
) {
10195 return (lhs
.uuid
== rhs
.uuid
&&
10196 lhs
.cluster_name
== rhs
.cluster_name
&&
10197 lhs
.client_name
== rhs
.client_name
);
10200 static std::ostream
& operator<<(std::ostream
&os
, const mirror_peer_t
&peer
) {
10201 os
<< "uuid=" << peer
.uuid
<< ", "
10202 << "cluster=" << peer
.cluster_name
<< ", "
10203 << "client=" << peer
.client_name
;
10207 } // namespace librbd
10209 TEST_F(TestLibRBD
, Mirror
) {
10210 librados::IoCtx ioctx
;
10211 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10215 std::vector
<librbd::mirror_peer_t
> expected_peers
;
10216 std::vector
<librbd::mirror_peer_t
> peers
;
10217 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
10218 ASSERT_EQ(expected_peers
, peers
);
10221 ASSERT_EQ(-EINVAL
, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
10223 rbd_mirror_mode_t mirror_mode
;
10224 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
10225 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED
, mirror_mode
);
10227 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
10228 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
10230 // Add some images to the pool
10232 std::string parent_name
= get_temp_image_name();
10233 std::string child_name
= get_temp_image_name();
10234 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), 2 << 20,
10238 ASSERT_EQ(0, get_features(&old_format
, &features
));
10239 if ((features
& RBD_FEATURE_LAYERING
) != 0) {
10240 librbd::Image parent
;
10241 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
10242 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
10243 ASSERT_EQ(0, parent
.close());
10244 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
10245 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
10246 ASSERT_EQ(0, parent
.close());
10247 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
10248 child_name
.c_str(), features
, &order
));
10251 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE
, mirror_mode
);
10253 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_POOL
));
10254 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
10255 ASSERT_EQ(RBD_MIRROR_MODE_POOL
, mirror_mode
);
10259 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
10260 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid2
, "cluster2", "admin"));
10261 ASSERT_EQ(-EEXIST
, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster1", "foo"));
10262 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster3", "admin"));
10264 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
10265 auto sort_peers
= [](const librbd::mirror_peer_t
&lhs
,
10266 const librbd::mirror_peer_t
&rhs
) {
10267 return lhs
.uuid
< rhs
.uuid
;
10270 {uuid1
, "cluster1", "client"},
10271 {uuid2
, "cluster2", "admin"},
10272 {uuid3
, "cluster3", "admin"}};
10273 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
10274 ASSERT_EQ(expected_peers
, peers
);
10276 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, "uuid4"));
10277 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid2
));
10279 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_client(ioctx
, "uuid4", "new client"));
10280 ASSERT_EQ(0, rbd
.mirror_peer_set_client(ioctx
, uuid1
, "new client"));
10282 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_cluster(ioctx
, "uuid4",
10284 ASSERT_EQ(0, rbd
.mirror_peer_set_cluster(ioctx
, uuid3
, "new cluster"));
10286 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
10288 {uuid1
, "cluster1", "new client"},
10289 {uuid3
, "new cluster", "admin"}};
10290 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
10291 ASSERT_EQ(expected_peers
, peers
);
10293 ASSERT_EQ(-EBUSY
, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
10294 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid1
));
10295 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid3
));
10296 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
10299 TEST_F(TestLibRBD
, MirrorPeerAttributes
) {
10300 REQUIRE(!is_librados_test_stub(_rados
));
10302 librados::IoCtx ioctx
;
10303 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10306 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
10309 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid
, "remote_cluster", "client"));
10311 std::map
<std::string
, std::string
> attributes
;
10312 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_get_attributes(ioctx
, uuid
, &attributes
));
10313 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_attributes(ioctx
, "missing uuid",
10316 std::map
<std::string
, std::string
> expected_attributes
{
10317 {"mon_host", "1.2.3.4"},
10319 ASSERT_EQ(0, rbd
.mirror_peer_set_attributes(ioctx
, uuid
,
10320 expected_attributes
));
10322 ASSERT_EQ(0, rbd
.mirror_peer_get_attributes(ioctx
, uuid
,
10324 ASSERT_EQ(expected_attributes
, attributes
);
10326 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid
));
10327 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
10330 TEST_F(TestLibRBD
, CreateWithMirrorEnabled
) {
10331 REQUIRE_FORMAT_V2();
10333 librados::IoCtx ioctx
;
10334 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10337 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
10339 librbd::ImageOptions image_options
;
10340 ASSERT_EQ(0, image_options
.set(
10341 RBD_IMAGE_OPTION_MIRROR_IMAGE_MODE
,
10342 static_cast<uint64_t>(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
)));
10344 std::string parent_name
= get_temp_image_name();
10345 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 2<<20, image_options
));
10347 librbd::Image parent_image
;
10348 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
10350 librbd::mirror_image_mode_t mirror_image_mode
;
10351 ASSERT_EQ(0, parent_image
.mirror_image_get_mode(&mirror_image_mode
));
10352 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
10354 ASSERT_EQ(0, parent_image
.snap_create("parent_snap"));
10355 ASSERT_EQ(0, parent_image
.snap_protect("parent_snap"));
10357 std::string child_name
= get_temp_image_name();
10358 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
10359 child_name
.c_str(), image_options
));
10361 librbd::Image child_image
;
10362 ASSERT_EQ(0, rbd
.open(ioctx
, child_image
, child_name
.c_str(), NULL
));
10364 ASSERT_EQ(0, child_image
.mirror_image_get_mode(&mirror_image_mode
));
10365 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
10367 ASSERT_EQ(0, child_image
.mirror_image_disable(true));
10368 ASSERT_EQ(0, parent_image
.mirror_image_disable(true));
10369 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
10372 TEST_F(TestLibRBD
, FlushCacheWithCopyupOnExternalSnapshot
) {
10373 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
10375 librados::IoCtx ioctx
;
10376 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10379 librbd::Image image
;
10380 std::string name
= get_temp_image_name();
10382 uint64_t size
= 1 << 18;
10385 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
10386 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
10389 bl
.append(std::string(size
, '1'));
10390 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
10391 ASSERT_EQ(0, image
.snap_create("one"));
10392 ASSERT_EQ(0, image
.snap_protect("one"));
10394 std::string clone_name
= this->get_temp_image_name();
10395 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
10396 RBD_FEATURE_LAYERING
, &order
));
10397 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
10399 librbd::Image image2
;
10400 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, clone_name
.c_str(), NULL
));
10402 // prepare CoW writeback that will be flushed on next op
10404 bl
.append(std::string(1, '1'));
10405 ASSERT_EQ(0, image
.flush());
10406 ASSERT_EQ(1, image
.write(0, 1, bl
));
10407 ASSERT_EQ(0, image2
.snap_create("snap1"));
10409 librbd::RBD::AioCompletion
*read_comp
=
10410 new librbd::RBD::AioCompletion(NULL
, NULL
);
10411 bufferlist read_bl
;
10412 image
.aio_read(0, 1024, read_bl
, read_comp
);
10413 ASSERT_EQ(0, read_comp
->wait_for_complete());
10414 read_comp
->release();
10417 TEST_F(TestLibRBD
, ExclusiveLock
)
10419 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
10421 static char buf
[10];
10423 rados_ioctx_t ioctx
;
10424 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
10426 std::string name
= get_temp_image_name();
10427 uint64_t size
= 2 << 20;
10429 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
10431 rbd_image_t image1
;
10432 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
10435 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
10436 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
10437 ASSERT_TRUE(lock_owner
);
10439 rbd_lock_mode_t lock_mode
;
10440 char *lock_owners
[1];
10441 size_t max_lock_owners
= 0;
10442 ASSERT_EQ(-ERANGE
, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
10443 &max_lock_owners
));
10444 ASSERT_EQ(1U, max_lock_owners
);
10446 ASSERT_EQ(0, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
10447 &max_lock_owners
));
10448 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
10449 ASSERT_STRNE("", lock_owners
[0]);
10450 ASSERT_EQ(1U, max_lock_owners
);
10452 rbd_image_t image2
;
10453 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
10455 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
10456 ASSERT_FALSE(lock_owner
);
10458 ASSERT_EQ(-EOPNOTSUPP
, rbd_lock_break(image1
, RBD_LOCK_MODE_SHARED
, ""));
10459 ASSERT_EQ(-EBUSY
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
10462 ASSERT_EQ(0, rbd_lock_release(image1
));
10463 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
10464 ASSERT_FALSE(lock_owner
);
10466 ASSERT_EQ(-ENOENT
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
10468 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
10470 ASSERT_EQ(-EROFS
, rbd_write(image1
, 0, sizeof(buf
), buf
));
10471 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image2
, 0, sizeof(buf
), buf
));
10473 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
10474 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
10475 ASSERT_TRUE(lock_owner
);
10477 ASSERT_EQ(0, rbd_lock_release(image2
));
10478 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
10479 ASSERT_FALSE(lock_owner
);
10481 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
10482 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
10483 ASSERT_TRUE(lock_owner
);
10485 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image1
, 0, sizeof(buf
), buf
));
10486 ASSERT_EQ(-EROFS
, rbd_write(image2
, 0, sizeof(buf
), buf
));
10488 ASSERT_EQ(0, rbd_lock_release(image1
));
10489 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
10490 ASSERT_FALSE(lock_owner
);
10494 const auto pingpong
= [&](int m_id
, rbd_image_t
&m_image
) {
10495 for (int i
= 0; i
< 10; i
++) {
10497 std::lock_guard
<std::mutex
> locker(lock
);
10498 if (owner_id
== m_id
) {
10499 std::cout
<< m_id
<< ": releasing exclusive lock" << std::endl
;
10500 EXPECT_EQ(0, rbd_lock_release(m_image
));
10502 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
10503 EXPECT_FALSE(lock_owner
);
10505 std::cout
<< m_id
<< ": exclusive lock released" << std::endl
;
10510 std::cout
<< m_id
<< ": acquiring exclusive lock" << std::endl
;
10513 r
= rbd_lock_acquire(m_image
, RBD_LOCK_MODE_EXCLUSIVE
);
10517 } while (r
== -EROFS
);
10521 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
10522 EXPECT_TRUE(lock_owner
);
10523 std::cout
<< m_id
<< ": exclusive lock acquired" << std::endl
;
10525 std::lock_guard
<std::mutex
> locker(lock
);
10528 usleep(rand() % 50000);
10531 std::lock_guard
<std::mutex
> locker(lock
);
10532 if (owner_id
== m_id
) {
10533 EXPECT_EQ(0, rbd_lock_release(m_image
));
10535 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
10536 EXPECT_FALSE(lock_owner
);
10540 thread
ping(bind(pingpong
, 1, ref(image1
)));
10541 thread
pong(bind(pingpong
, 2, ref(image2
)));
10546 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
10547 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
10548 ASSERT_TRUE(lock_owner
);
10550 ASSERT_EQ(0, rbd_close(image2
));
10552 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
10553 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
10554 ASSERT_TRUE(lock_owner
);
10556 ASSERT_EQ(0, rbd_close(image1
));
10557 rados_ioctx_destroy(ioctx
);
10560 TEST_F(TestLibRBD
, BreakLock
)
10563 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
10564 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
10566 static char buf
[10];
10568 rados_t blocklist_cluster
;
10569 ASSERT_EQ("", connect_cluster(&blocklist_cluster
));
10571 rados_ioctx_t ioctx
, blocklist_ioctx
;
10572 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
10573 ASSERT_EQ(0, rados_ioctx_create(blocklist_cluster
, m_pool_name
.c_str(),
10574 &blocklist_ioctx
));
10576 std::string name
= get_temp_image_name();
10577 uint64_t size
= 2 << 20;
10579 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
10581 rbd_image_t image
, blocklist_image
;
10582 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
10583 ASSERT_EQ(0, rbd_open(blocklist_ioctx
, name
.c_str(), &blocklist_image
, NULL
));
10585 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_blocklist_on_break_lock", "true"));
10586 ASSERT_EQ(0, rbd_lock_acquire(blocklist_image
, RBD_LOCK_MODE_EXCLUSIVE
));
10588 rbd_lock_mode_t lock_mode
;
10589 char *lock_owners
[1];
10590 size_t max_lock_owners
= 1;
10591 ASSERT_EQ(0, rbd_lock_get_owners(image
, &lock_mode
, lock_owners
,
10592 &max_lock_owners
));
10593 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
10594 ASSERT_STRNE("", lock_owners
[0]);
10595 ASSERT_EQ(1U, max_lock_owners
);
10597 ASSERT_EQ(0, rbd_lock_break(image
, RBD_LOCK_MODE_EXCLUSIVE
, lock_owners
[0]));
10598 ASSERT_EQ(0, rbd_lock_acquire(image
, RBD_LOCK_MODE_EXCLUSIVE
));
10599 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blocklist_cluster
));
10601 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image
, 0, sizeof(buf
), buf
));
10602 ASSERT_EQ(-EBLOCKLISTED
, rbd_write(blocklist_image
, 0, sizeof(buf
), buf
));
10604 ASSERT_EQ(0, rbd_close(image
));
10605 ASSERT_EQ(0, rbd_close(blocklist_image
));
10607 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
10609 rados_ioctx_destroy(ioctx
);
10610 rados_ioctx_destroy(blocklist_ioctx
);
10611 rados_shutdown(blocklist_cluster
);
10614 TEST_F(TestLibRBD
, DiscardAfterWrite
)
10616 librados::IoCtx ioctx
;
10617 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10620 std::string name
= get_temp_image_name();
10621 uint64_t size
= 1 << 20;
10623 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
10625 librbd::Image image
;
10626 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
10628 if (this->is_skip_partial_discard_enabled(image
)) {
10632 // enable writeback cache
10633 ASSERT_EQ(0, image
.flush());
10636 bl
.append(std::string(256, '1'));
10638 librbd::RBD::AioCompletion
*write_comp
=
10639 new librbd::RBD::AioCompletion(NULL
, NULL
);
10640 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
10641 ASSERT_EQ(0, write_comp
->wait_for_complete());
10642 write_comp
->release();
10644 librbd::RBD::AioCompletion
*discard_comp
=
10645 new librbd::RBD::AioCompletion(NULL
, NULL
);
10646 ASSERT_EQ(0, image
.aio_discard(0, 256, discard_comp
));
10647 ASSERT_EQ(0, discard_comp
->wait_for_complete());
10648 discard_comp
->release();
10650 librbd::RBD::AioCompletion
*read_comp
=
10651 new librbd::RBD::AioCompletion(NULL
, NULL
);
10652 bufferlist read_bl
;
10653 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
10654 ASSERT_EQ(0, read_comp
->wait_for_complete());
10655 ASSERT_EQ(bl
.length(), read_comp
->get_return_value());
10656 ASSERT_TRUE(read_bl
.is_zero());
10657 read_comp
->release();
10660 TEST_F(TestLibRBD
, DefaultFeatures
) {
10661 std::string orig_default_features
;
10662 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", orig_default_features
));
10663 BOOST_SCOPE_EXIT_ALL(orig_default_features
) {
10664 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features",
10665 orig_default_features
.c_str()));
10668 std::list
<std::pair
<std::string
, std::string
> > feature_names_to_bitmask
= {
10669 {"", orig_default_features
},
10671 {"layering, exclusive-lock", "5"},
10672 {"exclusive-lock,journaling", "68"},
10676 for (auto &pair
: feature_names_to_bitmask
) {
10677 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features", pair
.first
.c_str()));
10678 std::string features
;
10679 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", features
));
10680 ASSERT_EQ(pair
.second
, features
);
10684 TEST_F(TestLibRBD
, TestTrashMoveAndPurge
) {
10685 REQUIRE_FORMAT_V2();
10687 librados::IoCtx ioctx
;
10688 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10691 std::string name
= get_temp_image_name();
10693 uint64_t size
= 1 << 18;
10695 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
10697 librbd::Image image
;
10698 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
10700 std::string image_id
;
10701 ASSERT_EQ(0, image
.get_id(&image_id
));
10704 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 0));
10706 std::vector
<std::string
> images
;
10707 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
10708 for (const auto& image
: images
) {
10709 ASSERT_TRUE(image
!= name
);
10712 librbd::trash_image_info_t info
;
10713 ASSERT_EQ(-ENOENT
, rbd
.trash_get(ioctx
, "dummy image id", &info
));
10714 ASSERT_EQ(0, rbd
.trash_get(ioctx
, image_id
.c_str(), &info
));
10715 ASSERT_EQ(image_id
, info
.id
);
10717 std::vector
<librbd::trash_image_info_t
> entries
;
10718 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
10719 ASSERT_FALSE(entries
.empty());
10720 ASSERT_EQ(entries
.begin()->id
, image_id
);
10724 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
10726 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
10727 ASSERT_TRUE(entries
.empty());
10730 TEST_F(TestLibRBD
, TestTrashMoveAndPurgeNonExpiredDelay
) {
10731 REQUIRE_FORMAT_V2();
10733 librados::IoCtx ioctx
;
10734 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10737 std::string name
= get_temp_image_name();
10739 uint64_t size
= 1 << 18;
10741 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
10743 librbd::Image image
;
10744 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
10746 std::string image_id
;
10747 ASSERT_EQ(0, image
.get_id(&image_id
));
10750 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 100));
10753 ASSERT_EQ(-EPERM
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
10757 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
10761 TEST_F(TestLibRBD
, TestTrashPurge
) {
10762 REQUIRE_FORMAT_V2();
10764 librados::IoCtx ioctx
;
10765 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10768 std::string name1
= get_temp_image_name();
10769 std::string name2
= get_temp_image_name();
10771 uint64_t size
= 1 << 18;
10773 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name1
.c_str(), size
, &order
));
10774 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
10776 librbd::Image image1
;
10777 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name1
.c_str(), nullptr));
10779 std::string image_id1
;
10780 ASSERT_EQ(0, image1
.get_id(&image_id1
));
10783 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name1
.c_str(), 0));
10785 librbd::Image image2
;
10786 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), nullptr));
10787 ceph::bufferlist bl
;
10788 bl
.append(std::string(1024, '0'));
10789 ASSERT_EQ(1024, image2
.write(0, 1024, bl
));
10791 std::string image_id2
;
10792 ASSERT_EQ(0, image2
.get_id(&image_id2
));
10795 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name2
.c_str(), 100));
10796 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, 0, -1));
10798 std::vector
<librbd::trash_image_info_t
> entries
;
10799 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
10800 ASSERT_EQ(1U, entries
.size());
10801 ASSERT_EQ(image_id2
, entries
[0].id
);
10802 ASSERT_EQ(name2
, entries
[0].name
);
10805 struct timespec now
;
10806 clock_gettime(CLOCK_REALTIME
, &now
);
10807 float threshold
= 0.0;
10808 if (!is_librados_test_stub(_rados
)) {
10809 // real cluster usage reports have a long latency to update
10813 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, now
.tv_sec
+1000, threshold
));
10814 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
10815 ASSERT_EQ(0U, entries
.size());
10818 TEST_F(TestLibRBD
, TestTrashMoveAndRestore
) {
10819 REQUIRE_FORMAT_V2();
10821 librados::IoCtx ioctx
;
10822 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10825 std::string name
= get_temp_image_name();
10827 uint64_t size
= 1 << 18;
10829 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
10831 librbd::Image image
;
10832 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
10834 std::string image_id
;
10835 ASSERT_EQ(0, image
.get_id(&image_id
));
10838 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 10));
10840 std::vector
<std::string
> images
;
10841 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
10842 for (const auto& image
: images
) {
10843 ASSERT_TRUE(image
!= name
);
10846 std::vector
<librbd::trash_image_info_t
> entries
;
10847 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
10848 ASSERT_FALSE(entries
.empty());
10849 ASSERT_EQ(entries
.begin()->id
, image_id
);
10852 ASSERT_EQ(0, rbd
.trash_restore(ioctx
, image_id
.c_str(), ""));
10853 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
10854 ASSERT_FALSE(images
.empty());
10855 bool found
= false;
10856 for (const auto& image
: images
) {
10857 if (image
== name
) {
10862 ASSERT_TRUE(found
);
10865 TEST_F(TestLibRBD
, TestListWatchers
) {
10866 librados::IoCtx ioctx
;
10867 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10870 std::string name
= get_temp_image_name();
10872 uint64_t size
= 1 << 18;
10874 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
10876 librbd::Image image
;
10877 std::list
<librbd::image_watcher_t
> watchers
;
10880 ASSERT_EQ(0, rbd
.open_read_only(ioctx
, image
, name
.c_str(), nullptr));
10881 ASSERT_EQ(0, image
.list_watchers(watchers
));
10882 ASSERT_EQ(0U, watchers
.size());
10883 ASSERT_EQ(0, image
.close());
10886 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
10887 ASSERT_EQ(0, image
.list_watchers(watchers
));
10888 ASSERT_EQ(1U, watchers
.size());
10889 auto watcher1
= watchers
.front();
10890 ASSERT_EQ(0, image
.close());
10892 // (Still) one watcher
10893 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
10894 ASSERT_EQ(0, image
.list_watchers(watchers
));
10895 ASSERT_EQ(1U, watchers
.size());
10896 auto watcher2
= watchers
.front();
10897 ASSERT_EQ(0, image
.close());
10899 EXPECT_EQ(watcher1
.addr
, watcher2
.addr
);
10900 EXPECT_EQ(watcher1
.id
, watcher2
.id
);
10903 TEST_F(TestLibRBD
, TestSetSnapById
) {
10904 librados::IoCtx ioctx
;
10905 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10908 std::string name
= get_temp_image_name();
10910 uint64_t size
= 1 << 18;
10912 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
10914 librbd::Image image
;
10915 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
10916 ASSERT_EQ(0, image
.snap_create("snap"));
10918 vector
<librbd::snap_info_t
> snaps
;
10919 ASSERT_EQ(0, image
.snap_list(snaps
));
10920 ASSERT_EQ(1U, snaps
.size());
10922 ASSERT_EQ(0, image
.snap_set_by_id(snaps
[0].id
));
10923 ASSERT_EQ(0, image
.snap_set_by_id(CEPH_NOSNAP
));
10926 TEST_F(TestLibRBD
, Namespaces
) {
10927 rados_ioctx_t ioctx
;
10928 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
10929 rados_remove(ioctx
, RBD_NAMESPACE
);
10931 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name1"));
10932 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name2"));
10933 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name3"));
10934 ASSERT_EQ(0, rbd_namespace_remove(ioctx
, "name2"));
10937 size_t max_size
= sizeof(names
);
10938 int len
= rbd_namespace_list(ioctx
, names
, &max_size
);
10940 std::vector
<std::string
> cpp_names
;
10941 for (char* cur_name
= names
; cur_name
< names
+ len
; ) {
10942 cpp_names
.push_back(cur_name
);
10943 cur_name
+= strlen(cur_name
) + 1;
10945 ASSERT_EQ(2U, cpp_names
.size());
10946 ASSERT_EQ("name1", cpp_names
[0]);
10947 ASSERT_EQ("name3", cpp_names
[1]);
10949 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name2", &exists
));
10950 ASSERT_FALSE(exists
);
10951 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name3", &exists
));
10952 ASSERT_TRUE(exists
);
10953 rados_ioctx_destroy(ioctx
);
10956 TEST_F(TestLibRBD
, NamespacesPP
) {
10957 librados::IoCtx ioctx
;
10958 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
10959 ioctx
.remove(RBD_NAMESPACE
);
10962 ASSERT_EQ(-EINVAL
, rbd
.namespace_create(ioctx
, ""));
10963 ASSERT_EQ(-EINVAL
, rbd
.namespace_remove(ioctx
, ""));
10965 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name1"));
10966 ASSERT_EQ(-EEXIST
, rbd
.namespace_create(ioctx
, "name1"));
10967 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name2"));
10968 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name3"));
10969 ASSERT_EQ(0, rbd
.namespace_remove(ioctx
, "name2"));
10970 ASSERT_EQ(-ENOENT
, rbd
.namespace_remove(ioctx
, "name2"));
10972 std::vector
<std::string
> names
;
10973 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
10974 ASSERT_EQ(2U, names
.size());
10975 ASSERT_EQ("name1", names
[0]);
10976 ASSERT_EQ("name3", names
[1]);
10978 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name2", &exists
));
10979 ASSERT_FALSE(exists
);
10980 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name3", &exists
));
10981 ASSERT_TRUE(exists
);
10983 librados::IoCtx ns_io_ctx
;
10984 ns_io_ctx
.dup(ioctx
);
10986 std::string name
= get_temp_image_name();
10988 uint64_t features
= 0;
10989 if (!get_features(&features
)) {
10990 // old format doesn't support namespaces
10991 ns_io_ctx
.set_namespace("name1");
10992 ASSERT_EQ(-EINVAL
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0,
10997 ns_io_ctx
.set_namespace("missing");
10998 ASSERT_EQ(-ENOENT
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
11000 ns_io_ctx
.set_namespace("name1");
11001 ASSERT_EQ(0, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
11002 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
11004 std::string image_id
;
11006 librbd::Image image
;
11007 ASSERT_EQ(-ENOENT
, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
11008 ASSERT_EQ(0, rbd
.open(ns_io_ctx
, image
, name
.c_str(), NULL
));
11009 ASSERT_EQ(0, get_image_id(image
, &image_id
));
11012 ASSERT_EQ(-ENOENT
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
11013 ASSERT_EQ(0, rbd
.trash_move(ns_io_ctx
, name
.c_str(), 0));
11014 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
11017 ASSERT_EQ(-ENOENT
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
11019 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ns_io_ctx
, image_id
.c_str(),
11021 ASSERT_EQ(0, rbd
.namespace_remove(ns_io_ctx
, "name1"));
11024 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
11025 ASSERT_EQ(1U, names
.size());
11026 ASSERT_EQ("name3", names
[0]);
11029 TEST_F(TestLibRBD
, Migration
) {
11032 ASSERT_EQ(0, get_features(&old_format
, &features
));
11034 rados_ioctx_t ioctx
;
11035 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
11036 BOOST_SCOPE_EXIT(&ioctx
) {
11037 rados_ioctx_destroy(ioctx
);
11038 } BOOST_SCOPE_EXIT_END
;
11041 std::string name
= get_temp_image_name();
11042 uint64_t size
= 2 << 20;
11043 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
11045 rbd_image_options_t image_options
;
11046 rbd_image_options_create(&image_options
);
11047 BOOST_SCOPE_EXIT(&image_options
) {
11048 rbd_image_options_destroy(image_options
);
11049 } BOOST_SCOPE_EXIT_END
;
11051 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
11054 rbd_image_migration_status_t status
;
11055 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
11057 ASSERT_EQ(status
.source_pool_id
, rados_ioctx_get_id(ioctx
));
11058 ASSERT_EQ(status
.source_image_name
, name
);
11060 ASSERT_EQ(status
.source_image_id
, string());
11062 ASSERT_NE(status
.source_image_id
, string());
11063 ASSERT_EQ(-EROFS
, rbd_trash_remove(ioctx
, status
.source_image_id
, false));
11064 ASSERT_EQ(-EINVAL
, rbd_trash_restore(ioctx
, status
.source_image_id
, name
.c_str()));
11066 ASSERT_EQ(status
.dest_pool_id
, rados_ioctx_get_id(ioctx
));
11067 ASSERT_EQ(status
.dest_image_name
, name
);
11068 ASSERT_NE(status
.dest_image_id
, string());
11069 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
11070 rbd_migration_status_cleanup(&status
);
11073 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
11074 char source_spec
[2048];
11075 size_t source_spec_length
= sizeof(source_spec
);
11076 ASSERT_EQ(0, rbd_get_migration_source_spec(image
, source_spec
,
11077 &source_spec_length
));
11078 json_spirit::mValue json_source_spec
;
11079 json_spirit::read(source_spec
, json_source_spec
);
11080 EXPECT_EQ(0, rbd_close(image
));
11082 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, name
.c_str()));
11083 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, name
.c_str(), 0));
11085 ASSERT_EQ(0, rbd_migration_execute(ioctx
, name
.c_str()));
11087 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
11089 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
11090 rbd_migration_status_cleanup(&status
);
11092 ASSERT_EQ(0, rbd_migration_commit(ioctx
, name
.c_str()));
11094 std::string new_name
= get_temp_image_name();
11096 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
,
11097 new_name
.c_str(), image_options
));
11099 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, new_name
.c_str()));
11100 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, new_name
.c_str(), 0));
11102 ASSERT_EQ(0, rbd_migration_abort(ioctx
, name
.c_str()));
11104 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
11105 EXPECT_EQ(0, rbd_close(image
));
11108 TEST_F(TestLibRBD
, MigrationPP
) {
11111 ASSERT_EQ(0, get_features(&old_format
, &features
));
11113 librados::IoCtx ioctx
;
11114 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
11117 std::string name
= get_temp_image_name();
11118 uint64_t size
= 2 << 20;
11120 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
11122 librbd::ImageOptions image_options
;
11124 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
11127 librbd::image_migration_status_t status
;
11128 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
11130 ASSERT_EQ(status
.source_pool_id
, ioctx
.get_id());
11131 ASSERT_EQ(status
.source_image_name
, name
);
11133 ASSERT_EQ(status
.source_image_id
, "");
11135 ASSERT_NE(status
.source_image_id
, "");
11136 ASSERT_EQ(-EROFS
, rbd
.trash_remove(ioctx
, status
.source_image_id
.c_str(), false));
11137 ASSERT_EQ(-EINVAL
, rbd
.trash_restore(ioctx
, status
.source_image_id
.c_str(), name
.c_str()));
11139 ASSERT_EQ(status
.dest_pool_id
, ioctx
.get_id());
11140 ASSERT_EQ(status
.dest_image_name
, name
);
11141 ASSERT_NE(status
.dest_image_id
, "");
11142 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
11144 librbd::Image image
;
11145 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
11146 std::string source_spec
;
11147 ASSERT_EQ(0, image
.get_migration_source_spec(&source_spec
));
11148 json_spirit::mValue json_source_spec
;
11149 json_spirit::read(source_spec
, json_source_spec
);
11150 json_spirit::mObject json_source_spec_obj
= json_source_spec
.get_obj();
11151 ASSERT_EQ("native", json_source_spec_obj
["type"].get_str());
11152 ASSERT_EQ(ioctx
.get_id(), json_source_spec_obj
["pool_id"].get_int64());
11153 ASSERT_EQ("", json_source_spec_obj
["pool_namespace"].get_str());
11154 ASSERT_EQ(1, json_source_spec_obj
.count("image_name"));
11156 ASSERT_EQ(1, json_source_spec_obj
.count("image_id"));
11158 ASSERT_EQ(0, image
.close());
11160 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, name
.c_str()));
11161 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
11163 ASSERT_EQ(0, rbd
.migration_execute(ioctx
, name
.c_str()));
11165 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
11167 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
11169 ASSERT_EQ(0, rbd
.migration_commit(ioctx
, name
.c_str()));
11171 std::string new_name
= get_temp_image_name();
11173 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
,
11174 new_name
.c_str(), image_options
));
11176 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, new_name
.c_str()));
11177 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, new_name
.c_str(), 0));
11179 ASSERT_EQ(0, rbd
.migration_abort(ioctx
, name
.c_str()));
11181 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
11184 TEST_F(TestLibRBD
, TestGetAccessTimestamp
)
11186 REQUIRE_FORMAT_V2();
11188 rados_ioctx_t ioctx
;
11189 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
11193 std::string name
= get_temp_image_name();
11194 uint64_t size
= 2 << 20;
11195 struct timespec timestamp
;
11197 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
11198 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
11200 ASSERT_EQ(0, rbd_get_access_timestamp(image
, ×tamp
));
11201 ASSERT_LT(0, timestamp
.tv_sec
);
11203 ASSERT_PASSED(validate_object_map
, image
);
11204 ASSERT_EQ(0, rbd_close(image
));
11206 rados_ioctx_destroy(ioctx
);
11209 TEST_F(TestLibRBD
, TestGetModifyTimestamp
)
11211 REQUIRE_FORMAT_V2();
11213 rados_ioctx_t ioctx
;
11214 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
11218 std::string name
= get_temp_image_name();
11219 uint64_t size
= 2 << 20;
11220 struct timespec timestamp
;
11222 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
11223 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
11224 ASSERT_EQ(0, rbd_get_modify_timestamp(image
, ×tamp
));
11225 ASSERT_LT(0, timestamp
.tv_sec
);
11227 ASSERT_PASSED(validate_object_map
, image
);
11228 ASSERT_EQ(0, rbd_close(image
));
11230 rados_ioctx_destroy(ioctx
);
11233 TEST_F(TestLibRBD
, ZeroOverlapFlatten
) {
11234 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
11236 librados::IoCtx ioctx
;
11237 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
11240 librbd::Image parent_image
;
11241 std::string name
= get_temp_image_name();
11246 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
11247 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
11250 ASSERT_EQ(0, parent_image
.features(&features
));
11252 ASSERT_EQ(0, parent_image
.snap_create("snap"));
11253 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
11255 std::string clone_name
= this->get_temp_image_name();
11256 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
11257 features
, &order
));
11259 librbd::Image clone_image
;
11260 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
11261 ASSERT_EQ(0, clone_image
.resize(0));
11262 ASSERT_EQ(0, clone_image
.flatten());
11265 TEST_F(TestLibRBD
, PoolMetadata
)
11267 REQUIRE_FORMAT_V2();
11269 rados_ioctx_t ioctx
;
11270 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
11274 size_t keys_len
= sizeof(keys
);
11275 size_t vals_len
= sizeof(vals
);
11277 memset_rand(keys
, keys_len
);
11278 memset_rand(vals
, vals_len
);
11280 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
11282 ASSERT_EQ(0U, keys_len
);
11283 ASSERT_EQ(0U, vals_len
);
11286 size_t value_len
= sizeof(value
);
11287 memset_rand(value
, value_len
);
11289 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
11290 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key2", "value2"));
11291 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
11292 ASSERT_STREQ(value
, "value1");
11294 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
11295 ASSERT_EQ(value_len
, strlen("value1") + 1);
11297 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
11299 keys_len
= sizeof(keys
);
11300 vals_len
= sizeof(vals
);
11301 memset_rand(keys
, keys_len
);
11302 memset_rand(vals
, vals_len
);
11303 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
11305 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
11306 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
11307 ASSERT_STREQ(keys
, "key1");
11308 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
11309 ASSERT_STREQ(vals
, "value1");
11310 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
11312 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
11313 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_remove(ioctx
, "key3"));
11314 value_len
= sizeof(value
);
11315 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_get(ioctx
, "key3", value
, &value_len
));
11316 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
11318 ASSERT_EQ(keys_len
, strlen("key2") + 1);
11319 ASSERT_EQ(vals_len
, strlen("value2") + 1);
11320 ASSERT_STREQ(keys
, "key2");
11321 ASSERT_STREQ(vals
, "value2");
11323 // test config setting
11324 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
11325 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
11326 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
11327 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
11329 // test short buffer cases
11330 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
11331 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key3", "value3"));
11332 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key4", "value4"));
11334 keys_len
= strlen("key1") + 1;
11335 vals_len
= strlen("value1") + 1;
11336 memset_rand(keys
, keys_len
);
11337 memset_rand(vals
, vals_len
);
11338 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 1, keys
, &keys_len
, vals
,
11340 ASSERT_EQ(keys_len
, strlen("key1") + 1);
11341 ASSERT_EQ(vals_len
, strlen("value1") + 1);
11342 ASSERT_STREQ(keys
, "key1");
11343 ASSERT_STREQ(vals
, "value1");
11345 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 2, keys
, &keys_len
, vals
,
11347 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
11348 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
11350 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
11352 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
11353 1 + strlen("key4") + 1);
11354 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
11355 strlen("value3") + 1 + strlen("value4") + 1);
11357 // test `start` param
11358 keys_len
= sizeof(keys
);
11359 vals_len
= sizeof(vals
);
11360 memset_rand(keys
, keys_len
);
11361 memset_rand(vals
, vals_len
);
11362 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "key2", 0, keys
, &keys_len
, vals
,
11364 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
11365 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
11366 ASSERT_STREQ(keys
, "key3");
11367 ASSERT_STREQ(vals
, "value3");
11370 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
11371 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key2"));
11372 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key3"));
11373 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key4"));
11374 rados_ioctx_destroy(ioctx
);
11377 TEST_F(TestLibRBD
, PoolMetadataPP
)
11379 REQUIRE_FORMAT_V2();
11383 map
<string
, bufferlist
> pairs
;
11385 librados::IoCtx ioctx
;
11386 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
11388 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
11389 ASSERT_TRUE(pairs
.empty());
11391 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
11392 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key2", "value2"));
11393 ASSERT_EQ(0, rbd
.pool_metadata_get(ioctx
, "key1", &value
));
11394 ASSERT_EQ(value
, "value1");
11395 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
11396 ASSERT_EQ(2U, pairs
.size());
11397 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
11398 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
11400 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
11401 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_remove(ioctx
, "key3"));
11402 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_get(ioctx
, "key3", &value
));
11404 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
11405 ASSERT_EQ(1U, pairs
.size());
11406 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
11408 // test `start` param
11409 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
11410 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key3", "value3"));
11413 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "key2", 0, &pairs
));
11414 ASSERT_EQ(1U, pairs
.size());
11415 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
11417 // test config setting
11418 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
11419 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
11420 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
11421 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
11424 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
11425 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key2"));
11426 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key3"));
11429 TEST_F(TestLibRBD
, Config
)
11431 REQUIRE_FORMAT_V2();
11433 rados_ioctx_t ioctx
;
11434 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
11436 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
11438 rbd_config_option_t options
[1024];
11439 int max_options
= 0;
11440 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
11441 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
11442 ASSERT_GT(max_options
, 0);
11443 ASSERT_LT(max_options
, 1024);
11444 for (int i
= 0; i
< max_options
; i
++) {
11445 if (options
[i
].name
== std::string("rbd_cache")) {
11446 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
11447 ASSERT_STREQ("false", options
[i
].value
);
11449 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
11452 rbd_config_pool_list_cleanup(options
, max_options
);
11456 std::string name
= get_temp_image_name();
11457 uint64_t size
= 2 << 20;
11459 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
11460 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
11462 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
11463 for (int i
= 0; i
< max_options
; i
++) {
11464 if (options
[i
].name
== std::string("rbd_cache")) {
11465 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
11466 ASSERT_STREQ("false", options
[i
].value
);
11468 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
11471 rbd_config_image_list_cleanup(options
, max_options
);
11473 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_cache", "true"));
11475 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
11476 for (int i
= 0; i
< max_options
; i
++) {
11477 if (options
[i
].name
== std::string("rbd_cache")) {
11478 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_IMAGE
);
11479 ASSERT_STREQ("true", options
[i
].value
);
11481 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
11484 rbd_config_image_list_cleanup(options
, max_options
);
11486 ASSERT_EQ(0, rbd_metadata_remove(image
, "conf_rbd_cache"));
11488 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
11489 for (int i
= 0; i
< max_options
; i
++) {
11490 if (options
[i
].name
== std::string("rbd_cache")) {
11491 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
11492 ASSERT_STREQ("false", options
[i
].value
);
11494 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
11497 rbd_config_image_list_cleanup(options
, max_options
);
11499 ASSERT_EQ(0, rbd_close(image
));
11501 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
11503 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
11504 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
11505 for (int i
= 0; i
< max_options
; i
++) {
11506 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
11508 rbd_config_pool_list_cleanup(options
, max_options
);
11510 rados_ioctx_destroy(ioctx
);
11513 TEST_F(TestLibRBD
, ConfigPP
)
11515 REQUIRE_FORMAT_V2();
11520 librados::IoCtx ioctx
;
11521 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
11523 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
11525 std::vector
<librbd::config_option_t
> options
;
11526 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
11527 for (auto &option
: options
) {
11528 if (option
.name
== std::string("rbd_cache")) {
11529 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
11530 ASSERT_EQ("false", option
.value
);
11532 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
11537 std::string name
= get_temp_image_name();
11538 uint64_t size
= 2 << 20;
11539 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
11541 librbd::Image image
;
11542 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
11545 ASSERT_EQ(0, image
.config_list(&options
));
11546 for (auto &option
: options
) {
11547 if (option
.name
== std::string("rbd_cache")) {
11548 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
11549 ASSERT_EQ("false", option
.value
);
11551 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
11555 ASSERT_EQ(0, image
.metadata_set("conf_rbd_cache", "true"));
11558 ASSERT_EQ(0, image
.config_list(&options
));
11559 for (auto &option
: options
) {
11560 if (option
.name
== std::string("rbd_cache")) {
11561 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_IMAGE
);
11562 ASSERT_EQ("true", option
.value
);
11564 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
11568 ASSERT_EQ(0, image
.metadata_remove("conf_rbd_cache"));
11571 ASSERT_EQ(0, image
.config_list(&options
));
11572 for (auto &option
: options
) {
11573 if (option
.name
== std::string("rbd_cache")) {
11574 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
11575 ASSERT_EQ("false", option
.value
);
11577 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
11581 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
11584 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
11585 for (auto &option
: options
) {
11586 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
11590 TEST_F(TestLibRBD
, PoolStatsPP
)
11592 REQUIRE_FORMAT_V2();
11594 librados::IoCtx ioctx
;
11595 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
11598 std::string image_name
;
11599 uint64_t size
= 2 << 20;
11600 uint64_t expected_size
= 0;
11601 for (size_t idx
= 0; idx
< 4; ++idx
) {
11602 image_name
= get_temp_image_name();
11605 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, image_name
.c_str(), size
, &order
));
11606 expected_size
+= size
;
11609 librbd::Image image
;
11610 ASSERT_EQ(0, rbd
.open(ioctx
, image
, image_name
.c_str(), NULL
));
11611 ASSERT_EQ(0, image
.snap_create("snap1"));
11612 ASSERT_EQ(0, image
.resize(0));
11613 ASSERT_EQ(0, image
.close());
11614 uint64_t expect_head_size
= (expected_size
- size
);
11616 uint64_t image_count
;
11617 uint64_t provisioned_bytes
;
11618 uint64_t max_provisioned_bytes
;
11619 uint64_t snap_count
;
11620 uint64_t trash_image_count
;
11621 uint64_t trash_provisioned_bytes
;
11622 uint64_t trash_max_provisioned_bytes
;
11623 uint64_t trash_snap_count
;
11625 librbd::PoolStats pool_stats1
;
11626 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGES
, &image_count
);
11627 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
,
11628 &provisioned_bytes
);
11629 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
11631 ASSERT_EQ(4U, image_count
);
11632 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
11634 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
,
11635 &max_provisioned_bytes
);
11636 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
11637 ASSERT_EQ(4U, image_count
);
11638 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
11639 ASSERT_EQ(expected_size
, max_provisioned_bytes
);
11641 librbd::PoolStats pool_stats2
;
11642 pool_stats2
.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
, &snap_count
);
11643 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
11644 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
11645 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats2
));
11646 ASSERT_EQ(1U, snap_count
);
11647 ASSERT_EQ(0U, trash_image_count
);
11648 ASSERT_EQ(0U, trash_snap_count
);
11650 ASSERT_EQ(0, rbd
.trash_move(ioctx
, image_name
.c_str(), 0));
11652 librbd::PoolStats pool_stats3
;
11653 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
11654 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
,
11655 &trash_provisioned_bytes
);
11656 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
,
11657 &trash_max_provisioned_bytes
);
11658 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
11659 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats3
));
11660 ASSERT_EQ(1U, trash_image_count
);
11661 ASSERT_EQ(0U, trash_provisioned_bytes
);
11662 ASSERT_EQ(size
, trash_max_provisioned_bytes
);
11663 ASSERT_EQ(1U, trash_snap_count
);
11666 TEST_F(TestLibRBD
, ImageSpec
) {
11667 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
11669 librados::IoCtx ioctx
;
11670 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
11673 librbd::Image parent_image
;
11674 std::string name
= get_temp_image_name();
11679 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
11680 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
11682 std::string parent_id
;
11683 ASSERT_EQ(0, parent_image
.get_id(&parent_id
));
11686 ASSERT_EQ(0, parent_image
.features(&features
));
11688 ASSERT_EQ(0, parent_image
.snap_create("snap"));
11689 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
11691 std::string clone_name
= this->get_temp_image_name();
11692 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
11693 features
, &order
));
11695 librbd::Image clone_image
;
11696 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
11698 std::string clone_id
;
11699 ASSERT_EQ(0, clone_image
.get_id(&clone_id
));
11701 std::vector
<librbd::image_spec_t
> images
;
11702 ASSERT_EQ(0, rbd
.list2(ioctx
, &images
));
11704 std::vector
<librbd::image_spec_t
> expected_images
{
11705 {.id
= parent_id
, .name
= name
},
11706 {.id
= clone_id
, .name
= clone_name
}
11708 std::sort(expected_images
.begin(), expected_images
.end(),
11709 [](const librbd::image_spec_t
& lhs
, const librbd::image_spec_t
&rhs
) {
11710 return lhs
.name
< rhs
.name
;
11712 ASSERT_EQ(expected_images
, images
);
11714 librbd::linked_image_spec_t parent_image_spec
;
11715 librbd::snap_spec_t parent_snap_spec
;
11716 ASSERT_EQ(0, clone_image
.get_parent(&parent_image_spec
, &parent_snap_spec
));
11718 librbd::linked_image_spec_t expected_parent_image_spec
{
11719 .pool_id
= ioctx
.get_id(),
11720 .pool_name
= ioctx
.get_pool_name(),
11721 .pool_namespace
= ioctx
.get_namespace(),
11722 .image_id
= parent_id
,
11723 .image_name
= name
,
11726 ASSERT_EQ(expected_parent_image_spec
, parent_image_spec
);
11727 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER
, parent_snap_spec
.namespace_type
);
11728 ASSERT_EQ("snap", parent_snap_spec
.name
);
11730 std::vector
<librbd::linked_image_spec_t
> children
;
11731 ASSERT_EQ(0, parent_image
.list_children3(&children
));
11733 std::vector
<librbd::linked_image_spec_t
> expected_children
{
11735 .pool_id
= ioctx
.get_id(),
11736 .pool_name
= ioctx
.get_pool_name(),
11737 .pool_namespace
= ioctx
.get_namespace(),
11738 .image_id
= clone_id
,
11739 .image_name
= clone_name
,
11743 ASSERT_EQ(expected_children
, children
);
11746 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
11747 ASSERT_EQ(expected_children
, children
);
11749 ASSERT_EQ(0, clone_image
.snap_create("snap"));
11750 ASSERT_EQ(0, clone_image
.snap_protect("snap"));
11752 auto grand_clone_name
= this->get_temp_image_name();
11753 ASSERT_EQ(0, rbd
.clone(ioctx
, clone_name
.c_str(), "snap", ioctx
,
11754 grand_clone_name
.c_str(), features
, &order
));
11755 librbd::Image grand_clone_image
;
11756 ASSERT_EQ(0, rbd
.open(ioctx
, grand_clone_image
, grand_clone_name
.c_str(),
11758 std::string grand_clone_id
;
11759 ASSERT_EQ(0, grand_clone_image
.get_id(&grand_clone_id
));
11762 ASSERT_EQ(0, parent_image
.list_children3(&children
));
11763 ASSERT_EQ(expected_children
, children
);
11766 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
11767 expected_children
.push_back(
11769 .pool_id
= ioctx
.get_id(),
11770 .pool_name
= ioctx
.get_pool_name(),
11771 .pool_namespace
= ioctx
.get_namespace(),
11772 .image_id
= grand_clone_id
,
11773 .image_name
= grand_clone_name
,
11777 ASSERT_EQ(expected_children
, children
);
11780 void super_simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
11784 TEST_F(TestLibRBD
, DISABLED_TestSeqWriteAIOPP
)
11786 librados::IoCtx ioctx
;
11787 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
11791 librbd::Image image
;
11793 std::string name
= get_temp_image_name();
11794 uint64_t size
= 5 * (1 << order
);
11796 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
11797 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
11799 char test_data
[(TEST_IO_SIZE
+ 1) * 10];
11801 for (int i
= 0; i
< 10; i
++) {
11802 for (uint64_t j
= 0; j
< TEST_IO_SIZE
; j
++) {
11803 test_data
[(TEST_IO_SIZE
+ 1) * i
+ j
] = (char)(rand() % (126 - 33) + 33);
11805 test_data
[(TEST_IO_SIZE
+ 1) * i
+ TEST_IO_SIZE
] = '\0';
11808 struct timespec start_time
;
11809 clock_gettime(CLOCK_REALTIME
, &start_time
);
11811 std::list
<librbd::RBD::AioCompletion
*> comps
;
11812 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
11813 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
11814 ceph::bufferlist bl
;
11815 bl
.append(p
, strlen(p
));
11816 auto comp
= new librbd::RBD::AioCompletion(
11817 NULL
, (librbd::callback_t
) super_simple_write_cb_pp
);
11818 image
.aio_write(strlen(p
) * i
, strlen(p
), bl
, comp
);
11819 comps
.push_back(comp
);
11820 if (i
% 1000 == 0) {
11821 cout
<< i
<< " reqs sent" << std::endl
;
11823 for (auto comp
: comps
) {
11824 comp
->wait_for_complete();
11825 ASSERT_EQ(0, comp
->get_return_value());
11832 for (auto comp
: comps
) {
11833 comp
->wait_for_complete();
11834 ASSERT_EQ(0, comp
->get_return_value());
11836 if (i
% 1000 == 0) {
11837 std::cout
<< i
<< " reqs completed" << std::endl
;
11843 struct timespec end_time
;
11844 clock_gettime(CLOCK_REALTIME
, &end_time
);
11845 int duration
= end_time
.tv_sec
* 1000 + end_time
.tv_nsec
/ 1000000 -
11846 start_time
.tv_sec
* 1000 - start_time
.tv_nsec
/ 1000000;
11847 std::cout
<< "duration: " << duration
<< " msec" << std::endl
;
11849 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
11850 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
11851 ASSERT_PASSED(read_test_data
, image
, p
, strlen(p
) * i
, TEST_IO_SIZE
, 0);
11854 ASSERT_PASSED(validate_object_map
, image
);
11860 TEST_F(TestLibRBD
, SnapRemoveWithChildMissing
)
11862 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
11863 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
11864 BOOST_SCOPE_EXIT_ALL(&) {
11865 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
11869 rados_ioctx_t ioctx1
, ioctx2
;
11870 string pool_name1
= create_pool(true);
11871 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
11872 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx2
));
11876 rbd_image_t parent
, child1
, child2
, child3
;
11878 char child_id1
[4096];
11879 char child_id2
[4096];
11880 char child_id3
[4096];
11882 ASSERT_EQ(0, get_features(&old_format
, &features
));
11883 ASSERT_FALSE(old_format
);
11884 std::string parent_name
= get_temp_image_name();
11885 std::string child_name1
= get_temp_image_name();
11886 std::string child_name2
= get_temp_image_name();
11887 std::string child_name3
= get_temp_image_name();
11888 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
11890 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
11891 ASSERT_EQ(0, rbd_snap_create(parent
, "snap1"));
11892 ASSERT_EQ(0, rbd_snap_create(parent
, "snap2"));
11894 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap1",
11895 ioctx2
, child_name1
.c_str(), features
, &order
));
11896 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
11897 ioctx1
, child_name2
.c_str(), features
, &order
));
11898 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
11899 ioctx2
, child_name3
.c_str(), features
, &order
));
11901 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &child1
, NULL
));
11902 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &child2
, NULL
));
11903 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &child3
, NULL
));
11904 ASSERT_EQ(0, rbd_get_id(child1
, child_id1
, sizeof(child_id1
)));
11905 ASSERT_EQ(0, rbd_get_id(child2
, child_id2
, sizeof(child_id2
)));
11906 ASSERT_EQ(0, rbd_get_id(child3
, child_id3
, sizeof(child_id3
)));
11907 test_list_children2(parent
, 3,
11908 child_id1
, m_pool_name
.c_str(), child_name1
.c_str(), false,
11909 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
11910 child_id3
, m_pool_name
.c_str(), child_name3
.c_str(), false);
11912 size_t max_size
= 10;
11913 rbd_linked_image_spec_t children
[max_size
];
11914 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
11915 ASSERT_EQ(3, static_cast<int>(max_size
));
11916 rbd_linked_image_spec_list_cleanup(children
, max_size
);
11918 ASSERT_EQ(0, rbd_close(child1
));
11919 ASSERT_EQ(0, rbd_close(child2
));
11920 ASSERT_EQ(0, rbd_close(child3
));
11921 rados_ioctx_destroy(ioctx2
);
11922 ASSERT_EQ(0, rados_pool_delete(_cluster
, m_pool_name
.c_str()));
11923 _pool_names
.erase(std::remove(_pool_names
.begin(),
11924 _pool_names
.end(), m_pool_name
),
11925 _pool_names
.end());
11926 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
11928 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
11929 ASSERT_EQ(3, static_cast<int>(max_size
));
11930 rbd_linked_image_spec_list_cleanup(children
, max_size
);
11931 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap1"));
11932 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
11933 ASSERT_EQ(2, static_cast<int>(max_size
));
11934 rbd_linked_image_spec_list_cleanup(children
, max_size
);
11936 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
11937 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
11938 ASSERT_EQ(1, static_cast<int>(max_size
));
11939 rbd_linked_image_spec_list_cleanup(children
, max_size
);
11941 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap2"));
11942 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
11943 ASSERT_EQ(0, static_cast<int>(max_size
));
11944 rbd_linked_image_spec_list_cleanup(children
, max_size
);
11945 test_list_children2(parent
, 0);
11946 ASSERT_EQ(0, test_ls_snaps(parent
, 0));
11948 ASSERT_EQ(0, rbd_close(parent
));
11949 rados_ioctx_destroy(ioctx1
);
11952 TEST_F(TestLibRBD
, QuiesceWatch
)
11954 rados_ioctx_t ioctx
;
11955 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
11958 std::string name
= get_temp_image_name();
11959 uint64_t size
= 2 << 20;
11960 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
11962 rbd_image_t image1
, image2
;
11963 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
11964 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
11967 static void quiesce_cb(void *arg
) {
11968 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
11969 watcher
->handle_quiesce();
11971 static void unquiesce_cb(void *arg
) {
11972 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
11973 watcher
->handle_unquiesce();
11976 rbd_image_t
&image
;
11977 uint64_t handle
= 0;
11978 size_t quiesce_count
= 0;
11979 size_t unquiesce_count
= 0;
11981 ceph::mutex lock
= ceph::make_mutex("lock");
11982 ceph::condition_variable cv
;
11984 Watcher(rbd_image_t
&image
) : image(image
) {
11987 void handle_quiesce() {
11988 ASSERT_EQ(quiesce_count
, unquiesce_count
);
11990 rbd_quiesce_complete(image
, handle
, 0);
11992 void handle_unquiesce() {
11993 std::unique_lock
locker(lock
);
11995 ASSERT_EQ(quiesce_count
, unquiesce_count
);
11998 bool wait_for_unquiesce(size_t c
) {
11999 std::unique_lock
locker(lock
);
12000 return cv
.wait_for(locker
, seconds(60),
12001 [this, c
]() { return unquiesce_count
>= c
; });
12003 } watcher1(image1
), watcher2(image2
);
12005 ASSERT_EQ(0, rbd_quiesce_watch(image1
, Watcher::quiesce_cb
,
12006 Watcher::unquiesce_cb
, &watcher1
,
12007 &watcher1
.handle
));
12008 ASSERT_EQ(0, rbd_quiesce_watch(image2
, Watcher::quiesce_cb
,
12009 Watcher::unquiesce_cb
, &watcher2
,
12010 &watcher2
.handle
));
12012 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
12013 ASSERT_EQ(1U, watcher1
.quiesce_count
);
12014 ASSERT_TRUE(watcher1
.wait_for_unquiesce(1U));
12015 ASSERT_EQ(1U, watcher2
.quiesce_count
);
12016 ASSERT_TRUE(watcher2
.wait_for_unquiesce(1U));
12018 ASSERT_EQ(0, rbd_snap_create(image2
, "snap2"));
12019 ASSERT_EQ(2U, watcher1
.quiesce_count
);
12020 ASSERT_TRUE(watcher1
.wait_for_unquiesce(2U));
12021 ASSERT_EQ(2U, watcher2
.quiesce_count
);
12022 ASSERT_TRUE(watcher2
.wait_for_unquiesce(2U));
12024 ASSERT_EQ(0, rbd_quiesce_unwatch(image1
, watcher1
.handle
));
12026 ASSERT_EQ(0, rbd_snap_create(image1
, "snap3"));
12027 ASSERT_EQ(2U, watcher1
.quiesce_count
);
12028 ASSERT_EQ(2U, watcher1
.unquiesce_count
);
12029 ASSERT_EQ(3U, watcher2
.quiesce_count
);
12030 ASSERT_TRUE(watcher2
.wait_for_unquiesce(3U));
12032 ASSERT_EQ(0, rbd_quiesce_unwatch(image2
, watcher2
.handle
));
12034 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap1"));
12035 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap2"));
12036 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap3"));
12037 ASSERT_EQ(0, rbd_close(image1
));
12038 ASSERT_EQ(0, rbd_close(image2
));
12039 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
12040 rados_ioctx_destroy(ioctx
);
12043 TEST_F(TestLibRBD
, QuiesceWatchPP
)
12046 librados::IoCtx ioctx
;
12047 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
12048 std::string name
= get_temp_image_name();
12050 uint64_t size
= 2 << 20;
12051 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
12054 librbd::Image image1
, image2
;
12055 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
12056 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
12058 struct Watcher
: public librbd::QuiesceWatchCtx
{
12059 librbd::Image
&image
;
12060 uint64_t handle
= 0;
12061 size_t quiesce_count
= 0;
12062 size_t unquiesce_count
= 0;
12064 ceph::mutex lock
= ceph::make_mutex("lock");
12065 ceph::condition_variable cv
;
12067 Watcher(librbd::Image
&image
) : image(image
) {
12070 void handle_quiesce() override
{
12071 ASSERT_EQ(quiesce_count
, unquiesce_count
);
12073 image
.quiesce_complete(handle
, 0);
12075 void handle_unquiesce() override
{
12076 std::unique_lock
locker(lock
);
12078 ASSERT_EQ(quiesce_count
, unquiesce_count
);
12081 bool wait_for_unquiesce(size_t c
) {
12082 std::unique_lock
locker(lock
);
12083 return cv
.wait_for(locker
, seconds(60),
12084 [this, c
]() { return unquiesce_count
>= c
; });
12086 } watcher1(image1
), watcher2(image2
);
12088 ASSERT_EQ(0, image1
.quiesce_watch(&watcher1
, &watcher1
.handle
));
12089 ASSERT_EQ(0, image2
.quiesce_watch(&watcher2
, &watcher2
.handle
));
12091 ASSERT_EQ(0, image1
.snap_create("snap1"));
12092 ASSERT_EQ(1U, watcher1
.quiesce_count
);
12093 ASSERT_TRUE(watcher1
.wait_for_unquiesce(1U));
12094 ASSERT_EQ(1U, watcher2
.quiesce_count
);
12095 ASSERT_TRUE(watcher2
.wait_for_unquiesce(1U));
12097 ASSERT_EQ(0, image2
.snap_create("snap2"));
12098 ASSERT_EQ(2U, watcher1
.quiesce_count
);
12099 ASSERT_TRUE(watcher1
.wait_for_unquiesce(2U));
12100 ASSERT_EQ(2U, watcher2
.quiesce_count
);
12101 ASSERT_TRUE(watcher2
.wait_for_unquiesce(2U));
12103 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher1
.handle
));
12105 ASSERT_EQ(0, image1
.snap_create("snap3"));
12106 ASSERT_EQ(2U, watcher1
.quiesce_count
);
12107 ASSERT_EQ(2U, watcher1
.unquiesce_count
);
12108 ASSERT_EQ(3U, watcher2
.quiesce_count
);
12109 ASSERT_TRUE(watcher2
.wait_for_unquiesce(3U));
12111 ASSERT_EQ(0, image2
.quiesce_unwatch(watcher2
.handle
));
12113 ASSERT_EQ(0, image1
.snap_remove("snap1"));
12114 ASSERT_EQ(0, image1
.snap_remove("snap2"));
12115 ASSERT_EQ(0, image1
.snap_remove("snap3"));
12118 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
12122 TEST_F(TestLibRBD
, QuiesceWatchError
)
12126 librados::IoCtx ioctx
;
12127 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
12128 std::string name
= get_temp_image_name();
12130 uint64_t size
= 2 << 20;
12131 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
12134 librbd::Image image1
, image2
;
12135 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
12136 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
12138 struct Watcher
: public librbd::QuiesceWatchCtx
{
12139 librbd::Image
&image
;
12142 size_t quiesce_count
= 0;
12143 size_t unquiesce_count
= 0;
12145 ceph::mutex lock
= ceph::make_mutex("lock");
12146 ceph::condition_variable cv
;
12148 Watcher(librbd::Image
&image
, int r
) : image(image
), r(r
) {
12151 void reset_counters() {
12153 unquiesce_count
= 0;
12156 void handle_quiesce() override
{
12158 image
.quiesce_complete(handle
, r
);
12161 void handle_unquiesce() override
{
12162 std::unique_lock
locker(lock
);
12167 bool wait_for_unquiesce() {
12168 std::unique_lock
locker(lock
);
12169 return cv
.wait_for(locker
, seconds(60),
12171 return quiesce_count
== unquiesce_count
;
12174 } watcher10(image1
, -EINVAL
), watcher11(image1
, 0), watcher20(image2
, 0);
12176 ASSERT_EQ(0, image1
.quiesce_watch(&watcher10
, &watcher10
.handle
));
12177 ASSERT_EQ(0, image1
.quiesce_watch(&watcher11
, &watcher11
.handle
));
12178 ASSERT_EQ(0, image2
.quiesce_watch(&watcher20
, &watcher20
.handle
));
12180 ASSERT_EQ(-EINVAL
, image1
.snap_create("snap1"));
12181 ASSERT_GT(watcher10
.quiesce_count
, 0U);
12182 ASSERT_EQ(watcher10
.unquiesce_count
, 0U);
12183 ASSERT_GT(watcher11
.quiesce_count
, 0U);
12184 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
12185 ASSERT_GT(watcher20
.quiesce_count
, 0U);
12186 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
12188 PrintProgress prog_ctx
;
12189 watcher10
.reset_counters();
12190 watcher11
.reset_counters();
12191 watcher20
.reset_counters();
12192 ASSERT_EQ(0, image2
.snap_create2("snap2",
12193 RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR
,
12195 ASSERT_GT(watcher10
.quiesce_count
, 0U);
12196 ASSERT_EQ(watcher10
.unquiesce_count
, 0U);
12197 ASSERT_GT(watcher11
.quiesce_count
, 0U);
12198 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
12199 ASSERT_GT(watcher20
.quiesce_count
, 0U);
12200 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
12202 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher10
.handle
));
12204 watcher11
.reset_counters();
12205 watcher20
.reset_counters();
12206 ASSERT_EQ(0, image1
.snap_create("snap3"));
12207 ASSERT_GT(watcher11
.quiesce_count
, 0U);
12208 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
12209 ASSERT_GT(watcher20
.quiesce_count
, 0U);
12210 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
12212 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher11
.handle
));
12214 watcher20
.reset_counters();
12215 ASSERT_EQ(0, image2
.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE
,
12217 ASSERT_EQ(watcher20
.quiesce_count
, 0U);
12218 ASSERT_EQ(watcher20
.unquiesce_count
, 0U);
12220 ASSERT_EQ(0, image2
.quiesce_unwatch(watcher20
.handle
));
12222 ASSERT_EQ(0, image1
.snap_remove("snap2"));
12223 ASSERT_EQ(0, image1
.snap_remove("snap3"));
12224 ASSERT_EQ(0, image1
.snap_remove("snap4"));
12227 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
12231 TEST_F(TestLibRBD
, QuiesceWatchTimeout
)
12233 REQUIRE(!is_librados_test_stub(_rados
));
12235 ASSERT_EQ(0, _rados
.conf_set("rbd_quiesce_notification_attempts", "2"));
12238 librados::IoCtx ioctx
;
12239 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
12240 std::string name
= get_temp_image_name();
12242 uint64_t size
= 2 << 20;
12243 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
12246 librbd::Image image
;
12247 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
12249 struct Watcher
: public librbd::QuiesceWatchCtx
{
12250 librbd::Image
&image
;
12252 std::condition_variable m_cond
;
12253 size_t quiesce_count
= 0;
12254 size_t unquiesce_count
= 0;
12256 Watcher(librbd::Image
&image
) : image(image
) {
12259 void handle_quiesce() override
{
12260 std::lock_guard
<std::mutex
> locker(m_lock
);
12262 m_cond
.notify_one();
12265 void handle_unquiesce() override
{
12266 std::lock_guard
<std::mutex
> locker(m_lock
);
12268 m_cond
.notify_one();
12271 void wait_for_quiesce() {
12272 std::unique_lock
<std::mutex
> locker(m_lock
);
12273 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(60),
12275 return quiesce_count
>= 1;
12279 void wait_for_unquiesce() {
12280 std::unique_lock
<std::mutex
> locker(m_lock
);
12281 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(60),
12283 return quiesce_count
== unquiesce_count
;
12285 quiesce_count
= unquiesce_count
= 0;
12290 ASSERT_EQ(0, image
.quiesce_watch(&watcher
, &handle
));
12292 std::cerr
<< "test quiesce is not long enough to time out" << std::endl
;
12294 thread
quiesce1([&image
, &watcher
, handle
]() {
12295 watcher
.wait_for_quiesce();
12297 image
.quiesce_complete(handle
, 0);
12300 ASSERT_EQ(0, image
.snap_create("snap1"));
12302 ASSERT_GE(watcher
.quiesce_count
, 1U);
12303 watcher
.wait_for_unquiesce();
12305 std::cerr
<< "test quiesce is timed out" << std::endl
;
12307 bool timed_out
= false;
12308 thread
quiesce2([&image
, &watcher
, handle
, &timed_out
]() {
12309 watcher
.wait_for_quiesce();
12310 for (int i
= 0; !timed_out
&& i
< 60; i
++) {
12311 std::cerr
<< "waiting for timed out ... " << i
<< std::endl
;
12314 image
.quiesce_complete(handle
, 0);
12317 ASSERT_EQ(-ETIMEDOUT
, image
.snap_create("snap2"));
12320 ASSERT_GE(watcher
.quiesce_count
, 1U);
12321 watcher
.wait_for_unquiesce();
12323 thread
quiesce3([&image
, handle
, &watcher
]() {
12324 watcher
.wait_for_quiesce();
12325 image
.quiesce_complete(handle
, 0);
12328 std::cerr
<< "test retry succeeds" << std::endl
;
12330 ASSERT_EQ(0, image
.snap_create("snap2"));
12332 ASSERT_GE(watcher
.quiesce_count
, 1U);
12333 watcher
.wait_for_unquiesce();
12335 ASSERT_EQ(0, image
.snap_remove("snap1"));
12336 ASSERT_EQ(0, image
.snap_remove("snap2"));
12339 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
12343 TEST_F(TestLibRBD
, WriteZeroes
) {
12345 librados::IoCtx ioctx
;
12346 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
12347 std::string name
= get_temp_image_name();
12349 uint64_t size
= 2 << 20;
12350 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
12352 librbd::Image image
;
12353 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
12355 // 1s from [0, 256) / length 256
12357 memset(data
, 1, sizeof(data
));
12359 bl
.append(data
, 256);
12360 ASSERT_EQ(256, image
.write(0, 256, bl
));
12362 interval_set
<uint64_t> diff
;
12363 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12364 iterate_cb
, (void *)&diff
));
12365 auto expected_diff
= interval_set
<uint64_t>{{{0, 256}}};
12366 ASSERT_EQ(expected_diff
, diff
);
12368 // writes zero passed the current end extents.
12369 // Now 1s from [0, 192) / length 192
12370 ASSERT_EQ(size
- 192,
12371 image
.write_zeroes(192, size
- 192, 0U, 0));
12373 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12374 iterate_cb
, (void *)&diff
));
12375 expected_diff
= interval_set
<uint64_t>{{{0, 192}}};
12376 ASSERT_EQ(expected_diff
, diff
);
12378 // zero an existing extent and truncate some off the end
12379 // Now 1s from [64, 192) / length 192
12380 ASSERT_EQ(64, image
.write_zeroes(0, 64, 0U, 0));
12383 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12384 iterate_cb
, (void *)&diff
));
12385 expected_diff
= interval_set
<uint64_t>{{{0, 192}}};
12386 ASSERT_EQ(expected_diff
, diff
);
12388 bufferlist expected_bl
;
12389 expected_bl
.append_zero(64);
12391 sub_bl
.substr_of(bl
, 0, 128);
12392 expected_bl
.claim_append(sub_bl
);
12393 expected_bl
.append_zero(size
- 192);
12395 bufferlist read_bl
;
12396 EXPECT_EQ(size
, image
.read(0, size
, read_bl
));
12397 EXPECT_EQ(expected_bl
, read_bl
);
12399 ASSERT_EQ(0, image
.close());
12402 TEST_F(TestLibRBD
, WriteZeroesThickProvision
) {
12404 librados::IoCtx ioctx
;
12405 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
12406 std::string name
= get_temp_image_name();
12408 uint64_t size
= 2 << 20;
12409 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
12411 librbd::Image image
;
12412 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
12414 interval_set
<uint64_t> diff
;
12415 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12416 iterate_cb
, (void *)&diff
));
12417 auto expected_diff
= interval_set
<uint64_t>{{}};
12418 ASSERT_EQ(expected_diff
, diff
);
12420 // writes unaligned zeroes as a prepend
12421 ASSERT_EQ(128, image
.write_zeroes(
12422 0, 128, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
12424 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12425 iterate_cb
, (void *)&diff
));
12426 expected_diff
= interval_set
<uint64_t>{{{0, 128}}};
12427 ASSERT_EQ(expected_diff
, diff
);
12429 ASSERT_EQ(512, image
.write_zeroes(
12430 384, 512, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
12432 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12433 iterate_cb
, (void *)&diff
));
12434 expected_diff
= interval_set
<uint64_t>{{{0, 896}}};
12435 ASSERT_EQ(expected_diff
, diff
);
12437 // prepend with write-same
12438 ASSERT_EQ(640, image
.write_zeroes(
12439 896, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
12441 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12442 iterate_cb
, (void *)&diff
));
12443 expected_diff
= interval_set
<uint64_t>{{{0, 1536}}};
12444 ASSERT_EQ(expected_diff
, diff
);
12446 // write-same with append
12447 ASSERT_EQ(640, image
.write_zeroes(
12448 1536, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
12450 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12451 iterate_cb
, (void *)&diff
));
12452 expected_diff
= interval_set
<uint64_t>{{{0, 2176}}};
12453 ASSERT_EQ(expected_diff
, diff
);
12455 // prepend + write-same + append
12456 ASSERT_EQ(768, image
.write_zeroes(
12457 2176, 768, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
12459 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12460 iterate_cb
, (void *)&diff
));
12461 expected_diff
= interval_set
<uint64_t>{{{0, 2944}}};
12464 ASSERT_EQ(1024, image
.write_zeroes(
12465 3072, 1024, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
12467 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
12468 iterate_cb
, (void *)&diff
));
12469 expected_diff
= interval_set
<uint64_t>{{{0, 4096}}};
12471 bufferlist expected_bl
;
12472 expected_bl
.append_zero(size
);
12474 bufferlist read_bl
;
12475 EXPECT_EQ(size
, image
.read(0, size
, read_bl
));
12476 EXPECT_EQ(expected_bl
, read_bl
);
12478 ASSERT_EQ(0, image
.close());
12481 TEST_F(TestLibRBD
, ConcurentOperations
)
12484 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
12487 librados::IoCtx ioctx
;
12488 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
12489 std::string name
= get_temp_image_name();
12491 uint64_t size
= 2 << 20;
12492 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
12494 // Test creating/removing many snapshots simultaneously
12496 std::vector
<librbd::Image
> images(10);
12497 std::vector
<librbd::RBD::AioCompletion
*> comps
;
12499 for (auto &image
: images
) {
12500 auto comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
12501 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, comp
));
12502 comps
.push_back(comp
);
12505 for (auto &comp
: comps
) {
12506 ASSERT_EQ(0, comp
->wait_for_complete());
12507 ASSERT_EQ(1, comp
->is_complete());
12508 ASSERT_EQ(0, comp
->get_return_value());
12513 std::vector
<std::thread
> threads
;
12515 for (auto &image
: images
) {
12516 std::string snap_name
= "snap" + stringify(i
++);
12517 threads
.emplace_back([&image
, snap_name
]() {
12518 int r
= image
.snap_create(snap_name
.c_str());
12519 ceph_assert(r
== 0);
12523 for (auto &t
: threads
) {
12529 for (auto &image
: images
) {
12530 std::string snap_name
= "snap" + stringify(i
++);
12531 threads
.emplace_back([&image
, snap_name
](){
12532 int r
= image
.snap_remove(snap_name
.c_str());
12533 ceph_assert(r
== 0);
12537 for (auto &t
: threads
) {
12542 for (auto &image
: images
) {
12543 auto comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
12544 ASSERT_EQ(0, image
.aio_close(comp
));
12545 comps
.push_back(comp
);
12548 for (auto &comp
: comps
) {
12549 ASSERT_EQ(0, comp
->wait_for_complete());
12550 ASSERT_EQ(1, comp
->is_complete());
12551 ASSERT_EQ(0, comp
->get_return_value());
12558 librbd::Image image1
, image2
, image3
;
12559 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
12560 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
12561 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
12563 ASSERT_EQ(0, image1
.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE
));
12565 struct Watcher
: public librbd::QuiesceWatchCtx
{
12568 ceph::mutex lock
= ceph::make_mutex("lock");
12569 ceph::condition_variable cv
;
12571 void handle_quiesce() override
{
12572 std::unique_lock
locker(lock
);
12577 void handle_unquiesce() override
{
12580 bool wait_for_quiesce(size_t c
) {
12581 std::unique_lock
locker(lock
);
12582 return cv
.wait_for(locker
, seconds(60),
12583 [this, c
]() { return count
>= c
; });
12587 ASSERT_EQ(0, image2
.quiesce_watch(&watcher
, &handle
));
12589 auto close1_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
12591 std::thread
create_snap1([&image1
, close1_comp
]() {
12592 int r
= image1
.snap_create("snap1");
12593 ceph_assert(r
== 0);
12594 r
= image1
.aio_close(close1_comp
);
12595 ceph_assert(r
== 0);
12598 ASSERT_TRUE(watcher
.wait_for_quiesce(1));
12600 std::thread
create_snap2([&image2
]() {
12601 int r
= image2
.snap_create("snap2");
12602 ceph_assert(r
== 0);
12605 std::thread
create_snap3([&image3
]() {
12606 int r
= image3
.snap_create("snap3");
12607 ceph_assert(r
== 0);
12610 image2
.quiesce_complete(handle
, 0);
12611 create_snap1
.join();
12613 ASSERT_TRUE(watcher
.wait_for_quiesce(2));
12614 image2
.quiesce_complete(handle
, 0);
12616 ASSERT_TRUE(watcher
.wait_for_quiesce(3));
12617 image2
.quiesce_complete(handle
, 0);
12619 ASSERT_EQ(0, close1_comp
->wait_for_complete());
12620 ASSERT_EQ(1, close1_comp
->is_complete());
12621 ASSERT_EQ(0, close1_comp
->get_return_value());
12622 close1_comp
->release();
12624 create_snap2
.join();
12625 create_snap3
.join();
12627 ASSERT_EQ(0, image2
.quiesce_unwatch(handle
));
12628 ASSERT_EQ(0, image2
.snap_remove("snap1"));
12629 ASSERT_EQ(0, image2
.snap_remove("snap2"));
12630 ASSERT_EQ(0, image2
.snap_remove("snap3"));
12633 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
12638 // poorman's ceph_assert()
12640 void __ceph_assert_fail(const char *assertion
, const char *file
, int line
,
12641 const char *func
) {
12646 #pragma GCC diagnostic pop
12647 #pragma GCC diagnostic warning "-Wpragmas"