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>
45 #include "test/librados/test.h"
46 #include "test/librados/test_cxx.h"
47 #include "test/librbd/test_support.h"
48 #include "common/event_socket.h"
49 #include "include/interval_set.h"
50 #include "include/stringify.h"
52 #include <boost/assign/list_of.hpp>
53 #include <boost/scope_exit.hpp>
56 #include <sys/eventfd.h>
59 #pragma GCC diagnostic ignored "-Wpragmas"
60 #pragma GCC diagnostic push
61 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
65 using std::chrono::seconds
;
67 #define ASSERT_PASSED(x, args...) \
69 bool passed = false; \
71 ASSERT_TRUE(passed); \
74 void register_test_librbd() {
77 static int get_features(bool *old_format
, uint64_t *features
)
79 const char *c
= getenv("RBD_FEATURES");
80 if (c
&& strlen(c
) > 0) {
87 cout
<< "using new format!" << std::endl
;
91 cout
<< "using old format" << std::endl
;
97 static int create_image_full(rados_ioctx_t ioctx
, const char *name
,
98 uint64_t size
, int *order
, int old_format
,
102 // ensure old-format tests actually use the old format
103 int r
= rados_conf_set(rados_ioctx_get_cluster(ioctx
),
104 "rbd_default_format", "1");
108 return rbd_create(ioctx
, name
, size
, order
);
109 } else if ((features
& RBD_FEATURE_STRIPINGV2
) != 0) {
110 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
112 // use a conservative stripe_unit for non default order
113 stripe_unit
= (1ull << (*order
-1));
116 printf("creating image with stripe unit: %" PRIu64
", "
117 "stripe count: %" PRIu64
"\n",
118 stripe_unit
, IMAGE_STRIPE_COUNT
);
119 return rbd_create3(ioctx
, name
, size
, features
, order
,
120 stripe_unit
, IMAGE_STRIPE_COUNT
);
122 return rbd_create2(ioctx
, name
, size
, features
, order
);
126 static int clone_image(rados_ioctx_t p_ioctx
,
127 rbd_image_t p_image
, const char *p_name
,
128 const char *p_snap_name
, rados_ioctx_t c_ioctx
,
129 const char *c_name
, uint64_t features
, int *c_order
)
131 uint64_t stripe_unit
, stripe_count
;
134 r
= rbd_get_stripe_unit(p_image
, &stripe_unit
);
139 r
= rbd_get_stripe_count(p_image
, &stripe_count
);
144 return rbd_clone2(p_ioctx
, p_name
, p_snap_name
, c_ioctx
,
145 c_name
, features
, c_order
, stripe_unit
, stripe_count
);
149 static int create_image(rados_ioctx_t ioctx
, const char *name
,
150 uint64_t size
, int *order
)
155 int r
= get_features(&old_format
, &features
);
158 return create_image_full(ioctx
, name
, size
, order
, old_format
, features
);
161 static int create_image_pp(librbd::RBD
&rbd
,
162 librados::IoCtx
&ioctx
,
164 uint64_t size
, int *order
) {
167 int r
= get_features(&old_format
, &features
);
171 librados::Rados
rados(ioctx
);
172 int r
= rados
.conf_set("rbd_default_format", "1");
176 return rbd
.create(ioctx
, name
, size
, order
);
178 return rbd
.create2(ioctx
, name
, size
, features
, order
);
184 void simple_write_cb(rbd_completion_t cb
, void *arg
)
186 printf("write completion cb called!\n");
189 void simple_read_cb(rbd_completion_t cb
, void *arg
)
191 printf("read completion cb called!\n");
194 void aio_write_test_data_and_poll(rbd_image_t image
, int fd
, const char *test_data
,
195 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
197 rbd_completion_t comp
;
198 uint64_t data
= 0x123;
199 rbd_aio_create_completion((void*)&data
, (rbd_callback_t
) simple_write_cb
, &comp
);
200 printf("created completion\n");
201 printf("started write\n");
203 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
205 rbd_aio_write(image
, off
, len
, test_data
, comp
);
211 ASSERT_EQ(1, poll(&pfd
, 1, -1));
212 ASSERT_TRUE(pfd
.revents
& POLLIN
);
214 rbd_completion_t comps
[1];
215 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
217 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
218 read(fd
, &count
, sizeof(count
)));
219 int r
= rbd_aio_get_return_value(comps
[0]);
220 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
221 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps
[0]) == data
);
222 printf("return value is: %d\n", r
);
224 printf("finished write\n");
225 rbd_aio_release(comps
[0]);
229 void aio_write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
231 rbd_completion_t comp
;
232 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
233 printf("created completion\n");
235 rbd_aio_write2(image
, off
, len
, test_data
, comp
, iohint
);
237 rbd_aio_write(image
, off
, len
, test_data
, comp
);
238 printf("started write\n");
239 rbd_aio_wait_for_complete(comp
);
240 int r
= rbd_aio_get_return_value(comp
);
241 printf("return value is: %d\n", r
);
243 printf("finished write\n");
244 rbd_aio_release(comp
);
248 void write_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
252 written
= rbd_write2(image
, off
, len
, test_data
, iohint
);
254 written
= rbd_write(image
, off
, len
, test_data
);
255 printf("wrote: %d\n", (int) written
);
256 ASSERT_EQ(len
, static_cast<size_t>(written
));
260 void aio_discard_test_data(rbd_image_t image
, uint64_t off
, uint64_t len
, bool *passed
)
262 rbd_completion_t comp
;
263 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
264 rbd_aio_discard(image
, off
, len
, comp
);
265 rbd_aio_wait_for_complete(comp
);
266 int r
= rbd_aio_get_return_value(comp
);
268 printf("aio discard: %d~%d = %d\n", (int)off
, (int)len
, (int)r
);
269 rbd_aio_release(comp
);
273 void discard_test_data(rbd_image_t image
, uint64_t off
, size_t len
, bool *passed
)
276 written
= rbd_discard(image
, off
, len
);
277 printf("discard: %d~%d = %d\n", (int)off
, (int)len
, (int)written
);
278 ASSERT_EQ(len
, static_cast<size_t>(written
));
282 void aio_read_test_data_and_poll(rbd_image_t image
, int fd
, const char *expected
,
283 uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
285 rbd_completion_t comp
;
286 char *result
= (char *)malloc(len
+ 1);
288 ASSERT_NE(static_cast<char *>(NULL
), result
);
289 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
290 printf("created completion\n");
291 printf("started read\n");
293 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
295 rbd_aio_read(image
, off
, len
, result
, comp
);
301 ASSERT_EQ(1, poll(&pfd
, 1, -1));
302 ASSERT_TRUE(pfd
.revents
& POLLIN
);
304 rbd_completion_t comps
[1];
305 ASSERT_EQ(1, rbd_poll_io_events(image
, comps
, 1));
307 ASSERT_EQ(static_cast<ssize_t
>(sizeof(count
)),
308 read(fd
, &count
, sizeof(count
)));
310 int r
= rbd_aio_get_return_value(comps
[0]);
311 ASSERT_TRUE(rbd_aio_is_complete(comps
[0]));
312 printf("return value is: %d\n", r
);
313 ASSERT_EQ(len
, static_cast<size_t>(r
));
314 rbd_aio_release(comps
[0]);
315 if (memcmp(result
, expected
, len
)) {
316 printf("read: %s\nexpected: %s\n", result
, expected
);
317 ASSERT_EQ(0, memcmp(result
, expected
, len
));
323 void aio_read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
325 rbd_completion_t comp
;
326 char *result
= (char *)malloc(len
+ 1);
328 ASSERT_NE(static_cast<char *>(NULL
), result
);
329 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
330 printf("created completion\n");
332 rbd_aio_read2(image
, off
, len
, result
, comp
, iohint
);
334 rbd_aio_read(image
, off
, len
, result
, comp
);
335 printf("started read\n");
336 rbd_aio_wait_for_complete(comp
);
337 int r
= rbd_aio_get_return_value(comp
);
338 printf("return value is: %d\n", r
);
339 ASSERT_EQ(len
, static_cast<size_t>(r
));
340 rbd_aio_release(comp
);
341 if (memcmp(result
, expected
, len
)) {
342 printf("read: %s\nexpected: %s\n", result
, expected
);
343 ASSERT_EQ(0, memcmp(result
, expected
, len
));
349 void read_test_data(rbd_image_t image
, const char *expected
, uint64_t off
, size_t len
, uint32_t iohint
, bool *passed
)
352 char *result
= (char *)malloc(len
+ 1);
354 ASSERT_NE(static_cast<char *>(NULL
), result
);
356 read
= rbd_read2(image
, off
, len
, result
, iohint
);
358 read
= rbd_read(image
, off
, len
, result
);
359 printf("read: %d\n", (int) read
);
360 ASSERT_EQ(len
, static_cast<size_t>(read
));
362 if (memcmp(result
, expected
, len
)) {
363 printf("read: %s\nexpected: %s\n", result
, expected
);
364 ASSERT_EQ(0, memcmp(result
, expected
, len
));
370 void aio_writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
371 uint64_t data_len
, uint32_t iohint
, bool *passed
)
373 rbd_completion_t comp
;
374 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
375 printf("created completion\n");
377 r
= rbd_aio_writesame(image
, off
, len
, test_data
, data_len
, comp
, iohint
);
378 printf("started writesame\n");
379 if (len
% data_len
) {
380 ASSERT_EQ(-EINVAL
, r
);
381 printf("expected fail, finished writesame\n");
382 rbd_aio_release(comp
);
387 rbd_aio_wait_for_complete(comp
);
388 r
= rbd_aio_get_return_value(comp
);
389 printf("return value is: %d\n", r
);
391 printf("finished writesame\n");
392 rbd_aio_release(comp
);
395 printf("to verify the data\n");
397 char *result
= (char *)malloc(data_len
+ 1);
398 ASSERT_NE(static_cast<char *>(NULL
), result
);
401 read
= rbd_read(image
, off
, data_len
, result
);
402 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
403 result
[data_len
] = '\0';
404 if (memcmp(result
, test_data
, data_len
)) {
405 printf("read: %d ~ %d\n", (int) off
, (int) read
);
406 printf("read: %s\nexpected: %s\n", result
, test_data
);
407 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
414 printf("verified\n");
419 void writesame_test_data(rbd_image_t image
, const char *test_data
, uint64_t off
, uint64_t len
,
420 uint64_t data_len
, uint32_t iohint
, bool *passed
)
423 written
= rbd_writesame(image
, off
, len
, test_data
, data_len
, iohint
);
424 if (len
% data_len
) {
425 ASSERT_EQ(-EINVAL
, written
);
426 printf("expected fail, finished writesame\n");
430 ASSERT_EQ(len
, static_cast<size_t>(written
));
431 printf("wrote: %d\n", (int) written
);
434 printf("to verify the data\n");
436 char *result
= (char *)malloc(data_len
+ 1);
437 ASSERT_NE(static_cast<char *>(NULL
), result
);
440 read
= rbd_read(image
, off
, data_len
, result
);
441 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
442 result
[data_len
] = '\0';
443 if (memcmp(result
, test_data
, data_len
)) {
444 printf("read: %d ~ %d\n", (int) off
, (int) read
);
445 printf("read: %s\nexpected: %s\n", result
, test_data
);
446 ASSERT_EQ(0, memcmp(result
, test_data
, data_len
));
453 printf("verified\n");
458 void aio_compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
459 const char *test_data
, uint64_t off
,
460 size_t len
, uint32_t iohint
, bool *passed
)
462 rbd_completion_t comp
;
463 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_write_cb
, &comp
);
464 printf("created completion\n");
466 uint64_t mismatch_offset
;
467 rbd_aio_compare_and_write(image
, off
, len
, cmp_data
, test_data
, comp
, &mismatch_offset
, iohint
);
468 printf("started aio compare and write\n");
469 rbd_aio_wait_for_complete(comp
);
470 int r
= rbd_aio_get_return_value(comp
);
471 printf("return value is: %d\n", r
);
473 printf("finished aio compare and write\n");
474 rbd_aio_release(comp
);
478 void compare_and_write_test_data(rbd_image_t image
, const char *cmp_data
,
479 const char *test_data
, uint64_t off
, size_t len
,
480 uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
482 printf("start compare and write\n");
484 written
= rbd_compare_and_write(image
, off
, len
, cmp_data
, test_data
, mismatch_off
, iohint
);
485 printf("compare and wrote: %d\n", (int) written
);
486 ASSERT_EQ(len
, static_cast<size_t>(written
));
490 class TestLibRBD
: public ::testing::Test
{
493 TestLibRBD() : m_pool_number() {
496 static void SetUpTestCase() {
498 _unique_pool_names
.clear();
500 ASSERT_EQ("", connect_cluster(&_cluster
));
501 ASSERT_EQ("", connect_cluster_pp(_rados
));
503 create_optional_data_pool();
506 static void TearDownTestCase() {
507 rados_shutdown(_cluster
);
508 _rados
.wait_for_latest_osdmap();
509 _pool_names
.insert(_pool_names
.end(), _unique_pool_names
.begin(),
510 _unique_pool_names
.end());
511 for (size_t i
= 1; i
< _pool_names
.size(); ++i
) {
512 ASSERT_EQ(0, _rados
.pool_delete(_pool_names
[i
].c_str()));
514 if (!_pool_names
.empty()) {
515 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names
[0], _rados
));
519 void SetUp() override
{
520 ASSERT_NE("", m_pool_name
= create_pool());
523 bool is_skip_partial_discard_enabled() {
525 EXPECT_EQ(0, _rados
.conf_get("rbd_skip_partial_discard", value
));
526 return value
== "true";
529 bool is_skip_partial_discard_enabled(rbd_image_t image
) {
530 if (is_skip_partial_discard_enabled()) {
533 EXPECT_EQ(0, rbd_get_features(image
, &features
));
534 return !(features
& RBD_FEATURE_DIRTY_CACHE
);
539 bool is_skip_partial_discard_enabled(librbd::Image
& image
) {
540 if (is_skip_partial_discard_enabled()) {
543 EXPECT_EQ(0, image
.features(&features
));
544 return !(features
& RBD_FEATURE_DIRTY_CACHE
);
549 void validate_object_map(rbd_image_t image
, bool *passed
) {
551 ASSERT_EQ(0, rbd_get_flags(image
, &flags
));
552 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
555 void validate_object_map(librbd::Image
&image
, bool *passed
) {
557 ASSERT_EQ(0, image
.get_flags(&flags
));
558 *passed
= ((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
561 static std::string
get_temp_image_name() {
563 return "image" + stringify(_image_number
);
566 static void create_optional_data_pool() {
567 bool created
= false;
568 std::string data_pool
;
569 ASSERT_EQ(0, create_image_data_pool(_rados
, data_pool
, &created
));
570 if (!data_pool
.empty()) {
571 printf("using image data pool: %s\n", data_pool
.c_str());
573 _unique_pool_names
.push_back(data_pool
);
578 std::string
create_pool(bool unique
= false) {
579 librados::Rados rados
;
580 std::string pool_name
;
582 pool_name
= get_temp_pool_name("test-librbd-");
583 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
584 _unique_pool_names
.push_back(pool_name
);
585 } else if (m_pool_number
< _pool_names
.size()) {
586 pool_name
= _pool_names
[m_pool_number
];
588 pool_name
= get_temp_pool_name("test-librbd-");
589 EXPECT_EQ("", create_one_pool_pp(pool_name
, rados
));
590 _pool_names
.push_back(pool_name
);
596 void test_io(rbd_image_t image
) {
597 bool skip_discard
= is_skip_partial_discard_enabled(image
);
599 char test_data
[TEST_IO_SIZE
+ 1];
600 char zero_data
[TEST_IO_SIZE
+ 1];
601 char mismatch_data
[TEST_IO_SIZE
+ 1];
603 uint64_t mismatch_offset
;
605 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
606 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
608 test_data
[TEST_IO_SIZE
] = '\0';
609 memset(zero_data
, 0, sizeof(zero_data
));
610 memset(mismatch_data
, 9, sizeof(mismatch_data
));
612 for (i
= 0; i
< 5; ++i
)
613 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
616 for (i
= 5; i
< 10; ++i
)
617 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
620 for (i
= 0; i
< 5; ++i
)
621 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
622 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, 0);
624 for (i
= 5; i
< 10; ++i
)
625 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
626 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
628 for (i
= 0; i
< 5; ++i
)
629 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
632 for (i
= 5; i
< 10; ++i
)
633 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
636 // discard 2nd, 4th sections.
637 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
638 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
640 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
641 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
642 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
643 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2,
645 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
646 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
647 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4,
650 for (i
= 0; i
< 15; ++i
) {
652 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
653 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
654 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
655 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
656 } else if (i
% 3 == 1) {
657 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
658 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
659 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
660 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
662 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
663 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
664 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
665 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
668 for (i
= 0; i
< 15; ++i
) {
670 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
671 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
,
673 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
674 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
,
676 } else if (i
% 3 == 1) {
677 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
678 TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
679 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
680 TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
682 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
,
683 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
684 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
,
685 TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
689 rbd_image_info_t info
;
690 rbd_completion_t comp
;
691 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
692 // can't read or write starting past end
693 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
694 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
695 // reading through end returns amount up to end
696 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
697 // writing through end returns amount up to end
698 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
700 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
701 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
702 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
703 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
704 rbd_aio_release(comp
);
706 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
707 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
708 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
709 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
710 rbd_aio_release(comp
);
712 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
,
713 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
714 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
,
715 mismatch_data
, mismatch_data
, &mismatch_offset
, 0));
716 ASSERT_EQ(0U, mismatch_offset
);
717 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
718 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
,
719 mismatch_data
, comp
, &mismatch_offset
, 0));
720 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
721 ASSERT_EQ(0U, mismatch_offset
);
722 rbd_aio_release(comp
);
724 ASSERT_PASSED(validate_object_map
, image
);
727 static std::vector
<std::string
> _pool_names
;
728 static std::vector
<std::string
> _unique_pool_names
;
729 static rados_t _cluster
;
730 static librados::Rados _rados
;
731 static uint64_t _image_number
;
733 std::string m_pool_name
;
734 uint32_t m_pool_number
;
738 std::vector
<std::string
> TestLibRBD::_pool_names
;
739 std::vector
<std::string
> TestLibRBD::_unique_pool_names
;
740 rados_t
TestLibRBD::_cluster
;
741 librados::Rados
TestLibRBD::_rados
;
742 uint64_t TestLibRBD::_image_number
= 0;
744 TEST_F(TestLibRBD
, CreateAndStat
)
747 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
749 rbd_image_info_t info
;
752 std::string name
= get_temp_image_name();
753 uint64_t size
= 2 << 20;
755 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
756 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
757 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
758 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
759 ASSERT_EQ(info
.size
, size
);
760 ASSERT_EQ(info
.order
, order
);
761 ASSERT_EQ(0, rbd_close(image
));
763 rados_ioctx_destroy(ioctx
);
766 TEST_F(TestLibRBD
, CreateWithSameDataPool
)
771 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
774 std::string name
= get_temp_image_name();
775 uint64_t size
= 2 << 20;
779 ASSERT_EQ(0, get_features(&old_format
, &features
));
780 ASSERT_FALSE(old_format
);
782 rbd_image_options_t image_options
;
783 rbd_image_options_create(&image_options
);
784 BOOST_SCOPE_EXIT( (&image_options
) ) {
785 rbd_image_options_destroy(image_options
);
786 } BOOST_SCOPE_EXIT_END
;
788 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
789 RBD_IMAGE_OPTION_FEATURES
,
791 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
792 RBD_IMAGE_OPTION_DATA_POOL
,
793 m_pool_name
.c_str()));
795 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
796 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
798 ASSERT_EQ(0, rbd_close(image
));
800 rados_ioctx_destroy(ioctx
);
803 TEST_F(TestLibRBD
, CreateAndStatPP
)
805 librados::IoCtx ioctx
;
806 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
810 librbd::image_info_t info
;
813 std::string name
= get_temp_image_name();
814 uint64_t size
= 2 << 20;
816 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
817 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
818 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
819 ASSERT_EQ(info
.size
, size
);
820 ASSERT_EQ(info
.order
, order
);
826 TEST_F(TestLibRBD
, GetId
)
829 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
833 std::string name
= get_temp_image_name();
835 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
836 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
839 if (!is_feature_enabled(0)) {
841 ASSERT_EQ(-EINVAL
, rbd_get_id(image
, id
, sizeof(id
)));
843 ASSERT_EQ(-ERANGE
, rbd_get_id(image
, id
, 0));
844 ASSERT_EQ(0, rbd_get_id(image
, id
, sizeof(id
)));
845 ASSERT_LT(0U, strlen(id
));
847 ASSERT_EQ(0, rbd_close(image
));
848 ASSERT_EQ(0, rbd_open_by_id(ioctx
, id
, &image
, NULL
));
850 ASSERT_EQ(-ERANGE
, rbd_get_name(image
, NULL
, &name_len
));
851 ASSERT_EQ(name_len
, name
.size() + 1);
852 char image_name
[name_len
];
853 ASSERT_EQ(0, rbd_get_name(image
, image_name
, &name_len
));
854 ASSERT_STREQ(name
.c_str(), image_name
);
857 ASSERT_EQ(0, rbd_close(image
));
858 rados_ioctx_destroy(ioctx
);
861 TEST_F(TestLibRBD
, GetIdPP
)
863 librados::IoCtx ioctx
;
864 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
869 std::string name
= get_temp_image_name();
872 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
873 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
874 if (!is_feature_enabled(0)) {
876 ASSERT_EQ(-EINVAL
, image
.get_id(&id
));
878 ASSERT_EQ(0, image
.get_id(&id
));
879 ASSERT_LT(0U, id
.size());
881 ASSERT_EQ(0, image
.close());
882 ASSERT_EQ(0, rbd
.open_by_id(ioctx
, image
, id
.c_str(), NULL
));
883 std::string image_name
;
884 ASSERT_EQ(0, image
.get_name(&image_name
));
885 ASSERT_EQ(name
, image_name
);
889 TEST_F(TestLibRBD
, GetBlockNamePrefix
)
892 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
896 std::string name
= get_temp_image_name();
898 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
899 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
902 ASSERT_EQ(-ERANGE
, rbd_get_block_name_prefix(image
, prefix
, 0));
903 ASSERT_EQ(0, rbd_get_block_name_prefix(image
, prefix
, sizeof(prefix
)));
904 ASSERT_LT(0U, strlen(prefix
));
906 ASSERT_EQ(0, rbd_close(image
));
907 rados_ioctx_destroy(ioctx
);
910 TEST_F(TestLibRBD
, GetBlockNamePrefixPP
)
912 librados::IoCtx ioctx
;
913 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
918 std::string name
= get_temp_image_name();
920 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
921 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
922 ASSERT_LT(0U, image
.get_block_name_prefix().size());
925 TEST_F(TestLibRBD
, TestGetCreateTimestamp
)
930 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
934 std::string name
= get_temp_image_name();
936 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), 0, &order
));
937 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
939 struct timespec timestamp
;
940 ASSERT_EQ(0, rbd_get_create_timestamp(image
, ×tamp
));
941 ASSERT_LT(0, timestamp
.tv_sec
);
943 ASSERT_EQ(0, rbd_close(image
));
945 rados_ioctx_destroy(ioctx
);
948 TEST_F(TestLibRBD
, GetCreateTimestampPP
)
952 librados::IoCtx ioctx
;
953 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
958 std::string name
= get_temp_image_name();
960 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), 0, &order
));
961 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
963 struct timespec timestamp
;
964 ASSERT_EQ(0, image
.get_create_timestamp(×tamp
));
965 ASSERT_LT(0, timestamp
.tv_sec
);
968 TEST_F(TestLibRBD
, OpenAio
)
971 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
973 rbd_image_info_t info
;
976 std::string name
= get_temp_image_name();
977 uint64_t size
= 2 << 20;
979 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
981 rbd_completion_t open_comp
;
982 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
983 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
984 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
985 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
986 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp
));
987 rbd_aio_release(open_comp
);
989 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
990 printf("image has size %llu and order %d\n", (unsigned long long) info
.size
, info
.order
);
991 ASSERT_EQ(info
.size
, size
);
992 ASSERT_EQ(info
.order
, order
);
994 rbd_completion_t close_comp
;
995 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &close_comp
));
996 ASSERT_EQ(0, rbd_aio_close(image
, close_comp
));
997 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp
));
998 ASSERT_EQ(1, rbd_aio_is_complete(close_comp
));
999 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp
));
1000 rbd_aio_release(close_comp
);
1002 rados_ioctx_destroy(ioctx
);
1005 TEST_F(TestLibRBD
, OpenAioFail
)
1007 rados_ioctx_t ioctx
;
1008 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
1010 std::string name
= get_temp_image_name();
1012 rbd_completion_t open_comp
;
1013 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &open_comp
));
1014 ASSERT_EQ(0, rbd_aio_open(ioctx
, name
.c_str(), &image
, NULL
, open_comp
));
1015 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp
));
1016 ASSERT_EQ(1, rbd_aio_is_complete(open_comp
));
1017 ASSERT_EQ(-ENOENT
, rbd_aio_get_return_value(open_comp
));
1018 rbd_aio_release(open_comp
);
1020 rados_ioctx_destroy(ioctx
);
1023 TEST_F(TestLibRBD
, OpenAioPP
)
1025 librados::IoCtx ioctx
;
1026 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1029 librbd::image_info_t info
;
1030 librbd::Image image
;
1032 std::string name
= get_temp_image_name();
1033 uint64_t size
= 2 << 20;
1035 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1037 librbd::RBD::AioCompletion
*open_comp
=
1038 new librbd::RBD::AioCompletion(NULL
, NULL
);
1039 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1040 ASSERT_EQ(0, open_comp
->wait_for_complete());
1041 ASSERT_EQ(1, open_comp
->is_complete());
1042 ASSERT_EQ(0, open_comp
->get_return_value());
1043 open_comp
->release();
1045 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1046 ASSERT_EQ(info
.size
, size
);
1047 ASSERT_EQ(info
.order
, order
);
1050 open_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
1051 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1052 ASSERT_EQ(0, open_comp
->wait_for_complete());
1053 ASSERT_EQ(1, open_comp
->is_complete());
1054 ASSERT_EQ(0, open_comp
->get_return_value());
1055 open_comp
->release();
1058 librbd::RBD::AioCompletion
*close_comp
=
1059 new librbd::RBD::AioCompletion(NULL
, NULL
);
1060 ASSERT_EQ(0, image
.aio_close(close_comp
));
1061 ASSERT_EQ(0, close_comp
->wait_for_complete());
1062 ASSERT_EQ(1, close_comp
->is_complete());
1063 ASSERT_EQ(0, close_comp
->get_return_value());
1064 close_comp
->release();
1066 // close closed image
1067 close_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
1068 ASSERT_EQ(-EINVAL
, image
.aio_close(close_comp
));
1069 close_comp
->release();
1074 TEST_F(TestLibRBD
, OpenAioFailPP
)
1076 librados::IoCtx ioctx
;
1077 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1081 librbd::Image image
;
1082 std::string name
= get_temp_image_name();
1084 librbd::RBD::AioCompletion
*open_comp
=
1085 new librbd::RBD::AioCompletion(NULL
, NULL
);
1086 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, open_comp
));
1087 ASSERT_EQ(0, open_comp
->wait_for_complete());
1088 ASSERT_EQ(1, open_comp
->is_complete());
1089 ASSERT_EQ(-ENOENT
, open_comp
->get_return_value());
1090 open_comp
->release();
1096 TEST_F(TestLibRBD
, ResizeAndStat
)
1098 rados_ioctx_t ioctx
;
1099 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1101 rbd_image_info_t info
;
1104 std::string name
= get_temp_image_name();
1105 uint64_t size
= 2 << 20;
1107 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1108 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1110 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
1111 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1112 ASSERT_EQ(info
.size
, size
* 4);
1114 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
1115 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1116 ASSERT_EQ(info
.size
, size
/ 2);
1118 // downsizing without allowing shrink should fail
1119 // and image size should not change
1120 ASSERT_EQ(-EINVAL
, rbd_resize2(image
, size
/ 4, false, NULL
, NULL
));
1121 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1122 ASSERT_EQ(info
.size
, size
/ 2);
1124 ASSERT_EQ(0, rbd_resize2(image
, size
/ 4, true, NULL
, NULL
));
1125 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
1126 ASSERT_EQ(info
.size
, size
/ 4);
1128 ASSERT_PASSED(validate_object_map
, image
);
1129 ASSERT_EQ(0, rbd_close(image
));
1131 rados_ioctx_destroy(ioctx
);
1134 TEST_F(TestLibRBD
, ResizeAndStatPP
)
1136 librados::IoCtx ioctx
;
1137 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1141 librbd::image_info_t info
;
1142 librbd::Image image
;
1144 std::string name
= get_temp_image_name();
1145 uint64_t size
= 2 << 20;
1147 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1148 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1150 ASSERT_EQ(0, image
.resize(size
* 4));
1151 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1152 ASSERT_EQ(info
.size
, size
* 4);
1154 ASSERT_EQ(0, image
.resize(size
/ 2));
1155 ASSERT_EQ(0, image
.stat(info
, sizeof(info
)));
1156 ASSERT_EQ(info
.size
, size
/ 2);
1157 ASSERT_PASSED(validate_object_map
, image
);
1163 TEST_F(TestLibRBD
, UpdateWatchAndResize
)
1165 rados_ioctx_t ioctx
;
1166 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1170 std::string name
= get_temp_image_name();
1171 uint64_t size
= 2 << 20;
1173 rbd_image_t
&m_image
;
1175 std::condition_variable m_cond
;
1177 static void cb(void *arg
) {
1178 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
1179 watcher
->handle_notify();
1181 explicit Watcher(rbd_image_t
&image
) : m_image(image
) {}
1182 void handle_notify() {
1183 rbd_image_info_t info
;
1184 ASSERT_EQ(0, rbd_stat(m_image
, &info
, sizeof(info
)));
1185 std::lock_guard
<std::mutex
> locker(m_lock
);
1187 m_cond
.notify_one();
1189 void wait_for_size(size_t size
) {
1190 std::unique_lock
<std::mutex
> locker(m_lock
);
1191 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
1193 return this->m_size
== size
;}));
1198 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1199 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1201 ASSERT_EQ(0, rbd_update_watch(image
, &handle
, Watcher::cb
, &watcher
));
1203 ASSERT_EQ(0, rbd_resize(image
, size
* 4));
1204 watcher
.wait_for_size(size
* 4);
1206 ASSERT_EQ(0, rbd_resize(image
, size
/ 2));
1207 watcher
.wait_for_size(size
/ 2);
1209 ASSERT_EQ(0, rbd_update_unwatch(image
, handle
));
1211 ASSERT_EQ(0, rbd_close(image
));
1212 rados_ioctx_destroy(ioctx
);
1215 TEST_F(TestLibRBD
, UpdateWatchAndResizePP
)
1217 librados::IoCtx ioctx
;
1218 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1222 librbd::Image image
;
1224 std::string name
= get_temp_image_name();
1225 uint64_t size
= 2 << 20;
1226 struct Watcher
: public librbd::UpdateWatchCtx
{
1227 explicit Watcher(librbd::Image
&image
) : m_image(image
) {
1229 void handle_notify() override
{
1230 librbd::image_info_t info
;
1231 ASSERT_EQ(0, m_image
.stat(info
, sizeof(info
)));
1232 std::lock_guard
<std::mutex
> locker(m_lock
);
1234 m_cond
.notify_one();
1236 void wait_for_size(size_t size
) {
1237 std::unique_lock
<std::mutex
> locker(m_lock
);
1238 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(5),
1240 return this->m_size
== size
;}));
1242 librbd::Image
&m_image
;
1244 std::condition_variable m_cond
;
1249 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1250 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1252 ASSERT_EQ(0, image
.update_watch(&watcher
, &handle
));
1254 ASSERT_EQ(0, image
.resize(size
* 4));
1255 watcher
.wait_for_size(size
* 4);
1257 ASSERT_EQ(0, image
.resize(size
/ 2));
1258 watcher
.wait_for_size(size
/ 2);
1260 ASSERT_EQ(0, image
.update_unwatch(handle
));
1266 int test_ls(rados_ioctx_t io_ctx
, size_t num_expected
, ...)
1269 char *names
, *cur_name
;
1271 size_t max_size
= 1024;
1273 names
= (char *) malloc(sizeof(char) * 1024);
1274 int len
= rbd_list(io_ctx
, names
, &max_size
);
1276 std::set
<std::string
> image_names
;
1277 for (i
= 0, num_images
= 0, cur_name
= names
; cur_name
< names
+ len
; i
++) {
1278 printf("image: %s\n", cur_name
);
1279 image_names
.insert(cur_name
);
1280 cur_name
+= strlen(cur_name
) + 1;
1285 va_start(ap
, num_expected
);
1286 for (i
= num_expected
; i
> 0; i
--) {
1287 char *expected
= va_arg(ap
, char *);
1288 printf("expected = %s\n", expected
);
1289 std::set
<std::string
>::iterator it
= image_names
.find(expected
);
1290 if (it
!= image_names
.end()) {
1291 printf("found %s\n", expected
);
1292 image_names
.erase(it
);
1293 printf("erased %s\n", expected
);
1295 ADD_FAILURE() << "Unable to find image " << expected
;
1302 if (!image_names
.empty()) {
1303 ADD_FAILURE() << "Unexpected images discovered";
1309 TEST_F(TestLibRBD
, TestCreateLsDelete
)
1311 rados_ioctx_t ioctx
;
1312 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1315 std::string name
= get_temp_image_name();
1316 std::string name2
= get_temp_image_name();
1317 uint64_t size
= 2 << 20;
1319 ASSERT_EQ(0, test_ls(ioctx
, 0));
1320 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1321 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1322 ASSERT_EQ(0, create_image(ioctx
, name2
.c_str(), size
, &order
));
1323 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1324 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
1325 ASSERT_EQ(1, test_ls(ioctx
, 1, name2
.c_str()));
1327 ASSERT_EQ(-ENOENT
, rbd_remove(ioctx
, name
.c_str()));
1329 rados_ioctx_destroy(ioctx
);
1332 int test_ls_pp(librbd::RBD
& rbd
, librados::IoCtx
& io_ctx
, size_t num_expected
, ...)
1337 vector
<string
> names
;
1338 r
= rbd
.list(io_ctx
, names
);
1341 EXPECT_TRUE(r
>= 0);
1342 cout
<< "num images is: " << names
.size() << std::endl
1343 << "expected: " << num_expected
<< std::endl
;
1344 int num
= names
.size();
1346 for (i
= 0; i
< names
.size(); i
++) {
1347 cout
<< "image: " << names
[i
] << std::endl
;
1350 va_start(ap
, num_expected
);
1351 for (i
= num_expected
; i
> 0; i
--) {
1352 char *expected
= va_arg(ap
, char *);
1353 cout
<< "expected = " << expected
<< std::endl
;
1354 vector
<string
>::iterator listed_name
= find(names
.begin(), names
.end(), string(expected
));
1355 if (listed_name
== names
.end()) {
1356 ADD_FAILURE() << "Unable to find image " << expected
;
1360 names
.erase(listed_name
);
1364 if (!names
.empty()) {
1365 ADD_FAILURE() << "Unexpected images discovered";
1371 TEST_F(TestLibRBD
, TestCreateLsDeletePP
)
1373 librados::IoCtx ioctx
;
1374 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1378 librbd::Image image
;
1380 std::string name
= get_temp_image_name();
1381 std::string name2
= get_temp_image_name();
1382 uint64_t size
= 2 << 20;
1384 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1385 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1386 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
1387 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1388 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
1389 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name2
.c_str()));
1396 static int print_progress_percent(uint64_t offset
, uint64_t src_size
,
1399 float percent
= ((float)offset
* 100) / src_size
;
1400 printf("%3.2f%% done\n", percent
);
1404 TEST_F(TestLibRBD
, TestCopy
)
1406 rados_ioctx_t ioctx
;
1407 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1413 std::string name
= get_temp_image_name();
1414 std::string name2
= get_temp_image_name();
1415 std::string name3
= get_temp_image_name();
1417 uint64_t size
= 2 << 20;
1419 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1420 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1421 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1423 size_t sum_key_len
= 0;
1424 size_t sum_value_len
= 0;
1427 for (int i
= 1; i
<= 70; i
++) {
1428 key
= "key" + stringify(i
);
1429 val
= "value" + stringify(i
);
1430 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
1432 sum_key_len
+= (key
.size() + 1);
1433 sum_value_len
+= (val
.size() + 1);
1438 size_t keys_len
= sizeof(keys
);
1439 size_t vals_len
= sizeof(vals
);
1442 size_t value_len
= sizeof(value
);
1444 ASSERT_EQ(0, rbd_copy(image
, ioctx
, name2
.c_str()));
1445 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1446 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
1447 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 70, keys
, &keys_len
, vals
,
1449 ASSERT_EQ(keys_len
, sum_key_len
);
1450 ASSERT_EQ(vals_len
, sum_value_len
);
1452 for (int i
= 1; i
<= 70; i
++) {
1453 key
= "key" + stringify(i
);
1454 val
= "value" + stringify(i
);
1455 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
1456 ASSERT_STREQ(val
.c_str(), value
);
1458 value_len
= sizeof(value
);
1461 ASSERT_EQ(0, rbd_copy_with_progress(image
, ioctx
, name3
.c_str(),
1462 print_progress_percent
, NULL
));
1463 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1465 keys_len
= sizeof(keys
);
1466 vals_len
= sizeof(vals
);
1467 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1468 ASSERT_EQ(0, rbd_metadata_list(image3
, "key", 70, keys
, &keys_len
, vals
,
1470 ASSERT_EQ(keys_len
, sum_key_len
);
1471 ASSERT_EQ(vals_len
, sum_value_len
);
1473 for (int i
= 1; i
<= 70; i
++) {
1474 key
= "key" + stringify(i
);
1475 val
= "value" + stringify(i
);
1476 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1477 ASSERT_STREQ(val
.c_str(), value
);
1479 value_len
= sizeof(value
);
1482 ASSERT_EQ(0, rbd_close(image
));
1483 ASSERT_EQ(0, rbd_close(image2
));
1484 ASSERT_EQ(0, rbd_close(image3
));
1485 rados_ioctx_destroy(ioctx
);
1488 class PrintProgress
: public librbd::ProgressContext
1491 int update_progress(uint64_t offset
, uint64_t src_size
) override
1493 float percent
= ((float)offset
* 100) / src_size
;
1494 printf("%3.2f%% done\n", percent
);
1499 TEST_F(TestLibRBD
, TestCopyPP
)
1501 librados::IoCtx ioctx
;
1502 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1506 librbd::Image image
;
1507 librbd::Image image2
;
1508 librbd::Image image3
;
1510 std::string name
= get_temp_image_name();
1511 std::string name2
= get_temp_image_name();
1512 std::string name3
= get_temp_image_name();
1513 uint64_t size
= 2 << 20;
1516 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1517 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1521 for (int i
= 1; i
<= 70; i
++) {
1522 key
= "key" + stringify(i
);
1523 val
= "value" + stringify(i
);
1524 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1527 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1528 ASSERT_EQ(0, image
.copy(ioctx
, name2
.c_str()));
1529 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1530 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1532 map
<string
, bufferlist
> pairs
;
1534 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1535 ASSERT_EQ(70U, pairs
.size());
1537 for (int i
= 1; i
<= 70; i
++) {
1538 key
= "key" + stringify(i
);
1539 val
= "value" + stringify(i
);
1540 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1541 ASSERT_STREQ(val
.c_str(), value
.c_str());
1544 ASSERT_EQ(0, image
.copy_with_progress(ioctx
, name3
.c_str(), pp
));
1545 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1547 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1550 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1551 ASSERT_EQ(70U, pairs
.size());
1553 for (int i
= 1; i
<= 70; i
++) {
1554 key
= "key" + stringify(i
);
1555 val
= "value" + stringify(i
);
1556 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1557 ASSERT_STREQ(val
.c_str(), value
.c_str());
1564 TEST_F(TestLibRBD
, TestDeepCopy
)
1566 REQUIRE_FORMAT_V2();
1567 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
1569 rados_ioctx_t ioctx
;
1570 rados_ioctx_create(_cluster
, create_pool(true).c_str(), &ioctx
);
1571 BOOST_SCOPE_EXIT_ALL( (&ioctx
) ) {
1572 rados_ioctx_destroy(ioctx
);
1582 std::string name
= get_temp_image_name();
1583 std::string name2
= get_temp_image_name();
1584 std::string name3
= get_temp_image_name();
1585 std::string name4
= get_temp_image_name();
1586 std::string name5
= get_temp_image_name();
1587 std::string name6
= get_temp_image_name();
1589 uint64_t size
= 2 << 20;
1591 rbd_image_options_t opts
;
1592 rbd_image_options_create(&opts
);
1593 BOOST_SCOPE_EXIT_ALL( (&opts
) ) {
1594 rbd_image_options_destroy(opts
);
1597 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1598 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1599 BOOST_SCOPE_EXIT_ALL( (&image
) ) {
1600 ASSERT_EQ(0, rbd_close(image
));
1602 ASSERT_EQ(1, test_ls(ioctx
, 1, name
.c_str()));
1604 size_t sum_key_len
= 0;
1605 size_t sum_value_len
= 0;
1608 for (int i
= 1; i
<= 70; i
++) {
1609 key
= "key" + stringify(i
);
1610 val
= "value" + stringify(i
);
1611 ASSERT_EQ(0, rbd_metadata_set(image
, key
.c_str(), val
.c_str()));
1613 sum_key_len
+= (key
.size() + 1);
1614 sum_value_len
+= (val
.size() + 1);
1619 size_t keys_len
= sizeof(keys
);
1620 size_t vals_len
= sizeof(vals
);
1623 size_t value_len
= sizeof(value
);
1625 ASSERT_EQ(0, rbd_deep_copy(image
, ioctx
, name2
.c_str(), opts
));
1626 ASSERT_EQ(2, test_ls(ioctx
, 2, name
.c_str(), name2
.c_str()));
1627 ASSERT_EQ(0, rbd_open(ioctx
, name2
.c_str(), &image2
, NULL
));
1628 BOOST_SCOPE_EXIT_ALL( (&image2
) ) {
1629 ASSERT_EQ(0, rbd_close(image2
));
1631 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 70, keys
, &keys_len
, vals
,
1633 ASSERT_EQ(keys_len
, sum_key_len
);
1634 ASSERT_EQ(vals_len
, sum_value_len
);
1636 for (int i
= 1; i
<= 70; i
++) {
1637 key
= "key" + stringify(i
);
1638 val
= "value" + stringify(i
);
1639 ASSERT_EQ(0, rbd_metadata_get(image2
, key
.c_str(), value
, &value_len
));
1640 ASSERT_STREQ(val
.c_str(), value
);
1642 value_len
= sizeof(value
);
1645 ASSERT_EQ(0, rbd_deep_copy_with_progress(image
, ioctx
, name3
.c_str(), opts
,
1646 print_progress_percent
, NULL
));
1647 ASSERT_EQ(3, test_ls(ioctx
, 3, name
.c_str(), name2
.c_str(), name3
.c_str()));
1649 keys_len
= sizeof(keys
);
1650 vals_len
= sizeof(vals
);
1651 ASSERT_EQ(0, rbd_open(ioctx
, name3
.c_str(), &image3
, NULL
));
1652 BOOST_SCOPE_EXIT_ALL( (&image3
) ) {
1653 ASSERT_EQ(0, rbd_close(image3
));
1655 ASSERT_EQ(0, rbd_metadata_list(image3
, "key", 70, keys
, &keys_len
, vals
,
1657 ASSERT_EQ(keys_len
, sum_key_len
);
1658 ASSERT_EQ(vals_len
, sum_value_len
);
1660 for (int i
= 1; i
<= 70; i
++) {
1661 key
= "key" + stringify(i
);
1662 val
= "value" + stringify(i
);
1663 ASSERT_EQ(0, rbd_metadata_get(image3
, key
.c_str(), value
, &value_len
));
1664 ASSERT_STREQ(val
.c_str(), value
);
1666 value_len
= sizeof(value
);
1669 ASSERT_EQ(0, rbd_snap_create(image
, "deep_snap"));
1670 ASSERT_EQ(0, rbd_close(image
));
1671 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, "deep_snap"));
1672 ASSERT_EQ(0, rbd_snap_protect(image
, "deep_snap"));
1673 ASSERT_EQ(0, rbd_clone3(ioctx
, name
.c_str(), "deep_snap", ioctx
,
1674 name4
.c_str(), opts
));
1676 ASSERT_EQ(4, test_ls(ioctx
, 4, name
.c_str(), name2
.c_str(), name3
.c_str(),
1678 ASSERT_EQ(0, rbd_open(ioctx
, name4
.c_str(), &image4
, NULL
));
1679 BOOST_SCOPE_EXIT_ALL( (&image4
) ) {
1680 ASSERT_EQ(0, rbd_close(image4
));
1682 ASSERT_EQ(0, rbd_snap_create(image4
, "deep_snap"));
1684 ASSERT_EQ(0, rbd_deep_copy(image4
, ioctx
, name5
.c_str(), opts
));
1685 ASSERT_EQ(5, test_ls(ioctx
, 5, name
.c_str(), name2
.c_str(), name3
.c_str(),
1686 name4
.c_str(), name5
.c_str()));
1687 ASSERT_EQ(0, rbd_open(ioctx
, name5
.c_str(), &image5
, NULL
));
1688 BOOST_SCOPE_EXIT_ALL( (&image5
) ) {
1689 ASSERT_EQ(0, rbd_close(image5
));
1691 ASSERT_EQ(0, rbd_metadata_list(image5
, "key", 70, keys
, &keys_len
, vals
,
1693 ASSERT_EQ(keys_len
, sum_key_len
);
1694 ASSERT_EQ(vals_len
, sum_value_len
);
1696 for (int i
= 1; i
<= 70; i
++) {
1697 key
= "key" + stringify(i
);
1698 val
= "value" + stringify(i
);
1699 ASSERT_EQ(0, rbd_metadata_get(image5
, key
.c_str(), value
, &value_len
));
1700 ASSERT_STREQ(val
.c_str(), value
);
1702 value_len
= sizeof(value
);
1705 ASSERT_EQ(0, rbd_deep_copy_with_progress(image4
, ioctx
, name6
.c_str(), opts
,
1706 print_progress_percent
, NULL
));
1707 ASSERT_EQ(6, test_ls(ioctx
, 6, name
.c_str(), name2
.c_str(), name3
.c_str(),
1708 name4
.c_str(), name5
.c_str(), name6
.c_str()));
1710 keys_len
= sizeof(keys
);
1711 vals_len
= sizeof(vals
);
1712 ASSERT_EQ(0, rbd_open(ioctx
, name6
.c_str(), &image6
, NULL
));
1713 BOOST_SCOPE_EXIT_ALL( (&image6
) ) {
1714 ASSERT_EQ(0, rbd_close(image6
));
1716 ASSERT_EQ(0, rbd_metadata_list(image6
, "key", 70, keys
, &keys_len
, vals
,
1718 ASSERT_EQ(keys_len
, sum_key_len
);
1719 ASSERT_EQ(vals_len
, sum_value_len
);
1721 for (int i
= 1; i
<= 70; i
++) {
1722 key
= "key" + stringify(i
);
1723 val
= "value" + stringify(i
);
1724 ASSERT_EQ(0, rbd_metadata_get(image6
, key
.c_str(), value
, &value_len
));
1725 ASSERT_STREQ(val
.c_str(), value
);
1727 value_len
= sizeof(value
);
1731 TEST_F(TestLibRBD
, TestDeepCopyPP
)
1733 REQUIRE_FORMAT_V2();
1735 librados::IoCtx ioctx
;
1736 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
1740 librbd::Image image
;
1741 librbd::Image image2
;
1742 librbd::Image image3
;
1744 std::string name
= get_temp_image_name();
1745 std::string name2
= get_temp_image_name();
1746 std::string name3
= get_temp_image_name();
1747 uint64_t size
= 2 << 20;
1748 librbd::ImageOptions opts
;
1751 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1752 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1756 for (int i
= 1; i
<= 70; i
++) {
1757 key
= "key" + stringify(i
);
1758 val
= "value" + stringify(i
);
1759 ASSERT_EQ(0, image
.metadata_set(key
, val
));
1762 ASSERT_EQ(1, test_ls_pp(rbd
, ioctx
, 1, name
.c_str()));
1763 ASSERT_EQ(0, image
.deep_copy(ioctx
, name2
.c_str(), opts
));
1764 ASSERT_EQ(2, test_ls_pp(rbd
, ioctx
, 2, name
.c_str(), name2
.c_str()));
1765 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), NULL
));
1767 map
<string
, bufferlist
> pairs
;
1769 ASSERT_EQ(0, image2
.metadata_list("", 70, &pairs
));
1770 ASSERT_EQ(70U, pairs
.size());
1772 for (int i
= 1; i
<= 70; i
++) {
1773 key
= "key" + stringify(i
);
1774 val
= "value" + stringify(i
);
1775 ASSERT_EQ(0, image2
.metadata_get(key
.c_str(), &value
));
1776 ASSERT_STREQ(val
.c_str(), value
.c_str());
1779 ASSERT_EQ(0, image
.deep_copy_with_progress(ioctx
, name3
.c_str(), opts
, pp
));
1780 ASSERT_EQ(3, test_ls_pp(rbd
, ioctx
, 3, name
.c_str(), name2
.c_str(),
1782 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name3
.c_str(), NULL
));
1785 ASSERT_EQ(0, image3
.metadata_list("", 70, &pairs
));
1786 ASSERT_EQ(70U, pairs
.size());
1788 for (int i
= 1; i
<= 70; i
++) {
1789 key
= "key" + stringify(i
);
1790 val
= "value" + stringify(i
);
1791 ASSERT_EQ(0, image3
.metadata_get(key
.c_str(), &value
));
1792 ASSERT_STREQ(val
.c_str(), value
.c_str());
1799 int test_ls_snaps(rbd_image_t image
, int num_expected
, ...)
1801 int num_snaps
, i
, j
, max_size
= 10;
1803 rbd_snap_info_t snaps
[max_size
];
1804 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1805 printf("num snaps is: %d\nexpected: %d\n", num_snaps
, num_expected
);
1807 for (i
= 0; i
< num_snaps
; i
++) {
1808 printf("snap: %s\n", snaps
[i
].name
);
1811 va_start(ap
, num_expected
);
1812 for (i
= num_expected
; i
> 0; i
--) {
1813 char *expected
= va_arg(ap
, char *);
1814 uint64_t expected_size
= va_arg(ap
, uint64_t);
1816 for (j
= 0; j
< num_snaps
; j
++) {
1817 if (snaps
[j
].name
== NULL
)
1819 if (strcmp(snaps
[j
].name
, expected
) == 0) {
1820 printf("found %s with size %llu\n", snaps
[j
].name
, (unsigned long long) snaps
[j
].size
);
1821 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1822 free((void *) snaps
[j
].name
);
1823 snaps
[j
].name
= NULL
;
1832 for (i
= 0; i
< num_snaps
; i
++) {
1833 EXPECT_EQ((const char *)0, snaps
[i
].name
);
1839 TEST_F(TestLibRBD
, TestCreateLsDeleteSnap
)
1841 rados_ioctx_t ioctx
;
1842 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1846 std::string name
= get_temp_image_name();
1847 uint64_t size
= 2 << 20;
1848 uint64_t size2
= 4 << 20;
1850 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1851 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1853 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1854 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1855 ASSERT_EQ(0, rbd_resize(image
, size2
));
1856 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1857 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1858 ASSERT_EQ(0, rbd_snap_remove(image
, "snap1"));
1859 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1860 ASSERT_EQ(0, rbd_snap_remove(image
, "snap2"));
1861 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1863 ASSERT_EQ(0, rbd_close(image
));
1865 rados_ioctx_destroy(ioctx
);
1868 int test_get_snapshot_timestamp(rbd_image_t image
, uint64_t snap_id
)
1870 struct timespec timestamp
;
1871 EXPECT_EQ(0, rbd_snap_get_timestamp(image
, snap_id
, ×tamp
));
1872 EXPECT_LT(0, timestamp
.tv_sec
);
1876 TEST_F(TestLibRBD
, TestGetSnapShotTimeStamp
)
1878 REQUIRE_FORMAT_V2();
1880 rados_ioctx_t ioctx
;
1881 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
1885 std::string name
= get_temp_image_name();
1886 uint64_t size
= 2 << 20;
1887 int num_snaps
, max_size
= 10;
1888 rbd_snap_info_t snaps
[max_size
];
1890 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
1891 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
1893 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
1894 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1895 ASSERT_EQ(1, num_snaps
);
1896 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1897 free((void *)snaps
[0].name
);
1899 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
1900 num_snaps
= rbd_snap_list(image
, snaps
, &max_size
);
1901 ASSERT_EQ(2, num_snaps
);
1902 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[0].id
));
1903 ASSERT_EQ(0, test_get_snapshot_timestamp(image
, snaps
[1].id
));
1904 free((void *)snaps
[0].name
);
1905 free((void *)snaps
[1].name
);
1907 ASSERT_EQ(0, rbd_close(image
));
1909 rados_ioctx_destroy(ioctx
);
1913 int test_ls_snaps(librbd::Image
& image
, size_t num_expected
, ...)
1918 vector
<librbd::snap_info_t
> snaps
;
1919 r
= image
.snap_list(snaps
);
1920 EXPECT_TRUE(r
>= 0);
1921 cout
<< "num snaps is: " << snaps
.size() << std::endl
1922 << "expected: " << num_expected
<< std::endl
;
1924 for (i
= 0; i
< snaps
.size(); i
++) {
1925 cout
<< "snap: " << snaps
[i
].name
<< std::endl
;
1928 va_start(ap
, num_expected
);
1929 for (i
= num_expected
; i
> 0; i
--) {
1930 char *expected
= va_arg(ap
, char *);
1931 uint64_t expected_size
= va_arg(ap
, uint64_t);
1933 for (j
= 0; j
< snaps
.size(); j
++) {
1934 if (snaps
[j
].name
== "")
1936 if (strcmp(snaps
[j
].name
.c_str(), expected
) == 0) {
1937 cout
<< "found " << snaps
[j
].name
<< " with size " << snaps
[j
].size
1939 EXPECT_EQ(expected_size
, snaps
[j
].size
);
1949 for (i
= 0; i
< snaps
.size(); i
++) {
1950 EXPECT_EQ("", snaps
[i
].name
);
1953 return snaps
.size();
1956 TEST_F(TestLibRBD
, TestCreateLsDeleteSnapPP
)
1958 librados::IoCtx ioctx
;
1959 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
1963 librbd::Image image
;
1965 std::string name
= get_temp_image_name();
1966 uint64_t size
= 2 << 20;
1967 uint64_t size2
= 4 << 20;
1969 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
1970 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
1973 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1974 ASSERT_FALSE(exists
);
1975 ASSERT_EQ(0, image
.snap_create("snap1"));
1976 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1977 ASSERT_TRUE(exists
);
1978 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
1979 ASSERT_EQ(0, image
.resize(size2
));
1980 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1981 ASSERT_FALSE(exists
);
1982 ASSERT_EQ(0, image
.snap_create("snap2"));
1983 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1984 ASSERT_TRUE(exists
);
1985 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
1986 ASSERT_EQ(0, image
.snap_remove("snap1"));
1987 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
1988 ASSERT_FALSE(exists
);
1989 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2", size2
));
1990 ASSERT_EQ(0, image
.snap_remove("snap2"));
1991 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
1992 ASSERT_FALSE(exists
);
1993 ASSERT_EQ(0, test_ls_snaps(image
, 0));
1999 TEST_F(TestLibRBD
, TestGetNameIdSnapPP
)
2001 librados::IoCtx ioctx
;
2002 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2006 librbd::Image image
;
2008 std::string name
= get_temp_image_name();
2009 uint64_t size
= 2 << 20;
2011 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2012 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2014 ASSERT_EQ(0, image
.snap_create("snap1"));
2015 ASSERT_EQ(0, image
.snap_create("snap2"));
2016 ASSERT_EQ(0, image
.snap_create("snap3"));
2017 vector
<librbd::snap_info_t
> snaps
;
2018 int r
= image
.snap_list(snaps
);
2019 EXPECT_TRUE(r
>= 0);
2021 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
2022 std::string expected_snap_name
;
2023 image
.snap_get_name(snaps
[i
].id
, &expected_snap_name
);
2024 ASSERT_EQ(expected_snap_name
, snaps
[i
].name
);
2027 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
2028 uint64_t expected_snap_id
;
2029 image
.snap_get_id(snaps
[i
].name
, &expected_snap_id
);
2030 ASSERT_EQ(expected_snap_id
, snaps
[i
].id
);
2033 ASSERT_EQ(0, image
.snap_remove("snap1"));
2034 ASSERT_EQ(0, image
.snap_remove("snap2"));
2035 ASSERT_EQ(0, image
.snap_remove("snap3"));
2036 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2042 TEST_F(TestLibRBD
, TestCreateLsRenameSnapPP
)
2044 librados::IoCtx ioctx
;
2045 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2049 librbd::Image image
;
2051 std::string name
= get_temp_image_name();
2052 uint64_t size
= 2 << 20;
2053 uint64_t size2
= 4 << 20;
2055 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2056 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2059 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2060 ASSERT_FALSE(exists
);
2061 ASSERT_EQ(0, image
.snap_create("snap1"));
2062 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2063 ASSERT_TRUE(exists
);
2064 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap1", size
));
2065 ASSERT_EQ(0, image
.resize(size2
));
2066 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2067 ASSERT_FALSE(exists
);
2068 ASSERT_EQ(0, image
.snap_create("snap2"));
2069 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2070 ASSERT_TRUE(exists
);
2071 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1", size
, "snap2", size2
));
2072 ASSERT_EQ(0, image
.snap_rename("snap1","snap1-rename"));
2073 ASSERT_EQ(2, test_ls_snaps(image
, 2, "snap1-rename", size
, "snap2", size2
));
2074 ASSERT_EQ(0, image
.snap_exists2("snap1", &exists
));
2075 ASSERT_FALSE(exists
);
2076 ASSERT_EQ(0, image
.snap_exists2("snap1-rename", &exists
));
2077 ASSERT_TRUE(exists
);
2078 ASSERT_EQ(0, image
.snap_remove("snap1-rename"));
2079 ASSERT_EQ(0, image
.snap_rename("snap2","snap2-rename"));
2080 ASSERT_EQ(1, test_ls_snaps(image
, 1, "snap2-rename", size2
));
2081 ASSERT_EQ(0, image
.snap_exists2("snap2", &exists
));
2082 ASSERT_FALSE(exists
);
2083 ASSERT_EQ(0, image
.snap_exists2("snap2-rename", &exists
));
2084 ASSERT_TRUE(exists
);
2085 ASSERT_EQ(0, image
.snap_remove("snap2-rename"));
2086 ASSERT_EQ(0, test_ls_snaps(image
, 0));
2092 TEST_F(TestLibRBD
, ConcurrentCreatesUnvalidatedPool
)
2094 rados_ioctx_t ioctx
;
2095 ASSERT_EQ(0, rados_ioctx_create(_cluster
, create_pool(true).c_str(),
2098 std::vector
<std::string
> names
;
2099 for (int i
= 0; i
< 4; i
++) {
2100 names
.push_back(get_temp_image_name());
2102 uint64_t size
= 2 << 20;
2104 std::vector
<std::thread
> threads
;
2105 for (const auto& name
: names
) {
2106 threads
.emplace_back([ioctx
, &name
, size
]() {
2108 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2111 for (auto& thread
: threads
) {
2115 for (const auto& name
: names
) {
2116 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2118 rados_ioctx_destroy(ioctx
);
2121 static void remove_full_try(rados_ioctx_t ioctx
, const std::string
& image_name
,
2122 const std::string
& data_pool_name
)
2125 uint64_t quota
= 10 << 20;
2126 uint64_t size
= 5 * quota
;
2127 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), size
, &order
));
2129 std::string cmdstr
= "{\"prefix\": \"osd pool set-quota\", \"pool\": \"" +
2130 data_pool_name
+ "\", \"field\": \"max_bytes\", \"val\": \"" +
2131 std::to_string(quota
) + "\"}";
2133 cmd
[0] = (char *)cmdstr
.c_str();
2134 ASSERT_EQ(0, rados_mon_command(rados_ioctx_get_cluster(ioctx
),
2135 (const char **)cmd
, 1, "", 0, nullptr, 0,
2138 rados_set_pool_full_try(ioctx
);
2141 ASSERT_EQ(0, rbd_open(ioctx
, image_name
.c_str(), &image
, nullptr));
2144 size_t len
= 1 << 20;
2146 for (off
= 0; off
< size
; off
+= len
) {
2147 ret
= rbd_write_zeroes(image
, off
, len
,
2148 RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
,
2149 LIBRADOS_OP_FLAG_FADVISE_FUA
);
2153 ASSERT_EQ(ret
, len
);
2156 ASSERT_TRUE(off
>= quota
&& off
< size
);
2157 ASSERT_EQ(ret
, -EDQUOT
);
2159 ASSERT_EQ(0, rbd_close(image
));
2161 // make sure we have latest map that marked the pool full
2162 ASSERT_EQ(0, rados_wait_for_latest_osdmap(rados_ioctx_get_cluster(ioctx
)));
2163 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
2166 TEST_F(TestLibRBD
, RemoveFullTry
)
2168 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
2169 REQUIRE(!is_librados_test_stub(_rados
));
2171 rados_ioctx_t ioctx
;
2172 auto pool_name
= create_pool(true);
2173 ASSERT_EQ(0, rados_ioctx_create(_cluster
, pool_name
.c_str(), &ioctx
));
2174 // cancel out rbd_default_data_pool -- we need an image without
2175 // a separate data pool
2176 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_default_data_pool",
2177 pool_name
.c_str()));
2180 auto image_name
= get_temp_image_name();
2181 // FIXME: this is a workaround for rbd_trash object being created
2182 // on the first remove -- pre-create it to avoid bumping into quota
2183 ASSERT_EQ(0, create_image(ioctx
, image_name
.c_str(), 0, &order
));
2184 ASSERT_EQ(0, rbd_remove(ioctx
, image_name
.c_str()));
2185 remove_full_try(ioctx
, image_name
, pool_name
);
2187 rados_ioctx_destroy(ioctx
);
2190 TEST_F(TestLibRBD
, RemoveFullTryDataPool
)
2192 REQUIRE_FORMAT_V2();
2193 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
2194 REQUIRE(!is_librados_test_stub(_rados
));
2196 rados_ioctx_t ioctx
;
2197 auto pool_name
= create_pool(true);
2198 auto data_pool_name
= create_pool(true);
2199 ASSERT_EQ(0, rados_ioctx_create(_cluster
, pool_name
.c_str(), &ioctx
));
2200 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_default_data_pool",
2201 data_pool_name
.c_str()));
2203 auto image_name
= get_temp_image_name();
2204 remove_full_try(ioctx
, image_name
, data_pool_name
);
2206 rados_ioctx_destroy(ioctx
);
2209 TEST_F(TestLibRBD
, TestIO
)
2211 rados_ioctx_t ioctx
;
2212 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2216 std::string name
= get_temp_image_name();
2217 uint64_t size
= 2 << 20;
2219 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2220 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_read_from_replica_policy", "balance"));
2221 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2225 ASSERT_EQ(0, rbd_close(image
));
2227 rados_ioctx_destroy(ioctx
);
2230 TEST_F(TestLibRBD
, TestEncryptionLUKS1
)
2232 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2234 rados_ioctx_t ioctx
;
2235 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2238 std::string name
= get_temp_image_name();
2239 uint64_t size
= 32 << 20;
2241 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2242 ASSERT_EQ(0, rados_conf_set(
2243 _cluster
, "rbd_read_from_replica_policy", "balance"));
2246 rbd_encryption_luks1_format_options_t opts
= {
2247 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2248 .passphrase
= "password",
2249 .passphrase_size
= 8,
2251 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2253 #ifndef HAVE_LIBCRYPTSETUP
2254 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2255 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2256 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2257 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2259 ASSERT_EQ(0, rbd_encryption_format(
2260 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2261 ASSERT_EQ(-EEXIST
, rbd_encryption_load(
2262 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2267 write_test_data(image
, "test", 0, 4, 0, &passed
);
2268 ASSERT_TRUE(passed
);
2269 ASSERT_EQ(0, rbd_close(image
));
2271 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2272 ASSERT_EQ(0, rbd_encryption_load(
2273 image
, RBD_ENCRYPTION_FORMAT_LUKS1
, &opts
, sizeof(opts
)));
2274 read_test_data(image
, "test", 0, 4, 0, &passed
);
2275 ASSERT_TRUE(passed
);
2278 ASSERT_EQ(0, rbd_close(image
));
2279 rados_ioctx_destroy(ioctx
);
2282 TEST_F(TestLibRBD
, TestEncryptionLUKS2
)
2284 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING
));
2286 rados_ioctx_t ioctx
;
2287 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2290 std::string name
= get_temp_image_name();
2291 uint64_t size
= 32 << 20;
2293 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2294 ASSERT_EQ(0, rados_conf_set(
2295 _cluster
, "rbd_read_from_replica_policy", "balance"));
2298 rbd_encryption_luks2_format_options_t opts
= {
2299 .alg
= RBD_ENCRYPTION_ALGORITHM_AES256
,
2300 .passphrase
= "password",
2301 .passphrase_size
= 8,
2303 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2305 #ifndef HAVE_LIBCRYPTSETUP
2306 ASSERT_EQ(-ENOTSUP
, rbd_encryption_format(
2307 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2308 ASSERT_EQ(-ENOTSUP
, rbd_encryption_load(
2309 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2311 ASSERT_EQ(0, rbd_encryption_format(
2312 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2313 ASSERT_EQ(-EEXIST
, rbd_encryption_load(
2314 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2319 write_test_data(image
, "test", 0, 4, 0, &passed
);
2320 ASSERT_TRUE(passed
);
2321 ASSERT_EQ(0, rbd_close(image
));
2323 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2324 ASSERT_EQ(0, rbd_encryption_load(
2325 image
, RBD_ENCRYPTION_FORMAT_LUKS2
, &opts
, sizeof(opts
)));
2326 read_test_data(image
, "test", 0, 4, 0, &passed
);
2327 ASSERT_TRUE(passed
);
2330 ASSERT_EQ(0, rbd_close(image
));
2331 rados_ioctx_destroy(ioctx
);
2334 TEST_F(TestLibRBD
, TestIOWithIOHint
)
2336 rados_ioctx_t ioctx
;
2337 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2341 std::string name
= get_temp_image_name();
2342 uint64_t size
= 2 << 20;
2344 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2345 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2347 bool skip_discard
= is_skip_partial_discard_enabled(image
);
2349 char test_data
[TEST_IO_SIZE
+ 1];
2350 char zero_data
[TEST_IO_SIZE
+ 1];
2351 char mismatch_data
[TEST_IO_SIZE
+ 1];
2353 uint64_t mismatch_offset
;
2355 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2356 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2358 test_data
[TEST_IO_SIZE
] = '\0';
2359 memset(zero_data
, 0, sizeof(zero_data
));
2360 memset(mismatch_data
, 9, sizeof(mismatch_data
));
2362 for (i
= 0; i
< 5; ++i
)
2363 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2364 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2366 for (i
= 5; i
< 10; ++i
)
2367 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2368 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2370 for (i
= 0; i
< 5; ++i
)
2371 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
,
2372 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2374 for (i
= 5; i
< 10; ++i
)
2375 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
,
2376 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2378 for (i
= 0; i
< 5; ++i
)
2379 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
,
2380 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2382 for (i
= 5; i
< 10; ++i
)
2383 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
2384 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2386 // discard 2nd, 4th sections.
2387 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2388 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2390 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
,
2391 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2392 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2393 TEST_IO_SIZE
, TEST_IO_SIZE
,
2394 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2395 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
,
2396 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2397 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2398 TEST_IO_SIZE
*3, TEST_IO_SIZE
,
2399 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
2400 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2402 for (i
= 0; i
< 15; ++i
) {
2404 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2405 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2406 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2407 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2408 } else if (i
% 3 == 1) {
2409 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2410 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2411 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2412 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2414 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2415 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2416 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2417 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2420 for (i
= 0; i
< 15; ++i
) {
2422 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2423 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2424 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
,
2425 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2426 } else if (i
% 3 == 1) {
2427 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2428 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2429 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32,
2430 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2432 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2433 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2434 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32,
2435 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
2439 rbd_image_info_t info
;
2440 rbd_completion_t comp
;
2441 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2442 // can't read or write starting past end
2443 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2444 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2445 // reading through end returns amount up to end
2446 ASSERT_EQ(10, rbd_read2(image
, info
.size
- 10, 100, test_data
,
2447 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
));
2448 // writing through end returns amount up to end
2449 ASSERT_EQ(10, rbd_write2(image
, info
.size
- 10, 100, test_data
,
2450 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2452 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2453 ASSERT_EQ(0, rbd_aio_read2(image
, info
.size
, 1, test_data
, comp
,
2454 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2455 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2456 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2457 rbd_aio_release(comp
);
2459 ASSERT_PASSED(write_test_data
, image
, zero_data
, 0, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
2460 ASSERT_EQ(-EILSEQ
, rbd_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2461 &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2462 ASSERT_EQ(0U, mismatch_offset
);
2463 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2464 ASSERT_EQ(0, rbd_aio_compare_and_write(image
, 0, TEST_IO_SIZE
, mismatch_data
, mismatch_data
,
2465 comp
, &mismatch_offset
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
));
2466 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2467 ASSERT_EQ(0U, mismatch_offset
);
2468 rbd_aio_release(comp
);
2470 ASSERT_PASSED(validate_object_map
, image
);
2471 ASSERT_EQ(0, rbd_close(image
));
2473 rados_ioctx_destroy(ioctx
);
2476 TEST_F(TestLibRBD
, TestDataPoolIO
)
2478 REQUIRE_FORMAT_V2();
2480 rados_ioctx_t ioctx
;
2481 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2483 std::string data_pool_name
= create_pool(true);
2486 std::string name
= get_temp_image_name();
2487 uint64_t size
= 2 << 20;
2491 ASSERT_EQ(0, get_features(&old_format
, &features
));
2492 ASSERT_FALSE(old_format
);
2494 rbd_image_options_t image_options
;
2495 rbd_image_options_create(&image_options
);
2496 BOOST_SCOPE_EXIT( (&image_options
) ) {
2497 rbd_image_options_destroy(image_options
);
2498 } BOOST_SCOPE_EXIT_END
;
2500 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options
,
2501 RBD_IMAGE_OPTION_FEATURES
,
2503 ASSERT_EQ(0, rbd_image_options_set_string(image_options
,
2504 RBD_IMAGE_OPTION_DATA_POOL
,
2505 data_pool_name
.c_str()));
2507 ASSERT_EQ(0, rbd_create4(ioctx
, name
.c_str(), size
, image_options
));
2508 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2509 ASSERT_NE(-1, rbd_get_data_pool_id(image
));
2511 bool skip_discard
= is_skip_partial_discard_enabled(image
);
2513 char test_data
[TEST_IO_SIZE
+ 1];
2514 char zero_data
[TEST_IO_SIZE
+ 1];
2517 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2518 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2520 test_data
[TEST_IO_SIZE
] = '\0';
2521 memset(zero_data
, 0, sizeof(zero_data
));
2523 for (i
= 0; i
< 5; ++i
)
2524 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2526 for (i
= 5; i
< 10; ++i
)
2527 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2529 for (i
= 0; i
< 5; ++i
)
2530 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2532 for (i
= 5; i
< 10; ++i
)
2533 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2535 // discard 2nd, 4th sections.
2536 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
2537 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
2539 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
2540 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2541 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
2542 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
2543 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
2544 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
2545 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
2547 rbd_image_info_t info
;
2548 rbd_completion_t comp
;
2549 ASSERT_EQ(0, rbd_stat(image
, &info
, sizeof(info
)));
2550 // can't read or write starting past end
2551 ASSERT_EQ(-EINVAL
, rbd_write(image
, info
.size
, 1, test_data
));
2552 ASSERT_EQ(-EINVAL
, rbd_read(image
, info
.size
, 1, test_data
));
2553 // reading through end returns amount up to end
2554 ASSERT_EQ(10, rbd_read(image
, info
.size
- 10, 100, test_data
));
2555 // writing through end returns amount up to end
2556 ASSERT_EQ(10, rbd_write(image
, info
.size
- 10, 100, test_data
));
2558 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2559 ASSERT_EQ(0, rbd_aio_write(image
, info
.size
, 1, test_data
, comp
));
2560 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2561 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2562 rbd_aio_release(comp
);
2564 rbd_aio_create_completion(NULL
, (rbd_callback_t
) simple_read_cb
, &comp
);
2565 ASSERT_EQ(0, rbd_aio_read(image
, info
.size
, 1, test_data
, comp
));
2566 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2567 ASSERT_EQ(-EINVAL
, rbd_aio_get_return_value(comp
));
2568 rbd_aio_release(comp
);
2570 ASSERT_PASSED(validate_object_map
, image
);
2571 ASSERT_EQ(0, rbd_close(image
));
2573 rados_ioctx_destroy(ioctx
);
2576 TEST_F(TestLibRBD
, TestScatterGatherIO
)
2578 rados_ioctx_t ioctx
;
2579 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2583 std::string name
= get_temp_image_name();
2584 uint64_t size
= 20 << 20;
2586 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2587 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2589 std::string
write_buffer("This is a test");
2590 struct iovec bad_iovs
[] = {
2591 {.iov_base
= NULL
, .iov_len
= static_cast<size_t>(-1)}
2593 struct iovec write_iovs
[] = {
2594 {.iov_base
= &write_buffer
[0], .iov_len
= 5},
2595 {.iov_base
= &write_buffer
[5], .iov_len
= 3},
2596 {.iov_base
= &write_buffer
[8], .iov_len
= 2},
2597 {.iov_base
= &write_buffer
[10], .iov_len
= 4}
2600 rbd_completion_t comp
;
2601 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2602 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, write_iovs
, 0, 0, comp
));
2603 ASSERT_EQ(-EINVAL
, rbd_aio_writev(image
, bad_iovs
, 1, 0, comp
));
2604 ASSERT_EQ(0, rbd_aio_writev(image
, write_iovs
,
2605 sizeof(write_iovs
) / sizeof(struct iovec
),
2607 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2608 ASSERT_EQ(0, rbd_aio_get_return_value(comp
));
2609 rbd_aio_release(comp
);
2611 std::string
read_buffer(write_buffer
.size(), '1');
2612 struct iovec read_iovs
[] = {
2613 {.iov_base
= &read_buffer
[0], .iov_len
= 4},
2614 {.iov_base
= &read_buffer
[8], .iov_len
= 4},
2615 {.iov_base
= &read_buffer
[12], .iov_len
= 2}
2618 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2619 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, read_iovs
, 0, 0, comp
));
2620 ASSERT_EQ(-EINVAL
, rbd_aio_readv(image
, bad_iovs
, 1, 0, comp
));
2621 ASSERT_EQ(0, rbd_aio_readv(image
, read_iovs
,
2622 sizeof(read_iovs
) / sizeof(struct iovec
),
2624 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2625 ASSERT_EQ(10, rbd_aio_get_return_value(comp
));
2626 rbd_aio_release(comp
);
2627 ASSERT_EQ("This1111 is a ", read_buffer
);
2629 std::string
linear_buffer(write_buffer
.size(), '1');
2630 struct iovec linear_iovs
[] = {
2631 {.iov_base
= &linear_buffer
[4], .iov_len
= 4}
2633 rbd_aio_create_completion(NULL
, NULL
, &comp
);
2634 ASSERT_EQ(0, rbd_aio_readv(image
, linear_iovs
,
2635 sizeof(linear_iovs
) / sizeof(struct iovec
),
2637 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp
));
2638 ASSERT_EQ(4, rbd_aio_get_return_value(comp
));
2639 rbd_aio_release(comp
);
2640 ASSERT_EQ("1111This111111", linear_buffer
);
2642 ASSERT_PASSED(validate_object_map
, image
);
2643 ASSERT_EQ(0, rbd_close(image
));
2645 rados_ioctx_destroy(ioctx
);
2648 TEST_F(TestLibRBD
, TestEmptyDiscard
)
2650 rados_ioctx_t ioctx
;
2651 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2655 std::string name
= get_temp_image_name();
2656 uint64_t size
= 20 << 20;
2658 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2659 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
2661 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 1*1024*1024);
2662 ASSERT_PASSED(aio_discard_test_data
, image
, 0, 4*1024*1024);
2663 ASSERT_PASSED(aio_discard_test_data
, image
, 3*1024*1024, 1*1024*1024);
2665 ASSERT_PASSED(validate_object_map
, image
);
2666 ASSERT_EQ(0, rbd_close(image
));
2668 rados_ioctx_destroy(ioctx
);
2671 TEST_F(TestLibRBD
, TestFUA
)
2673 rados_ioctx_t ioctx
;
2674 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
2676 rbd_image_t image_write
;
2677 rbd_image_t image_read
;
2679 std::string name
= get_temp_image_name();
2680 uint64_t size
= 2 << 20;
2682 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
2683 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_write
, NULL
));
2684 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_read
, NULL
));
2686 // enable writeback cache
2687 rbd_flush(image_write
);
2689 char test_data
[TEST_IO_SIZE
+ 1];
2692 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2693 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2695 test_data
[TEST_IO_SIZE
] = '\0';
2696 for (i
= 0; i
< 5; ++i
)
2697 ASSERT_PASSED(write_test_data
, image_write
, test_data
,
2698 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2700 for (i
= 0; i
< 5; ++i
)
2701 ASSERT_PASSED(read_test_data
, image_read
, test_data
,
2702 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2704 for (i
= 5; i
< 10; ++i
)
2705 ASSERT_PASSED(aio_write_test_data
, image_write
, test_data
,
2706 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_FUA
);
2708 for (i
= 5; i
< 10; ++i
)
2709 ASSERT_PASSED(aio_read_test_data
, image_read
, test_data
,
2710 TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
2712 ASSERT_PASSED(validate_object_map
, image_write
);
2713 ASSERT_PASSED(validate_object_map
, image_read
);
2714 ASSERT_EQ(0, rbd_close(image_write
));
2715 ASSERT_EQ(0, rbd_close(image_read
));
2716 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
2717 rados_ioctx_destroy(ioctx
);
2720 void simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
2722 cout
<< "write completion cb called!" << std::endl
;
2725 void simple_read_cb_pp(librbd::completion_t cb
, void *arg
)
2727 cout
<< "read completion cb called!" << std::endl
;
2730 void aio_write_test_data(librbd::Image
& image
, const char *test_data
,
2731 off_t off
, uint32_t iohint
, bool *passed
)
2733 ceph::bufferlist bl
;
2734 bl
.append(test_data
, strlen(test_data
));
2735 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2736 printf("created completion\n");
2738 image
.aio_write2(off
, strlen(test_data
), bl
, comp
, iohint
);
2740 image
.aio_write(off
, strlen(test_data
), bl
, comp
);
2741 printf("started write\n");
2742 comp
->wait_for_complete();
2743 int r
= comp
->get_return_value();
2744 printf("return value is: %d\n", r
);
2746 printf("finished write\n");
2751 void aio_discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2753 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2754 image
.aio_discard(off
, len
, comp
);
2755 comp
->wait_for_complete();
2756 int r
= comp
->get_return_value();
2762 void write_test_data(librbd::Image
& image
, const char *test_data
, off_t off
, uint32_t iohint
, bool *passed
)
2765 size_t len
= strlen(test_data
);
2766 ceph::bufferlist bl
;
2767 bl
.append(test_data
, len
);
2769 written
= image
.write2(off
, len
, bl
, iohint
);
2771 written
= image
.write(off
, len
, bl
);
2772 printf("wrote: %u\n", (unsigned int) written
);
2773 ASSERT_EQ(bl
.length(), written
);
2777 void discard_test_data(librbd::Image
& image
, off_t off
, size_t len
, bool *passed
)
2780 written
= image
.discard(off
, len
);
2781 printf("discard: %u~%u\n", (unsigned)off
, (unsigned)len
);
2782 ASSERT_EQ(len
, written
);
2786 void aio_read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2788 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_read_cb_pp
);
2789 ceph::bufferlist bl
;
2790 printf("created completion\n");
2792 image
.aio_read2(off
, expected_len
, bl
, comp
, iohint
);
2794 image
.aio_read(off
, expected_len
, bl
, comp
);
2795 printf("started read\n");
2796 comp
->wait_for_complete();
2797 int r
= comp
->get_return_value();
2798 printf("return value is: %d\n", r
);
2799 ASSERT_EQ(TEST_IO_SIZE
, r
);
2800 ASSERT_EQ(0, memcmp(expected
, bl
.c_str(), TEST_IO_SIZE
));
2801 printf("finished read\n");
2806 void read_test_data(librbd::Image
& image
, const char *expected
, off_t off
, size_t expected_len
, uint32_t iohint
, bool *passed
)
2809 size_t len
= expected_len
;
2810 ceph::bufferlist bl
;
2812 read
= image
.read2(off
, len
, bl
, iohint
);
2814 read
= image
.read(off
, len
, bl
);
2815 ASSERT_TRUE(read
>= 0);
2816 std::string
bl_str(bl
.c_str(), read
);
2818 printf("read: %u\n", (unsigned int) read
);
2819 int result
= memcmp(bl_str
.c_str(), expected
, expected_len
);
2821 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), expected
);
2822 ASSERT_EQ(0, result
);
2827 void aio_writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2828 size_t len
, size_t data_len
, uint32_t iohint
, bool *passed
)
2830 ceph::bufferlist bl
;
2831 bl
.append(test_data
, data_len
);
2832 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2833 printf("created completion\n");
2835 r
= image
.aio_writesame(off
, len
, bl
, comp
, iohint
);
2836 printf("started writesame\n");
2837 if (len
% data_len
) {
2838 ASSERT_EQ(-EINVAL
, r
);
2839 printf("expected fail, finished writesame\n");
2845 comp
->wait_for_complete();
2846 r
= comp
->get_return_value();
2847 printf("return value is: %d\n", r
);
2849 printf("finished writesame\n");
2853 printf("to verify the data\n");
2855 uint64_t left
= len
;
2857 ceph::bufferlist bl
;
2858 read
= image
.read(off
, data_len
, bl
);
2859 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2860 std::string
bl_str(bl
.c_str(), read
);
2861 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2863 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2864 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2865 ASSERT_EQ(0, result
);
2870 ASSERT_EQ(0U, left
);
2871 printf("verified\n");
2876 void writesame_test_data(librbd::Image
& image
, const char *test_data
, off_t off
,
2877 ssize_t len
, size_t data_len
, uint32_t iohint
,
2881 ceph::bufferlist bl
;
2882 bl
.append(test_data
, data_len
);
2883 written
= image
.writesame(off
, len
, bl
, iohint
);
2884 if (len
% data_len
) {
2885 ASSERT_EQ(-EINVAL
, written
);
2886 printf("expected fail, finished writesame\n");
2890 ASSERT_EQ(len
, written
);
2891 printf("wrote: %u\n", (unsigned int) written
);
2895 printf("to verify the data\n");
2897 uint64_t left
= len
;
2899 ceph::bufferlist bl
;
2900 read
= image
.read(off
, data_len
, bl
);
2901 ASSERT_EQ(data_len
, static_cast<size_t>(read
));
2902 std::string
bl_str(bl
.c_str(), read
);
2903 int result
= memcmp(bl_str
.c_str(), test_data
, data_len
);
2905 printf("read: %u ~ %u\n", (unsigned int) off
, (unsigned int) read
);
2906 printf("read: %s\nexpected: %s\n", bl_str
.c_str(), test_data
);
2907 ASSERT_EQ(0, result
);
2912 ASSERT_EQ(0U, left
);
2913 printf("verified\n");
2918 void aio_compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
,
2919 const char *test_data
, off_t off
, ssize_t len
,
2920 uint32_t iohint
, bool *passed
)
2922 ceph::bufferlist cmp_bl
;
2923 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2924 ceph::bufferlist test_bl
;
2925 test_bl
.append(test_data
, strlen(test_data
));
2926 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
, (librbd::callback_t
) simple_write_cb_pp
);
2927 printf("created completion\n");
2929 uint64_t mismatch_offset
;
2930 image
.aio_compare_and_write(off
, len
, cmp_bl
, test_bl
, comp
, &mismatch_offset
, iohint
);
2931 printf("started aio compare and write\n");
2932 comp
->wait_for_complete();
2933 int r
= comp
->get_return_value();
2934 printf("return value is: %d\n", r
);
2936 printf("finished aio compare and write\n");
2941 void compare_and_write_test_data(librbd::Image
& image
, const char *cmp_data
, const char *test_data
,
2942 off_t off
, ssize_t len
, uint64_t *mismatch_off
, uint32_t iohint
, bool *passed
)
2945 ceph::bufferlist cmp_bl
;
2946 cmp_bl
.append(cmp_data
, strlen(cmp_data
));
2947 ceph::bufferlist test_bl
;
2948 test_bl
.append(test_data
, strlen(test_data
));
2949 printf("start compare and write\n");
2950 written
= image
.compare_and_write(off
, len
, cmp_bl
, test_bl
, mismatch_off
, iohint
);
2951 printf("compare and wrote: %d\n", (int) written
);
2952 ASSERT_EQ(len
, static_cast<ssize_t
>(written
));
2956 TEST_F(TestLibRBD
, TestIOPP
)
2958 librados::IoCtx ioctx
;
2959 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
2963 librbd::Image image
;
2965 std::string name
= get_temp_image_name();
2966 uint64_t size
= 2 << 20;
2968 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
2969 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
2971 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
2973 char test_data
[TEST_IO_SIZE
+ 1];
2974 char zero_data
[TEST_IO_SIZE
+ 1];
2976 uint64_t mismatch_offset
;
2978 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
2979 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
2981 test_data
[TEST_IO_SIZE
] = '\0';
2982 memset(zero_data
, 0, sizeof(zero_data
));
2984 for (i
= 0; i
< 5; ++i
)
2985 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2987 for (i
= 5; i
< 10; ++i
)
2988 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
, 0);
2990 for (i
= 0; i
< 5; ++i
)
2991 ASSERT_PASSED(compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
2992 TEST_IO_SIZE
, &mismatch_offset
, 0);
2994 for (i
= 5; i
< 10; ++i
)
2995 ASSERT_PASSED(aio_compare_and_write_test_data
, image
, test_data
, test_data
, TEST_IO_SIZE
* i
,
2998 for (i
= 0; i
< 5; ++i
)
2999 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
3001 for (i
= 5; i
< 10; ++i
)
3002 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
, TEST_IO_SIZE
, 0);
3004 // discard 2nd, 4th sections.
3005 ASSERT_PASSED(discard_test_data
, image
, TEST_IO_SIZE
, TEST_IO_SIZE
);
3006 ASSERT_PASSED(aio_discard_test_data
, image
, TEST_IO_SIZE
*3, TEST_IO_SIZE
);
3008 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_SIZE
, 0);
3009 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3010 TEST_IO_SIZE
, TEST_IO_SIZE
, 0);
3011 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*2, TEST_IO_SIZE
, 0);
3012 ASSERT_PASSED(read_test_data
, image
, skip_discard
? test_data
: zero_data
,
3013 TEST_IO_SIZE
*3, TEST_IO_SIZE
, 0);
3014 ASSERT_PASSED(read_test_data
, image
, test_data
, TEST_IO_SIZE
*4, TEST_IO_SIZE
, 0);
3016 for (i
= 0; i
< 15; ++i
) {
3018 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3019 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3020 } else if (i
% 3 == 1) {
3021 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3022 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
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);
3028 for (i
= 0; i
< 15; ++i
) {
3030 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3031 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, 0);
3032 } else if (i
% 3 == 1) {
3033 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
3034 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
, TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, 0);
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);
3041 ASSERT_PASSED(validate_object_map
, image
);
3047 TEST_F(TestLibRBD
, TestIOPPWithIOHint
)
3049 librados::IoCtx ioctx
;
3050 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
3054 librbd::Image image
;
3056 std::string name
= get_temp_image_name();
3057 uint64_t size
= 2 << 20;
3059 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
3060 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
3062 char test_data
[TEST_IO_SIZE
+ 1];
3063 char zero_data
[TEST_IO_SIZE
+ 1];
3064 test_data
[TEST_IO_SIZE
] = '\0';
3067 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
3068 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
3070 memset(zero_data
, 0, sizeof(zero_data
));
3072 for (i
= 0; i
< 5; ++i
)
3073 ASSERT_PASSED(write_test_data
, image
, test_data
, strlen(test_data
) * i
,
3074 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3076 for (i
= 5; i
< 10; ++i
)
3077 ASSERT_PASSED(aio_write_test_data
, image
, test_data
, strlen(test_data
) * i
,
3078 LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3080 ASSERT_PASSED(read_test_data
, image
, test_data
, strlen(test_data
),
3081 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_RANDOM
);
3083 for (i
= 5; i
< 10; ++i
)
3084 ASSERT_PASSED(aio_read_test_data
, image
, test_data
, strlen(test_data
) * i
,
3085 TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3087 for (i
= 0; i
< 15; ++i
) {
3089 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3090 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3091 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3092 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3093 } else if (i
% 3 == 1) {
3094 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
3095 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3096 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
3097 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3099 ASSERT_PASSED(writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3100 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3101 ASSERT_PASSED(writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3102 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
3105 for (i
= 0; i
< 15; ++i
) {
3107 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3108 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3109 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3110 TEST_IO_SIZE
* i
* 32 + i
, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3111 } else if (i
% 3 == 1) {
3112 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
+ i
,
3113 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3114 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
+ i
,
3115 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3117 ASSERT_PASSED(aio_writesame_test_data
, image
, test_data
, TEST_IO_SIZE
* i
,
3118 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3119 ASSERT_PASSED(aio_writesame_test_data
, image
, zero_data
, TEST_IO_SIZE
* i
,
3120 TEST_IO_SIZE
* i
* 32, TEST_IO_SIZE
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
3124 ASSERT_PASSED(validate_object_map
, image
);
3132 TEST_F(TestLibRBD
, TestIOToSnapshot
)
3134 rados_ioctx_t ioctx
;
3135 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3139 std::string name
= get_temp_image_name();
3140 uint64_t isize
= 2 << 20;
3142 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
3143 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3146 rbd_image_t image_at_snap
;
3147 char orig_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
3148 char test_data
[TEST_IO_TO_SNAP_SIZE
+ 1];
3150 for (i
= 0; i
< TEST_IO_TO_SNAP_SIZE
; ++i
)
3151 test_data
[i
] = (char) (i
+ 48);
3152 test_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
3153 orig_data
[TEST_IO_TO_SNAP_SIZE
] = '\0';
3155 r
= rbd_read(image
, 0, TEST_IO_TO_SNAP_SIZE
, orig_data
);
3156 ASSERT_EQ(r
, TEST_IO_TO_SNAP_SIZE
);
3158 ASSERT_EQ(0, test_ls_snaps(image
, 0));
3159 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
3160 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
3161 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3163 printf("write test data!\n");
3164 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3165 ASSERT_EQ(0, rbd_snap_create(image
, "written"));
3166 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
3168 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3170 rbd_snap_set(image
, "orig");
3171 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3173 rbd_snap_set(image
, "written");
3174 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3176 rbd_snap_set(image
, "orig");
3178 r
= rbd_write(image
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
3179 printf("write to snapshot returned %d\n", r
);
3181 cout
<< strerror(-r
) << std::endl
;
3183 ASSERT_PASSED(read_test_data
, image
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3184 rbd_snap_set(image
, "written");
3185 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3187 r
= rbd_snap_rollback(image
, "orig");
3188 ASSERT_EQ(r
, -EROFS
);
3190 r
= rbd_snap_set(image
, NULL
);
3192 r
= rbd_snap_rollback(image
, "orig");
3195 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3199 printf("opening testimg@orig\n");
3200 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image_at_snap
, "orig"));
3201 ASSERT_PASSED(read_test_data
, image_at_snap
, orig_data
, 0, TEST_IO_TO_SNAP_SIZE
, 0);
3202 r
= rbd_write(image_at_snap
, 0, TEST_IO_TO_SNAP_SIZE
, test_data
);
3203 printf("write to snapshot returned %d\n", r
);
3205 cout
<< strerror(-r
) << std::endl
;
3206 ASSERT_EQ(0, rbd_close(image_at_snap
));
3208 ASSERT_EQ(2, test_ls_snaps(image
, 2, "orig", isize
, "written", isize
));
3209 ASSERT_EQ(0, rbd_snap_remove(image
, "written"));
3210 ASSERT_EQ(1, test_ls_snaps(image
, 1, "orig", isize
));
3211 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
3212 ASSERT_EQ(0, test_ls_snaps(image
, 0));
3214 ASSERT_PASSED(validate_object_map
, image
);
3215 ASSERT_EQ(0, rbd_close(image
));
3217 rados_ioctx_destroy(ioctx
);
3220 TEST_F(TestLibRBD
, TestSnapshotDeletedIo
)
3222 rados_ioctx_t ioctx
;
3223 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3227 std::string name
= get_temp_image_name();
3228 uint64_t isize
= 2 << 20;
3232 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), isize
, &order
));
3233 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
3234 ASSERT_EQ(0, rbd_snap_create(image
, "orig"));
3236 r
= rbd_snap_set(image
, "orig");
3239 ASSERT_EQ(0, rbd_snap_remove(image
, "orig"));
3241 ASSERT_EQ(-ENOENT
, rbd_read(image
, 20, 20, test
));
3243 r
= rbd_snap_set(image
, NULL
);
3246 ASSERT_EQ(0, rbd_close(image
));
3247 rados_ioctx_destroy(ioctx
);
3250 TEST_F(TestLibRBD
, TestClone
)
3252 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3253 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "1"));
3254 BOOST_SCOPE_EXIT_ALL(&) {
3255 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
3258 rados_ioctx_t ioctx
;
3259 rbd_image_info_t pinfo
, cinfo
;
3260 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3264 rbd_image_t parent
, child
;
3267 ASSERT_EQ(0, get_features(&old_format
, &features
));
3268 ASSERT_FALSE(old_format
);
3270 std::string parent_name
= get_temp_image_name();
3271 std::string child_name
= get_temp_image_name();
3273 // make a parent to clone from
3274 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
3276 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
3277 printf("made parent image \"parent\"\n");
3279 char *data
= (char *)"testdata";
3280 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
3282 // can't clone a non-snapshot, expect failure
3283 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
3284 child_name
.c_str(), features
, &order
));
3286 // verify that there is no parent info on "parent"
3287 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
3288 printf("parent has no parent info\n");
3290 // create 70 metadatas to verify we can clone all key/value pairs
3293 size_t sum_key_len
= 0;
3294 size_t sum_value_len
= 0;
3295 for (int i
= 1; i
<= 70; i
++) {
3296 key
= "key" + stringify(i
);
3297 val
= "value" + stringify(i
);
3298 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
3300 sum_key_len
+= (key
.size() + 1);
3301 sum_value_len
+= (val
.size() + 1);
3306 size_t keys_len
= sizeof(keys
);
3307 size_t vals_len
= sizeof(vals
);
3310 size_t value_len
= sizeof(value
);
3312 // create a snapshot, reopen as the parent we're interested in
3313 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3314 printf("made snapshot \"parent@parent_snap\"\n");
3315 ASSERT_EQ(0, rbd_close(parent
));
3316 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
3318 ASSERT_EQ(-EINVAL
, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3319 ioctx
, child_name
.c_str(), features
, &order
));
3321 // unprotected image should fail unprotect
3322 ASSERT_EQ(-EINVAL
, rbd_snap_unprotect(parent
, "parent_snap"));
3323 printf("can't unprotect an unprotected snap\n");
3325 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3326 // protecting again should fail
3327 ASSERT_EQ(-EBUSY
, rbd_snap_protect(parent
, "parent_snap"));
3328 printf("can't protect a protected snap\n");
3330 // This clone and open should work
3331 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3332 ioctx
, child_name
.c_str(), features
, &order
));
3333 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
3334 printf("made and opened clone \"child\"\n");
3337 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
3340 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(child
, 20, strlen(data
), data
));
3341 ASSERT_PASSED(read_test_data
, child
, data
, 20, strlen(data
), 0);
3342 ASSERT_PASSED(read_test_data
, child
, data
, 0, strlen(data
), 0);
3345 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
3346 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3347 EXPECT_EQ(cinfo
.size
, pinfo
.size
);
3349 rbd_get_overlap(child
, &overlap
);
3350 EXPECT_EQ(overlap
, pinfo
.size
);
3351 EXPECT_EQ(cinfo
.obj_size
, pinfo
.obj_size
);
3352 EXPECT_EQ(cinfo
.order
, pinfo
.order
);
3353 printf("sizes and overlaps are good between parent and child\n");
3355 // check key/value pairs in child image
3356 ASSERT_EQ(0, rbd_metadata_list(child
, "key", 70, keys
, &keys_len
, vals
,
3358 ASSERT_EQ(sum_key_len
, keys_len
);
3359 ASSERT_EQ(sum_value_len
, vals_len
);
3361 for (int i
= 1; i
<= 70; i
++) {
3362 key
= "key" + stringify(i
);
3363 val
= "value" + stringify(i
);
3364 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3365 ASSERT_STREQ(val
.c_str(), value
);
3367 value_len
= sizeof(value
);
3369 printf("child image successfully cloned all image-meta pairs\n");
3371 // sizing down child results in changing overlap and size, not parent size
3372 ASSERT_EQ(0, rbd_resize(child
, 2UL<<20));
3373 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3374 rbd_get_overlap(child
, &overlap
);
3375 ASSERT_EQ(overlap
, 2UL<<20);
3376 ASSERT_EQ(cinfo
.size
, 2UL<<20);
3377 ASSERT_EQ(0, rbd_resize(child
, 4UL<<20));
3378 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3379 rbd_get_overlap(child
, &overlap
);
3380 ASSERT_EQ(overlap
, 2UL<<20);
3381 ASSERT_EQ(cinfo
.size
, 4UL<<20);
3382 printf("sized down clone, changed overlap\n");
3384 // sizing back up doesn't change that
3385 ASSERT_EQ(0, rbd_resize(child
, 5UL<<20));
3386 ASSERT_EQ(0, rbd_stat(child
, &cinfo
, sizeof(cinfo
)));
3387 rbd_get_overlap(child
, &overlap
);
3388 ASSERT_EQ(overlap
, 2UL<<20);
3389 ASSERT_EQ(cinfo
.size
, 5UL<<20);
3390 ASSERT_EQ(0, rbd_stat(parent
, &pinfo
, sizeof(pinfo
)));
3391 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
3392 (unsigned long long)pinfo
.size
, (unsigned long long)pinfo
.obj_size
,
3393 (unsigned long long)pinfo
.parent_pool
);
3394 ASSERT_EQ(pinfo
.size
, 4UL<<20);
3395 printf("sized up clone, changed size but not overlap or parent's size\n");
3397 ASSERT_PASSED(validate_object_map
, child
);
3398 ASSERT_EQ(0, rbd_close(child
));
3400 ASSERT_PASSED(validate_object_map
, parent
);
3401 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3402 printf("can't remove parent while child still exists\n");
3403 ASSERT_EQ(0, rbd_remove(ioctx
, child_name
.c_str()));
3404 ASSERT_EQ(-EBUSY
, rbd_snap_remove(parent
, "parent_snap"));
3405 printf("can't remove parent while still protected\n");
3406 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3407 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3408 printf("removed parent snap after unprotecting\n");
3410 ASSERT_EQ(0, rbd_close(parent
));
3411 rados_ioctx_destroy(ioctx
);
3414 TEST_F(TestLibRBD
, TestClone2
)
3416 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3417 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
3418 BOOST_SCOPE_EXIT_ALL(&) {
3419 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
3422 rados_ioctx_t ioctx
;
3423 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
3427 rbd_image_t parent
, child
;
3430 ASSERT_EQ(0, get_features(&old_format
, &features
));
3431 ASSERT_FALSE(old_format
);
3433 std::string parent_name
= get_temp_image_name();
3434 std::string child_name
= get_temp_image_name();
3436 // make a parent to clone from
3437 ASSERT_EQ(0, create_image_full(ioctx
, parent_name
.c_str(), 4<<20, &order
,
3439 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
3440 printf("made parent image \"parent\"\n");
3442 char *data
= (char *)"testdata";
3443 char *childata
= (char *)"childata";
3444 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
3445 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
3447 // can't clone a non-snapshot, expect failure
3448 EXPECT_NE(0, clone_image(ioctx
, parent
, parent_name
.c_str(), NULL
, ioctx
,
3449 child_name
.c_str(), features
, &order
));
3451 // verify that there is no parent info on "parent"
3452 ASSERT_EQ(-ENOENT
, rbd_get_parent_info(parent
, NULL
, 0, NULL
, 0, NULL
, 0));
3453 printf("parent has no parent info\n");
3455 // create 70 metadatas to verify we can clone all key/value pairs
3458 size_t sum_key_len
= 0;
3459 size_t sum_value_len
= 0;
3460 for (int i
= 1; i
<= 70; i
++) {
3461 key
= "key" + stringify(i
);
3462 val
= "value" + stringify(i
);
3463 ASSERT_EQ(0, rbd_metadata_set(parent
, key
.c_str(), val
.c_str()));
3465 sum_key_len
+= (key
.size() + 1);
3466 sum_value_len
+= (val
.size() + 1);
3471 size_t keys_len
= sizeof(keys
);
3472 size_t vals_len
= sizeof(vals
);
3475 size_t value_len
= sizeof(value
);
3477 // create a snapshot, reopen as the parent we're interested in
3478 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3479 printf("made snapshot \"parent@parent_snap\"\n");
3480 ASSERT_EQ(0, rbd_close(parent
));
3481 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
3483 // This clone and open should work
3484 ASSERT_EQ(0, clone_image(ioctx
, parent
, parent_name
.c_str(), "parent_snap",
3485 ioctx
, child_name
.c_str(), features
, &order
));
3486 ASSERT_EQ(0, rbd_open(ioctx
, child_name
.c_str(), &child
, NULL
));
3487 printf("made and opened clone \"child\"\n");
3489 // check key/value pairs in child image
3490 ASSERT_EQ(0, rbd_metadata_list(child
, "key", 70, keys
, &keys_len
, vals
,
3492 ASSERT_EQ(sum_key_len
, keys_len
);
3493 ASSERT_EQ(sum_value_len
, vals_len
);
3495 for (int i
= 1; i
<= 70; i
++) {
3496 key
= "key" + stringify(i
);
3497 val
= "value" + stringify(i
);
3498 ASSERT_EQ(0, rbd_metadata_get(child
, key
.c_str(), value
, &value_len
));
3499 ASSERT_STREQ(val
.c_str(), value
);
3501 value_len
= sizeof(value
);
3503 printf("child image successfully cloned all image-meta pairs\n");
3505 // write something in
3506 ASSERT_EQ((ssize_t
)strlen(childata
), rbd_write(child
, 20, strlen(childata
), childata
));
3508 char test
[strlen(data
) * 2];
3509 ASSERT_EQ((ssize_t
)strlen(data
), rbd_read(child
, 20, strlen(data
), test
));
3510 ASSERT_EQ(0, memcmp(test
, childata
, strlen(childata
)));
3513 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 20 - strlen(data
), sizeof(test
), test
));
3514 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3515 ASSERT_EQ(0, memcmp(test
+ strlen(data
), childata
, strlen(childata
)));
3518 ASSERT_EQ((ssize_t
)sizeof(test
), rbd_read(child
, 0, sizeof(test
), test
));
3519 ASSERT_EQ(0, memcmp(test
, data
, strlen(data
)));
3521 ASSERT_PASSED(validate_object_map
, child
);
3522 ASSERT_PASSED(validate_object_map
, parent
);
3524 rbd_snap_info_t snaps
[2];
3526 ASSERT_EQ(1, rbd_snap_list(parent
, snaps
, &max_snaps
));
3527 rbd_snap_list_end(snaps
);
3529 ASSERT_EQ(0, rbd_snap_remove_by_id(parent
, snaps
[0].id
));
3531 rbd_snap_namespace_type_t snap_namespace_type
;
3532 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent
, snaps
[0].id
,
3533 &snap_namespace_type
));
3534 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH
, snap_namespace_type
);
3536 char original_name
[32];
3537 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent
, snaps
[0].id
,
3539 sizeof(original_name
)));
3540 ASSERT_EQ(0, strcmp("parent_snap", original_name
));
3542 ASSERT_EQ(0, rbd_close(child
));
3543 ASSERT_EQ(0, rbd_close(parent
));
3544 rados_ioctx_destroy(ioctx
);
3547 static void test_list_children(rbd_image_t image
, ssize_t num_expected
, ...)
3550 va_start(ap
, num_expected
);
3551 size_t pools_len
= 100;
3552 size_t children_len
= 100;
3554 char *children
= NULL
;
3555 ssize_t num_children
;
3560 pools
= (char *) malloc(pools_len
);
3561 children
= (char *) malloc(children_len
);
3562 num_children
= rbd_list_children(image
, pools
, &pools_len
,
3563 children
, &children_len
);
3564 } while (num_children
== -ERANGE
);
3566 ASSERT_EQ(num_expected
, num_children
);
3567 for (ssize_t i
= num_expected
; i
> 0; --i
) {
3568 char *expected_pool
= va_arg(ap
, char *);
3569 char *expected_image
= va_arg(ap
, char *);
3571 char *image
= children
;
3573 printf("\ntrying to find %s/%s\n", expected_pool
, expected_image
);
3574 for (ssize_t j
= 0; j
< num_children
; ++j
) {
3575 printf("checking %s/%s\n", pool
, image
);
3576 if (strcmp(expected_pool
, pool
) == 0 &&
3577 strcmp(expected_image
, image
) == 0) {
3578 printf("found child %s/%s\n\n", pool
, image
);
3582 pool
+= strlen(pool
) + 1;
3583 image
+= strlen(image
) + 1;
3584 if (j
== num_children
- 1) {
3585 ASSERT_EQ(pool
- pools
- 1, (ssize_t
) pools_len
);
3586 ASSERT_EQ(image
- children
- 1, (ssize_t
) children_len
);
3599 static void test_list_children2(rbd_image_t image
, int num_expected
, ...)
3601 int num_children
, i
, j
, max_size
= 10;
3603 rbd_child_info_t children
[max_size
];
3604 num_children
= rbd_list_children2(image
, children
, &max_size
);
3605 printf("num children is: %d\nexpected: %d\n", num_children
, num_expected
);
3607 for (i
= 0; i
< num_children
; i
++) {
3608 printf("child: %s\n", children
[i
].image_name
);
3611 va_start(ap
, num_expected
);
3612 for (i
= num_expected
; i
> 0; i
--) {
3613 char *expected_id
= va_arg(ap
, char *);
3614 char *expected_pool
= va_arg(ap
, char *);
3615 char *expected_image
= va_arg(ap
, char *);
3616 bool expected_trash
= va_arg(ap
, int);
3618 for (j
= 0; j
< num_children
; j
++) {
3619 if (children
[j
].pool_name
== NULL
||
3620 children
[j
].image_name
== NULL
||
3621 children
[j
].image_id
== NULL
)
3623 if (strcmp(children
[j
].image_id
, expected_id
) == 0 &&
3624 strcmp(children
[j
].pool_name
, expected_pool
) == 0 &&
3625 strcmp(children
[j
].image_name
, expected_image
) == 0 &&
3626 children
[j
].trash
== expected_trash
) {
3627 printf("found child %s/%s/%s\n\n", children
[j
].pool_name
, children
[j
].image_name
, children
[j
].image_id
);
3628 rbd_list_child_cleanup(&children
[j
]);
3629 children
[j
].pool_name
= NULL
;
3630 children
[j
].image_name
= NULL
;
3631 children
[j
].image_id
= NULL
;
3640 for (i
= 0; i
< num_children
; i
++) {
3641 EXPECT_EQ((const char *)0, children
[i
].pool_name
);
3642 EXPECT_EQ((const char *)0, children
[i
].image_name
);
3643 EXPECT_EQ((const char *)0, children
[i
].image_id
);
3647 TEST_F(TestLibRBD
, ListChildren
)
3649 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3652 rados_ioctx_t ioctx1
, ioctx2
;
3653 string pool_name1
= create_pool(true);
3654 string pool_name2
= create_pool(true);
3655 ASSERT_NE("", pool_name2
);
3657 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3658 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3670 ASSERT_EQ(0, get_features(&old_format
, &features
));
3671 ASSERT_FALSE(old_format
);
3673 std::string parent_name
= get_temp_image_name();
3674 std::string child_name1
= get_temp_image_name();
3675 std::string child_name2
= get_temp_image_name();
3676 std::string child_name3
= get_temp_image_name();
3677 std::string child_name4
= get_temp_image_name();
3679 char child_id1
[4096];
3680 char child_id2
[4096];
3681 char child_id3
[4096];
3682 char child_id4
[4096];
3684 // make a parent to clone from
3685 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3687 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3688 // create a snapshot, reopen as the parent we're interested in
3689 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3690 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3691 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3693 ASSERT_EQ(0, rbd_close(parent
));
3694 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3696 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3697 ioctx2
, child_name1
.c_str(), features
, &order
));
3698 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3699 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3700 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3701 test_list_children2(parent
, 1,
3702 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3704 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3705 ioctx1
, child_name2
.c_str(), features
, &order
));
3706 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3707 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3708 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3709 pool_name1
.c_str(), child_name2
.c_str());
3710 test_list_children2(parent
, 2,
3711 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3712 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3714 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3715 ioctx2
, child_name3
.c_str(), features
, &order
));
3716 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3717 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3718 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3719 pool_name1
.c_str(), child_name2
.c_str(),
3720 pool_name2
.c_str(), child_name3
.c_str());
3721 test_list_children2(parent
, 3,
3722 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3723 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3724 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3726 librados::IoCtx ioctx3
;
3727 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3728 ASSERT_EQ(0, rbd_close(image3
));
3729 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3730 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3731 pool_name1
.c_str(), child_name2
.c_str());
3732 test_list_children2(parent
, 3,
3733 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3734 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3735 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3737 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3738 ioctx2
, child_name4
.c_str(), features
, &order
));
3739 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3740 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3741 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3742 pool_name1
.c_str(), child_name2
.c_str(),
3743 pool_name2
.c_str(), child_name4
.c_str());
3744 test_list_children2(parent
, 4,
3745 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3746 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3747 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3748 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3750 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3751 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3752 pool_name1
.c_str(), child_name2
.c_str(),
3753 pool_name2
.c_str(), child_name3
.c_str(),
3754 pool_name2
.c_str(), child_name4
.c_str());
3755 test_list_children2(parent
, 4,
3756 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3757 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3758 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3759 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3761 ASSERT_EQ(0, rbd_close(image1
));
3762 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3763 test_list_children(parent
, 3,
3764 pool_name1
.c_str(), child_name2
.c_str(),
3765 pool_name2
.c_str(), child_name3
.c_str(),
3766 pool_name2
.c_str(), child_name4
.c_str());
3767 test_list_children2(parent
, 3,
3768 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3769 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3770 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3772 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3773 test_list_children(parent
, 2,
3774 pool_name1
.c_str(), child_name2
.c_str(),
3775 pool_name2
.c_str(), child_name4
.c_str());
3776 test_list_children2(parent
, 2,
3777 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3778 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3780 ASSERT_EQ(0, rbd_close(image4
));
3781 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3782 test_list_children(parent
, 1,
3783 pool_name1
.c_str(), child_name2
.c_str());
3784 test_list_children2(parent
, 1,
3785 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3788 ASSERT_EQ(0, rbd_close(image2
));
3789 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3790 test_list_children(parent
, 0);
3791 test_list_children2(parent
, 0);
3793 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3794 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3795 ASSERT_EQ(0, rbd_close(parent
));
3796 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3797 rados_ioctx_destroy(ioctx1
);
3798 rados_ioctx_destroy(ioctx2
);
3801 TEST_F(TestLibRBD
, ListChildrenTiered
)
3803 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
3806 string pool_name1
= create_pool(true);
3807 string pool_name2
= create_pool(true);
3808 string pool_name3
= create_pool(true);
3809 ASSERT_NE("", pool_name1
);
3810 ASSERT_NE("", pool_name2
);
3811 ASSERT_NE("", pool_name3
);
3813 std::string cmdstr
= "{\"prefix\": \"osd tier add\", \"pool\": \"" +
3814 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\", \"force_nonempty\":\"\"}";
3816 cmd
[0] = (char *)cmdstr
.c_str();
3817 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3819 cmdstr
= "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
3820 pool_name3
+ "\", \"mode\":\"writeback\"}";
3821 cmd
[0] = (char *)cmdstr
.c_str();
3822 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3824 cmdstr
= "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
3825 pool_name1
+ "\", \"overlaypool\":\"" + pool_name3
+ "\"}";
3826 cmd
[0] = (char *)cmdstr
.c_str();
3827 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3829 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
3831 string parent_name
= get_temp_image_name();
3832 string child_name1
= get_temp_image_name();
3833 string child_name2
= get_temp_image_name();
3834 string child_name3
= get_temp_image_name();
3835 string child_name4
= get_temp_image_name();
3837 char child_id1
[4096];
3838 char child_id2
[4096];
3839 char child_id3
[4096];
3840 char child_id4
[4096];
3847 rados_ioctx_t ioctx1
, ioctx2
;
3848 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
3849 rados_ioctx_create(_cluster
, pool_name2
.c_str(), &ioctx2
);
3856 ASSERT_EQ(0, get_features(&old_format
, &features
));
3857 ASSERT_FALSE(old_format
);
3859 // make a parent to clone from
3860 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
3862 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
3863 // create a snapshot, reopen as the parent we're interested in
3864 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
3865 ASSERT_EQ(0, rbd_snap_set(parent
, "parent_snap"));
3866 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
3868 ASSERT_EQ(0, rbd_close(parent
));
3869 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, "parent_snap"));
3871 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3872 ioctx2
, child_name1
.c_str(), features
, &order
));
3873 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &image1
, NULL
));
3874 ASSERT_EQ(0, rbd_get_id(image1
, child_id1
, sizeof(child_id1
)));
3875 test_list_children(parent
, 1, pool_name2
.c_str(), child_name1
.c_str());
3876 test_list_children2(parent
, 1,
3877 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false);
3879 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3880 ioctx1
, child_name2
.c_str(), features
, &order
));
3881 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &image2
, NULL
));
3882 ASSERT_EQ(0, rbd_get_id(image2
, child_id2
, sizeof(child_id2
)));
3883 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3884 pool_name1
.c_str(), child_name2
.c_str());
3885 test_list_children2(parent
, 2,
3886 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3887 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3889 // read from the cache to populate it
3890 rbd_image_t tier_image
;
3891 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &tier_image
, NULL
));
3892 size_t len
= 4 * 1024 * 1024;
3893 char* buf
= (char*)malloc(len
);
3894 ssize_t size
= rbd_read(tier_image
, 0, len
, buf
);
3897 ASSERT_EQ(0, rbd_close(tier_image
));
3899 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3900 ioctx2
, child_name3
.c_str(), features
, &order
));
3901 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &image3
, NULL
));
3902 ASSERT_EQ(0, rbd_get_id(image3
, child_id3
, sizeof(child_id3
)));
3903 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3904 pool_name1
.c_str(), child_name2
.c_str(),
3905 pool_name2
.c_str(), child_name3
.c_str());
3906 test_list_children2(parent
, 3,
3907 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3908 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3909 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false);
3911 librados::IoCtx ioctx3
;
3912 ASSERT_EQ(0, _rados
.ioctx_create(pool_name2
.c_str(), ioctx3
));
3913 ASSERT_EQ(0, rbd_close(image3
));
3914 ASSERT_EQ(0, rbd
.trash_move(ioctx3
, child_name3
.c_str(), 0));
3915 test_list_children(parent
, 2, pool_name2
.c_str(), child_name1
.c_str(),
3916 pool_name1
.c_str(), child_name2
.c_str());
3917 test_list_children2(parent
, 3,
3918 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3919 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3920 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true);
3922 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "parent_snap",
3923 ioctx2
, child_name4
.c_str(), features
, &order
));
3924 ASSERT_EQ(0, rbd_open(ioctx2
, child_name4
.c_str(), &image4
, NULL
));
3925 ASSERT_EQ(0, rbd_get_id(image4
, child_id4
, sizeof(child_id4
)));
3926 test_list_children(parent
, 3, pool_name2
.c_str(), child_name1
.c_str(),
3927 pool_name1
.c_str(), child_name2
.c_str(),
3928 pool_name2
.c_str(), child_name4
.c_str());
3929 test_list_children2(parent
, 4,
3930 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3931 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3932 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), true,
3933 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3935 ASSERT_EQ(0, rbd
.trash_restore(ioctx3
, child_id3
, ""));
3936 test_list_children(parent
, 4, pool_name2
.c_str(), child_name1
.c_str(),
3937 pool_name1
.c_str(), child_name2
.c_str(),
3938 pool_name2
.c_str(), child_name3
.c_str(),
3939 pool_name2
.c_str(), child_name4
.c_str());
3940 test_list_children2(parent
, 4,
3941 child_id1
, pool_name2
.c_str(), child_name1
.c_str(), false,
3942 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3943 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3944 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3946 ASSERT_EQ(0, rbd_close(image1
));
3947 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name1
.c_str()));
3948 test_list_children(parent
, 3,
3949 pool_name1
.c_str(), child_name2
.c_str(),
3950 pool_name2
.c_str(), child_name3
.c_str(),
3951 pool_name2
.c_str(), child_name4
.c_str());
3952 test_list_children2(parent
, 3,
3953 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3954 child_id3
, pool_name2
.c_str(), child_name3
.c_str(), false,
3955 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3957 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name3
.c_str()));
3958 test_list_children(parent
, 2,
3959 pool_name1
.c_str(), child_name2
.c_str(),
3960 pool_name2
.c_str(), child_name4
.c_str());
3961 test_list_children2(parent
, 2,
3962 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
3963 child_id4
, pool_name2
.c_str(), child_name4
.c_str(), false);
3965 ASSERT_EQ(0, rbd_close(image4
));
3966 ASSERT_EQ(0, rbd_remove(ioctx2
, child_name4
.c_str()));
3967 test_list_children(parent
, 1,
3968 pool_name1
.c_str(), child_name2
.c_str());
3969 test_list_children2(parent
, 1,
3970 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false);
3972 ASSERT_EQ(0, rbd_close(image2
));
3973 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
3974 test_list_children(parent
, 0);
3975 test_list_children2(parent
, 0);
3977 ASSERT_EQ(0, rbd_snap_unprotect(parent
, "parent_snap"));
3978 ASSERT_EQ(0, rbd_snap_remove(parent
, "parent_snap"));
3979 ASSERT_EQ(0, rbd_close(parent
));
3980 ASSERT_EQ(0, rbd_remove(ioctx1
, parent_name
.c_str()));
3981 rados_ioctx_destroy(ioctx1
);
3982 rados_ioctx_destroy(ioctx2
);
3983 cmdstr
= "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
3985 cmd
[0] = (char *)cmdstr
.c_str();
3986 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3987 cmdstr
= "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
3988 pool_name1
+ "\", \"tierpool\":\"" + pool_name3
+ "\"}";
3989 cmd
[0] = (char *)cmdstr
.c_str();
3990 ASSERT_EQ(0, rados_mon_command(_cluster
, (const char **)cmd
, 1, "", 0, NULL
, 0, NULL
, 0));
3993 TEST_F(TestLibRBD
, LockingPP
)
3995 librados::IoCtx ioctx
;
3996 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4000 librbd::Image image
;
4002 std::string name
= get_temp_image_name();
4003 uint64_t size
= 2 << 20;
4004 std::string cookie1
= "foo";
4005 std::string cookie2
= "bar";
4007 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4008 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4010 // no lockers initially
4011 std::list
<librbd::locker_t
> lockers
;
4014 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4015 ASSERT_EQ(0u, lockers
.size());
4018 // exclusive lock is exclusive
4019 ASSERT_EQ(0, image
.lock_exclusive(cookie1
));
4020 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
4021 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
4022 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
4023 ASSERT_EQ(-EBUSY
, image
.lock_shared(cookie1
, "test"));
4024 ASSERT_EQ(-EBUSY
, image
.lock_shared("", "test"));
4025 ASSERT_EQ(-EBUSY
, image
.lock_shared("", ""));
4028 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4029 ASSERT_TRUE(exclusive
);
4031 ASSERT_EQ(1u, lockers
.size());
4032 ASSERT_EQ(cookie1
, lockers
.front().cookie
);
4035 ASSERT_EQ(-ENOENT
, image
.unlock(""));
4036 ASSERT_EQ(-ENOENT
, image
.unlock(cookie2
));
4037 ASSERT_EQ(0, image
.unlock(cookie1
));
4038 ASSERT_EQ(-ENOENT
, image
.unlock(cookie1
));
4039 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4040 ASSERT_EQ(0u, lockers
.size());
4042 ASSERT_EQ(0, image
.lock_shared(cookie1
, ""));
4043 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie1
, ""));
4044 ASSERT_EQ(0, image
.lock_shared(cookie2
, ""));
4045 ASSERT_EQ(-EEXIST
, image
.lock_shared(cookie2
, ""));
4046 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie1
));
4047 ASSERT_EQ(-EEXIST
, image
.lock_exclusive(cookie2
));
4048 ASSERT_EQ(-EBUSY
, image
.lock_exclusive(""));
4049 ASSERT_EQ(-EBUSY
, image
.lock_exclusive("test"));
4052 ASSERT_EQ(0, image
.list_lockers(&lockers
, &exclusive
, &tag
));
4053 ASSERT_EQ(2u, lockers
.size());
4059 TEST_F(TestLibRBD
, FlushAio
)
4061 rados_ioctx_t ioctx
;
4062 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4066 std::string name
= get_temp_image_name();
4067 uint64_t size
= 2 << 20;
4068 size_t num_aios
= 256;
4070 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4071 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4073 char test_data
[TEST_IO_SIZE
+ 1];
4075 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4076 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4079 rbd_completion_t write_comps
[num_aios
];
4080 for (i
= 0; i
< num_aios
; ++i
) {
4081 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &write_comps
[i
]));
4082 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4083 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
4087 rbd_completion_t flush_comp
;
4088 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &flush_comp
));
4089 ASSERT_EQ(0, rbd_aio_flush(image
, flush_comp
));
4090 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp
));
4091 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp
));
4092 rbd_aio_release(flush_comp
);
4094 for (i
= 0; i
< num_aios
; ++i
) {
4095 ASSERT_EQ(1, rbd_aio_is_complete(write_comps
[i
]));
4096 rbd_aio_release(write_comps
[i
]);
4099 ASSERT_PASSED(validate_object_map
, image
);
4100 ASSERT_EQ(0, rbd_close(image
));
4101 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
4102 rados_ioctx_destroy(ioctx
);
4105 TEST_F(TestLibRBD
, FlushAioPP
)
4107 librados::IoCtx ioctx
;
4108 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
4112 librbd::Image image
;
4114 std::string name
= get_temp_image_name();
4115 uint64_t size
= 2 << 20;
4116 const size_t num_aios
= 256;
4118 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4119 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4121 char test_data
[TEST_IO_SIZE
+ 1];
4123 for (i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4124 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4126 test_data
[TEST_IO_SIZE
] = '\0';
4128 librbd::RBD::AioCompletion
*write_comps
[num_aios
];
4129 ceph::bufferlist bls
[num_aios
];
4130 for (i
= 0; i
< num_aios
; ++i
) {
4131 bls
[i
].append(test_data
, strlen(test_data
));
4132 write_comps
[i
] = new librbd::RBD::AioCompletion(NULL
, NULL
);
4133 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4134 ASSERT_EQ(0, image
.aio_write(offset
, TEST_IO_SIZE
, bls
[i
],
4138 librbd::RBD::AioCompletion
*flush_comp
=
4139 new librbd::RBD::AioCompletion(NULL
, NULL
);
4140 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
4141 ASSERT_EQ(0, flush_comp
->wait_for_complete());
4142 ASSERT_EQ(1, flush_comp
->is_complete());
4143 flush_comp
->release();
4145 for (i
= 0; i
< num_aios
; ++i
) {
4146 librbd::RBD::AioCompletion
*comp
= write_comps
[i
];
4147 ASSERT_EQ(1, comp
->is_complete());
4150 ASSERT_PASSED(validate_object_map
, image
);
4157 int iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
4159 //cout << "iterate_cb " << off << "~" << len << std::endl;
4160 interval_set
<uint64_t> *diff
= static_cast<interval_set
<uint64_t> *>(arg
);
4161 diff
->insert(off
, len
);
4165 static int iterate_error_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
4170 void scribble(librbd::Image
& image
, int n
, int max
, bool skip_discard
,
4171 interval_set
<uint64_t> *exists
,
4172 interval_set
<uint64_t> *what
)
4176 interval_set
<uint64_t> exists_at_start
= *exists
;
4178 for (int i
=0; i
<n
; i
++) {
4179 uint64_t off
= rand() % (size
- max
+ 1);
4180 uint64_t len
= 1 + rand() % max
;
4181 if (!skip_discard
&& rand() % 4 == 0) {
4182 ASSERT_EQ((int)len
, image
.discard(off
, len
));
4183 interval_set
<uint64_t> w
;
4186 // the zeroed bit no longer exists...
4187 w
.intersection_of(*exists
);
4188 exists
->subtract(w
);
4190 // the bits we discarded are no long written...
4191 interval_set
<uint64_t> w2
= w
;
4192 w2
.intersection_of(*what
);
4195 // except for the extents that existed at the start that we overwrote.
4196 interval_set
<uint64_t> w3
;
4197 w3
.insert(off
, len
);
4198 w3
.intersection_of(exists_at_start
);
4203 bl
.append(buffer::create(len
));
4205 ASSERT_EQ((int)len
, image
.write(off
, len
, bl
));
4206 interval_set
<uint64_t> w
;
4209 exists
->union_of(w
);
4214 interval_set
<uint64_t> round_diff_interval(const interval_set
<uint64_t>& diff
,
4215 uint64_t object_size
)
4217 if (object_size
== 0) {
4221 interval_set
<uint64_t> rounded_diff
;
4222 for (interval_set
<uint64_t>::const_iterator it
= diff
.begin();
4223 it
!= diff
.end(); ++it
) {
4224 uint64_t off
= it
.get_start();
4225 uint64_t len
= it
.get_len();
4226 off
-= off
% object_size
;
4227 len
+= (object_size
- (len
% object_size
));
4228 interval_set
<uint64_t> interval
;
4229 interval
.insert(off
, len
);
4230 rounded_diff
.union_of(interval
);
4232 return rounded_diff
;
4235 template <typename T
>
4236 class DiffIterateTest
: public TestLibRBD
{
4238 static const uint8_t whole_object
= T::whole_object
;
4241 template <bool _whole_object
>
4242 class DiffIterateParams
{
4244 static const uint8_t whole_object
= _whole_object
;
4247 typedef ::testing::Types
<DiffIterateParams
<false>,
4248 DiffIterateParams
<true> > DiffIterateTypes
;
4249 TYPED_TEST_SUITE(DiffIterateTest
, DiffIterateTypes
);
4251 TYPED_TEST(DiffIterateTest
, DiffIterate
)
4253 librados::IoCtx ioctx
;
4254 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4258 librbd::Image image
;
4260 std::string name
= this->get_temp_image_name();
4261 uint64_t size
= 20 << 20;
4263 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4264 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4266 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4268 uint64_t object_size
= 0;
4269 if (this->whole_object
) {
4270 object_size
= 1 << order
;
4273 interval_set
<uint64_t> exists
;
4274 interval_set
<uint64_t> one
, two
;
4275 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4276 cout
<< " wrote " << one
<< std::endl
;
4277 ASSERT_EQ(0, image
.snap_create("one"));
4278 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4280 two
= round_diff_interval(two
, object_size
);
4281 cout
<< " wrote " << two
<< std::endl
;
4283 interval_set
<uint64_t> diff
;
4284 ASSERT_EQ(0, image
.diff_iterate2("one", 0, size
, true, this->whole_object
,
4285 iterate_cb
, (void *)&diff
));
4286 cout
<< " diff was " << diff
<< std::endl
;
4287 if (!two
.subset_of(diff
)) {
4288 interval_set
<uint64_t> i
;
4289 i
.intersection_of(two
, diff
);
4290 interval_set
<uint64_t> l
= two
;
4292 cout
<< " ... two - (two*diff) = " << l
<< std::endl
;
4294 ASSERT_TRUE(two
.subset_of(diff
));
4299 struct diff_extent
{
4300 diff_extent(uint64_t _offset
, uint64_t _length
, bool _exists
,
4301 uint64_t object_size
) :
4302 offset(_offset
), length(_length
), exists(_exists
)
4304 if (object_size
!= 0) {
4305 offset
-= offset
% object_size
;
4306 length
= object_size
;
4312 bool operator==(const diff_extent
& o
) const {
4313 return offset
== o
.offset
&& length
== o
.length
&& exists
== o
.exists
;
4317 ostream
& operator<<(ostream
& o
, const diff_extent
& e
) {
4318 return o
<< '(' << e
.offset
<< '~' << e
.length
<< ' ' << (e
.exists
? "true" : "false") << ')';
4321 int vector_iterate_cb(uint64_t off
, size_t len
, int exists
, void *arg
)
4323 cout
<< "iterate_cb " << off
<< "~" << len
<< std::endl
;
4324 vector
<diff_extent
> *diff
= static_cast<vector
<diff_extent
> *>(arg
);
4325 diff
->push_back(diff_extent(off
, len
, exists
, 0));
4329 TYPED_TEST(DiffIterateTest
, DiffIterateDiscard
)
4331 librados::IoCtx ioctx
;
4332 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4335 librbd::Image image
;
4337 std::string name
= this->get_temp_image_name();
4338 uint64_t size
= 20 << 20;
4340 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4341 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4343 uint64_t object_size
= 0;
4344 if (this->whole_object
) {
4345 object_size
= 1 << order
;
4347 vector
<diff_extent
> extents
;
4348 ceph::bufferlist bl
;
4350 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4351 vector_iterate_cb
, (void *) &extents
));
4352 ASSERT_EQ(0u, extents
.size());
4355 memset(data
, 1, sizeof(data
));
4356 bl
.append(data
, 256);
4357 ASSERT_EQ(256, image
.write(0, 256, bl
));
4358 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4359 vector_iterate_cb
, (void *) &extents
));
4360 ASSERT_EQ(1u, extents
.size());
4361 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4364 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4367 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4368 vector_iterate_cb
, (void *) &extents
));
4369 ASSERT_EQ(0u, extents
.size());
4371 ASSERT_EQ(0, image
.snap_create("snap1"));
4372 ASSERT_EQ(256, image
.write(0, 256, bl
));
4373 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4374 vector_iterate_cb
, (void *) &extents
));
4375 ASSERT_EQ(1u, extents
.size());
4376 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4377 ASSERT_EQ(0, image
.snap_create("snap2"));
4379 ASSERT_EQ(obj_ofs
, image
.discard(0, obj_ofs
));
4382 ASSERT_EQ(0, image
.snap_set("snap2"));
4383 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4384 vector_iterate_cb
, (void *) &extents
));
4385 ASSERT_EQ(1u, extents
.size());
4386 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4388 ASSERT_EQ(0, image
.snap_set(NULL
));
4389 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4390 ASSERT_EQ(0, image
.snap_create("snap3"));
4391 ASSERT_EQ(0, image
.snap_set("snap3"));
4394 ASSERT_EQ(0, image
.diff_iterate2("snap1", 0, size
, true, this->whole_object
,
4395 vector_iterate_cb
, (void *) &extents
));
4396 ASSERT_EQ(1u, extents
.size());
4397 ASSERT_EQ(diff_extent(0, 256, false, object_size
), extents
[0]);
4398 ASSERT_PASSED(this->validate_object_map
, image
);
4401 TYPED_TEST(DiffIterateTest
, DiffIterateStress
)
4403 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)this->_rados
.cct()));
4404 librados::IoCtx ioctx
;
4405 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4408 librbd::Image image
;
4410 std::string name
= this->get_temp_image_name();
4411 uint64_t size
= 400 << 20;
4413 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4414 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4416 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4418 uint64_t object_size
= 0;
4419 if (this->whole_object
) {
4420 object_size
= 1 << order
;
4423 interval_set
<uint64_t> curexists
;
4424 vector
<interval_set
<uint64_t> > wrote
;
4425 vector
<interval_set
<uint64_t> > exists
;
4426 vector
<string
> snap
;
4428 for (int i
=0; i
<n
; i
++) {
4429 interval_set
<uint64_t> w
;
4430 scribble(image
, 10, 8192000, skip_discard
, &curexists
, &w
);
4431 cout
<< " i=" << i
<< " exists " << curexists
<< " wrote " << w
<< std::endl
;
4432 string s
= "snap" + stringify(i
);
4433 ASSERT_EQ(0, image
.snap_create(s
.c_str()));
4435 exists
.push_back(curexists
);
4439 for (int h
=0; h
<n
-1; h
++) {
4440 for (int i
=0; i
<n
-h
-1; i
++) {
4441 for (int j
=(h
==0 ? i
+1 : n
-1); j
<n
; j
++) {
4442 interval_set
<uint64_t> diff
, actual
, uex
;
4443 for (int k
=i
+1; k
<=j
; k
++)
4444 diff
.union_of(wrote
[k
]);
4445 cout
<< "from " << i
<< " to "
4446 << (h
!= 0 ? string("HEAD") : stringify(j
)) << " diff "
4447 << round_diff_interval(diff
, object_size
) << std::endl
;
4449 // limit to extents that exists both at the beginning and at the end
4450 uex
.union_of(exists
[i
], exists
[j
]);
4451 diff
.intersection_of(uex
);
4452 diff
= round_diff_interval(diff
, object_size
);
4453 cout
<< " limited diff " << diff
<< std::endl
;
4455 ASSERT_EQ(0, image
.snap_set(h
==0 ? snap
[j
].c_str() : NULL
));
4456 ASSERT_EQ(0, image
.diff_iterate2(snap
[i
].c_str(), 0, size
, true,
4457 this->whole_object
, iterate_cb
,
4459 cout
<< " actual was " << actual
<< std::endl
;
4460 if (!diff
.subset_of(actual
)) {
4461 interval_set
<uint64_t> i
;
4462 i
.intersection_of(diff
, actual
);
4463 interval_set
<uint64_t> l
= diff
;
4465 cout
<< " ... diff - (actual*diff) = " << l
<< std::endl
;
4467 ASSERT_TRUE(diff
.subset_of(actual
));
4470 ASSERT_EQ(0, image
.snap_set(NULL
));
4471 ASSERT_EQ(0, image
.snap_remove(snap
[n
-h
-1].c_str()));
4474 ASSERT_PASSED(this->validate_object_map
, image
);
4477 TYPED_TEST(DiffIterateTest
, DiffIterateRegression6926
)
4479 librados::IoCtx ioctx
;
4480 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4483 librbd::Image image
;
4485 std::string name
= this->get_temp_image_name();
4486 uint64_t size
= 20 << 20;
4488 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4489 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4491 uint64_t object_size
= 0;
4492 if (this->whole_object
) {
4493 object_size
= 1 << order
;
4495 vector
<diff_extent
> extents
;
4496 ceph::bufferlist bl
;
4498 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4499 vector_iterate_cb
, (void *) &extents
));
4500 ASSERT_EQ(0u, extents
.size());
4502 ASSERT_EQ(0, image
.snap_create("snap1"));
4504 memset(data
, 1, sizeof(data
));
4505 bl
.append(data
, 256);
4506 ASSERT_EQ(256, image
.write(0, 256, bl
));
4509 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4510 vector_iterate_cb
, (void *) &extents
));
4511 ASSERT_EQ(1u, extents
.size());
4512 ASSERT_EQ(diff_extent(0, 256, true, object_size
), extents
[0]);
4514 ASSERT_EQ(0, image
.snap_set("snap1"));
4516 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4517 vector_iterate_cb
, (void *) &extents
));
4518 ASSERT_EQ(static_cast<size_t>(0), extents
.size());
4521 TYPED_TEST(DiffIterateTest
, DiffIterateParent
)
4523 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4525 librados::IoCtx ioctx
;
4526 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4530 librbd::Image image
;
4532 std::string name
= this->get_temp_image_name();
4533 ssize_t size
= 20 << 20;
4535 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4536 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4539 ASSERT_EQ(0, image
.features(&features
));
4540 uint64_t object_size
= 0;
4541 if (this->whole_object
) {
4542 object_size
= 1 << order
;
4545 ceph::bufferlist bl
;
4546 bl
.append(std::string(size
, '1'));
4547 ASSERT_EQ(size
, image
.write(0, size
, bl
));
4548 ASSERT_EQ(0, image
.snap_create("snap"));
4549 ASSERT_EQ(0, image
.snap_protect("snap"));
4551 std::string clone_name
= this->get_temp_image_name();
4552 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
,
4553 clone_name
.c_str(), features
, &order
));
4554 librbd::Image clone
;
4555 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
4557 std::vector
<diff_extent
> extents
;
4558 ASSERT_EQ(0, clone
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4559 vector_iterate_cb
, &extents
));
4560 ASSERT_EQ(5u, extents
.size());
4561 ASSERT_EQ(diff_extent(0, 4194304, true, object_size
), extents
[0]);
4562 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size
), extents
[1]);
4563 ASSERT_EQ(diff_extent(8388608, 4194304, true, object_size
), extents
[2]);
4564 ASSERT_EQ(diff_extent(12582912, 4194304, true, object_size
), extents
[3]);
4565 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size
), extents
[4]);
4568 ASSERT_EQ(0, clone
.resize(size
/ 2));
4569 ASSERT_EQ(0, clone
.resize(size
));
4570 ASSERT_EQ(1, clone
.write(size
- 1, 1, bl
));
4572 ASSERT_EQ(0, clone
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4573 vector_iterate_cb
, &extents
));
4574 ASSERT_EQ(4u, extents
.size());
4575 ASSERT_EQ(diff_extent(0, 4194304, true, object_size
), extents
[0]);
4576 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size
), extents
[1]);
4577 ASSERT_EQ(diff_extent(8388608, 2097152, true, object_size
), extents
[2]);
4578 // hole (parent overlap = 10M) followed by copyup'ed object
4579 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size
), extents
[3]);
4581 ASSERT_PASSED(this->validate_object_map
, image
);
4582 ASSERT_PASSED(this->validate_object_map
, clone
);
4588 TYPED_TEST(DiffIterateTest
, DiffIterateIgnoreParent
)
4590 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4592 librados::IoCtx ioctx
;
4593 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4596 librbd::Image image
;
4597 std::string name
= this->get_temp_image_name();
4598 uint64_t size
= 20 << 20;
4601 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4602 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4604 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4607 ASSERT_EQ(0, image
.features(&features
));
4608 uint64_t object_size
= 0;
4609 if (this->whole_object
) {
4610 object_size
= 1 << order
;
4614 bl
.append(buffer::create(size
));
4616 interval_set
<uint64_t> one
;
4617 one
.insert(0, size
);
4618 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
4619 ASSERT_EQ(0, image
.snap_create("one"));
4620 ASSERT_EQ(0, image
.snap_protect("one"));
4622 std::string clone_name
= this->get_temp_image_name();
4623 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
4625 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4627 interval_set
<uint64_t> exists
;
4628 interval_set
<uint64_t> two
;
4629 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4630 two
= round_diff_interval(two
, object_size
);
4631 cout
<< " wrote " << two
<< " to clone" << std::endl
;
4633 interval_set
<uint64_t> diff
;
4634 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, false, this->whole_object
,
4635 iterate_cb
, (void *)&diff
));
4636 cout
<< " diff was " << diff
<< std::endl
;
4637 if (!this->whole_object
) {
4638 ASSERT_FALSE(one
.subset_of(diff
));
4640 ASSERT_TRUE(two
.subset_of(diff
));
4643 TYPED_TEST(DiffIterateTest
, DiffIterateCallbackError
)
4645 librados::IoCtx ioctx
;
4646 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4650 librbd::Image image
;
4652 std::string name
= this->get_temp_image_name();
4653 uint64_t size
= 20 << 20;
4655 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4656 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4658 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4660 interval_set
<uint64_t> exists
;
4661 interval_set
<uint64_t> one
;
4662 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4663 cout
<< " wrote " << one
<< std::endl
;
4665 interval_set
<uint64_t> diff
;
4666 ASSERT_EQ(-EINVAL
, image
.diff_iterate2(NULL
, 0, size
, true,
4668 iterate_error_cb
, NULL
));
4673 TYPED_TEST(DiffIterateTest
, DiffIterateParentDiscard
)
4675 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4677 librados::IoCtx ioctx
;
4678 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4681 librbd::Image image
;
4682 std::string name
= this->get_temp_image_name();
4683 uint64_t size
= 20 << 20;
4686 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4687 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4689 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
4692 ASSERT_EQ(0, image
.features(&features
));
4693 uint64_t object_size
= 0;
4694 if (this->whole_object
) {
4695 object_size
= 1 << order
;
4698 interval_set
<uint64_t> exists
;
4699 interval_set
<uint64_t> one
;
4700 scribble(image
, 10, 102400, skip_discard
, &exists
, &one
);
4701 ASSERT_EQ(0, image
.snap_create("one"));
4703 ASSERT_EQ(1 << order
, image
.discard(0, 1 << order
));
4704 ASSERT_EQ(0, image
.snap_create("two"));
4705 ASSERT_EQ(0, image
.snap_protect("two"));
4709 std::string clone_name
= this->get_temp_image_name();
4710 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "two", ioctx
,
4711 clone_name
.c_str(), features
, &order
));
4712 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
4714 interval_set
<uint64_t> two
;
4715 scribble(image
, 10, 102400, skip_discard
, &exists
, &two
);
4716 two
= round_diff_interval(two
, object_size
);
4718 interval_set
<uint64_t> diff
;
4719 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 0, size
, true, this->whole_object
,
4720 iterate_cb
, (void *)&diff
));
4721 ASSERT_TRUE(two
.subset_of(diff
));
4724 TYPED_TEST(DiffIterateTest
, DiffIterateUnalignedSmall
)
4726 librados::IoCtx ioctx
;
4727 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4731 librbd::Image image
;
4733 std::string name
= this->get_temp_image_name();
4734 ssize_t size
= 10 << 20;
4736 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4737 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4739 ceph::bufferlist bl
;
4740 bl
.append(std::string(size
, '1'));
4741 ASSERT_EQ(size
, image
.write(0, size
, bl
));
4743 std::vector
<diff_extent
> extents
;
4744 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 5000005, 1234, true,
4745 this->whole_object
, vector_iterate_cb
,
4747 ASSERT_EQ(1u, extents
.size());
4748 ASSERT_EQ(diff_extent(5000005, 1234, true, 0), extents
[0]);
4750 ASSERT_PASSED(this->validate_object_map
, image
);
4756 TYPED_TEST(DiffIterateTest
, DiffIterateUnaligned
)
4758 librados::IoCtx ioctx
;
4759 ASSERT_EQ(0, this->_rados
.ioctx_create(this->m_pool_name
.c_str(), ioctx
));
4763 librbd::Image image
;
4765 std::string name
= this->get_temp_image_name();
4766 ssize_t size
= 20 << 20;
4768 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
4769 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
4771 ceph::bufferlist bl
;
4772 bl
.append(std::string(size
, '1'));
4773 ASSERT_EQ(size
, image
.write(0, size
, bl
));
4775 std::vector
<diff_extent
> extents
;
4776 ASSERT_EQ(0, image
.diff_iterate2(NULL
, 8376263, 4260970, true,
4777 this->whole_object
, vector_iterate_cb
,
4779 ASSERT_EQ(3u, extents
.size());
4780 ASSERT_EQ(diff_extent(8376263, 12345, true, 0), extents
[0]);
4781 ASSERT_EQ(diff_extent(8388608, 4194304, true, 0), extents
[1]);
4782 ASSERT_EQ(diff_extent(12582912, 54321, true, 0), extents
[2]);
4784 ASSERT_PASSED(this->validate_object_map
, image
);
4790 TEST_F(TestLibRBD
, ZeroLengthWrite
)
4792 rados_ioctx_t ioctx
;
4793 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4797 std::string name
= get_temp_image_name();
4798 uint64_t size
= 2 << 20;
4800 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4801 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4804 ASSERT_EQ(0, rbd_write(image
, 0, 0, NULL
));
4805 ASSERT_EQ(1, rbd_read(image
, 0, 1, read_data
));
4806 ASSERT_EQ('\0', read_data
[0]);
4808 ASSERT_PASSED(validate_object_map
, image
);
4809 ASSERT_EQ(0, rbd_close(image
));
4811 rados_ioctx_destroy(ioctx
);
4815 TEST_F(TestLibRBD
, ZeroLengthDiscard
)
4817 rados_ioctx_t ioctx
;
4818 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4822 std::string name
= get_temp_image_name();
4823 uint64_t size
= 2 << 20;
4825 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4826 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4828 const char data
[] = "blah";
4829 char read_data
[sizeof(data
)];
4830 ASSERT_EQ((int)strlen(data
), rbd_write(image
, 0, strlen(data
), data
));
4831 ASSERT_EQ(0, rbd_discard(image
, 0, 0));
4832 ASSERT_EQ((int)strlen(data
), rbd_read(image
, 0, strlen(data
), read_data
));
4833 ASSERT_EQ(0, memcmp(data
, read_data
, strlen(data
)));
4835 ASSERT_PASSED(validate_object_map
, image
);
4836 ASSERT_EQ(0, rbd_close(image
));
4838 rados_ioctx_destroy(ioctx
);
4841 TEST_F(TestLibRBD
, ZeroLengthRead
)
4843 rados_ioctx_t ioctx
;
4844 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4848 std::string name
= get_temp_image_name();
4849 uint64_t size
= 2 << 20;
4851 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4852 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4855 ASSERT_EQ(0, rbd_read(image
, 0, 0, read_data
));
4857 ASSERT_EQ(0, rbd_close(image
));
4859 rados_ioctx_destroy(ioctx
);
4862 TEST_F(TestLibRBD
, LargeCacheRead
)
4864 std::string config_value
;
4865 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", config_value
));
4866 if (config_value
== "false") {
4867 std::cout
<< "SKIPPING due to disabled cache" << std::endl
;
4871 rados_ioctx_t ioctx
;
4872 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4874 uint32_t new_cache_size
= 1 << 20;
4875 std::string orig_cache_size
;
4876 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", orig_cache_size
));
4877 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size",
4878 stringify(new_cache_size
).c_str()));
4879 ASSERT_EQ(0, _rados
.conf_get("rbd_cache_size", config_value
));
4880 ASSERT_EQ(stringify(new_cache_size
), config_value
);
4881 BOOST_SCOPE_EXIT( (orig_cache_size
) ) {
4882 ASSERT_EQ(0, _rados
.conf_set("rbd_cache_size", orig_cache_size
.c_str()));
4883 } BOOST_SCOPE_EXIT_END
;
4887 std::string name
= get_temp_image_name();
4888 uint64_t size
= 1 << order
;
4890 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
4891 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4893 std::string
buffer(1 << order
, '1');
4895 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
4896 rbd_write(image
, 0, buffer
.size(), buffer
.c_str()));
4898 ASSERT_EQ(0, rbd_invalidate_cache(image
));
4900 ASSERT_EQ(static_cast<ssize_t
>(buffer
.size()),
4901 rbd_read(image
, 0, buffer
.size(), &buffer
[0]));
4903 ASSERT_EQ(0, rbd_close(image
));
4905 rados_ioctx_destroy(ioctx
);
4908 TEST_F(TestLibRBD
, TestPendingAio
)
4910 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
4912 rados_ioctx_t ioctx
;
4913 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
4920 ASSERT_EQ(0, get_features(&old_format
, &features
));
4921 ASSERT_FALSE(old_format
);
4923 std::string name
= get_temp_image_name();
4925 uint64_t size
= 4 << 20;
4926 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
4928 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
4930 ASSERT_EQ(0, rbd_invalidate_cache(image
));
4932 char test_data
[TEST_IO_SIZE
];
4933 for (size_t i
= 0; i
< TEST_IO_SIZE
; ++i
) {
4934 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
4937 size_t num_aios
= 256;
4938 rbd_completion_t comps
[num_aios
];
4939 for (size_t i
= 0; i
< num_aios
; ++i
) {
4940 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
4941 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4942 ASSERT_EQ(0, rbd_aio_write(image
, offset
, TEST_IO_SIZE
, test_data
,
4945 for (size_t i
= 0; i
< num_aios
; ++i
) {
4946 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps
[i
]));
4947 rbd_aio_release(comps
[i
]);
4949 ASSERT_EQ(0, rbd_invalidate_cache(image
));
4951 for (size_t i
= 0; i
< num_aios
; ++i
) {
4952 ASSERT_EQ(0, rbd_aio_create_completion(NULL
, NULL
, &comps
[i
]));
4953 uint64_t offset
= rand() % (size
- TEST_IO_SIZE
);
4954 ASSERT_LE(0, rbd_aio_read(image
, offset
, TEST_IO_SIZE
, test_data
,
4958 ASSERT_PASSED(validate_object_map
, image
);
4959 ASSERT_EQ(0, rbd_close(image
));
4960 for (size_t i
= 0; i
< num_aios
; ++i
) {
4961 ASSERT_EQ(1, rbd_aio_is_complete(comps
[i
]));
4962 rbd_aio_release(comps
[i
]);
4965 rados_ioctx_destroy(ioctx
);
4968 void compare_and_write_copyup(librados::IoCtx
&ioctx
, bool deep_copyup
,
4972 std::string parent_name
= TestLibRBD::get_temp_image_name();
4973 uint64_t size
= 2 << 20;
4975 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
4977 librbd::Image parent_image
;
4978 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
4981 bl
.append(std::string(4096, '1'));
4982 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
4984 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
4985 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
4988 ASSERT_EQ(0, parent_image
.features(&features
));
4990 std::string clone_name
= TestLibRBD::get_temp_image_name();
4991 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
4992 clone_name
.c_str(), features
, &order
));
4994 librbd::Image clone_image
;
4995 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
4997 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
5001 cmp_bl
.append(std::string(96, '1'));
5002 bufferlist write_bl
;
5003 write_bl
.append(std::string(512, '2'));
5004 uint64_t mismatch_off
;
5005 ASSERT_EQ((ssize_t
)write_bl
.length(),
5006 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
5007 write_bl
, &mismatch_off
, 0));
5010 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
5012 bufferlist expected_bl
;
5013 expected_bl
.append(std::string(512, '1'));
5014 expected_bl
.append(std::string(512, '2'));
5015 expected_bl
.append(std::string(3072, '1'));
5016 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
5020 TEST_F(TestLibRBD
, CompareAndWriteCopyup
)
5022 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5024 librados::IoCtx ioctx
;
5025 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5027 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, false);
5028 ASSERT_PASSED(compare_and_write_copyup
, ioctx
, true);
5031 void compare_and_write_copyup_mismatch(librados::IoCtx
&ioctx
,
5032 bool deep_copyup
, bool *passed
)
5035 std::string parent_name
= TestLibRBD::get_temp_image_name();
5036 uint64_t size
= 2 << 20;
5038 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5040 librbd::Image parent_image
;
5041 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5044 bl
.append(std::string(4096, '1'));
5045 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
5047 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5048 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5051 ASSERT_EQ(0, parent_image
.features(&features
));
5053 std::string clone_name
= TestLibRBD::get_temp_image_name();
5054 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5055 clone_name
.c_str(), features
, &order
));
5057 librbd::Image clone_image
;
5058 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
5060 ASSERT_EQ(0, clone_image
.snap_create("snap1"));
5064 cmp_bl
.append(std::string(48, '1'));
5065 cmp_bl
.append(std::string(48, '3'));
5066 bufferlist write_bl
;
5067 write_bl
.append(std::string(512, '2'));
5068 uint64_t mismatch_off
;
5070 clone_image
.compare_and_write(512, write_bl
.length(), cmp_bl
,
5071 write_bl
, &mismatch_off
, 0));
5072 ASSERT_EQ(48U, mismatch_off
);
5075 ASSERT_EQ(4096, clone_image
.read(0, 4096, read_bl
));
5077 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5081 TEST_F(TestLibRBD
, CompareAndWriteCopyupMismatch
)
5083 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5085 librados::IoCtx ioctx
;
5086 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5088 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, false);
5089 ASSERT_PASSED(compare_and_write_copyup_mismatch
, ioctx
, true);
5092 TEST_F(TestLibRBD
, Flatten
)
5094 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5096 librados::IoCtx ioctx
;
5097 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5100 std::string parent_name
= get_temp_image_name();
5101 uint64_t size
= 2 << 20;
5103 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5105 librbd::Image parent_image
;
5106 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5109 bl
.append(std::string(4096, '1'));
5110 ASSERT_EQ((ssize_t
)bl
.length(), parent_image
.write(0, bl
.length(), bl
));
5112 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5113 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5116 ASSERT_EQ(0, parent_image
.features(&features
));
5118 std::string clone_name
= get_temp_image_name();
5119 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5120 clone_name
.c_str(), features
, &order
));
5122 librbd::Image clone_image
;
5123 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
5124 ASSERT_EQ(0, clone_image
.flatten());
5126 librbd::RBD::AioCompletion
*read_comp
=
5127 new librbd::RBD::AioCompletion(NULL
, NULL
);
5129 clone_image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
5130 ASSERT_EQ(0, read_comp
->wait_for_complete());
5131 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
5132 read_comp
->release();
5133 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5135 ASSERT_PASSED(validate_object_map
, clone_image
);
5138 TEST_F(TestLibRBD
, Sparsify
)
5140 rados_ioctx_t ioctx
;
5141 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
5142 BOOST_SCOPE_EXIT_ALL(&ioctx
) {
5143 rados_ioctx_destroy(ioctx
);
5146 const size_t CHUNK_SIZE
= 4096 * 2;
5149 std::string name
= get_temp_image_name();
5150 uint64_t size
= CHUNK_SIZE
* 1024;
5152 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5153 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5154 BOOST_SCOPE_EXIT_ALL(&image
) {
5158 char test_data
[4 * CHUNK_SIZE
+ 1];
5159 for (size_t i
= 0; i
< 4 ; ++i
) {
5160 for (size_t j
= 0; j
< CHUNK_SIZE
; j
++) {
5162 test_data
[i
* CHUNK_SIZE
+ j
] = (char)(rand() % (126 - 33) + 33);
5164 test_data
[i
* CHUNK_SIZE
+ j
] = '\0';
5168 test_data
[4 * CHUNK_SIZE
] = '\0';
5170 ASSERT_PASSED(write_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
5171 ASSERT_EQ(0, rbd_flush(image
));
5173 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 16));
5174 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 1 << (order
+ 1)));
5175 ASSERT_EQ(-EINVAL
, rbd_sparsify(image
, 4096 + 1));
5176 ASSERT_EQ(0, rbd_sparsify(image
, 4096));
5178 ASSERT_PASSED(read_test_data
, image
, test_data
, 0, 4 * CHUNK_SIZE
, 0);
5181 TEST_F(TestLibRBD
, SparsifyPP
)
5183 librados::IoCtx ioctx
;
5184 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5187 std::string name
= get_temp_image_name();
5188 uint64_t size
= 12 * 1024 * 1024;
5190 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5192 librbd::Image image
;
5193 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
5196 bl
.append(std::string(4096, '\0'));
5197 bl
.append(std::string(4096, '1'));
5198 bl
.append(std::string(4096, '\0'));
5199 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
5200 ASSERT_EQ(0, image
.flush());
5202 ASSERT_EQ(-EINVAL
, image
.sparsify(16));
5203 ASSERT_EQ(-EINVAL
, image
.sparsify(1 << (order
+ 1)));
5204 ASSERT_EQ(-EINVAL
, image
.sparsify(4096 + 1));
5205 ASSERT_EQ(0, image
.sparsify(4096));
5208 ASSERT_EQ((ssize_t
)bl
.length(), image
.read(0, bl
.length(), read_bl
));
5209 ASSERT_TRUE(bl
.contents_equal(read_bl
));
5211 ASSERT_PASSED(validate_object_map
, image
);
5214 TEST_F(TestLibRBD
, SnapshotLimit
)
5216 rados_ioctx_t ioctx
;
5217 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5221 std::string name
= get_temp_image_name();
5222 uint64_t size
= 2 << 20;
5225 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5226 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5228 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
5229 ASSERT_EQ(UINT64_MAX
, limit
);
5230 ASSERT_EQ(0, rbd_snap_set_limit(image
, 2));
5231 ASSERT_EQ(0, rbd_snap_get_limit(image
, &limit
));
5232 ASSERT_EQ(2U, limit
);
5234 ASSERT_EQ(0, rbd_snap_create(image
, "snap1"));
5235 ASSERT_EQ(-ERANGE
, rbd_snap_set_limit(image
, 0));
5236 ASSERT_EQ(0, rbd_snap_create(image
, "snap2"));
5237 ASSERT_EQ(-EDQUOT
, rbd_snap_create(image
, "snap3"));
5238 ASSERT_EQ(0, rbd_snap_set_limit(image
, UINT64_MAX
));
5239 ASSERT_EQ(0, rbd_snap_create(image
, "snap3"));
5240 ASSERT_EQ(0, rbd_close(image
));
5242 rados_ioctx_destroy(ioctx
);
5246 TEST_F(TestLibRBD
, SnapshotLimitPP
)
5248 librados::IoCtx ioctx
;
5249 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5253 librbd::Image image
;
5254 std::string name
= get_temp_image_name();
5255 uint64_t size
= 2 << 20;
5259 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5260 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5262 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
5263 ASSERT_EQ(UINT64_MAX
, limit
);
5264 ASSERT_EQ(0, image
.snap_set_limit(2));
5265 ASSERT_EQ(0, image
.snap_get_limit(&limit
));
5266 ASSERT_EQ(2U, limit
);
5268 ASSERT_EQ(0, image
.snap_create("snap1"));
5269 ASSERT_EQ(-ERANGE
, image
.snap_set_limit(0));
5270 ASSERT_EQ(0, image
.snap_create("snap2"));
5271 ASSERT_EQ(-EDQUOT
, image
.snap_create("snap3"));
5272 ASSERT_EQ(0, image
.snap_set_limit(UINT64_MAX
));
5273 ASSERT_EQ(0, image
.snap_create("snap3"));
5279 TEST_F(TestLibRBD
, RebuildObjectMapViaLockOwner
)
5281 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_OBJECT_MAP
);
5283 librados::IoCtx ioctx
;
5284 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5287 std::string name
= get_temp_image_name();
5288 uint64_t size
= 2 << 20;
5290 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5292 std::string object_map_oid
;
5294 librbd::Image image
;
5295 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
5297 std::string image_id
;
5298 ASSERT_EQ(0, get_image_id(image
, &image_id
));
5299 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
5302 // corrupt the object map
5305 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
5307 librbd::Image image1
;
5308 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5312 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5313 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5314 ASSERT_TRUE(lock_owner
);
5317 ASSERT_EQ(0, image1
.get_flags(&flags
));
5318 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
5320 librbd::Image image2
;
5321 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5322 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5323 ASSERT_FALSE(lock_owner
);
5325 PrintProgress prog_ctx
;
5326 ASSERT_EQ(0, image2
.rebuild_object_map(prog_ctx
));
5327 ASSERT_PASSED(validate_object_map
, image1
);
5328 ASSERT_PASSED(validate_object_map
, image2
);
5331 TEST_F(TestLibRBD
, RenameViaLockOwner
)
5333 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5335 librados::IoCtx ioctx
;
5336 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5339 std::string name
= get_temp_image_name();
5340 uint64_t size
= 2 << 20;
5342 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5344 librbd::Image image1
;
5345 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5348 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5349 ASSERT_FALSE(lock_owner
);
5351 std::string new_name
= get_temp_image_name();
5352 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
5353 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5354 ASSERT_FALSE(lock_owner
);
5357 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5358 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5359 ASSERT_TRUE(lock_owner
);
5362 new_name
= get_temp_image_name();
5363 ASSERT_EQ(0, rbd
.rename(ioctx
, name
.c_str(), new_name
.c_str()));
5364 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5365 ASSERT_TRUE(lock_owner
);
5367 librbd::Image image2
;
5368 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, new_name
.c_str(), NULL
));
5371 TEST_F(TestLibRBD
, SnapCreateViaLockOwner
)
5373 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5375 librados::IoCtx ioctx
;
5376 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5379 std::string name
= get_temp_image_name();
5380 uint64_t size
= 2 << 20;
5382 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5384 librbd::Image image1
;
5385 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5387 // switch to writeback cache
5388 ASSERT_EQ(0, image1
.flush());
5391 bl
.append(std::string(4096, '1'));
5392 ASSERT_EQ((ssize_t
)bl
.length(), image1
.write(0, bl
.length(), bl
));
5395 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5396 ASSERT_TRUE(lock_owner
);
5398 librbd::Image image2
;
5399 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5401 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5402 ASSERT_FALSE(lock_owner
);
5404 ASSERT_EQ(0, image2
.snap_create("snap1"));
5406 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5407 ASSERT_TRUE(exists
);
5408 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
5409 ASSERT_TRUE(exists
);
5411 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5412 ASSERT_TRUE(lock_owner
);
5415 TEST_F(TestLibRBD
, SnapRemoveViaLockOwner
)
5417 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
5419 librados::IoCtx ioctx
;
5420 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5423 std::string name
= get_temp_image_name();
5424 uint64_t size
= 2 << 20;
5426 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5428 librbd::Image image1
;
5429 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5432 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5433 ASSERT_EQ(0, image1
.snap_create("snap1"));
5436 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5437 ASSERT_TRUE(lock_owner
);
5439 librbd::Image image2
;
5440 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5442 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5443 ASSERT_FALSE(lock_owner
);
5445 ASSERT_EQ(0, image2
.snap_remove("snap1"));
5447 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5448 ASSERT_FALSE(exists
);
5449 ASSERT_EQ(0, image2
.snap_exists2("snap1", &exists
));
5450 ASSERT_FALSE(exists
);
5452 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5453 ASSERT_TRUE(lock_owner
);
5456 TEST_F(TestLibRBD
, UpdateFeaturesViaLockOwner
) {
5458 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5460 librados::IoCtx ioctx
;
5461 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5463 std::string name
= get_temp_image_name();
5464 uint64_t size
= 2 << 20;
5467 //creates full with rbd default features
5468 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5471 librbd::Image image1
;
5472 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5474 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5475 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5476 ASSERT_TRUE(lock_owner
);
5478 librbd::Image image2
;
5479 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5480 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5481 ASSERT_FALSE(lock_owner
);
5483 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
5484 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5485 ASSERT_FALSE(lock_owner
);
5487 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
5488 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5489 ASSERT_FALSE(lock_owner
);
5493 TEST_F(TestLibRBD
, EnableJournalingViaLockOwner
)
5495 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
5497 librados::IoCtx ioctx
;
5498 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5501 std::string name
= get_temp_image_name();
5502 uint64_t size
= 2 << 20;
5504 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5506 librbd::Image image1
;
5507 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5510 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5513 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5514 ASSERT_TRUE(lock_owner
);
5516 librbd::Image image2
;
5517 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5519 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, false));
5521 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5522 ASSERT_TRUE(lock_owner
);
5523 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5524 ASSERT_FALSE(lock_owner
);
5526 ASSERT_EQ(0, image2
.update_features(RBD_FEATURE_JOURNALING
, true));
5528 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5529 ASSERT_FALSE(lock_owner
);
5530 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5531 ASSERT_TRUE(lock_owner
);
5534 TEST_F(TestLibRBD
, SnapRemove2
)
5536 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5538 librados::IoCtx ioctx
;
5539 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5542 std::string name
= get_temp_image_name();
5543 uint64_t size
= 2 << 20;
5545 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5547 librbd::Image image1
;
5548 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5551 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5552 ASSERT_EQ(0, image1
.snap_create("snap1"));
5554 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5555 ASSERT_TRUE(exists
);
5556 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5558 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5559 ASSERT_TRUE(is_protected
);
5562 ASSERT_EQ(0, image1
.features(&features
));
5564 std::string child_name
= get_temp_image_name();
5565 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5566 child_name
.c_str(), features
, &order
));
5568 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5569 ASSERT_TRUE(exists
);
5570 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5571 ASSERT_TRUE(is_protected
);
5573 ASSERT_EQ(-EBUSY
, image1
.snap_remove("snap1"));
5575 ASSERT_EQ(0, image1
.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE
, pp
));
5576 ASSERT_EQ(0, image1
.snap_exists2("snap1", &exists
));
5577 ASSERT_FALSE(exists
);
5580 TEST_F(TestLibRBD
, SnapRenameViaLockOwner
)
5582 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5584 librados::IoCtx ioctx
;
5585 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5588 std::string name
= get_temp_image_name();
5589 uint64_t size
= 2 << 20;
5591 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5593 librbd::Image image1
;
5594 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5597 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5598 ASSERT_EQ(0, image1
.snap_create("snap1"));
5601 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5602 ASSERT_TRUE(lock_owner
);
5604 librbd::Image image2
;
5605 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5607 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5608 ASSERT_FALSE(lock_owner
);
5610 ASSERT_EQ(0, image2
.snap_rename("snap1", "snap1-rename"));
5612 ASSERT_EQ(0, image1
.snap_exists2("snap1-rename", &exists
));
5613 ASSERT_TRUE(exists
);
5614 ASSERT_EQ(0, image2
.snap_exists2("snap1-rename", &exists
));
5615 ASSERT_TRUE(exists
);
5617 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5618 ASSERT_TRUE(lock_owner
);
5621 TEST_F(TestLibRBD
, SnapProtectViaLockOwner
)
5623 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5625 librados::IoCtx ioctx
;
5626 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5629 std::string name
= get_temp_image_name();
5630 uint64_t size
= 2 << 20;
5632 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5634 librbd::Image image1
;
5635 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5638 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5641 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5642 ASSERT_TRUE(lock_owner
);
5643 ASSERT_EQ(0, image1
.snap_create("snap1"));
5645 librbd::Image image2
;
5646 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5648 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5649 ASSERT_FALSE(lock_owner
);
5651 ASSERT_EQ(0, image2
.snap_protect("snap1"));
5653 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5654 ASSERT_TRUE(is_protected
);
5655 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5656 ASSERT_TRUE(is_protected
);
5658 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5659 ASSERT_TRUE(lock_owner
);
5662 TEST_F(TestLibRBD
, SnapUnprotectViaLockOwner
)
5664 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_EXCLUSIVE_LOCK
);
5666 librados::IoCtx ioctx
;
5667 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5670 std::string name
= get_temp_image_name();
5671 uint64_t size
= 2 << 20;
5673 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5675 librbd::Image image1
;
5676 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5679 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5682 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5683 ASSERT_TRUE(lock_owner
);
5684 ASSERT_EQ(0, image1
.snap_create("snap1"));
5685 ASSERT_EQ(0, image1
.snap_protect("snap1"));
5687 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5688 ASSERT_TRUE(is_protected
);
5690 librbd::Image image2
;
5691 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5693 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5694 ASSERT_FALSE(lock_owner
);
5696 ASSERT_EQ(0, image2
.snap_unprotect("snap1"));
5697 ASSERT_EQ(0, image2
.snap_is_protected("snap1", &is_protected
));
5698 ASSERT_FALSE(is_protected
);
5699 ASSERT_EQ(0, image1
.snap_is_protected("snap1", &is_protected
));
5700 ASSERT_FALSE(is_protected
);
5702 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5703 ASSERT_TRUE(lock_owner
);
5706 TEST_F(TestLibRBD
, FlattenViaLockOwner
)
5708 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5710 librados::IoCtx ioctx
;
5711 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5714 std::string parent_name
= get_temp_image_name();
5715 uint64_t size
= 2 << 20;
5717 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), size
, &order
));
5719 librbd::Image parent_image
;
5720 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
5721 ASSERT_EQ(0, parent_image
.snap_create("snap1"));
5722 ASSERT_EQ(0, parent_image
.snap_protect("snap1"));
5725 ASSERT_EQ(0, parent_image
.features(&features
));
5727 std::string name
= get_temp_image_name();
5728 EXPECT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "snap1", ioctx
,
5729 name
.c_str(), features
, &order
));
5731 librbd::Image image1
;
5732 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5735 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5738 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5739 ASSERT_TRUE(lock_owner
);
5741 librbd::Image image2
;
5742 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5744 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5745 ASSERT_FALSE(lock_owner
);
5747 ASSERT_EQ(0, image2
.flatten());
5749 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5750 ASSERT_TRUE(lock_owner
);
5751 ASSERT_PASSED(validate_object_map
, image1
);
5754 TEST_F(TestLibRBD
, ResizeViaLockOwner
)
5756 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5758 librados::IoCtx ioctx
;
5759 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5762 std::string name
= get_temp_image_name();
5763 uint64_t size
= 2 << 20;
5765 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5767 librbd::Image image1
;
5768 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5771 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5774 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5775 ASSERT_TRUE(lock_owner
);
5777 librbd::Image image2
;
5778 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5780 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5781 ASSERT_FALSE(lock_owner
);
5783 ASSERT_EQ(0, image2
.resize(0));
5785 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5786 ASSERT_TRUE(lock_owner
);
5787 ASSERT_PASSED(validate_object_map
, image1
);
5790 TEST_F(TestLibRBD
, SparsifyViaLockOwner
)
5792 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
5794 librados::IoCtx ioctx
;
5795 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5798 std::string name
= get_temp_image_name();
5799 uint64_t size
= 2 << 20;
5801 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5803 librbd::Image image1
;
5804 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5807 ASSERT_EQ(0, image1
.write(0, 0, bl
));
5810 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5811 ASSERT_TRUE(lock_owner
);
5813 librbd::Image image2
;
5814 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
5816 ASSERT_EQ(0, image2
.is_exclusive_lock_owner(&lock_owner
));
5817 ASSERT_FALSE(lock_owner
);
5819 ASSERT_EQ(0, image2
.sparsify(4096));
5821 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
5822 ASSERT_TRUE(lock_owner
);
5823 ASSERT_PASSED(validate_object_map
, image1
);
5826 TEST_F(TestLibRBD
, ObjectMapConsistentSnap
)
5828 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
5830 librados::IoCtx ioctx
;
5831 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
5834 std::string name
= get_temp_image_name();
5835 uint64_t size
= 1 << 20;
5837 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
5839 librbd::Image image1
;
5840 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
5843 for (int i
= 0; i
< num_snaps
; ++i
) {
5844 std::string snap_name
= "snap" + stringify(i
);
5845 ASSERT_EQ(0, image1
.snap_create(snap_name
.c_str()));
5849 thread
writer([&image1
](){
5850 librbd::image_info_t info
;
5851 int r
= image1
.stat(info
, sizeof(info
));
5852 ceph_assert(r
== 0);
5855 for (unsigned i
= 0; i
< info
.num_objs
; ++i
) {
5856 r
= image1
.write((1 << info
.order
) * i
, bl
.length(), bl
);
5857 ceph_assert(r
== (int) bl
.length());
5862 for (int i
= 0; i
< num_snaps
; ++i
) {
5863 std::string snap_name
= "snap" + stringify(i
);
5864 ASSERT_EQ(0, image1
.snap_set(snap_name
.c_str()));
5865 ASSERT_PASSED(validate_object_map
, image1
);
5868 ASSERT_EQ(0, image1
.snap_set(NULL
));
5869 ASSERT_PASSED(validate_object_map
, image1
);
5872 void memset_rand(char *buf
, size_t len
) {
5873 for (size_t i
= 0; i
< len
; ++i
) {
5874 buf
[i
] = (char) (rand() % (126 - 33) + 33);
5878 TEST_F(TestLibRBD
, Metadata
)
5880 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
5882 rados_ioctx_t ioctx
;
5883 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
5885 std::string name
= get_temp_image_name();
5886 uint64_t size
= 2 << 20;
5888 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
5891 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
5894 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
5898 size_t keys_len
= sizeof(keys
);
5899 size_t vals_len
= sizeof(vals
);
5901 memset_rand(keys
, keys_len
);
5902 memset_rand(vals
, vals_len
);
5904 ASSERT_EQ(0, rbd_metadata_list(image
, "key", 0, keys
, &keys_len
, vals
,
5906 ASSERT_EQ(0U, keys_len
);
5907 ASSERT_EQ(0U, vals_len
);
5910 size_t value_len
= sizeof(value
);
5911 memset_rand(value
, value_len
);
5913 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
5914 ASSERT_EQ(0, rbd_metadata_set(image1
, "key2", "value2"));
5915 ASSERT_EQ(0, rbd_metadata_get(image1
, "key1", value
, &value_len
));
5916 ASSERT_STREQ(value
, "value1");
5918 ASSERT_EQ(-ERANGE
, rbd_metadata_get(image1
, "key1", value
, &value_len
));
5919 ASSERT_EQ(value_len
, strlen("value1") + 1);
5921 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
5923 keys_len
= sizeof(keys
);
5924 vals_len
= sizeof(vals
);
5925 memset_rand(keys
, keys_len
);
5926 memset_rand(vals
, vals_len
);
5927 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
5929 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
5930 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
5931 ASSERT_STREQ(keys
, "key1");
5932 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
5933 ASSERT_STREQ(vals
, "value1");
5934 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
5936 ASSERT_EQ(0, rbd_metadata_remove(image1
, "key1"));
5937 ASSERT_EQ(-ENOENT
, rbd_metadata_remove(image1
, "key3"));
5938 value_len
= sizeof(value
);
5939 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key3", value
, &value_len
));
5940 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
5942 ASSERT_EQ(keys_len
, strlen("key2") + 1);
5943 ASSERT_EQ(vals_len
, strlen("value2") + 1);
5944 ASSERT_STREQ(keys
, "key2");
5945 ASSERT_STREQ(vals
, "value2");
5947 // test config setting
5948 ASSERT_EQ(0, rbd_metadata_set(image1
, "conf_rbd_cache", "false"));
5949 ASSERT_EQ(-EINVAL
, rbd_metadata_set(image1
, "conf_rbd_cache", "INVALID_VAL"));
5950 ASSERT_EQ(0, rbd_metadata_remove(image1
, "conf_rbd_cache"));
5952 // test metadata with snapshot adding
5953 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
5954 ASSERT_EQ(0, rbd_snap_protect(image1
, "snap1"));
5955 ASSERT_EQ(0, rbd_snap_set(image1
, "snap1"));
5957 ASSERT_EQ(-EROFS
, rbd_metadata_set(image1
, "key1", "value1"));
5958 ASSERT_EQ(-EROFS
, rbd_metadata_remove(image1
, "key2"));
5960 keys_len
= sizeof(keys
);
5961 vals_len
= sizeof(vals
);
5962 memset_rand(keys
, keys_len
);
5963 memset_rand(vals
, vals_len
);
5964 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
5966 ASSERT_EQ(keys_len
, strlen("key2") + 1);
5967 ASSERT_EQ(vals_len
, strlen("value2") + 1);
5968 ASSERT_STREQ(keys
, "key2");
5969 ASSERT_STREQ(vals
, "value2");
5971 ASSERT_EQ(0, rbd_snap_set(image1
, NULL
));
5972 ASSERT_EQ(0, rbd_metadata_set(image1
, "key1", "value1"));
5973 ASSERT_EQ(0, rbd_metadata_set(image1
, "key3", "value3"));
5974 keys_len
= sizeof(keys
);
5975 vals_len
= sizeof(vals
);
5976 memset_rand(keys
, keys_len
);
5977 memset_rand(vals
, vals_len
);
5978 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
5981 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5983 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5984 ASSERT_STREQ(keys
, "key1");
5985 ASSERT_STREQ(keys
+ strlen("key1") + 1, "key2");
5986 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1, "key3");
5987 ASSERT_STREQ(vals
, "value1");
5988 ASSERT_STREQ(vals
+ strlen("value1") + 1, "value2");
5989 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1, "value3");
5991 // test metadata with cloning
5993 ASSERT_EQ(0, rbd_get_features(image1
, &features
));
5995 string cname
= get_temp_image_name();
5996 EXPECT_EQ(0, rbd_clone(ioctx
, name
.c_str(), "snap1", ioctx
,
5997 cname
.c_str(), features
, &order
));
5999 ASSERT_EQ(0, rbd_open(ioctx
, cname
.c_str(), &image2
, NULL
));
6000 ASSERT_EQ(0, rbd_metadata_set(image2
, "key4", "value4"));
6002 keys_len
= sizeof(keys
);
6003 vals_len
= sizeof(vals
);
6004 memset_rand(keys
, keys_len
);
6005 memset_rand(vals
, vals_len
);
6006 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 0, keys
, &keys_len
, vals
,
6008 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
6009 1 + strlen("key4") + 1);
6010 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
6011 strlen("value3") + 1 + strlen("value4") + 1);
6012 ASSERT_STREQ(keys
+ strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
6014 ASSERT_STREQ(vals
+ strlen("value1") + 1 + strlen("value2") + 1 +
6015 strlen("value3") + 1, "value4");
6017 ASSERT_EQ(0, rbd_metadata_list(image1
, "key", 0, keys
, &keys_len
, vals
,
6020 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
6022 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
6023 ASSERT_EQ(-ENOENT
, rbd_metadata_get(image1
, "key4", value
, &value_len
));
6025 // test short buffer cases
6026 keys_len
= strlen("key1") + 1;
6027 vals_len
= strlen("value1") + 1;
6028 memset_rand(keys
, keys_len
);
6029 memset_rand(vals
, vals_len
);
6030 ASSERT_EQ(0, rbd_metadata_list(image2
, "key", 1, keys
, &keys_len
, vals
,
6032 ASSERT_EQ(keys_len
, strlen("key1") + 1);
6033 ASSERT_EQ(vals_len
, strlen("value1") + 1);
6034 ASSERT_STREQ(keys
, "key1");
6035 ASSERT_STREQ(vals
, "value1");
6037 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "key", 2, keys
, &keys_len
, vals
,
6039 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
6040 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
6042 ASSERT_EQ(-ERANGE
, rbd_metadata_list(image2
, "key", 0, keys
, &keys_len
, vals
,
6044 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
6045 1 + strlen("key4") + 1);
6046 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
6047 strlen("value3") + 1 + strlen("value4") + 1);
6049 // test `start` param
6050 keys_len
= sizeof(keys
);
6051 vals_len
= sizeof(vals
);
6052 memset_rand(keys
, keys_len
);
6053 memset_rand(vals
, vals_len
);
6054 ASSERT_EQ(0, rbd_metadata_list(image2
, "key2", 0, keys
, &keys_len
, vals
,
6056 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
6057 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
6058 ASSERT_STREQ(keys
, "key3");
6059 ASSERT_STREQ(vals
, "value3");
6061 ASSERT_EQ(0, rbd_close(image
));
6062 ASSERT_EQ(0, rbd_close(image1
));
6063 ASSERT_EQ(0, rbd_close(image2
));
6064 rados_ioctx_destroy(ioctx
);
6067 TEST_F(TestLibRBD
, MetadataPP
)
6069 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6071 librados::IoCtx ioctx
;
6072 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6075 string name
= get_temp_image_name();
6076 uint64_t size
= 2 << 20;
6080 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6082 librbd::Image image1
;
6083 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6084 map
<string
, bufferlist
> pairs
;
6085 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6086 ASSERT_TRUE(pairs
.empty());
6088 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
6089 ASSERT_EQ(0, image1
.metadata_set("key2", "value2"));
6090 ASSERT_EQ(0, image1
.metadata_get("key1", &value
));
6091 ASSERT_EQ(0, strcmp("value1", value
.c_str()));
6092 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6093 ASSERT_EQ(2U, pairs
.size());
6094 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
6095 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6098 ASSERT_EQ(0, image1
.metadata_remove("key1"));
6099 ASSERT_EQ(-ENOENT
, image1
.metadata_remove("key3"));
6100 ASSERT_TRUE(image1
.metadata_get("key3", &value
) < 0);
6101 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6102 ASSERT_EQ(1U, pairs
.size());
6103 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6105 // test config setting
6106 ASSERT_EQ(0, image1
.metadata_set("conf_rbd_cache", "false"));
6107 ASSERT_EQ(-EINVAL
, image1
.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
6108 ASSERT_EQ(0, image1
.metadata_remove("conf_rbd_cache"));
6110 // test metadata with snapshot adding
6111 ASSERT_EQ(0, image1
.snap_create("snap1"));
6112 ASSERT_EQ(0, image1
.snap_protect("snap1"));
6113 ASSERT_EQ(0, image1
.snap_set("snap1"));
6116 ASSERT_EQ(-EROFS
, image1
.metadata_set("key1", "value1"));
6117 ASSERT_EQ(-EROFS
, image1
.metadata_remove("key2"));
6118 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6119 ASSERT_EQ(1U, pairs
.size());
6120 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6122 ASSERT_EQ(0, image1
.snap_set(NULL
));
6123 ASSERT_EQ(0, image1
.metadata_set("key1", "value1"));
6124 ASSERT_EQ(0, image1
.metadata_set("key3", "value3"));
6125 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6126 ASSERT_EQ(3U, pairs
.size());
6127 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
6128 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
6129 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
6131 // test metadata with cloning
6132 string cname
= get_temp_image_name();
6133 librbd::Image image2
;
6134 ASSERT_EQ(0, image1
.features(&features
));
6135 EXPECT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap1", ioctx
,
6136 cname
.c_str(), features
, &order
));
6137 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, cname
.c_str(), NULL
));
6138 ASSERT_EQ(0, image2
.metadata_set("key4", "value4"));
6140 ASSERT_EQ(0, image2
.metadata_list("key", 0, &pairs
));
6141 ASSERT_EQ(4U, pairs
.size());
6143 ASSERT_EQ(0, image1
.metadata_list("key", 0, &pairs
));
6144 ASSERT_EQ(3U, pairs
.size());
6145 ASSERT_EQ(-ENOENT
, image1
.metadata_get("key4", &value
));
6148 TEST_F(TestLibRBD
, UpdateFeatures
)
6150 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6152 librados::IoCtx ioctx
;
6153 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6156 std::string name
= get_temp_image_name();
6157 uint64_t size
= 1 << 20;
6159 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6161 librbd::Image image
;
6162 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6165 ASSERT_EQ(0, image
.old_format(&old_format
));
6167 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
6172 ASSERT_EQ(0, image
.features(&features
));
6174 // must provide a single feature
6175 ASSERT_EQ(-EINVAL
, image
.update_features(0, true));
6177 uint64_t disable_features
;
6178 disable_features
= features
& (RBD_FEATURE_EXCLUSIVE_LOCK
|
6179 RBD_FEATURE_OBJECT_MAP
|
6180 RBD_FEATURE_FAST_DIFF
|
6181 RBD_FEATURE_JOURNALING
);
6182 if (disable_features
!= 0) {
6183 ASSERT_EQ(0, image
.update_features(disable_features
, false));
6186 ASSERT_EQ(0, image
.features(&features
));
6187 ASSERT_EQ(0U, features
& disable_features
);
6189 // cannot enable object map nor journaling w/o exclusive lock
6190 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6191 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_JOURNALING
, true));
6192 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, true));
6194 ASSERT_EQ(0, image
.features(&features
));
6195 ASSERT_NE(0U, features
& RBD_FEATURE_EXCLUSIVE_LOCK
);
6197 // can enable fast diff w/o object map
6198 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_FAST_DIFF
, true));
6199 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6200 ASSERT_EQ(0, image
.features(&features
));
6201 ASSERT_NE(0U, features
& RBD_FEATURE_OBJECT_MAP
);
6203 uint64_t expected_flags
= RBD_FLAG_OBJECT_MAP_INVALID
|
6204 RBD_FLAG_FAST_DIFF_INVALID
;
6206 ASSERT_EQ(0, image
.get_flags(&flags
));
6207 ASSERT_EQ(expected_flags
, flags
);
6209 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
6210 ASSERT_EQ(0, image
.features(&features
));
6211 ASSERT_EQ(0U, features
& RBD_FEATURE_OBJECT_MAP
);
6213 // can disable object map w/ fast diff
6214 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6215 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
6216 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_FAST_DIFF
, false));
6217 ASSERT_EQ(0, image
.features(&features
));
6218 ASSERT_EQ(0U, features
& RBD_FEATURE_FAST_DIFF
);
6220 ASSERT_EQ(0, image
.get_flags(&flags
));
6221 ASSERT_EQ(0U, flags
);
6223 // cannot disable exclusive lock w/ object map
6224 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, true));
6225 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
6226 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_OBJECT_MAP
, false));
6228 // cannot disable exclusive lock w/ journaling
6229 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, true));
6230 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
6231 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_JOURNALING
, false));
6233 ASSERT_EQ(0, image
.get_flags(&flags
));
6234 ASSERT_EQ(0U, flags
);
6236 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_EXCLUSIVE_LOCK
, false));
6238 ASSERT_EQ(0, image
.features(&features
));
6239 if ((features
& RBD_FEATURE_DEEP_FLATTEN
) != 0) {
6240 ASSERT_EQ(0, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, false));
6242 ASSERT_EQ(-EINVAL
, image
.update_features(RBD_FEATURE_DEEP_FLATTEN
, true));
6245 TEST_F(TestLibRBD
, FeaturesBitmaskString
)
6248 uint64_t features
= RBD_FEATURES_DEFAULT
;
6250 std::string features_str
;
6251 std::string expected_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
6252 rbd
.features_to_string(features
, &features_str
);
6253 ASSERT_EQ(expected_str
, features_str
);
6255 features
= RBD_FEATURE_LAYERING
;
6257 expected_str
= "layering";
6258 rbd
.features_to_string(features
, &features_str
);
6259 ASSERT_EQ(expected_str
, features_str
);
6261 uint64_t features_bitmask
;
6262 features_str
= "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
6263 rbd
.features_from_string(features_str
, &features_bitmask
);
6264 ASSERT_EQ(features_bitmask
, RBD_FEATURES_DEFAULT
);
6266 features_str
= "layering";
6267 features_bitmask
= 0;
6268 rbd
.features_from_string(features_str
, &features_bitmask
);
6269 ASSERT_EQ(features_bitmask
, RBD_FEATURE_LAYERING
);
6272 TEST_F(TestLibRBD
, RebuildObjectMap
)
6274 librados::IoCtx ioctx
;
6275 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6278 std::string name
= get_temp_image_name();
6279 uint64_t size
= 1 << 20;
6281 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6283 PrintProgress prog_ctx
;
6284 std::string object_map_oid
;
6288 librbd::Image image
;
6289 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6292 ASSERT_EQ(0, image
.features(&features
));
6293 if ((features
& RBD_FEATURE_OBJECT_MAP
) == 0) {
6294 ASSERT_EQ(-EINVAL
, image
.rebuild_object_map(prog_ctx
));
6298 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(0, bl
.length(), bl
));
6300 ASSERT_EQ(0, image
.snap_create("snap1"));
6301 ASSERT_EQ((ssize_t
)bl
.length(), image
.write(1<<order
, bl
.length(), bl
));
6303 std::string image_id
;
6304 ASSERT_EQ(0, get_image_id(image
, &image_id
));
6305 object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
6308 // corrupt the object map
6309 ASSERT_EQ(0, ioctx
.write(object_map_oid
, bl
, bl
.length(), 0));
6311 librbd::Image image1
;
6312 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6316 ASSERT_EQ(0, image1
.write(0, 0, bl
));
6317 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6318 ASSERT_TRUE(lock_owner
);
6321 ASSERT_EQ(0, image1
.get_flags(&flags
));
6322 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
6324 ASSERT_EQ(0, image1
.rebuild_object_map(prog_ctx
));
6326 librbd::Image image2
;
6327 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6330 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(0, bl
.length(), read_bl
));
6331 ASSERT_TRUE(bl
.contents_equal(read_bl
));
6334 ASSERT_EQ((ssize_t
)bl
.length(), image2
.read(1<<order
, bl
.length(), read_bl
));
6335 ASSERT_TRUE(bl
.contents_equal(read_bl
));
6337 ASSERT_PASSED(validate_object_map
, image1
);
6338 ASSERT_PASSED(validate_object_map
, image2
);
6341 TEST_F(TestLibRBD
, RebuildNewObjectMap
)
6343 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
6345 rados_ioctx_t ioctx
;
6346 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6348 std::string name
= get_temp_image_name();
6349 uint64_t size
= 1 << 20;
6351 uint64_t features
= RBD_FEATURE_EXCLUSIVE_LOCK
;
6352 ASSERT_EQ(0, create_image_full(ioctx
, name
.c_str(), size
, &order
,
6356 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6357 ASSERT_EQ(0, rbd_update_features(image
, RBD_FEATURE_OBJECT_MAP
, true));
6358 ASSERT_EQ(0, rbd_rebuild_object_map(image
, print_progress_percent
, NULL
));
6360 ASSERT_PASSED(validate_object_map
, image
);
6362 ASSERT_EQ(0, rbd_close(image
));
6363 rados_ioctx_destroy(ioctx
);
6366 TEST_F(TestLibRBD
, CheckObjectMap
)
6368 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
6370 librados::IoCtx ioctx
;
6371 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6374 std::string name
= get_temp_image_name();
6375 uint64_t size
= 1 << 20;
6377 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6379 PrintProgress prog_ctx
;
6384 librbd::Image image
;
6385 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6388 ASSERT_EQ(0, image
.features(&features
));
6390 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(0, bl1
.length(), bl1
));
6392 ASSERT_EQ(0, image
.snap_create("snap1"));
6393 ASSERT_EQ((ssize_t
)bl1
.length(), image
.write(1<<order
, bl1
.length(), bl1
));
6396 librbd::Image image1
;
6397 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6399 std::string image_id
;
6400 ASSERT_EQ(0, get_image_id(image1
, &image_id
));
6402 std::string object_map_oid
= RBD_OBJECT_MAP_PREFIX
+ image_id
;
6404 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl2
, 1024, 0));
6407 ASSERT_EQ((ssize_t
)bl1
.length(), image1
.write(3 * (1 << 18), bl1
.length(), bl1
));
6408 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6409 ASSERT_TRUE(lock_owner
);
6411 //reopen image to reread now corrupt object map from disk
6415 ASSERT_LT(0, ioctx
.read(object_map_oid
, bl1
, 1024, 0));
6416 ASSERT_FALSE(bl1
.contents_equal(bl2
));
6418 ASSERT_EQ(0, ioctx
.write_full(object_map_oid
, bl2
));
6419 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6422 ASSERT_EQ(0, image1
.get_flags(&flags
));
6423 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) == 0);
6425 ASSERT_EQ(0, image1
.check_object_map(prog_ctx
));
6427 ASSERT_EQ(0, image1
.get_flags(&flags
));
6428 ASSERT_TRUE((flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0);
6431 TEST_F(TestLibRBD
, BlockingAIO
)
6433 librados::IoCtx ioctx
;
6434 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6437 std::string name
= get_temp_image_name();
6438 uint64_t size
= 1 << 20;
6440 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6442 std::string non_blocking_aio
;
6443 ASSERT_EQ(0, _rados
.conf_get("rbd_non_blocking_aio", non_blocking_aio
));
6444 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio", "0"));
6445 BOOST_SCOPE_EXIT( (non_blocking_aio
) ) {
6446 ASSERT_EQ(0, _rados
.conf_set("rbd_non_blocking_aio",
6447 non_blocking_aio
.c_str()));
6448 } BOOST_SCOPE_EXIT_END
;
6450 librbd::Image image
;
6451 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6453 bool skip_discard
= this->is_skip_partial_discard_enabled(image
);
6456 ASSERT_EQ(0, image
.write(0, bl
.length(), bl
));
6458 bl
.append(std::string(256, '1'));
6459 librbd::RBD::AioCompletion
*write_comp
=
6460 new librbd::RBD::AioCompletion(NULL
, NULL
);
6461 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
6463 librbd::RBD::AioCompletion
*flush_comp
=
6464 new librbd::RBD::AioCompletion(NULL
, NULL
);
6465 ASSERT_EQ(0, image
.aio_flush(flush_comp
));
6466 ASSERT_EQ(0, flush_comp
->wait_for_complete());
6467 ASSERT_EQ(0, flush_comp
->get_return_value());
6468 flush_comp
->release();
6470 ASSERT_EQ(1, write_comp
->is_complete());
6471 ASSERT_EQ(0, write_comp
->get_return_value());
6472 write_comp
->release();
6474 librbd::RBD::AioCompletion
*discard_comp
=
6475 new librbd::RBD::AioCompletion(NULL
, NULL
);
6476 ASSERT_EQ(0, image
.aio_discard(128, 128, discard_comp
));
6477 ASSERT_EQ(0, discard_comp
->wait_for_complete());
6478 discard_comp
->release();
6480 librbd::RBD::AioCompletion
*read_comp
=
6481 new librbd::RBD::AioCompletion(NULL
, NULL
);
6483 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
6484 ASSERT_EQ(0, read_comp
->wait_for_complete());
6485 ASSERT_EQ((ssize_t
)bl
.length(), read_comp
->get_return_value());
6486 read_comp
->release();
6488 bufferlist expected_bl
;
6489 expected_bl
.append(std::string(128, '1'));
6490 expected_bl
.append(std::string(128, skip_discard
? '1' : '\0'));
6491 ASSERT_TRUE(expected_bl
.contents_equal(read_bl
));
6494 TEST_F(TestLibRBD
, ExclusiveLockTransition
)
6496 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
6498 librados::IoCtx ioctx
;
6499 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6502 std::string name
= get_temp_image_name();
6504 uint64_t size
= 1 << 18;
6506 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6508 librbd::Image image1
;
6509 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6511 librbd::Image image2
;
6512 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6514 std::list
<librbd::RBD::AioCompletion
*> comps
;
6515 ceph::bufferlist bl
;
6516 bl
.append(std::string(1 << order
, '1'));
6517 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6518 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
6520 comps
.push_back(comp
);
6521 if (object_no
% 2 == 0) {
6522 ASSERT_EQ(0, image1
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
6524 ASSERT_EQ(0, image2
.aio_write(object_no
<< order
, bl
.length(), bl
, comp
));
6528 while (!comps
.empty()) {
6529 librbd::RBD::AioCompletion
*comp
= comps
.front();
6531 ASSERT_EQ(0, comp
->wait_for_complete());
6532 ASSERT_EQ(1, comp
->is_complete());
6536 librbd::Image image3
;
6537 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
6538 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6540 ASSERT_EQ((ssize_t
)bl
.length(), image3
.read(object_no
<< order
, bl
.length(),
6542 ASSERT_TRUE(bl
.contents_equal(read_bl
));
6545 ASSERT_PASSED(validate_object_map
, image1
);
6546 ASSERT_PASSED(validate_object_map
, image2
);
6547 ASSERT_PASSED(validate_object_map
, image3
);
6550 TEST_F(TestLibRBD
, ExclusiveLockReadTransition
)
6552 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
6554 librados::IoCtx ioctx
;
6555 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6558 std::string name
= get_temp_image_name();
6560 uint64_t size
= 1 << 18;
6562 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6564 librbd::Image image1
;
6565 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6568 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6569 ASSERT_FALSE(lock_owner
);
6571 // journaling should force read ops to acquire the lock
6573 ASSERT_EQ(0, image1
.read(0, 0, read_bl
));
6575 ASSERT_EQ(0, image1
.is_exclusive_lock_owner(&lock_owner
));
6576 ASSERT_TRUE(lock_owner
);
6578 librbd::Image image2
;
6579 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6581 std::list
<librbd::RBD::AioCompletion
*> comps
;
6582 std::list
<bufferlist
> read_bls
;
6583 for (size_t object_no
= 0; object_no
< (size
>> 12); ++object_no
) {
6584 librbd::RBD::AioCompletion
*comp
= new librbd::RBD::AioCompletion(NULL
,
6586 comps
.push_back(comp
);
6587 read_bls
.emplace_back();
6588 if (object_no
% 2 == 0) {
6589 ASSERT_EQ(0, image1
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6591 ASSERT_EQ(0, image2
.aio_read(object_no
<< order
, 1 << order
, read_bls
.back(), comp
));
6595 while (!comps
.empty()) {
6596 librbd::RBD::AioCompletion
*comp
= comps
.front();
6598 ASSERT_EQ(0, comp
->wait_for_complete());
6599 ASSERT_EQ(1, comp
->is_complete());
6604 TEST_F(TestLibRBD
, CacheMayCopyOnWrite
) {
6605 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
6607 librados::IoCtx ioctx
;
6608 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6611 std::string name
= get_temp_image_name();
6613 uint64_t size
= 1 << 18;
6615 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6617 librbd::Image image
;
6618 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
6619 ASSERT_EQ(0, image
.snap_create("one"));
6620 ASSERT_EQ(0, image
.snap_protect("one"));
6622 std::string clone_name
= this->get_temp_image_name();
6623 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
6624 RBD_FEATURE_LAYERING
, &order
));
6626 librbd::Image clone
;
6627 ASSERT_EQ(0, rbd
.open(ioctx
, clone
, clone_name
.c_str(), NULL
));
6628 ASSERT_EQ(0, clone
.flush());
6630 bufferlist expect_bl
;
6631 expect_bl
.append(std::string(1024, '\0'));
6633 // test double read path
6635 uint64_t offset
= 0;
6636 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6637 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6639 bufferlist write_bl
;
6640 write_bl
.append(std::string(1024, '1'));
6641 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6644 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6645 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6647 // test read retry path
6648 offset
= 1 << order
;
6649 ASSERT_EQ(1024, clone
.write(offset
, write_bl
.length(), write_bl
));
6652 ASSERT_EQ(1024, clone
.read(offset
+ 2048, 1024, read_bl
));
6653 ASSERT_TRUE(expect_bl
.contents_equal(read_bl
));
6656 TEST_F(TestLibRBD
, FlushEmptyOpsOnExternalSnapshot
) {
6657 std::string cache_enabled
;
6658 ASSERT_EQ(0, _rados
.conf_get("rbd_cache", cache_enabled
));
6659 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", "false"));
6660 BOOST_SCOPE_EXIT( (cache_enabled
) ) {
6661 ASSERT_EQ(0, _rados
.conf_set("rbd_cache", cache_enabled
.c_str()));
6662 } BOOST_SCOPE_EXIT_END
;
6664 librados::IoCtx ioctx
;
6665 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6668 std::string name
= get_temp_image_name();
6669 uint64_t size
= 1 << 18;
6671 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
6673 librbd::Image image1
;
6674 librbd::Image image2
;
6675 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
6676 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
6677 ASSERT_EQ(0, image1
.snap_create("snap1"));
6679 librbd::RBD::AioCompletion
*read_comp
=
6680 new librbd::RBD::AioCompletion(NULL
, NULL
);
6682 image2
.aio_read(0, 1024, read_bl
, read_comp
);
6683 ASSERT_EQ(0, read_comp
->wait_for_complete());
6684 read_comp
->release();
6687 TEST_F(TestLibRBD
, TestImageOptions
)
6689 rados_ioctx_t ioctx
;
6690 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6692 //make create image options
6693 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6695 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6696 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6697 rbd_image_options_t opts
;
6698 rbd_image_options_create(&opts
);
6701 ASSERT_EQ(-EINVAL
, rbd_image_options_is_set(opts
, 12345, &is_set
));
6702 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6704 ASSERT_FALSE(is_set
);
6706 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FORMAT
,
6708 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_FEATURES
,
6710 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6712 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_UNIT
,
6714 ASSERT_EQ(0, rbd_image_options_set_uint64(opts
, RBD_IMAGE_OPTION_STRIPE_COUNT
,
6717 ASSERT_EQ(0, rbd_image_options_is_set(opts
, RBD_IMAGE_OPTION_FORMAT
,
6719 ASSERT_TRUE(is_set
);
6721 std::string parent_name
= get_temp_image_name();
6724 ASSERT_EQ(0, rbd_create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6726 // check order is returned in opts
6727 ASSERT_EQ(0, rbd_image_options_get_uint64(opts
, RBD_IMAGE_OPTION_ORDER
,
6729 ASSERT_NE((uint64_t)0, order
);
6731 // write some data to parent
6733 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, NULL
));
6734 char *data
= (char *)"testdata";
6735 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 0, strlen(data
), data
));
6736 ASSERT_EQ((ssize_t
)strlen(data
), rbd_write(parent
, 12, strlen(data
), data
));
6738 // create a snapshot, reopen as the parent we're interested in
6739 ASSERT_EQ(0, rbd_snap_create(parent
, "parent_snap"));
6740 ASSERT_EQ(0, rbd_close(parent
));
6741 ASSERT_EQ(0, rbd_open(ioctx
, parent_name
.c_str(), &parent
, "parent_snap"));
6744 std::string child_name
= get_temp_image_name();
6745 ASSERT_EQ(0, rbd_snap_protect(parent
, "parent_snap"));
6746 ASSERT_EQ(0, rbd_clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6747 child_name
.c_str(), opts
));
6750 std::string copy1_name
= get_temp_image_name();
6751 ASSERT_EQ(0, rbd_copy3(parent
, ioctx
, copy1_name
.c_str(), opts
));
6752 std::string copy2_name
= get_temp_image_name();
6753 ASSERT_EQ(0, rbd_copy_with_progress3(parent
, ioctx
, copy2_name
.c_str(), opts
,
6754 print_progress_percent
, NULL
));
6756 ASSERT_EQ(0, rbd_close(parent
));
6758 rbd_image_options_destroy(opts
);
6760 rados_ioctx_destroy(ioctx
);
6763 TEST_F(TestLibRBD
, TestImageOptionsPP
)
6765 librados::IoCtx ioctx
;
6766 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6768 //make create image options
6769 uint64_t features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_STRIPINGV2
;
6771 uint64_t stripe_unit
= IMAGE_STRIPE_UNIT
;
6772 uint64_t stripe_count
= IMAGE_STRIPE_COUNT
;
6773 librbd::ImageOptions opts
;
6774 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FORMAT
, static_cast<uint64_t>(2)));
6775 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_FEATURES
, features
));
6776 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_ORDER
, order
));
6777 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
));
6778 ASSERT_EQ(0, opts
.set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
));
6781 std::string parent_name
= get_temp_image_name();
6784 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 4<<20, opts
));
6786 // check order is returned in opts
6787 ASSERT_EQ(0, opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
));
6788 ASSERT_NE((uint64_t)0, order
);
6790 // write some data to parent
6791 librbd::Image parent
;
6792 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
6796 bl
.append(buffer::create(len
));
6798 ASSERT_EQ(len
, parent
.write(0, len
, bl
));
6799 ASSERT_EQ(len
, parent
.write(len
, len
, bl
));
6801 // create a snapshot, reopen as the parent we're interested in
6802 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
6803 ASSERT_EQ(0, parent
.close());
6804 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
6807 std::string child_name
= get_temp_image_name();
6808 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
6809 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6810 child_name
.c_str(), opts
));
6813 std::string copy1_name
= get_temp_image_name();
6814 ASSERT_EQ(0, parent
.copy3(ioctx
, copy1_name
.c_str(), opts
));
6815 std::string copy2_name
= get_temp_image_name();
6817 ASSERT_EQ(0, parent
.copy_with_progress3(ioctx
, copy2_name
.c_str(), opts
, pp
));
6819 ASSERT_EQ(0, parent
.close());
6822 TEST_F(TestLibRBD
, EventSocketPipe
)
6824 EventSocket event_sock
;
6825 int pipe_fd
[2]; // read and write fd
6828 ASSERT_EQ(0, pipe(pipe_fd
));
6830 ASSERT_FALSE(event_sock
.is_valid());
6832 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_NONE
));
6833 ASSERT_FALSE(event_sock
.is_valid());
6835 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], 44));
6836 ASSERT_FALSE(event_sock
.is_valid());
6838 #ifndef HAVE_EVENTFD
6839 ASSERT_EQ(-EINVAL
, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_EVENTFD
));
6840 ASSERT_FALSE(event_sock
.is_valid());
6843 ASSERT_EQ(0, event_sock
.init(pipe_fd
[1], EVENT_SOCKET_TYPE_PIPE
));
6844 ASSERT_TRUE(event_sock
.is_valid());
6845 ASSERT_EQ(0, event_sock
.notify());
6846 ASSERT_EQ(1, read(pipe_fd
[0], buf
, 32));
6847 ASSERT_EQ('i', buf
[0]);
6853 TEST_F(TestLibRBD
, EventSocketEventfd
)
6856 EventSocket event_sock
;
6858 struct pollfd poll_fd
;
6861 event_fd
= eventfd(0, EFD_NONBLOCK
);
6862 ASSERT_NE(-1, event_fd
);
6864 ASSERT_FALSE(event_sock
.is_valid());
6866 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_NONE
));
6867 ASSERT_FALSE(event_sock
.is_valid());
6869 ASSERT_EQ(-EINVAL
, event_sock
.init(event_fd
, 44));
6870 ASSERT_FALSE(event_sock
.is_valid());
6872 ASSERT_EQ(0, event_sock
.init(event_fd
, EVENT_SOCKET_TYPE_EVENTFD
));
6873 ASSERT_TRUE(event_sock
.is_valid());
6874 ASSERT_EQ(0, event_sock
.notify());
6876 poll_fd
.fd
= event_fd
;
6877 poll_fd
.events
= POLLIN
;
6878 ASSERT_EQ(1, poll(&poll_fd
, 1, -1));
6879 ASSERT_TRUE(poll_fd
.revents
& POLLIN
);
6881 ASSERT_EQ(static_cast<ssize_t
>(sizeof(uint64_t)), read(event_fd
, buf
, 32));
6882 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf
));
6888 TEST_F(TestLibRBD
, ImagePollIO
)
6891 rados_ioctx_t ioctx
;
6892 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
6896 std::string name
= get_temp_image_name();
6897 uint64_t size
= 2 << 20;
6898 int fd
= eventfd(0, EFD_NONBLOCK
);
6900 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
6901 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
6903 ASSERT_EQ(0, rbd_set_image_notification(image
, fd
, EVENT_SOCKET_TYPE_EVENTFD
));
6905 char test_data
[TEST_IO_SIZE
+ 1];
6906 char zero_data
[TEST_IO_SIZE
+ 1];
6909 for (i
= 0; i
< TEST_IO_SIZE
; ++i
)
6910 test_data
[i
] = (char) (rand() % (126 - 33) + 33);
6911 test_data
[TEST_IO_SIZE
] = '\0';
6912 memset(zero_data
, 0, sizeof(zero_data
));
6914 for (i
= 0; i
< 5; ++i
)
6915 ASSERT_PASSED(write_test_data
, image
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6917 for (i
= 5; i
< 10; ++i
)
6918 ASSERT_PASSED(aio_write_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6920 for (i
= 5; i
< 10; ++i
)
6921 ASSERT_PASSED(aio_read_test_data_and_poll
, image
, fd
, test_data
, TEST_IO_SIZE
* i
, TEST_IO_SIZE
, 0);
6923 ASSERT_EQ(0, rbd_close(image
));
6924 rados_ioctx_destroy(ioctx
);
6930 static bool operator==(const image_spec_t
&lhs
, const image_spec_t
&rhs
) {
6931 return (lhs
.id
== rhs
.id
&& lhs
.name
== rhs
.name
);
6934 static bool operator==(const linked_image_spec_t
&lhs
,
6935 const linked_image_spec_t
&rhs
) {
6936 return (lhs
.pool_id
== rhs
.pool_id
&&
6937 lhs
.pool_name
== rhs
.pool_name
&&
6938 lhs
.pool_namespace
== rhs
.pool_namespace
&&
6939 lhs
.image_id
== rhs
.image_id
&&
6940 lhs
.image_name
== rhs
.image_name
&&
6941 lhs
.trash
== rhs
.trash
);
6944 static bool operator==(const mirror_peer_t
&lhs
, const mirror_peer_t
&rhs
) {
6945 return (lhs
.uuid
== rhs
.uuid
&&
6946 lhs
.cluster_name
== rhs
.cluster_name
&&
6947 lhs
.client_name
== rhs
.client_name
);
6950 static std::ostream
& operator<<(std::ostream
&os
, const mirror_peer_t
&peer
) {
6951 os
<< "uuid=" << peer
.uuid
<< ", "
6952 << "cluster=" << peer
.cluster_name
<< ", "
6953 << "client=" << peer
.client_name
;
6957 } // namespace librbd
6959 TEST_F(TestLibRBD
, Mirror
) {
6960 librados::IoCtx ioctx
;
6961 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
6965 std::vector
<librbd::mirror_peer_t
> expected_peers
;
6966 std::vector
<librbd::mirror_peer_t
> peers
;
6967 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
6968 ASSERT_EQ(expected_peers
, peers
);
6971 ASSERT_EQ(-EINVAL
, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
6973 rbd_mirror_mode_t mirror_mode
;
6974 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6975 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED
, mirror_mode
);
6977 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
6978 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
6980 // Add some images to the pool
6982 std::string parent_name
= get_temp_image_name();
6983 std::string child_name
= get_temp_image_name();
6984 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, parent_name
.c_str(), 2 << 20,
6988 ASSERT_EQ(0, get_features(&old_format
, &features
));
6989 if ((features
& RBD_FEATURE_LAYERING
) != 0) {
6990 librbd::Image parent
;
6991 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), NULL
));
6992 ASSERT_EQ(0, parent
.snap_create("parent_snap"));
6993 ASSERT_EQ(0, parent
.close());
6994 ASSERT_EQ(0, rbd
.open(ioctx
, parent
, parent_name
.c_str(), "parent_snap"));
6995 ASSERT_EQ(0, parent
.snap_protect("parent_snap"));
6996 ASSERT_EQ(0, parent
.close());
6997 ASSERT_EQ(0, rbd
.clone(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
6998 child_name
.c_str(), features
, &order
));
7001 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE
, mirror_mode
);
7003 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_POOL
));
7004 ASSERT_EQ(0, rbd
.mirror_mode_get(ioctx
, &mirror_mode
));
7005 ASSERT_EQ(RBD_MIRROR_MODE_POOL
, mirror_mode
);
7009 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid1
, "cluster1", "client"));
7010 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid2
, "cluster2", "admin"));
7011 ASSERT_EQ(-EEXIST
, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster1", "foo"));
7012 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid3
, "cluster3", "admin"));
7014 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
7015 auto sort_peers
= [](const librbd::mirror_peer_t
&lhs
,
7016 const librbd::mirror_peer_t
&rhs
) {
7017 return lhs
.uuid
< rhs
.uuid
;
7020 {uuid1
, "cluster1", "client"},
7021 {uuid2
, "cluster2", "admin"},
7022 {uuid3
, "cluster3", "admin"}};
7023 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
7024 ASSERT_EQ(expected_peers
, peers
);
7026 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, "uuid4"));
7027 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid2
));
7029 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_client(ioctx
, "uuid4", "new client"));
7030 ASSERT_EQ(0, rbd
.mirror_peer_set_client(ioctx
, uuid1
, "new client"));
7032 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_cluster(ioctx
, "uuid4",
7034 ASSERT_EQ(0, rbd
.mirror_peer_set_cluster(ioctx
, uuid3
, "new cluster"));
7036 ASSERT_EQ(0, rbd
.mirror_peer_list(ioctx
, &peers
));
7038 {uuid1
, "cluster1", "new client"},
7039 {uuid3
, "new cluster", "admin"}};
7040 std::sort(expected_peers
.begin(), expected_peers
.end(), sort_peers
);
7041 ASSERT_EQ(expected_peers
, peers
);
7043 ASSERT_EQ(-EBUSY
, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7044 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid1
));
7045 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid3
));
7046 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7049 TEST_F(TestLibRBD
, MirrorPeerAttributes
) {
7050 REQUIRE(!is_librados_test_stub(_rados
));
7052 librados::IoCtx ioctx
;
7053 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7056 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
7059 ASSERT_EQ(0, rbd
.mirror_peer_add(ioctx
, &uuid
, "remote_cluster", "client"));
7061 std::map
<std::string
, std::string
> attributes
;
7062 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_get_attributes(ioctx
, uuid
, &attributes
));
7063 ASSERT_EQ(-ENOENT
, rbd
.mirror_peer_set_attributes(ioctx
, "missing uuid",
7066 std::map
<std::string
, std::string
> expected_attributes
{
7067 {"mon_host", "1.2.3.4"},
7069 ASSERT_EQ(0, rbd
.mirror_peer_set_attributes(ioctx
, uuid
,
7070 expected_attributes
));
7072 ASSERT_EQ(0, rbd
.mirror_peer_get_attributes(ioctx
, uuid
,
7074 ASSERT_EQ(expected_attributes
, attributes
);
7076 ASSERT_EQ(0, rbd
.mirror_peer_remove(ioctx
, uuid
));
7077 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7080 TEST_F(TestLibRBD
, CreateWithMirrorEnabled
) {
7081 REQUIRE_FORMAT_V2();
7083 librados::IoCtx ioctx
;
7084 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7087 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_IMAGE
));
7089 librbd::ImageOptions image_options
;
7090 ASSERT_EQ(0, image_options
.set(
7091 RBD_IMAGE_OPTION_MIRROR_IMAGE_MODE
,
7092 static_cast<uint64_t>(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
)));
7094 std::string parent_name
= get_temp_image_name();
7095 ASSERT_EQ(0, rbd
.create4(ioctx
, parent_name
.c_str(), 2<<20, image_options
));
7097 librbd::Image parent_image
;
7098 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, parent_name
.c_str(), NULL
));
7100 librbd::mirror_image_mode_t mirror_image_mode
;
7101 ASSERT_EQ(0, parent_image
.mirror_image_get_mode(&mirror_image_mode
));
7102 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
7104 ASSERT_EQ(0, parent_image
.snap_create("parent_snap"));
7105 ASSERT_EQ(0, parent_image
.snap_protect("parent_snap"));
7107 std::string child_name
= get_temp_image_name();
7108 ASSERT_EQ(0, rbd
.clone3(ioctx
, parent_name
.c_str(), "parent_snap", ioctx
,
7109 child_name
.c_str(), image_options
));
7111 librbd::Image child_image
;
7112 ASSERT_EQ(0, rbd
.open(ioctx
, child_image
, child_name
.c_str(), NULL
));
7114 ASSERT_EQ(0, child_image
.mirror_image_get_mode(&mirror_image_mode
));
7115 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT
, mirror_image_mode
);
7117 ASSERT_EQ(0, child_image
.mirror_image_disable(true));
7118 ASSERT_EQ(0, parent_image
.mirror_image_disable(true));
7119 ASSERT_EQ(0, rbd
.mirror_mode_set(ioctx
, RBD_MIRROR_MODE_DISABLED
));
7122 TEST_F(TestLibRBD
, FlushCacheWithCopyupOnExternalSnapshot
) {
7123 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7125 librados::IoCtx ioctx
;
7126 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7129 librbd::Image image
;
7130 std::string name
= get_temp_image_name();
7132 uint64_t size
= 1 << 18;
7135 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7136 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7139 bl
.append(std::string(size
, '1'));
7140 ASSERT_EQ((int)size
, image
.write(0, size
, bl
));
7141 ASSERT_EQ(0, image
.snap_create("one"));
7142 ASSERT_EQ(0, image
.snap_protect("one"));
7144 std::string clone_name
= this->get_temp_image_name();
7145 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "one", ioctx
, clone_name
.c_str(),
7146 RBD_FEATURE_LAYERING
, &order
));
7147 ASSERT_EQ(0, rbd
.open(ioctx
, image
, clone_name
.c_str(), NULL
));
7149 librbd::Image image2
;
7150 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, clone_name
.c_str(), NULL
));
7152 // prepare CoW writeback that will be flushed on next op
7154 bl
.append(std::string(1, '1'));
7155 ASSERT_EQ(0, image
.flush());
7156 ASSERT_EQ(1, image
.write(0, 1, bl
));
7157 ASSERT_EQ(0, image2
.snap_create("snap1"));
7159 librbd::RBD::AioCompletion
*read_comp
=
7160 new librbd::RBD::AioCompletion(NULL
, NULL
);
7162 image
.aio_read(0, 1024, read_bl
, read_comp
);
7163 ASSERT_EQ(0, read_comp
->wait_for_complete());
7164 read_comp
->release();
7167 TEST_F(TestLibRBD
, ExclusiveLock
)
7169 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
7171 static char buf
[10];
7173 rados_ioctx_t ioctx
;
7174 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7176 std::string name
= get_temp_image_name();
7177 uint64_t size
= 2 << 20;
7179 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7182 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
7185 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
7186 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7187 ASSERT_TRUE(lock_owner
);
7189 rbd_lock_mode_t lock_mode
;
7190 char *lock_owners
[1];
7191 size_t max_lock_owners
= 0;
7192 ASSERT_EQ(-ERANGE
, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
7194 ASSERT_EQ(1U, max_lock_owners
);
7196 ASSERT_EQ(0, rbd_lock_get_owners(image1
, &lock_mode
, lock_owners
,
7198 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
7199 ASSERT_STRNE("", lock_owners
[0]);
7200 ASSERT_EQ(1U, max_lock_owners
);
7203 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
7205 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7206 ASSERT_FALSE(lock_owner
);
7208 ASSERT_EQ(-EOPNOTSUPP
, rbd_lock_break(image1
, RBD_LOCK_MODE_SHARED
, ""));
7209 ASSERT_EQ(-EBUSY
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
7212 ASSERT_EQ(0, rbd_lock_release(image1
));
7213 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7214 ASSERT_FALSE(lock_owner
);
7216 ASSERT_EQ(-ENOENT
, rbd_lock_break(image1
, RBD_LOCK_MODE_EXCLUSIVE
,
7218 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
7220 ASSERT_EQ(-EROFS
, rbd_write(image1
, 0, sizeof(buf
), buf
));
7221 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image2
, 0, sizeof(buf
), buf
));
7223 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
7224 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7225 ASSERT_TRUE(lock_owner
);
7227 ASSERT_EQ(0, rbd_lock_release(image2
));
7228 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7229 ASSERT_FALSE(lock_owner
);
7231 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
7232 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7233 ASSERT_TRUE(lock_owner
);
7235 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image1
, 0, sizeof(buf
), buf
));
7236 ASSERT_EQ(-EROFS
, rbd_write(image2
, 0, sizeof(buf
), buf
));
7238 ASSERT_EQ(0, rbd_lock_release(image1
));
7239 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7240 ASSERT_FALSE(lock_owner
);
7244 const auto pingpong
= [&](int m_id
, rbd_image_t
&m_image
) {
7245 for (int i
= 0; i
< 10; i
++) {
7247 std::lock_guard
<std::mutex
> locker(lock
);
7248 if (owner_id
== m_id
) {
7249 std::cout
<< m_id
<< ": releasing exclusive lock" << std::endl
;
7250 EXPECT_EQ(0, rbd_lock_release(m_image
));
7252 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
7253 EXPECT_FALSE(lock_owner
);
7255 std::cout
<< m_id
<< ": exclusive lock released" << std::endl
;
7260 std::cout
<< m_id
<< ": acquiring exclusive lock" << std::endl
;
7263 r
= rbd_lock_acquire(m_image
, RBD_LOCK_MODE_EXCLUSIVE
);
7267 } while (r
== -EROFS
);
7271 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
7272 EXPECT_TRUE(lock_owner
);
7273 std::cout
<< m_id
<< ": exclusive lock acquired" << std::endl
;
7275 std::lock_guard
<std::mutex
> locker(lock
);
7278 usleep(rand() % 50000);
7281 std::lock_guard
<std::mutex
> locker(lock
);
7282 if (owner_id
== m_id
) {
7283 EXPECT_EQ(0, rbd_lock_release(m_image
));
7285 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image
, &lock_owner
));
7286 EXPECT_FALSE(lock_owner
);
7290 thread
ping(bind(pingpong
, 1, ref(image1
)));
7291 thread
pong(bind(pingpong
, 2, ref(image2
)));
7296 ASSERT_EQ(0, rbd_lock_acquire(image2
, RBD_LOCK_MODE_EXCLUSIVE
));
7297 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2
, &lock_owner
));
7298 ASSERT_TRUE(lock_owner
);
7300 ASSERT_EQ(0, rbd_close(image2
));
7302 ASSERT_EQ(0, rbd_lock_acquire(image1
, RBD_LOCK_MODE_EXCLUSIVE
));
7303 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1
, &lock_owner
));
7304 ASSERT_TRUE(lock_owner
);
7306 ASSERT_EQ(0, rbd_close(image1
));
7307 rados_ioctx_destroy(ioctx
);
7310 TEST_F(TestLibRBD
, BreakLock
)
7312 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
7313 REQUIRE(!is_rbd_pwl_enabled((CephContext
*)_rados
.cct()));
7315 static char buf
[10];
7317 rados_t blocklist_cluster
;
7318 ASSERT_EQ("", connect_cluster(&blocklist_cluster
));
7320 rados_ioctx_t ioctx
, blocklist_ioctx
;
7321 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
7322 ASSERT_EQ(0, rados_ioctx_create(blocklist_cluster
, m_pool_name
.c_str(),
7325 std::string name
= get_temp_image_name();
7326 uint64_t size
= 2 << 20;
7328 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7330 rbd_image_t image
, blocklist_image
;
7331 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7332 ASSERT_EQ(0, rbd_open(blocklist_ioctx
, name
.c_str(), &blocklist_image
, NULL
));
7334 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_blocklist_on_break_lock", "true"));
7335 ASSERT_EQ(0, rbd_lock_acquire(blocklist_image
, RBD_LOCK_MODE_EXCLUSIVE
));
7337 rbd_lock_mode_t lock_mode
;
7338 char *lock_owners
[1];
7339 size_t max_lock_owners
= 1;
7340 ASSERT_EQ(0, rbd_lock_get_owners(image
, &lock_mode
, lock_owners
,
7342 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE
, lock_mode
);
7343 ASSERT_STRNE("", lock_owners
[0]);
7344 ASSERT_EQ(1U, max_lock_owners
);
7346 ASSERT_EQ(0, rbd_lock_break(image
, RBD_LOCK_MODE_EXCLUSIVE
, lock_owners
[0]));
7347 ASSERT_EQ(0, rbd_lock_acquire(image
, RBD_LOCK_MODE_EXCLUSIVE
));
7348 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blocklist_cluster
));
7350 ASSERT_EQ((ssize_t
)sizeof(buf
), rbd_write(image
, 0, sizeof(buf
), buf
));
7351 ASSERT_EQ(-EBLOCKLISTED
, rbd_write(blocklist_image
, 0, sizeof(buf
), buf
));
7353 ASSERT_EQ(0, rbd_close(image
));
7354 ASSERT_EQ(0, rbd_close(blocklist_image
));
7356 rbd_lock_get_owners_cleanup(lock_owners
, max_lock_owners
);
7358 rados_ioctx_destroy(ioctx
);
7359 rados_ioctx_destroy(blocklist_ioctx
);
7360 rados_shutdown(blocklist_cluster
);
7363 TEST_F(TestLibRBD
, DiscardAfterWrite
)
7365 librados::IoCtx ioctx
;
7366 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7369 std::string name
= get_temp_image_name();
7370 uint64_t size
= 1 << 20;
7372 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7374 librbd::Image image
;
7375 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7377 if (this->is_skip_partial_discard_enabled(image
)) {
7381 // enable writeback cache
7382 ASSERT_EQ(0, image
.flush());
7385 bl
.append(std::string(256, '1'));
7387 librbd::RBD::AioCompletion
*write_comp
=
7388 new librbd::RBD::AioCompletion(NULL
, NULL
);
7389 ASSERT_EQ(0, image
.aio_write(0, bl
.length(), bl
, write_comp
));
7390 ASSERT_EQ(0, write_comp
->wait_for_complete());
7391 write_comp
->release();
7393 librbd::RBD::AioCompletion
*discard_comp
=
7394 new librbd::RBD::AioCompletion(NULL
, NULL
);
7395 ASSERT_EQ(0, image
.aio_discard(0, 256, discard_comp
));
7396 ASSERT_EQ(0, discard_comp
->wait_for_complete());
7397 discard_comp
->release();
7399 librbd::RBD::AioCompletion
*read_comp
=
7400 new librbd::RBD::AioCompletion(NULL
, NULL
);
7402 image
.aio_read(0, bl
.length(), read_bl
, read_comp
);
7403 ASSERT_EQ(0, read_comp
->wait_for_complete());
7404 ASSERT_EQ(bl
.length(), read_comp
->get_return_value());
7405 ASSERT_TRUE(read_bl
.is_zero());
7406 read_comp
->release();
7409 TEST_F(TestLibRBD
, DefaultFeatures
) {
7410 std::string orig_default_features
;
7411 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", orig_default_features
));
7412 BOOST_SCOPE_EXIT_ALL(orig_default_features
) {
7413 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features",
7414 orig_default_features
.c_str()));
7417 std::list
<std::pair
<std::string
, std::string
> > feature_names_to_bitmask
= {
7418 {"", orig_default_features
},
7420 {"layering, exclusive-lock", "5"},
7421 {"exclusive-lock,journaling", "68"},
7425 for (auto &pair
: feature_names_to_bitmask
) {
7426 ASSERT_EQ(0, _rados
.conf_set("rbd_default_features", pair
.first
.c_str()));
7427 std::string features
;
7428 ASSERT_EQ(0, _rados
.conf_get("rbd_default_features", features
));
7429 ASSERT_EQ(pair
.second
, features
);
7433 TEST_F(TestLibRBD
, TestTrashMoveAndPurge
) {
7434 REQUIRE_FORMAT_V2();
7436 librados::IoCtx ioctx
;
7437 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7440 std::string name
= get_temp_image_name();
7442 uint64_t size
= 1 << 18;
7444 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7446 librbd::Image image
;
7447 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7449 std::string image_id
;
7450 ASSERT_EQ(0, image
.get_id(&image_id
));
7453 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7455 std::vector
<std::string
> images
;
7456 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7457 for (const auto& image
: images
) {
7458 ASSERT_TRUE(image
!= name
);
7461 librbd::trash_image_info_t info
;
7462 ASSERT_EQ(-ENOENT
, rbd
.trash_get(ioctx
, "dummy image id", &info
));
7463 ASSERT_EQ(0, rbd
.trash_get(ioctx
, image_id
.c_str(), &info
));
7464 ASSERT_EQ(image_id
, info
.id
);
7466 std::vector
<librbd::trash_image_info_t
> entries
;
7467 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7468 ASSERT_FALSE(entries
.empty());
7469 ASSERT_EQ(entries
.begin()->id
, image_id
);
7473 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7475 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7476 ASSERT_TRUE(entries
.empty());
7479 TEST_F(TestLibRBD
, TestTrashMoveAndPurgeNonExpiredDelay
) {
7480 REQUIRE_FORMAT_V2();
7482 librados::IoCtx ioctx
;
7483 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7486 std::string name
= get_temp_image_name();
7488 uint64_t size
= 1 << 18;
7490 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7492 librbd::Image image
;
7493 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7495 std::string image_id
;
7496 ASSERT_EQ(0, image
.get_id(&image_id
));
7499 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 100));
7502 ASSERT_EQ(-EPERM
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7506 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7510 TEST_F(TestLibRBD
, TestTrashPurge
) {
7511 REQUIRE_FORMAT_V2();
7513 librados::IoCtx ioctx
;
7514 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7517 std::string name1
= get_temp_image_name();
7518 std::string name2
= get_temp_image_name();
7520 uint64_t size
= 1 << 18;
7522 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name1
.c_str(), size
, &order
));
7523 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name2
.c_str(), size
, &order
));
7525 librbd::Image image1
;
7526 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name1
.c_str(), nullptr));
7528 std::string image_id1
;
7529 ASSERT_EQ(0, image1
.get_id(&image_id1
));
7532 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name1
.c_str(), 0));
7534 librbd::Image image2
;
7535 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name2
.c_str(), nullptr));
7536 ceph::bufferlist bl
;
7537 bl
.append(std::string(1024, '0'));
7538 ASSERT_EQ(1024, image2
.write(0, 1024, bl
));
7540 std::string image_id2
;
7541 ASSERT_EQ(0, image2
.get_id(&image_id2
));
7544 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name2
.c_str(), 100));
7545 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, 0, -1));
7547 std::vector
<librbd::trash_image_info_t
> entries
;
7548 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7549 ASSERT_EQ(1U, entries
.size());
7550 ASSERT_EQ(image_id2
, entries
[0].id
);
7551 ASSERT_EQ(name2
, entries
[0].name
);
7554 struct timespec now
;
7555 clock_gettime(CLOCK_REALTIME
, &now
);
7556 float threshold
= 0.0;
7557 if (!is_librados_test_stub(_rados
)) {
7558 // real cluster usage reports have a long latency to update
7562 ASSERT_EQ(0, rbd
.trash_purge(ioctx
, now
.tv_sec
+1000, threshold
));
7563 ASSERT_EQ(0, rbd
.trash_list(ioctx
, entries
));
7564 ASSERT_EQ(0U, entries
.size());
7567 TEST_F(TestLibRBD
, TestTrashMoveAndRestore
) {
7568 REQUIRE_FORMAT_V2();
7570 librados::IoCtx ioctx
;
7571 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7574 std::string name
= get_temp_image_name();
7576 uint64_t size
= 1 << 18;
7578 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7580 librbd::Image image
;
7581 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7583 std::string image_id
;
7584 ASSERT_EQ(0, image
.get_id(&image_id
));
7587 ASSERT_EQ(0, rbd
.trash_move(ioctx
, name
.c_str(), 10));
7589 std::vector
<std::string
> images
;
7590 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7591 for (const auto& image
: images
) {
7592 ASSERT_TRUE(image
!= name
);
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
);
7601 ASSERT_EQ(0, rbd
.trash_restore(ioctx
, image_id
.c_str(), ""));
7602 ASSERT_EQ(0, rbd
.list(ioctx
, images
));
7603 ASSERT_FALSE(images
.empty());
7605 for (const auto& image
: images
) {
7606 if (image
== name
) {
7614 TEST_F(TestLibRBD
, TestListWatchers
) {
7615 librados::IoCtx ioctx
;
7616 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7619 std::string name
= get_temp_image_name();
7621 uint64_t size
= 1 << 18;
7623 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7625 librbd::Image image
;
7626 std::list
<librbd::image_watcher_t
> watchers
;
7629 ASSERT_EQ(0, rbd
.open_read_only(ioctx
, image
, name
.c_str(), nullptr));
7630 ASSERT_EQ(0, image
.list_watchers(watchers
));
7631 ASSERT_EQ(0U, watchers
.size());
7632 ASSERT_EQ(0, image
.close());
7635 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7636 ASSERT_EQ(0, image
.list_watchers(watchers
));
7637 ASSERT_EQ(1U, watchers
.size());
7638 ASSERT_EQ(0, image
.close());
7641 TEST_F(TestLibRBD
, TestSetSnapById
) {
7642 librados::IoCtx ioctx
;
7643 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7646 std::string name
= get_temp_image_name();
7648 uint64_t size
= 1 << 18;
7650 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7652 librbd::Image image
;
7653 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
7654 ASSERT_EQ(0, image
.snap_create("snap"));
7656 vector
<librbd::snap_info_t
> snaps
;
7657 ASSERT_EQ(0, image
.snap_list(snaps
));
7658 ASSERT_EQ(1U, snaps
.size());
7660 ASSERT_EQ(0, image
.snap_set_by_id(snaps
[0].id
));
7661 ASSERT_EQ(0, image
.snap_set_by_id(CEPH_NOSNAP
));
7664 TEST_F(TestLibRBD
, Namespaces
) {
7665 rados_ioctx_t ioctx
;
7666 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
));
7667 rados_remove(ioctx
, RBD_NAMESPACE
);
7669 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name1"));
7670 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name2"));
7671 ASSERT_EQ(0, rbd_namespace_create(ioctx
, "name3"));
7672 ASSERT_EQ(0, rbd_namespace_remove(ioctx
, "name2"));
7675 size_t max_size
= sizeof(names
);
7676 int len
= rbd_namespace_list(ioctx
, names
, &max_size
);
7678 std::vector
<std::string
> cpp_names
;
7679 for (char* cur_name
= names
; cur_name
< names
+ len
; ) {
7680 cpp_names
.push_back(cur_name
);
7681 cur_name
+= strlen(cur_name
) + 1;
7683 ASSERT_EQ(2U, cpp_names
.size());
7684 ASSERT_EQ("name1", cpp_names
[0]);
7685 ASSERT_EQ("name3", cpp_names
[1]);
7687 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name2", &exists
));
7688 ASSERT_FALSE(exists
);
7689 ASSERT_EQ(0, rbd_namespace_exists(ioctx
, "name3", &exists
));
7690 ASSERT_TRUE(exists
);
7691 rados_ioctx_destroy(ioctx
);
7694 TEST_F(TestLibRBD
, NamespacesPP
) {
7695 librados::IoCtx ioctx
;
7696 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7697 ioctx
.remove(RBD_NAMESPACE
);
7700 ASSERT_EQ(-EINVAL
, rbd
.namespace_create(ioctx
, ""));
7701 ASSERT_EQ(-EINVAL
, rbd
.namespace_remove(ioctx
, ""));
7703 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name1"));
7704 ASSERT_EQ(-EEXIST
, rbd
.namespace_create(ioctx
, "name1"));
7705 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name2"));
7706 ASSERT_EQ(0, rbd
.namespace_create(ioctx
, "name3"));
7707 ASSERT_EQ(0, rbd
.namespace_remove(ioctx
, "name2"));
7708 ASSERT_EQ(-ENOENT
, rbd
.namespace_remove(ioctx
, "name2"));
7710 std::vector
<std::string
> names
;
7711 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7712 ASSERT_EQ(2U, names
.size());
7713 ASSERT_EQ("name1", names
[0]);
7714 ASSERT_EQ("name3", names
[1]);
7716 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name2", &exists
));
7717 ASSERT_FALSE(exists
);
7718 ASSERT_EQ(0, rbd
.namespace_exists(ioctx
, "name3", &exists
));
7719 ASSERT_TRUE(exists
);
7721 librados::IoCtx ns_io_ctx
;
7722 ns_io_ctx
.dup(ioctx
);
7724 std::string name
= get_temp_image_name();
7726 uint64_t features
= 0;
7727 if (!get_features(&features
)) {
7728 // old format doesn't support namespaces
7729 ns_io_ctx
.set_namespace("name1");
7730 ASSERT_EQ(-EINVAL
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0,
7735 ns_io_ctx
.set_namespace("missing");
7736 ASSERT_EQ(-ENOENT
, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7738 ns_io_ctx
.set_namespace("name1");
7739 ASSERT_EQ(0, create_image_pp(rbd
, ns_io_ctx
, name
.c_str(), 0, &order
));
7740 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7742 std::string image_id
;
7744 librbd::Image image
;
7745 ASSERT_EQ(-ENOENT
, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7746 ASSERT_EQ(0, rbd
.open(ns_io_ctx
, image
, name
.c_str(), NULL
));
7747 ASSERT_EQ(0, get_image_id(image
, &image_id
));
7750 ASSERT_EQ(-ENOENT
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7751 ASSERT_EQ(0, rbd
.trash_move(ns_io_ctx
, name
.c_str(), 0));
7752 ASSERT_EQ(-EBUSY
, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7755 ASSERT_EQ(-ENOENT
, rbd
.trash_remove_with_progress(ioctx
, image_id
.c_str(),
7757 ASSERT_EQ(0, rbd
.trash_remove_with_progress(ns_io_ctx
, image_id
.c_str(),
7759 ASSERT_EQ(0, rbd
.namespace_remove(ns_io_ctx
, "name1"));
7762 ASSERT_EQ(0, rbd
.namespace_list(ioctx
, &names
));
7763 ASSERT_EQ(1U, names
.size());
7764 ASSERT_EQ("name3", names
[0]);
7767 TEST_F(TestLibRBD
, Migration
) {
7770 ASSERT_EQ(0, get_features(&old_format
, &features
));
7772 rados_ioctx_t ioctx
;
7773 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7774 BOOST_SCOPE_EXIT(&ioctx
) {
7775 rados_ioctx_destroy(ioctx
);
7776 } BOOST_SCOPE_EXIT_END
;
7779 std::string name
= get_temp_image_name();
7780 uint64_t size
= 2 << 20;
7781 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7783 rbd_image_options_t image_options
;
7784 rbd_image_options_create(&image_options
);
7785 BOOST_SCOPE_EXIT(&image_options
) {
7786 rbd_image_options_destroy(image_options
);
7787 } BOOST_SCOPE_EXIT_END
;
7789 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7792 rbd_image_migration_status_t status
;
7793 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7795 ASSERT_EQ(status
.source_pool_id
, rados_ioctx_get_id(ioctx
));
7796 ASSERT_EQ(status
.source_image_name
, name
);
7798 ASSERT_EQ(status
.source_image_id
, string());
7800 ASSERT_NE(status
.source_image_id
, string());
7801 ASSERT_EQ(-EROFS
, rbd_trash_remove(ioctx
, status
.source_image_id
, false));
7802 ASSERT_EQ(-EINVAL
, rbd_trash_restore(ioctx
, status
.source_image_id
, name
.c_str()));
7804 ASSERT_EQ(status
.dest_pool_id
, rados_ioctx_get_id(ioctx
));
7805 ASSERT_EQ(status
.dest_image_name
, name
);
7806 ASSERT_NE(status
.dest_image_id
, string());
7807 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
7808 rbd_migration_status_cleanup(&status
);
7811 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7812 char source_spec
[2048];
7813 size_t source_spec_length
= sizeof(source_spec
);
7814 ASSERT_EQ(0, rbd_get_migration_source_spec(image
, source_spec
,
7815 &source_spec_length
));
7816 json_spirit::mValue json_source_spec
;
7817 json_spirit::read(source_spec
, json_source_spec
);
7818 EXPECT_EQ(0, rbd_close(image
));
7820 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, name
.c_str()));
7821 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, name
.c_str(), 0));
7823 ASSERT_EQ(0, rbd_migration_execute(ioctx
, name
.c_str()));
7825 ASSERT_EQ(0, rbd_migration_status(ioctx
, name
.c_str(), &status
,
7827 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
7828 rbd_migration_status_cleanup(&status
);
7830 ASSERT_EQ(0, rbd_migration_commit(ioctx
, name
.c_str()));
7832 std::string new_name
= get_temp_image_name();
7834 ASSERT_EQ(0, rbd_migration_prepare(ioctx
, name
.c_str(), ioctx
,
7835 new_name
.c_str(), image_options
));
7837 ASSERT_EQ(-EBUSY
, rbd_remove(ioctx
, new_name
.c_str()));
7838 ASSERT_EQ(-EBUSY
, rbd_trash_move(ioctx
, new_name
.c_str(), 0));
7840 ASSERT_EQ(0, rbd_migration_abort(ioctx
, name
.c_str()));
7842 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7843 EXPECT_EQ(0, rbd_close(image
));
7846 TEST_F(TestLibRBD
, MigrationPP
) {
7849 ASSERT_EQ(0, get_features(&old_format
, &features
));
7851 librados::IoCtx ioctx
;
7852 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7855 std::string name
= get_temp_image_name();
7856 uint64_t size
= 2 << 20;
7858 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7860 librbd::ImageOptions image_options
;
7862 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
, name
.c_str(),
7865 librbd::image_migration_status_t status
;
7866 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
7868 ASSERT_EQ(status
.source_pool_id
, ioctx
.get_id());
7869 ASSERT_EQ(status
.source_image_name
, name
);
7871 ASSERT_EQ(status
.source_image_id
, "");
7873 ASSERT_NE(status
.source_image_id
, "");
7874 ASSERT_EQ(-EROFS
, rbd
.trash_remove(ioctx
, status
.source_image_id
.c_str(), false));
7875 ASSERT_EQ(-EINVAL
, rbd
.trash_restore(ioctx
, status
.source_image_id
.c_str(), name
.c_str()));
7877 ASSERT_EQ(status
.dest_pool_id
, ioctx
.get_id());
7878 ASSERT_EQ(status
.dest_image_name
, name
);
7879 ASSERT_NE(status
.dest_image_id
, "");
7880 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_PREPARED
);
7882 librbd::Image image
;
7883 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7884 std::string source_spec
;
7885 ASSERT_EQ(0, image
.get_migration_source_spec(&source_spec
));
7886 json_spirit::mValue json_source_spec
;
7887 json_spirit::read(source_spec
, json_source_spec
);
7888 json_spirit::mObject json_source_spec_obj
= json_source_spec
.get_obj();
7889 ASSERT_EQ("native", json_source_spec_obj
["type"].get_str());
7890 ASSERT_EQ(ioctx
.get_id(), json_source_spec_obj
["pool_id"].get_int64());
7891 ASSERT_EQ("", json_source_spec_obj
["pool_namespace"].get_str());
7892 ASSERT_EQ(1, json_source_spec_obj
.count("image_name"));
7894 ASSERT_EQ(1, json_source_spec_obj
.count("image_id"));
7896 ASSERT_EQ(0, image
.close());
7898 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, name
.c_str()));
7899 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, name
.c_str(), 0));
7901 ASSERT_EQ(0, rbd
.migration_execute(ioctx
, name
.c_str()));
7903 ASSERT_EQ(0, rbd
.migration_status(ioctx
, name
.c_str(), &status
,
7905 ASSERT_EQ(status
.state
, RBD_IMAGE_MIGRATION_STATE_EXECUTED
);
7907 ASSERT_EQ(0, rbd
.migration_commit(ioctx
, name
.c_str()));
7909 std::string new_name
= get_temp_image_name();
7911 ASSERT_EQ(0, rbd
.migration_prepare(ioctx
, name
.c_str(), ioctx
,
7912 new_name
.c_str(), image_options
));
7914 ASSERT_EQ(-EBUSY
, rbd
.remove(ioctx
, new_name
.c_str()));
7915 ASSERT_EQ(-EBUSY
, rbd
.trash_move(ioctx
, new_name
.c_str(), 0));
7917 ASSERT_EQ(0, rbd
.migration_abort(ioctx
, name
.c_str()));
7919 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
7922 TEST_F(TestLibRBD
, TestGetAccessTimestamp
)
7924 REQUIRE_FORMAT_V2();
7926 rados_ioctx_t ioctx
;
7927 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7931 std::string name
= get_temp_image_name();
7932 uint64_t size
= 2 << 20;
7933 struct timespec timestamp
;
7935 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7936 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7938 ASSERT_EQ(0, rbd_get_access_timestamp(image
, ×tamp
));
7939 ASSERT_LT(0, timestamp
.tv_sec
);
7941 ASSERT_PASSED(validate_object_map
, image
);
7942 ASSERT_EQ(0, rbd_close(image
));
7944 rados_ioctx_destroy(ioctx
);
7947 TEST_F(TestLibRBD
, TestGetModifyTimestamp
)
7949 REQUIRE_FORMAT_V2();
7951 rados_ioctx_t ioctx
;
7952 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
7956 std::string name
= get_temp_image_name();
7957 uint64_t size
= 2 << 20;
7958 struct timespec timestamp
;
7960 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
7961 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
7962 ASSERT_EQ(0, rbd_get_modify_timestamp(image
, ×tamp
));
7963 ASSERT_LT(0, timestamp
.tv_sec
);
7965 ASSERT_PASSED(validate_object_map
, image
);
7966 ASSERT_EQ(0, rbd_close(image
));
7968 rados_ioctx_destroy(ioctx
);
7971 TEST_F(TestLibRBD
, ZeroOverlapFlatten
) {
7972 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
7974 librados::IoCtx ioctx
;
7975 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
7978 librbd::Image parent_image
;
7979 std::string name
= get_temp_image_name();
7984 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
7985 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
7988 ASSERT_EQ(0, parent_image
.features(&features
));
7990 ASSERT_EQ(0, parent_image
.snap_create("snap"));
7991 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
7993 std::string clone_name
= this->get_temp_image_name();
7994 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
7997 librbd::Image clone_image
;
7998 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
7999 ASSERT_EQ(0, clone_image
.resize(0));
8000 ASSERT_EQ(0, clone_image
.flatten());
8003 TEST_F(TestLibRBD
, PoolMetadata
)
8005 REQUIRE_FORMAT_V2();
8007 rados_ioctx_t ioctx
;
8008 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8012 size_t keys_len
= sizeof(keys
);
8013 size_t vals_len
= sizeof(vals
);
8015 memset_rand(keys
, keys_len
);
8016 memset_rand(vals
, vals_len
);
8018 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8020 ASSERT_EQ(0U, keys_len
);
8021 ASSERT_EQ(0U, vals_len
);
8024 size_t value_len
= sizeof(value
);
8025 memset_rand(value
, value_len
);
8027 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
8028 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key2", "value2"));
8029 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
8030 ASSERT_STREQ(value
, "value1");
8032 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_get(ioctx
, "key1", value
, &value_len
));
8033 ASSERT_EQ(value_len
, strlen("value1") + 1);
8035 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8037 keys_len
= sizeof(keys
);
8038 vals_len
= sizeof(vals
);
8039 memset_rand(keys
, keys_len
);
8040 memset_rand(vals
, vals_len
);
8041 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8043 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
8044 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
8045 ASSERT_STREQ(keys
, "key1");
8046 ASSERT_STREQ(keys
+ strlen(keys
) + 1, "key2");
8047 ASSERT_STREQ(vals
, "value1");
8048 ASSERT_STREQ(vals
+ strlen(vals
) + 1, "value2");
8050 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
8051 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_remove(ioctx
, "key3"));
8052 value_len
= sizeof(value
);
8053 ASSERT_EQ(-ENOENT
, rbd_pool_metadata_get(ioctx
, "key3", value
, &value_len
));
8054 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8056 ASSERT_EQ(keys_len
, strlen("key2") + 1);
8057 ASSERT_EQ(vals_len
, strlen("value2") + 1);
8058 ASSERT_STREQ(keys
, "key2");
8059 ASSERT_STREQ(vals
, "value2");
8061 // test config setting
8062 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
8063 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8064 ASSERT_EQ(-EINVAL
, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
8065 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8067 // test short buffer cases
8068 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key1", "value1"));
8069 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key3", "value3"));
8070 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "key4", "value4"));
8072 keys_len
= strlen("key1") + 1;
8073 vals_len
= strlen("value1") + 1;
8074 memset_rand(keys
, keys_len
);
8075 memset_rand(vals
, vals_len
);
8076 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "", 1, keys
, &keys_len
, vals
,
8078 ASSERT_EQ(keys_len
, strlen("key1") + 1);
8079 ASSERT_EQ(vals_len
, strlen("value1") + 1);
8080 ASSERT_STREQ(keys
, "key1");
8081 ASSERT_STREQ(vals
, "value1");
8083 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 2, keys
, &keys_len
, vals
,
8085 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1);
8086 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1);
8088 ASSERT_EQ(-ERANGE
, rbd_pool_metadata_list(ioctx
, "", 0, keys
, &keys_len
, vals
,
8090 ASSERT_EQ(keys_len
, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
8091 1 + strlen("key4") + 1);
8092 ASSERT_EQ(vals_len
, strlen("value1") + 1 + strlen("value2") + 1 +
8093 strlen("value3") + 1 + strlen("value4") + 1);
8095 // test `start` param
8096 keys_len
= sizeof(keys
);
8097 vals_len
= sizeof(vals
);
8098 memset_rand(keys
, keys_len
);
8099 memset_rand(vals
, vals_len
);
8100 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx
, "key2", 0, keys
, &keys_len
, vals
,
8102 ASSERT_EQ(keys_len
, strlen("key3") + 1 + strlen("key4") + 1);
8103 ASSERT_EQ(vals_len
, strlen("value3") + 1 + strlen("value4") + 1);
8104 ASSERT_STREQ(keys
, "key3");
8105 ASSERT_STREQ(vals
, "value3");
8108 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key1"));
8109 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key2"));
8110 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key3"));
8111 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "key4"));
8112 rados_ioctx_destroy(ioctx
);
8115 TEST_F(TestLibRBD
, PoolMetadataPP
)
8117 REQUIRE_FORMAT_V2();
8121 map
<string
, bufferlist
> pairs
;
8123 librados::IoCtx ioctx
;
8124 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8126 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
8127 ASSERT_TRUE(pairs
.empty());
8129 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
8130 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key2", "value2"));
8131 ASSERT_EQ(0, rbd
.pool_metadata_get(ioctx
, "key1", &value
));
8132 ASSERT_EQ(value
, "value1");
8133 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
8134 ASSERT_EQ(2U, pairs
.size());
8135 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
8136 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
8138 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
8139 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_remove(ioctx
, "key3"));
8140 ASSERT_EQ(-ENOENT
, rbd
.pool_metadata_get(ioctx
, "key3", &value
));
8142 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "", 0, &pairs
));
8143 ASSERT_EQ(1U, pairs
.size());
8144 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
8146 // test `start` param
8147 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key1", "value1"));
8148 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "key3", "value3"));
8151 ASSERT_EQ(0, rbd
.pool_metadata_list(ioctx
, "key2", 0, &pairs
));
8152 ASSERT_EQ(1U, pairs
.size());
8153 ASSERT_EQ(0, strncmp("value3", pairs
["key3"].c_str(), 6));
8155 // test config setting
8156 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_UNKNOWN", "false"));
8157 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8158 ASSERT_EQ(-EINVAL
, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "INVALID"));
8159 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8162 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key1"));
8163 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key2"));
8164 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "key3"));
8167 TEST_F(TestLibRBD
, Config
)
8169 REQUIRE_FORMAT_V2();
8171 rados_ioctx_t ioctx
;
8172 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8174 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8176 rbd_config_option_t options
[1024];
8177 int max_options
= 0;
8178 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
8179 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
8180 ASSERT_GT(max_options
, 0);
8181 ASSERT_LT(max_options
, 1024);
8182 for (int i
= 0; i
< max_options
; i
++) {
8183 if (options
[i
].name
== std::string("rbd_cache")) {
8184 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
8185 ASSERT_STREQ("false", options
[i
].value
);
8187 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8190 rbd_config_pool_list_cleanup(options
, max_options
);
8194 std::string name
= get_temp_image_name();
8195 uint64_t size
= 2 << 20;
8197 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8198 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image
, NULL
));
8200 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
8201 for (int i
= 0; i
< max_options
; i
++) {
8202 if (options
[i
].name
== std::string("rbd_cache")) {
8203 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
8204 ASSERT_STREQ("false", options
[i
].value
);
8206 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8209 rbd_config_image_list_cleanup(options
, max_options
);
8211 ASSERT_EQ(0, rbd_metadata_set(image
, "conf_rbd_cache", "true"));
8213 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
8214 for (int i
= 0; i
< max_options
; i
++) {
8215 if (options
[i
].name
== std::string("rbd_cache")) {
8216 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_IMAGE
);
8217 ASSERT_STREQ("true", options
[i
].value
);
8219 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8222 rbd_config_image_list_cleanup(options
, max_options
);
8224 ASSERT_EQ(0, rbd_metadata_remove(image
, "conf_rbd_cache"));
8226 ASSERT_EQ(0, rbd_config_image_list(image
, options
, &max_options
));
8227 for (int i
= 0; i
< max_options
; i
++) {
8228 if (options
[i
].name
== std::string("rbd_cache")) {
8229 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_POOL
);
8230 ASSERT_STREQ("false", options
[i
].value
);
8232 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8235 rbd_config_image_list_cleanup(options
, max_options
);
8237 ASSERT_EQ(0, rbd_close(image
));
8239 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8241 ASSERT_EQ(-ERANGE
, rbd_config_pool_list(ioctx
, options
, &max_options
));
8242 ASSERT_EQ(0, rbd_config_pool_list(ioctx
, options
, &max_options
));
8243 for (int i
= 0; i
< max_options
; i
++) {
8244 ASSERT_EQ(options
[i
].source
, RBD_CONFIG_SOURCE_CONFIG
);
8246 rbd_config_pool_list_cleanup(options
, max_options
);
8248 rados_ioctx_destroy(ioctx
);
8251 TEST_F(TestLibRBD
, ConfigPP
)
8253 REQUIRE_FORMAT_V2();
8258 librados::IoCtx ioctx
;
8259 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8261 ASSERT_EQ(0, rbd
.pool_metadata_set(ioctx
, "conf_rbd_cache", "false"));
8263 std::vector
<librbd::config_option_t
> options
;
8264 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
8265 for (auto &option
: options
) {
8266 if (option
.name
== std::string("rbd_cache")) {
8267 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
8268 ASSERT_EQ("false", option
.value
);
8270 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8275 std::string name
= get_temp_image_name();
8276 uint64_t size
= 2 << 20;
8277 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8279 librbd::Image image
;
8280 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), nullptr));
8283 ASSERT_EQ(0, image
.config_list(&options
));
8284 for (auto &option
: options
) {
8285 if (option
.name
== std::string("rbd_cache")) {
8286 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
8287 ASSERT_EQ("false", option
.value
);
8289 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8293 ASSERT_EQ(0, image
.metadata_set("conf_rbd_cache", "true"));
8296 ASSERT_EQ(0, image
.config_list(&options
));
8297 for (auto &option
: options
) {
8298 if (option
.name
== std::string("rbd_cache")) {
8299 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_IMAGE
);
8300 ASSERT_EQ("true", option
.value
);
8302 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8306 ASSERT_EQ(0, image
.metadata_remove("conf_rbd_cache"));
8309 ASSERT_EQ(0, image
.config_list(&options
));
8310 for (auto &option
: options
) {
8311 if (option
.name
== std::string("rbd_cache")) {
8312 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_POOL
);
8313 ASSERT_EQ("false", option
.value
);
8315 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8319 ASSERT_EQ(0, rbd
.pool_metadata_remove(ioctx
, "conf_rbd_cache"));
8322 ASSERT_EQ(0, rbd
.config_list(ioctx
, &options
));
8323 for (auto &option
: options
) {
8324 ASSERT_EQ(option
.source
, RBD_CONFIG_SOURCE_CONFIG
);
8328 TEST_F(TestLibRBD
, PoolStatsPP
)
8330 REQUIRE_FORMAT_V2();
8332 librados::IoCtx ioctx
;
8333 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
8336 std::string image_name
;
8337 uint64_t size
= 2 << 20;
8338 uint64_t expected_size
= 0;
8339 for (size_t idx
= 0; idx
< 4; ++idx
) {
8340 image_name
= get_temp_image_name();
8343 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, image_name
.c_str(), size
, &order
));
8344 expected_size
+= size
;
8347 librbd::Image image
;
8348 ASSERT_EQ(0, rbd
.open(ioctx
, image
, image_name
.c_str(), NULL
));
8349 ASSERT_EQ(0, image
.snap_create("snap1"));
8350 ASSERT_EQ(0, image
.resize(0));
8351 ASSERT_EQ(0, image
.close());
8352 uint64_t expect_head_size
= (expected_size
- size
);
8354 uint64_t image_count
;
8355 uint64_t provisioned_bytes
;
8356 uint64_t max_provisioned_bytes
;
8357 uint64_t snap_count
;
8358 uint64_t trash_image_count
;
8359 uint64_t trash_provisioned_bytes
;
8360 uint64_t trash_max_provisioned_bytes
;
8361 uint64_t trash_snap_count
;
8363 librbd::PoolStats pool_stats1
;
8364 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGES
, &image_count
);
8365 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
,
8366 &provisioned_bytes
);
8367 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
8369 ASSERT_EQ(4U, image_count
);
8370 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
8372 pool_stats1
.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
,
8373 &max_provisioned_bytes
);
8374 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats1
));
8375 ASSERT_EQ(4U, image_count
);
8376 ASSERT_EQ(expect_head_size
, provisioned_bytes
);
8377 ASSERT_EQ(expected_size
, max_provisioned_bytes
);
8379 librbd::PoolStats pool_stats2
;
8380 pool_stats2
.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
, &snap_count
);
8381 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
8382 pool_stats2
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
8383 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats2
));
8384 ASSERT_EQ(1U, snap_count
);
8385 ASSERT_EQ(0U, trash_image_count
);
8386 ASSERT_EQ(0U, trash_snap_count
);
8388 ASSERT_EQ(0, rbd
.trash_move(ioctx
, image_name
.c_str(), 0));
8390 librbd::PoolStats pool_stats3
;
8391 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES
, &trash_image_count
);
8392 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
,
8393 &trash_provisioned_bytes
);
8394 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
,
8395 &trash_max_provisioned_bytes
);
8396 pool_stats3
.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
, &trash_snap_count
);
8397 ASSERT_EQ(0, rbd
.pool_stats_get(ioctx
, &pool_stats3
));
8398 ASSERT_EQ(1U, trash_image_count
);
8399 ASSERT_EQ(0U, trash_provisioned_bytes
);
8400 ASSERT_EQ(size
, trash_max_provisioned_bytes
);
8401 ASSERT_EQ(1U, trash_snap_count
);
8404 TEST_F(TestLibRBD
, ImageSpec
) {
8405 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8407 librados::IoCtx ioctx
;
8408 ASSERT_EQ(0, _rados
.ioctx_create(create_pool(true).c_str(), ioctx
));
8411 librbd::Image parent_image
;
8412 std::string name
= get_temp_image_name();
8417 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8418 ASSERT_EQ(0, rbd
.open(ioctx
, parent_image
, name
.c_str(), NULL
));
8420 std::string parent_id
;
8421 ASSERT_EQ(0, parent_image
.get_id(&parent_id
));
8424 ASSERT_EQ(0, parent_image
.features(&features
));
8426 ASSERT_EQ(0, parent_image
.snap_create("snap"));
8427 ASSERT_EQ(0, parent_image
.snap_protect("snap"));
8429 std::string clone_name
= this->get_temp_image_name();
8430 ASSERT_EQ(0, rbd
.clone(ioctx
, name
.c_str(), "snap", ioctx
, clone_name
.c_str(),
8433 librbd::Image clone_image
;
8434 ASSERT_EQ(0, rbd
.open(ioctx
, clone_image
, clone_name
.c_str(), NULL
));
8436 std::string clone_id
;
8437 ASSERT_EQ(0, clone_image
.get_id(&clone_id
));
8439 std::vector
<librbd::image_spec_t
> images
;
8440 ASSERT_EQ(0, rbd
.list2(ioctx
, &images
));
8442 std::vector
<librbd::image_spec_t
> expected_images
{
8443 {.id
= parent_id
, .name
= name
},
8444 {.id
= clone_id
, .name
= clone_name
}
8446 std::sort(expected_images
.begin(), expected_images
.end(),
8447 [](const librbd::image_spec_t
& lhs
, const librbd::image_spec_t
&rhs
) {
8448 return lhs
.name
< rhs
.name
;
8450 ASSERT_EQ(expected_images
, images
);
8452 librbd::linked_image_spec_t parent_image_spec
;
8453 librbd::snap_spec_t parent_snap_spec
;
8454 ASSERT_EQ(0, clone_image
.get_parent(&parent_image_spec
, &parent_snap_spec
));
8456 librbd::linked_image_spec_t expected_parent_image_spec
{
8457 .pool_id
= ioctx
.get_id(),
8458 .pool_name
= ioctx
.get_pool_name(),
8459 .pool_namespace
= ioctx
.get_namespace(),
8460 .image_id
= parent_id
,
8464 ASSERT_EQ(expected_parent_image_spec
, parent_image_spec
);
8465 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER
, parent_snap_spec
.namespace_type
);
8466 ASSERT_EQ("snap", parent_snap_spec
.name
);
8468 std::vector
<librbd::linked_image_spec_t
> children
;
8469 ASSERT_EQ(0, parent_image
.list_children3(&children
));
8471 std::vector
<librbd::linked_image_spec_t
> expected_children
{
8473 .pool_id
= ioctx
.get_id(),
8474 .pool_name
= ioctx
.get_pool_name(),
8475 .pool_namespace
= ioctx
.get_namespace(),
8476 .image_id
= clone_id
,
8477 .image_name
= clone_name
,
8481 ASSERT_EQ(expected_children
, children
);
8484 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
8485 ASSERT_EQ(expected_children
, children
);
8487 ASSERT_EQ(0, clone_image
.snap_create("snap"));
8488 ASSERT_EQ(0, clone_image
.snap_protect("snap"));
8490 auto grand_clone_name
= this->get_temp_image_name();
8491 ASSERT_EQ(0, rbd
.clone(ioctx
, clone_name
.c_str(), "snap", ioctx
,
8492 grand_clone_name
.c_str(), features
, &order
));
8493 librbd::Image grand_clone_image
;
8494 ASSERT_EQ(0, rbd
.open(ioctx
, grand_clone_image
, grand_clone_name
.c_str(),
8496 std::string grand_clone_id
;
8497 ASSERT_EQ(0, grand_clone_image
.get_id(&grand_clone_id
));
8500 ASSERT_EQ(0, parent_image
.list_children3(&children
));
8501 ASSERT_EQ(expected_children
, children
);
8504 ASSERT_EQ(0, parent_image
.list_descendants(&children
));
8505 expected_children
.push_back(
8507 .pool_id
= ioctx
.get_id(),
8508 .pool_name
= ioctx
.get_pool_name(),
8509 .pool_namespace
= ioctx
.get_namespace(),
8510 .image_id
= grand_clone_id
,
8511 .image_name
= grand_clone_name
,
8515 ASSERT_EQ(expected_children
, children
);
8518 void super_simple_write_cb_pp(librbd::completion_t cb
, void *arg
)
8522 TEST_F(TestLibRBD
, DISABLED_TestSeqWriteAIOPP
)
8524 librados::IoCtx ioctx
;
8525 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8529 librbd::Image image
;
8531 std::string name
= get_temp_image_name();
8532 uint64_t size
= 5 * (1 << order
);
8534 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8535 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8537 char test_data
[(TEST_IO_SIZE
+ 1) * 10];
8539 for (int i
= 0; i
< 10; i
++) {
8540 for (uint64_t j
= 0; j
< TEST_IO_SIZE
; j
++) {
8541 test_data
[(TEST_IO_SIZE
+ 1) * i
+ j
] = (char)(rand() % (126 - 33) + 33);
8543 test_data
[(TEST_IO_SIZE
+ 1) * i
+ TEST_IO_SIZE
] = '\0';
8546 struct timespec start_time
;
8547 clock_gettime(CLOCK_REALTIME
, &start_time
);
8549 std::list
<librbd::RBD::AioCompletion
*> comps
;
8550 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
8551 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
8552 ceph::bufferlist bl
;
8553 bl
.append(p
, strlen(p
));
8554 auto comp
= new librbd::RBD::AioCompletion(
8555 NULL
, (librbd::callback_t
) super_simple_write_cb_pp
);
8556 image
.aio_write(strlen(p
) * i
, strlen(p
), bl
, comp
);
8557 comps
.push_back(comp
);
8558 if (i
% 1000 == 0) {
8559 cout
<< i
<< " reqs sent" << std::endl
;
8561 for (auto comp
: comps
) {
8562 comp
->wait_for_complete();
8563 ASSERT_EQ(0, comp
->get_return_value());
8570 for (auto comp
: comps
) {
8571 comp
->wait_for_complete();
8572 ASSERT_EQ(0, comp
->get_return_value());
8574 if (i
% 1000 == 0) {
8575 std::cout
<< i
<< " reqs completed" << std::endl
;
8581 struct timespec end_time
;
8582 clock_gettime(CLOCK_REALTIME
, &end_time
);
8583 int duration
= end_time
.tv_sec
* 1000 + end_time
.tv_nsec
/ 1000000 -
8584 start_time
.tv_sec
* 1000 - start_time
.tv_nsec
/ 1000000;
8585 std::cout
<< "duration: " << duration
<< " msec" << std::endl
;
8587 for (uint64_t i
= 0; i
< size
/ TEST_IO_SIZE
; ++i
) {
8588 char *p
= test_data
+ (TEST_IO_SIZE
+ 1) * (i
% 10);
8589 ASSERT_PASSED(read_test_data
, image
, p
, strlen(p
) * i
, TEST_IO_SIZE
, 0);
8592 ASSERT_PASSED(validate_object_map
, image
);
8598 TEST_F(TestLibRBD
, SnapRemoveWithChildMissing
)
8600 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
8601 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "2"));
8602 BOOST_SCOPE_EXIT_ALL(&) {
8603 ASSERT_EQ(0, rados_conf_set(_cluster
, "rbd_default_clone_format", "auto"));
8607 rados_ioctx_t ioctx1
, ioctx2
;
8608 string pool_name1
= create_pool(true);
8609 rados_ioctx_create(_cluster
, pool_name1
.c_str(), &ioctx1
);
8610 ASSERT_EQ(0, rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx2
));
8614 rbd_image_t parent
, child1
, child2
, child3
;
8616 char child_id1
[4096];
8617 char child_id2
[4096];
8618 char child_id3
[4096];
8620 ASSERT_EQ(0, get_features(&old_format
, &features
));
8621 ASSERT_FALSE(old_format
);
8622 std::string parent_name
= get_temp_image_name();
8623 std::string child_name1
= get_temp_image_name();
8624 std::string child_name2
= get_temp_image_name();
8625 std::string child_name3
= get_temp_image_name();
8626 ASSERT_EQ(0, create_image_full(ioctx1
, parent_name
.c_str(), 4<<20, &order
,
8628 ASSERT_EQ(0, rbd_open(ioctx1
, parent_name
.c_str(), &parent
, NULL
));
8629 ASSERT_EQ(0, rbd_snap_create(parent
, "snap1"));
8630 ASSERT_EQ(0, rbd_snap_create(parent
, "snap2"));
8632 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap1",
8633 ioctx2
, child_name1
.c_str(), features
, &order
));
8634 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
8635 ioctx1
, child_name2
.c_str(), features
, &order
));
8636 ASSERT_EQ(0, clone_image(ioctx1
, parent
, parent_name
.c_str(), "snap2",
8637 ioctx2
, child_name3
.c_str(), features
, &order
));
8639 ASSERT_EQ(0, rbd_open(ioctx2
, child_name1
.c_str(), &child1
, NULL
));
8640 ASSERT_EQ(0, rbd_open(ioctx1
, child_name2
.c_str(), &child2
, NULL
));
8641 ASSERT_EQ(0, rbd_open(ioctx2
, child_name3
.c_str(), &child3
, NULL
));
8642 ASSERT_EQ(0, rbd_get_id(child1
, child_id1
, sizeof(child_id1
)));
8643 ASSERT_EQ(0, rbd_get_id(child2
, child_id2
, sizeof(child_id2
)));
8644 ASSERT_EQ(0, rbd_get_id(child3
, child_id3
, sizeof(child_id3
)));
8645 test_list_children2(parent
, 3,
8646 child_id1
, m_pool_name
.c_str(), child_name1
.c_str(), false,
8647 child_id2
, pool_name1
.c_str(), child_name2
.c_str(), false,
8648 child_id3
, m_pool_name
.c_str(), child_name3
.c_str(), false);
8650 size_t max_size
= 10;
8651 rbd_linked_image_spec_t children
[max_size
];
8652 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8653 ASSERT_EQ(3, static_cast<int>(max_size
));
8654 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8656 ASSERT_EQ(0, rbd_close(child1
));
8657 ASSERT_EQ(0, rbd_close(child2
));
8658 ASSERT_EQ(0, rbd_close(child3
));
8659 rados_ioctx_destroy(ioctx2
);
8660 ASSERT_EQ(0, rados_pool_delete(_cluster
, m_pool_name
.c_str()));
8661 _pool_names
.erase(std::remove(_pool_names
.begin(),
8662 _pool_names
.end(), m_pool_name
),
8664 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster
));
8666 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8667 ASSERT_EQ(3, static_cast<int>(max_size
));
8668 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8669 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap1"));
8670 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8671 ASSERT_EQ(2, static_cast<int>(max_size
));
8672 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8674 ASSERT_EQ(0, rbd_remove(ioctx1
, child_name2
.c_str()));
8675 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8676 ASSERT_EQ(1, static_cast<int>(max_size
));
8677 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8679 ASSERT_EQ(0, rbd_snap_remove(parent
, "snap2"));
8680 ASSERT_EQ(0, rbd_list_children3(parent
, children
, &max_size
));
8681 ASSERT_EQ(0, static_cast<int>(max_size
));
8682 rbd_linked_image_spec_list_cleanup(children
, max_size
);
8683 test_list_children2(parent
, 0);
8684 ASSERT_EQ(0, test_ls_snaps(parent
, 0));
8686 ASSERT_EQ(0, rbd_close(parent
));
8687 rados_ioctx_destroy(ioctx1
);
8690 TEST_F(TestLibRBD
, QuiesceWatch
)
8692 rados_ioctx_t ioctx
;
8693 rados_ioctx_create(_cluster
, m_pool_name
.c_str(), &ioctx
);
8696 std::string name
= get_temp_image_name();
8697 uint64_t size
= 2 << 20;
8698 ASSERT_EQ(0, create_image(ioctx
, name
.c_str(), size
, &order
));
8700 rbd_image_t image1
, image2
;
8701 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image1
, NULL
));
8702 ASSERT_EQ(0, rbd_open(ioctx
, name
.c_str(), &image2
, NULL
));
8705 static void quiesce_cb(void *arg
) {
8706 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
8707 watcher
->handle_quiesce();
8709 static void unquiesce_cb(void *arg
) {
8710 Watcher
*watcher
= static_cast<Watcher
*>(arg
);
8711 watcher
->handle_unquiesce();
8715 uint64_t handle
= 0;
8716 size_t quiesce_count
= 0;
8717 size_t unquiesce_count
= 0;
8719 ceph::mutex lock
= ceph::make_mutex("lock");
8720 ceph::condition_variable cv
;
8722 Watcher(rbd_image_t
&image
) : image(image
) {
8725 void handle_quiesce() {
8726 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8728 rbd_quiesce_complete(image
, handle
, 0);
8730 void handle_unquiesce() {
8731 std::unique_lock
locker(lock
);
8733 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8736 bool wait_for_unquiesce(size_t c
) {
8737 std::unique_lock
locker(lock
);
8738 return cv
.wait_for(locker
, seconds(60),
8739 [this, c
]() { return unquiesce_count
>= c
; });
8741 } watcher1(image1
), watcher2(image2
);
8743 ASSERT_EQ(0, rbd_quiesce_watch(image1
, Watcher::quiesce_cb
,
8744 Watcher::unquiesce_cb
, &watcher1
,
8746 ASSERT_EQ(0, rbd_quiesce_watch(image2
, Watcher::quiesce_cb
,
8747 Watcher::unquiesce_cb
, &watcher2
,
8750 ASSERT_EQ(0, rbd_snap_create(image1
, "snap1"));
8751 ASSERT_EQ(1U, watcher1
.quiesce_count
);
8752 ASSERT_TRUE(watcher1
.wait_for_unquiesce(1U));
8753 ASSERT_EQ(1U, watcher2
.quiesce_count
);
8754 ASSERT_TRUE(watcher2
.wait_for_unquiesce(1U));
8756 ASSERT_EQ(0, rbd_snap_create(image2
, "snap2"));
8757 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8758 ASSERT_TRUE(watcher1
.wait_for_unquiesce(2U));
8759 ASSERT_EQ(2U, watcher2
.quiesce_count
);
8760 ASSERT_TRUE(watcher2
.wait_for_unquiesce(2U));
8762 ASSERT_EQ(0, rbd_quiesce_unwatch(image1
, watcher1
.handle
));
8764 ASSERT_EQ(0, rbd_snap_create(image1
, "snap3"));
8765 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8766 ASSERT_EQ(2U, watcher1
.unquiesce_count
);
8767 ASSERT_EQ(3U, watcher2
.quiesce_count
);
8768 ASSERT_TRUE(watcher2
.wait_for_unquiesce(3U));
8770 ASSERT_EQ(0, rbd_quiesce_unwatch(image2
, watcher2
.handle
));
8772 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap1"));
8773 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap2"));
8774 ASSERT_EQ(0, rbd_snap_remove(image1
, "snap3"));
8775 ASSERT_EQ(0, rbd_close(image1
));
8776 ASSERT_EQ(0, rbd_close(image2
));
8777 ASSERT_EQ(0, rbd_remove(ioctx
, name
.c_str()));
8778 rados_ioctx_destroy(ioctx
);
8781 TEST_F(TestLibRBD
, QuiesceWatchPP
)
8784 librados::IoCtx ioctx
;
8785 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8786 std::string name
= get_temp_image_name();
8788 uint64_t size
= 2 << 20;
8789 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8792 librbd::Image image1
, image2
;
8793 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8794 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8796 struct Watcher
: public librbd::QuiesceWatchCtx
{
8797 librbd::Image
&image
;
8798 uint64_t handle
= 0;
8799 size_t quiesce_count
= 0;
8800 size_t unquiesce_count
= 0;
8802 ceph::mutex lock
= ceph::make_mutex("lock");
8803 ceph::condition_variable cv
;
8805 Watcher(librbd::Image
&image
) : image(image
) {
8808 void handle_quiesce() override
{
8809 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8811 image
.quiesce_complete(handle
, 0);
8813 void handle_unquiesce() override
{
8814 std::unique_lock
locker(lock
);
8816 ASSERT_EQ(quiesce_count
, unquiesce_count
);
8819 bool wait_for_unquiesce(size_t c
) {
8820 std::unique_lock
locker(lock
);
8821 return cv
.wait_for(locker
, seconds(60),
8822 [this, c
]() { return unquiesce_count
>= c
; });
8824 } watcher1(image1
), watcher2(image2
);
8826 ASSERT_EQ(0, image1
.quiesce_watch(&watcher1
, &watcher1
.handle
));
8827 ASSERT_EQ(0, image2
.quiesce_watch(&watcher2
, &watcher2
.handle
));
8829 ASSERT_EQ(0, image1
.snap_create("snap1"));
8830 ASSERT_EQ(1U, watcher1
.quiesce_count
);
8831 ASSERT_TRUE(watcher1
.wait_for_unquiesce(1U));
8832 ASSERT_EQ(1U, watcher2
.quiesce_count
);
8833 ASSERT_TRUE(watcher2
.wait_for_unquiesce(1U));
8835 ASSERT_EQ(0, image2
.snap_create("snap2"));
8836 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8837 ASSERT_TRUE(watcher1
.wait_for_unquiesce(2U));
8838 ASSERT_EQ(2U, watcher2
.quiesce_count
);
8839 ASSERT_TRUE(watcher2
.wait_for_unquiesce(2U));
8841 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher1
.handle
));
8843 ASSERT_EQ(0, image1
.snap_create("snap3"));
8844 ASSERT_EQ(2U, watcher1
.quiesce_count
);
8845 ASSERT_EQ(2U, watcher1
.unquiesce_count
);
8846 ASSERT_EQ(3U, watcher2
.quiesce_count
);
8847 ASSERT_TRUE(watcher2
.wait_for_unquiesce(3U));
8849 ASSERT_EQ(0, image2
.quiesce_unwatch(watcher2
.handle
));
8851 ASSERT_EQ(0, image1
.snap_remove("snap1"));
8852 ASSERT_EQ(0, image1
.snap_remove("snap2"));
8853 ASSERT_EQ(0, image1
.snap_remove("snap3"));
8856 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
8860 TEST_F(TestLibRBD
, QuiesceWatchError
)
8863 librados::IoCtx ioctx
;
8864 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8865 std::string name
= get_temp_image_name();
8867 uint64_t size
= 2 << 20;
8868 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8871 librbd::Image image1
, image2
;
8872 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
8873 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
8875 struct Watcher
: public librbd::QuiesceWatchCtx
{
8876 librbd::Image
&image
;
8879 size_t quiesce_count
= 0;
8880 size_t unquiesce_count
= 0;
8882 ceph::mutex lock
= ceph::make_mutex("lock");
8883 ceph::condition_variable cv
;
8885 Watcher(librbd::Image
&image
, int r
) : image(image
), r(r
) {
8888 void reset_counters() {
8890 unquiesce_count
= 0;
8893 void handle_quiesce() override
{
8895 image
.quiesce_complete(handle
, r
);
8898 void handle_unquiesce() override
{
8899 std::unique_lock
locker(lock
);
8904 bool wait_for_unquiesce() {
8905 std::unique_lock
locker(lock
);
8906 return cv
.wait_for(locker
, seconds(60),
8908 return quiesce_count
== unquiesce_count
;
8911 } watcher10(image1
, -EINVAL
), watcher11(image1
, 0), watcher20(image2
, 0);
8913 ASSERT_EQ(0, image1
.quiesce_watch(&watcher10
, &watcher10
.handle
));
8914 ASSERT_EQ(0, image1
.quiesce_watch(&watcher11
, &watcher11
.handle
));
8915 ASSERT_EQ(0, image2
.quiesce_watch(&watcher20
, &watcher20
.handle
));
8917 ASSERT_EQ(-EINVAL
, image1
.snap_create("snap1"));
8918 ASSERT_GT(watcher10
.quiesce_count
, 0U);
8919 ASSERT_EQ(watcher10
.unquiesce_count
, 0U);
8920 ASSERT_GT(watcher11
.quiesce_count
, 0U);
8921 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
8922 ASSERT_GT(watcher20
.quiesce_count
, 0U);
8923 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
8925 PrintProgress prog_ctx
;
8926 watcher10
.reset_counters();
8927 watcher11
.reset_counters();
8928 watcher20
.reset_counters();
8929 ASSERT_EQ(0, image2
.snap_create2("snap2",
8930 RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR
,
8932 ASSERT_GT(watcher10
.quiesce_count
, 0U);
8933 ASSERT_EQ(watcher10
.unquiesce_count
, 0U);
8934 ASSERT_GT(watcher11
.quiesce_count
, 0U);
8935 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
8936 ASSERT_GT(watcher20
.quiesce_count
, 0U);
8937 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
8939 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher10
.handle
));
8941 watcher11
.reset_counters();
8942 watcher20
.reset_counters();
8943 ASSERT_EQ(0, image1
.snap_create("snap3"));
8944 ASSERT_GT(watcher11
.quiesce_count
, 0U);
8945 ASSERT_TRUE(watcher11
.wait_for_unquiesce());
8946 ASSERT_GT(watcher20
.quiesce_count
, 0U);
8947 ASSERT_TRUE(watcher20
.wait_for_unquiesce());
8949 ASSERT_EQ(0, image1
.quiesce_unwatch(watcher11
.handle
));
8951 watcher20
.reset_counters();
8952 ASSERT_EQ(0, image2
.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE
,
8954 ASSERT_EQ(watcher20
.quiesce_count
, 0U);
8955 ASSERT_EQ(watcher20
.unquiesce_count
, 0U);
8957 ASSERT_EQ(0, image2
.quiesce_unwatch(watcher20
.handle
));
8959 ASSERT_EQ(0, image1
.snap_remove("snap2"));
8960 ASSERT_EQ(0, image1
.snap_remove("snap3"));
8961 ASSERT_EQ(0, image1
.snap_remove("snap4"));
8964 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
8968 TEST_F(TestLibRBD
, QuiesceWatchTimeout
)
8970 REQUIRE(!is_librados_test_stub(_rados
));
8972 ASSERT_EQ(0, _rados
.conf_set("rbd_quiesce_notification_attempts", "2"));
8975 librados::IoCtx ioctx
;
8976 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
8977 std::string name
= get_temp_image_name();
8979 uint64_t size
= 2 << 20;
8980 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
8983 librbd::Image image
;
8984 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
8986 struct Watcher
: public librbd::QuiesceWatchCtx
{
8987 librbd::Image
&image
;
8989 std::condition_variable m_cond
;
8990 size_t quiesce_count
= 0;
8991 size_t unquiesce_count
= 0;
8993 Watcher(librbd::Image
&image
) : image(image
) {
8996 void handle_quiesce() override
{
8997 std::lock_guard
<std::mutex
> locker(m_lock
);
8999 m_cond
.notify_one();
9002 void handle_unquiesce() override
{
9003 std::lock_guard
<std::mutex
> locker(m_lock
);
9005 m_cond
.notify_one();
9008 void wait_for_quiesce() {
9009 std::unique_lock
<std::mutex
> locker(m_lock
);
9010 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(60),
9012 return quiesce_count
>= 1;
9016 void wait_for_unquiesce() {
9017 std::unique_lock
<std::mutex
> locker(m_lock
);
9018 ASSERT_TRUE(m_cond
.wait_for(locker
, seconds(60),
9020 return quiesce_count
== unquiesce_count
;
9022 quiesce_count
= unquiesce_count
= 0;
9027 ASSERT_EQ(0, image
.quiesce_watch(&watcher
, &handle
));
9029 std::cerr
<< "test quiesce is not long enough to time out" << std::endl
;
9031 thread
quiesce1([&image
, &watcher
, handle
]() {
9032 watcher
.wait_for_quiesce();
9034 image
.quiesce_complete(handle
, 0);
9037 ASSERT_EQ(0, image
.snap_create("snap1"));
9039 ASSERT_GE(watcher
.quiesce_count
, 1U);
9040 watcher
.wait_for_unquiesce();
9042 std::cerr
<< "test quiesce is timed out" << std::endl
;
9044 bool timed_out
= false;
9045 thread
quiesce2([&image
, &watcher
, handle
, &timed_out
]() {
9046 watcher
.wait_for_quiesce();
9047 for (int i
= 0; !timed_out
&& i
< 60; i
++) {
9048 std::cerr
<< "waiting for timed out ... " << i
<< std::endl
;
9051 image
.quiesce_complete(handle
, 0);
9054 ASSERT_EQ(-ETIMEDOUT
, image
.snap_create("snap2"));
9057 ASSERT_GE(watcher
.quiesce_count
, 1U);
9058 watcher
.wait_for_unquiesce();
9060 thread
quiesce3([&image
, handle
, &watcher
]() {
9061 watcher
.wait_for_quiesce();
9062 image
.quiesce_complete(handle
, 0);
9065 std::cerr
<< "test retry succeeds" << std::endl
;
9067 ASSERT_EQ(0, image
.snap_create("snap2"));
9069 ASSERT_GE(watcher
.quiesce_count
, 1U);
9070 watcher
.wait_for_unquiesce();
9072 ASSERT_EQ(0, image
.snap_remove("snap1"));
9073 ASSERT_EQ(0, image
.snap_remove("snap2"));
9076 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
9080 TEST_F(TestLibRBD
, WriteZeroes
) {
9082 librados::IoCtx ioctx
;
9083 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9084 std::string name
= get_temp_image_name();
9086 uint64_t size
= 2 << 20;
9087 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9089 librbd::Image image
;
9090 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9092 // 1s from [0, 256) / length 256
9094 memset(data
, 1, sizeof(data
));
9096 bl
.append(data
, 256);
9097 ASSERT_EQ(256, image
.write(0, 256, bl
));
9099 interval_set
<uint64_t> diff
;
9100 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9101 iterate_cb
, (void *)&diff
));
9102 auto expected_diff
= interval_set
<uint64_t>{{{0, 256}}};
9103 ASSERT_EQ(expected_diff
, diff
);
9105 // writes zero passed the current end extents.
9106 // Now 1s from [0, 192) / length 192
9107 ASSERT_EQ(size
- 192,
9108 image
.write_zeroes(192, size
- 192, 0U, 0));
9110 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9111 iterate_cb
, (void *)&diff
));
9112 expected_diff
= interval_set
<uint64_t>{{{0, 192}}};
9113 ASSERT_EQ(expected_diff
, diff
);
9115 // zero an existing extent and truncate some off the end
9116 // Now 1s from [64, 192) / length 192
9117 ASSERT_EQ(64, image
.write_zeroes(0, 64, 0U, 0));
9120 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9121 iterate_cb
, (void *)&diff
));
9122 expected_diff
= interval_set
<uint64_t>{{{0, 192}}};
9123 ASSERT_EQ(expected_diff
, diff
);
9125 bufferlist expected_bl
;
9126 expected_bl
.append_zero(64);
9128 sub_bl
.substr_of(bl
, 0, 128);
9129 expected_bl
.claim_append(sub_bl
);
9130 expected_bl
.append_zero(size
- 192);
9133 EXPECT_EQ(size
, image
.read(0, size
, read_bl
));
9134 EXPECT_EQ(expected_bl
, read_bl
);
9136 ASSERT_EQ(0, image
.close());
9139 TEST_F(TestLibRBD
, WriteZeroesThickProvision
) {
9141 librados::IoCtx ioctx
;
9142 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9143 std::string name
= get_temp_image_name();
9145 uint64_t size
= 2 << 20;
9146 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9148 librbd::Image image
;
9149 ASSERT_EQ(0, rbd
.open(ioctx
, image
, name
.c_str(), NULL
));
9151 interval_set
<uint64_t> diff
;
9152 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9153 iterate_cb
, (void *)&diff
));
9154 auto expected_diff
= interval_set
<uint64_t>{{}};
9155 ASSERT_EQ(expected_diff
, diff
);
9157 // writes unaligned zeroes as a prepend
9158 ASSERT_EQ(128, image
.write_zeroes(
9159 0, 128, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9161 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9162 iterate_cb
, (void *)&diff
));
9163 expected_diff
= interval_set
<uint64_t>{{{0, 128}}};
9164 ASSERT_EQ(expected_diff
, diff
);
9166 ASSERT_EQ(512, image
.write_zeroes(
9167 384, 512, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9169 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9170 iterate_cb
, (void *)&diff
));
9171 expected_diff
= interval_set
<uint64_t>{{{0, 896}}};
9172 ASSERT_EQ(expected_diff
, diff
);
9174 // prepend with write-same
9175 ASSERT_EQ(640, image
.write_zeroes(
9176 896, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9178 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9179 iterate_cb
, (void *)&diff
));
9180 expected_diff
= interval_set
<uint64_t>{{{0, 1536}}};
9181 ASSERT_EQ(expected_diff
, diff
);
9183 // write-same with append
9184 ASSERT_EQ(640, image
.write_zeroes(
9185 1536, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9187 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9188 iterate_cb
, (void *)&diff
));
9189 expected_diff
= interval_set
<uint64_t>{{{0, 2176}}};
9190 ASSERT_EQ(expected_diff
, diff
);
9192 // prepend + write-same + append
9193 ASSERT_EQ(768, image
.write_zeroes(
9194 2176, 768, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9196 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9197 iterate_cb
, (void *)&diff
));
9198 expected_diff
= interval_set
<uint64_t>{{{0, 2944}}};
9201 ASSERT_EQ(1024, image
.write_zeroes(
9202 3072, 1024, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
, 0));
9204 ASSERT_EQ(0, image
.diff_iterate2(nullptr, 0, size
, false, false,
9205 iterate_cb
, (void *)&diff
));
9206 expected_diff
= interval_set
<uint64_t>{{{0, 4096}}};
9208 bufferlist expected_bl
;
9209 expected_bl
.append_zero(size
);
9212 EXPECT_EQ(size
, image
.read(0, size
, read_bl
));
9213 EXPECT_EQ(expected_bl
, read_bl
);
9215 ASSERT_EQ(0, image
.close());
9218 TEST_F(TestLibRBD
, ConcurentOperations
)
9220 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
9223 librados::IoCtx ioctx
;
9224 ASSERT_EQ(0, _rados
.ioctx_create(m_pool_name
.c_str(), ioctx
));
9225 std::string name
= get_temp_image_name();
9227 uint64_t size
= 2 << 20;
9228 ASSERT_EQ(0, create_image_pp(rbd
, ioctx
, name
.c_str(), size
, &order
));
9230 // Test creating/removing many snapshots simultaneously
9232 std::vector
<librbd::Image
> images(10);
9233 std::vector
<librbd::RBD::AioCompletion
*> comps
;
9235 for (auto &image
: images
) {
9236 auto comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
9237 ASSERT_EQ(0, rbd
.aio_open(ioctx
, image
, name
.c_str(), NULL
, comp
));
9238 comps
.push_back(comp
);
9241 for (auto &comp
: comps
) {
9242 ASSERT_EQ(0, comp
->wait_for_complete());
9243 ASSERT_EQ(1, comp
->is_complete());
9244 ASSERT_EQ(0, comp
->get_return_value());
9249 std::vector
<std::thread
> threads
;
9251 for (auto &image
: images
) {
9252 std::string snap_name
= "snap" + stringify(i
++);
9253 threads
.emplace_back([&image
, snap_name
]() {
9254 int r
= image
.snap_create(snap_name
.c_str());
9255 ceph_assert(r
== 0);
9259 for (auto &t
: threads
) {
9265 for (auto &image
: images
) {
9266 std::string snap_name
= "snap" + stringify(i
++);
9267 threads
.emplace_back([&image
, snap_name
](){
9268 int r
= image
.snap_remove(snap_name
.c_str());
9269 ceph_assert(r
== 0);
9273 for (auto &t
: threads
) {
9278 for (auto &image
: images
) {
9279 auto comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
9280 ASSERT_EQ(0, image
.aio_close(comp
));
9281 comps
.push_back(comp
);
9284 for (auto &comp
: comps
) {
9285 ASSERT_EQ(0, comp
->wait_for_complete());
9286 ASSERT_EQ(1, comp
->is_complete());
9287 ASSERT_EQ(0, comp
->get_return_value());
9294 librbd::Image image1
, image2
, image3
;
9295 ASSERT_EQ(0, rbd
.open(ioctx
, image1
, name
.c_str(), NULL
));
9296 ASSERT_EQ(0, rbd
.open(ioctx
, image2
, name
.c_str(), NULL
));
9297 ASSERT_EQ(0, rbd
.open(ioctx
, image3
, name
.c_str(), NULL
));
9299 ASSERT_EQ(0, image1
.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE
));
9301 struct Watcher
: public librbd::QuiesceWatchCtx
{
9304 ceph::mutex lock
= ceph::make_mutex("lock");
9305 ceph::condition_variable cv
;
9307 void handle_quiesce() override
{
9308 std::unique_lock
locker(lock
);
9313 void handle_unquiesce() override
{
9316 bool wait_for_quiesce(size_t c
) {
9317 std::unique_lock
locker(lock
);
9318 return cv
.wait_for(locker
, seconds(60),
9319 [this, c
]() { return count
>= c
; });
9323 ASSERT_EQ(0, image2
.quiesce_watch(&watcher
, &handle
));
9325 auto close1_comp
= new librbd::RBD::AioCompletion(NULL
, NULL
);
9327 std::thread
create_snap1([&image1
, close1_comp
]() {
9328 int r
= image1
.snap_create("snap1");
9329 ceph_assert(r
== 0);
9330 r
= image1
.aio_close(close1_comp
);
9331 ceph_assert(r
== 0);
9334 ASSERT_TRUE(watcher
.wait_for_quiesce(1));
9336 std::thread
create_snap2([&image2
]() {
9337 int r
= image2
.snap_create("snap2");
9338 ceph_assert(r
== 0);
9341 std::thread
create_snap3([&image3
]() {
9342 int r
= image3
.snap_create("snap3");
9343 ceph_assert(r
== 0);
9346 image2
.quiesce_complete(handle
, 0);
9347 create_snap1
.join();
9349 ASSERT_TRUE(watcher
.wait_for_quiesce(2));
9350 image2
.quiesce_complete(handle
, 0);
9352 ASSERT_TRUE(watcher
.wait_for_quiesce(3));
9353 image2
.quiesce_complete(handle
, 0);
9355 ASSERT_EQ(0, close1_comp
->wait_for_complete());
9356 ASSERT_EQ(1, close1_comp
->is_complete());
9357 ASSERT_EQ(0, close1_comp
->get_return_value());
9358 close1_comp
->release();
9360 create_snap2
.join();
9361 create_snap3
.join();
9363 ASSERT_EQ(0, image2
.quiesce_unwatch(handle
));
9364 ASSERT_EQ(0, image2
.snap_remove("snap1"));
9365 ASSERT_EQ(0, image2
.snap_remove("snap2"));
9366 ASSERT_EQ(0, image2
.snap_remove("snap3"));
9369 ASSERT_EQ(0, rbd
.remove(ioctx
, name
.c_str()));
9374 // poorman's ceph_assert()
9376 void __ceph_assert_fail(const char *assertion
, const char *file
, int line
,
9382 #pragma GCC diagnostic pop
9383 #pragma GCC diagnostic warning "-Wpragmas"