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"
25 #include "gtest/gtest.h"
31 #include <sys/types.h>
37 #include <condition_variable>
46 #include "test/librados/test.h"
47 #include "test/librados/test_cxx.h"
48 #include "test/librbd/test_support.h"
49 #include "common/event_socket.h"
50 #include "include/interval_set.h"
51 #include "include/stringify.h"
53 #include <boost/assign/list_of.hpp>
54 #include <boost/scope_exit.hpp>
57 #include <sys/eventfd.h>
60 #pragma GCC diagnostic ignored "-Wpragmas"
61 #pragma GCC diagnostic push
62 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
66 using std::chrono::seconds
;
68 #define ASSERT_PASSED(x, args...) \
70 bool passed = false; \
72 ASSERT_TRUE(passed); \
75 void register_test_librbd() {
78 static int get_features(bool *old_format
, uint64_t *features
)
80 const char *c
= getenv("RBD_FEATURES");
81 if (c
&& strlen(c
) > 0) {
88 cout
<< "using new format!" << std::endl
;
92 cout
<< "using old format" << std::endl
;
98 static int create_image_full(rados_ioctx_t ioctx
, const char *name
,
99 uint64_t size
, int *order
, int old_format
,
103 // ensure old-format tests actually use the old format
104 int r
= rados_conf_set(rados_ioctx_get_cluster(ioctx
),
105 "rbd_default_format", "1");
109 return rbd_create(ioctx
, name
, size
, order
);
110 } else if ((features
& RBD_FEATURE_STRIPINGV2
) != 0) {
111 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
113 // use a conservative stripe_unit for non default order
114 stripe_unit
= (1ull << (*order
-1));
117 printf("creating image with stripe unit: %" PRIu64
", "
118 "stripe count: %" PRIu64
"\n",
119 stripe_unit
, IMAGE_STRIPE_COUNT
);
120 return rbd_create3(ioctx
, name
, size
, features
, order
,
121 stripe_unit
, IMAGE_STRIPE_COUNT
);
123 return rbd_create2(ioctx
, name
, size
, features
, order
);
127 static int clone_image(rados_ioctx_t p_ioctx
,
128 rbd_image_t p_image
, const char *p_name
,
129 const char *p_snap_name
, rados_ioctx_t c_ioctx
,
130 const char *c_name
, uint64_t features
, int *c_order
)
132 uint64_t stripe_unit
, stripe_count
;
135 r
= rbd_get_stripe_unit(p_image
, &stripe_unit
);
140 r
= rbd_get_stripe_count(p_image
, &stripe_count
);
145 return rbd_clone2(p_ioctx
, p_name
, p_snap_name
, c_ioctx
,
146 c_name
, features
, c_order
, stripe_unit
, stripe_count
);
150 static int create_image(rados_ioctx_t ioctx
, const char *name
,
151 uint64_t size
, int *order
)
156 int r
= get_features(&old_format
, &features
);
159 return create_image_full(ioctx
, name
, size
, order
, old_format
, features
);
162 static int create_image_pp(librbd::RBD
&rbd
,
163 librados::IoCtx
&ioctx
,
165 uint64_t size
, int *order
) {
168 int r
= get_features(&old_format
, &features
);
172 librados::Rados
rados(ioctx
);
173 int r
= rados
.conf_set("rbd_default_format", "1");
177 return rbd
.create(ioctx
, name
, size
, order
);
179 return rbd
.create2(ioctx
, name
, size
, features
, order
);
185 void simple_write_cb(rbd_completion_t cb
, void *arg
)
187 printf("write completion cb called!\n");
190 void simple_read_cb(rbd_completion_t cb
, void *arg
)
192 printf("read completion cb called!\n");
195 void aio_write_test_data_and_poll(rbd_image_t image
, int fd
, const char *test_data
,
196 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
198 rbd_completion_t comp
;
199 uint64_t data
= 0x123;
200 rbd_aio_create_completion((void*)&data
, (rbd_callback_t
) simple_write_cb
, &comp
);
201 printf("created completion\n");
202 printf("started write\n");
204 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
206 rbd_aio_write(image
, off
, len
, test_data
, comp
);
212 ASSERT_EQ(1, poll(&pfd
, 1, -1));
213 ASSERT_TRUE(pfd
.revents
& POLLIN
);
215 rbd_completion_t comps
[1];
216 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
218 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
219 read(fd
, &count
, sizeof(count
)));
220 int r
= rbd_aio_get_return_value(comps
[0]);
221 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
222 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps
[0]) == data
);
223 printf("return value is: %d\n", r
);
225 printf("finished write\n");
226 rbd_aio_release(comps
[0]);
230 void aio_write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
232 rbd_completion_t comp
;
233 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
234 printf("created completion\n");
236 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
238 rbd_aio_write(image
, off
, len
, test_data
, comp
);
239 printf("started write\n");
240 rbd_aio_wait_for_complete(comp
);
241 int r
= rbd_aio_get_return_value(comp
);
242 printf("return value is: %d\n", r
);
244 printf("finished write\n");
245 rbd_aio_release(comp
);
249 void write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
253 written
= rbd_write2(image
, off
, len
, test_data
, iohint
);
255 written
= rbd_write(image
, off
, len
, test_data
);
256 printf("wrote: %d\n", (int) written
);
257 ASSERT_EQ(len
, static_cast<size_t>(written
));
261 void aio_discard_test_data(rbd_image_t image
, uint64_t off
, uint64_t len
, bool *passed
)
263 rbd_completion_t comp
;
264 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
265 rbd_aio_discard(image
, off
, len
, comp
);
266 rbd_aio_wait_for_complete(comp
);
267 int r
= rbd_aio_get_return_value(comp
);
269 printf("aio discard: %d~%d = %d\n", (int)off
, (int)len
, (int)r
);
270 rbd_aio_release(comp
);
274 void discard_test_data(rbd_image_t image
, uint64_t off
, size_t len
, bool *passed
)
277 written
= rbd_discard(image
, off
, len
);
278 printf("discard: %d~%d = %d\n", (int)off
, (int)len
, (int)written
);
279 ASSERT_EQ(len
, static_cast<size_t>(written
));
283 void aio_read_test_data_and_poll(rbd_image_t image
, int fd
, const char *expected
,
284 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
286 rbd_completion_t comp
;
287 char *result
= (char *)malloc(len
+ 1);
289 ASSERT_NE(static_cast<char *>(NULL
), result
);
290 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
291 printf("created completion\n");
292 printf("started read\n");
294 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
296 rbd_aio_read(image
, off
, len
, result
, comp
);
302 ASSERT_EQ(1, poll(&pfd
, 1, -1));
303 ASSERT_TRUE(pfd
.revents
& POLLIN
);
305 rbd_completion_t comps
[1];
306 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
308 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
309 read(fd
, &count
, sizeof(count
)));
311 int r
= rbd_aio_get_return_value(comps
[0]);
312 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
313 printf("return value is: %d\n", r
);
314 ASSERT_EQ(len
, static_cast<size_t>(r
));
315 rbd_aio_release(comps
[0]);
316 if (memcmp(result
, expected
, len
)) {
317 printf("read: %s\nexpected: %s\n", result
, expected
);
318 ASSERT_EQ(0, memcmp(result
, expected
, len
));
324 void aio_read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
326 rbd_completion_t comp
;
327 char *result
= (char *)malloc(len
+ 1);
329 ASSERT_NE(static_cast<char *>(NULL
), result
);
330 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
331 printf("created completion\n");
333 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
335 rbd_aio_read(image
, off
, len
, result
, comp
);
336 printf("started read\n");
337 rbd_aio_wait_for_complete(comp
);
338 int r
= rbd_aio_get_return_value(comp
);
339 printf("return value is: %d\n", r
);
340 ASSERT_EQ(len
, static_cast<size_t>(r
));
341 rbd_aio_release(comp
);
342 if (memcmp(result
, expected
, len
)) {
343 printf("read: %s\nexpected: %s\n", result
, expected
);
344 ASSERT_EQ(0, memcmp(result
, expected
, len
));
350 void read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
353 char *result
= (char *)malloc(len
+ 1);
355 ASSERT_NE(static_cast<char *>(NULL
), result
);
357 read
= rbd_read2(image
, off
, len
, result
, iohint
);
359 read
= rbd_read(image
, off
, len
, result
);
360 printf("read: %d\n", (int) read
);
361 ASSERT_EQ(len
, static_cast<size_t>(read
));
363 if (memcmp(result
, expected
, len
)) {
364 printf("read: %s\nexpected: %s\n", result
, expected
);
365 ASSERT_EQ(0, memcmp(result
, expected
, len
));
371 void aio_writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
372 uint64_t data_len
, uint32_t iohint
, bool *passed
)
374 rbd_completion_t comp
;
375 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
376 printf("created completion\n");
378 r
= rbd_aio_writesame(image
, off
, len
, test_data
, data_len
, comp
, iohint
);
379 printf("started writesame\n");
380 if (len
% data_len
) {
381 ASSERT_EQ(-EINVAL
, r
);
382 printf("expected fail, finished writesame\n");
383 rbd_aio_release(comp
);
388 rbd_aio_wait_for_complete(comp
);
389 r
= rbd_aio_get_return_value(comp
);
390 printf("return value is: %d\n", r
);
392 printf("finished writesame\n");
393 rbd_aio_release(comp
);
396 printf("to verify the data\n");
398 char *result
= (char *)malloc(data_len
+ 1);
399 ASSERT_NE(static_cast<char *>(NULL
), result
);
402 read
= rbd_read(image
, off
, data_len
, result
);
403 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
404 result
[data_len
] = '\0';
405 if (memcmp(result
, test_data
, data_len
)) {
406 printf("read: %d ~ %d\n", (int) off
, (int) read
);
407 printf("read: %s\nexpected: %s\n", result
, test_data
);
408 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
415 printf("verified\n");
420 void writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
421 uint64_t data_len
, uint32_t iohint
, bool *passed
)
424 written
= rbd_writesame(image
, off
, len
, test_data
, data_len
, iohint
);
425 if (len
% data_len
) {
426 ASSERT_EQ(-EINVAL
, written
);
427 printf("expected fail, finished writesame\n");
431 ASSERT_EQ(len
, static_cast<size_t>(written
));
432 printf("wrote: %d\n", (int) written
);
435 printf("to verify the data\n");
437 char *result
= (char *)malloc(data_len
+ 1);
438 ASSERT_NE(static_cast<char *>(NULL
), result
);
441 read
= rbd_read(image
, off
, data_len
, result
);
442 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
443 result
[data_len
] = '\0';
444 if (memcmp(result
, test_data
, data_len
)) {
445 printf("read: %d ~ %d\n", (int) off
, (int) read
);
446 printf("read: %s\nexpected: %s\n", result
, test_data
);
447 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
454 printf("verified\n");
459 void aio_compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
460 const char *test_data
, uint64_t off
,
461 size_t len
, uint32_t iohint
, bool *passed
)
463 rbd_completion_t comp
;
464 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
465 printf("created completion\n");
467 uint64_t mismatch_offset
;
468 rbd_aio_compare_and_write(image
, off
, len
, cmp_data
, test_data
, comp
, &mismatch_offset
, iohint
);
469 printf("started aio compare and write\n");
470 rbd_aio_wait_for_complete(comp
);
471 int r
= rbd_aio_get_return_value(comp
);
472 printf("return value is: %d\n", r
);
474 printf("finished aio compare and write\n");
475 rbd_aio_release(comp
);
479 void compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
480 const char *test_data
, uint64_t off
, size_t len
,
481 uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
483 printf("start compare and write\n");
485 written
= rbd_compare_and_write(image
, off
, len
, cmp_data
, test_data
, mismatch_off
, iohint
);
486 printf("compare and wrote: %d\n", (int) written
);
487 ASSERT_EQ(len
, static_cast<size_t>(written
));
491 class TestLibRBD
: public ::testing::Test
{
494 TestLibRBD() : m_pool_number() {
497 static void SetUpTestCase() {
499 _unique_pool_names
.clear();
501 ASSERT_EQ("", connect_cluster(&_cluster
));
502 ASSERT_EQ("", connect_cluster_pp(_rados
));
504 create_optional_data_pool();
507 static void TearDownTestCase() {
508 rados_shutdown(_cluster
);
509 _rados
.wait_for_latest_osdmap();
510 _pool_names
.insert(_pool_names
.end(), _unique_pool_names
.begin(),
511 _unique_pool_names
.end());
512 for (size_t i
= 1; i
< _pool_names
.size(); ++i
) {
513 ASSERT_EQ(0, _rados
.pool_delete(_pool_names
[i
].c_str()));
515 if (!_pool_names
.empty()) {
516 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names
[0], _rados
));
520 void SetUp() override
{
521 ASSERT_NE("", m_pool_name
= create_pool());
524 bool is_skip_partial_discard_enabled() {
526 EXPECT_EQ(0, _rados
.conf_get("rbd_skip_partial_discard", value
));
527 return value
== "true";
530 bool is_skip_partial_discard_enabled(rbd_image_t image
) {
531 if (is_skip_partial_discard_enabled()) {
534 EXPECT_EQ(0, rbd_get_features(image
, &features
));
535 return !(features
& RBD_FEATURE_DIRTY_CACHE
);
540 bool is_skip_partial_discard_enabled(librbd::Image
& image
) {
541 if (is_skip_partial_discard_enabled()) {
544 EXPECT_EQ(0, image
.features(&features
));
545 return !(features
& RBD_FEATURE_DIRTY_CACHE
);
550 void validate_object_map(rbd_image_t image
, bool *passed
) {
552 ASSERT_EQ(0, rbd_get_flags(image
, &flags
));
553 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
556 void validate_object_map(librbd::Image
&image
, bool *passed
) {
558 ASSERT_EQ(0, image
.get_flags(&flags
));
559 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
562 static std::string
get_temp_image_name() {
564 return "image" + stringify(_image_number
);
567 static void create_optional_data_pool() {
568 bool created
= false;
569 std::string data_pool
;
570 ASSERT_EQ(0, create_image_data_pool(_rados
, data_pool
, &created
));
571 if (!data_pool
.empty()) {
572 printf("using image data pool: %s\n", data_pool
.c_str());
574 _unique_pool_names
.push_back(data_pool
);
579 std::string
create_pool(bool unique
= false) {
580 librados::Rados rados
;
581 std::string pool_name
;
583 pool_name
= get_temp_pool_name("test-librbd-");
584 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
585 _unique_pool_names
.push_back(pool_name
);
586 } else if (m_pool_number
< _pool_names
.size()) {
587 pool_name
= _pool_names
[m_pool_number
];
589 pool_name
= get_temp_pool_name("test-librbd-");
590 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
591 _pool_names
.push_back(pool_name
);
597 void test_io(rbd_image_t image
) {
598 bool skip_discard
= is_skip_partial_discard_enabled(image
);
600 char test_data
[TEST_IO_SIZE
+ 1];
601 char zero_data
[TEST_IO_SIZE
+ 1];
602 char mismatch_data
[TEST_IO_SIZE
+ 1];
604 uint64_t mismatch_offset
;
606 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
607 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
609 test_data
[TEST_IO_SIZE
] = '\0';
610 memset(zero_data
, 0, sizeof(zero_data
));
611 memset(mismatch_data
, 9, sizeof(mismatch_data
));
613 for (i
= 0; i
< 5; ++i
)
614 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
617 for (i
= 5; i
< 10; ++i
)
618 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
621 for (i
= 0; i
< 5; ++i
)
622 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
623 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, 0);
625 for (i
= 5; i
< 10; ++i
)
626 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
627 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
629 for (i
= 0; i
< 5; ++i
)
630 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
633 for (i
= 5; i
< 10; ++i
)
634 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
637 // discard 2nd, 4th sections.
638 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
639 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
641 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
642 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
643 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
644 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2,
646 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
647 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
648 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4,
651 for (i
= 0; i
< 15; ++i
) {
653 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
654 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
655 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
656 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
657 } else if (i
% 3 == 1) {
658 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
659 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
660 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
661 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
663 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
664 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
665 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
666 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
669 for (i
= 0; i
< 15; ++i
) {
671 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
672 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
,
674 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
675 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
,
677 } else if (i
% 3 == 1) {
678 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
679 TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
680 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
681 TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
683 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
684 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
685 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
686 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
690 rbd_image_info_t info
;
691 rbd_completion_t comp
;
692 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
693 // can't read or write starting past end
694 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
695 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
696 // reading through end returns amount up to end
697 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
698 // writing through end returns amount up to end
699 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
701 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
702 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
703 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
704 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
705 rbd_aio_release(comp
);
707 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
708 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
709 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
710 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
711 rbd_aio_release(comp
);
713 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
,
714 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
715 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
,
716 mismatch_data
, mismatch_data
, &mismatch_offset
, 0));
717 ASSERT_EQ(0U, mismatch_offset
);
718 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
719 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
,
720 mismatch_data
, comp
, &mismatch_offset
, 0));
721 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
722 ASSERT_EQ(0U, mismatch_offset
);
723 rbd_aio_release(comp
);
725 ASSERT_PASSED(validate_object_map
, image
);
728 static std::vector
<std::string
> _pool_names
;
729 static std::vector
<std::string
> _unique_pool_names
;
730 static rados_t _cluster
;
731 static librados::Rados _rados
;
732 static uint64_t _image_number
;
734 std::string m_pool_name
;
735 uint32_t m_pool_number
;
739 std::vector
<std::string
> TestLibRBD::_pool_names
;
740 std::vector
<std::string
> TestLibRBD::_unique_pool_names
;
741 rados_t
TestLibRBD::_cluster
;
742 librados::Rados
TestLibRBD::_rados
;
743 uint64_t TestLibRBD::_image_number
= 0;
745 TEST_F(TestLibRBD
, CreateAndStat
)
748 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
750 rbd_image_info_t info
;
753 std::string name
= get_temp_image_name();
754 uint64_t size
= 2 << 20;
756 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
757 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
758 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
759 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
760 ASSERT_EQ(info
.size
, size
);
761 ASSERT_EQ(info
.order
, order
);
762 ASSERT_EQ(0, rbd_close(image
));
764 rados_ioctx_destroy(ioctx
);
767 TEST_F(TestLibRBD
, CreateWithSameDataPool
)
772 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
775 std::string name
= get_temp_image_name();
776 uint64_t size
= 2 << 20;
780 ASSERT_EQ(0, get_features(&old_format
, &features
));
781 ASSERT_FALSE(old_format
);
783 rbd_image_options_t image_options
;
784 rbd_image_options_create(&image_options
);
785 BOOST_SCOPE_EXIT( (&image_options
) ) {
786 rbd_image_options_destroy(image_options
);
787 } BOOST_SCOPE_EXIT_END
;
789 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
790 RBD_IMAGE_OPTION_FEATURES
,
792 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
793 RBD_IMAGE_OPTION_DATA_POOL
,
794 m_pool_name
.c_str()));
796 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
797 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
799 ASSERT_EQ(0, rbd_close(image
));
801 rados_ioctx_destroy(ioctx
);
804 TEST_F(TestLibRBD
, CreateAndStatPP
)
806 librados::IoCtx ioctx
;
807 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
811 librbd::image_info_t info
;
814 std::string name
= get_temp_image_name();
815 uint64_t size
= 2 << 20;
817 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
818 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
819 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
820 ASSERT_EQ(info
.size
, size
);
821 ASSERT_EQ(info
.order
, order
);
827 TEST_F(TestLibRBD
, GetId
)
830 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
834 std::string name
= get_temp_image_name();
836 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
837 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
840 if (!is_feature_enabled(0)) {
842 ASSERT_EQ(-EINVAL
, rbd_get_id(image
, id
, sizeof(id
)));
844 ASSERT_EQ(-ERANGE
, rbd_get_id(image
, id
, 0));
845 ASSERT_EQ(0, rbd_get_id(image
, id
, sizeof(id
)));
846 ASSERT_LT(0U, strlen(id
));
848 ASSERT_EQ(0, rbd_close(image
));
849 ASSERT_EQ(0, rbd_open_by_id(ioctx
, id
, &image
, NULL
));
851 ASSERT_EQ(-ERANGE
, rbd_get_name(image
, NULL
, &name_len
));
852 ASSERT_EQ(name_len
, name
.size() + 1);
853 char image_name
[name_len
];
854 ASSERT_EQ(0, rbd_get_name(image
, image_name
, &name_len
));
855 ASSERT_STREQ(name
.c_str(), image_name
);
858 ASSERT_EQ(0, rbd_close(image
));
859 rados_ioctx_destroy(ioctx
);
862 TEST_F(TestLibRBD
, GetIdPP
)
864 librados::IoCtx ioctx
;
865 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
870 std::string name
= get_temp_image_name();
873 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
874 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
875 if (!is_feature_enabled(0)) {
877 ASSERT_EQ(-EINVAL
, image
.get_id(&id
));
879 ASSERT_EQ(0, image
.get_id(&id
));
880 ASSERT_LT(0U, id
.size());
882 ASSERT_EQ(0, image
.close());
883 ASSERT_EQ(0, rbd
.open_by_id(ioctx
, image
, id
.c_str(), NULL
));
884 std::string image_name
;
885 ASSERT_EQ(0, image
.get_name(&image_name
));
886 ASSERT_EQ(name
, image_name
);
890 TEST_F(TestLibRBD
, GetBlockNamePrefix
)
893 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
897 std::string name
= get_temp_image_name();
899 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
900 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
903 ASSERT_EQ(-ERANGE
, rbd_get_block_name_prefix(image
, prefix
, 0));
904 ASSERT_EQ(0, rbd_get_block_name_prefix(image
, prefix
, sizeof(prefix
)));
905 ASSERT_LT(0U, strlen(prefix
));
907 ASSERT_EQ(0, rbd_close(image
));
908 rados_ioctx_destroy(ioctx
);
911 TEST_F(TestLibRBD
, GetBlockNamePrefixPP
)
913 librados::IoCtx ioctx
;
914 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
919 std::string name
= get_temp_image_name();
921 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
922 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
923 ASSERT_LT(0U, image
.get_block_name_prefix().size());
926 TEST_F(TestLibRBD
, TestGetCreateTimestamp
)
931 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
935 std::string name
= get_temp_image_name();
937 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
938 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
940 struct timespec timestamp
;
941 ASSERT_EQ(0, rbd_get_create_timestamp(image
, ×tamp
));
942 ASSERT_LT(0, timestamp
.tv_sec
);
944 ASSERT_EQ(0, rbd_close(image
));
946 rados_ioctx_destroy(ioctx
);
949 TEST_F(TestLibRBD
, GetCreateTimestampPP
)
953 librados::IoCtx ioctx
;
954 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
959 std::string name
= get_temp_image_name();
961 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
962 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
964 struct timespec timestamp
;
965 ASSERT_EQ(0, image
.get_create_timestamp(×tamp
));
966 ASSERT_LT(0, timestamp
.tv_sec
);
969 TEST_F(TestLibRBD
, OpenAio
)
972 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
974 rbd_image_info_t info
;
977 std::string name
= get_temp_image_name();
978 uint64_t size
= 2 << 20;
980 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
982 rbd_completion_t open_comp
;
983 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
984 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
985 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
986 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
987 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp
));
988 rbd_aio_release(open_comp
);
990 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
991 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
992 ASSERT_EQ(info
.size
, size
);
993 ASSERT_EQ(info
.order
, order
);
995 rbd_completion_t close_comp
;
996 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &close_comp
));
997 ASSERT_EQ(0, rbd_aio_close(image
, close_comp
));
998 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp
));
999 ASSERT_EQ(1, rbd_aio_is_complete(close_comp
));
1000 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp
));
1001 rbd_aio_release(close_comp
);
1003 rados_ioctx_destroy(ioctx
);
1006 TEST_F(TestLibRBD
, OpenAioFail
)
1008 rados_ioctx_t ioctx
;
1009 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
1011 std::string name
= get_temp_image_name();
1013 rbd_completion_t open_comp
;
1014 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
1015 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
1016 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
1017 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
1018 ASSERT_EQ(-ENOENT
, rbd_aio_get_return_value(open_comp
));
1019 rbd_aio_release(open_comp
);
1021 rados_ioctx_destroy(ioctx
);
1024 TEST_F(TestLibRBD
, OpenAioPP
)
1026 librados::IoCtx ioctx
;
1027 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1030 librbd::image_info_t info
;
1031 librbd::Image image
;
1033 std::string name
= get_temp_image_name();
1034 uint64_t size
= 2 << 20;
1036 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1038 librbd::RBD::AioCompletion
*open_comp
=
1039 new librbd::RBD::AioCompletion(NULL
, NULL
);
1040 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1041 ASSERT_EQ(0, open_comp
->wait_for_complete());
1042 ASSERT_EQ(1, open_comp
->is_complete());
1043 ASSERT_EQ(0, open_comp
->get_return_value());
1044 open_comp
->release();
1046 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1047 ASSERT_EQ(info
.size
, size
);
1048 ASSERT_EQ(info
.order
, order
);
1051 open_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
1052 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1053 ASSERT_EQ(0, open_comp
->wait_for_complete());
1054 ASSERT_EQ(1, open_comp
->is_complete());
1055 ASSERT_EQ(0, open_comp
->get_return_value());
1056 open_comp
->release();
1059 librbd::RBD::AioCompletion
*close_comp
=
1060 new librbd::RBD::AioCompletion(NULL
, NULL
);
1061 ASSERT_EQ(0, image
.aio_close(close_comp
));
1062 ASSERT_EQ(0, close_comp
->wait_for_complete());
1063 ASSERT_EQ(1, close_comp
->is_complete());
1064 ASSERT_EQ(0, close_comp
->get_return_value());
1065 close_comp
->release();
1067 // close closed image
1068 close_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
1069 ASSERT_EQ(-EINVAL
, image
.aio_close(close_comp
));
1070 close_comp
->release();
1075 TEST_F(TestLibRBD
, OpenAioFailPP
)
1077 librados::IoCtx ioctx
;
1078 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1082 librbd::Image image
;
1083 std::string name
= get_temp_image_name();
1085 librbd::RBD::AioCompletion
*open_comp
=
1086 new librbd::RBD::AioCompletion(NULL
, NULL
);
1087 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1088 ASSERT_EQ(0, open_comp
->wait_for_complete());
1089 ASSERT_EQ(1, open_comp
->is_complete());
1090 ASSERT_EQ(-ENOENT
, open_comp
->get_return_value());
1091 open_comp
->release();
1097 TEST_F(TestLibRBD
, ResizeAndStat
)
1099 rados_ioctx_t ioctx
;
1100 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1102 rbd_image_info_t info
;
1105 std::string name
= get_temp_image_name();
1106 uint64_t size
= 2 << 20;
1108 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1109 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1111 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
1112 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1113 ASSERT_EQ(info
.size
, size
* 4);
1115 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
1116 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1117 ASSERT_EQ(info
.size
, size
/ 2);
1119 // downsizing without allowing shrink should fail
1120 // and image size should not change
1121 ASSERT_EQ(-EINVAL
, rbd_resize2(image
, size
/ 4, false, NULL
, NULL
));
1122 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1123 ASSERT_EQ(info
.size
, size
/ 2);
1125 ASSERT_EQ(0, rbd_resize2(image
, size
/ 4, true, NULL
, NULL
));
1126 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1127 ASSERT_EQ(info
.size
, size
/ 4);
1129 ASSERT_PASSED(validate_object_map
, image
);
1130 ASSERT_EQ(0, rbd_close(image
));
1132 rados_ioctx_destroy(ioctx
);
1135 TEST_F(TestLibRBD
, ResizeAndStatPP
)
1137 librados::IoCtx ioctx
;
1138 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1142 librbd::image_info_t info
;
1143 librbd::Image image
;
1145 std::string name
= get_temp_image_name();
1146 uint64_t size
= 2 << 20;
1148 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1149 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1151 ASSERT_EQ(0, image
.resize(size
* 4));
1152 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1153 ASSERT_EQ(info
.size
, size
* 4);
1155 ASSERT_EQ(0, image
.resize(size
/ 2));
1156 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1157 ASSERT_EQ(info
.size
, size
/ 2);
1158 ASSERT_PASSED(validate_object_map
, image
);
1164 TEST_F(TestLibRBD
, UpdateWatchAndResize
)
1166 rados_ioctx_t ioctx
;
1167 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1171 std::string name
= get_temp_image_name();
1172 uint64_t size
= 2 << 20;
1174 rbd_image_t
&m_image
;
1176 std::condition_variable m_cond
;
1178 static void cb(void *arg
) {
1179 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
1180 watcher
->handle_notify();
1182 explicit Watcher(rbd_image_t
&image
) : m_image(image
) {}
1183 void handle_notify() {
1184 rbd_image_info_t info
;
1185 ASSERT_EQ(0, rbd_stat(m_image
, &info
, sizeof(info
)));
1186 std::lock_guard
<std::mutex
> locker(m_lock
);
1188 m_cond
.notify_one();
1190 void wait_for_size(size_t size
) {
1191 std::unique_lock
<std::mutex
> locker(m_lock
);
1192 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
1194 return this->m_size
== size
;}));
1199 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1200 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1202 ASSERT_EQ(0, rbd_update_watch(image
, &handle
, Watcher::cb
, &watcher
));
1204 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
1205 watcher
.wait_for_size(size
* 4);
1207 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
1208 watcher
.wait_for_size(size
/ 2);
1210 ASSERT_EQ(0, rbd_update_unwatch(image
, handle
));
1212 ASSERT_EQ(0, rbd_close(image
));
1213 rados_ioctx_destroy(ioctx
);
1216 TEST_F(TestLibRBD
, UpdateWatchAndResizePP
)
1218 librados::IoCtx ioctx
;
1219 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1223 librbd::Image image
;
1225 std::string name
= get_temp_image_name();
1226 uint64_t size
= 2 << 20;
1227 struct Watcher
: public librbd::UpdateWatchCtx
{
1228 explicit Watcher(librbd::Image
&image
) : m_image(image
) {
1230 void handle_notify() override
{
1231 librbd::image_info_t info
;
1232 ASSERT_EQ(0, m_image
.stat(info
, sizeof(info
)));
1233 std::lock_guard
<std::mutex
> locker(m_lock
);
1235 m_cond
.notify_one();
1237 void wait_for_size(size_t size
) {
1238 std::unique_lock
<std::mutex
> locker(m_lock
);
1239 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
1241 return this->m_size
== size
;}));
1243 librbd::Image
&m_image
;
1245 std::condition_variable m_cond
;
1250 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1251 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1253 ASSERT_EQ(0, image
.update_watch(&watcher
, &handle
));
1255 ASSERT_EQ(0, image
.resize(size
* 4));
1256 watcher
.wait_for_size(size
* 4);
1258 ASSERT_EQ(0, image
.resize(size
/ 2));
1259 watcher
.wait_for_size(size
/ 2);
1261 ASSERT_EQ(0, image
.update_unwatch(handle
));
1267 int test_ls(rados_ioctx_t io_ctx
, size_t num_expected
, ...)
1270 char *names
, *cur_name
;
1272 size_t max_size
= 1024;
1274 names
= (char *) malloc(sizeof(char) * 1024);
1275 int len
= rbd_list(io_ctx
, names
, &max_size
);
1277 std::set
<std::string
> image_names
;
1278 for (i
= 0, num_images
= 0, cur_name
= names
; cur_name
< names
+ len
; i
++) {
1279 printf("image: %s\n", cur_name
);
1280 image_names
.insert(cur_name
);
1281 cur_name
+= strlen(cur_name
) + 1;
1286 va_start(ap
, num_expected
);
1287 for (i
= num_expected
; i
> 0; i
--) {
1288 char *expected
= va_arg(ap
, char *);
1289 printf("expected = %s\n", expected
);
1290 std::set
<std::string
>::iterator it
= image_names
.find(expected
);
1291 if (it
!= image_names
.end()) {
1292 printf("found %s\n", expected
);
1293 image_names
.erase(it
);
1294 printf("erased %s\n", expected
);
1296 ADD_FAILURE() << "Unable to find image " << expected
;
1303 if (!image_names
.empty()) {
1304 ADD_FAILURE() << "Unexpected images discovered";
1310 TEST_F(TestLibRBD
, TestCreateLsDelete
)
1312 rados_ioctx_t ioctx
;
1313 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1316 std::string name
= get_temp_image_name();
1317 std::string name2
= get_temp_image_name();
1318 uint64_t size
= 2 << 20;
1320 ASSERT_EQ(0, test_ls(ioctx
, 0));
1321 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1322 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1323 ASSERT_EQ(0, create_image(ioctx
, name2
.c_str(), size
, &order
));
1324 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1325 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
1326 ASSERT_EQ(1, test_ls(ioctx
, 1, name2
.c_str()));
1328 ASSERT_EQ(-ENOENT
, rbd_remove(ioctx
, name
.c_str()));
1330 rados_ioctx_destroy(ioctx
);
1333 int test_ls_pp(librbd::RBD
& rbd
, librados::IoCtx
& io_ctx
, size_t num_expected
, ...)
1338 vector
<string
> names
;
1339 r
= rbd
.list(io_ctx
, names
);
1342 EXPECT_TRUE(r
>= 0);
1343 cout
<< "num images is: " << names
.size() << std::endl
1344 << "expected: " << num_expected
<< std::endl
;
1345 int num
= names
.size();
1347 for (i
= 0; i
< names
.size(); i
++) {
1348 cout
<< "image: " << names
[i
] << std::endl
;
1351 va_start(ap
, num_expected
);
1352 for (i
= num_expected
; i
> 0; i
--) {
1353 char *expected
= va_arg(ap
, char *);
1354 cout
<< "expected = " << expected
<< std::endl
;
1355 vector
<string
>::iterator listed_name
= find(names
.begin(), names
.end(), string(expected
));
1356 if (listed_name
== names
.end()) {
1357 ADD_FAILURE() << "Unable to find image " << expected
;
1361 names
.erase(listed_name
);
1365 if (!names
.empty()) {
1366 ADD_FAILURE() << "Unexpected images discovered";
1372 TEST_F(TestLibRBD
, TestCreateLsDeletePP
)
1374 librados::IoCtx ioctx
;
1375 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1379 librbd::Image image
;
1381 std::string name
= get_temp_image_name();
1382 std::string name2
= get_temp_image_name();
1383 uint64_t size
= 2 << 20;
1385 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1386 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1387 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
1388 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1389 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
1390 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name2
.c_str()));
1397 static int print_progress_percent(uint64_t offset
, uint64_t src_size
,
1400 float percent
= ((float)offset
* 100) / src_size
;
1401 printf("%3.2f%% done\n", percent
);
1405 TEST_F(TestLibRBD
, TestCopy
)
1407 rados_ioctx_t ioctx
;
1408 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1414 std::string name
= get_temp_image_name();
1415 std::string name2
= get_temp_image_name();
1416 std::string name3
= get_temp_image_name();
1418 uint64_t size
= 2 << 20;
1420 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1421 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1422 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1424 size_t sum_key_len
= 0;
1425 size_t sum_value_len
= 0;
1428 for (int i
= 1; i
<= 70; i
++) {
1429 key
= "key" + stringify(i
);
1430 val
= "value" + stringify(i
);
1431 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
1433 sum_key_len
+= (key
.size() + 1);
1434 sum_value_len
+= (val
.size() + 1);
1439 size_t keys_len
= sizeof(keys
);
1440 size_t vals_len
= sizeof(vals
);
1443 size_t value_len
= sizeof(value
);
1445 ASSERT_EQ(0, rbd_copy(image
, ioctx
, name2
.c_str()));
1446 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1447 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
1448 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 70, keys
, &keys_len
, vals
,
1450 ASSERT_EQ(keys_len
, sum_key_len
);
1451 ASSERT_EQ(vals_len
, sum_value_len
);
1453 for (int i
= 1; i
<= 70; i
++) {
1454 key
= "key" + stringify(i
);
1455 val
= "value" + stringify(i
);
1456 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
1457 ASSERT_STREQ(val
.c_str(), value
);
1459 value_len
= sizeof(value
);
1462 ASSERT_EQ(0, rbd_copy_with_progress(image
, ioctx
, name3
.c_str(),
1463 print_progress_percent
, NULL
));
1464 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1466 keys_len
= sizeof(keys
);
1467 vals_len
= sizeof(vals
);
1468 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1469 ASSERT_EQ(0, rbd_metadata_list(image3
, "key", 70, keys
, &keys_len
, vals
,
1471 ASSERT_EQ(keys_len
, sum_key_len
);
1472 ASSERT_EQ(vals_len
, sum_value_len
);
1474 for (int i
= 1; i
<= 70; i
++) {
1475 key
= "key" + stringify(i
);
1476 val
= "value" + stringify(i
);
1477 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1478 ASSERT_STREQ(val
.c_str(), value
);
1480 value_len
= sizeof(value
);
1483 ASSERT_EQ(0, rbd_close(image
));
1484 ASSERT_EQ(0, rbd_close(image2
));
1485 ASSERT_EQ(0, rbd_close(image3
));
1486 rados_ioctx_destroy(ioctx
);
1489 class PrintProgress
: public librbd::ProgressContext
1492 int update_progress(uint64_t offset
, uint64_t src_size
) override
1494 float percent
= ((float)offset
* 100) / src_size
;
1495 printf("%3.2f%% done\n", percent
);
1500 TEST_F(TestLibRBD
, TestCopyPP
)
1502 librados::IoCtx ioctx
;
1503 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1507 librbd::Image image
;
1508 librbd::Image image2
;
1509 librbd::Image image3
;
1511 std::string name
= get_temp_image_name();
1512 std::string name2
= get_temp_image_name();
1513 std::string name3
= get_temp_image_name();
1514 uint64_t size
= 2 << 20;
1517 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1518 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1522 for (int i
= 1; i
<= 70; i
++) {
1523 key
= "key" + stringify(i
);
1524 val
= "value" + stringify(i
);
1525 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1528 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1529 ASSERT_EQ(0, image
.copy(ioctx
, name2
.c_str()));
1530 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1531 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1533 map
<string
, bufferlist
> pairs
;
1535 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1536 ASSERT_EQ(70U, pairs
.size());
1538 for (int i
= 1; i
<= 70; i
++) {
1539 key
= "key" + stringify(i
);
1540 val
= "value" + stringify(i
);
1541 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1542 ASSERT_STREQ(val
.c_str(), value
.c_str());
1545 ASSERT_EQ(0, image
.copy_with_progress(ioctx
, name3
.c_str(), pp
));
1546 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1548 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1551 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1552 ASSERT_EQ(70U, pairs
.size());
1554 for (int i
= 1; i
<= 70; i
++) {
1555 key
= "key" + stringify(i
);
1556 val
= "value" + stringify(i
);
1557 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1558 ASSERT_STREQ(val
.c_str(), value
.c_str());
1565 TEST_F(TestLibRBD
, TestDeepCopy
)
1567 REQUIRE_FORMAT_V2();
1568 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1570 rados_ioctx_t ioctx
;
1571 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1572 BOOST_SCOPE_EXIT_ALL( (&ioctx
) ) {
1573 rados_ioctx_destroy(ioctx
);
1583 std::string name
= get_temp_image_name();
1584 std::string name2
= get_temp_image_name();
1585 std::string name3
= get_temp_image_name();
1586 std::string name4
= get_temp_image_name();
1587 std::string name5
= get_temp_image_name();
1588 std::string name6
= get_temp_image_name();
1590 uint64_t size
= 2 << 20;
1592 rbd_image_options_t opts
;
1593 rbd_image_options_create(&opts
);
1594 BOOST_SCOPE_EXIT_ALL( (&opts
) ) {
1595 rbd_image_options_destroy(opts
);
1598 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1599 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1600 BOOST_SCOPE_EXIT_ALL( (&image
) ) {
1601 ASSERT_EQ(0, rbd_close(image
));
1603 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1605 size_t sum_key_len
= 0;
1606 size_t sum_value_len
= 0;
1609 for (int i
= 1; i
<= 70; i
++) {
1610 key
= "key" + stringify(i
);
1611 val
= "value" + stringify(i
);
1612 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
1614 sum_key_len
+= (key
.size() + 1);
1615 sum_value_len
+= (val
.size() + 1);
1620 size_t keys_len
= sizeof(keys
);
1621 size_t vals_len
= sizeof(vals
);
1624 size_t value_len
= sizeof(value
);
1626 ASSERT_EQ(0, rbd_deep_copy(image
, ioctx
, name2
.c_str(), opts
));
1627 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1628 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
1629 BOOST_SCOPE_EXIT_ALL( (&image2
) ) {
1630 ASSERT_EQ(0, rbd_close(image2
));
1632 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 70, keys
, &keys_len
, vals
,
1634 ASSERT_EQ(keys_len
, sum_key_len
);
1635 ASSERT_EQ(vals_len
, sum_value_len
);
1637 for (int i
= 1; i
<= 70; i
++) {
1638 key
= "key" + stringify(i
);
1639 val
= "value" + stringify(i
);
1640 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
1641 ASSERT_STREQ(val
.c_str(), value
);
1643 value_len
= sizeof(value
);
1646 ASSERT_EQ(0, rbd_deep_copy_with_progress(image
, ioctx
, name3
.c_str(), opts
,
1647 print_progress_percent
, NULL
));
1648 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1650 keys_len
= sizeof(keys
);
1651 vals_len
= sizeof(vals
);
1652 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1653 BOOST_SCOPE_EXIT_ALL( (&image3
) ) {
1654 ASSERT_EQ(0, rbd_close(image3
));
1656 ASSERT_EQ(0, rbd_metadata_list(image3
, "key", 70, keys
, &keys_len
, vals
,
1658 ASSERT_EQ(keys_len
, sum_key_len
);
1659 ASSERT_EQ(vals_len
, sum_value_len
);
1661 for (int i
= 1; i
<= 70; i
++) {
1662 key
= "key" + stringify(i
);
1663 val
= "value" + stringify(i
);
1664 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1665 ASSERT_STREQ(val
.c_str(), value
);
1667 value_len
= sizeof(value
);
1670 ASSERT_EQ(0, rbd_snap_create(image
, "deep_snap"));
1671 ASSERT_EQ(0, rbd_close(image
));
1672 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, "deep_snap"));
1673 ASSERT_EQ(0, rbd_snap_protect(image
, "deep_snap"));
1674 ASSERT_EQ(0, rbd_clone3(ioctx
, name
.c_str(), "deep_snap", ioctx
,
1675 name4
.c_str(), opts
));
1677 ASSERT_EQ(4, test_ls(ioctx
, 4, name
.c_str(), name2
.c_str(), name3
.c_str(),
1679 ASSERT_EQ(0, rbd_open(ioctx
, name4
.c_str(), &image4
, NULL
));
1680 BOOST_SCOPE_EXIT_ALL( (&image4
) ) {
1681 ASSERT_EQ(0, rbd_close(image4
));
1683 ASSERT_EQ(0, rbd_snap_create(image4
, "deep_snap"));
1685 ASSERT_EQ(0, rbd_deep_copy(image4
, ioctx
, name5
.c_str(), opts
));
1686 ASSERT_EQ(5, test_ls(ioctx
, 5, name
.c_str(), name2
.c_str(), name3
.c_str(),
1687 name4
.c_str(), name5
.c_str()));
1688 ASSERT_EQ(0, rbd_open(ioctx
, name5
.c_str(), &image5
, NULL
));
1689 BOOST_SCOPE_EXIT_ALL( (&image5
) ) {
1690 ASSERT_EQ(0, rbd_close(image5
));
1692 ASSERT_EQ(0, rbd_metadata_list(image5
, "key", 70, keys
, &keys_len
, vals
,
1694 ASSERT_EQ(keys_len
, sum_key_len
);
1695 ASSERT_EQ(vals_len
, sum_value_len
);
1697 for (int i
= 1; i
<= 70; i
++) {
1698 key
= "key" + stringify(i
);
1699 val
= "value" + stringify(i
);
1700 ASSERT_EQ(0, rbd_metadata_get(image5
, key
.c_str(), value
, &value_len
));
1701 ASSERT_STREQ(val
.c_str(), value
);
1703 value_len
= sizeof(value
);
1706 ASSERT_EQ(0, rbd_deep_copy_with_progress(image4
, ioctx
, name6
.c_str(), opts
,
1707 print_progress_percent
, NULL
));
1708 ASSERT_EQ(6, test_ls(ioctx
, 6, name
.c_str(), name2
.c_str(), name3
.c_str(),
1709 name4
.c_str(), name5
.c_str(), name6
.c_str()));
1711 keys_len
= sizeof(keys
);
1712 vals_len
= sizeof(vals
);
1713 ASSERT_EQ(0, rbd_open(ioctx
, name6
.c_str(), &image6
, NULL
));
1714 BOOST_SCOPE_EXIT_ALL( (&image6
) ) {
1715 ASSERT_EQ(0, rbd_close(image6
));
1717 ASSERT_EQ(0, rbd_metadata_list(image6
, "key", 70, keys
, &keys_len
, vals
,
1719 ASSERT_EQ(keys_len
, sum_key_len
);
1720 ASSERT_EQ(vals_len
, sum_value_len
);
1722 for (int i
= 1; i
<= 70; i
++) {
1723 key
= "key" + stringify(i
);
1724 val
= "value" + stringify(i
);
1725 ASSERT_EQ(0, rbd_metadata_get(image6
, key
.c_str(), value
, &value_len
));
1726 ASSERT_STREQ(val
.c_str(), value
);
1728 value_len
= sizeof(value
);
1732 TEST_F(TestLibRBD
, TestDeepCopyPP
)
1734 REQUIRE_FORMAT_V2();
1736 librados::IoCtx ioctx
;
1737 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1741 librbd::Image image
;
1742 librbd::Image image2
;
1743 librbd::Image image3
;
1745 std::string name
= get_temp_image_name();
1746 std::string name2
= get_temp_image_name();
1747 std::string name3
= get_temp_image_name();
1748 uint64_t size
= 2 << 20;
1749 librbd::ImageOptions opts
;
1752 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1753 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1757 for (int i
= 1; i
<= 70; i
++) {
1758 key
= "key" + stringify(i
);
1759 val
= "value" + stringify(i
);
1760 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1763 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1764 ASSERT_EQ(0, image
.deep_copy(ioctx
, name2
.c_str(), opts
));
1765 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1766 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1768 map
<string
, bufferlist
> pairs
;
1770 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1771 ASSERT_EQ(70U, pairs
.size());
1773 for (int i
= 1; i
<= 70; i
++) {
1774 key
= "key" + stringify(i
);
1775 val
= "value" + stringify(i
);
1776 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1777 ASSERT_STREQ(val
.c_str(), value
.c_str());
1780 ASSERT_EQ(0, image
.deep_copy_with_progress(ioctx
, name3
.c_str(), opts
, pp
));
1781 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1783 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1786 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1787 ASSERT_EQ(70U, pairs
.size());
1789 for (int i
= 1; i
<= 70; i
++) {
1790 key
= "key" + stringify(i
);
1791 val
= "value" + stringify(i
);
1792 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1793 ASSERT_STREQ(val
.c_str(), value
.c_str());
1800 int test_ls_snaps(rbd_image_t image
, int num_expected
, ...)
1802 int num_snaps
, i
, j
, max_size
= 10;
1804 rbd_snap_info_t snaps
[max_size
];
1805 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1806 printf("num snaps is: %d\nexpected: %d\n", num_snaps
, num_expected
);
1808 for (i
= 0; i
< num_snaps
; i
++) {
1809 printf("snap: %s\n", snaps
[i
].name
);
1812 va_start(ap
, num_expected
);
1813 for (i
= num_expected
; i
> 0; i
--) {
1814 char *expected
= va_arg(ap
, char *);
1815 uint64_t expected_size
= va_arg(ap
, uint64_t);
1817 for (j
= 0; j
< num_snaps
; j
++) {
1818 if (snaps
[j
].name
== NULL
)
1820 if (strcmp(snaps
[j
].name
, expected
) == 0) {
1821 printf("found %s with size %llu\n", snaps
[j
].name
, (unsigned long long) snaps
[j
].size
);
1822 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1823 free((void *) snaps
[j
].name
);
1824 snaps
[j
].name
= NULL
;
1833 for (i
= 0; i
< num_snaps
; i
++) {
1834 EXPECT_EQ((const char *)0, snaps
[i
].name
);
1840 TEST_F(TestLibRBD
, TestCreateLsDeleteSnap
)
1842 rados_ioctx_t ioctx
;
1843 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1847 std::string name
= get_temp_image_name();
1848 uint64_t size
= 2 << 20;
1849 uint64_t size2
= 4 << 20;
1851 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1852 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1854 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1855 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1856 ASSERT_EQ(0, rbd_resize(image
, size2
));
1857 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1858 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1859 ASSERT_EQ(0, rbd_snap_remove(image
, "snap1"));
1860 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1861 ASSERT_EQ(0, rbd_snap_remove(image
, "snap2"));
1862 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1864 ASSERT_EQ(0, rbd_close(image
));
1866 rados_ioctx_destroy(ioctx
);
1869 int test_get_snapshot_timestamp(rbd_image_t image
, uint64_t snap_id
)
1871 struct timespec timestamp
;
1872 EXPECT_EQ(0, rbd_snap_get_timestamp(image
, snap_id
, ×tamp
));
1873 EXPECT_LT(0, timestamp
.tv_sec
);
1877 TEST_F(TestLibRBD
, TestGetSnapShotTimeStamp
)
1879 REQUIRE_FORMAT_V2();
1881 rados_ioctx_t ioctx
;
1882 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1886 std::string name
= get_temp_image_name();
1887 uint64_t size
= 2 << 20;
1888 int num_snaps
, max_size
= 10;
1889 rbd_snap_info_t snaps
[max_size
];
1891 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1892 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1894 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1895 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1896 ASSERT_EQ(1, num_snaps
);
1897 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1898 free((void *)snaps
[0].name
);
1900 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1901 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1902 ASSERT_EQ(2, num_snaps
);
1903 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1904 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[1].id
));
1905 free((void *)snaps
[0].name
);
1906 free((void *)snaps
[1].name
);
1908 ASSERT_EQ(0, rbd_close(image
));
1910 rados_ioctx_destroy(ioctx
);
1914 int test_ls_snaps(librbd::Image
& image
, size_t num_expected
, ...)
1919 vector
<librbd::snap_info_t
> snaps
;
1920 r
= image
.snap_list(snaps
);
1921 EXPECT_TRUE(r
>= 0);
1922 cout
<< "num snaps is: " << snaps
.size() << std::endl
1923 << "expected: " << num_expected
<< std::endl
;
1925 for (i
= 0; i
< snaps
.size(); i
++) {
1926 cout
<< "snap: " << snaps
[i
].name
<< std::endl
;
1929 va_start(ap
, num_expected
);
1930 for (i
= num_expected
; i
> 0; i
--) {
1931 char *expected
= va_arg(ap
, char *);
1932 uint64_t expected_size
= va_arg(ap
, uint64_t);
1934 for (j
= 0; j
< snaps
.size(); j
++) {
1935 if (snaps
[j
].name
== "")
1937 if (strcmp(snaps
[j
].name
.c_str(), expected
) == 0) {
1938 cout
<< "found " << snaps
[j
].name
<< " with size " << snaps
[j
].size
1940 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1950 for (i
= 0; i
< snaps
.size(); i
++) {
1951 EXPECT_EQ("", snaps
[i
].name
);
1954 return snaps
.size();
1957 TEST_F(TestLibRBD
, TestCreateLsDeleteSnapPP
)
1959 librados::IoCtx ioctx
;
1960 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1964 librbd::Image image
;
1966 std::string name
= get_temp_image_name();
1967 uint64_t size
= 2 << 20;
1968 uint64_t size2
= 4 << 20;
1970 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1971 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1974 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1975 ASSERT_FALSE(exists
);
1976 ASSERT_EQ(0, image
.snap_create("snap1"));
1977 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1978 ASSERT_TRUE(exists
);
1979 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1980 ASSERT_EQ(0, image
.resize(size2
));
1981 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1982 ASSERT_FALSE(exists
);
1983 ASSERT_EQ(0, image
.snap_create("snap2"));
1984 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1985 ASSERT_TRUE(exists
);
1986 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1987 ASSERT_EQ(0, image
.snap_remove("snap1"));
1988 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1989 ASSERT_FALSE(exists
);
1990 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1991 ASSERT_EQ(0, image
.snap_remove("snap2"));
1992 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1993 ASSERT_FALSE(exists
);
1994 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2000 TEST_F(TestLibRBD
, TestGetNameIdSnapPP
)
2002 librados::IoCtx ioctx
;
2003 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2007 librbd::Image image
;
2009 std::string name
= get_temp_image_name();
2010 uint64_t size
= 2 << 20;
2012 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2013 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2015 ASSERT_EQ(0, image
.snap_create("snap1"));
2016 ASSERT_EQ(0, image
.snap_create("snap2"));
2017 ASSERT_EQ(0, image
.snap_create("snap3"));
2018 vector
<librbd::snap_info_t
> snaps
;
2019 int r
= image
.snap_list(snaps
);
2020 EXPECT_TRUE(r
>= 0);
2022 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
2023 std::string expected_snap_name
;
2024 image
.snap_get_name(snaps
[i
].id
, &expected_snap_name
);
2025 ASSERT_EQ(expected_snap_name
, snaps
[i
].name
);
2028 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
2029 uint64_t expected_snap_id
;
2030 image
.snap_get_id(snaps
[i
].name
, &expected_snap_id
);
2031 ASSERT_EQ(expected_snap_id
, snaps
[i
].id
);
2034 ASSERT_EQ(0, image
.snap_remove("snap1"));
2035 ASSERT_EQ(0, image
.snap_remove("snap2"));
2036 ASSERT_EQ(0, image
.snap_remove("snap3"));
2037 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2043 TEST_F(TestLibRBD
, TestCreateLsRenameSnapPP
)
2045 librados::IoCtx ioctx
;
2046 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2050 librbd::Image image
;
2052 std::string name
= get_temp_image_name();
2053 uint64_t size
= 2 << 20;
2054 uint64_t size2
= 4 << 20;
2056 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2057 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2060 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2061 ASSERT_FALSE(exists
);
2062 ASSERT_EQ(0, image
.snap_create("snap1"));
2063 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2064 ASSERT_TRUE(exists
);
2065 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
2066 ASSERT_EQ(0, image
.resize(size2
));
2067 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2068 ASSERT_FALSE(exists
);
2069 ASSERT_EQ(0, image
.snap_create("snap2"));
2070 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2071 ASSERT_TRUE(exists
);
2072 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
2073 ASSERT_EQ(0, image
.snap_rename("snap1","snap1-rename"));
2074 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1-rename", size
, "snap2", size2
));
2075 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2076 ASSERT_FALSE(exists
);
2077 ASSERT_EQ(0, image
.snap_exists2("snap1-rename", &exists
));
2078 ASSERT_TRUE(exists
);
2079 ASSERT_EQ(0, image
.snap_remove("snap1-rename"));
2080 ASSERT_EQ(0, image
.snap_rename("snap2","snap2-rename"));
2081 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2-rename", size2
));
2082 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2083 ASSERT_FALSE(exists
);
2084 ASSERT_EQ(0, image
.snap_exists2("snap2-rename", &exists
));
2085 ASSERT_TRUE(exists
);
2086 ASSERT_EQ(0, image
.snap_remove("snap2-rename"));
2087 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2093 TEST_F(TestLibRBD
, ConcurrentCreatesUnvalidatedPool
)
2095 rados_ioctx_t ioctx
;
2096 ASSERT_EQ(0, rados_ioctx_create(_cluster
, create_pool(true).c_str(),
2099 std::vector
<std::string
> names
;
2100 for (int i
= 0; i
< 4; i
++) {
2101 names
.push_back(get_temp_image_name());
2103 uint64_t size
= 2 << 20;
2105 std::vector
<std::thread
> threads
;
2106 for (const auto& name
: names
) {
2107 threads
.emplace_back([ioctx
, &name
, size
]() {
2109 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2112 for (auto& thread
: threads
) {
2116 for (const auto& name
: names
) {
2117 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2119 rados_ioctx_destroy(ioctx
);
2122 static void remove_full_try(rados_ioctx_t ioctx
, const std::string
& image_name
,
2123 const std::string
& data_pool_name
)
2126 uint64_t quota
= 10 << 20;
2127 uint64_t size
= 5 * quota
;
2128 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), size
, &order
));
2130 std::string cmdstr
= "{\"prefix\": \"osd pool set-quota\", \"pool\": \"" +
2131 data_pool_name
+ "\", \"field\": \"max_bytes\", \"val\": \"" +
2132 std::to_string(quota
) + "\"}";
2134 cmd
[0] = (char *)cmdstr
.c_str();
2135 ASSERT_EQ(0, rados_mon_command(rados_ioctx_get_cluster(ioctx
),
2136 (const char **)cmd
, 1, "", 0, nullptr, 0,
2139 rados_set_pool_full_try(ioctx
);
2142 ASSERT_EQ(0, rbd_open(ioctx
, image_name
.c_str(), &image
, nullptr));
2145 size_t len
= 1 << 20;
2147 for (off
= 0; off
< size
; off
+= len
) {
2148 ret
= rbd_write_zeroes(image
, off
, len
,
2149 RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
,
2150 LIBRADOS_OP_FLAG_FADVISE_FUA
);
2154 ASSERT_EQ(ret
, len
);
2157 ASSERT_TRUE(off
>= quota
&& off
< size
);
2158 ASSERT_EQ(ret
, -EDQUOT
);
2160 ASSERT_EQ(0, rbd_close(image
));
2162 // make sure we have latest map that marked the pool full
2163 ASSERT_EQ(0, rados_wait_for_latest_osdmap(rados_ioctx_get_cluster(ioctx
)));
2164 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
2167 TEST_F(TestLibRBD
, RemoveFullTry
)
2169 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
2170 REQUIRE(!is_librados_test_stub(_rados
));
2172 rados_ioctx_t ioctx
;
2173 auto pool_name
= create_pool(true);
2174 ASSERT_EQ(0, rados_ioctx_create(_cluster
, pool_name
.c_str(), &ioctx
));
2175 // cancel out rbd_default_data_pool -- we need an image without
2176 // a separate data pool
2177 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_default_data_pool",
2178 pool_name
.c_str()));
2181 auto image_name
= get_temp_image_name();
2182 // FIXME: this is a workaround for rbd_trash object being created
2183 // on the first remove -- pre-create it to avoid bumping into quota
2184 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), 0, &order
));
2185 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
2186 remove_full_try(ioctx
, image_name
, pool_name
);
2188 rados_ioctx_destroy(ioctx
);
2191 TEST_F(TestLibRBD
, RemoveFullTryDataPool
)
2193 REQUIRE_FORMAT_V2();
2194 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
2195 REQUIRE(!is_librados_test_stub(_rados
));
2197 rados_ioctx_t ioctx
;
2198 auto pool_name
= create_pool(true);
2199 auto data_pool_name
= create_pool(true);
2200 ASSERT_EQ(0, rados_ioctx_create(_cluster
, pool_name
.c_str(), &ioctx
));
2201 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_default_data_pool",
2202 data_pool_name
.c_str()));
2204 auto image_name
= get_temp_image_name();
2205 remove_full_try(ioctx
, image_name
, data_pool_name
);
2207 rados_ioctx_destroy(ioctx
);
2210 TEST_F(TestLibRBD
, TestIO
)
2212 rados_ioctx_t ioctx
;
2213 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2217 std::string name
= get_temp_image_name();
2218 uint64_t size
= 2 << 20;
2220 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2221 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_read_from_replica_policy", "balance"));
2222 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2226 ASSERT_EQ(0, rbd_close(image
));
2228 rados_ioctx_destroy(ioctx
);
2231 TEST_F(TestLibRBD
, TestEncryptionLUKS1
)
2233 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2235 rados_ioctx_t ioctx
;
2236 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2239 std::string name
= get_temp_image_name();
2240 uint64_t size
= 32 << 20;
2242 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2243 ASSERT_EQ(0, rados_conf_set(
2244 _cluster
, "rbd_read_from_replica_policy", "balance"));
2247 rbd_encryption_luks1_format_options_t opts
= {
2248 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2249 .passphrase
= "password",
2250 .passphrase_size
= 8,
2252 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2254 #ifndef HAVE_LIBCRYPTSETUP
2255 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2256 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2257 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2258 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2260 ASSERT_EQ(0, rbd_encryption_format(
2261 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2262 ASSERT_EQ(-EEXIST
, rbd_encryption_load(
2263 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2268 write_test_data(image
, "test", 0, 4, 0, &passed
);
2269 ASSERT_TRUE(passed
);
2270 ASSERT_EQ(0, rbd_close(image
));
2272 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2273 ASSERT_EQ(0, rbd_encryption_load(
2274 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2275 read_test_data(image
, "test", 0, 4, 0, &passed
);
2276 ASSERT_TRUE(passed
);
2279 ASSERT_EQ(0, rbd_close(image
));
2280 rados_ioctx_destroy(ioctx
);
2283 TEST_F(TestLibRBD
, TestEncryptionLUKS2
)
2285 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2287 rados_ioctx_t ioctx
;
2288 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2291 std::string name
= get_temp_image_name();
2292 uint64_t size
= 32 << 20;
2294 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2295 ASSERT_EQ(0, rados_conf_set(
2296 _cluster
, "rbd_read_from_replica_policy", "balance"));
2299 rbd_encryption_luks2_format_options_t opts
= {
2300 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2301 .passphrase
= "password",
2302 .passphrase_size
= 8,
2304 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2306 #ifndef HAVE_LIBCRYPTSETUP
2307 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2308 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2309 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2310 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2312 ASSERT_EQ(0, rbd_encryption_format(
2313 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2314 ASSERT_EQ(-EEXIST
, rbd_encryption_load(
2315 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2320 write_test_data(image
, "test", 0, 4, 0, &passed
);
2321 ASSERT_TRUE(passed
);
2322 ASSERT_EQ(0, rbd_close(image
));
2324 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2325 ASSERT_EQ(0, rbd_encryption_load(
2326 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2327 read_test_data(image
, "test", 0, 4, 0, &passed
);
2328 ASSERT_TRUE(passed
);
2331 ASSERT_EQ(0, rbd_close(image
));
2332 rados_ioctx_destroy(ioctx
);
2335 TEST_F(TestLibRBD
, TestIOWithIOHint
)
2337 rados_ioctx_t ioctx
;
2338 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2342 std::string name
= get_temp_image_name();
2343 uint64_t size
= 2 << 20;
2345 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2346 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2348 bool skip_discard
= is_skip_partial_discard_enabled(image
);
2350 char test_data
[TEST_IO_SIZE
+ 1];
2351 char zero_data
[TEST_IO_SIZE
+ 1];
2352 char mismatch_data
[TEST_IO_SIZE
+ 1];
2354 uint64_t mismatch_offset
;
2356 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2357 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2359 test_data
[TEST_IO_SIZE
] = '\0';
2360 memset(zero_data
, 0, sizeof(zero_data
));
2361 memset(mismatch_data
, 9, sizeof(mismatch_data
));
2363 for (i
= 0; i
< 5; ++i
)
2364 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2365 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2367 for (i
= 5; i
< 10; ++i
)
2368 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2369 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2371 for (i
= 0; i
< 5; ++i
)
2372 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
2373 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2375 for (i
= 5; i
< 10; ++i
)
2376 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
2377 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2379 for (i
= 0; i
< 5; ++i
)
2380 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
,
2381 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2383 for (i
= 5; i
< 10; ++i
)
2384 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2385 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2387 // discard 2nd, 4th sections.
2388 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2389 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2391 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
,
2392 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2393 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2394 TEST_IO_SIZE
, TEST_IO_SIZE
,
2395 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2396 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
,
2397 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2398 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2399 TEST_IO_SIZE
*3, TEST_IO_SIZE
,
2400 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2401 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2403 for (i
= 0; i
< 15; ++i
) {
2405 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2406 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2407 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2408 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2409 } else if (i
% 3 == 1) {
2410 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2411 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2412 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2413 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2415 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2416 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2417 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2418 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2421 for (i
= 0; i
< 15; ++i
) {
2423 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2424 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2425 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2426 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2427 } else if (i
% 3 == 1) {
2428 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2429 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2430 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2431 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2433 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2434 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2435 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2436 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2440 rbd_image_info_t info
;
2441 rbd_completion_t comp
;
2442 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2443 // can't read or write starting past end
2444 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2445 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2446 // reading through end returns amount up to end
2447 ASSERT_EQ(10, rbd_read2(image
, info
.size
- 10, 100, test_data
,
2448 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
));
2449 // writing through end returns amount up to end
2450 ASSERT_EQ(10, rbd_write2(image
, info
.size
- 10, 100, test_data
,
2451 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2453 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2454 ASSERT_EQ(0, rbd_aio_read2(image
, info
.size
, 1, test_data
, comp
,
2455 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2456 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2457 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2458 rbd_aio_release(comp
);
2460 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2461 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2462 &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2463 ASSERT_EQ(0U, mismatch_offset
);
2464 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2465 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2466 comp
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2467 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2468 ASSERT_EQ(0U, mismatch_offset
);
2469 rbd_aio_release(comp
);
2471 ASSERT_PASSED(validate_object_map
, image
);
2472 ASSERT_EQ(0, rbd_close(image
));
2474 rados_ioctx_destroy(ioctx
);
2477 TEST_F(TestLibRBD
, TestDataPoolIO
)
2479 REQUIRE_FORMAT_V2();
2481 rados_ioctx_t ioctx
;
2482 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2484 std::string data_pool_name
= create_pool(true);
2487 std::string name
= get_temp_image_name();
2488 uint64_t size
= 2 << 20;
2492 ASSERT_EQ(0, get_features(&old_format
, &features
));
2493 ASSERT_FALSE(old_format
);
2495 rbd_image_options_t image_options
;
2496 rbd_image_options_create(&image_options
);
2497 BOOST_SCOPE_EXIT( (&image_options
) ) {
2498 rbd_image_options_destroy(image_options
);
2499 } BOOST_SCOPE_EXIT_END
;
2501 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
2502 RBD_IMAGE_OPTION_FEATURES
,
2504 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
2505 RBD_IMAGE_OPTION_DATA_POOL
,
2506 data_pool_name
.c_str()));
2508 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
2509 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2510 ASSERT_NE(-1, rbd_get_data_pool_id(image
));
2512 bool skip_discard
= is_skip_partial_discard_enabled(image
);
2514 char test_data
[TEST_IO_SIZE
+ 1];
2515 char zero_data
[TEST_IO_SIZE
+ 1];
2518 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2519 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2521 test_data
[TEST_IO_SIZE
] = '\0';
2522 memset(zero_data
, 0, sizeof(zero_data
));
2524 for (i
= 0; i
< 5; ++i
)
2525 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2527 for (i
= 5; i
< 10; ++i
)
2528 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2530 for (i
= 0; i
< 5; ++i
)
2531 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2533 for (i
= 5; i
< 10; ++i
)
2534 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2536 // discard 2nd, 4th sections.
2537 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2538 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2540 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
2541 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2542 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
2543 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
2544 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2545 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
2546 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2548 rbd_image_info_t info
;
2549 rbd_completion_t comp
;
2550 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2551 // can't read or write starting past end
2552 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2553 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2554 // reading through end returns amount up to end
2555 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
2556 // writing through end returns amount up to end
2557 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
2559 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2560 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
2561 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2562 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2563 rbd_aio_release(comp
);
2565 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2566 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
2567 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2568 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2569 rbd_aio_release(comp
);
2571 ASSERT_PASSED(validate_object_map
, image
);
2572 ASSERT_EQ(0, rbd_close(image
));
2574 rados_ioctx_destroy(ioctx
);
2577 TEST_F(TestLibRBD
, TestScatterGatherIO
)
2579 rados_ioctx_t ioctx
;
2580 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2584 std::string name
= get_temp_image_name();
2585 uint64_t size
= 20 << 20;
2587 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2588 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2590 std::string
write_buffer("This is a test");
2591 // These iovecs should produce a length overflow
2592 struct iovec bad_iovs
[] = {
2593 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
2594 {.iov_base
= NULL
, .iov_len
= std::numeric_limits
<size_t>::max()}
2596 struct iovec write_iovs
[] = {
2597 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
2598 {.iov_base
= &write_buffer
[5], .iov_len
= 3},
2599 {.iov_base
= &write_buffer
[8], .iov_len
= 2},
2600 {.iov_base
= &write_buffer
[10], .iov_len
= 4}
2603 rbd_completion_t comp
;
2604 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2605 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, write_iovs
, 0, 0, comp
));
2606 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, bad_iovs
, 2, 0, comp
));
2607 ASSERT_EQ(0, rbd_aio_writev(image
, write_iovs
,
2608 sizeof(write_iovs
) / sizeof(struct iovec
),
2610 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2611 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
2612 rbd_aio_release(comp
);
2614 std::string
read_buffer(write_buffer
.size(), '1');
2615 struct iovec read_iovs
[] = {
2616 {.iov_base
= &read_buffer
[0], .iov_len
= 4},
2617 {.iov_base
= &read_buffer
[8], .iov_len
= 4},
2618 {.iov_base
= &read_buffer
[12], .iov_len
= 2}
2621 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2622 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, read_iovs
, 0, 0, comp
));
2623 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, bad_iovs
, 2, 0, comp
));
2624 ASSERT_EQ(0, rbd_aio_readv(image
, read_iovs
,
2625 sizeof(read_iovs
) / sizeof(struct iovec
),
2627 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2628 ASSERT_EQ(10, rbd_aio_get_return_value(comp
));
2629 rbd_aio_release(comp
);
2630 ASSERT_EQ("This1111 is a ", read_buffer
);
2632 std::string
linear_buffer(write_buffer
.size(), '1');
2633 struct iovec linear_iovs
[] = {
2634 {.iov_base
= &linear_buffer
[4], .iov_len
= 4}
2636 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2637 ASSERT_EQ(0, rbd_aio_readv(image
, linear_iovs
,
2638 sizeof(linear_iovs
) / sizeof(struct iovec
),
2640 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2641 ASSERT_EQ(4, rbd_aio_get_return_value(comp
));
2642 rbd_aio_release(comp
);
2643 ASSERT_EQ("1111This111111", linear_buffer
);
2645 ASSERT_PASSED(validate_object_map
, image
);
2646 ASSERT_EQ(0, rbd_close(image
));
2648 rados_ioctx_destroy(ioctx
);
2651 TEST_F(TestLibRBD
, TestEmptyDiscard
)
2653 rados_ioctx_t ioctx
;
2654 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2658 std::string name
= get_temp_image_name();
2659 uint64_t size
= 20 << 20;
2661 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2662 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2664 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 1*1024*1024);
2665 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 4*1024*1024);
2666 ASSERT_PASSED(aio_discard_test_data
, image
, 3*1024*1024, 1*1024*1024);
2668 ASSERT_PASSED(validate_object_map
, image
);
2669 ASSERT_EQ(0, rbd_close(image
));
2671 rados_ioctx_destroy(ioctx
);
2674 TEST_F(TestLibRBD
, TestFUA
)
2676 rados_ioctx_t ioctx
;
2677 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2679 rbd_image_t image_write
;
2680 rbd_image_t image_read
;
2682 std::string name
= get_temp_image_name();
2683 uint64_t size
= 2 << 20;
2685 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2686 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_write
, NULL
));
2687 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_read
, NULL
));
2689 // enable writeback cache
2690 rbd_flush(image_write
);
2692 char test_data
[TEST_IO_SIZE
+ 1];
2695 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2696 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2698 test_data
[TEST_IO_SIZE
] = '\0';
2699 for (i
= 0; i
< 5; ++i
)
2700 ASSERT_PASSED(write_test_data
, image_write
, test_data
,
2701 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2703 for (i
= 0; i
< 5; ++i
)
2704 ASSERT_PASSED(read_test_data
, image_read
, test_data
,
2705 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2707 for (i
= 5; i
< 10; ++i
)
2708 ASSERT_PASSED(aio_write_test_data
, image_write
, test_data
,
2709 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2711 for (i
= 5; i
< 10; ++i
)
2712 ASSERT_PASSED(aio_read_test_data
, image_read
, test_data
,
2713 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2715 ASSERT_PASSED(validate_object_map
, image_write
);
2716 ASSERT_PASSED(validate_object_map
, image_read
);
2717 ASSERT_EQ(0, rbd_close(image_write
));
2718 ASSERT_EQ(0, rbd_close(image_read
));
2719 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2720 rados_ioctx_destroy(ioctx
);
2723 void simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
2725 cout
<< "write completion cb called!" << std::endl
;
2728 void simple_read_cb_pp(librbd::completion_t cb
, void *arg
)
2730 cout
<< "read completion cb called!" << std::endl
;
2733 void aio_write_test_data(librbd::Image
& image
, const char *test_data
,
2734 off_t off
, uint32_t iohint
, bool *passed
)
2736 ceph::bufferlist bl
;
2737 bl
.append(test_data
, strlen(test_data
));
2738 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2739 printf("created completion\n");
2741 image
.aio_write2(off
, strlen(test_data
), bl
, comp
, iohint
);
2743 image
.aio_write(off
, strlen(test_data
), bl
, comp
);
2744 printf("started write\n");
2745 comp
->wait_for_complete();
2746 int r
= comp
->get_return_value();
2747 printf("return value is: %d\n", r
);
2749 printf("finished write\n");
2754 void aio_discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2756 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2757 image
.aio_discard(off
, len
, comp
);
2758 comp
->wait_for_complete();
2759 int r
= comp
->get_return_value();
2765 void write_test_data(librbd::Image
& image
, const char *test_data
, off_t off
, uint32_t iohint
, bool *passed
)
2768 size_t len
= strlen(test_data
);
2769 ceph::bufferlist bl
;
2770 bl
.append(test_data
, len
);
2772 written
= image
.write2(off
, len
, bl
, iohint
);
2774 written
= image
.write(off
, len
, bl
);
2775 printf("wrote: %u\n", (unsigned int) written
);
2776 ASSERT_EQ(bl
.length(), written
);
2780 void discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2783 written
= image
.discard(off
, len
);
2784 printf("discard: %u~%u\n", (unsigned)off
, (unsigned)len
);
2785 ASSERT_EQ(len
, written
);
2789 void aio_read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2791 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_read_cb_pp
);
2792 ceph::bufferlist bl
;
2793 printf("created completion\n");
2795 image
.aio_read2(off
, expected_len
, bl
, comp
, iohint
);
2797 image
.aio_read(off
, expected_len
, bl
, comp
);
2798 printf("started read\n");
2799 comp
->wait_for_complete();
2800 int r
= comp
->get_return_value();
2801 printf("return value is: %d\n", r
);
2802 ASSERT_EQ(TEST_IO_SIZE
, r
);
2803 ASSERT_EQ(0, memcmp(expected
, bl
.c_str(), TEST_IO_SIZE
));
2804 printf("finished read\n");
2809 void read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2812 size_t len
= expected_len
;
2813 ceph::bufferlist bl
;
2815 read
= image
.read2(off
, len
, bl
, iohint
);
2817 read
= image
.read(off
, len
, bl
);
2818 ASSERT_TRUE(read
>= 0);
2819 std::string
bl_str(bl
.c_str(), read
);
2821 printf("read: %u\n", (unsigned int) read
);
2822 int result
= memcmp(bl_str
.c_str(), expected
, expected_len
);
2824 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), expected
);
2825 ASSERT_EQ(0, result
);
2830 void aio_writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2831 size_t len
, size_t data_len
, uint32_t iohint
, bool *passed
)
2833 ceph::bufferlist bl
;
2834 bl
.append(test_data
, data_len
);
2835 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2836 printf("created completion\n");
2838 r
= image
.aio_writesame(off
, len
, bl
, comp
, iohint
);
2839 printf("started writesame\n");
2840 if (len
% data_len
) {
2841 ASSERT_EQ(-EINVAL
, r
);
2842 printf("expected fail, finished writesame\n");
2848 comp
->wait_for_complete();
2849 r
= comp
->get_return_value();
2850 printf("return value is: %d\n", r
);
2852 printf("finished writesame\n");
2856 printf("to verify the data\n");
2858 uint64_t left
= len
;
2860 ceph::bufferlist bl
;
2861 read
= image
.read(off
, data_len
, bl
);
2862 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2863 std::string
bl_str(bl
.c_str(), read
);
2864 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2866 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2867 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2868 ASSERT_EQ(0, result
);
2873 ASSERT_EQ(0U, left
);
2874 printf("verified\n");
2879 void writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2880 ssize_t len
, size_t data_len
, uint32_t iohint
,
2884 ceph::bufferlist bl
;
2885 bl
.append(test_data
, data_len
);
2886 written
= image
.writesame(off
, len
, bl
, iohint
);
2887 if (len
% data_len
) {
2888 ASSERT_EQ(-EINVAL
, written
);
2889 printf("expected fail, finished writesame\n");
2893 ASSERT_EQ(len
, written
);
2894 printf("wrote: %u\n", (unsigned int) written
);
2898 printf("to verify the data\n");
2900 uint64_t left
= len
;
2902 ceph::bufferlist bl
;
2903 read
= image
.read(off
, data_len
, bl
);
2904 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2905 std::string
bl_str(bl
.c_str(), read
);
2906 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2908 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2909 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2910 ASSERT_EQ(0, result
);
2915 ASSERT_EQ(0U, left
);
2916 printf("verified\n");
2921 void aio_compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
,
2922 const char *test_data
, off_t off
, ssize_t len
,
2923 uint32_t iohint
, bool *passed
)
2925 ceph::bufferlist cmp_bl
;
2926 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2927 ceph::bufferlist test_bl
;
2928 test_bl
.append(test_data
, strlen(test_data
));
2929 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2930 printf("created completion\n");
2932 uint64_t mismatch_offset
;
2933 image
.aio_compare_and_write(off
, len
, cmp_bl
, test_bl
, comp
, &mismatch_offset
, iohint
);
2934 printf("started aio compare and write\n");
2935 comp
->wait_for_complete();
2936 int r
= comp
->get_return_value();
2937 printf("return value is: %d\n", r
);
2939 printf("finished aio compare and write\n");
2944 void compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
, const char *test_data
,
2945 off_t off
, ssize_t len
, uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
2948 ceph::bufferlist cmp_bl
;
2949 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2950 ceph::bufferlist test_bl
;
2951 test_bl
.append(test_data
, strlen(test_data
));
2952 printf("start compare and write\n");
2953 written
= image
.compare_and_write(off
, len
, cmp_bl
, test_bl
, mismatch_off
, iohint
);
2954 printf("compare and wrote: %d\n", (int) written
);
2955 ASSERT_EQ(len
, static_cast<ssize_t
>(written
));
2959 TEST_F(TestLibRBD
, TestIOPP
)
2961 librados::IoCtx ioctx
;
2962 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2966 librbd::Image image
;
2968 std::string name
= get_temp_image_name();
2969 uint64_t size
= 2 << 20;
2971 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2972 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2974 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
2976 char test_data
[TEST_IO_SIZE
+ 1];
2977 char zero_data
[TEST_IO_SIZE
+ 1];
2979 uint64_t mismatch_offset
;
2981 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2982 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2984 test_data
[TEST_IO_SIZE
] = '\0';
2985 memset(zero_data
, 0, sizeof(zero_data
));
2987 for (i
= 0; i
< 5; ++i
)
2988 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2990 for (i
= 5; i
< 10; ++i
)
2991 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2993 for (i
= 0; i
< 5; ++i
)
2994 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
2995 TEST_IO_SIZE
, &mismatch_offset
, 0);
2997 for (i
= 5; i
< 10; ++i
)
2998 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
3001 for (i
= 0; i
< 5; ++i
)
3002 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
3004 for (i
= 5; i
< 10; ++i
)
3005 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
3007 // discard 2nd, 4th sections.
3008 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
3009 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
3011 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
3012 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3013 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
3014 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
3015 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3016 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
3017 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
3019 for (i
= 0; i
< 15; ++i
) {
3021 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3022 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3023 } else if (i
% 3 == 1) {
3024 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3025 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3027 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3028 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3031 for (i
= 0; i
< 15; ++i
) {
3033 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3034 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3035 } else if (i
% 3 == 1) {
3036 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3037 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3039 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3040 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3044 ASSERT_PASSED(validate_object_map
, image
);
3050 TEST_F(TestLibRBD
, TestIOPPWithIOHint
)
3052 librados::IoCtx ioctx
;
3053 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3057 librbd::Image image
;
3059 std::string name
= get_temp_image_name();
3060 uint64_t size
= 2 << 20;
3062 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3063 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3065 char test_data
[TEST_IO_SIZE
+ 1];
3066 char zero_data
[TEST_IO_SIZE
+ 1];
3067 test_data
[TEST_IO_SIZE
] = '\0';
3070 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3071 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3073 memset(zero_data
, 0, sizeof(zero_data
));
3075 for (i
= 0; i
< 5; ++i
)
3076 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
,
3077 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3079 for (i
= 5; i
< 10; ++i
)
3080 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
,
3081 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3083 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
),
3084 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_RANDOM
);
3086 for (i
= 5; i
< 10; ++i
)
3087 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
,
3088 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3090 for (i
= 0; i
< 15; ++i
) {
3092 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3093 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3094 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3095 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3096 } else if (i
% 3 == 1) {
3097 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
3098 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3099 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
3100 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3102 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3103 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3104 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3105 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3108 for (i
= 0; i
< 15; ++i
) {
3110 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3111 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3112 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3113 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3114 } else if (i
% 3 == 1) {
3115 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
3116 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3117 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
3118 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3120 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3121 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3122 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3123 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3127 ASSERT_PASSED(validate_object_map
, image
);
3135 TEST_F(TestLibRBD
, TestIOToSnapshot
)
3137 rados_ioctx_t ioctx
;
3138 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3142 std::string name
= get_temp_image_name();
3143 uint64_t isize
= 2 << 20;
3145 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
3146 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3149 rbd_image_t image_at_snap
;
3150 char orig_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
3151 char test_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
3153 for (i
= 0; i
< TEST_IO_TO_SNAP_SIZE
; ++i
)
3154 test_data
[i
] = (char) (i
+ 48);
3155 test_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
3156 orig_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
3158 r
= rbd_read(image
, 0, TEST_IO_TO_SNAP_SIZE
, orig_data
);
3159 ASSERT_EQ(r
, TEST_IO_TO_SNAP_SIZE
);
3161 ASSERT_EQ(0, test_ls_snaps(image
, 0));
3162 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
3163 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
3164 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3166 printf("write test data!\n");
3167 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3168 ASSERT_EQ(0, rbd_snap_create(image
, "written"));
3169 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
3171 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3173 rbd_snap_set(image
, "orig");
3174 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3176 rbd_snap_set(image
, "written");
3177 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3179 rbd_snap_set(image
, "orig");
3181 r
= rbd_write(image
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
3182 printf("write to snapshot returned %d\n", r
);
3184 cout
<< strerror(-r
) << std::endl
;
3186 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3187 rbd_snap_set(image
, "written");
3188 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3190 r
= rbd_snap_rollback(image
, "orig");
3191 ASSERT_EQ(r
, -EROFS
);
3193 r
= rbd_snap_set(image
, NULL
);
3195 r
= rbd_snap_rollback(image
, "orig");
3198 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3202 printf("opening testimg@orig\n");
3203 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_at_snap
, "orig"));
3204 ASSERT_PASSED(read_test_data
, image_at_snap
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3205 r
= rbd_write(image_at_snap
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
3206 printf("write to snapshot returned %d\n", r
);
3208 cout
<< strerror(-r
) << std::endl
;
3209 ASSERT_EQ(0, rbd_close(image_at_snap
));
3211 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
3212 ASSERT_EQ(0, rbd_snap_remove(image
, "written"));
3213 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
3214 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
3215 ASSERT_EQ(0, test_ls_snaps(image
, 0));
3217 ASSERT_PASSED(validate_object_map
, image
);
3218 ASSERT_EQ(0, rbd_close(image
));
3220 rados_ioctx_destroy(ioctx
);
3223 TEST_F(TestLibRBD
, TestSnapshotDeletedIo
)
3225 rados_ioctx_t ioctx
;
3226 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3230 std::string name
= get_temp_image_name();
3231 uint64_t isize
= 2 << 20;
3235 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
3236 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3237 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
3239 r
= rbd_snap_set(image
, "orig");
3242 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
3244 ASSERT_EQ(-ENOENT
, rbd_read(image
, 20, 20, test
));
3246 r
= rbd_snap_set(image
, NULL
);
3249 ASSERT_EQ(0, rbd_close(image
));
3250 rados_ioctx_destroy(ioctx
);
3253 TEST_F(TestLibRBD
, TestClone
)
3255 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3256 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "1"));
3257 BOOST_SCOPE_EXIT_ALL(&) {
3258 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
3261 rados_ioctx_t ioctx
;
3262 rbd_image_info_t pinfo
, cinfo
;
3263 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3267 rbd_image_t parent
, child
;
3270 ASSERT_EQ(0, get_features(&old_format
, &features
));
3271 ASSERT_FALSE(old_format
);
3273 std::string parent_name
= get_temp_image_name();
3274 std::string child_name
= get_temp_image_name();
3276 // make a parent to clone from
3277 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
3279 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
3280 printf("made parent image \"parent\"\n");
3282 char *data
= (char *)"testdata";
3283 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
3285 // can't clone a non-snapshot, expect failure
3286 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
3287 child_name
.c_str(), features
, &order
));
3289 // verify that there is no parent info on "parent"
3290 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
3291 printf("parent has no parent info\n");
3293 // create 70 metadatas to verify we can clone all key/value pairs
3296 size_t sum_key_len
= 0;
3297 size_t sum_value_len
= 0;
3298 for (int i
= 1; i
<= 70; i
++) {
3299 key
= "key" + stringify(i
);
3300 val
= "value" + stringify(i
);
3301 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
3303 sum_key_len
+= (key
.size() + 1);
3304 sum_value_len
+= (val
.size() + 1);
3309 size_t keys_len
= sizeof(keys
);
3310 size_t vals_len
= sizeof(vals
);
3313 size_t value_len
= sizeof(value
);
3315 // create a snapshot, reopen as the parent we're interested in
3316 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3317 printf("made snapshot \"parent@parent_snap\"\n");
3318 ASSERT_EQ(0, rbd_close(parent
));
3319 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
3321 ASSERT_EQ(-EINVAL
, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3322 ioctx
, child_name
.c_str(), features
, &order
));
3324 // unprotected image should fail unprotect
3325 ASSERT_EQ(-EINVAL
, rbd_snap_unprotect(parent
, "parent_snap"));
3326 printf("can't unprotect an unprotected snap\n");
3328 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3329 // protecting again should fail
3330 ASSERT_EQ(-EBUSY
, rbd_snap_protect(parent
, "parent_snap"));
3331 printf("can't protect a protected snap\n");
3333 // This clone and open should work
3334 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3335 ioctx
, child_name
.c_str(), features
, &order
));
3336 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
3337 printf("made and opened clone \"child\"\n");
3340 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
3343 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(child
, 20, strlen(data
), data
));
3344 ASSERT_PASSED(read_test_data
, child
, data
, 20, strlen(data
), 0);
3345 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
3348 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
3349 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3350 EXPECT_EQ(cinfo
.size
, pinfo
.size
);
3352 rbd_get_overlap(child
, &overlap
);
3353 EXPECT_EQ(overlap
, pinfo
.size
);
3354 EXPECT_EQ(cinfo
.obj_size
, pinfo
.obj_size
);
3355 EXPECT_EQ(cinfo
.order
, pinfo
.order
);
3356 printf("sizes and overlaps are good between parent and child\n");
3358 // check key/value pairs in child image
3359 ASSERT_EQ(0, rbd_metadata_list(child
, "key", 70, keys
, &keys_len
, vals
,
3361 ASSERT_EQ(sum_key_len
, keys_len
);
3362 ASSERT_EQ(sum_value_len
, vals_len
);
3364 for (int i
= 1; i
<= 70; i
++) {
3365 key
= "key" + stringify(i
);
3366 val
= "value" + stringify(i
);
3367 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3368 ASSERT_STREQ(val
.c_str(), value
);
3370 value_len
= sizeof(value
);
3372 printf("child image successfully cloned all image-meta pairs\n");
3374 // sizing down child results in changing overlap and size, not parent size
3375 ASSERT_EQ(0, rbd_resize(child
, 2UL<<20));
3376 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3377 rbd_get_overlap(child
, &overlap
);
3378 ASSERT_EQ(overlap
, 2UL<<20);
3379 ASSERT_EQ(cinfo
.size
, 2UL<<20);
3380 ASSERT_EQ(0, rbd_resize(child
, 4UL<<20));
3381 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3382 rbd_get_overlap(child
, &overlap
);
3383 ASSERT_EQ(overlap
, 2UL<<20);
3384 ASSERT_EQ(cinfo
.size
, 4UL<<20);
3385 printf("sized down clone, changed overlap\n");
3387 // sizing back up doesn't change that
3388 ASSERT_EQ(0, rbd_resize(child
, 5UL<<20));
3389 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3390 rbd_get_overlap(child
, &overlap
);
3391 ASSERT_EQ(overlap
, 2UL<<20);
3392 ASSERT_EQ(cinfo
.size
, 5UL<<20);
3393 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
3394 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
3395 (unsigned long long)pinfo
.size
, (unsigned long long)pinfo
.obj_size
,
3396 (unsigned long long)pinfo
.parent_pool
);
3397 ASSERT_EQ(pinfo
.size
, 4UL<<20);
3398 printf("sized up clone, changed size but not overlap or parent's size\n");
3400 ASSERT_PASSED(validate_object_map
, child
);
3401 ASSERT_EQ(0, rbd_close(child
));
3403 ASSERT_PASSED(validate_object_map
, parent
);
3404 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3405 printf("can't remove parent while child still exists\n");
3406 ASSERT_EQ(0, rbd_remove(ioctx
, child_name
.c_str()));
3407 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3408 printf("can't remove parent while still protected\n");
3409 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3410 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3411 printf("removed parent snap after unprotecting\n");
3413 ASSERT_EQ(0, rbd_close(parent
));
3414 rados_ioctx_destroy(ioctx
);
3417 TEST_F(TestLibRBD
, TestClone2
)
3419 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3420 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
3421 BOOST_SCOPE_EXIT_ALL(&) {
3422 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
3425 rados_ioctx_t ioctx
;
3426 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3430 rbd_image_t parent
, child
;
3433 ASSERT_EQ(0, get_features(&old_format
, &features
));
3434 ASSERT_FALSE(old_format
);
3436 std::string parent_name
= get_temp_image_name();
3437 std::string child_name
= get_temp_image_name();
3439 // make a parent to clone from
3440 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
3442 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
3443 printf("made parent image \"parent\"\n");
3445 char *data
= (char *)"testdata";
3446 char *childata
= (char *)"childata";
3447 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
3448 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
3450 // can't clone a non-snapshot, expect failure
3451 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
3452 child_name
.c_str(), features
, &order
));
3454 // verify that there is no parent info on "parent"
3455 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
3456 printf("parent has no parent info\n");
3458 // create 70 metadatas to verify we can clone all key/value pairs
3461 size_t sum_key_len
= 0;
3462 size_t sum_value_len
= 0;
3463 for (int i
= 1; i
<= 70; i
++) {
3464 key
= "key" + stringify(i
);
3465 val
= "value" + stringify(i
);
3466 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
3468 sum_key_len
+= (key
.size() + 1);
3469 sum_value_len
+= (val
.size() + 1);
3474 size_t keys_len
= sizeof(keys
);
3475 size_t vals_len
= sizeof(vals
);
3478 size_t value_len
= sizeof(value
);
3480 // create a snapshot, reopen as the parent we're interested in
3481 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3482 printf("made snapshot \"parent@parent_snap\"\n");
3483 ASSERT_EQ(0, rbd_close(parent
));
3484 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
3486 // This clone and open should work
3487 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3488 ioctx
, child_name
.c_str(), features
, &order
));
3489 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
3490 printf("made and opened clone \"child\"\n");
3492 // check key/value pairs in child image
3493 ASSERT_EQ(0, rbd_metadata_list(child
, "key", 70, keys
, &keys_len
, vals
,
3495 ASSERT_EQ(sum_key_len
, keys_len
);
3496 ASSERT_EQ(sum_value_len
, vals_len
);
3498 for (int i
= 1; i
<= 70; i
++) {
3499 key
= "key" + stringify(i
);
3500 val
= "value" + stringify(i
);
3501 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3502 ASSERT_STREQ(val
.c_str(), value
);
3504 value_len
= sizeof(value
);
3506 printf("child image successfully cloned all image-meta pairs\n");
3508 // write something in
3509 ASSERT_EQ((ssize_t
)strlen(childata
), rbd_write(child
, 20, strlen(childata
), childata
));
3511 char test
[strlen(data
) * 2];
3512 ASSERT_EQ((ssize_t
)strlen(data
), rbd_read(child
, 20, strlen(data
), test
));
3513 ASSERT_EQ(0, memcmp(test
, childata
, strlen(childata
)));
3516 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 20 - strlen(data
), sizeof(test
), test
));
3517 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3518 ASSERT_EQ(0, memcmp(test
+ strlen(data
), childata
, strlen(childata
)));
3521 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 0, sizeof(test
), test
));
3522 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3524 ASSERT_PASSED(validate_object_map
, child
);
3525 ASSERT_PASSED(validate_object_map
, parent
);
3527 rbd_snap_info_t snaps
[2];
3529 ASSERT_EQ(1, rbd_snap_list(parent
, snaps
, &max_snaps
));
3530 rbd_snap_list_end(snaps
);
3532 ASSERT_EQ(0, rbd_snap_remove_by_id(parent
, snaps
[0].id
));
3534 rbd_snap_namespace_type_t snap_namespace_type
;
3535 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent
, snaps
[0].id
,
3536 &snap_namespace_type
));
3537 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH
, snap_namespace_type
);
3539 char original_name
[32];
3540 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent
, snaps
[0].id
,
3542 sizeof(original_name
)));
3543 ASSERT_EQ(0, strcmp("parent_snap", original_name
));
3545 ASSERT_EQ(0, rbd_close(child
));
3546 ASSERT_EQ(0, rbd_close(parent
));
3547 rados_ioctx_destroy(ioctx
);
3550 static void test_list_children(rbd_image_t image
, ssize_t num_expected
, ...)
3553 va_start(ap
, num_expected
);
3554 size_t pools_len
= 100;
3555 size_t children_len
= 100;
3557 char *children
= NULL
;
3558 ssize_t num_children
;
3563 pools
= (char *) malloc(pools_len
);
3564 children
= (char *) malloc(children_len
);
3565 num_children
= rbd_list_children(image
, pools
, &pools_len
,
3566 children
, &children_len
);
3567 } while (num_children
== -ERANGE
);
3569 ASSERT_EQ(num_expected
, num_children
);
3570 for (ssize_t i
= num_expected
; i
> 0; --i
) {
3571 char *expected_pool
= va_arg(ap
, char *);
3572 char *expected_image
= va_arg(ap
, char *);
3574 char *image
= children
;
3576 printf("\ntrying to find %s/%s\n", expected_pool
, expected_image
);
3577 for (ssize_t j
= 0; j
< num_children
; ++j
) {
3578 printf("checking %s/%s\n", pool
, image
);
3579 if (strcmp(expected_pool
, pool
) == 0 &&
3580 strcmp(expected_image
, image
) == 0) {
3581 printf("found child %s/%s\n\n", pool
, image
);
3585 pool
+= strlen(pool
) + 1;
3586 image
+= strlen(image
) + 1;
3587 if (j
== num_children
- 1) {
3588 ASSERT_EQ(pool
- pools
- 1, (ssize_t
) pools_len
);
3589 ASSERT_EQ(image
- children
- 1, (ssize_t
) children_len
);
3602 static void test_list_children2(rbd_image_t image
, int num_expected
, ...)
3604 int num_children
, i
, j
, max_size
= 10;
3606 rbd_child_info_t children
[max_size
];
3607 num_children
= rbd_list_children2(image
, children
, &max_size
);
3608 printf("num children is: %d\nexpected: %d\n", num_children
, num_expected
);
3610 for (i
= 0; i
< num_children
; i
++) {
3611 printf("child: %s\n", children
[i
].image_name
);
3614 va_start(ap
, num_expected
);
3615 for (i
= num_expected
; i
> 0; i
--) {
3616 char *expected_id
= va_arg(ap
, char *);
3617 char *expected_pool
= va_arg(ap
, char *);
3618 char *expected_image
= va_arg(ap
, char *);
3619 bool expected_trash
= va_arg(ap
, int);
3621 for (j
= 0; j
< num_children
; j
++) {
3622 if (children
[j
].pool_name
== NULL
||
3623 children
[j
].image_name
== NULL
||
3624 children
[j
].image_id
== NULL
)
3626 if (strcmp(children
[j
].image_id
, expected_id
) == 0 &&
3627 strcmp(children
[j
].pool_name
, expected_pool
) == 0 &&
3628 strcmp(children
[j
].image_name
, expected_image
) == 0 &&
3629 children
[j
].trash
== expected_trash
) {
3630 printf("found child %s/%s/%s\n\n", children
[j
].pool_name
, children
[j
].image_name
, children
[j
].image_id
);
3631 rbd_list_child_cleanup(&children
[j
]);
3632 children
[j
].pool_name
= NULL
;
3633 children
[j
].image_name
= NULL
;
3634 children
[j
].image_id
= NULL
;
3643 for (i
= 0; i
< num_children
; i
++) {
3644 EXPECT_EQ((const char *)0, children
[i
].pool_name
);
3645 EXPECT_EQ((const char *)0, children
[i
].image_name
);
3646 EXPECT_EQ((const char *)0, children
[i
].image_id
);
3650 TEST_F(TestLibRBD
, ListChildren
)
3652 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3655 rados_ioctx_t ioctx1
, ioctx2
;
3656 string pool_name1
= create_pool(true);
3657 string pool_name2
= create_pool(true);
3658 ASSERT_NE("", pool_name2
);
3660 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3661 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3673 ASSERT_EQ(0, get_features(&old_format
, &features
));
3674 ASSERT_FALSE(old_format
);
3676 std::string parent_name
= get_temp_image_name();
3677 std::string child_name1
= get_temp_image_name();
3678 std::string child_name2
= get_temp_image_name();
3679 std::string child_name3
= get_temp_image_name();
3680 std::string child_name4
= get_temp_image_name();
3682 char child_id1
[4096];
3683 char child_id2
[4096];
3684 char child_id3
[4096];
3685 char child_id4
[4096];
3687 // make a parent to clone from
3688 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3690 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3691 // create a snapshot, reopen as the parent we're interested in
3692 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3693 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3694 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3696 ASSERT_EQ(0, rbd_close(parent
));
3697 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3699 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3700 ioctx2
, child_name1
.c_str(), features
, &order
));
3701 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3702 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3703 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3704 test_list_children2(parent
, 1,
3705 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3707 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3708 ioctx1
, child_name2
.c_str(), features
, &order
));
3709 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3710 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3711 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3712 pool_name1
.c_str(), child_name2
.c_str());
3713 test_list_children2(parent
, 2,
3714 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3715 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3717 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3718 ioctx2
, child_name3
.c_str(), features
, &order
));
3719 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3720 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3721 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3722 pool_name1
.c_str(), child_name2
.c_str(),
3723 pool_name2
.c_str(), child_name3
.c_str());
3724 test_list_children2(parent
, 3,
3725 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3726 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3727 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3729 librados::IoCtx ioctx3
;
3730 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3731 ASSERT_EQ(0, rbd_close(image3
));
3732 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3733 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3734 pool_name1
.c_str(), child_name2
.c_str());
3735 test_list_children2(parent
, 3,
3736 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3737 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3738 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3740 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3741 ioctx2
, child_name4
.c_str(), features
, &order
));
3742 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3743 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3744 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3745 pool_name1
.c_str(), child_name2
.c_str(),
3746 pool_name2
.c_str(), child_name4
.c_str());
3747 test_list_children2(parent
, 4,
3748 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3749 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3750 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3751 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3753 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3754 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3755 pool_name1
.c_str(), child_name2
.c_str(),
3756 pool_name2
.c_str(), child_name3
.c_str(),
3757 pool_name2
.c_str(), child_name4
.c_str());
3758 test_list_children2(parent
, 4,
3759 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3760 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3761 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3762 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3764 ASSERT_EQ(0, rbd_close(image1
));
3765 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3766 test_list_children(parent
, 3,
3767 pool_name1
.c_str(), child_name2
.c_str(),
3768 pool_name2
.c_str(), child_name3
.c_str(),
3769 pool_name2
.c_str(), child_name4
.c_str());
3770 test_list_children2(parent
, 3,
3771 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3772 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3773 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3775 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3776 test_list_children(parent
, 2,
3777 pool_name1
.c_str(), child_name2
.c_str(),
3778 pool_name2
.c_str(), child_name4
.c_str());
3779 test_list_children2(parent
, 2,
3780 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3781 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3783 ASSERT_EQ(0, rbd_close(image4
));
3784 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3785 test_list_children(parent
, 1,
3786 pool_name1
.c_str(), child_name2
.c_str());
3787 test_list_children2(parent
, 1,
3788 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3791 ASSERT_EQ(0, rbd_close(image2
));
3792 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3793 test_list_children(parent
, 0);
3794 test_list_children2(parent
, 0);
3796 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3797 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3798 ASSERT_EQ(0, rbd_close(parent
));
3799 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3800 rados_ioctx_destroy(ioctx1
);
3801 rados_ioctx_destroy(ioctx2
);
3804 TEST_F(TestLibRBD
, ListChildrenTiered
)
3806 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3809 string pool_name1
= create_pool(true);
3810 string pool_name2
= create_pool(true);
3811 string pool_name3
= create_pool(true);
3812 ASSERT_NE("", pool_name1
);
3813 ASSERT_NE("", pool_name2
);
3814 ASSERT_NE("", pool_name3
);
3816 std::string cmdstr
= "{\"prefix\": \"osd tier add\", \"pool\": \"" +
3817 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\", \"force_nonempty\":\"\"}";
3819 cmd
[0] = (char *)cmdstr
.c_str();
3820 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3822 cmdstr
= "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
3823 pool_name3
+ "\", \"mode\":\"writeback\"}";
3824 cmd
[0] = (char *)cmdstr
.c_str();
3825 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3827 cmdstr
= "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
3828 pool_name1
+ "\", \"overlaypool\":\"" + pool_name3
+ "\"}";
3829 cmd
[0] = (char *)cmdstr
.c_str();
3830 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3832 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
3834 string parent_name
= get_temp_image_name();
3835 string child_name1
= get_temp_image_name();
3836 string child_name2
= get_temp_image_name();
3837 string child_name3
= get_temp_image_name();
3838 string child_name4
= get_temp_image_name();
3840 char child_id1
[4096];
3841 char child_id2
[4096];
3842 char child_id3
[4096];
3843 char child_id4
[4096];
3850 rados_ioctx_t ioctx1
, ioctx2
;
3851 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3852 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3859 ASSERT_EQ(0, get_features(&old_format
, &features
));
3860 ASSERT_FALSE(old_format
);
3862 // make a parent to clone from
3863 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3865 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3866 // create a snapshot, reopen as the parent we're interested in
3867 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3868 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3869 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3871 ASSERT_EQ(0, rbd_close(parent
));
3872 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3874 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3875 ioctx2
, child_name1
.c_str(), features
, &order
));
3876 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3877 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3878 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3879 test_list_children2(parent
, 1,
3880 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3882 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3883 ioctx1
, child_name2
.c_str(), features
, &order
));
3884 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3885 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3886 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3887 pool_name1
.c_str(), child_name2
.c_str());
3888 test_list_children2(parent
, 2,
3889 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3890 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3892 // read from the cache to populate it
3893 rbd_image_t tier_image
;
3894 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &tier_image
, NULL
));
3895 size_t len
= 4 * 1024 * 1024;
3896 char* buf
= (char*)malloc(len
);
3897 ssize_t size
= rbd_read(tier_image
, 0, len
, buf
);
3900 ASSERT_EQ(0, rbd_close(tier_image
));
3902 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3903 ioctx2
, child_name3
.c_str(), features
, &order
));
3904 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3905 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3906 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3907 pool_name1
.c_str(), child_name2
.c_str(),
3908 pool_name2
.c_str(), child_name3
.c_str());
3909 test_list_children2(parent
, 3,
3910 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3911 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3912 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3914 librados::IoCtx ioctx3
;
3915 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3916 ASSERT_EQ(0, rbd_close(image3
));
3917 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3918 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3919 pool_name1
.c_str(), child_name2
.c_str());
3920 test_list_children2(parent
, 3,
3921 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3922 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3923 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3925 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3926 ioctx2
, child_name4
.c_str(), features
, &order
));
3927 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3928 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3929 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3930 pool_name1
.c_str(), child_name2
.c_str(),
3931 pool_name2
.c_str(), child_name4
.c_str());
3932 test_list_children2(parent
, 4,
3933 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3934 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3935 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3936 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3938 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3939 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3940 pool_name1
.c_str(), child_name2
.c_str(),
3941 pool_name2
.c_str(), child_name3
.c_str(),
3942 pool_name2
.c_str(), child_name4
.c_str());
3943 test_list_children2(parent
, 4,
3944 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3945 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3946 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3947 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3949 ASSERT_EQ(0, rbd_close(image1
));
3950 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3951 test_list_children(parent
, 3,
3952 pool_name1
.c_str(), child_name2
.c_str(),
3953 pool_name2
.c_str(), child_name3
.c_str(),
3954 pool_name2
.c_str(), child_name4
.c_str());
3955 test_list_children2(parent
, 3,
3956 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3957 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3958 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3960 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3961 test_list_children(parent
, 2,
3962 pool_name1
.c_str(), child_name2
.c_str(),
3963 pool_name2
.c_str(), child_name4
.c_str());
3964 test_list_children2(parent
, 2,
3965 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3966 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3968 ASSERT_EQ(0, rbd_close(image4
));
3969 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3970 test_list_children(parent
, 1,
3971 pool_name1
.c_str(), child_name2
.c_str());
3972 test_list_children2(parent
, 1,
3973 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3975 ASSERT_EQ(0, rbd_close(image2
));
3976 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3977 test_list_children(parent
, 0);
3978 test_list_children2(parent
, 0);
3980 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3981 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3982 ASSERT_EQ(0, rbd_close(parent
));
3983 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3984 rados_ioctx_destroy(ioctx1
);
3985 rados_ioctx_destroy(ioctx2
);
3986 cmdstr
= "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
3988 cmd
[0] = (char *)cmdstr
.c_str();
3989 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3990 cmdstr
= "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
3991 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\"}";
3992 cmd
[0] = (char *)cmdstr
.c_str();
3993 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3996 TEST_F(TestLibRBD
, LockingPP
)
3998 librados::IoCtx ioctx
;
3999 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4003 librbd::Image image
;
4005 std::string name
= get_temp_image_name();
4006 uint64_t size
= 2 << 20;
4007 std::string cookie1
= "foo";
4008 std::string cookie2
= "bar";
4010 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4011 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4013 // no lockers initially
4014 std::list
<librbd::locker_t
> lockers
;
4017 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4018 ASSERT_EQ(0u, lockers
.size());
4021 // exclusive lock is exclusive
4022 ASSERT_EQ(0, image
.lock_exclusive(cookie1
));
4023 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
4024 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
4025 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
4026 ASSERT_EQ(-EBUSY
, image
.lock_shared(cookie1
, "test"));
4027 ASSERT_EQ(-EBUSY
, image
.lock_shared("", "test"));
4028 ASSERT_EQ(-EBUSY
, image
.lock_shared("", ""));
4031 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4032 ASSERT_TRUE(exclusive
);
4034 ASSERT_EQ(1u, lockers
.size());
4035 ASSERT_EQ(cookie1
, lockers
.front().cookie
);
4038 ASSERT_EQ(-ENOENT
, image
.unlock(""));
4039 ASSERT_EQ(-ENOENT
, image
.unlock(cookie2
));
4040 ASSERT_EQ(0, image
.unlock(cookie1
));
4041 ASSERT_EQ(-ENOENT
, image
.unlock(cookie1
));
4042 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4043 ASSERT_EQ(0u, lockers
.size());
4045 ASSERT_EQ(0, image
.lock_shared(cookie1
, ""));
4046 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
4047 ASSERT_EQ(0, image
.lock_shared(cookie2
, ""));
4048 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie2
, ""));
4049 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
4050 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie2
));
4051 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
4052 ASSERT_EQ(-EBUSY
, image
.lock_exclusive("test"));
4055 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4056 ASSERT_EQ(2u, lockers
.size());
4062 TEST_F(TestLibRBD
, FlushAio
)
4064 rados_ioctx_t ioctx
;
4065 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4069 std::string name
= get_temp_image_name();
4070 uint64_t size
= 2 << 20;
4071 size_t num_aios
= 256;
4073 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4074 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4076 char test_data
[TEST_IO_SIZE
+ 1];
4078 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4079 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4082 rbd_completion_t write_comps
[num_aios
];
4083 for (i
= 0; i
< num_aios
; ++i
) {
4084 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &write_comps
[i
]));
4085 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4086 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
4090 rbd_completion_t flush_comp
;
4091 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &flush_comp
));
4092 ASSERT_EQ(0, rbd_aio_flush(image
, flush_comp
));
4093 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp
));
4094 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp
));
4095 rbd_aio_release(flush_comp
);
4097 for (i
= 0; i
< num_aios
; ++i
) {
4098 ASSERT_EQ(1, rbd_aio_is_complete(write_comps
[i
]));
4099 rbd_aio_release(write_comps
[i
]);
4102 ASSERT_PASSED(validate_object_map
, image
);
4103 ASSERT_EQ(0, rbd_close(image
));
4104 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
4105 rados_ioctx_destroy(ioctx
);
4108 TEST_F(TestLibRBD
, FlushAioPP
)
4110 librados::IoCtx ioctx
;
4111 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4115 librbd::Image image
;
4117 std::string name
= get_temp_image_name();
4118 uint64_t size
= 2 << 20;
4119 const size_t num_aios
= 256;
4121 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4122 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4124 char test_data
[TEST_IO_SIZE
+ 1];
4126 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4127 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4129 test_data
[TEST_IO_SIZE
] = '\0';
4131 librbd::RBD::AioCompletion
*write_comps
[num_aios
];
4132 ceph::bufferlist bls
[num_aios
];
4133 for (i
= 0; i
< num_aios
; ++i
) {
4134 bls
[i
].append(test_data
, strlen(test_data
));
4135 write_comps
[i
] = new librbd::RBD::AioCompletion(NULL
, NULL
);
4136 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4137 ASSERT_EQ(0, image
.aio_write(offset
, TEST_IO_SIZE
, bls
[i
],
4141 librbd::RBD::AioCompletion
*flush_comp
=
4142 new librbd::RBD::AioCompletion(NULL
, NULL
);
4143 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
4144 ASSERT_EQ(0, flush_comp
->wait_for_complete());
4145 ASSERT_EQ(1, flush_comp
->is_complete());
4146 flush_comp
->release();
4148 for (i
= 0; i
< num_aios
; ++i
) {
4149 librbd::RBD::AioCompletion
*comp
= write_comps
[i
];
4150 ASSERT_EQ(1, comp
->is_complete());
4153 ASSERT_PASSED(validate_object_map
, image
);
4160 int iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
4162 //cout << "iterate_cb " << off << "~" << len << std::endl;
4163 interval_set
<uint64_t> *diff
= static_cast<interval_set
<uint64_t> *>(arg
);
4164 diff
->insert(off
, len
);
4168 static int iterate_error_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
4173 void scribble(librbd::Image
& image
, int n
, int max
, bool skip_discard
,
4174 interval_set
<uint64_t> *exists
,
4175 interval_set
<uint64_t> *what
)
4179 interval_set
<uint64_t> exists_at_start
= *exists
;
4181 for (int i
=0; i
<n
; i
++) {
4182 uint64_t off
= rand() % (size
- max
+ 1);
4183 uint64_t len
= 1 + rand() % max
;
4184 if (!skip_discard
&& rand() % 4 == 0) {
4185 ASSERT_EQ((int)len
, image
.discard(off
, len
));
4186 interval_set
<uint64_t> w
;
4189 // the zeroed bit no longer exists...
4190 w
.intersection_of(*exists
);
4191 exists
->subtract(w
);
4193 // the bits we discarded are no long written...
4194 interval_set
<uint64_t> w2
= w
;
4195 w2
.intersection_of(*what
);
4198 // except for the extents that existed at the start that we overwrote.
4199 interval_set
<uint64_t> w3
;
4200 w3
.insert(off
, len
);
4201 w3
.intersection_of(exists_at_start
);
4206 bl
.append(buffer::create(len
));
4208 ASSERT_EQ((int)len
, image
.write(off
, len
, bl
));
4209 interval_set
<uint64_t> w
;
4212 exists
->union_of(w
);
4217 interval_set
<uint64_t> round_diff_interval(const interval_set
<uint64_t>& diff
,
4218 uint64_t object_size
)
4220 if (object_size
== 0) {
4224 interval_set
<uint64_t> rounded_diff
;
4225 for (interval_set
<uint64_t>::const_iterator it
= diff
.begin();
4226 it
!= diff
.end(); ++it
) {
4227 uint64_t off
= it
.get_start();
4228 uint64_t len
= it
.get_len();
4229 off
-= off
% object_size
;
4230 len
+= (object_size
- (len
% object_size
));
4231 interval_set
<uint64_t> interval
;
4232 interval
.insert(off
, len
);
4233 rounded_diff
.union_of(interval
);
4235 return rounded_diff
;
4238 TEST_F(TestLibRBD
, SnapDiff
)
4240 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
4242 rados_ioctx_t ioctx
;
4243 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4247 std::string image_name
= get_temp_image_name();
4248 uint64_t size
= 100 << 20;
4249 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), size
, &order
));
4250 ASSERT_EQ(0, rbd_open(ioctx
, image_name
.c_str(), &image
, nullptr));
4252 char test_data
[TEST_IO_SIZE
+ 1];
4253 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4254 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4256 test_data
[TEST_IO_SIZE
] = '\0';
4258 ASSERT_PASSED(write_test_data
, image
, test_data
, 0,
4259 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
4261 interval_set
<uint64_t> diff
;
4262 ASSERT_EQ(0, rbd_diff_iterate2(image
, nullptr, 0, size
, true, true,
4263 iterate_cb
, &diff
));
4264 EXPECT_EQ(1 << order
, diff
.size());
4266 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
4267 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
4270 ASSERT_EQ(0, rbd_diff_iterate2(image
, nullptr, 0, size
, true, true,
4271 iterate_cb
, &diff
));
4272 EXPECT_EQ(1 << order
, diff
.size());
4275 ASSERT_EQ(0, rbd_diff_iterate2(image
, "snap1", 0, size
, true, true,
4276 iterate_cb
, &diff
));
4277 EXPECT_EQ(0, diff
.size());
4280 ASSERT_EQ(0, rbd_diff_iterate2(image
, "snap2", 0, size
, true, true,
4281 iterate_cb
, &diff
));
4282 EXPECT_EQ(0, diff
.size());
4284 ASSERT_EQ(0, rbd_snap_remove(image
, "snap1"));
4285 ASSERT_EQ(0, rbd_snap_remove(image
, "snap2"));
4287 ASSERT_EQ(0, rbd_close(image
));
4288 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
4290 rados_ioctx_destroy(ioctx
);
4293 template <typename T
>
4294 class DiffIterateTest
: public TestLibRBD
{
4296 static const uint8_t whole_object
= T::whole_object
;
4299 template <bool _whole_object
>
4300 class DiffIterateParams
{
4302 static const uint8_t whole_object
= _whole_object
;
4305 typedef ::testing::Types
<DiffIterateParams
<false>,
4306 DiffIterateParams
<true> > DiffIterateTypes
;
4307 TYPED_TEST_SUITE(DiffIterateTest
, DiffIterateTypes
);
4309 TYPED_TEST(DiffIterateTest
, DiffIterate
)
4311 librados::IoCtx ioctx
;
4312 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4316 librbd::Image image
;
4318 std::string name
= this->get_temp_image_name();
4319 uint64_t size
= 20 << 20;
4321 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4322 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4324 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4326 uint64_t object_size
= 0;
4327 if (this->whole_object
) {
4328 object_size
= 1 << order
;
4331 interval_set
<uint64_t> exists
;
4332 interval_set
<uint64_t> one
, two
;
4333 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4334 cout
<< " wrote " << one
<< std::endl
;
4335 ASSERT_EQ(0, image
.snap_create("one"));
4336 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4338 two
= round_diff_interval(two
, object_size
);
4339 cout
<< " wrote " << two
<< std::endl
;
4341 interval_set
<uint64_t> diff
;
4342 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
4343 iterate_cb
, (void *)&diff
));
4344 cout
<< " diff was " << diff
<< std::endl
;
4345 if (!two
.subset_of(diff
)) {
4346 interval_set
<uint64_t> i
;
4347 i
.intersection_of(two
, diff
);
4348 interval_set
<uint64_t> l
= two
;
4350 cout
<< " ... two - (two*diff) = " << l
<< std::endl
;
4352 ASSERT_TRUE(two
.subset_of(diff
));
4357 struct diff_extent
{
4358 diff_extent(uint64_t _offset
, uint64_t _length
, bool _exists
,
4359 uint64_t object_size
) :
4360 offset(_offset
), length(_length
), exists(_exists
)
4362 if (object_size
!= 0) {
4363 offset
-= offset
% object_size
;
4364 length
= object_size
;
4370 bool operator==(const diff_extent
& o
) const {
4371 return offset
== o
.offset
&& length
== o
.length
&& exists
== o
.exists
;
4375 ostream
& operator<<(ostream
& o
, const diff_extent
& e
) {
4376 return o
<< '(' << e
.offset
<< '~' << e
.length
<< ' ' << (e
.exists
? "true" : "false") << ')';
4379 int vector_iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
4381 cout
<< "iterate_cb " << off
<< "~" << len
<< std::endl
;
4382 vector
<diff_extent
> *diff
= static_cast<vector
<diff_extent
> *>(arg
);
4383 diff
->push_back(diff_extent(off
, len
, exists
, 0));
4387 TYPED_TEST(DiffIterateTest
, DiffIterateDiscard
)
4389 librados::IoCtx ioctx
;
4390 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4393 librbd::Image image
;
4395 std::string name
= this->get_temp_image_name();
4396 uint64_t size
= 20 << 20;
4398 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4399 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4401 uint64_t object_size
= 0;
4402 if (this->whole_object
) {
4403 object_size
= 1 << order
;
4405 vector
<diff_extent
> extents
;
4406 ceph::bufferlist bl
;
4408 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4409 vector_iterate_cb
, (void *) &extents
));
4410 ASSERT_EQ(0u, extents
.size());
4413 memset(data
, 1, sizeof(data
));
4414 bl
.append(data
, 256);
4415 ASSERT_EQ(256, image
.write(0, 256, bl
));
4416 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4417 vector_iterate_cb
, (void *) &extents
));
4418 ASSERT_EQ(1u, extents
.size());
4419 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4422 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4425 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4426 vector_iterate_cb
, (void *) &extents
));
4427 ASSERT_EQ(0u, extents
.size());
4429 ASSERT_EQ(0, image
.snap_create("snap1"));
4430 ASSERT_EQ(256, image
.write(0, 256, bl
));
4431 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4432 vector_iterate_cb
, (void *) &extents
));
4433 ASSERT_EQ(1u, extents
.size());
4434 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4435 ASSERT_EQ(0, image
.snap_create("snap2"));
4437 ASSERT_EQ(obj_ofs
, image
.discard(0, obj_ofs
));
4440 ASSERT_EQ(0, image
.snap_set("snap2"));
4441 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4442 vector_iterate_cb
, (void *) &extents
));
4443 ASSERT_EQ(1u, extents
.size());
4444 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4446 ASSERT_EQ(0, image
.snap_set(NULL
));
4447 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4448 ASSERT_EQ(0, image
.snap_create("snap3"));
4449 ASSERT_EQ(0, image
.snap_set("snap3"));
4452 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4453 vector_iterate_cb
, (void *) &extents
));
4454 ASSERT_EQ(1u, extents
.size());
4455 ASSERT_EQ(diff_extent(0, 256, false, object_size
), extents
[0]);
4456 ASSERT_PASSED(this->validate_object_map
, image
);
4459 TYPED_TEST(DiffIterateTest
, DiffIterateStress
)
4461 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)this->_rados
.cct()));
4462 librados::IoCtx ioctx
;
4463 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4466 librbd::Image image
;
4468 std::string name
= this->get_temp_image_name();
4469 uint64_t size
= 400 << 20;
4471 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4472 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4474 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4476 uint64_t object_size
= 0;
4477 if (this->whole_object
) {
4478 object_size
= 1 << order
;
4481 interval_set
<uint64_t> curexists
;
4482 vector
<interval_set
<uint64_t> > wrote
;
4483 vector
<interval_set
<uint64_t> > exists
;
4484 vector
<string
> snap
;
4486 for (int i
=0; i
<n
; i
++) {
4487 interval_set
<uint64_t> w
;
4488 scribble(image
, 10, 8192000, skip_discard
, &curexists
, &w
);
4489 cout
<< " i=" << i
<< " exists " << curexists
<< " wrote " << w
<< std::endl
;
4490 string s
= "snap" + stringify(i
);
4491 ASSERT_EQ(0, image
.snap_create(s
.c_str()));
4493 exists
.push_back(curexists
);
4497 for (int h
=0; h
<n
-1; h
++) {
4498 for (int i
=0; i
<n
-h
-1; i
++) {
4499 for (int j
=(h
==0 ? i
+1 : n
-1); j
<n
; j
++) {
4500 interval_set
<uint64_t> diff
, actual
, uex
;
4501 for (int k
=i
+1; k
<=j
; k
++)
4502 diff
.union_of(wrote
[k
]);
4503 cout
<< "from " << i
<< " to "
4504 << (h
!= 0 ? string("HEAD") : stringify(j
)) << " diff "
4505 << round_diff_interval(diff
, object_size
) << std::endl
;
4507 // limit to extents that exists both at the beginning and at the end
4508 uex
.union_of(exists
[i
], exists
[j
]);
4509 diff
.intersection_of(uex
);
4510 diff
= round_diff_interval(diff
, object_size
);
4511 cout
<< " limited diff " << diff
<< std::endl
;
4513 ASSERT_EQ(0, image
.snap_set(h
==0 ? snap
[j
].c_str() : NULL
));
4514 ASSERT_EQ(0, image
.diff_iterate2(snap
[i
].c_str(), 0, size
, true,
4515 this->whole_object
, iterate_cb
,
4517 cout
<< " actual was " << actual
<< std::endl
;
4518 if (!diff
.subset_of(actual
)) {
4519 interval_set
<uint64_t> i
;
4520 i
.intersection_of(diff
, actual
);
4521 interval_set
<uint64_t> l
= diff
;
4523 cout
<< " ... diff - (actual*diff) = " << l
<< std::endl
;
4525 ASSERT_TRUE(diff
.subset_of(actual
));
4528 ASSERT_EQ(0, image
.snap_set(NULL
));
4529 ASSERT_EQ(0, image
.snap_remove(snap
[n
-h
-1].c_str()));
4532 ASSERT_PASSED(this->validate_object_map
, image
);
4535 TYPED_TEST(DiffIterateTest
, DiffIterateRegression6926
)
4537 librados::IoCtx ioctx
;
4538 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4541 librbd::Image image
;
4543 std::string name
= this->get_temp_image_name();
4544 uint64_t size
= 20 << 20;
4546 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4547 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4549 uint64_t object_size
= 0;
4550 if (this->whole_object
) {
4551 object_size
= 1 << order
;
4553 vector
<diff_extent
> extents
;
4554 ceph::bufferlist bl
;
4556 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4557 vector_iterate_cb
, (void *) &extents
));
4558 ASSERT_EQ(0u, extents
.size());
4560 ASSERT_EQ(0, image
.snap_create("snap1"));
4562 memset(data
, 1, sizeof(data
));
4563 bl
.append(data
, 256);
4564 ASSERT_EQ(256, image
.write(0, 256, bl
));
4567 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4568 vector_iterate_cb
, (void *) &extents
));
4569 ASSERT_EQ(1u, extents
.size());
4570 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4572 ASSERT_EQ(0, image
.snap_set("snap1"));
4574 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4575 vector_iterate_cb
, (void *) &extents
));
4576 ASSERT_EQ(static_cast<size_t>(0), extents
.size());
4579 TYPED_TEST(DiffIterateTest
, DiffIterateParent
)
4581 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4583 librados::IoCtx ioctx
;
4584 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4588 librbd::Image image
;
4590 std::string name
= this->get_temp_image_name();
4591 ssize_t size
= 20 << 20;
4593 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4594 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4597 ASSERT_EQ(0, image
.features(&features
));
4598 uint64_t object_size
= 0;
4599 if (this->whole_object
) {
4600 object_size
= 1 << order
;
4603 ceph::bufferlist bl
;
4604 bl
.append(std::string(size
, '1'));
4605 ASSERT_EQ(size
, image
.write(0, size
, bl
));
4606 ASSERT_EQ(0, image
.snap_create("snap"));
4607 ASSERT_EQ(0, image
.snap_protect("snap"));
4609 std::string clone_name
= this->get_temp_image_name();
4610 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
,
4611 clone_name
.c_str(), features
, &order
));
4612 librbd::Image clone
;
4613 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
4615 std::vector
<diff_extent
> extents
;
4616 ASSERT_EQ(0, clone
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4617 vector_iterate_cb
, &extents
));
4618 ASSERT_EQ(5u, extents
.size());
4619 ASSERT_EQ(diff_extent(0, 4194304, true, object_size
), extents
[0]);
4620 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size
), extents
[1]);
4621 ASSERT_EQ(diff_extent(8388608, 4194304, true, object_size
), extents
[2]);
4622 ASSERT_EQ(diff_extent(12582912, 4194304, true, object_size
), extents
[3]);
4623 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size
), extents
[4]);
4626 ASSERT_EQ(0, clone
.resize(size
/ 2));
4627 ASSERT_EQ(0, clone
.resize(size
));
4628 ASSERT_EQ(1, clone
.write(size
- 1, 1, bl
));
4630 ASSERT_EQ(0, clone
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4631 vector_iterate_cb
, &extents
));
4632 ASSERT_EQ(4u, extents
.size());
4633 ASSERT_EQ(diff_extent(0, 4194304, true, object_size
), extents
[0]);
4634 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size
), extents
[1]);
4635 ASSERT_EQ(diff_extent(8388608, 2097152, true, object_size
), extents
[2]);
4636 // hole (parent overlap = 10M) followed by copyup'ed object
4637 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size
), extents
[3]);
4639 ASSERT_PASSED(this->validate_object_map
, image
);
4640 ASSERT_PASSED(this->validate_object_map
, clone
);
4646 TYPED_TEST(DiffIterateTest
, DiffIterateIgnoreParent
)
4648 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4650 librados::IoCtx ioctx
;
4651 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4654 librbd::Image image
;
4655 std::string name
= this->get_temp_image_name();
4656 uint64_t size
= 20 << 20;
4659 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4660 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4662 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4665 ASSERT_EQ(0, image
.features(&features
));
4666 uint64_t object_size
= 0;
4667 if (this->whole_object
) {
4668 object_size
= 1 << order
;
4672 bl
.append(buffer::create(size
));
4674 interval_set
<uint64_t> one
;
4675 one
.insert(0, size
);
4676 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
4677 ASSERT_EQ(0, image
.snap_create("one"));
4678 ASSERT_EQ(0, image
.snap_protect("one"));
4680 std::string clone_name
= this->get_temp_image_name();
4681 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
4683 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4685 interval_set
<uint64_t> exists
;
4686 interval_set
<uint64_t> two
;
4687 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4688 two
= round_diff_interval(two
, object_size
);
4689 cout
<< " wrote " << two
<< " to clone" << std::endl
;
4691 interval_set
<uint64_t> diff
;
4692 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, false, this->whole_object
,
4693 iterate_cb
, (void *)&diff
));
4694 cout
<< " diff was " << diff
<< std::endl
;
4695 if (!this->whole_object
) {
4696 ASSERT_FALSE(one
.subset_of(diff
));
4698 ASSERT_TRUE(two
.subset_of(diff
));
4701 TYPED_TEST(DiffIterateTest
, DiffIterateCallbackError
)
4703 librados::IoCtx ioctx
;
4704 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4708 librbd::Image image
;
4710 std::string name
= this->get_temp_image_name();
4711 uint64_t size
= 20 << 20;
4713 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4714 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4716 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4718 interval_set
<uint64_t> exists
;
4719 interval_set
<uint64_t> one
;
4720 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4721 cout
<< " wrote " << one
<< std::endl
;
4723 interval_set
<uint64_t> diff
;
4724 ASSERT_EQ(-EINVAL
, image
.diff_iterate2(NULL
, 0, size
, true,
4726 iterate_error_cb
, NULL
));
4731 TYPED_TEST(DiffIterateTest
, DiffIterateParentDiscard
)
4733 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4735 librados::IoCtx ioctx
;
4736 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4739 librbd::Image image
;
4740 std::string name
= this->get_temp_image_name();
4741 uint64_t size
= 20 << 20;
4744 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4745 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4747 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4750 ASSERT_EQ(0, image
.features(&features
));
4751 uint64_t object_size
= 0;
4752 if (this->whole_object
) {
4753 object_size
= 1 << order
;
4756 interval_set
<uint64_t> exists
;
4757 interval_set
<uint64_t> one
;
4758 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4759 ASSERT_EQ(0, image
.snap_create("one"));
4761 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4762 ASSERT_EQ(0, image
.snap_create("two"));
4763 ASSERT_EQ(0, image
.snap_protect("two"));
4767 std::string clone_name
= this->get_temp_image_name();
4768 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "two", ioctx
,
4769 clone_name
.c_str(), features
, &order
));
4770 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4772 interval_set
<uint64_t> two
;
4773 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4774 two
= round_diff_interval(two
, object_size
);
4776 interval_set
<uint64_t> diff
;
4777 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4778 iterate_cb
, (void *)&diff
));
4779 ASSERT_TRUE(two
.subset_of(diff
));
4782 TYPED_TEST(DiffIterateTest
, DiffIterateUnalignedSmall
)
4784 librados::IoCtx ioctx
;
4785 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4789 librbd::Image image
;
4791 std::string name
= this->get_temp_image_name();
4792 ssize_t size
= 10 << 20;
4794 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4795 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4797 ceph::bufferlist bl
;
4798 bl
.append(std::string(size
, '1'));
4799 ASSERT_EQ(size
, image
.write(0, size
, bl
));
4801 std::vector
<diff_extent
> extents
;
4802 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 5000005, 1234, true,
4803 this->whole_object
, vector_iterate_cb
,
4805 ASSERT_EQ(1u, extents
.size());
4806 ASSERT_EQ(diff_extent(5000005, 1234, true, 0), extents
[0]);
4808 ASSERT_PASSED(this->validate_object_map
, image
);
4814 TYPED_TEST(DiffIterateTest
, DiffIterateUnaligned
)
4816 librados::IoCtx ioctx
;
4817 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4821 librbd::Image image
;
4823 std::string name
= this->get_temp_image_name();
4824 ssize_t size
= 20 << 20;
4826 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4827 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4829 ceph::bufferlist bl
;
4830 bl
.append(std::string(size
, '1'));
4831 ASSERT_EQ(size
, image
.write(0, size
, bl
));
4833 std::vector
<diff_extent
> extents
;
4834 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 8376263, 4260970, true,
4835 this->whole_object
, vector_iterate_cb
,
4837 ASSERT_EQ(3u, extents
.size());
4838 ASSERT_EQ(diff_extent(8376263, 12345, true, 0), extents
[0]);
4839 ASSERT_EQ(diff_extent(8388608, 4194304, true, 0), extents
[1]);
4840 ASSERT_EQ(diff_extent(12582912, 54321, true, 0), extents
[2]);
4842 ASSERT_PASSED(this->validate_object_map
, image
);
4848 TYPED_TEST(DiffIterateTest
, DiffIterateStriping
)
4850 REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2
);
4852 librados::IoCtx ioctx
;
4853 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4857 ASSERT_EQ(0, get_features(&old_format
, &features
));
4858 ASSERT_FALSE(old_format
);
4862 librbd::Image image
;
4864 std::string name
= this->get_temp_image_name();
4865 ssize_t size
= 24 << 20;
4867 ASSERT_EQ(0, rbd
.create3(ioctx
, name
.c_str(), size
, features
, &order
,
4869 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4871 ceph::bufferlist bl
;
4872 bl
.append(std::string(size
, '1'));
4873 ASSERT_EQ(size
, image
.write(0, size
, bl
));
4875 std::vector
<diff_extent
> extents
;
4876 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4877 vector_iterate_cb
, &extents
));
4878 ASSERT_EQ(2u, extents
.size());
4879 ASSERT_EQ(diff_extent(0, 12 << 20, true, 0), extents
[0]);
4880 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents
[1]);
4883 ASSERT_EQ(0, image
.snap_create("one"));
4884 ASSERT_EQ(size
, image
.discard(0, size
));
4886 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
4887 vector_iterate_cb
, &extents
));
4888 ASSERT_EQ(2u, extents
.size());
4889 ASSERT_EQ(diff_extent(0, 12 << 20, false, 0), extents
[0]);
4890 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, false, 0), extents
[1]);
4893 ASSERT_EQ(1 << 20, image
.write(0, 1 << 20, bl
));
4894 ASSERT_EQ(2 << 20, image
.write(2 << 20, 2 << 20, bl
));
4895 ASSERT_EQ(2 << 20, image
.write(5 << 20, 2 << 20, bl
));
4896 ASSERT_EQ(2 << 20, image
.write(8 << 20, 2 << 20, bl
));
4897 ASSERT_EQ(13 << 20, image
.write(11 << 20, 13 << 20, bl
));
4899 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
4900 vector_iterate_cb
, &extents
));
4901 ASSERT_EQ(10u, extents
.size());
4902 ASSERT_EQ(diff_extent(0, 1 << 20, true, 0), extents
[0]);
4903 ASSERT_EQ(diff_extent(1 << 20, 1 << 20, false, 0), extents
[1]);
4904 ASSERT_EQ(diff_extent(2 << 20, 2 << 20, true, 0), extents
[2]);
4905 ASSERT_EQ(diff_extent(4 << 20, 1 << 20, false, 0), extents
[3]);
4906 ASSERT_EQ(diff_extent(5 << 20, 2 << 20, true, 0), extents
[4]);
4907 ASSERT_EQ(diff_extent(7 << 20, 1 << 20, false, 0), extents
[5]);
4908 ASSERT_EQ(diff_extent(8 << 20, 2 << 20, true, 0), extents
[6]);
4909 ASSERT_EQ(diff_extent(10 << 20, 1 << 20, false, 0), extents
[7]);
4910 ASSERT_EQ(diff_extent(11 << 20, 1 << 20, true, 0), extents
[8]);
4911 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents
[9]);
4913 ASSERT_PASSED(this->validate_object_map
, image
);
4919 TEST_F(TestLibRBD
, ZeroLengthWrite
)
4921 rados_ioctx_t ioctx
;
4922 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4926 std::string name
= get_temp_image_name();
4927 uint64_t size
= 2 << 20;
4929 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4930 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4933 ASSERT_EQ(0, rbd_write(image
, 0, 0, NULL
));
4934 ASSERT_EQ(1, rbd_read(image
, 0, 1, read_data
));
4935 ASSERT_EQ('\0', read_data
[0]);
4937 ASSERT_PASSED(validate_object_map
, image
);
4938 ASSERT_EQ(0, rbd_close(image
));
4940 rados_ioctx_destroy(ioctx
);
4944 TEST_F(TestLibRBD
, ZeroLengthDiscard
)
4946 rados_ioctx_t ioctx
;
4947 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4951 std::string name
= get_temp_image_name();
4952 uint64_t size
= 2 << 20;
4954 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4955 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4957 const char data
[] = "blah";
4958 char read_data
[sizeof(data
)];
4959 ASSERT_EQ((int)strlen(data
), rbd_write(image
, 0, strlen(data
), data
));
4960 ASSERT_EQ(0, rbd_discard(image
, 0, 0));
4961 ASSERT_EQ((int)strlen(data
), rbd_read(image
, 0, strlen(data
), read_data
));
4962 ASSERT_EQ(0, memcmp(data
, read_data
, strlen(data
)));
4964 ASSERT_PASSED(validate_object_map
, image
);
4965 ASSERT_EQ(0, rbd_close(image
));
4967 rados_ioctx_destroy(ioctx
);
4970 TEST_F(TestLibRBD
, ZeroLengthRead
)
4972 rados_ioctx_t ioctx
;
4973 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4977 std::string name
= get_temp_image_name();
4978 uint64_t size
= 2 << 20;
4980 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4981 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4984 ASSERT_EQ(0, rbd_read(image
, 0, 0, read_data
));
4986 ASSERT_EQ(0, rbd_close(image
));
4988 rados_ioctx_destroy(ioctx
);
4991 TEST_F(TestLibRBD
, LargeCacheRead
)
4993 std::string config_value
;
4994 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", config_value
));
4995 if (config_value
== "false") {
4996 std::cout
<< "SKIPPING due to disabled cache" << std::endl
;
5000 rados_ioctx_t ioctx
;
5001 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5003 uint32_t new_cache_size
= 1 << 20;
5004 std::string orig_cache_size
;
5005 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", orig_cache_size
));
5006 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size",
5007 stringify(new_cache_size
).c_str()));
5008 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", config_value
));
5009 ASSERT_EQ(stringify(new_cache_size
), config_value
);
5010 BOOST_SCOPE_EXIT( (orig_cache_size
) ) {
5011 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size", orig_cache_size
.c_str()));
5012 } BOOST_SCOPE_EXIT_END
;
5016 std::string name
= get_temp_image_name();
5017 uint64_t size
= 1 << order
;
5019 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5020 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5022 std::string
buffer(1 << order
, '1');
5024 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
5025 rbd_write(image
, 0, buffer
.size(), buffer
.c_str()));
5027 ASSERT_EQ(0, rbd_invalidate_cache(image
));
5029 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
5030 rbd_read(image
, 0, buffer
.size(), &buffer
[0]));
5032 ASSERT_EQ(0, rbd_close(image
));
5034 rados_ioctx_destroy(ioctx
);
5037 TEST_F(TestLibRBD
, TestPendingAio
)
5039 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5041 rados_ioctx_t ioctx
;
5042 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5049 ASSERT_EQ(0, get_features(&old_format
, &features
));
5050 ASSERT_FALSE(old_format
);
5052 std::string name
= get_temp_image_name();
5054 uint64_t size
= 4 << 20;
5055 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
5057 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5059 ASSERT_EQ(0, rbd_invalidate_cache(image
));
5061 char test_data
[TEST_IO_SIZE
];
5062 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
5063 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
5066 size_t num_aios
= 256;
5067 rbd_completion_t comps
[num_aios
];
5068 for (size_t i
= 0; i
< num_aios
; ++i
) {
5069 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
5070 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
5071 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
5074 for (size_t i
= 0; i
< num_aios
; ++i
) {
5075 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps
[i
]));
5076 rbd_aio_release(comps
[i
]);
5078 ASSERT_EQ(0, rbd_invalidate_cache(image
));
5080 for (size_t i
= 0; i
< num_aios
; ++i
) {
5081 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
5082 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
5083 ASSERT_LE(0, rbd_aio_read(image
, offset
, TEST_IO_SIZE
, test_data
,
5087 ASSERT_PASSED(validate_object_map
, image
);
5088 ASSERT_EQ(0, rbd_close(image
));
5089 for (size_t i
= 0; i
< num_aios
; ++i
) {
5090 ASSERT_EQ(1, rbd_aio_is_complete(comps
[i
]));
5091 rbd_aio_release(comps
[i
]);
5094 rados_ioctx_destroy(ioctx
);
5097 void compare_and_write_copyup(librados::IoCtx
&ioctx
, bool deep_copyup
,
5101 std::string parent_name
= TestLibRBD::get_temp_image_name();
5102 uint64_t size
= 2 << 20;
5104 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5106 librbd::Image parent_image
;
5107 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5110 bl
.append(std::string(4096, '1'));
5111 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
5113 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5114 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5117 ASSERT_EQ(0, parent_image
.features(&features
));
5119 std::string clone_name
= TestLibRBD::get_temp_image_name();
5120 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5121 clone_name
.c_str(), features
, &order
));
5123 librbd::Image clone_image
;
5124 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
5126 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
5130 cmp_bl
.append(std::string(96, '1'));
5131 bufferlist write_bl
;
5132 write_bl
.append(std::string(512, '2'));
5133 uint64_t mismatch_off
;
5134 ASSERT_EQ((ssize_t
)write_bl
.length(),
5135 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
5136 write_bl
, &mismatch_off
, 0));
5139 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
5141 bufferlist expected_bl
;
5142 expected_bl
.append(std::string(512, '1'));
5143 expected_bl
.append(std::string(512, '2'));
5144 expected_bl
.append(std::string(3072, '1'));
5145 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
5149 TEST_F(TestLibRBD
, CompareAndWriteCopyup
)
5151 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5153 librados::IoCtx ioctx
;
5154 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5156 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, false);
5157 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, true);
5160 void compare_and_write_copyup_mismatch(librados::IoCtx
&ioctx
,
5161 bool deep_copyup
, bool *passed
)
5164 std::string parent_name
= TestLibRBD::get_temp_image_name();
5165 uint64_t size
= 2 << 20;
5167 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5169 librbd::Image parent_image
;
5170 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5173 bl
.append(std::string(4096, '1'));
5174 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
5176 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5177 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5180 ASSERT_EQ(0, parent_image
.features(&features
));
5182 std::string clone_name
= TestLibRBD::get_temp_image_name();
5183 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5184 clone_name
.c_str(), features
, &order
));
5186 librbd::Image clone_image
;
5187 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
5189 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
5193 cmp_bl
.append(std::string(48, '1'));
5194 cmp_bl
.append(std::string(48, '3'));
5195 bufferlist write_bl
;
5196 write_bl
.append(std::string(512, '2'));
5197 uint64_t mismatch_off
;
5199 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
5200 write_bl
, &mismatch_off
, 0));
5201 ASSERT_EQ(48U, mismatch_off
);
5204 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
5206 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5210 TEST_F(TestLibRBD
, CompareAndWriteCopyupMismatch
)
5212 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5214 librados::IoCtx ioctx
;
5215 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5217 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, false);
5218 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, true);
5221 TEST_F(TestLibRBD
, Flatten
)
5223 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5225 librados::IoCtx ioctx
;
5226 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5229 std::string parent_name
= get_temp_image_name();
5230 uint64_t size
= 2 << 20;
5232 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5234 librbd::Image parent_image
;
5235 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5238 bl
.append(std::string(4096, '1'));
5239 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
5241 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5242 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5245 ASSERT_EQ(0, parent_image
.features(&features
));
5247 std::string clone_name
= get_temp_image_name();
5248 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5249 clone_name
.c_str(), features
, &order
));
5251 librbd::Image clone_image
;
5252 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
5253 ASSERT_EQ(0, clone_image
.flatten());
5255 librbd::RBD::AioCompletion
*read_comp
=
5256 new librbd::RBD::AioCompletion(NULL
, NULL
);
5258 clone_image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
5259 ASSERT_EQ(0, read_comp
->wait_for_complete());
5260 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
5261 read_comp
->release();
5262 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5264 ASSERT_PASSED(validate_object_map
, clone_image
);
5267 TEST_F(TestLibRBD
, Sparsify
)
5269 rados_ioctx_t ioctx
;
5270 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
5271 BOOST_SCOPE_EXIT_ALL(&ioctx
) {
5272 rados_ioctx_destroy(ioctx
);
5275 const size_t CHUNK_SIZE
= 4096 * 2;
5278 std::string name
= get_temp_image_name();
5279 uint64_t size
= CHUNK_SIZE
* 1024;
5281 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5282 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5283 BOOST_SCOPE_EXIT_ALL(&image
) {
5287 char test_data
[4 * CHUNK_SIZE
+ 1];
5288 for (size_t i
= 0; i
< 4 ; ++i
) {
5289 for (size_t j
= 0; j
< CHUNK_SIZE
; j
++) {
5291 test_data
[i
* CHUNK_SIZE
+ j
] = (char)(rand() % (126 - 33) + 33);
5293 test_data
[i
* CHUNK_SIZE
+ j
] = '\0';
5297 test_data
[4 * CHUNK_SIZE
] = '\0';
5299 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
5300 ASSERT_EQ(0, rbd_flush(image
));
5302 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 16));
5303 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 1 << (order
+ 1)));
5304 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 4096 + 1));
5305 ASSERT_EQ(0, rbd_sparsify(image
, 4096));
5307 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
5310 TEST_F(TestLibRBD
, SparsifyPP
)
5312 librados::IoCtx ioctx
;
5313 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5316 std::string name
= get_temp_image_name();
5317 uint64_t size
= 12 * 1024 * 1024;
5319 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5321 librbd::Image image
;
5322 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
5325 bl
.append(std::string(4096, '\0'));
5326 bl
.append(std::string(4096, '1'));
5327 bl
.append(std::string(4096, '\0'));
5328 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
5329 ASSERT_EQ(0, image
.flush());
5331 ASSERT_EQ(-EINVAL
, image
.sparsify(16));
5332 ASSERT_EQ(-EINVAL
, image
.sparsify(1 << (order
+ 1)));
5333 ASSERT_EQ(-EINVAL
, image
.sparsify(4096 + 1));
5334 ASSERT_EQ(0, image
.sparsify(4096));
5337 ASSERT_EQ((ssize_t
)bl
.length(), image
.read(0, bl
.length(), read_bl
));
5338 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5340 ASSERT_PASSED(validate_object_map
, image
);
5343 TEST_F(TestLibRBD
, SnapshotLimit
)
5345 rados_ioctx_t ioctx
;
5346 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5350 std::string name
= get_temp_image_name();
5351 uint64_t size
= 2 << 20;
5354 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5355 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5357 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
5358 ASSERT_EQ(UINT64_MAX
, limit
);
5359 ASSERT_EQ(0, rbd_snap_set_limit(image
, 2));
5360 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
5361 ASSERT_EQ(2U, limit
);
5363 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
5364 ASSERT_EQ(-ERANGE
, rbd_snap_set_limit(image
, 0));
5365 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
5366 ASSERT_EQ(-EDQUOT
, rbd_snap_create(image
, "snap3"));
5367 ASSERT_EQ(0, rbd_snap_set_limit(image
, UINT64_MAX
));
5368 ASSERT_EQ(0, rbd_snap_create(image
, "snap3"));
5369 ASSERT_EQ(0, rbd_close(image
));
5371 rados_ioctx_destroy(ioctx
);
5375 TEST_F(TestLibRBD
, SnapshotLimitPP
)
5377 librados::IoCtx ioctx
;
5378 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5382 librbd::Image image
;
5383 std::string name
= get_temp_image_name();
5384 uint64_t size
= 2 << 20;
5388 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5389 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5391 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
5392 ASSERT_EQ(UINT64_MAX
, limit
);
5393 ASSERT_EQ(0, image
.snap_set_limit(2));
5394 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
5395 ASSERT_EQ(2U, limit
);
5397 ASSERT_EQ(0, image
.snap_create("snap1"));
5398 ASSERT_EQ(-ERANGE
, image
.snap_set_limit(0));
5399 ASSERT_EQ(0, image
.snap_create("snap2"));
5400 ASSERT_EQ(-EDQUOT
, image
.snap_create("snap3"));
5401 ASSERT_EQ(0, image
.snap_set_limit(UINT64_MAX
));
5402 ASSERT_EQ(0, image
.snap_create("snap3"));
5408 TEST_F(TestLibRBD
, RebuildObjectMapViaLockOwner
)
5410 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_OBJECT_MAP
);
5412 librados::IoCtx ioctx
;
5413 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5416 std::string name
= get_temp_image_name();
5417 uint64_t size
= 2 << 20;
5419 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5421 std::string object_map_oid
;
5423 librbd::Image image
;
5424 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5426 std::string image_id
;
5427 ASSERT_EQ(0, get_image_id(image
, &image_id
));
5428 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
5431 // corrupt the object map
5434 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
5436 librbd::Image image1
;
5437 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5441 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5442 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5443 ASSERT_TRUE(lock_owner
);
5446 ASSERT_EQ(0, image1
.get_flags(&flags
));
5447 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
5449 librbd::Image image2
;
5450 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5451 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5452 ASSERT_FALSE(lock_owner
);
5454 PrintProgress prog_ctx
;
5455 ASSERT_EQ(0, image2
.rebuild_object_map(prog_ctx
));
5456 ASSERT_PASSED(validate_object_map
, image1
);
5457 ASSERT_PASSED(validate_object_map
, image2
);
5460 TEST_F(TestLibRBD
, RenameViaLockOwner
)
5462 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5464 librados::IoCtx ioctx
;
5465 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5468 std::string name
= get_temp_image_name();
5469 uint64_t size
= 2 << 20;
5471 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5473 librbd::Image image1
;
5474 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5477 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5478 ASSERT_FALSE(lock_owner
);
5480 std::string new_name
= get_temp_image_name();
5481 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
5482 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5483 ASSERT_FALSE(lock_owner
);
5486 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5487 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5488 ASSERT_TRUE(lock_owner
);
5491 new_name
= get_temp_image_name();
5492 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
5493 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5494 ASSERT_TRUE(lock_owner
);
5496 librbd::Image image2
;
5497 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, new_name
.c_str(), NULL
));
5500 TEST_F(TestLibRBD
, SnapCreateViaLockOwner
)
5502 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5504 librados::IoCtx ioctx
;
5505 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5508 std::string name
= get_temp_image_name();
5509 uint64_t size
= 2 << 20;
5511 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5513 librbd::Image image1
;
5514 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5516 // switch to writeback cache
5517 ASSERT_EQ(0, image1
.flush());
5520 bl
.append(std::string(4096, '1'));
5521 ASSERT_EQ((ssize_t
)bl
.length(), image1
.write(0, bl
.length(), bl
));
5524 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5525 ASSERT_TRUE(lock_owner
);
5527 librbd::Image image2
;
5528 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5530 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5531 ASSERT_FALSE(lock_owner
);
5533 ASSERT_EQ(0, image2
.snap_create("snap1"));
5535 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5536 ASSERT_TRUE(exists
);
5537 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
5538 ASSERT_TRUE(exists
);
5540 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5541 ASSERT_TRUE(lock_owner
);
5544 TEST_F(TestLibRBD
, SnapRemoveViaLockOwner
)
5546 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
5548 librados::IoCtx ioctx
;
5549 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5552 std::string name
= get_temp_image_name();
5553 uint64_t size
= 2 << 20;
5555 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5557 librbd::Image image1
;
5558 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5561 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5562 ASSERT_EQ(0, image1
.snap_create("snap1"));
5565 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5566 ASSERT_TRUE(lock_owner
);
5568 librbd::Image image2
;
5569 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5571 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5572 ASSERT_FALSE(lock_owner
);
5574 ASSERT_EQ(0, image2
.snap_remove("snap1"));
5576 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5577 ASSERT_FALSE(exists
);
5578 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
5579 ASSERT_FALSE(exists
);
5581 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5582 ASSERT_TRUE(lock_owner
);
5585 TEST_F(TestLibRBD
, UpdateFeaturesViaLockOwner
) {
5587 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5589 librados::IoCtx ioctx
;
5590 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5592 std::string name
= get_temp_image_name();
5593 uint64_t size
= 2 << 20;
5596 //creates full with rbd default features
5597 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5600 librbd::Image image1
;
5601 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5603 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5604 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5605 ASSERT_TRUE(lock_owner
);
5607 librbd::Image image2
;
5608 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5609 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5610 ASSERT_FALSE(lock_owner
);
5612 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5613 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5614 ASSERT_FALSE(lock_owner
);
5616 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5617 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5618 ASSERT_FALSE(lock_owner
);
5622 TEST_F(TestLibRBD
, EnableJournalingViaLockOwner
)
5624 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
5626 librados::IoCtx ioctx
;
5627 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5630 std::string name
= get_temp_image_name();
5631 uint64_t size
= 2 << 20;
5633 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5635 librbd::Image image1
;
5636 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5639 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5642 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5643 ASSERT_TRUE(lock_owner
);
5645 librbd::Image image2
;
5646 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5648 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, false));
5650 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5651 ASSERT_TRUE(lock_owner
);
5652 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5653 ASSERT_FALSE(lock_owner
);
5655 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, true));
5657 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5658 ASSERT_FALSE(lock_owner
);
5659 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5660 ASSERT_TRUE(lock_owner
);
5663 TEST_F(TestLibRBD
, SnapRemove2
)
5665 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5667 librados::IoCtx ioctx
;
5668 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5671 std::string name
= get_temp_image_name();
5672 uint64_t size
= 2 << 20;
5674 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5676 librbd::Image image1
;
5677 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5680 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5681 ASSERT_EQ(0, image1
.snap_create("snap1"));
5683 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5684 ASSERT_TRUE(exists
);
5685 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5687 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5688 ASSERT_TRUE(is_protected
);
5691 ASSERT_EQ(0, image1
.features(&features
));
5693 std::string child_name
= get_temp_image_name();
5694 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5695 child_name
.c_str(), features
, &order
));
5697 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5698 ASSERT_TRUE(exists
);
5699 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5700 ASSERT_TRUE(is_protected
);
5702 ASSERT_EQ(-EBUSY
, image1
.snap_remove("snap1"));
5704 ASSERT_EQ(0, image1
.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE
, pp
));
5705 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5706 ASSERT_FALSE(exists
);
5709 TEST_F(TestLibRBD
, SnapRenameViaLockOwner
)
5711 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5713 librados::IoCtx ioctx
;
5714 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5717 std::string name
= get_temp_image_name();
5718 uint64_t size
= 2 << 20;
5720 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5722 librbd::Image image1
;
5723 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5726 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5727 ASSERT_EQ(0, image1
.snap_create("snap1"));
5730 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5731 ASSERT_TRUE(lock_owner
);
5733 librbd::Image image2
;
5734 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5736 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5737 ASSERT_FALSE(lock_owner
);
5739 ASSERT_EQ(0, image2
.snap_rename("snap1", "snap1-rename"));
5741 ASSERT_EQ(0, image1
.snap_exists2("snap1-rename", &exists
));
5742 ASSERT_TRUE(exists
);
5743 ASSERT_EQ(0, image2
.snap_exists2("snap1-rename", &exists
));
5744 ASSERT_TRUE(exists
);
5746 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5747 ASSERT_TRUE(lock_owner
);
5750 TEST_F(TestLibRBD
, SnapProtectViaLockOwner
)
5752 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5754 librados::IoCtx ioctx
;
5755 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5758 std::string name
= get_temp_image_name();
5759 uint64_t size
= 2 << 20;
5761 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5763 librbd::Image image1
;
5764 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5767 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5770 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5771 ASSERT_TRUE(lock_owner
);
5772 ASSERT_EQ(0, image1
.snap_create("snap1"));
5774 librbd::Image image2
;
5775 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5777 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5778 ASSERT_FALSE(lock_owner
);
5780 ASSERT_EQ(0, image2
.snap_protect("snap1"));
5782 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5783 ASSERT_TRUE(is_protected
);
5784 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5785 ASSERT_TRUE(is_protected
);
5787 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5788 ASSERT_TRUE(lock_owner
);
5791 TEST_F(TestLibRBD
, SnapUnprotectViaLockOwner
)
5793 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5795 librados::IoCtx ioctx
;
5796 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5799 std::string name
= get_temp_image_name();
5800 uint64_t size
= 2 << 20;
5802 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5804 librbd::Image image1
;
5805 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5808 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5811 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5812 ASSERT_TRUE(lock_owner
);
5813 ASSERT_EQ(0, image1
.snap_create("snap1"));
5814 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5816 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5817 ASSERT_TRUE(is_protected
);
5819 librbd::Image image2
;
5820 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5822 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5823 ASSERT_FALSE(lock_owner
);
5825 ASSERT_EQ(0, image2
.snap_unprotect("snap1"));
5826 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5827 ASSERT_FALSE(is_protected
);
5828 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5829 ASSERT_FALSE(is_protected
);
5831 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5832 ASSERT_TRUE(lock_owner
);
5835 TEST_F(TestLibRBD
, FlattenViaLockOwner
)
5837 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5839 librados::IoCtx ioctx
;
5840 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5843 std::string parent_name
= get_temp_image_name();
5844 uint64_t size
= 2 << 20;
5846 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5848 librbd::Image parent_image
;
5849 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5850 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5851 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5854 ASSERT_EQ(0, parent_image
.features(&features
));
5856 std::string name
= get_temp_image_name();
5857 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5858 name
.c_str(), features
, &order
));
5860 librbd::Image image1
;
5861 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5864 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5867 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5868 ASSERT_TRUE(lock_owner
);
5870 librbd::Image image2
;
5871 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5873 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5874 ASSERT_FALSE(lock_owner
);
5876 ASSERT_EQ(0, image2
.flatten());
5878 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5879 ASSERT_TRUE(lock_owner
);
5880 ASSERT_PASSED(validate_object_map
, image1
);
5883 TEST_F(TestLibRBD
, ResizeViaLockOwner
)
5885 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5887 librados::IoCtx ioctx
;
5888 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5891 std::string name
= get_temp_image_name();
5892 uint64_t size
= 2 << 20;
5894 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5896 librbd::Image image1
;
5897 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5900 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5903 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5904 ASSERT_TRUE(lock_owner
);
5906 librbd::Image image2
;
5907 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5909 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5910 ASSERT_FALSE(lock_owner
);
5912 ASSERT_EQ(0, image2
.resize(0));
5914 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5915 ASSERT_TRUE(lock_owner
);
5916 ASSERT_PASSED(validate_object_map
, image1
);
5919 TEST_F(TestLibRBD
, SparsifyViaLockOwner
)
5921 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5923 librados::IoCtx ioctx
;
5924 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5927 std::string name
= get_temp_image_name();
5928 uint64_t size
= 2 << 20;
5930 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5932 librbd::Image image1
;
5933 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5936 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5939 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5940 ASSERT_TRUE(lock_owner
);
5942 librbd::Image image2
;
5943 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5945 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5946 ASSERT_FALSE(lock_owner
);
5948 ASSERT_EQ(0, image2
.sparsify(4096));
5950 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5951 ASSERT_TRUE(lock_owner
);
5952 ASSERT_PASSED(validate_object_map
, image1
);
5955 TEST_F(TestLibRBD
, ObjectMapConsistentSnap
)
5957 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5959 librados::IoCtx ioctx
;
5960 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5963 std::string name
= get_temp_image_name();
5964 uint64_t size
= 1 << 20;
5966 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5968 librbd::Image image1
;
5969 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5972 for (int i
= 0; i
< num_snaps
; ++i
) {
5973 std::string snap_name
= "snap" + stringify(i
);
5974 ASSERT_EQ(0, image1
.snap_create(snap_name
.c_str()));
5978 thread
writer([&image1
](){
5979 librbd::image_info_t info
;
5980 int r
= image1
.stat(info
, sizeof(info
));
5981 ceph_assert(r
== 0);
5984 for (unsigned i
= 0; i
< info
.num_objs
; ++i
) {
5985 r
= image1
.write((1 << info
.order
) * i
, bl
.length(), bl
);
5986 ceph_assert(r
== (int) bl
.length());
5991 for (int i
= 0; i
< num_snaps
; ++i
) {
5992 std::string snap_name
= "snap" + stringify(i
);
5993 ASSERT_EQ(0, image1
.snap_set(snap_name
.c_str()));
5994 ASSERT_PASSED(validate_object_map
, image1
);
5997 ASSERT_EQ(0, image1
.snap_set(NULL
));
5998 ASSERT_PASSED(validate_object_map
, image1
);
6001 void memset_rand(char *buf
, size_t len
) {
6002 for (size_t i
= 0; i
< len
; ++i
) {
6003 buf
[i
] = (char) (rand() % (126 - 33) + 33);
6007 TEST_F(TestLibRBD
, Metadata
)
6009 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6011 rados_ioctx_t ioctx
;
6012 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6014 std::string name
= get_temp_image_name();
6015 uint64_t size
= 2 << 20;
6017 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6020 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6023 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
6027 size_t keys_len
= sizeof(keys
);
6028 size_t vals_len
= sizeof(vals
);
6030 memset_rand(keys
, keys_len
);
6031 memset_rand(vals
, vals_len
);
6033 ASSERT_EQ(0, rbd_metadata_list(image
, "key", 0, keys
, &keys_len
, vals
,
6035 ASSERT_EQ(0U, keys_len
);
6036 ASSERT_EQ(0U, vals_len
);
6039 size_t value_len
= sizeof(value
);
6040 memset_rand(value
, value_len
);
6042 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
6043 ASSERT_EQ(0, rbd_metadata_set(image1
, "key2", "value2"));
6044 ASSERT_EQ(0, rbd_metadata_get(image1
, "key1", value
, &value_len
));
6045 ASSERT_STREQ(value
, "value1");
6047 ASSERT_EQ(-ERANGE
, rbd_metadata_get(image1
, "key1", value
, &value_len
));
6048 ASSERT_EQ(value_len
, strlen("value1") + 1);
6050 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
6052 keys_len
= sizeof(keys
);
6053 vals_len
= sizeof(vals
);
6054 memset_rand(keys
, keys_len
);
6055 memset_rand(vals
, vals_len
);
6056 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
6058 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
6059 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
6060 ASSERT_STREQ(keys
, "key1");
6061 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
6062 ASSERT_STREQ(vals
, "value1");
6063 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
6065 ASSERT_EQ(0, rbd_metadata_remove(image1
, "key1"));
6066 ASSERT_EQ(-ENOENT
, rbd_metadata_remove(image1
, "key3"));
6067 value_len
= sizeof(value
);
6068 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key3", value
, &value_len
));
6069 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
6071 ASSERT_EQ(keys_len
, strlen("key2") + 1);
6072 ASSERT_EQ(vals_len
, strlen("value2") + 1);
6073 ASSERT_STREQ(keys
, "key2");
6074 ASSERT_STREQ(vals
, "value2");
6076 // test config setting
6077 ASSERT_EQ(0, rbd_metadata_set(image1
, "conf_rbd_cache", "false"));
6078 ASSERT_EQ(-EINVAL
, rbd_metadata_set(image1
, "conf_rbd_cache", "INVALID_VAL"));
6079 ASSERT_EQ(0, rbd_metadata_remove(image1
, "conf_rbd_cache"));
6081 // test metadata with snapshot adding
6082 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
6083 ASSERT_EQ(0, rbd_snap_protect(image1
, "snap1"));
6084 ASSERT_EQ(0, rbd_snap_set(image1
, "snap1"));
6086 ASSERT_EQ(-EROFS
, rbd_metadata_set(image1
, "key1", "value1"));
6087 ASSERT_EQ(-EROFS
, rbd_metadata_remove(image1
, "key2"));
6089 keys_len
= sizeof(keys
);
6090 vals_len
= sizeof(vals
);
6091 memset_rand(keys
, keys_len
);
6092 memset_rand(vals
, vals_len
);
6093 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
6095 ASSERT_EQ(keys_len
, strlen("key2") + 1);
6096 ASSERT_EQ(vals_len
, strlen("value2") + 1);
6097 ASSERT_STREQ(keys
, "key2");
6098 ASSERT_STREQ(vals
, "value2");
6100 ASSERT_EQ(0, rbd_snap_set(image1
, NULL
));
6101 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
6102 ASSERT_EQ(0, rbd_metadata_set(image1
, "key3", "value3"));
6103 keys_len
= sizeof(keys
);
6104 vals_len
= sizeof(vals
);
6105 memset_rand(keys
, keys_len
);
6106 memset_rand(vals
, vals_len
);
6107 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
6110 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
6112 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
6113 ASSERT_STREQ(keys
, "key1");
6114 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
6115 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
6116 ASSERT_STREQ(vals
, "value1");
6117 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
6118 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
6120 // test metadata with cloning
6122 ASSERT_EQ(0, rbd_get_features(image1
, &features
));
6124 string cname
= get_temp_image_name();
6125 EXPECT_EQ(0, rbd_clone(ioctx
, name
.c_str(), "snap1", ioctx
,
6126 cname
.c_str(), features
, &order
));
6128 ASSERT_EQ(0, rbd_open(ioctx
, cname
.c_str(), &image2
, NULL
));
6129 ASSERT_EQ(0, rbd_metadata_set(image2
, "key4", "value4"));
6131 keys_len
= sizeof(keys
);
6132 vals_len
= sizeof(vals
);
6133 memset_rand(keys
, keys_len
);
6134 memset_rand(vals
, vals_len
);
6135 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 0, keys
, &keys_len
, vals
,
6137 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
6138 1 + strlen("key4") + 1);
6139 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
6140 strlen("value3") + 1 + strlen("value4") + 1);
6141 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
6143 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1 +
6144 strlen("value3") + 1, "value4");
6146 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
6149 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
6151 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
6152 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key4", value
, &value_len
));
6154 // test short buffer cases
6155 keys_len
= strlen("key1") + 1;
6156 vals_len
= strlen("value1") + 1;
6157 memset_rand(keys
, keys_len
);
6158 memset_rand(vals
, vals_len
);
6159 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 1, keys
, &keys_len
, vals
,
6161 ASSERT_EQ(keys_len
, strlen("key1") + 1);
6162 ASSERT_EQ(vals_len
, strlen("value1") + 1);
6163 ASSERT_STREQ(keys
, "key1");
6164 ASSERT_STREQ(vals
, "value1");
6166 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "key", 2, keys
, &keys_len
, vals
,
6168 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
6169 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
6171 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "key", 0, keys
, &keys_len
, vals
,
6173 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
6174 1 + strlen("key4") + 1);
6175 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
6176 strlen("value3") + 1 + strlen("value4") + 1);
6178 // test `start` param
6179 keys_len
= sizeof(keys
);
6180 vals_len
= sizeof(vals
);
6181 memset_rand(keys
, keys_len
);
6182 memset_rand(vals
, vals_len
);
6183 ASSERT_EQ(0, rbd_metadata_list(image2
, "key2", 0, keys
, &keys_len
, vals
,
6185 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
6186 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
6187 ASSERT_STREQ(keys
, "key3");
6188 ASSERT_STREQ(vals
, "value3");
6190 ASSERT_EQ(0, rbd_close(image
));
6191 ASSERT_EQ(0, rbd_close(image1
));
6192 ASSERT_EQ(0, rbd_close(image2
));
6193 rados_ioctx_destroy(ioctx
);
6196 TEST_F(TestLibRBD
, MetadataPP
)
6198 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6200 librados::IoCtx ioctx
;
6201 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6204 string name
= get_temp_image_name();
6205 uint64_t size
= 2 << 20;
6209 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6211 librbd::Image image1
;
6212 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6213 map
<string
, bufferlist
> pairs
;
6214 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6215 ASSERT_TRUE(pairs
.empty());
6217 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
6218 ASSERT_EQ(0, image1
.metadata_set("key2", "value2"));
6219 ASSERT_EQ(0, image1
.metadata_get("key1", &value
));
6220 ASSERT_EQ(0, strcmp("value1", value
.c_str()));
6221 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6222 ASSERT_EQ(2U, pairs
.size());
6223 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
6224 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6227 ASSERT_EQ(0, image1
.metadata_remove("key1"));
6228 ASSERT_EQ(-ENOENT
, image1
.metadata_remove("key3"));
6229 ASSERT_TRUE(image1
.metadata_get("key3", &value
) < 0);
6230 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6231 ASSERT_EQ(1U, pairs
.size());
6232 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6234 // test config setting
6235 ASSERT_EQ(0, image1
.metadata_set("conf_rbd_cache", "false"));
6236 ASSERT_EQ(-EINVAL
, image1
.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
6237 ASSERT_EQ(0, image1
.metadata_remove("conf_rbd_cache"));
6239 // test metadata with snapshot adding
6240 ASSERT_EQ(0, image1
.snap_create("snap1"));
6241 ASSERT_EQ(0, image1
.snap_protect("snap1"));
6242 ASSERT_EQ(0, image1
.snap_set("snap1"));
6245 ASSERT_EQ(-EROFS
, image1
.metadata_set("key1", "value1"));
6246 ASSERT_EQ(-EROFS
, image1
.metadata_remove("key2"));
6247 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6248 ASSERT_EQ(1U, pairs
.size());
6249 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6251 ASSERT_EQ(0, image1
.snap_set(NULL
));
6252 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
6253 ASSERT_EQ(0, image1
.metadata_set("key3", "value3"));
6254 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6255 ASSERT_EQ(3U, pairs
.size());
6256 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
6257 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6258 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
6260 // test metadata with cloning
6261 string cname
= get_temp_image_name();
6262 librbd::Image image2
;
6263 ASSERT_EQ(0, image1
.features(&features
));
6264 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
6265 cname
.c_str(), features
, &order
));
6266 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, cname
.c_str(), NULL
));
6267 ASSERT_EQ(0, image2
.metadata_set("key4", "value4"));
6269 ASSERT_EQ(0, image2
.metadata_list("key", 0, &pairs
));
6270 ASSERT_EQ(4U, pairs
.size());
6272 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6273 ASSERT_EQ(3U, pairs
.size());
6274 ASSERT_EQ(-ENOENT
, image1
.metadata_get("key4", &value
));
6277 TEST_F(TestLibRBD
, UpdateFeatures
)
6279 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6281 librados::IoCtx ioctx
;
6282 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6285 std::string name
= get_temp_image_name();
6286 uint64_t size
= 1 << 20;
6288 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6290 librbd::Image image
;
6291 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6294 ASSERT_EQ(0, image
.old_format(&old_format
));
6296 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
6301 ASSERT_EQ(0, image
.features(&features
));
6303 // must provide a single feature
6304 ASSERT_EQ(-EINVAL
, image
.update_features(0, true));
6306 uint64_t disable_features
;
6307 disable_features
= features
& (RBD_FEATURE_EXCLUSIVE_LOCK
|
6308 RBD_FEATURE_OBJECT_MAP
|
6309 RBD_FEATURE_FAST_DIFF
|
6310 RBD_FEATURE_JOURNALING
);
6311 if (disable_features
!= 0) {
6312 ASSERT_EQ(0, image
.update_features(disable_features
, false));
6315 ASSERT_EQ(0, image
.features(&features
));
6316 ASSERT_EQ(0U, features
& disable_features
);
6318 // cannot enable object map nor journaling w/o exclusive lock
6319 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6320 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_JOURNALING
, true));
6321 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
6323 ASSERT_EQ(0, image
.features(&features
));
6324 ASSERT_NE(0U, features
& RBD_FEATURE_EXCLUSIVE_LOCK
);
6326 // can enable fast diff w/o object map
6327 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_FAST_DIFF
, true));
6328 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6329 ASSERT_EQ(0, image
.features(&features
));
6330 ASSERT_NE(0U, features
& RBD_FEATURE_OBJECT_MAP
);
6332 uint64_t expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
|
6333 RBD_FLAG_FAST_DIFF_INVALID
;
6335 ASSERT_EQ(0, image
.get_flags(&flags
));
6336 ASSERT_EQ(expected_flags
, flags
);
6338 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
6339 ASSERT_EQ(0, image
.features(&features
));
6340 ASSERT_EQ(0U, features
& RBD_FEATURE_OBJECT_MAP
);
6342 // can disable object map w/ fast diff
6343 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6344 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
6345 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_FAST_DIFF
, false));
6346 ASSERT_EQ(0, image
.features(&features
));
6347 ASSERT_EQ(0U, features
& RBD_FEATURE_FAST_DIFF
);
6349 ASSERT_EQ(0, image
.get_flags(&flags
));
6350 ASSERT_EQ(0U, flags
);
6352 // cannot disable exclusive lock w/ object map
6353 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6354 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
6355 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
6357 // cannot disable exclusive lock w/ journaling
6358 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, true));
6359 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
6360 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, false));
6362 ASSERT_EQ(0, image
.get_flags(&flags
));
6363 ASSERT_EQ(0U, flags
);
6365 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
6367 ASSERT_EQ(0, image
.features(&features
));
6368 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0) {
6369 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, false));
6371 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, true));
6374 TEST_F(TestLibRBD
, FeaturesBitmaskString
)
6377 uint64_t features
= RBD_FEATURES_DEFAULT
;
6379 std::string features_str
;
6380 std::string expected_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
6381 rbd
.features_to_string(features
, &features_str
);
6382 ASSERT_EQ(expected_str
, features_str
);
6384 features
= RBD_FEATURE_LAYERING
;
6386 expected_str
= "layering";
6387 rbd
.features_to_string(features
, &features_str
);
6388 ASSERT_EQ(expected_str
, features_str
);
6390 uint64_t features_bitmask
;
6391 features_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
6392 rbd
.features_from_string(features_str
, &features_bitmask
);
6393 ASSERT_EQ(features_bitmask
, RBD_FEATURES_DEFAULT
);
6395 features_str
= "layering";
6396 features_bitmask
= 0;
6397 rbd
.features_from_string(features_str
, &features_bitmask
);
6398 ASSERT_EQ(features_bitmask
, RBD_FEATURE_LAYERING
);
6401 TEST_F(TestLibRBD
, RebuildObjectMap
)
6403 librados::IoCtx ioctx
;
6404 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6407 std::string name
= get_temp_image_name();
6408 uint64_t size
= 1 << 20;
6410 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6412 PrintProgress prog_ctx
;
6413 std::string object_map_oid
;
6417 librbd::Image image
;
6418 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6421 ASSERT_EQ(0, image
.features(&features
));
6422 if ((features
& RBD_FEATURE_OBJECT_MAP
) == 0) {
6423 ASSERT_EQ(-EINVAL
, image
.rebuild_object_map(prog_ctx
));
6427 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
6429 ASSERT_EQ(0, image
.snap_create("snap1"));
6430 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(1<<order
, bl
.length(), bl
));
6432 std::string image_id
;
6433 ASSERT_EQ(0, get_image_id(image
, &image_id
));
6434 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
6437 // corrupt the object map
6438 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
6440 librbd::Image image1
;
6441 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6445 ASSERT_EQ(0, image1
.write(0, 0, bl
));
6446 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6447 ASSERT_TRUE(lock_owner
);
6450 ASSERT_EQ(0, image1
.get_flags(&flags
));
6451 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
6453 ASSERT_EQ(0, image1
.rebuild_object_map(prog_ctx
));
6455 librbd::Image image2
;
6456 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6459 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(0, bl
.length(), read_bl
));
6460 ASSERT_TRUE(bl
.contents_equal(read_bl
));
6463 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(1<<order
, bl
.length(), read_bl
));
6464 ASSERT_TRUE(bl
.contents_equal(read_bl
));
6466 ASSERT_PASSED(validate_object_map
, image1
);
6467 ASSERT_PASSED(validate_object_map
, image2
);
6470 TEST_F(TestLibRBD
, RebuildNewObjectMap
)
6472 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
6474 rados_ioctx_t ioctx
;
6475 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6477 std::string name
= get_temp_image_name();
6478 uint64_t size
= 1 << 20;
6480 uint64_t features
= RBD_FEATURE_EXCLUSIVE_LOCK
;
6481 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
6485 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6486 ASSERT_EQ(0, rbd_update_features(image
, RBD_FEATURE_OBJECT_MAP
, true));
6487 ASSERT_EQ(0, rbd_rebuild_object_map(image
, print_progress_percent
, NULL
));
6489 ASSERT_PASSED(validate_object_map
, image
);
6491 ASSERT_EQ(0, rbd_close(image
));
6492 rados_ioctx_destroy(ioctx
);
6495 TEST_F(TestLibRBD
, CheckObjectMap
)
6497 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
6499 librados::IoCtx ioctx
;
6500 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6503 std::string name
= get_temp_image_name();
6504 uint64_t size
= 1 << 20;
6506 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6508 PrintProgress prog_ctx
;
6513 librbd::Image image
;
6514 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6517 ASSERT_EQ(0, image
.features(&features
));
6519 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(0, bl1
.length(), bl1
));
6521 ASSERT_EQ(0, image
.snap_create("snap1"));
6522 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(1<<order
, bl1
.length(), bl1
));
6525 librbd::Image image1
;
6526 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6528 std::string image_id
;
6529 ASSERT_EQ(0, get_image_id(image1
, &image_id
));
6531 std::string object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
6533 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl2
, 1024, 0));
6536 ASSERT_EQ((ssize_t
)bl1
.length(), image1
.write(3 * (1 << 18), bl1
.length(), bl1
));
6537 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6538 ASSERT_TRUE(lock_owner
);
6540 //reopen image to reread now corrupt object map from disk
6544 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl1
, 1024, 0));
6545 ASSERT_FALSE(bl1
.contents_equal(bl2
));
6547 ASSERT_EQ(0, ioctx
.write_full(object_map_oid
, bl2
));
6548 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6551 ASSERT_EQ(0, image1
.get_flags(&flags
));
6552 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
6554 ASSERT_EQ(0, image1
.check_object_map(prog_ctx
));
6556 ASSERT_EQ(0, image1
.get_flags(&flags
));
6557 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
6560 TEST_F(TestLibRBD
, BlockingAIO
)
6562 librados::IoCtx ioctx
;
6563 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6566 std::string name
= get_temp_image_name();
6567 uint64_t size
= 1 << 20;
6569 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6571 std::string non_blocking_aio
;
6572 ASSERT_EQ(0, _rados
.conf_get("rbd_non_blocking_aio", non_blocking_aio
));
6573 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio", "0"));
6574 BOOST_SCOPE_EXIT( (non_blocking_aio
) ) {
6575 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio",
6576 non_blocking_aio
.c_str()));
6577 } BOOST_SCOPE_EXIT_END
;
6579 librbd::Image image
;
6580 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6582 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
6585 ASSERT_EQ(0, image
.write(0, bl
.length(), bl
));
6587 bl
.append(std::string(256, '1'));
6588 librbd::RBD::AioCompletion
*write_comp
=
6589 new librbd::RBD::AioCompletion(NULL
, NULL
);
6590 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
6592 librbd::RBD::AioCompletion
*flush_comp
=
6593 new librbd::RBD::AioCompletion(NULL
, NULL
);
6594 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
6595 ASSERT_EQ(0, flush_comp
->wait_for_complete());
6596 ASSERT_EQ(0, flush_comp
->get_return_value());
6597 flush_comp
->release();
6599 ASSERT_EQ(1, write_comp
->is_complete());
6600 ASSERT_EQ(0, write_comp
->get_return_value());
6601 write_comp
->release();
6603 librbd::RBD::AioCompletion
*discard_comp
=
6604 new librbd::RBD::AioCompletion(NULL
, NULL
);
6605 ASSERT_EQ(0, image
.aio_discard(128, 128, discard_comp
));
6606 ASSERT_EQ(0, discard_comp
->wait_for_complete());
6607 discard_comp
->release();
6609 librbd::RBD::AioCompletion
*read_comp
=
6610 new librbd::RBD::AioCompletion(NULL
, NULL
);
6612 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
6613 ASSERT_EQ(0, read_comp
->wait_for_complete());
6614 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
6615 read_comp
->release();
6617 bufferlist expected_bl
;
6618 expected_bl
.append(std::string(128, '1'));
6619 expected_bl
.append(std::string(128, skip_discard
? '1' : '\0'));
6620 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
6623 TEST_F(TestLibRBD
, ExclusiveLockTransition
)
6625 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
6627 librados::IoCtx ioctx
;
6628 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6631 std::string name
= get_temp_image_name();
6633 uint64_t size
= 1 << 18;
6635 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6637 librbd::Image image1
;
6638 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6640 librbd::Image image2
;
6641 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6643 std::list
<librbd::RBD::AioCompletion
*> comps
;
6644 ceph::bufferlist bl
;
6645 bl
.append(std::string(1 << order
, '1'));
6646 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6647 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
6649 comps
.push_back(comp
);
6650 if (object_no
% 2 == 0) {
6651 ASSERT_EQ(0, image1
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
6653 ASSERT_EQ(0, image2
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
6657 while (!comps
.empty()) {
6658 librbd::RBD::AioCompletion
*comp
= comps
.front();
6660 ASSERT_EQ(0, comp
->wait_for_complete());
6661 ASSERT_EQ(1, comp
->is_complete());
6665 librbd::Image image3
;
6666 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
6667 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6669 ASSERT_EQ((ssize_t
)bl
.length(), image3
.read(object_no
<< order
, bl
.length(),
6671 ASSERT_TRUE(bl
.contents_equal(read_bl
));
6674 ASSERT_PASSED(validate_object_map
, image1
);
6675 ASSERT_PASSED(validate_object_map
, image2
);
6676 ASSERT_PASSED(validate_object_map
, image3
);
6679 TEST_F(TestLibRBD
, ExclusiveLockReadTransition
)
6681 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
6683 librados::IoCtx ioctx
;
6684 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6687 std::string name
= get_temp_image_name();
6689 uint64_t size
= 1 << 18;
6691 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6693 librbd::Image image1
;
6694 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6697 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6698 ASSERT_FALSE(lock_owner
);
6700 // journaling should force read ops to acquire the lock
6702 ASSERT_EQ(0, image1
.read(0, 0, read_bl
));
6704 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6705 ASSERT_TRUE(lock_owner
);
6707 librbd::Image image2
;
6708 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6710 std::list
<librbd::RBD::AioCompletion
*> comps
;
6711 std::list
<bufferlist
> read_bls
;
6712 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6713 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
6715 comps
.push_back(comp
);
6716 read_bls
.emplace_back();
6717 if (object_no
% 2 == 0) {
6718 ASSERT_EQ(0, image1
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6720 ASSERT_EQ(0, image2
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6724 while (!comps
.empty()) {
6725 librbd::RBD::AioCompletion
*comp
= comps
.front();
6727 ASSERT_EQ(0, comp
->wait_for_complete());
6728 ASSERT_EQ(1, comp
->is_complete());
6733 TEST_F(TestLibRBD
, CacheMayCopyOnWrite
) {
6734 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6736 librados::IoCtx ioctx
;
6737 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6740 std::string name
= get_temp_image_name();
6742 uint64_t size
= 1 << 18;
6744 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6746 librbd::Image image
;
6747 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6748 ASSERT_EQ(0, image
.snap_create("one"));
6749 ASSERT_EQ(0, image
.snap_protect("one"));
6751 std::string clone_name
= this->get_temp_image_name();
6752 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
6753 RBD_FEATURE_LAYERING
, &order
));
6755 librbd::Image clone
;
6756 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
6757 ASSERT_EQ(0, clone
.flush());
6759 bufferlist expect_bl
;
6760 expect_bl
.append(std::string(1024, '\0'));
6762 // test double read path
6764 uint64_t offset
= 0;
6765 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6766 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6768 bufferlist write_bl
;
6769 write_bl
.append(std::string(1024, '1'));
6770 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6773 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6774 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6776 // test read retry path
6777 offset
= 1 << order
;
6778 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6781 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6782 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6785 TEST_F(TestLibRBD
, FlushEmptyOpsOnExternalSnapshot
) {
6786 std::string cache_enabled
;
6787 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", cache_enabled
));
6788 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", "false"));
6789 BOOST_SCOPE_EXIT( (cache_enabled
) ) {
6790 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", cache_enabled
.c_str()));
6791 } BOOST_SCOPE_EXIT_END
;
6793 librados::IoCtx ioctx
;
6794 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6797 std::string name
= get_temp_image_name();
6798 uint64_t size
= 1 << 18;
6800 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6802 librbd::Image image1
;
6803 librbd::Image image2
;
6804 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6805 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6806 ASSERT_EQ(0, image1
.snap_create("snap1"));
6808 librbd::RBD::AioCompletion
*read_comp
=
6809 new librbd::RBD::AioCompletion(NULL
, NULL
);
6811 image2
.aio_read(0, 1024, read_bl
, read_comp
);
6812 ASSERT_EQ(0, read_comp
->wait_for_complete());
6813 read_comp
->release();
6816 TEST_F(TestLibRBD
, TestImageOptions
)
6818 rados_ioctx_t ioctx
;
6819 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6821 //make create image options
6822 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6824 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6825 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6826 rbd_image_options_t opts
;
6827 rbd_image_options_create(&opts
);
6830 ASSERT_EQ(-EINVAL
, rbd_image_options_is_set(opts
, 12345, &is_set
));
6831 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6833 ASSERT_FALSE(is_set
);
6835 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FORMAT
,
6837 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FEATURES
,
6839 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6841 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_UNIT
,
6843 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_COUNT
,
6846 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6848 ASSERT_TRUE(is_set
);
6850 std::string parent_name
= get_temp_image_name();
6853 ASSERT_EQ(0, rbd_create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6855 // check order is returned in opts
6856 ASSERT_EQ(0, rbd_image_options_get_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6858 ASSERT_NE((uint64_t)0, order
);
6860 // write some data to parent
6862 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
6863 char *data
= (char *)"testdata";
6864 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
6865 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
6867 // create a snapshot, reopen as the parent we're interested in
6868 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6869 ASSERT_EQ(0, rbd_close(parent
));
6870 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
6873 std::string child_name
= get_temp_image_name();
6874 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
6875 ASSERT_EQ(0, rbd_clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6876 child_name
.c_str(), opts
));
6879 std::string copy1_name
= get_temp_image_name();
6880 ASSERT_EQ(0, rbd_copy3(parent
, ioctx
, copy1_name
.c_str(), opts
));
6881 std::string copy2_name
= get_temp_image_name();
6882 ASSERT_EQ(0, rbd_copy_with_progress3(parent
, ioctx
, copy2_name
.c_str(), opts
,
6883 print_progress_percent
, NULL
));
6885 ASSERT_EQ(0, rbd_close(parent
));
6887 rbd_image_options_destroy(opts
);
6889 rados_ioctx_destroy(ioctx
);
6892 TEST_F(TestLibRBD
, TestImageOptionsPP
)
6894 librados::IoCtx ioctx
;
6895 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6897 //make create image options
6898 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6900 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6901 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6902 librbd::ImageOptions opts
;
6903 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FORMAT
, static_cast<uint64_t>(2)));
6904 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FEATURES
, features
));
6905 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_ORDER
, order
));
6906 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
));
6907 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
));
6910 std::string parent_name
= get_temp_image_name();
6913 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6915 // check order is returned in opts
6916 ASSERT_EQ(0, opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
));
6917 ASSERT_NE((uint64_t)0, order
);
6919 // write some data to parent
6920 librbd::Image parent
;
6921 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
6925 bl
.append(buffer::create(len
));
6927 ASSERT_EQ(len
, parent
.write(0, len
, bl
));
6928 ASSERT_EQ(len
, parent
.write(len
, len
, bl
));
6930 // create a snapshot, reopen as the parent we're interested in
6931 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
6932 ASSERT_EQ(0, parent
.close());
6933 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
6936 std::string child_name
= get_temp_image_name();
6937 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
6938 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6939 child_name
.c_str(), opts
));
6942 std::string copy1_name
= get_temp_image_name();
6943 ASSERT_EQ(0, parent
.copy3(ioctx
, copy1_name
.c_str(), opts
));
6944 std::string copy2_name
= get_temp_image_name();
6946 ASSERT_EQ(0, parent
.copy_with_progress3(ioctx
, copy2_name
.c_str(), opts
, pp
));
6948 ASSERT_EQ(0, parent
.close());
6951 TEST_F(TestLibRBD
, EventSocketPipe
)
6953 EventSocket event_sock
;
6954 int pipe_fd
[2]; // read and write fd
6957 ASSERT_EQ(0, pipe(pipe_fd
));
6959 ASSERT_FALSE(event_sock
.is_valid());
6961 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_NONE
));
6962 ASSERT_FALSE(event_sock
.is_valid());
6964 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], 44));
6965 ASSERT_FALSE(event_sock
.is_valid());
6967 #ifndef HAVE_EVENTFD
6968 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_EVENTFD
));
6969 ASSERT_FALSE(event_sock
.is_valid());
6972 ASSERT_EQ(0, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_PIPE
));
6973 ASSERT_TRUE(event_sock
.is_valid());
6974 ASSERT_EQ(0, event_sock
.notify());
6975 ASSERT_EQ(1, read(pipe_fd
[0], buf
, 32));
6976 ASSERT_EQ('i', buf
[0]);
6982 TEST_F(TestLibRBD
, EventSocketEventfd
)
6985 EventSocket event_sock
;
6987 struct pollfd poll_fd
;
6990 event_fd
= eventfd(0, EFD_NONBLOCK
);
6991 ASSERT_NE(-1, event_fd
);
6993 ASSERT_FALSE(event_sock
.is_valid());
6995 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_NONE
));
6996 ASSERT_FALSE(event_sock
.is_valid());
6998 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, 44));
6999 ASSERT_FALSE(event_sock
.is_valid());
7001 ASSERT_EQ(0, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_EVENTFD
));
7002 ASSERT_TRUE(event_sock
.is_valid());
7003 ASSERT_EQ(0, event_sock
.notify());
7005 poll_fd
.fd
= event_fd
;
7006 poll_fd
.events
= POLLIN
;
7007 ASSERT_EQ(1, poll(&poll_fd
, 1, -1));
7008 ASSERT_TRUE(poll_fd
.revents
& POLLIN
);
7010 ASSERT_EQ(static_cast<ssize_t
>(sizeof(uint64_t)), read(event_fd
, buf
, 32));
7011 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf
));
7017 TEST_F(TestLibRBD
, ImagePollIO
)
7020 rados_ioctx_t ioctx
;
7021 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7025 std::string name
= get_temp_image_name();
7026 uint64_t size
= 2 << 20;
7027 int fd
= eventfd(0, EFD_NONBLOCK
);
7029 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7030 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7032 ASSERT_EQ(0, rbd_set_image_notification(image
, fd
, EVENT_SOCKET_TYPE_EVENTFD
));
7034 char test_data
[TEST_IO_SIZE
+ 1];
7035 char zero_data
[TEST_IO_SIZE
+ 1];
7038 for (i
= 0; i
< TEST_IO_SIZE
; ++i
)
7039 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
7040 test_data
[TEST_IO_SIZE
] = '\0';
7041 memset(zero_data
, 0, sizeof(zero_data
));
7043 for (i
= 0; i
< 5; ++i
)
7044 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
7046 for (i
= 5; i
< 10; ++i
)
7047 ASSERT_PASSED(aio_write_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
7049 for (i
= 5; i
< 10; ++i
)
7050 ASSERT_PASSED(aio_read_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
7052 ASSERT_EQ(0, rbd_close(image
));
7053 rados_ioctx_destroy(ioctx
);
7059 static bool operator==(const image_spec_t
&lhs
, const image_spec_t
&rhs
) {
7060 return (lhs
.id
== rhs
.id
&& lhs
.name
== rhs
.name
);
7063 static bool operator==(const linked_image_spec_t
&lhs
,
7064 const linked_image_spec_t
&rhs
) {
7065 return (lhs
.pool_id
== rhs
.pool_id
&&
7066 lhs
.pool_name
== rhs
.pool_name
&&
7067 lhs
.pool_namespace
== rhs
.pool_namespace
&&
7068 lhs
.image_id
== rhs
.image_id
&&
7069 lhs
.image_name
== rhs
.image_name
&&
7070 lhs
.trash
== rhs
.trash
);
7073 static bool operator==(const mirror_peer_t
&lhs
, const mirror_peer_t
&rhs
) {
7074 return (lhs
.uuid
== rhs
.uuid
&&
7075 lhs
.cluster_name
== rhs
.cluster_name
&&
7076 lhs
.client_name
== rhs
.client_name
);
7079 static std::ostream
& operator<<(std::ostream
&os
, const mirror_peer_t
&peer
) {
7080 os
<< "uuid=" << peer
.uuid
<< ", "
7081 << "cluster=" << peer
.cluster_name
<< ", "
7082 << "client=" << peer
.client_name
;
7086 } // namespace librbd
7088 TEST_F(TestLibRBD
, Mirror
) {
7089 librados::IoCtx ioctx
;
7090 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7094 std::vector
<librbd::mirror_peer_t
> expected_peers
;
7095 std::vector
<librbd::mirror_peer_t
> peers
;
7096 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
7097 ASSERT_EQ(expected_peers
, peers
);
7100 ASSERT_EQ(-EINVAL
, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
7102 rbd_mirror_mode_t mirror_mode
;
7103 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
7104 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED
, mirror_mode
);
7106 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
7107 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
7109 // Add some images to the pool
7111 std::string parent_name
= get_temp_image_name();
7112 std::string child_name
= get_temp_image_name();
7113 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), 2 << 20,
7117 ASSERT_EQ(0, get_features(&old_format
, &features
));
7118 if ((features
& RBD_FEATURE_LAYERING
) != 0) {
7119 librbd::Image parent
;
7120 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
7121 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
7122 ASSERT_EQ(0, parent
.close());
7123 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
7124 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
7125 ASSERT_EQ(0, parent
.close());
7126 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
7127 child_name
.c_str(), features
, &order
));
7130 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE
, mirror_mode
);
7132 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_POOL
));
7133 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
7134 ASSERT_EQ(RBD_MIRROR_MODE_POOL
, mirror_mode
);
7138 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
7139 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid2
, "cluster2", "admin"));
7140 ASSERT_EQ(-EEXIST
, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster1", "foo"));
7141 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster3", "admin"));
7143 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
7144 auto sort_peers
= [](const librbd::mirror_peer_t
&lhs
,
7145 const librbd::mirror_peer_t
&rhs
) {
7146 return lhs
.uuid
< rhs
.uuid
;
7149 {uuid1
, "cluster1", "client"},
7150 {uuid2
, "cluster2", "admin"},
7151 {uuid3
, "cluster3", "admin"}};
7152 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
7153 ASSERT_EQ(expected_peers
, peers
);
7155 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, "uuid4"));
7156 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid2
));
7158 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_client(ioctx
, "uuid4", "new client"));
7159 ASSERT_EQ(0, rbd
.mirror_peer_set_client(ioctx
, uuid1
, "new client"));
7161 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_cluster(ioctx
, "uuid4",
7163 ASSERT_EQ(0, rbd
.mirror_peer_set_cluster(ioctx
, uuid3
, "new cluster"));
7165 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
7167 {uuid1
, "cluster1", "new client"},
7168 {uuid3
, "new cluster", "admin"}};
7169 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
7170 ASSERT_EQ(expected_peers
, peers
);
7172 ASSERT_EQ(-EBUSY
, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7173 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid1
));
7174 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid3
));
7175 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7178 TEST_F(TestLibRBD
, MirrorPeerAttributes
) {
7179 REQUIRE(!is_librados_test_stub(_rados
));
7181 librados::IoCtx ioctx
;
7182 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7185 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
7188 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid
, "remote_cluster", "client"));
7190 std::map
<std::string
, std::string
> attributes
;
7191 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_get_attributes(ioctx
, uuid
, &attributes
));
7192 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_attributes(ioctx
, "missing uuid",
7195 std::map
<std::string
, std::string
> expected_attributes
{
7196 {"mon_host", "1.2.3.4"},
7198 ASSERT_EQ(0, rbd
.mirror_peer_set_attributes(ioctx
, uuid
,
7199 expected_attributes
));
7201 ASSERT_EQ(0, rbd
.mirror_peer_get_attributes(ioctx
, uuid
,
7203 ASSERT_EQ(expected_attributes
, attributes
);
7205 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid
));
7206 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7209 TEST_F(TestLibRBD
, CreateWithMirrorEnabled
) {
7210 REQUIRE_FORMAT_V2();
7212 librados::IoCtx ioctx
;
7213 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7216 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
7218 librbd::ImageOptions image_options
;
7219 ASSERT_EQ(0, image_options
.set(
7220 RBD_IMAGE_OPTION_MIRROR_IMAGE_MODE
,
7221 static_cast<uint64_t>(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
)));
7223 std::string parent_name
= get_temp_image_name();
7224 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 2<<20, image_options
));
7226 librbd::Image parent_image
;
7227 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
7229 librbd::mirror_image_mode_t mirror_image_mode
;
7230 ASSERT_EQ(0, parent_image
.mirror_image_get_mode(&mirror_image_mode
));
7231 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
7233 ASSERT_EQ(0, parent_image
.snap_create("parent_snap"));
7234 ASSERT_EQ(0, parent_image
.snap_protect("parent_snap"));
7236 std::string child_name
= get_temp_image_name();
7237 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
7238 child_name
.c_str(), image_options
));
7240 librbd::Image child_image
;
7241 ASSERT_EQ(0, rbd
.open(ioctx
, child_image
, child_name
.c_str(), NULL
));
7243 ASSERT_EQ(0, child_image
.mirror_image_get_mode(&mirror_image_mode
));
7244 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
7246 ASSERT_EQ(0, child_image
.mirror_image_disable(true));
7247 ASSERT_EQ(0, parent_image
.mirror_image_disable(true));
7248 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7251 TEST_F(TestLibRBD
, FlushCacheWithCopyupOnExternalSnapshot
) {
7252 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7254 librados::IoCtx ioctx
;
7255 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7258 librbd::Image image
;
7259 std::string name
= get_temp_image_name();
7261 uint64_t size
= 1 << 18;
7264 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7265 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7268 bl
.append(std::string(size
, '1'));
7269 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
7270 ASSERT_EQ(0, image
.snap_create("one"));
7271 ASSERT_EQ(0, image
.snap_protect("one"));
7273 std::string clone_name
= this->get_temp_image_name();
7274 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
7275 RBD_FEATURE_LAYERING
, &order
));
7276 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
7278 librbd::Image image2
;
7279 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, clone_name
.c_str(), NULL
));
7281 // prepare CoW writeback that will be flushed on next op
7283 bl
.append(std::string(1, '1'));
7284 ASSERT_EQ(0, image
.flush());
7285 ASSERT_EQ(1, image
.write(0, 1, bl
));
7286 ASSERT_EQ(0, image2
.snap_create("snap1"));
7288 librbd::RBD::AioCompletion
*read_comp
=
7289 new librbd::RBD::AioCompletion(NULL
, NULL
);
7291 image
.aio_read(0, 1024, read_bl
, read_comp
);
7292 ASSERT_EQ(0, read_comp
->wait_for_complete());
7293 read_comp
->release();
7296 TEST_F(TestLibRBD
, ExclusiveLock
)
7298 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
7300 static char buf
[10];
7302 rados_ioctx_t ioctx
;
7303 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7305 std::string name
= get_temp_image_name();
7306 uint64_t size
= 2 << 20;
7308 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7311 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
7314 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
7315 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7316 ASSERT_TRUE(lock_owner
);
7318 rbd_lock_mode_t lock_mode
;
7319 char *lock_owners
[1];
7320 size_t max_lock_owners
= 0;
7321 ASSERT_EQ(-ERANGE
, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
7323 ASSERT_EQ(1U, max_lock_owners
);
7325 ASSERT_EQ(0, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
7327 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
7328 ASSERT_STRNE("", lock_owners
[0]);
7329 ASSERT_EQ(1U, max_lock_owners
);
7332 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
7334 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7335 ASSERT_FALSE(lock_owner
);
7337 ASSERT_EQ(-EOPNOTSUPP
, rbd_lock_break(image1
, RBD_LOCK_MODE_SHARED
, ""));
7338 ASSERT_EQ(-EBUSY
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
7341 ASSERT_EQ(0, rbd_lock_release(image1
));
7342 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7343 ASSERT_FALSE(lock_owner
);
7345 ASSERT_EQ(-ENOENT
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
7347 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
7349 ASSERT_EQ(-EROFS
, rbd_write(image1
, 0, sizeof(buf
), buf
));
7350 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image2
, 0, sizeof(buf
), buf
));
7352 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
7353 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7354 ASSERT_TRUE(lock_owner
);
7356 ASSERT_EQ(0, rbd_lock_release(image2
));
7357 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7358 ASSERT_FALSE(lock_owner
);
7360 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
7361 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7362 ASSERT_TRUE(lock_owner
);
7364 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image1
, 0, sizeof(buf
), buf
));
7365 ASSERT_EQ(-EROFS
, rbd_write(image2
, 0, sizeof(buf
), buf
));
7367 ASSERT_EQ(0, rbd_lock_release(image1
));
7368 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7369 ASSERT_FALSE(lock_owner
);
7373 const auto pingpong
= [&](int m_id
, rbd_image_t
&m_image
) {
7374 for (int i
= 0; i
< 10; i
++) {
7376 std::lock_guard
<std::mutex
> locker(lock
);
7377 if (owner_id
== m_id
) {
7378 std::cout
<< m_id
<< ": releasing exclusive lock" << std::endl
;
7379 EXPECT_EQ(0, rbd_lock_release(m_image
));
7381 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
7382 EXPECT_FALSE(lock_owner
);
7384 std::cout
<< m_id
<< ": exclusive lock released" << std::endl
;
7389 std::cout
<< m_id
<< ": acquiring exclusive lock" << std::endl
;
7392 r
= rbd_lock_acquire(m_image
, RBD_LOCK_MODE_EXCLUSIVE
);
7396 } while (r
== -EROFS
);
7400 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
7401 EXPECT_TRUE(lock_owner
);
7402 std::cout
<< m_id
<< ": exclusive lock acquired" << std::endl
;
7404 std::lock_guard
<std::mutex
> locker(lock
);
7407 usleep(rand() % 50000);
7410 std::lock_guard
<std::mutex
> locker(lock
);
7411 if (owner_id
== m_id
) {
7412 EXPECT_EQ(0, rbd_lock_release(m_image
));
7414 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
7415 EXPECT_FALSE(lock_owner
);
7419 thread
ping(bind(pingpong
, 1, ref(image1
)));
7420 thread
pong(bind(pingpong
, 2, ref(image2
)));
7425 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
7426 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7427 ASSERT_TRUE(lock_owner
);
7429 ASSERT_EQ(0, rbd_close(image2
));
7431 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
7432 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7433 ASSERT_TRUE(lock_owner
);
7435 ASSERT_EQ(0, rbd_close(image1
));
7436 rados_ioctx_destroy(ioctx
);
7439 TEST_F(TestLibRBD
, BreakLock
)
7441 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
7442 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
7444 static char buf
[10];
7446 rados_t blocklist_cluster
;
7447 ASSERT_EQ("", connect_cluster(&blocklist_cluster
));
7449 rados_ioctx_t ioctx
, blocklist_ioctx
;
7450 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
7451 ASSERT_EQ(0, rados_ioctx_create(blocklist_cluster
, m_pool_name
.c_str(),
7454 std::string name
= get_temp_image_name();
7455 uint64_t size
= 2 << 20;
7457 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7459 rbd_image_t image
, blocklist_image
;
7460 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7461 ASSERT_EQ(0, rbd_open(blocklist_ioctx
, name
.c_str(), &blocklist_image
, NULL
));
7463 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_blocklist_on_break_lock", "true"));
7464 ASSERT_EQ(0, rbd_lock_acquire(blocklist_image
, RBD_LOCK_MODE_EXCLUSIVE
));
7466 rbd_lock_mode_t lock_mode
;
7467 char *lock_owners
[1];
7468 size_t max_lock_owners
= 1;
7469 ASSERT_EQ(0, rbd_lock_get_owners(image
, &lock_mode
, lock_owners
,
7471 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
7472 ASSERT_STRNE("", lock_owners
[0]);
7473 ASSERT_EQ(1U, max_lock_owners
);
7475 ASSERT_EQ(0, rbd_lock_break(image
, RBD_LOCK_MODE_EXCLUSIVE
, lock_owners
[0]));
7476 ASSERT_EQ(0, rbd_lock_acquire(image
, RBD_LOCK_MODE_EXCLUSIVE
));
7477 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blocklist_cluster
));
7479 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image
, 0, sizeof(buf
), buf
));
7480 ASSERT_EQ(-EBLOCKLISTED
, rbd_write(blocklist_image
, 0, sizeof(buf
), buf
));
7482 ASSERT_EQ(0, rbd_close(image
));
7483 ASSERT_EQ(0, rbd_close(blocklist_image
));
7485 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
7487 rados_ioctx_destroy(ioctx
);
7488 rados_ioctx_destroy(blocklist_ioctx
);
7489 rados_shutdown(blocklist_cluster
);
7492 TEST_F(TestLibRBD
, DiscardAfterWrite
)
7494 librados::IoCtx ioctx
;
7495 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7498 std::string name
= get_temp_image_name();
7499 uint64_t size
= 1 << 20;
7501 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7503 librbd::Image image
;
7504 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7506 if (this->is_skip_partial_discard_enabled(image
)) {
7510 // enable writeback cache
7511 ASSERT_EQ(0, image
.flush());
7514 bl
.append(std::string(256, '1'));
7516 librbd::RBD::AioCompletion
*write_comp
=
7517 new librbd::RBD::AioCompletion(NULL
, NULL
);
7518 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
7519 ASSERT_EQ(0, write_comp
->wait_for_complete());
7520 write_comp
->release();
7522 librbd::RBD::AioCompletion
*discard_comp
=
7523 new librbd::RBD::AioCompletion(NULL
, NULL
);
7524 ASSERT_EQ(0, image
.aio_discard(0, 256, discard_comp
));
7525 ASSERT_EQ(0, discard_comp
->wait_for_complete());
7526 discard_comp
->release();
7528 librbd::RBD::AioCompletion
*read_comp
=
7529 new librbd::RBD::AioCompletion(NULL
, NULL
);
7531 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
7532 ASSERT_EQ(0, read_comp
->wait_for_complete());
7533 ASSERT_EQ(bl
.length(), read_comp
->get_return_value());
7534 ASSERT_TRUE(read_bl
.is_zero());
7535 read_comp
->release();
7538 TEST_F(TestLibRBD
, DefaultFeatures
) {
7539 std::string orig_default_features
;
7540 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", orig_default_features
));
7541 BOOST_SCOPE_EXIT_ALL(orig_default_features
) {
7542 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features",
7543 orig_default_features
.c_str()));
7546 std::list
<std::pair
<std::string
, std::string
> > feature_names_to_bitmask
= {
7547 {"", orig_default_features
},
7549 {"layering, exclusive-lock", "5"},
7550 {"exclusive-lock,journaling", "68"},
7554 for (auto &pair
: feature_names_to_bitmask
) {
7555 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features", pair
.first
.c_str()));
7556 std::string features
;
7557 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", features
));
7558 ASSERT_EQ(pair
.second
, features
);
7562 TEST_F(TestLibRBD
, TestTrashMoveAndPurge
) {
7563 REQUIRE_FORMAT_V2();
7565 librados::IoCtx ioctx
;
7566 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7569 std::string name
= get_temp_image_name();
7571 uint64_t size
= 1 << 18;
7573 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7575 librbd::Image image
;
7576 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7578 std::string image_id
;
7579 ASSERT_EQ(0, image
.get_id(&image_id
));
7582 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7584 std::vector
<std::string
> images
;
7585 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7586 for (const auto& image
: images
) {
7587 ASSERT_TRUE(image
!= name
);
7590 librbd::trash_image_info_t info
;
7591 ASSERT_EQ(-ENOENT
, rbd
.trash_get(ioctx
, "dummy image id", &info
));
7592 ASSERT_EQ(0, rbd
.trash_get(ioctx
, image_id
.c_str(), &info
));
7593 ASSERT_EQ(image_id
, info
.id
);
7595 std::vector
<librbd::trash_image_info_t
> entries
;
7596 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7597 ASSERT_FALSE(entries
.empty());
7598 ASSERT_EQ(entries
.begin()->id
, image_id
);
7602 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7604 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7605 ASSERT_TRUE(entries
.empty());
7608 TEST_F(TestLibRBD
, TestTrashMoveAndPurgeNonExpiredDelay
) {
7609 REQUIRE_FORMAT_V2();
7611 librados::IoCtx ioctx
;
7612 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7615 std::string name
= get_temp_image_name();
7617 uint64_t size
= 1 << 18;
7619 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7621 librbd::Image image
;
7622 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7624 std::string image_id
;
7625 ASSERT_EQ(0, image
.get_id(&image_id
));
7628 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 100));
7631 ASSERT_EQ(-EPERM
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7635 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7639 TEST_F(TestLibRBD
, TestTrashPurge
) {
7640 REQUIRE_FORMAT_V2();
7642 librados::IoCtx ioctx
;
7643 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7646 std::string name1
= get_temp_image_name();
7647 std::string name2
= get_temp_image_name();
7649 uint64_t size
= 1 << 18;
7651 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name1
.c_str(), size
, &order
));
7652 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
7654 librbd::Image image1
;
7655 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name1
.c_str(), nullptr));
7657 std::string image_id1
;
7658 ASSERT_EQ(0, image1
.get_id(&image_id1
));
7661 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name1
.c_str(), 0));
7663 librbd::Image image2
;
7664 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), nullptr));
7665 ceph::bufferlist bl
;
7666 bl
.append(std::string(1024, '0'));
7667 ASSERT_EQ(1024, image2
.write(0, 1024, bl
));
7669 std::string image_id2
;
7670 ASSERT_EQ(0, image2
.get_id(&image_id2
));
7673 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name2
.c_str(), 100));
7674 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, 0, -1));
7676 std::vector
<librbd::trash_image_info_t
> entries
;
7677 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7678 ASSERT_EQ(1U, entries
.size());
7679 ASSERT_EQ(image_id2
, entries
[0].id
);
7680 ASSERT_EQ(name2
, entries
[0].name
);
7683 struct timespec now
;
7684 clock_gettime(CLOCK_REALTIME
, &now
);
7685 float threshold
= 0.0;
7686 if (!is_librados_test_stub(_rados
)) {
7687 // real cluster usage reports have a long latency to update
7691 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, now
.tv_sec
+1000, threshold
));
7692 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7693 ASSERT_EQ(0U, entries
.size());
7696 TEST_F(TestLibRBD
, TestTrashMoveAndRestore
) {
7697 REQUIRE_FORMAT_V2();
7699 librados::IoCtx ioctx
;
7700 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7703 std::string name
= get_temp_image_name();
7705 uint64_t size
= 1 << 18;
7707 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7709 librbd::Image image
;
7710 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7712 std::string image_id
;
7713 ASSERT_EQ(0, image
.get_id(&image_id
));
7716 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 10));
7718 std::vector
<std::string
> images
;
7719 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7720 for (const auto& image
: images
) {
7721 ASSERT_TRUE(image
!= name
);
7724 std::vector
<librbd::trash_image_info_t
> entries
;
7725 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7726 ASSERT_FALSE(entries
.empty());
7727 ASSERT_EQ(entries
.begin()->id
, image_id
);
7730 ASSERT_EQ(0, rbd
.trash_restore(ioctx
, image_id
.c_str(), ""));
7731 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7732 ASSERT_FALSE(images
.empty());
7734 for (const auto& image
: images
) {
7735 if (image
== name
) {
7743 TEST_F(TestLibRBD
, TestListWatchers
) {
7744 librados::IoCtx ioctx
;
7745 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7748 std::string name
= get_temp_image_name();
7750 uint64_t size
= 1 << 18;
7752 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7754 librbd::Image image
;
7755 std::list
<librbd::image_watcher_t
> watchers
;
7758 ASSERT_EQ(0, rbd
.open_read_only(ioctx
, image
, name
.c_str(), nullptr));
7759 ASSERT_EQ(0, image
.list_watchers(watchers
));
7760 ASSERT_EQ(0U, watchers
.size());
7761 ASSERT_EQ(0, image
.close());
7764 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7765 ASSERT_EQ(0, image
.list_watchers(watchers
));
7766 ASSERT_EQ(1U, watchers
.size());
7767 ASSERT_EQ(0, image
.close());
7770 TEST_F(TestLibRBD
, TestSetSnapById
) {
7771 librados::IoCtx ioctx
;
7772 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7775 std::string name
= get_temp_image_name();
7777 uint64_t size
= 1 << 18;
7779 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7781 librbd::Image image
;
7782 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7783 ASSERT_EQ(0, image
.snap_create("snap"));
7785 vector
<librbd::snap_info_t
> snaps
;
7786 ASSERT_EQ(0, image
.snap_list(snaps
));
7787 ASSERT_EQ(1U, snaps
.size());
7789 ASSERT_EQ(0, image
.snap_set_by_id(snaps
[0].id
));
7790 ASSERT_EQ(0, image
.snap_set_by_id(CEPH_NOSNAP
));
7793 TEST_F(TestLibRBD
, Namespaces
) {
7794 rados_ioctx_t ioctx
;
7795 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
7796 rados_remove(ioctx
, RBD_NAMESPACE
);
7798 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name1"));
7799 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name2"));
7800 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name3"));
7801 ASSERT_EQ(0, rbd_namespace_remove(ioctx
, "name2"));
7804 size_t max_size
= sizeof(names
);
7805 int len
= rbd_namespace_list(ioctx
, names
, &max_size
);
7807 std::vector
<std::string
> cpp_names
;
7808 for (char* cur_name
= names
; cur_name
< names
+ len
; ) {
7809 cpp_names
.push_back(cur_name
);
7810 cur_name
+= strlen(cur_name
) + 1;
7812 ASSERT_EQ(2U, cpp_names
.size());
7813 ASSERT_EQ("name1", cpp_names
[0]);
7814 ASSERT_EQ("name3", cpp_names
[1]);
7816 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name2", &exists
));
7817 ASSERT_FALSE(exists
);
7818 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name3", &exists
));
7819 ASSERT_TRUE(exists
);
7820 rados_ioctx_destroy(ioctx
);
7823 TEST_F(TestLibRBD
, NamespacesPP
) {
7824 librados::IoCtx ioctx
;
7825 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7826 ioctx
.remove(RBD_NAMESPACE
);
7829 ASSERT_EQ(-EINVAL
, rbd
.namespace_create(ioctx
, ""));
7830 ASSERT_EQ(-EINVAL
, rbd
.namespace_remove(ioctx
, ""));
7832 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name1"));
7833 ASSERT_EQ(-EEXIST
, rbd
.namespace_create(ioctx
, "name1"));
7834 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name2"));
7835 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name3"));
7836 ASSERT_EQ(0, rbd
.namespace_remove(ioctx
, "name2"));
7837 ASSERT_EQ(-ENOENT
, rbd
.namespace_remove(ioctx
, "name2"));
7839 std::vector
<std::string
> names
;
7840 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7841 ASSERT_EQ(2U, names
.size());
7842 ASSERT_EQ("name1", names
[0]);
7843 ASSERT_EQ("name3", names
[1]);
7845 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name2", &exists
));
7846 ASSERT_FALSE(exists
);
7847 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name3", &exists
));
7848 ASSERT_TRUE(exists
);
7850 librados::IoCtx ns_io_ctx
;
7851 ns_io_ctx
.dup(ioctx
);
7853 std::string name
= get_temp_image_name();
7855 uint64_t features
= 0;
7856 if (!get_features(&features
)) {
7857 // old format doesn't support namespaces
7858 ns_io_ctx
.set_namespace("name1");
7859 ASSERT_EQ(-EINVAL
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0,
7864 ns_io_ctx
.set_namespace("missing");
7865 ASSERT_EQ(-ENOENT
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7867 ns_io_ctx
.set_namespace("name1");
7868 ASSERT_EQ(0, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7869 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7871 std::string image_id
;
7873 librbd::Image image
;
7874 ASSERT_EQ(-ENOENT
, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7875 ASSERT_EQ(0, rbd
.open(ns_io_ctx
, image
, name
.c_str(), NULL
));
7876 ASSERT_EQ(0, get_image_id(image
, &image_id
));
7879 ASSERT_EQ(-ENOENT
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7880 ASSERT_EQ(0, rbd
.trash_move(ns_io_ctx
, name
.c_str(), 0));
7881 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7884 ASSERT_EQ(-ENOENT
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7886 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ns_io_ctx
, image_id
.c_str(),
7888 ASSERT_EQ(0, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7891 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7892 ASSERT_EQ(1U, names
.size());
7893 ASSERT_EQ("name3", names
[0]);
7896 TEST_F(TestLibRBD
, Migration
) {
7899 ASSERT_EQ(0, get_features(&old_format
, &features
));
7901 rados_ioctx_t ioctx
;
7902 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7903 BOOST_SCOPE_EXIT(&ioctx
) {
7904 rados_ioctx_destroy(ioctx
);
7905 } BOOST_SCOPE_EXIT_END
;
7908 std::string name
= get_temp_image_name();
7909 uint64_t size
= 2 << 20;
7910 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7912 rbd_image_options_t image_options
;
7913 rbd_image_options_create(&image_options
);
7914 BOOST_SCOPE_EXIT(&image_options
) {
7915 rbd_image_options_destroy(image_options
);
7916 } BOOST_SCOPE_EXIT_END
;
7918 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7921 rbd_image_migration_status_t status
;
7922 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7924 ASSERT_EQ(status
.source_pool_id
, rados_ioctx_get_id(ioctx
));
7925 ASSERT_EQ(status
.source_image_name
, name
);
7927 ASSERT_EQ(status
.source_image_id
, string());
7929 ASSERT_NE(status
.source_image_id
, string());
7930 ASSERT_EQ(-EROFS
, rbd_trash_remove(ioctx
, status
.source_image_id
, false));
7931 ASSERT_EQ(-EINVAL
, rbd_trash_restore(ioctx
, status
.source_image_id
, name
.c_str()));
7933 ASSERT_EQ(status
.dest_pool_id
, rados_ioctx_get_id(ioctx
));
7934 ASSERT_EQ(status
.dest_image_name
, name
);
7935 ASSERT_NE(status
.dest_image_id
, string());
7936 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
7937 rbd_migration_status_cleanup(&status
);
7940 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7941 char source_spec
[2048];
7942 size_t source_spec_length
= sizeof(source_spec
);
7943 ASSERT_EQ(0, rbd_get_migration_source_spec(image
, source_spec
,
7944 &source_spec_length
));
7945 json_spirit::mValue json_source_spec
;
7946 json_spirit::read(source_spec
, json_source_spec
);
7947 EXPECT_EQ(0, rbd_close(image
));
7949 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, name
.c_str()));
7950 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, name
.c_str(), 0));
7952 ASSERT_EQ(0, rbd_migration_execute(ioctx
, name
.c_str()));
7954 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7956 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
7957 rbd_migration_status_cleanup(&status
);
7959 ASSERT_EQ(0, rbd_migration_commit(ioctx
, name
.c_str()));
7961 std::string new_name
= get_temp_image_name();
7963 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
,
7964 new_name
.c_str(), image_options
));
7966 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, new_name
.c_str()));
7967 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, new_name
.c_str(), 0));
7969 ASSERT_EQ(0, rbd_migration_abort(ioctx
, name
.c_str()));
7971 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7972 EXPECT_EQ(0, rbd_close(image
));
7975 TEST_F(TestLibRBD
, MigrationPP
) {
7978 ASSERT_EQ(0, get_features(&old_format
, &features
));
7980 librados::IoCtx ioctx
;
7981 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7984 std::string name
= get_temp_image_name();
7985 uint64_t size
= 2 << 20;
7987 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7989 librbd::ImageOptions image_options
;
7991 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7994 librbd::image_migration_status_t status
;
7995 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
7997 ASSERT_EQ(status
.source_pool_id
, ioctx
.get_id());
7998 ASSERT_EQ(status
.source_image_name
, name
);
8000 ASSERT_EQ(status
.source_image_id
, "");
8002 ASSERT_NE(status
.source_image_id
, "");
8003 ASSERT_EQ(-EROFS
, rbd
.trash_remove(ioctx
, status
.source_image_id
.c_str(), false));
8004 ASSERT_EQ(-EINVAL
, rbd
.trash_restore(ioctx
, status
.source_image_id
.c_str(), name
.c_str()));
8006 ASSERT_EQ(status
.dest_pool_id
, ioctx
.get_id());
8007 ASSERT_EQ(status
.dest_image_name
, name
);
8008 ASSERT_NE(status
.dest_image_id
, "");
8009 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
8011 librbd::Image image
;
8012 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8013 std::string source_spec
;
8014 ASSERT_EQ(0, image
.get_migration_source_spec(&source_spec
));
8015 json_spirit::mValue json_source_spec
;
8016 json_spirit::read(source_spec
, json_source_spec
);
8017 json_spirit::mObject json_source_spec_obj
= json_source_spec
.get_obj();
8018 ASSERT_EQ("native", json_source_spec_obj
["type"].get_str());
8019 ASSERT_EQ(ioctx
.get_id(), json_source_spec_obj
["pool_id"].get_int64());
8020 ASSERT_EQ("", json_source_spec_obj
["pool_namespace"].get_str());
8021 ASSERT_EQ(1, json_source_spec_obj
.count("image_name"));
8023 ASSERT_EQ(1, json_source_spec_obj
.count("image_id"));
8025 ASSERT_EQ(0, image
.close());
8027 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, name
.c_str()));
8028 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
8030 ASSERT_EQ(0, rbd
.migration_execute(ioctx
, name
.c_str()));
8032 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
8034 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
8036 ASSERT_EQ(0, rbd
.migration_commit(ioctx
, name
.c_str()));
8038 std::string new_name
= get_temp_image_name();
8040 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
,
8041 new_name
.c_str(), image_options
));
8043 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, new_name
.c_str()));
8044 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, new_name
.c_str(), 0));
8046 ASSERT_EQ(0, rbd
.migration_abort(ioctx
, name
.c_str()));
8048 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8051 TEST_F(TestLibRBD
, TestGetAccessTimestamp
)
8053 REQUIRE_FORMAT_V2();
8055 rados_ioctx_t ioctx
;
8056 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8060 std::string name
= get_temp_image_name();
8061 uint64_t size
= 2 << 20;
8062 struct timespec timestamp
;
8064 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8065 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8067 ASSERT_EQ(0, rbd_get_access_timestamp(image
, ×tamp
));
8068 ASSERT_LT(0, timestamp
.tv_sec
);
8070 ASSERT_PASSED(validate_object_map
, image
);
8071 ASSERT_EQ(0, rbd_close(image
));
8073 rados_ioctx_destroy(ioctx
);
8076 TEST_F(TestLibRBD
, TestGetModifyTimestamp
)
8078 REQUIRE_FORMAT_V2();
8080 rados_ioctx_t ioctx
;
8081 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8085 std::string name
= get_temp_image_name();
8086 uint64_t size
= 2 << 20;
8087 struct timespec timestamp
;
8089 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8090 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8091 ASSERT_EQ(0, rbd_get_modify_timestamp(image
, ×tamp
));
8092 ASSERT_LT(0, timestamp
.tv_sec
);
8094 ASSERT_PASSED(validate_object_map
, image
);
8095 ASSERT_EQ(0, rbd_close(image
));
8097 rados_ioctx_destroy(ioctx
);
8100 TEST_F(TestLibRBD
, ZeroOverlapFlatten
) {
8101 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8103 librados::IoCtx ioctx
;
8104 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8107 librbd::Image parent_image
;
8108 std::string name
= get_temp_image_name();
8113 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8114 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
8117 ASSERT_EQ(0, parent_image
.features(&features
));
8119 ASSERT_EQ(0, parent_image
.snap_create("snap"));
8120 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
8122 std::string clone_name
= this->get_temp_image_name();
8123 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
8126 librbd::Image clone_image
;
8127 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
8128 ASSERT_EQ(0, clone_image
.resize(0));
8129 ASSERT_EQ(0, clone_image
.flatten());
8132 TEST_F(TestLibRBD
, PoolMetadata
)
8134 REQUIRE_FORMAT_V2();
8136 rados_ioctx_t ioctx
;
8137 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8141 size_t keys_len
= sizeof(keys
);
8142 size_t vals_len
= sizeof(vals
);
8144 memset_rand(keys
, keys_len
);
8145 memset_rand(vals
, vals_len
);
8147 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8149 ASSERT_EQ(0U, keys_len
);
8150 ASSERT_EQ(0U, vals_len
);
8153 size_t value_len
= sizeof(value
);
8154 memset_rand(value
, value_len
);
8156 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
8157 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key2", "value2"));
8158 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
8159 ASSERT_STREQ(value
, "value1");
8161 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
8162 ASSERT_EQ(value_len
, strlen("value1") + 1);
8164 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8166 keys_len
= sizeof(keys
);
8167 vals_len
= sizeof(vals
);
8168 memset_rand(keys
, keys_len
);
8169 memset_rand(vals
, vals_len
);
8170 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8172 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
8173 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
8174 ASSERT_STREQ(keys
, "key1");
8175 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
8176 ASSERT_STREQ(vals
, "value1");
8177 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
8179 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
8180 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_remove(ioctx
, "key3"));
8181 value_len
= sizeof(value
);
8182 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_get(ioctx
, "key3", value
, &value_len
));
8183 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8185 ASSERT_EQ(keys_len
, strlen("key2") + 1);
8186 ASSERT_EQ(vals_len
, strlen("value2") + 1);
8187 ASSERT_STREQ(keys
, "key2");
8188 ASSERT_STREQ(vals
, "value2");
8190 // test config setting
8191 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
8192 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8193 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
8194 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8196 // test short buffer cases
8197 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
8198 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key3", "value3"));
8199 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key4", "value4"));
8201 keys_len
= strlen("key1") + 1;
8202 vals_len
= strlen("value1") + 1;
8203 memset_rand(keys
, keys_len
);
8204 memset_rand(vals
, vals_len
);
8205 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 1, keys
, &keys_len
, vals
,
8207 ASSERT_EQ(keys_len
, strlen("key1") + 1);
8208 ASSERT_EQ(vals_len
, strlen("value1") + 1);
8209 ASSERT_STREQ(keys
, "key1");
8210 ASSERT_STREQ(vals
, "value1");
8212 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 2, keys
, &keys_len
, vals
,
8214 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
8215 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
8217 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8219 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
8220 1 + strlen("key4") + 1);
8221 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
8222 strlen("value3") + 1 + strlen("value4") + 1);
8224 // test `start` param
8225 keys_len
= sizeof(keys
);
8226 vals_len
= sizeof(vals
);
8227 memset_rand(keys
, keys_len
);
8228 memset_rand(vals
, vals_len
);
8229 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "key2", 0, keys
, &keys_len
, vals
,
8231 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
8232 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
8233 ASSERT_STREQ(keys
, "key3");
8234 ASSERT_STREQ(vals
, "value3");
8237 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
8238 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key2"));
8239 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key3"));
8240 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key4"));
8241 rados_ioctx_destroy(ioctx
);
8244 TEST_F(TestLibRBD
, PoolMetadataPP
)
8246 REQUIRE_FORMAT_V2();
8250 map
<string
, bufferlist
> pairs
;
8252 librados::IoCtx ioctx
;
8253 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8255 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
8256 ASSERT_TRUE(pairs
.empty());
8258 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
8259 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key2", "value2"));
8260 ASSERT_EQ(0, rbd
.pool_metadata_get(ioctx
, "key1", &value
));
8261 ASSERT_EQ(value
, "value1");
8262 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
8263 ASSERT_EQ(2U, pairs
.size());
8264 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
8265 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
8267 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
8268 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_remove(ioctx
, "key3"));
8269 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_get(ioctx
, "key3", &value
));
8271 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
8272 ASSERT_EQ(1U, pairs
.size());
8273 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
8275 // test `start` param
8276 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
8277 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key3", "value3"));
8280 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "key2", 0, &pairs
));
8281 ASSERT_EQ(1U, pairs
.size());
8282 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
8284 // test config setting
8285 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
8286 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8287 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
8288 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8291 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
8292 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key2"));
8293 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key3"));
8296 TEST_F(TestLibRBD
, Config
)
8298 REQUIRE_FORMAT_V2();
8300 rados_ioctx_t ioctx
;
8301 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8303 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8305 rbd_config_option_t options
[1024];
8306 int max_options
= 0;
8307 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
8308 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
8309 ASSERT_GT(max_options
, 0);
8310 ASSERT_LT(max_options
, 1024);
8311 for (int i
= 0; i
< max_options
; i
++) {
8312 if (options
[i
].name
== std::string("rbd_cache")) {
8313 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
8314 ASSERT_STREQ("false", options
[i
].value
);
8316 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8319 rbd_config_pool_list_cleanup(options
, max_options
);
8323 std::string name
= get_temp_image_name();
8324 uint64_t size
= 2 << 20;
8326 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8327 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8329 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
8330 for (int i
= 0; i
< max_options
; i
++) {
8331 if (options
[i
].name
== std::string("rbd_cache")) {
8332 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
8333 ASSERT_STREQ("false", options
[i
].value
);
8335 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8338 rbd_config_image_list_cleanup(options
, max_options
);
8340 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_cache", "true"));
8342 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
8343 for (int i
= 0; i
< max_options
; i
++) {
8344 if (options
[i
].name
== std::string("rbd_cache")) {
8345 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_IMAGE
);
8346 ASSERT_STREQ("true", options
[i
].value
);
8348 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8351 rbd_config_image_list_cleanup(options
, max_options
);
8353 ASSERT_EQ(0, rbd_metadata_remove(image
, "conf_rbd_cache"));
8355 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
8356 for (int i
= 0; i
< max_options
; i
++) {
8357 if (options
[i
].name
== std::string("rbd_cache")) {
8358 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
8359 ASSERT_STREQ("false", options
[i
].value
);
8361 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8364 rbd_config_image_list_cleanup(options
, max_options
);
8366 ASSERT_EQ(0, rbd_close(image
));
8368 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8370 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
8371 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
8372 for (int i
= 0; i
< max_options
; i
++) {
8373 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8375 rbd_config_pool_list_cleanup(options
, max_options
);
8377 rados_ioctx_destroy(ioctx
);
8380 TEST_F(TestLibRBD
, ConfigPP
)
8382 REQUIRE_FORMAT_V2();
8387 librados::IoCtx ioctx
;
8388 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8390 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8392 std::vector
<librbd::config_option_t
> options
;
8393 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
8394 for (auto &option
: options
) {
8395 if (option
.name
== std::string("rbd_cache")) {
8396 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
8397 ASSERT_EQ("false", option
.value
);
8399 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8404 std::string name
= get_temp_image_name();
8405 uint64_t size
= 2 << 20;
8406 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8408 librbd::Image image
;
8409 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
8412 ASSERT_EQ(0, image
.config_list(&options
));
8413 for (auto &option
: options
) {
8414 if (option
.name
== std::string("rbd_cache")) {
8415 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
8416 ASSERT_EQ("false", option
.value
);
8418 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8422 ASSERT_EQ(0, image
.metadata_set("conf_rbd_cache", "true"));
8425 ASSERT_EQ(0, image
.config_list(&options
));
8426 for (auto &option
: options
) {
8427 if (option
.name
== std::string("rbd_cache")) {
8428 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_IMAGE
);
8429 ASSERT_EQ("true", option
.value
);
8431 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8435 ASSERT_EQ(0, image
.metadata_remove("conf_rbd_cache"));
8438 ASSERT_EQ(0, image
.config_list(&options
));
8439 for (auto &option
: options
) {
8440 if (option
.name
== std::string("rbd_cache")) {
8441 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
8442 ASSERT_EQ("false", option
.value
);
8444 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8448 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8451 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
8452 for (auto &option
: options
) {
8453 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8457 TEST_F(TestLibRBD
, PoolStatsPP
)
8459 REQUIRE_FORMAT_V2();
8461 librados::IoCtx ioctx
;
8462 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
8465 std::string image_name
;
8466 uint64_t size
= 2 << 20;
8467 uint64_t expected_size
= 0;
8468 for (size_t idx
= 0; idx
< 4; ++idx
) {
8469 image_name
= get_temp_image_name();
8472 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, image_name
.c_str(), size
, &order
));
8473 expected_size
+= size
;
8476 librbd::Image image
;
8477 ASSERT_EQ(0, rbd
.open(ioctx
, image
, image_name
.c_str(), NULL
));
8478 ASSERT_EQ(0, image
.snap_create("snap1"));
8479 ASSERT_EQ(0, image
.resize(0));
8480 ASSERT_EQ(0, image
.close());
8481 uint64_t expect_head_size
= (expected_size
- size
);
8483 uint64_t image_count
;
8484 uint64_t provisioned_bytes
;
8485 uint64_t max_provisioned_bytes
;
8486 uint64_t snap_count
;
8487 uint64_t trash_image_count
;
8488 uint64_t trash_provisioned_bytes
;
8489 uint64_t trash_max_provisioned_bytes
;
8490 uint64_t trash_snap_count
;
8492 librbd::PoolStats pool_stats1
;
8493 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGES
, &image_count
);
8494 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
,
8495 &provisioned_bytes
);
8496 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
8498 ASSERT_EQ(4U, image_count
);
8499 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
8501 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
,
8502 &max_provisioned_bytes
);
8503 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
8504 ASSERT_EQ(4U, image_count
);
8505 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
8506 ASSERT_EQ(expected_size
, max_provisioned_bytes
);
8508 librbd::PoolStats pool_stats2
;
8509 pool_stats2
.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
, &snap_count
);
8510 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
8511 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
8512 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats2
));
8513 ASSERT_EQ(1U, snap_count
);
8514 ASSERT_EQ(0U, trash_image_count
);
8515 ASSERT_EQ(0U, trash_snap_count
);
8517 ASSERT_EQ(0, rbd
.trash_move(ioctx
, image_name
.c_str(), 0));
8519 librbd::PoolStats pool_stats3
;
8520 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
8521 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
,
8522 &trash_provisioned_bytes
);
8523 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
,
8524 &trash_max_provisioned_bytes
);
8525 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
8526 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats3
));
8527 ASSERT_EQ(1U, trash_image_count
);
8528 ASSERT_EQ(0U, trash_provisioned_bytes
);
8529 ASSERT_EQ(size
, trash_max_provisioned_bytes
);
8530 ASSERT_EQ(1U, trash_snap_count
);
8533 TEST_F(TestLibRBD
, ImageSpec
) {
8534 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8536 librados::IoCtx ioctx
;
8537 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
8540 librbd::Image parent_image
;
8541 std::string name
= get_temp_image_name();
8546 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8547 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
8549 std::string parent_id
;
8550 ASSERT_EQ(0, parent_image
.get_id(&parent_id
));
8553 ASSERT_EQ(0, parent_image
.features(&features
));
8555 ASSERT_EQ(0, parent_image
.snap_create("snap"));
8556 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
8558 std::string clone_name
= this->get_temp_image_name();
8559 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
8562 librbd::Image clone_image
;
8563 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
8565 std::string clone_id
;
8566 ASSERT_EQ(0, clone_image
.get_id(&clone_id
));
8568 std::vector
<librbd::image_spec_t
> images
;
8569 ASSERT_EQ(0, rbd
.list2(ioctx
, &images
));
8571 std::vector
<librbd::image_spec_t
> expected_images
{
8572 {.id
= parent_id
, .name
= name
},
8573 {.id
= clone_id
, .name
= clone_name
}
8575 std::sort(expected_images
.begin(), expected_images
.end(),
8576 [](const librbd::image_spec_t
& lhs
, const librbd::image_spec_t
&rhs
) {
8577 return lhs
.name
< rhs
.name
;
8579 ASSERT_EQ(expected_images
, images
);
8581 librbd::linked_image_spec_t parent_image_spec
;
8582 librbd::snap_spec_t parent_snap_spec
;
8583 ASSERT_EQ(0, clone_image
.get_parent(&parent_image_spec
, &parent_snap_spec
));
8585 librbd::linked_image_spec_t expected_parent_image_spec
{
8586 .pool_id
= ioctx
.get_id(),
8587 .pool_name
= ioctx
.get_pool_name(),
8588 .pool_namespace
= ioctx
.get_namespace(),
8589 .image_id
= parent_id
,
8593 ASSERT_EQ(expected_parent_image_spec
, parent_image_spec
);
8594 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER
, parent_snap_spec
.namespace_type
);
8595 ASSERT_EQ("snap", parent_snap_spec
.name
);
8597 std::vector
<librbd::linked_image_spec_t
> children
;
8598 ASSERT_EQ(0, parent_image
.list_children3(&children
));
8600 std::vector
<librbd::linked_image_spec_t
> expected_children
{
8602 .pool_id
= ioctx
.get_id(),
8603 .pool_name
= ioctx
.get_pool_name(),
8604 .pool_namespace
= ioctx
.get_namespace(),
8605 .image_id
= clone_id
,
8606 .image_name
= clone_name
,
8610 ASSERT_EQ(expected_children
, children
);
8613 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
8614 ASSERT_EQ(expected_children
, children
);
8616 ASSERT_EQ(0, clone_image
.snap_create("snap"));
8617 ASSERT_EQ(0, clone_image
.snap_protect("snap"));
8619 auto grand_clone_name
= this->get_temp_image_name();
8620 ASSERT_EQ(0, rbd
.clone(ioctx
, clone_name
.c_str(), "snap", ioctx
,
8621 grand_clone_name
.c_str(), features
, &order
));
8622 librbd::Image grand_clone_image
;
8623 ASSERT_EQ(0, rbd
.open(ioctx
, grand_clone_image
, grand_clone_name
.c_str(),
8625 std::string grand_clone_id
;
8626 ASSERT_EQ(0, grand_clone_image
.get_id(&grand_clone_id
));
8629 ASSERT_EQ(0, parent_image
.list_children3(&children
));
8630 ASSERT_EQ(expected_children
, children
);
8633 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
8634 expected_children
.push_back(
8636 .pool_id
= ioctx
.get_id(),
8637 .pool_name
= ioctx
.get_pool_name(),
8638 .pool_namespace
= ioctx
.get_namespace(),
8639 .image_id
= grand_clone_id
,
8640 .image_name
= grand_clone_name
,
8644 ASSERT_EQ(expected_children
, children
);
8647 void super_simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
8651 TEST_F(TestLibRBD
, DISABLED_TestSeqWriteAIOPP
)
8653 librados::IoCtx ioctx
;
8654 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8658 librbd::Image image
;
8660 std::string name
= get_temp_image_name();
8661 uint64_t size
= 5 * (1 << order
);
8663 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8664 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8666 char test_data
[(TEST_IO_SIZE
+ 1) * 10];
8668 for (int i
= 0; i
< 10; i
++) {
8669 for (uint64_t j
= 0; j
< TEST_IO_SIZE
; j
++) {
8670 test_data
[(TEST_IO_SIZE
+ 1) * i
+ j
] = (char)(rand() % (126 - 33) + 33);
8672 test_data
[(TEST_IO_SIZE
+ 1) * i
+ TEST_IO_SIZE
] = '\0';
8675 struct timespec start_time
;
8676 clock_gettime(CLOCK_REALTIME
, &start_time
);
8678 std::list
<librbd::RBD::AioCompletion
*> comps
;
8679 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
8680 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
8681 ceph::bufferlist bl
;
8682 bl
.append(p
, strlen(p
));
8683 auto comp
= new librbd::RBD::AioCompletion(
8684 NULL
, (librbd::callback_t
) super_simple_write_cb_pp
);
8685 image
.aio_write(strlen(p
) * i
, strlen(p
), bl
, comp
);
8686 comps
.push_back(comp
);
8687 if (i
% 1000 == 0) {
8688 cout
<< i
<< " reqs sent" << std::endl
;
8690 for (auto comp
: comps
) {
8691 comp
->wait_for_complete();
8692 ASSERT_EQ(0, comp
->get_return_value());
8699 for (auto comp
: comps
) {
8700 comp
->wait_for_complete();
8701 ASSERT_EQ(0, comp
->get_return_value());
8703 if (i
% 1000 == 0) {
8704 std::cout
<< i
<< " reqs completed" << std::endl
;
8710 struct timespec end_time
;
8711 clock_gettime(CLOCK_REALTIME
, &end_time
);
8712 int duration
= end_time
.tv_sec
* 1000 + end_time
.tv_nsec
/ 1000000 -
8713 start_time
.tv_sec
* 1000 - start_time
.tv_nsec
/ 1000000;
8714 std::cout
<< "duration: " << duration
<< " msec" << std::endl
;
8716 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
8717 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
8718 ASSERT_PASSED(read_test_data
, image
, p
, strlen(p
) * i
, TEST_IO_SIZE
, 0);
8721 ASSERT_PASSED(validate_object_map
, image
);
8727 TEST_F(TestLibRBD
, SnapRemoveWithChildMissing
)
8729 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8730 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
8731 BOOST_SCOPE_EXIT_ALL(&) {
8732 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
8736 rados_ioctx_t ioctx1
, ioctx2
;
8737 string pool_name1
= create_pool(true);
8738 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
8739 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx2
));
8743 rbd_image_t parent
, child1
, child2
, child3
;
8745 char child_id1
[4096];
8746 char child_id2
[4096];
8747 char child_id3
[4096];
8749 ASSERT_EQ(0, get_features(&old_format
, &features
));
8750 ASSERT_FALSE(old_format
);
8751 std::string parent_name
= get_temp_image_name();
8752 std::string child_name1
= get_temp_image_name();
8753 std::string child_name2
= get_temp_image_name();
8754 std::string child_name3
= get_temp_image_name();
8755 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
8757 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
8758 ASSERT_EQ(0, rbd_snap_create(parent
, "snap1"));
8759 ASSERT_EQ(0, rbd_snap_create(parent
, "snap2"));
8761 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap1",
8762 ioctx2
, child_name1
.c_str(), features
, &order
));
8763 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
8764 ioctx1
, child_name2
.c_str(), features
, &order
));
8765 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
8766 ioctx2
, child_name3
.c_str(), features
, &order
));
8768 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &child1
, NULL
));
8769 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &child2
, NULL
));
8770 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &child3
, NULL
));
8771 ASSERT_EQ(0, rbd_get_id(child1
, child_id1
, sizeof(child_id1
)));
8772 ASSERT_EQ(0, rbd_get_id(child2
, child_id2
, sizeof(child_id2
)));
8773 ASSERT_EQ(0, rbd_get_id(child3
, child_id3
, sizeof(child_id3
)));
8774 test_list_children2(parent
, 3,
8775 child_id1
, m_pool_name
.c_str(), child_name1
.c_str(), false,
8776 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
8777 child_id3
, m_pool_name
.c_str(), child_name3
.c_str(), false);
8779 size_t max_size
= 10;
8780 rbd_linked_image_spec_t children
[max_size
];
8781 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8782 ASSERT_EQ(3, static_cast<int>(max_size
));
8783 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8785 ASSERT_EQ(0, rbd_close(child1
));
8786 ASSERT_EQ(0, rbd_close(child2
));
8787 ASSERT_EQ(0, rbd_close(child3
));
8788 rados_ioctx_destroy(ioctx2
);
8789 ASSERT_EQ(0, rados_pool_delete(_cluster
, m_pool_name
.c_str()));
8790 _pool_names
.erase(std::remove(_pool_names
.begin(),
8791 _pool_names
.end(), m_pool_name
),
8793 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
8795 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8796 ASSERT_EQ(3, static_cast<int>(max_size
));
8797 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8798 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap1"));
8799 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8800 ASSERT_EQ(2, static_cast<int>(max_size
));
8801 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8803 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
8804 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8805 ASSERT_EQ(1, static_cast<int>(max_size
));
8806 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8808 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap2"));
8809 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8810 ASSERT_EQ(0, static_cast<int>(max_size
));
8811 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8812 test_list_children2(parent
, 0);
8813 ASSERT_EQ(0, test_ls_snaps(parent
, 0));
8815 ASSERT_EQ(0, rbd_close(parent
));
8816 rados_ioctx_destroy(ioctx1
);
8819 TEST_F(TestLibRBD
, QuiesceWatch
)
8821 rados_ioctx_t ioctx
;
8822 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8825 std::string name
= get_temp_image_name();
8826 uint64_t size
= 2 << 20;
8827 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8829 rbd_image_t image1
, image2
;
8830 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
8831 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
8834 static void quiesce_cb(void *arg
) {
8835 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
8836 watcher
->handle_quiesce();
8838 static void unquiesce_cb(void *arg
) {
8839 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
8840 watcher
->handle_unquiesce();
8844 uint64_t handle
= 0;
8845 size_t quiesce_count
= 0;
8846 size_t unquiesce_count
= 0;
8848 ceph::mutex lock
= ceph::make_mutex("lock");
8849 ceph::condition_variable cv
;
8851 Watcher(rbd_image_t
&image
) : image(image
) {
8854 void handle_quiesce() {
8855 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8857 rbd_quiesce_complete(image
, handle
, 0);
8859 void handle_unquiesce() {
8860 std::unique_lock
locker(lock
);
8862 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8865 bool wait_for_unquiesce(size_t c
) {
8866 std::unique_lock
locker(lock
);
8867 return cv
.wait_for(locker
, seconds(60),
8868 [this, c
]() { return unquiesce_count
>= c
; });
8870 } watcher1(image1
), watcher2(image2
);
8872 ASSERT_EQ(0, rbd_quiesce_watch(image1
, Watcher::quiesce_cb
,
8873 Watcher::unquiesce_cb
, &watcher1
,
8875 ASSERT_EQ(0, rbd_quiesce_watch(image2
, Watcher::quiesce_cb
,
8876 Watcher::unquiesce_cb
, &watcher2
,
8879 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
8880 ASSERT_EQ(1U, watcher1
.quiesce_count
);
8881 ASSERT_TRUE(watcher1
.wait_for_unquiesce(1U));
8882 ASSERT_EQ(1U, watcher2
.quiesce_count
);
8883 ASSERT_TRUE(watcher2
.wait_for_unquiesce(1U));
8885 ASSERT_EQ(0, rbd_snap_create(image2
, "snap2"));
8886 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8887 ASSERT_TRUE(watcher1
.wait_for_unquiesce(2U));
8888 ASSERT_EQ(2U, watcher2
.quiesce_count
);
8889 ASSERT_TRUE(watcher2
.wait_for_unquiesce(2U));
8891 ASSERT_EQ(0, rbd_quiesce_unwatch(image1
, watcher1
.handle
));
8893 ASSERT_EQ(0, rbd_snap_create(image1
, "snap3"));
8894 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8895 ASSERT_EQ(2U, watcher1
.unquiesce_count
);
8896 ASSERT_EQ(3U, watcher2
.quiesce_count
);
8897 ASSERT_TRUE(watcher2
.wait_for_unquiesce(3U));
8899 ASSERT_EQ(0, rbd_quiesce_unwatch(image2
, watcher2
.handle
));
8901 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap1"));
8902 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap2"));
8903 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap3"));
8904 ASSERT_EQ(0, rbd_close(image1
));
8905 ASSERT_EQ(0, rbd_close(image2
));
8906 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
8907 rados_ioctx_destroy(ioctx
);
8910 TEST_F(TestLibRBD
, QuiesceWatchPP
)
8913 librados::IoCtx ioctx
;
8914 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8915 std::string name
= get_temp_image_name();
8917 uint64_t size
= 2 << 20;
8918 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8921 librbd::Image image1
, image2
;
8922 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8923 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8925 struct Watcher
: public librbd::QuiesceWatchCtx
{
8926 librbd::Image
&image
;
8927 uint64_t handle
= 0;
8928 size_t quiesce_count
= 0;
8929 size_t unquiesce_count
= 0;
8931 ceph::mutex lock
= ceph::make_mutex("lock");
8932 ceph::condition_variable cv
;
8934 Watcher(librbd::Image
&image
) : image(image
) {
8937 void handle_quiesce() override
{
8938 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8940 image
.quiesce_complete(handle
, 0);
8942 void handle_unquiesce() override
{
8943 std::unique_lock
locker(lock
);
8945 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8948 bool wait_for_unquiesce(size_t c
) {
8949 std::unique_lock
locker(lock
);
8950 return cv
.wait_for(locker
, seconds(60),
8951 [this, c
]() { return unquiesce_count
>= c
; });
8953 } watcher1(image1
), watcher2(image2
);
8955 ASSERT_EQ(0, image1
.quiesce_watch(&watcher1
, &watcher1
.handle
));
8956 ASSERT_EQ(0, image2
.quiesce_watch(&watcher2
, &watcher2
.handle
));
8958 ASSERT_EQ(0, image1
.snap_create("snap1"));
8959 ASSERT_EQ(1U, watcher1
.quiesce_count
);
8960 ASSERT_TRUE(watcher1
.wait_for_unquiesce(1U));
8961 ASSERT_EQ(1U, watcher2
.quiesce_count
);
8962 ASSERT_TRUE(watcher2
.wait_for_unquiesce(1U));
8964 ASSERT_EQ(0, image2
.snap_create("snap2"));
8965 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8966 ASSERT_TRUE(watcher1
.wait_for_unquiesce(2U));
8967 ASSERT_EQ(2U, watcher2
.quiesce_count
);
8968 ASSERT_TRUE(watcher2
.wait_for_unquiesce(2U));
8970 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher1
.handle
));
8972 ASSERT_EQ(0, image1
.snap_create("snap3"));
8973 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8974 ASSERT_EQ(2U, watcher1
.unquiesce_count
);
8975 ASSERT_EQ(3U, watcher2
.quiesce_count
);
8976 ASSERT_TRUE(watcher2
.wait_for_unquiesce(3U));
8978 ASSERT_EQ(0, image2
.quiesce_unwatch(watcher2
.handle
));
8980 ASSERT_EQ(0, image1
.snap_remove("snap1"));
8981 ASSERT_EQ(0, image1
.snap_remove("snap2"));
8982 ASSERT_EQ(0, image1
.snap_remove("snap3"));
8985 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
8989 TEST_F(TestLibRBD
, QuiesceWatchError
)
8992 librados::IoCtx ioctx
;
8993 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8994 std::string name
= get_temp_image_name();
8996 uint64_t size
= 2 << 20;
8997 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9000 librbd::Image image1
, image2
;
9001 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9002 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9004 struct Watcher
: public librbd::QuiesceWatchCtx
{
9005 librbd::Image
&image
;
9008 size_t quiesce_count
= 0;
9009 size_t unquiesce_count
= 0;
9011 ceph::mutex lock
= ceph::make_mutex("lock");
9012 ceph::condition_variable cv
;
9014 Watcher(librbd::Image
&image
, int r
) : image(image
), r(r
) {
9017 void reset_counters() {
9019 unquiesce_count
= 0;
9022 void handle_quiesce() override
{
9024 image
.quiesce_complete(handle
, r
);
9027 void handle_unquiesce() override
{
9028 std::unique_lock
locker(lock
);
9033 bool wait_for_unquiesce() {
9034 std::unique_lock
locker(lock
);
9035 return cv
.wait_for(locker
, seconds(60),
9037 return quiesce_count
== unquiesce_count
;
9040 } watcher10(image1
, -EINVAL
), watcher11(image1
, 0), watcher20(image2
, 0);
9042 ASSERT_EQ(0, image1
.quiesce_watch(&watcher10
, &watcher10
.handle
));
9043 ASSERT_EQ(0, image1
.quiesce_watch(&watcher11
, &watcher11
.handle
));
9044 ASSERT_EQ(0, image2
.quiesce_watch(&watcher20
, &watcher20
.handle
));
9046 ASSERT_EQ(-EINVAL
, image1
.snap_create("snap1"));
9047 ASSERT_GT(watcher10
.quiesce_count
, 0U);
9048 ASSERT_EQ(watcher10
.unquiesce_count
, 0U);
9049 ASSERT_GT(watcher11
.quiesce_count
, 0U);
9050 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
9051 ASSERT_GT(watcher20
.quiesce_count
, 0U);
9052 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
9054 PrintProgress prog_ctx
;
9055 watcher10
.reset_counters();
9056 watcher11
.reset_counters();
9057 watcher20
.reset_counters();
9058 ASSERT_EQ(0, image2
.snap_create2("snap2",
9059 RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR
,
9061 ASSERT_GT(watcher10
.quiesce_count
, 0U);
9062 ASSERT_EQ(watcher10
.unquiesce_count
, 0U);
9063 ASSERT_GT(watcher11
.quiesce_count
, 0U);
9064 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
9065 ASSERT_GT(watcher20
.quiesce_count
, 0U);
9066 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
9068 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher10
.handle
));
9070 watcher11
.reset_counters();
9071 watcher20
.reset_counters();
9072 ASSERT_EQ(0, image1
.snap_create("snap3"));
9073 ASSERT_GT(watcher11
.quiesce_count
, 0U);
9074 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
9075 ASSERT_GT(watcher20
.quiesce_count
, 0U);
9076 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
9078 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher11
.handle
));
9080 watcher20
.reset_counters();
9081 ASSERT_EQ(0, image2
.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE
,
9083 ASSERT_EQ(watcher20
.quiesce_count
, 0U);
9084 ASSERT_EQ(watcher20
.unquiesce_count
, 0U);
9086 ASSERT_EQ(0, image2
.quiesce_unwatch(watcher20
.handle
));
9088 ASSERT_EQ(0, image1
.snap_remove("snap2"));
9089 ASSERT_EQ(0, image1
.snap_remove("snap3"));
9090 ASSERT_EQ(0, image1
.snap_remove("snap4"));
9093 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
9097 TEST_F(TestLibRBD
, QuiesceWatchTimeout
)
9099 REQUIRE(!is_librados_test_stub(_rados
));
9101 ASSERT_EQ(0, _rados
.conf_set("rbd_quiesce_notification_attempts", "2"));
9104 librados::IoCtx ioctx
;
9105 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9106 std::string name
= get_temp_image_name();
9108 uint64_t size
= 2 << 20;
9109 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9112 librbd::Image image
;
9113 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9115 struct Watcher
: public librbd::QuiesceWatchCtx
{
9116 librbd::Image
&image
;
9118 std::condition_variable m_cond
;
9119 size_t quiesce_count
= 0;
9120 size_t unquiesce_count
= 0;
9122 Watcher(librbd::Image
&image
) : image(image
) {
9125 void handle_quiesce() override
{
9126 std::lock_guard
<std::mutex
> locker(m_lock
);
9128 m_cond
.notify_one();
9131 void handle_unquiesce() override
{
9132 std::lock_guard
<std::mutex
> locker(m_lock
);
9134 m_cond
.notify_one();
9137 void wait_for_quiesce() {
9138 std::unique_lock
<std::mutex
> locker(m_lock
);
9139 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(60),
9141 return quiesce_count
>= 1;
9145 void wait_for_unquiesce() {
9146 std::unique_lock
<std::mutex
> locker(m_lock
);
9147 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(60),
9149 return quiesce_count
== unquiesce_count
;
9151 quiesce_count
= unquiesce_count
= 0;
9156 ASSERT_EQ(0, image
.quiesce_watch(&watcher
, &handle
));
9158 std::cerr
<< "test quiesce is not long enough to time out" << std::endl
;
9160 thread
quiesce1([&image
, &watcher
, handle
]() {
9161 watcher
.wait_for_quiesce();
9163 image
.quiesce_complete(handle
, 0);
9166 ASSERT_EQ(0, image
.snap_create("snap1"));
9168 ASSERT_GE(watcher
.quiesce_count
, 1U);
9169 watcher
.wait_for_unquiesce();
9171 std::cerr
<< "test quiesce is timed out" << std::endl
;
9173 bool timed_out
= false;
9174 thread
quiesce2([&image
, &watcher
, handle
, &timed_out
]() {
9175 watcher
.wait_for_quiesce();
9176 for (int i
= 0; !timed_out
&& i
< 60; i
++) {
9177 std::cerr
<< "waiting for timed out ... " << i
<< std::endl
;
9180 image
.quiesce_complete(handle
, 0);
9183 ASSERT_EQ(-ETIMEDOUT
, image
.snap_create("snap2"));
9186 ASSERT_GE(watcher
.quiesce_count
, 1U);
9187 watcher
.wait_for_unquiesce();
9189 thread
quiesce3([&image
, handle
, &watcher
]() {
9190 watcher
.wait_for_quiesce();
9191 image
.quiesce_complete(handle
, 0);
9194 std::cerr
<< "test retry succeeds" << std::endl
;
9196 ASSERT_EQ(0, image
.snap_create("snap2"));
9198 ASSERT_GE(watcher
.quiesce_count
, 1U);
9199 watcher
.wait_for_unquiesce();
9201 ASSERT_EQ(0, image
.snap_remove("snap1"));
9202 ASSERT_EQ(0, image
.snap_remove("snap2"));
9205 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
9209 TEST_F(TestLibRBD
, WriteZeroes
) {
9211 librados::IoCtx ioctx
;
9212 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9213 std::string name
= get_temp_image_name();
9215 uint64_t size
= 2 << 20;
9216 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9218 librbd::Image image
;
9219 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9221 // 1s from [0, 256) / length 256
9223 memset(data
, 1, sizeof(data
));
9225 bl
.append(data
, 256);
9226 ASSERT_EQ(256, image
.write(0, 256, bl
));
9228 interval_set
<uint64_t> diff
;
9229 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9230 iterate_cb
, (void *)&diff
));
9231 auto expected_diff
= interval_set
<uint64_t>{{{0, 256}}};
9232 ASSERT_EQ(expected_diff
, diff
);
9234 // writes zero passed the current end extents.
9235 // Now 1s from [0, 192) / length 192
9236 ASSERT_EQ(size
- 192,
9237 image
.write_zeroes(192, size
- 192, 0U, 0));
9239 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9240 iterate_cb
, (void *)&diff
));
9241 expected_diff
= interval_set
<uint64_t>{{{0, 192}}};
9242 ASSERT_EQ(expected_diff
, diff
);
9244 // zero an existing extent and truncate some off the end
9245 // Now 1s from [64, 192) / length 192
9246 ASSERT_EQ(64, image
.write_zeroes(0, 64, 0U, 0));
9249 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9250 iterate_cb
, (void *)&diff
));
9251 expected_diff
= interval_set
<uint64_t>{{{0, 192}}};
9252 ASSERT_EQ(expected_diff
, diff
);
9254 bufferlist expected_bl
;
9255 expected_bl
.append_zero(64);
9257 sub_bl
.substr_of(bl
, 0, 128);
9258 expected_bl
.claim_append(sub_bl
);
9259 expected_bl
.append_zero(size
- 192);
9262 EXPECT_EQ(size
, image
.read(0, size
, read_bl
));
9263 EXPECT_EQ(expected_bl
, read_bl
);
9265 ASSERT_EQ(0, image
.close());
9268 TEST_F(TestLibRBD
, WriteZeroesThickProvision
) {
9270 librados::IoCtx ioctx
;
9271 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9272 std::string name
= get_temp_image_name();
9274 uint64_t size
= 2 << 20;
9275 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9277 librbd::Image image
;
9278 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9280 interval_set
<uint64_t> diff
;
9281 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9282 iterate_cb
, (void *)&diff
));
9283 auto expected_diff
= interval_set
<uint64_t>{{}};
9284 ASSERT_EQ(expected_diff
, diff
);
9286 // writes unaligned zeroes as a prepend
9287 ASSERT_EQ(128, image
.write_zeroes(
9288 0, 128, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9290 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9291 iterate_cb
, (void *)&diff
));
9292 expected_diff
= interval_set
<uint64_t>{{{0, 128}}};
9293 ASSERT_EQ(expected_diff
, diff
);
9295 ASSERT_EQ(512, image
.write_zeroes(
9296 384, 512, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9298 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9299 iterate_cb
, (void *)&diff
));
9300 expected_diff
= interval_set
<uint64_t>{{{0, 896}}};
9301 ASSERT_EQ(expected_diff
, diff
);
9303 // prepend with write-same
9304 ASSERT_EQ(640, image
.write_zeroes(
9305 896, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9307 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9308 iterate_cb
, (void *)&diff
));
9309 expected_diff
= interval_set
<uint64_t>{{{0, 1536}}};
9310 ASSERT_EQ(expected_diff
, diff
);
9312 // write-same with append
9313 ASSERT_EQ(640, image
.write_zeroes(
9314 1536, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9316 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9317 iterate_cb
, (void *)&diff
));
9318 expected_diff
= interval_set
<uint64_t>{{{0, 2176}}};
9319 ASSERT_EQ(expected_diff
, diff
);
9321 // prepend + write-same + append
9322 ASSERT_EQ(768, image
.write_zeroes(
9323 2176, 768, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9325 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9326 iterate_cb
, (void *)&diff
));
9327 expected_diff
= interval_set
<uint64_t>{{{0, 2944}}};
9330 ASSERT_EQ(1024, image
.write_zeroes(
9331 3072, 1024, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9333 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9334 iterate_cb
, (void *)&diff
));
9335 expected_diff
= interval_set
<uint64_t>{{{0, 4096}}};
9337 bufferlist expected_bl
;
9338 expected_bl
.append_zero(size
);
9341 EXPECT_EQ(size
, image
.read(0, size
, read_bl
));
9342 EXPECT_EQ(expected_bl
, read_bl
);
9344 ASSERT_EQ(0, image
.close());
9347 TEST_F(TestLibRBD
, ConcurentOperations
)
9349 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
9352 librados::IoCtx ioctx
;
9353 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9354 std::string name
= get_temp_image_name();
9356 uint64_t size
= 2 << 20;
9357 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9359 // Test creating/removing many snapshots simultaneously
9361 std::vector
<librbd::Image
> images(10);
9362 std::vector
<librbd::RBD::AioCompletion
*> comps
;
9364 for (auto &image
: images
) {
9365 auto comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
9366 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, comp
));
9367 comps
.push_back(comp
);
9370 for (auto &comp
: comps
) {
9371 ASSERT_EQ(0, comp
->wait_for_complete());
9372 ASSERT_EQ(1, comp
->is_complete());
9373 ASSERT_EQ(0, comp
->get_return_value());
9378 std::vector
<std::thread
> threads
;
9380 for (auto &image
: images
) {
9381 std::string snap_name
= "snap" + stringify(i
++);
9382 threads
.emplace_back([&image
, snap_name
]() {
9383 int r
= image
.snap_create(snap_name
.c_str());
9384 ceph_assert(r
== 0);
9388 for (auto &t
: threads
) {
9394 for (auto &image
: images
) {
9395 std::string snap_name
= "snap" + stringify(i
++);
9396 threads
.emplace_back([&image
, snap_name
](){
9397 int r
= image
.snap_remove(snap_name
.c_str());
9398 ceph_assert(r
== 0);
9402 for (auto &t
: threads
) {
9407 for (auto &image
: images
) {
9408 auto comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
9409 ASSERT_EQ(0, image
.aio_close(comp
));
9410 comps
.push_back(comp
);
9413 for (auto &comp
: comps
) {
9414 ASSERT_EQ(0, comp
->wait_for_complete());
9415 ASSERT_EQ(1, comp
->is_complete());
9416 ASSERT_EQ(0, comp
->get_return_value());
9423 librbd::Image image1
, image2
, image3
;
9424 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9425 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9426 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
9428 ASSERT_EQ(0, image1
.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE
));
9430 struct Watcher
: public librbd::QuiesceWatchCtx
{
9433 ceph::mutex lock
= ceph::make_mutex("lock");
9434 ceph::condition_variable cv
;
9436 void handle_quiesce() override
{
9437 std::unique_lock
locker(lock
);
9442 void handle_unquiesce() override
{
9445 bool wait_for_quiesce(size_t c
) {
9446 std::unique_lock
locker(lock
);
9447 return cv
.wait_for(locker
, seconds(60),
9448 [this, c
]() { return count
>= c
; });
9452 ASSERT_EQ(0, image2
.quiesce_watch(&watcher
, &handle
));
9454 auto close1_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
9456 std::thread
create_snap1([&image1
, close1_comp
]() {
9457 int r
= image1
.snap_create("snap1");
9458 ceph_assert(r
== 0);
9459 r
= image1
.aio_close(close1_comp
);
9460 ceph_assert(r
== 0);
9463 ASSERT_TRUE(watcher
.wait_for_quiesce(1));
9465 std::thread
create_snap2([&image2
]() {
9466 int r
= image2
.snap_create("snap2");
9467 ceph_assert(r
== 0);
9470 std::thread
create_snap3([&image3
]() {
9471 int r
= image3
.snap_create("snap3");
9472 ceph_assert(r
== 0);
9475 image2
.quiesce_complete(handle
, 0);
9476 create_snap1
.join();
9478 ASSERT_TRUE(watcher
.wait_for_quiesce(2));
9479 image2
.quiesce_complete(handle
, 0);
9481 ASSERT_TRUE(watcher
.wait_for_quiesce(3));
9482 image2
.quiesce_complete(handle
, 0);
9484 ASSERT_EQ(0, close1_comp
->wait_for_complete());
9485 ASSERT_EQ(1, close1_comp
->is_complete());
9486 ASSERT_EQ(0, close1_comp
->get_return_value());
9487 close1_comp
->release();
9489 create_snap2
.join();
9490 create_snap3
.join();
9492 ASSERT_EQ(0, image2
.quiesce_unwatch(handle
));
9493 ASSERT_EQ(0, image2
.snap_remove("snap1"));
9494 ASSERT_EQ(0, image2
.snap_remove("snap2"));
9495 ASSERT_EQ(0, image2
.snap_remove("snap3"));
9498 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
9503 // poorman's ceph_assert()
9505 void __ceph_assert_fail(const char *assertion
, const char *file
, int line
,
9511 #pragma GCC diagnostic pop
9512 #pragma GCC diagnostic warning "-Wpragmas"