]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_librbd.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / test / librbd / test_librbd.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
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.
12 *
13 */
14
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"
c07f9fc5 21#include "include/err.h"
f67539c2
TL
22#include "common/ceph_mutex.h"
23#include "json_spirit/json_spirit.h"
7c673cae 24
7c673cae
FG
25#include "gtest/gtest.h"
26
7c673cae
FG
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <sys/types.h>
32#include <poll.h>
33#include <time.h>
34#include <unistd.h>
7c673cae 35#include <algorithm>
31f18b77
FG
36#include <chrono>
37#include <condition_variable>
38#include <iostream>
7c673cae
FG
39#include <sstream>
40#include <list>
41#include <set>
31f18b77 42#include <thread>
7c673cae
FG
43#include <vector>
44
45#include "test/librados/test.h"
11fdf7f2 46#include "test/librados/test_cxx.h"
7c673cae 47#include "test/librbd/test_support.h"
7c673cae
FG
48#include "common/event_socket.h"
49#include "include/interval_set.h"
50#include "include/stringify.h"
51
52#include <boost/assign/list_of.hpp>
53#include <boost/scope_exit.hpp>
54
55#ifdef HAVE_EVENTFD
56#include <sys/eventfd.h>
57#endif
58
11fdf7f2
TL
59#pragma GCC diagnostic ignored "-Wpragmas"
60#pragma GCC diagnostic push
61#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
62
7c673cae
FG
63using namespace std;
64
65using std::chrono::seconds;
66
67#define ASSERT_PASSED(x, args...) \
68 do { \
69 bool passed = false; \
70 x(args, &passed); \
71 ASSERT_TRUE(passed); \
72 } while(0)
73
74void register_test_librbd() {
75}
76
77static int get_features(bool *old_format, uint64_t *features)
78{
79 const char *c = getenv("RBD_FEATURES");
11fdf7f2 80 if (c && strlen(c) > 0) {
7c673cae
FG
81 stringstream ss;
82 ss << c;
83 ss >> *features;
84 if (ss.fail())
85 return -EINVAL;
86 *old_format = false;
87 cout << "using new format!" << std::endl;
88 } else {
89 *old_format = true;
90 *features = 0;
91 cout << "using old format" << std::endl;
92 }
93
94 return 0;
95}
96
97static int create_image_full(rados_ioctx_t ioctx, const char *name,
98 uint64_t size, int *order, int old_format,
99 uint64_t features)
100{
101 if (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");
105 if (r < 0) {
106 return r;
107 }
108 return rbd_create(ioctx, name, size, order);
109 } else if ((features & RBD_FEATURE_STRIPINGV2) != 0) {
110 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
111 if (*order) {
112 // use a conservative stripe_unit for non default order
113 stripe_unit = (1ull << (*order-1));
114 }
115
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);
121 } else {
122 return rbd_create2(ioctx, name, size, features, order);
123 }
124}
125
126static 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)
130{
131 uint64_t stripe_unit, stripe_count;
132
133 int r;
134 r = rbd_get_stripe_unit(p_image, &stripe_unit);
135 if (r != 0) {
136 return r;
137 }
138
139 r = rbd_get_stripe_count(p_image, &stripe_count);
140 if (r != 0) {
141 return r;
142 }
143
144 return rbd_clone2(p_ioctx, p_name, p_snap_name, c_ioctx,
145 c_name, features, c_order, stripe_unit, stripe_count);
146}
147
148
149static int create_image(rados_ioctx_t ioctx, const char *name,
150 uint64_t size, int *order)
151{
152 bool old_format;
153 uint64_t features;
154
155 int r = get_features(&old_format, &features);
156 if (r < 0)
157 return r;
158 return create_image_full(ioctx, name, size, order, old_format, features);
159}
160
161static int create_image_pp(librbd::RBD &rbd,
162 librados::IoCtx &ioctx,
163 const char *name,
164 uint64_t size, int *order) {
165 bool old_format;
166 uint64_t features;
167 int r = get_features(&old_format, &features);
168 if (r < 0)
169 return r;
170 if (old_format) {
171 librados::Rados rados(ioctx);
172 int r = rados.conf_set("rbd_default_format", "1");
173 if (r < 0) {
174 return r;
175 }
176 return rbd.create(ioctx, name, size, order);
177 } else {
178 return rbd.create2(ioctx, name, size, features, order);
179 }
180}
181
f67539c2
TL
182
183
184void simple_write_cb(rbd_completion_t cb, void *arg)
185{
186 printf("write completion cb called!\n");
187}
188
189void simple_read_cb(rbd_completion_t cb, void *arg)
190{
191 printf("read completion cb called!\n");
192}
193
194void 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)
196{
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");
202 if (iohint)
203 rbd_aio_write2(image, off, len, test_data, comp, iohint);
204 else
205 rbd_aio_write(image, off, len, test_data, comp);
206
207 struct pollfd pfd;
208 pfd.fd = fd;
209 pfd.events = POLLIN;
210
211 ASSERT_EQ(1, poll(&pfd, 1, -1));
212 ASSERT_TRUE(pfd.revents & POLLIN);
213
214 rbd_completion_t comps[1];
215 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
216 uint64_t count;
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);
223 ASSERT_EQ(0, r);
224 printf("finished write\n");
225 rbd_aio_release(comps[0]);
226 *passed = true;
227}
228
229void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
230{
231 rbd_completion_t comp;
232 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
233 printf("created completion\n");
234 if (iohint)
235 rbd_aio_write2(image, off, len, test_data, comp, iohint);
236 else
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);
242 ASSERT_EQ(0, r);
243 printf("finished write\n");
244 rbd_aio_release(comp);
245 *passed = true;
246}
247
248void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
249{
250 ssize_t written;
251 if (iohint)
252 written = rbd_write2(image, off, len, test_data, iohint);
253 else
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));
257 *passed = true;
258}
259
260void aio_discard_test_data(rbd_image_t image, uint64_t off, uint64_t len, bool *passed)
261{
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);
267 ASSERT_EQ(0, r);
268 printf("aio discard: %d~%d = %d\n", (int)off, (int)len, (int)r);
269 rbd_aio_release(comp);
270 *passed = true;
271}
272
273void discard_test_data(rbd_image_t image, uint64_t off, size_t len, bool *passed)
274{
275 ssize_t written;
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));
279 *passed = true;
280}
281
282void 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)
284{
285 rbd_completion_t comp;
286 char *result = (char *)malloc(len + 1);
287
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");
292 if (iohint)
293 rbd_aio_read2(image, off, len, result, comp, iohint);
294 else
295 rbd_aio_read(image, off, len, result, comp);
296
297 struct pollfd pfd;
298 pfd.fd = fd;
299 pfd.events = POLLIN;
300
301 ASSERT_EQ(1, poll(&pfd, 1, -1));
302 ASSERT_TRUE(pfd.revents & POLLIN);
303
304 rbd_completion_t comps[1];
305 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
306 uint64_t count;
307 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
308 read(fd, &count, sizeof(count)));
309
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));
318 }
319 free(result);
320 *passed = true;
321}
322
323void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
324{
325 rbd_completion_t comp;
326 char *result = (char *)malloc(len + 1);
327
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");
331 if (iohint)
332 rbd_aio_read2(image, off, len, result, comp, iohint);
333 else
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));
344 }
345 free(result);
346 *passed = true;
347}
348
349void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
350{
351 ssize_t read;
352 char *result = (char *)malloc(len + 1);
353
354 ASSERT_NE(static_cast<char *>(NULL), result);
355 if (iohint)
356 read = rbd_read2(image, off, len, result, iohint);
357 else
358 read = rbd_read(image, off, len, result);
359 printf("read: %d\n", (int) read);
360 ASSERT_EQ(len, static_cast<size_t>(read));
361 result[len] = '\0';
362 if (memcmp(result, expected, len)) {
363 printf("read: %s\nexpected: %s\n", result, expected);
364 ASSERT_EQ(0, memcmp(result, expected, len));
365 }
366 free(result);
367 *passed = true;
368}
369
370void 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)
372{
373 rbd_completion_t comp;
374 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
375 printf("created completion\n");
376 int r;
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);
383 *passed = true;
384 return;
385 }
386
387 rbd_aio_wait_for_complete(comp);
388 r = rbd_aio_get_return_value(comp);
389 printf("return value is: %d\n", r);
390 ASSERT_EQ(0, r);
391 printf("finished writesame\n");
392 rbd_aio_release(comp);
393
394 //verify data
395 printf("to verify the data\n");
396 ssize_t read;
397 char *result = (char *)malloc(data_len+ 1);
398 ASSERT_NE(static_cast<char *>(NULL), result);
399 uint64_t left = len;
400 while (left > 0) {
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));
408 }
409 off += data_len;
410 left -= data_len;
411 }
412 ASSERT_EQ(0U, left);
413 free(result);
414 printf("verified\n");
415
416 *passed = true;
417}
418
419void 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)
421{
422 ssize_t written;
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");
427 *passed = true;
428 return;
429 }
430 ASSERT_EQ(len, static_cast<size_t>(written));
431 printf("wrote: %d\n", (int) written);
432
433 //verify data
434 printf("to verify the data\n");
435 ssize_t read;
436 char *result = (char *)malloc(data_len+ 1);
437 ASSERT_NE(static_cast<char *>(NULL), result);
438 uint64_t left = len;
439 while (left > 0) {
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));
447 }
448 off += data_len;
449 left -= data_len;
450 }
451 ASSERT_EQ(0U, left);
452 free(result);
453 printf("verified\n");
454
455 *passed = true;
456}
457
458void 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)
461{
462 rbd_completion_t comp;
463 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
464 printf("created completion\n");
465
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);
472 ASSERT_EQ(0, r);
473 printf("finished aio compare and write\n");
474 rbd_aio_release(comp);
475 *passed = true;
476}
477
478void 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)
481{
482 printf("start compare and write\n");
483 ssize_t written;
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));
487 *passed = true;
488}
489
7c673cae
FG
490class TestLibRBD : public ::testing::Test {
491public:
492
493 TestLibRBD() : m_pool_number() {
494 }
495
496 static void SetUpTestCase() {
7c673cae
FG
497 _pool_names.clear();
498 _unique_pool_names.clear();
499 _image_number = 0;
500 ASSERT_EQ("", connect_cluster(&_cluster));
501 ASSERT_EQ("", connect_cluster_pp(_rados));
502
503 create_optional_data_pool();
504 }
505
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(),
f67539c2 510 _unique_pool_names.end());
7c673cae
FG
511 for (size_t i = 1; i < _pool_names.size(); ++i) {
512 ASSERT_EQ(0, _rados.pool_delete(_pool_names[i].c_str()));
513 }
514 if (!_pool_names.empty()) {
515 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names[0], _rados));
516 }
517 }
518
519 void SetUp() override {
520 ASSERT_NE("", m_pool_name = create_pool());
521 }
522
523 bool is_skip_partial_discard_enabled() {
524 std::string value;
525 EXPECT_EQ(0, _rados.conf_get("rbd_skip_partial_discard", value));
526 return value == "true";
527 }
528
f67539c2
TL
529 bool is_skip_partial_discard_enabled(rbd_image_t image) {
530 if (is_skip_partial_discard_enabled()) {
531 rbd_flush(image);
532 uint64_t features;
533 EXPECT_EQ(0, rbd_get_features(image, &features));
534 return !(features & RBD_FEATURE_DIRTY_CACHE);
535 }
536 return false;
537 }
538
539 bool is_skip_partial_discard_enabled(librbd::Image& image) {
540 if (is_skip_partial_discard_enabled()) {
541 image.flush();
542 uint64_t features;
543 EXPECT_EQ(0, image.features(&features));
544 return !(features & RBD_FEATURE_DIRTY_CACHE);
545 }
546 return false;
547 }
548
7c673cae
FG
549 void validate_object_map(rbd_image_t image, bool *passed) {
550 uint64_t flags;
551 ASSERT_EQ(0, rbd_get_flags(image, &flags));
552 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
553 }
554
555 void validate_object_map(librbd::Image &image, bool *passed) {
556 uint64_t flags;
557 ASSERT_EQ(0, image.get_flags(&flags));
558 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
559 }
560
11fdf7f2 561 static std::string get_temp_image_name() {
7c673cae
FG
562 ++_image_number;
563 return "image" + stringify(_image_number);
564 }
565
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());
572 if (created) {
573 _unique_pool_names.push_back(data_pool);
574 }
575 }
576 }
577
578 std::string create_pool(bool unique = false) {
579 librados::Rados rados;
580 std::string pool_name;
581 if (unique) {
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];
587 } else {
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);
591 }
592 ++m_pool_number;
593 return pool_name;
594 }
595
f67539c2
TL
596 void test_io(rbd_image_t image) {
597 bool skip_discard = is_skip_partial_discard_enabled(image);
598
599 char test_data[TEST_IO_SIZE + 1];
600 char zero_data[TEST_IO_SIZE + 1];
601 char mismatch_data[TEST_IO_SIZE + 1];
602 int i;
603 uint64_t mismatch_offset;
604
605 for (i = 0; i < TEST_IO_SIZE; ++i) {
606 test_data[i] = (char) (rand() % (126 - 33) + 33);
607 }
608 test_data[TEST_IO_SIZE] = '\0';
609 memset(zero_data, 0, sizeof(zero_data));
610 memset(mismatch_data, 9, sizeof(mismatch_data));
611
612 for (i = 0; i < 5; ++i)
613 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
614 TEST_IO_SIZE, 0);
615
616 for (i = 5; i < 10; ++i)
617 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
618 TEST_IO_SIZE, 0);
619
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);
623
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);
627
628 for (i = 0; i < 5; ++i)
629 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i,
630 TEST_IO_SIZE, 0);
631
632 for (i = 5; i < 10; ++i)
633 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
634 TEST_IO_SIZE, 0);
635
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);
639
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,
644 TEST_IO_SIZE, 0);
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,
648 TEST_IO_SIZE, 0);
649
650 for (i = 0; i < 15; ++i) {
651 if (i % 3 == 2) {
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);
661 } else {
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);
666 }
667 }
668 for (i = 0; i < 15; ++i) {
669 if (i % 3 == 2) {
670 ASSERT_PASSED(aio_writesame_test_data, image, test_data,
671 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE,
672 0);
673 ASSERT_PASSED(aio_writesame_test_data, image, zero_data,
674 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE,
675 0);
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);
681 } else {
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);
686 }
687 }
688
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));
699
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);
705
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);
711
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);
723
724 ASSERT_PASSED(validate_object_map, image);
725 }
726
7c673cae
FG
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;
732
733 std::string m_pool_name;
734 uint32_t m_pool_number;
735
736};
737
738std::vector<std::string> TestLibRBD::_pool_names;
739std::vector<std::string> TestLibRBD::_unique_pool_names;
740rados_t TestLibRBD::_cluster;
741librados::Rados TestLibRBD::_rados;
742uint64_t TestLibRBD::_image_number = 0;
743
744TEST_F(TestLibRBD, CreateAndStat)
745{
746 rados_ioctx_t ioctx;
747 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
748
749 rbd_image_info_t info;
750 rbd_image_t image;
751 int order = 0;
752 std::string name = get_temp_image_name();
753 uint64_t size = 2 << 20;
754
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));
762
763 rados_ioctx_destroy(ioctx);
764}
765
766TEST_F(TestLibRBD, CreateWithSameDataPool)
767{
768 REQUIRE_FORMAT_V2();
769
770 rados_ioctx_t ioctx;
771 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
772
773 rbd_image_t image;
774 std::string name = get_temp_image_name();
775 uint64_t size = 2 << 20;
776
777 bool old_format;
778 uint64_t features;
779 ASSERT_EQ(0, get_features(&old_format, &features));
780 ASSERT_FALSE(old_format);
781
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;
787
788 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
789 RBD_IMAGE_OPTION_FEATURES,
790 features));
791 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
792 RBD_IMAGE_OPTION_DATA_POOL,
793 m_pool_name.c_str()));
794
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));
797
798 ASSERT_EQ(0, rbd_close(image));
799
800 rados_ioctx_destroy(ioctx);
801}
802
803TEST_F(TestLibRBD, CreateAndStatPP)
804{
805 librados::IoCtx ioctx;
806 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
807
808 {
809 librbd::RBD rbd;
810 librbd::image_info_t info;
811 librbd::Image image;
812 int order = 0;
813 std::string name = get_temp_image_name();
814 uint64_t size = 2 << 20;
815
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);
821 }
822
823 ioctx.close();
824}
825
826TEST_F(TestLibRBD, GetId)
827{
828 rados_ioctx_t ioctx;
829 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
830
831 rbd_image_t image;
832 int order = 0;
833 std::string name = get_temp_image_name();
834
835 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
836 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
837
838 char id[4096];
839 if (!is_feature_enabled(0)) {
840 // V1 image
841 ASSERT_EQ(-EINVAL, rbd_get_id(image, id, sizeof(id)));
842 } else {
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));
11fdf7f2
TL
846
847 ASSERT_EQ(0, rbd_close(image));
848 ASSERT_EQ(0, rbd_open_by_id(ioctx, id, &image, NULL));
849 size_t name_len = 0;
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);
7c673cae
FG
855 }
856
857 ASSERT_EQ(0, rbd_close(image));
858 rados_ioctx_destroy(ioctx);
859}
860
861TEST_F(TestLibRBD, GetIdPP)
862{
863 librados::IoCtx ioctx;
864 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
865
866 librbd::RBD rbd;
867 librbd::Image image;
868 int order = 0;
869 std::string name = get_temp_image_name();
870
871 std::string id;
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)) {
875 // V1 image
876 ASSERT_EQ(-EINVAL, image.get_id(&id));
877 } else {
878 ASSERT_EQ(0, image.get_id(&id));
879 ASSERT_LT(0U, id.size());
11fdf7f2
TL
880
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);
7c673cae
FG
886 }
887}
888
889TEST_F(TestLibRBD, GetBlockNamePrefix)
890{
891 rados_ioctx_t ioctx;
892 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
893
894 rbd_image_t image;
895 int order = 0;
896 std::string name = get_temp_image_name();
897
898 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
899 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
900
901 char prefix[4096];
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));
905
906 ASSERT_EQ(0, rbd_close(image));
907 rados_ioctx_destroy(ioctx);
908}
909
910TEST_F(TestLibRBD, GetBlockNamePrefixPP)
911{
912 librados::IoCtx ioctx;
913 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
914
915 librbd::RBD rbd;
916 librbd::Image image;
917 int order = 0;
918 std::string name = get_temp_image_name();
919
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());
923}
924
31f18b77
FG
925TEST_F(TestLibRBD, TestGetCreateTimestamp)
926{
927 REQUIRE_FORMAT_V2();
928
929 rados_ioctx_t ioctx;
930 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
931
932 rbd_image_t image;
933 int order = 0;
934 std::string name = get_temp_image_name();
935
936 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
937 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
938
939 struct timespec timestamp;
940 ASSERT_EQ(0, rbd_get_create_timestamp(image, &timestamp));
941 ASSERT_LT(0, timestamp.tv_sec);
942
943 ASSERT_EQ(0, rbd_close(image));
944
945 rados_ioctx_destroy(ioctx);
946}
947
948TEST_F(TestLibRBD, GetCreateTimestampPP)
949{
950 REQUIRE_FORMAT_V2();
951
952 librados::IoCtx ioctx;
953 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
954
955 librbd::RBD rbd;
956 librbd::Image image;
957 int order = 0;
958 std::string name = get_temp_image_name();
959
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));
962
963 struct timespec timestamp;
964 ASSERT_EQ(0, image.get_create_timestamp(&timestamp));
965 ASSERT_LT(0, timestamp.tv_sec);
966}
967
7c673cae
FG
968TEST_F(TestLibRBD, OpenAio)
969{
970 rados_ioctx_t ioctx;
971 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
972
973 rbd_image_info_t info;
974 rbd_image_t image;
975 int order = 0;
976 std::string name = get_temp_image_name();
977 uint64_t size = 2 << 20;
978
979 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
980
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);
988
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);
993
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);
1001
1002 rados_ioctx_destroy(ioctx);
1003}
1004
1005TEST_F(TestLibRBD, OpenAioFail)
1006{
1007 rados_ioctx_t ioctx;
1008 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
1009
1010 std::string name = get_temp_image_name();
1011 rbd_image_t image;
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);
1019
1020 rados_ioctx_destroy(ioctx);
1021}
1022
1023TEST_F(TestLibRBD, OpenAioPP)
1024{
1025 librados::IoCtx ioctx;
1026 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1027
1028 librbd::RBD rbd;
1029 librbd::image_info_t info;
1030 librbd::Image image;
1031 int order = 0;
1032 std::string name = get_temp_image_name();
1033 uint64_t size = 2 << 20;
1034
1035 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1036
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();
1044
1045 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1046 ASSERT_EQ(info.size, size);
1047 ASSERT_EQ(info.order, order);
1048
1049 // reopen
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();
1056
1057 // close
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();
1065
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();
1070
1071 ioctx.close();
1072}
1073
1074TEST_F(TestLibRBD, OpenAioFailPP)
1075{
1076 librados::IoCtx ioctx;
1077 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1078
1079 {
1080 librbd::RBD rbd;
1081 librbd::Image image;
1082 std::string name = get_temp_image_name();
1083
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();
1091 }
1092
1093 ioctx.close();
1094}
1095
1096TEST_F(TestLibRBD, ResizeAndStat)
1097{
1098 rados_ioctx_t ioctx;
1099 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1100
1101 rbd_image_info_t info;
1102 rbd_image_t image;
1103 int order = 0;
1104 std::string name = get_temp_image_name();
1105 uint64_t size = 2 << 20;
1106
1107 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1108 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1109
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);
1113
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);
1117
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);
1123
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);
1127
1128 ASSERT_PASSED(validate_object_map, image);
1129 ASSERT_EQ(0, rbd_close(image));
1130
1131 rados_ioctx_destroy(ioctx);
1132}
1133
1134TEST_F(TestLibRBD, ResizeAndStatPP)
1135{
1136 librados::IoCtx ioctx;
1137 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1138
1139 {
1140 librbd::RBD rbd;
1141 librbd::image_info_t info;
1142 librbd::Image image;
1143 int order = 0;
1144 std::string name = get_temp_image_name();
1145 uint64_t size = 2 << 20;
1146
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));
1149
1150 ASSERT_EQ(0, image.resize(size * 4));
1151 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1152 ASSERT_EQ(info.size, size * 4);
1153
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);
1158 }
1159
1160 ioctx.close();
1161}
1162
1163TEST_F(TestLibRBD, UpdateWatchAndResize)
1164{
1165 rados_ioctx_t ioctx;
1166 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1167
1168 rbd_image_t image;
1169 int order = 0;
1170 std::string name = get_temp_image_name();
1171 uint64_t size = 2 << 20;
1172 struct Watcher {
31f18b77 1173 rbd_image_t &m_image;
f67539c2
TL
1174 std::mutex m_lock;
1175 std::condition_variable m_cond;
31f18b77 1176 size_t m_size = 0;
7c673cae
FG
1177 static void cb(void *arg) {
1178 Watcher *watcher = static_cast<Watcher *>(arg);
1179 watcher->handle_notify();
1180 }
11fdf7f2 1181 explicit Watcher(rbd_image_t &image) : m_image(image) {}
7c673cae
FG
1182 void handle_notify() {
1183 rbd_image_info_t info;
1184 ASSERT_EQ(0, rbd_stat(m_image, &info, sizeof(info)));
f67539c2 1185 std::lock_guard<std::mutex> locker(m_lock);
7c673cae 1186 m_size = info.size;
31f18b77 1187 m_cond.notify_one();
7c673cae
FG
1188 }
1189 void wait_for_size(size_t size) {
f67539c2 1190 std::unique_lock<std::mutex> locker(m_lock);
31f18b77
FG
1191 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
1192 [size, this] {
1193 return this->m_size == size;}));
7c673cae 1194 }
7c673cae
FG
1195 } watcher(image);
1196 uint64_t handle;
1197
1198 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1199 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1200
1201 ASSERT_EQ(0, rbd_update_watch(image, &handle, Watcher::cb, &watcher));
1202
1203 ASSERT_EQ(0, rbd_resize(image, size * 4));
1204 watcher.wait_for_size(size * 4);
1205
1206 ASSERT_EQ(0, rbd_resize(image, size / 2));
1207 watcher.wait_for_size(size / 2);
1208
1209 ASSERT_EQ(0, rbd_update_unwatch(image, handle));
1210
1211 ASSERT_EQ(0, rbd_close(image));
1212 rados_ioctx_destroy(ioctx);
1213}
1214
1215TEST_F(TestLibRBD, UpdateWatchAndResizePP)
1216{
1217 librados::IoCtx ioctx;
1218 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1219
1220 {
1221 librbd::RBD rbd;
1222 librbd::Image image;
1223 int order = 0;
1224 std::string name = get_temp_image_name();
1225 uint64_t size = 2 << 20;
1226 struct Watcher : public librbd::UpdateWatchCtx {
11fdf7f2 1227 explicit Watcher(librbd::Image &image) : m_image(image) {
7c673cae
FG
1228 }
1229 void handle_notify() override {
1230 librbd::image_info_t info;
1231 ASSERT_EQ(0, m_image.stat(info, sizeof(info)));
f67539c2 1232 std::lock_guard<std::mutex> locker(m_lock);
7c673cae 1233 m_size = info.size;
31f18b77 1234 m_cond.notify_one();
7c673cae
FG
1235 }
1236 void wait_for_size(size_t size) {
f67539c2 1237 std::unique_lock<std::mutex> locker(m_lock);
31f18b77
FG
1238 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
1239 [size, this] {
1240 return this->m_size == size;}));
7c673cae
FG
1241 }
1242 librbd::Image &m_image;
f67539c2
TL
1243 std::mutex m_lock;
1244 std::condition_variable m_cond;
7c673cae
FG
1245 size_t m_size = 0;
1246 } watcher(image);
1247 uint64_t handle;
1248
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));
1251
1252 ASSERT_EQ(0, image.update_watch(&watcher, &handle));
1253
1254 ASSERT_EQ(0, image.resize(size * 4));
1255 watcher.wait_for_size(size * 4);
1256
1257 ASSERT_EQ(0, image.resize(size / 2));
1258 watcher.wait_for_size(size / 2);
1259
1260 ASSERT_EQ(0, image.update_unwatch(handle));
1261 }
1262
1263 ioctx.close();
1264}
1265
1266int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
1267{
1268 int num_images, i;
1269 char *names, *cur_name;
1270 va_list ap;
1271 size_t max_size = 1024;
1272
1273 names = (char *) malloc(sizeof(char) * 1024);
1274 int len = rbd_list(io_ctx, names, &max_size);
1275
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;
1281 num_images++;
1282 }
1283 free(names);
1284
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);
1294 } else {
1295 ADD_FAILURE() << "Unable to find image " << expected;
1296 va_end(ap);
1297 return -ENOENT;
1298 }
1299 }
1300 va_end(ap);
1301
1302 if (!image_names.empty()) {
1303 ADD_FAILURE() << "Unexpected images discovered";
1304 return -EINVAL;
1305 }
1306 return num_images;
1307}
1308
1309TEST_F(TestLibRBD, TestCreateLsDelete)
1310{
1311 rados_ioctx_t ioctx;
1312 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
1313
1314 int order = 0;
1315 std::string name = get_temp_image_name();
1316 std::string name2 = get_temp_image_name();
1317 uint64_t size = 2 << 20;
11fdf7f2
TL
1318
1319 ASSERT_EQ(0, test_ls(ioctx, 0));
7c673cae
FG
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()));
1326
1327 ASSERT_EQ(-ENOENT, rbd_remove(ioctx, name.c_str()));
1328
1329 rados_ioctx_destroy(ioctx);
1330}
1331
1332int test_ls_pp(librbd::RBD& rbd, librados::IoCtx& io_ctx, size_t num_expected, ...)
1333{
1334 int r;
1335 size_t i;
1336 va_list ap;
1337 vector<string> names;
1338 r = rbd.list(io_ctx, names);
1339 if (r == -ENOENT)
1340 r = 0;
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();
1345
1346 for (i = 0; i < names.size(); i++) {
1347 cout << "image: " << names[i] << std::endl;
1348 }
1349
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;
1357 va_end(ap);
1358 return -ENOENT;
1359 }
1360 names.erase(listed_name);
1361 }
f67539c2 1362 va_end(ap);
7c673cae 1363
f67539c2
TL
1364 if (!names.empty()) {
1365 ADD_FAILURE() << "Unexpected images discovered";
1366 return -EINVAL;
7c673cae 1367 }
f67539c2
TL
1368 return num;
1369}
7c673cae 1370
f67539c2 1371TEST_F(TestLibRBD, TestCreateLsDeletePP)
7c673cae
FG
1372{
1373 librados::IoCtx ioctx;
1374 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
1375
1376 {
1377 librbd::RBD rbd;
1378 librbd::Image image;
1379 int order = 0;
1380 std::string name = get_temp_image_name();
1381 std::string name2 = get_temp_image_name();
7c673cae 1382 uint64_t size = 2 << 20;
7c673cae
FG
1383
1384 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7c673cae 1385 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
f67539c2 1386 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
7c673cae 1387 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
f67539c2
TL
1388 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
1389 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name2.c_str()));
7c673cae
FG
1390 }
1391
1392 ioctx.close();
1393}
1394
f67539c2
TL
1395
1396static int print_progress_percent(uint64_t offset, uint64_t src_size,
1397 void *data)
11fdf7f2 1398{
f67539c2
TL
1399 float percent = ((float)offset * 100) / src_size;
1400 printf("%3.2f%% done\n", percent);
1401 return 0;
1402}
11fdf7f2 1403
f67539c2
TL
1404TEST_F(TestLibRBD, TestCopy)
1405{
11fdf7f2
TL
1406 rados_ioctx_t ioctx;
1407 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
11fdf7f2
TL
1408
1409 rbd_image_t image;
1410 rbd_image_t image2;
1411 rbd_image_t image3;
11fdf7f2
TL
1412 int order = 0;
1413 std::string name = get_temp_image_name();
1414 std::string name2 = get_temp_image_name();
1415 std::string name3 = get_temp_image_name();
11fdf7f2
TL
1416
1417 uint64_t size = 2 << 20;
1418
11fdf7f2
TL
1419 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1420 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11fdf7f2
TL
1421 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
1422
1423 size_t sum_key_len = 0;
1424 size_t sum_value_len = 0;
1425 std::string key;
1426 std::string val;
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()));
1431
1432 sum_key_len += (key.size() + 1);
1433 sum_value_len += (val.size() + 1);
1434 }
1435
1436 char keys[1024];
1437 char vals[1024];
1438 size_t keys_len = sizeof(keys);
1439 size_t vals_len = sizeof(vals);
1440
1441 char value[1024];
1442 size_t value_len = sizeof(value);
1443
f67539c2 1444 ASSERT_EQ(0, rbd_copy(image, ioctx, name2.c_str()));
11fdf7f2
TL
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));
f67539c2 1447 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
11fdf7f2
TL
1448 &vals_len));
1449 ASSERT_EQ(keys_len, sum_key_len);
1450 ASSERT_EQ(vals_len, sum_value_len);
1451
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);
1457
1458 value_len = sizeof(value);
1459 }
1460
f67539c2
TL
1461 ASSERT_EQ(0, rbd_copy_with_progress(image, ioctx, name3.c_str(),
1462 print_progress_percent, NULL));
11fdf7f2
TL
1463 ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
1464
1465 keys_len = sizeof(keys);
1466 vals_len = sizeof(vals);
1467 ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
f67539c2 1468 ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
11fdf7f2
TL
1469 &vals_len));
1470 ASSERT_EQ(keys_len, sum_key_len);
1471 ASSERT_EQ(vals_len, sum_value_len);
1472
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);
1478
1479 value_len = sizeof(value);
1480 }
1481
11fdf7f2 1482 ASSERT_EQ(0, rbd_close(image));
f67539c2
TL
1483 ASSERT_EQ(0, rbd_close(image2));
1484 ASSERT_EQ(0, rbd_close(image3));
1485 rados_ioctx_destroy(ioctx);
11fdf7f2
TL
1486}
1487
f67539c2 1488class PrintProgress : public librbd::ProgressContext
11fdf7f2 1489{
f67539c2
TL
1490public:
1491 int update_progress(uint64_t offset, uint64_t src_size) override
1492 {
1493 float percent = ((float)offset * 100) / src_size;
1494 printf("%3.2f%% done\n", percent);
1495 return 0;
1496 }
1497};
11fdf7f2 1498
f67539c2
TL
1499TEST_F(TestLibRBD, TestCopyPP)
1500{
11fdf7f2
TL
1501 librados::IoCtx ioctx;
1502 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
1503
1504 {
1505 librbd::RBD rbd;
1506 librbd::Image image;
1507 librbd::Image image2;
1508 librbd::Image image3;
1509 int order = 0;
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;
11fdf7f2
TL
1514 PrintProgress pp;
1515
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));
1518
1519 std::string key;
1520 std::string val;
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));
1525 }
1526
1527 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
f67539c2 1528 ASSERT_EQ(0, image.copy(ioctx, name2.c_str()));
11fdf7f2
TL
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));
1531
1532 map<string, bufferlist> pairs;
1533 std::string value;
1534 ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
1535 ASSERT_EQ(70U, pairs.size());
1536
1537 for (int i = 1; i <= 70; i++) {
1538 key = "key" + stringify(i);
1539 val = "value" + stringify(i);
f67539c2
TL
1540 ASSERT_EQ(0, image2.metadata_get(key.c_str(), &value));
1541 ASSERT_STREQ(val.c_str(), value.c_str());
1542 }
7c673cae 1543
f67539c2
TL
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(),
1546 name3.c_str()));
1547 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
7c673cae 1548
f67539c2
TL
1549 pairs.clear();
1550 ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
1551 ASSERT_EQ(70U, pairs.size());
7c673cae 1552
f67539c2
TL
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());
1558 }
1559 }
7c673cae 1560
f67539c2 1561 ioctx.close();
7c673cae
FG
1562}
1563
f67539c2 1564TEST_F(TestLibRBD, TestDeepCopy)
7c673cae
FG
1565{
1566 REQUIRE_FORMAT_V2();
f67539c2 1567 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7c673cae
FG
1568
1569 rados_ioctx_t ioctx;
f67539c2
TL
1570 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
1571 BOOST_SCOPE_EXIT_ALL( (&ioctx) ) {
1572 rados_ioctx_destroy(ioctx);
1573 };
7c673cae
FG
1574
1575 rbd_image_t image;
f67539c2
TL
1576 rbd_image_t image2;
1577 rbd_image_t image3;
1578 rbd_image_t image4;
1579 rbd_image_t image5;
1580 rbd_image_t image6;
31f18b77 1581 int order = 0;
7c673cae 1582 std::string name = get_temp_image_name();
f67539c2
TL
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();
1588
7c673cae 1589 uint64_t size = 2 << 20;
f67539c2
TL
1590
1591 rbd_image_options_t opts;
1592 rbd_image_options_create(&opts);
1593 BOOST_SCOPE_EXIT_ALL( (&opts) ) {
1594 rbd_image_options_destroy(opts);
1595 };
31f18b77 1596
7c673cae
FG
1597 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1598 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
f67539c2
TL
1599 BOOST_SCOPE_EXIT_ALL( (&image) ) {
1600 ASSERT_EQ(0, rbd_close(image));
1601 };
1602 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
7c673cae 1603
f67539c2
TL
1604 size_t sum_key_len = 0;
1605 size_t sum_value_len = 0;
1606 std::string key;
1607 std::string val;
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()));
7c673cae 1612
f67539c2
TL
1613 sum_key_len += (key.size() + 1);
1614 sum_value_len += (val.size() + 1);
1615 }
7c673cae 1616
f67539c2
TL
1617 char keys[1024];
1618 char vals[1024];
1619 size_t keys_len = sizeof(keys);
1620 size_t vals_len = sizeof(vals);
7c673cae 1621
f67539c2
TL
1622 char value[1024];
1623 size_t value_len = sizeof(value);
7c673cae 1624
f67539c2
TL
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));
1630 };
1631 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
1632 &vals_len));
1633 ASSERT_EQ(keys_len, sum_key_len);
1634 ASSERT_EQ(vals_len, sum_value_len);
7c673cae 1635
f67539c2
TL
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);
7c673cae 1641
f67539c2 1642 value_len = sizeof(value);
7c673cae
FG
1643 }
1644
f67539c2
TL
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()));
7c673cae 1648
f67539c2
TL
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));
1654 };
1655 ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
1656 &vals_len));
1657 ASSERT_EQ(keys_len, sum_key_len);
1658 ASSERT_EQ(vals_len, sum_value_len);
1659
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);
1665
1666 value_len = sizeof(value);
7c673cae
FG
1667 }
1668
f67539c2
TL
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));
7c673cae 1675
f67539c2
TL
1676 ASSERT_EQ(4, test_ls(ioctx, 4, name.c_str(), name2.c_str(), name3.c_str(),
1677 name4.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));
1681 };
1682 ASSERT_EQ(0, rbd_snap_create(image4, "deep_snap"));
7c673cae 1683
f67539c2
TL
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));
1690 };
1691 ASSERT_EQ(0, rbd_metadata_list(image5, "key", 70, keys, &keys_len, vals,
1692 &vals_len));
1693 ASSERT_EQ(keys_len, sum_key_len);
1694 ASSERT_EQ(vals_len, sum_value_len);
1695
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);
1701
1702 value_len = sizeof(value);
7c673cae
FG
1703 }
1704
f67539c2
TL
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()));
1709
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));
1715 };
1716 ASSERT_EQ(0, rbd_metadata_list(image6, "key", 70, keys, &keys_len, vals,
1717 &vals_len));
1718 ASSERT_EQ(keys_len, sum_key_len);
1719 ASSERT_EQ(vals_len, sum_value_len);
1720
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);
1726
1727 value_len = sizeof(value);
1728 }
7c673cae
FG
1729}
1730
f67539c2 1731TEST_F(TestLibRBD, TestDeepCopyPP)
9f95a23c 1732{
f67539c2
TL
1733 REQUIRE_FORMAT_V2();
1734
9f95a23c 1735 librados::IoCtx ioctx;
f67539c2 1736 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
9f95a23c
TL
1737
1738 {
1739 librbd::RBD rbd;
1740 librbd::Image image;
f67539c2
TL
1741 librbd::Image image2;
1742 librbd::Image image3;
9f95a23c
TL
1743 int order = 0;
1744 std::string name = get_temp_image_name();
f67539c2
TL
1745 std::string name2 = get_temp_image_name();
1746 std::string name3 = get_temp_image_name();
9f95a23c 1747 uint64_t size = 2 << 20;
f67539c2
TL
1748 librbd::ImageOptions opts;
1749 PrintProgress pp;
9f95a23c
TL
1750
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));
1753
f67539c2
TL
1754 std::string key;
1755 std::string val;
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));
9f95a23c
TL
1760 }
1761
f67539c2
TL
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));
9f95a23c 1766
f67539c2
TL
1767 map<string, bufferlist> pairs;
1768 std::string value;
1769 ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
1770 ASSERT_EQ(70U, pairs.size());
9f95a23c 1771
f67539c2
TL
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());
1777 }
9f95a23c 1778
f67539c2
TL
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(),
1781 name3.c_str()));
1782 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
7c673cae 1783
f67539c2
TL
1784 pairs.clear();
1785 ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
1786 ASSERT_EQ(70U, pairs.size());
1787
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());
1793 }
7c673cae
FG
1794 }
1795
1796 ioctx.close();
1797}
1798
f67539c2 1799int test_ls_snaps(rbd_image_t image, int num_expected, ...)
7c673cae 1800{
f67539c2
TL
1801 int num_snaps, i, j, max_size = 10;
1802 va_list ap;
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);
7c673cae 1806
f67539c2
TL
1807 for (i = 0; i < num_snaps; i++) {
1808 printf("snap: %s\n", snaps[i].name);
1809 }
7c673cae 1810
f67539c2
TL
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);
1815 bool found = false;
1816 for (j = 0; j < num_snaps; j++) {
1817 if (snaps[j].name == NULL)
1818 continue;
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;
1824 found = true;
1825 break;
1826 }
1827 }
1828 EXPECT_TRUE(found);
1829 }
1830 va_end(ap);
7c673cae 1831
f67539c2
TL
1832 for (i = 0; i < num_snaps; i++) {
1833 EXPECT_EQ((const char *)0, snaps[i].name);
1834 }
7c673cae 1835
f67539c2 1836 return num_snaps;
7c673cae
FG
1837}
1838
f67539c2 1839TEST_F(TestLibRBD, TestCreateLsDeleteSnap)
7c673cae 1840{
f67539c2
TL
1841 rados_ioctx_t ioctx;
1842 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 1843
f67539c2
TL
1844 rbd_image_t image;
1845 int order = 0;
1846 std::string name = get_temp_image_name();
1847 uint64_t size = 2 << 20;
1848 uint64_t size2 = 4 << 20;
1849
1850 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1851 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 1852
f67539c2
TL
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));
1862
1863 ASSERT_EQ(0, rbd_close(image));
1864
1865 rados_ioctx_destroy(ioctx);
7c673cae
FG
1866}
1867
f67539c2 1868int test_get_snapshot_timestamp(rbd_image_t image, uint64_t snap_id)
7c673cae 1869{
f67539c2
TL
1870 struct timespec timestamp;
1871 EXPECT_EQ(0, rbd_snap_get_timestamp(image, snap_id, &timestamp));
1872 EXPECT_LT(0, timestamp.tv_sec);
1873 return 0;
7c673cae
FG
1874}
1875
f67539c2 1876TEST_F(TestLibRBD, TestGetSnapShotTimeStamp)
7c673cae 1877{
f67539c2 1878 REQUIRE_FORMAT_V2();
7c673cae 1879
f67539c2
TL
1880 rados_ioctx_t ioctx;
1881 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 1882
f67539c2
TL
1883 rbd_image_t image;
1884 int order = 0;
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];
7c673cae 1889
f67539c2
TL
1890 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1891 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 1892
f67539c2
TL
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);
7c673cae 1898
f67539c2
TL
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);
7c673cae 1906
f67539c2 1907 ASSERT_EQ(0, rbd_close(image));
7c673cae 1908
f67539c2 1909 rados_ioctx_destroy(ioctx);
7c673cae
FG
1910}
1911
7c673cae 1912
f67539c2 1913int test_ls_snaps(librbd::Image& image, size_t num_expected, ...)
7c673cae 1914{
7c673cae 1915 int r;
f67539c2
TL
1916 size_t i, j;
1917 va_list ap;
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;
7c673cae 1923
f67539c2
TL
1924 for (i = 0; i < snaps.size(); i++) {
1925 cout << "snap: " << snaps[i].name << std::endl;
1926 }
7c673cae 1927
f67539c2
TL
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);
1932 int found = 0;
1933 for (j = 0; j < snaps.size(); j++) {
1934 if (snaps[j].name == "")
1935 continue;
1936 if (strcmp(snaps[j].name.c_str(), expected) == 0) {
1937 cout << "found " << snaps[j].name << " with size " << snaps[j].size
1938 << std::endl;
1939 EXPECT_EQ(expected_size, snaps[j].size);
1940 snaps[j].name = "";
1941 found = 1;
1942 break;
1943 }
7c673cae 1944 }
f67539c2 1945 EXPECT_TRUE(found);
7c673cae 1946 }
f67539c2 1947 va_end(ap);
7c673cae 1948
f67539c2
TL
1949 for (i = 0; i < snaps.size(); i++) {
1950 EXPECT_EQ("", snaps[i].name);
1951 }
1952
1953 return snaps.size();
7c673cae
FG
1954}
1955
f67539c2 1956TEST_F(TestLibRBD, TestCreateLsDeleteSnapPP)
7c673cae 1957{
f67539c2
TL
1958 librados::IoCtx ioctx;
1959 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 1960
f67539c2
TL
1961 {
1962 librbd::RBD rbd;
1963 librbd::Image image;
1964 int order = 0;
1965 std::string name = get_temp_image_name();
1966 uint64_t size = 2 << 20;
1967 uint64_t size2 = 4 << 20;
1968
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));
1971
1972 bool exists;
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));
7c673cae 1994 }
7c673cae 1995
f67539c2 1996 ioctx.close();
7c673cae
FG
1997}
1998
f67539c2 1999TEST_F(TestLibRBD, TestGetNameIdSnapPP)
c07f9fc5 2000{
f67539c2
TL
2001 librados::IoCtx ioctx;
2002 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
c07f9fc5 2003
f67539c2
TL
2004 {
2005 librbd::RBD rbd;
2006 librbd::Image image;
2007 int order = 0;
2008 std::string name = get_temp_image_name();
2009 uint64_t size = 2 << 20;
2010
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));
2013
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);
2020
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);
2025 }
2026
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);
2031 }
2032
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));
2037 }
2038
2039 ioctx.close();
c07f9fc5
FG
2040}
2041
f67539c2 2042TEST_F(TestLibRBD, TestCreateLsRenameSnapPP)
c07f9fc5 2043{
f67539c2
TL
2044 librados::IoCtx ioctx;
2045 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2046
2047 {
2048 librbd::RBD rbd;
2049 librbd::Image image;
2050 int order = 0;
2051 std::string name = get_temp_image_name();
2052 uint64_t size = 2 << 20;
2053 uint64_t size2 = 4 << 20;
2054
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));
2057
2058 bool exists;
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));
2087 }
c07f9fc5 2088
f67539c2
TL
2089 ioctx.close();
2090}
c07f9fc5 2091
7c673cae
FG
2092TEST_F(TestLibRBD, TestIO)
2093{
2094 rados_ioctx_t ioctx;
2095 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2096
7c673cae
FG
2097 rbd_image_t image;
2098 int order = 0;
2099 std::string name = get_temp_image_name();
11fdf7f2 2100 uint64_t size = 2 << 20;
7c673cae
FG
2101
2102 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9f95a23c 2103 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_read_from_replica_policy", "balance"));
7c673cae 2104 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 2105
f67539c2 2106 test_io(image);
7c673cae 2107
f67539c2 2108 ASSERT_EQ(0, rbd_close(image));
7c673cae 2109
f67539c2
TL
2110 rados_ioctx_destroy(ioctx);
2111}
7c673cae 2112
f67539c2
TL
2113TEST_F(TestLibRBD, TestEncryptionLUKS1)
2114{
2115 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
c07f9fc5 2116
f67539c2
TL
2117 rados_ioctx_t ioctx;
2118 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
c07f9fc5 2119
f67539c2
TL
2120 int order = 0;
2121 std::string name = get_temp_image_name();
2122 uint64_t size = 32 << 20;
7c673cae 2123
f67539c2
TL
2124 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2125 ASSERT_EQ(0, rados_conf_set(
2126 _cluster, "rbd_read_from_replica_policy", "balance"));
7c673cae 2127
f67539c2
TL
2128 rbd_image_t image;
2129 rbd_encryption_luks1_format_options_t opts = {
2130 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2131 .passphrase = "password",
2132 .passphrase_size = 8,
2133 };
2134 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 2135
f67539c2
TL
2136#ifndef HAVE_LIBCRYPTSETUP
2137 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2138 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2139 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2140 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2141#else
2142 ASSERT_EQ(0, rbd_encryption_format(
2143 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2144 ASSERT_EQ(-EEXIST, rbd_encryption_load(
2145 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2146
2147 test_io(image);
2148
2149 bool passed;
2150 write_test_data(image, "test", 0, 4, 0, &passed);
2151 ASSERT_TRUE(passed);
2152 ASSERT_EQ(0, rbd_close(image));
7c673cae 2153
f67539c2
TL
2154 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2155 ASSERT_EQ(0, rbd_encryption_load(
2156 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2157 read_test_data(image, "test", 0, 4, 0, &passed);
2158 ASSERT_TRUE(passed);
2159#endif
7c673cae 2160
f67539c2
TL
2161 ASSERT_EQ(0, rbd_close(image));
2162 rados_ioctx_destroy(ioctx);
2163}
7c673cae 2164
f67539c2
TL
2165TEST_F(TestLibRBD, TestEncryptionLUKS2)
2166{
2167 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
7c673cae 2168
f67539c2
TL
2169 rados_ioctx_t ioctx;
2170 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 2171
f67539c2
TL
2172 int order = 0;
2173 std::string name = get_temp_image_name();
2174 uint64_t size = 32 << 20;
c07f9fc5 2175
f67539c2
TL
2176 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2177 ASSERT_EQ(0, rados_conf_set(
2178 _cluster, "rbd_read_from_replica_policy", "balance"));
2179
2180 rbd_image_t image;
2181 rbd_encryption_luks2_format_options_t opts = {
2182 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2183 .passphrase = "password",
2184 .passphrase_size = 8,
2185 };
2186 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2187
2188#ifndef HAVE_LIBCRYPTSETUP
2189 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2190 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2191 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2192 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2193#else
2194 ASSERT_EQ(0, rbd_encryption_format(
2195 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2196 ASSERT_EQ(-EEXIST, rbd_encryption_load(
2197 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2198
2199 test_io(image);
2200
2201 bool passed;
2202 write_test_data(image, "test", 0, 4, 0, &passed);
2203 ASSERT_TRUE(passed);
7c673cae
FG
2204 ASSERT_EQ(0, rbd_close(image));
2205
f67539c2
TL
2206 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2207 ASSERT_EQ(0, rbd_encryption_load(
2208 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2209 read_test_data(image, "test", 0, 4, 0, &passed);
2210 ASSERT_TRUE(passed);
2211#endif
2212
2213 ASSERT_EQ(0, rbd_close(image));
7c673cae
FG
2214 rados_ioctx_destroy(ioctx);
2215}
2216
2217TEST_F(TestLibRBD, TestIOWithIOHint)
2218{
2219 rados_ioctx_t ioctx;
2220 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2221
7c673cae
FG
2222 rbd_image_t image;
2223 int order = 0;
2224 std::string name = get_temp_image_name();
2225 uint64_t size = 2 << 20;
2226
2227 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2228 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2229
f67539c2
TL
2230 bool skip_discard = is_skip_partial_discard_enabled(image);
2231
7c673cae
FG
2232 char test_data[TEST_IO_SIZE + 1];
2233 char zero_data[TEST_IO_SIZE + 1];
c07f9fc5 2234 char mismatch_data[TEST_IO_SIZE + 1];
7c673cae 2235 int i;
c07f9fc5 2236 uint64_t mismatch_offset;
7c673cae
FG
2237
2238 for (i = 0; i < TEST_IO_SIZE; ++i) {
2239 test_data[i] = (char) (rand() % (126 - 33) + 33);
2240 }
2241 test_data[TEST_IO_SIZE] = '\0';
2242 memset(zero_data, 0, sizeof(zero_data));
c07f9fc5 2243 memset(mismatch_data, 9, sizeof(mismatch_data));
7c673cae
FG
2244
2245 for (i = 0; i < 5; ++i)
2246 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
2247 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2248
2249 for (i = 5; i < 10; ++i)
2250 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
2251 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2252
c07f9fc5
FG
2253 for (i = 0; i < 5; ++i)
2254 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
2255 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2256
2257 for (i = 5; i < 10; ++i)
2258 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
2259 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2260
7c673cae
FG
2261 for (i = 0; i < 5; ++i)
2262 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE,
2263 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2264
2265 for (i = 5; i < 10; ++i)
2266 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
2267 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2268
2269 // discard 2nd, 4th sections.
2270 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2271 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2272
2273 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE,
2274 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2275 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2276 TEST_IO_SIZE, TEST_IO_SIZE,
2277 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2278 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE,
2279 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2280 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2281 TEST_IO_SIZE*3, TEST_IO_SIZE,
2282 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2283 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2284
2285 for (i = 0; i < 15; ++i) {
2286 if (i % 3 == 2) {
2287 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2288 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2289 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2290 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2291 } else if (i % 3 == 1) {
2292 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2293 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2294 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2295 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2296 } else {
2297 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2298 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2299 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2300 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2301 }
2302 }
2303 for (i = 0; i < 15; ++i) {
2304 if (i % 3 == 2) {
2305 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2306 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2307 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2308 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2309 } else if (i % 3 == 1) {
2310 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2311 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2312 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2313 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2314 } else {
2315 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2316 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2317 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2318 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2319 }
2320 }
2321
2322 rbd_image_info_t info;
2323 rbd_completion_t comp;
2324 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
2325 // can't read or write starting past end
2326 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
2327 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
2328 // reading through end returns amount up to end
2329 ASSERT_EQ(10, rbd_read2(image, info.size - 10, 100, test_data,
2330 LIBRADOS_OP_FLAG_FADVISE_NOCACHE));
2331 // writing through end returns amount up to end
2332 ASSERT_EQ(10, rbd_write2(image, info.size - 10, 100, test_data,
2333 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2334
2335 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2336 ASSERT_EQ(0, rbd_aio_read2(image, info.size, 1, test_data, comp,
2337 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2338 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2339 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2340 rbd_aio_release(comp);
2341
c07f9fc5
FG
2342 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2343 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
2344 &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2345 ASSERT_EQ(0U, mismatch_offset);
2346 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2347 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
2348 comp, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2349 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2350 ASSERT_EQ(0U, mismatch_offset);
2351 rbd_aio_release(comp);
2352
7c673cae
FG
2353 ASSERT_PASSED(validate_object_map, image);
2354 ASSERT_EQ(0, rbd_close(image));
2355
2356 rados_ioctx_destroy(ioctx);
2357}
2358
2359TEST_F(TestLibRBD, TestDataPoolIO)
2360{
2361 REQUIRE_FORMAT_V2();
2362
2363 rados_ioctx_t ioctx;
2364 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2365
2366 std::string data_pool_name = create_pool(true);
2367
7c673cae
FG
2368 rbd_image_t image;
2369 std::string name = get_temp_image_name();
2370 uint64_t size = 2 << 20;
2371
2372 bool old_format;
2373 uint64_t features;
2374 ASSERT_EQ(0, get_features(&old_format, &features));
2375 ASSERT_FALSE(old_format);
2376
2377 rbd_image_options_t image_options;
2378 rbd_image_options_create(&image_options);
2379 BOOST_SCOPE_EXIT( (&image_options) ) {
2380 rbd_image_options_destroy(image_options);
2381 } BOOST_SCOPE_EXIT_END;
2382
2383 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
2384 RBD_IMAGE_OPTION_FEATURES,
2385 features));
2386 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
2387 RBD_IMAGE_OPTION_DATA_POOL,
2388 data_pool_name.c_str()));
2389
2390 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
2391 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2392 ASSERT_NE(-1, rbd_get_data_pool_id(image));
2393
f67539c2
TL
2394 bool skip_discard = is_skip_partial_discard_enabled(image);
2395
7c673cae
FG
2396 char test_data[TEST_IO_SIZE + 1];
2397 char zero_data[TEST_IO_SIZE + 1];
2398 int i;
2399
2400 for (i = 0; i < TEST_IO_SIZE; ++i) {
2401 test_data[i] = (char) (rand() % (126 - 33) + 33);
2402 }
2403 test_data[TEST_IO_SIZE] = '\0';
2404 memset(zero_data, 0, sizeof(zero_data));
2405
2406 for (i = 0; i < 5; ++i)
2407 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2408
2409 for (i = 5; i < 10; ++i)
2410 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2411
2412 for (i = 0; i < 5; ++i)
2413 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2414
2415 for (i = 5; i < 10; ++i)
2416 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2417
2418 // discard 2nd, 4th sections.
2419 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2420 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2421
2422 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
2423 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2424 TEST_IO_SIZE, TEST_IO_SIZE, 0);
2425 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
2426 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2427 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
2428 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2429
2430 rbd_image_info_t info;
2431 rbd_completion_t comp;
2432 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
2433 // can't read or write starting past end
2434 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
2435 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
2436 // reading through end returns amount up to end
2437 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
2438 // writing through end returns amount up to end
2439 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
2440
2441 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2442 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
2443 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2444 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2445 rbd_aio_release(comp);
2446
2447 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2448 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
2449 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2450 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2451 rbd_aio_release(comp);
2452
2453 ASSERT_PASSED(validate_object_map, image);
2454 ASSERT_EQ(0, rbd_close(image));
2455
2456 rados_ioctx_destroy(ioctx);
2457}
2458
2459TEST_F(TestLibRBD, TestScatterGatherIO)
2460{
2461 rados_ioctx_t ioctx;
2462 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2463
2464 rbd_image_t image;
2465 int order = 0;
2466 std::string name = get_temp_image_name();
2467 uint64_t size = 20 << 20;
2468
2469 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2470 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2471
2472 std::string write_buffer("This is a test");
2473 struct iovec bad_iovs[] = {
2474 {.iov_base = NULL, .iov_len = static_cast<size_t>(-1)}
2475 };
2476 struct iovec write_iovs[] = {
2477 {.iov_base = &write_buffer[0], .iov_len = 5},
2478 {.iov_base = &write_buffer[5], .iov_len = 3},
2479 {.iov_base = &write_buffer[8], .iov_len = 2},
2480 {.iov_base = &write_buffer[10], .iov_len = 4}
2481 };
2482
2483 rbd_completion_t comp;
2484 rbd_aio_create_completion(NULL, NULL, &comp);
2485 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, write_iovs, 0, 0, comp));
2486 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 1, 0, comp));
2487 ASSERT_EQ(0, rbd_aio_writev(image, write_iovs,
2488 sizeof(write_iovs) / sizeof(struct iovec),
2489 1<<order, comp));
2490 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2491 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
2492 rbd_aio_release(comp);
2493
2494 std::string read_buffer(write_buffer.size(), '1');
2495 struct iovec read_iovs[] = {
2496 {.iov_base = &read_buffer[0], .iov_len = 4},
2497 {.iov_base = &read_buffer[8], .iov_len = 4},
2498 {.iov_base = &read_buffer[12], .iov_len = 2}
2499 };
2500
2501 rbd_aio_create_completion(NULL, NULL, &comp);
2502 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, read_iovs, 0, 0, comp));
2503 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 1, 0, comp));
2504 ASSERT_EQ(0, rbd_aio_readv(image, read_iovs,
2505 sizeof(read_iovs) / sizeof(struct iovec),
2506 1<<order, comp));
2507 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2508 ASSERT_EQ(10, rbd_aio_get_return_value(comp));
2509 rbd_aio_release(comp);
2510 ASSERT_EQ("This1111 is a ", read_buffer);
2511
2512 std::string linear_buffer(write_buffer.size(), '1');
2513 struct iovec linear_iovs[] = {
2514 {.iov_base = &linear_buffer[4], .iov_len = 4}
2515 };
2516 rbd_aio_create_completion(NULL, NULL, &comp);
2517 ASSERT_EQ(0, rbd_aio_readv(image, linear_iovs,
2518 sizeof(linear_iovs) / sizeof(struct iovec),
2519 1<<order, comp));
2520 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2521 ASSERT_EQ(4, rbd_aio_get_return_value(comp));
2522 rbd_aio_release(comp);
2523 ASSERT_EQ("1111This111111", linear_buffer);
2524
2525 ASSERT_PASSED(validate_object_map, image);
2526 ASSERT_EQ(0, rbd_close(image));
2527
2528 rados_ioctx_destroy(ioctx);
2529}
2530
2531TEST_F(TestLibRBD, TestEmptyDiscard)
2532{
2533 rados_ioctx_t ioctx;
2534 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2535
2536 rbd_image_t image;
2537 int order = 0;
2538 std::string name = get_temp_image_name();
2539 uint64_t size = 20 << 20;
31f18b77 2540
7c673cae
FG
2541 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2542 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2543
2544 ASSERT_PASSED(aio_discard_test_data, image, 0, 1*1024*1024);
2545 ASSERT_PASSED(aio_discard_test_data, image, 0, 4*1024*1024);
31f18b77 2546 ASSERT_PASSED(aio_discard_test_data, image, 3*1024*1024, 1*1024*1024);
7c673cae
FG
2547
2548 ASSERT_PASSED(validate_object_map, image);
2549 ASSERT_EQ(0, rbd_close(image));
2550
2551 rados_ioctx_destroy(ioctx);
2552}
2553
11fdf7f2
TL
2554TEST_F(TestLibRBD, TestFUA)
2555{
2556 rados_ioctx_t ioctx;
2557 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2558
2559 rbd_image_t image_write;
2560 rbd_image_t image_read;
2561 int order = 0;
2562 std::string name = get_temp_image_name();
2563 uint64_t size = 2 << 20;
2564
2565 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2566 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_write, NULL));
2567 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_read, NULL));
2568
2569 // enable writeback cache
2570 rbd_flush(image_write);
2571
2572 char test_data[TEST_IO_SIZE + 1];
2573 int i;
2574
2575 for (i = 0; i < TEST_IO_SIZE; ++i) {
2576 test_data[i] = (char) (rand() % (126 - 33) + 33);
2577 }
2578 test_data[TEST_IO_SIZE] = '\0';
2579 for (i = 0; i < 5; ++i)
2580 ASSERT_PASSED(write_test_data, image_write, test_data,
2581 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
2582
2583 for (i = 0; i < 5; ++i)
2584 ASSERT_PASSED(read_test_data, image_read, test_data,
2585 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2586
2587 for (i = 5; i < 10; ++i)
2588 ASSERT_PASSED(aio_write_test_data, image_write, test_data,
2589 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
2590
2591 for (i = 5; i < 10; ++i)
2592 ASSERT_PASSED(aio_read_test_data, image_read, test_data,
2593 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2594
2595 ASSERT_PASSED(validate_object_map, image_write);
2596 ASSERT_PASSED(validate_object_map, image_read);
2597 ASSERT_EQ(0, rbd_close(image_write));
2598 ASSERT_EQ(0, rbd_close(image_read));
2599 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
2600 rados_ioctx_destroy(ioctx);
2601}
7c673cae
FG
2602
2603void simple_write_cb_pp(librbd::completion_t cb, void *arg)
2604{
2605 cout << "write completion cb called!" << std::endl;
2606}
2607
2608void simple_read_cb_pp(librbd::completion_t cb, void *arg)
2609{
2610 cout << "read completion cb called!" << std::endl;
2611}
2612
2613void aio_write_test_data(librbd::Image& image, const char *test_data,
2614 off_t off, uint32_t iohint, bool *passed)
2615{
2616 ceph::bufferlist bl;
2617 bl.append(test_data, strlen(test_data));
2618 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2619 printf("created completion\n");
2620 if (iohint)
2621 image.aio_write2(off, strlen(test_data), bl, comp, iohint);
2622 else
2623 image.aio_write(off, strlen(test_data), bl, comp);
2624 printf("started write\n");
2625 comp->wait_for_complete();
2626 int r = comp->get_return_value();
2627 printf("return value is: %d\n", r);
2628 ASSERT_EQ(0, r);
2629 printf("finished write\n");
2630 comp->release();
2631 *passed = true;
2632}
2633
2634void aio_discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2635{
2636 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2637 image.aio_discard(off, len, comp);
2638 comp->wait_for_complete();
2639 int r = comp->get_return_value();
2640 ASSERT_EQ(0, r);
2641 comp->release();
2642 *passed = true;
2643}
2644
2645void write_test_data(librbd::Image& image, const char *test_data, off_t off, uint32_t iohint, bool *passed)
2646{
2647 size_t written;
2648 size_t len = strlen(test_data);
2649 ceph::bufferlist bl;
2650 bl.append(test_data, len);
2651 if (iohint)
2652 written = image.write2(off, len, bl, iohint);
2653 else
2654 written = image.write(off, len, bl);
2655 printf("wrote: %u\n", (unsigned int) written);
2656 ASSERT_EQ(bl.length(), written);
2657 *passed = true;
2658}
2659
2660void discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2661{
2662 size_t written;
2663 written = image.discard(off, len);
2664 printf("discard: %u~%u\n", (unsigned)off, (unsigned)len);
2665 ASSERT_EQ(len, written);
2666 *passed = true;
2667}
2668
2669void aio_read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2670{
2671 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_read_cb_pp);
2672 ceph::bufferlist bl;
2673 printf("created completion\n");
2674 if (iohint)
2675 image.aio_read2(off, expected_len, bl, comp, iohint);
2676 else
2677 image.aio_read(off, expected_len, bl, comp);
2678 printf("started read\n");
2679 comp->wait_for_complete();
2680 int r = comp->get_return_value();
2681 printf("return value is: %d\n", r);
2682 ASSERT_EQ(TEST_IO_SIZE, r);
2683 ASSERT_EQ(0, memcmp(expected, bl.c_str(), TEST_IO_SIZE));
2684 printf("finished read\n");
2685 comp->release();
2686 *passed = true;
2687}
2688
2689void read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2690{
31f18b77 2691 int read;
7c673cae
FG
2692 size_t len = expected_len;
2693 ceph::bufferlist bl;
2694 if (iohint)
31f18b77 2695 read = image.read2(off, len, bl, iohint);
7c673cae 2696 else
31f18b77 2697 read = image.read(off, len, bl);
7c673cae
FG
2698 ASSERT_TRUE(read >= 0);
2699 std::string bl_str(bl.c_str(), read);
2700
2701 printf("read: %u\n", (unsigned int) read);
2702 int result = memcmp(bl_str.c_str(), expected, expected_len);
2703 if (result != 0) {
2704 printf("read: %s\nexpected: %s\n", bl_str.c_str(), expected);
2705 ASSERT_EQ(0, result);
2706 }
2707 *passed = true;
2708}
2709
2710void aio_writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2711 size_t len, size_t data_len, uint32_t iohint, bool *passed)
2712{
2713 ceph::bufferlist bl;
2714 bl.append(test_data, data_len);
2715 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2716 printf("created completion\n");
2717 int r;
2718 r = image.aio_writesame(off, len, bl, comp, iohint);
2719 printf("started writesame\n");
2720 if (len % data_len) {
2721 ASSERT_EQ(-EINVAL, r);
2722 printf("expected fail, finished writesame\n");
2723 comp->release();
2724 *passed = true;
2725 return;
2726 }
2727
2728 comp->wait_for_complete();
2729 r = comp->get_return_value();
2730 printf("return value is: %d\n", r);
2731 ASSERT_EQ(0, r);
2732 printf("finished writesame\n");
2733 comp->release();
2734
2735 //verify data
2736 printf("to verify the data\n");
2737 int read;
2738 uint64_t left = len;
2739 while (left > 0) {
2740 ceph::bufferlist bl;
2741 read = image.read(off, data_len, bl);
2742 ASSERT_EQ(data_len, static_cast<size_t>(read));
2743 std::string bl_str(bl.c_str(), read);
2744 int result = memcmp(bl_str.c_str(), test_data, data_len);
2745 if (result !=0 ) {
2746 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2747 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2748 ASSERT_EQ(0, result);
2749 }
2750 off += data_len;
2751 left -= data_len;
2752 }
2753 ASSERT_EQ(0U, left);
2754 printf("verified\n");
2755
2756 *passed = true;
2757}
2758
2759void writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2760 ssize_t len, size_t data_len, uint32_t iohint,
2761 bool *passed)
2762{
2763 ssize_t written;
2764 ceph::bufferlist bl;
2765 bl.append(test_data, data_len);
2766 written = image.writesame(off, len, bl, iohint);
2767 if (len % data_len) {
2768 ASSERT_EQ(-EINVAL, written);
2769 printf("expected fail, finished writesame\n");
2770 *passed = true;
2771 return;
2772 }
2773 ASSERT_EQ(len, written);
2774 printf("wrote: %u\n", (unsigned int) written);
2775 *passed = true;
2776
2777 //verify data
2778 printf("to verify the data\n");
2779 int read;
2780 uint64_t left = len;
2781 while (left > 0) {
2782 ceph::bufferlist bl;
2783 read = image.read(off, data_len, bl);
2784 ASSERT_EQ(data_len, static_cast<size_t>(read));
2785 std::string bl_str(bl.c_str(), read);
2786 int result = memcmp(bl_str.c_str(), test_data, data_len);
2787 if (result !=0 ) {
2788 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2789 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2790 ASSERT_EQ(0, result);
2791 }
2792 off += data_len;
2793 left -= data_len;
2794 }
2795 ASSERT_EQ(0U, left);
2796 printf("verified\n");
2797
2798 *passed = true;
2799}
2800
c07f9fc5
FG
2801void aio_compare_and_write_test_data(librbd::Image& image, const char *cmp_data,
2802 const char *test_data, off_t off, ssize_t len,
2803 uint32_t iohint, bool *passed)
2804{
2805 ceph::bufferlist cmp_bl;
2806 cmp_bl.append(cmp_data, strlen(cmp_data));
2807 ceph::bufferlist test_bl;
2808 test_bl.append(test_data, strlen(test_data));
2809 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2810 printf("created completion\n");
2811
2812 uint64_t mismatch_offset;
2813 image.aio_compare_and_write(off, len, cmp_bl, test_bl, comp, &mismatch_offset, iohint);
2814 printf("started aio compare and write\n");
2815 comp->wait_for_complete();
2816 int r = comp->get_return_value();
2817 printf("return value is: %d\n", r);
2818 ASSERT_EQ(0, r);
2819 printf("finished aio compare and write\n");
2820 comp->release();
2821 *passed = true;
2822}
2823
2824void compare_and_write_test_data(librbd::Image& image, const char *cmp_data, const char *test_data,
2825 off_t off, ssize_t len, uint64_t *mismatch_off, uint32_t iohint, bool *passed)
2826{
2827 size_t written;
2828 ceph::bufferlist cmp_bl;
2829 cmp_bl.append(cmp_data, strlen(cmp_data));
2830 ceph::bufferlist test_bl;
2831 test_bl.append(test_data, strlen(test_data));
2832 printf("start compare and write\n");
2833 written = image.compare_and_write(off, len, cmp_bl, test_bl, mismatch_off, iohint);
2834 printf("compare and wrote: %d\n", (int) written);
2835 ASSERT_EQ(len, static_cast<ssize_t>(written));
2836 *passed = true;
2837}
2838
7c673cae
FG
2839TEST_F(TestLibRBD, TestIOPP)
2840{
2841 librados::IoCtx ioctx;
2842 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2843
7c673cae
FG
2844 {
2845 librbd::RBD rbd;
2846 librbd::Image image;
2847 int order = 0;
2848 std::string name = get_temp_image_name();
2849 uint64_t size = 2 << 20;
2850
2851 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2852 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2853
f67539c2
TL
2854 bool skip_discard = this->is_skip_partial_discard_enabled(image);
2855
7c673cae
FG
2856 char test_data[TEST_IO_SIZE + 1];
2857 char zero_data[TEST_IO_SIZE + 1];
2858 int i;
c07f9fc5 2859 uint64_t mismatch_offset;
7c673cae
FG
2860
2861 for (i = 0; i < TEST_IO_SIZE; ++i) {
2862 test_data[i] = (char) (rand() % (126 - 33) + 33);
2863 }
2864 test_data[TEST_IO_SIZE] = '\0';
2865 memset(zero_data, 0, sizeof(zero_data));
2866
2867 for (i = 0; i < 5; ++i)
2868 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i, 0);
2869
2870 for (i = 5; i < 10; ++i)
2871 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i, 0);
2872
c07f9fc5
FG
2873 for (i = 0; i < 5; ++i)
2874 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2875 TEST_IO_SIZE, &mismatch_offset, 0);
2876
2877 for (i = 5; i < 10; ++i)
2878 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2879 TEST_IO_SIZE, 0);
2880
7c673cae
FG
2881 for (i = 0; i < 5; ++i)
2882 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2883
2884 for (i = 5; i < 10; ++i)
2885 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2886
2887 // discard 2nd, 4th sections.
2888 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2889 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2890
2891 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
2892 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2893 TEST_IO_SIZE, TEST_IO_SIZE, 0);
2894 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
2895 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2896 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
2897 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2898
2899 for (i = 0; i < 15; ++i) {
2900 if (i % 3 == 2) {
2901 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2902 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2903 } else if (i % 3 == 1) {
2904 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2905 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2906 } else {
2907 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2908 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2909 }
2910 }
2911 for (i = 0; i < 15; ++i) {
2912 if (i % 3 == 2) {
2913 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2914 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2915 } else if (i % 3 == 1) {
2916 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2917 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2918 } else {
2919 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2920 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2921 }
2922 }
2923
2924 ASSERT_PASSED(validate_object_map, image);
2925 }
2926
2927 ioctx.close();
2928}
2929
2930TEST_F(TestLibRBD, TestIOPPWithIOHint)
2931{
2932 librados::IoCtx ioctx;
2933 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2934
2935 {
2936 librbd::RBD rbd;
2937 librbd::Image image;
2938 int order = 0;
2939 std::string name = get_temp_image_name();
2940 uint64_t size = 2 << 20;
2941
2942 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2943 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2944
2945 char test_data[TEST_IO_SIZE + 1];
2946 char zero_data[TEST_IO_SIZE + 1];
2947 test_data[TEST_IO_SIZE] = '\0';
2948 int i;
2949
2950 for (i = 0; i < TEST_IO_SIZE; ++i) {
2951 test_data[i] = (char) (rand() % (126 - 33) + 33);
2952 }
2953 memset(zero_data, 0, sizeof(zero_data));
2954
2955 for (i = 0; i < 5; ++i)
2956 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i,
2957 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2958
2959 for (i = 5; i < 10; ++i)
2960 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i,
2961 LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2962
2963 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data),
2964 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_RANDOM);
2965
2966 for (i = 5; i < 10; ++i)
2967 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i,
2968 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2969
2970 for (i = 0; i < 15; ++i) {
2971 if (i % 3 == 2) {
2972 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2973 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2974 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2975 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2976 } else if (i % 3 == 1) {
2977 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2978 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2979 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2980 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2981 } else {
2982 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2983 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2984 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2985 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2986 }
2987 }
2988 for (i = 0; i < 15; ++i) {
2989 if (i % 3 == 2) {
2990 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2991 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2992 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2993 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2994 } else if (i % 3 == 1) {
2995 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2996 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2997 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2998 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2999 } else {
3000 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
3001 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3002 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
3003 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3004 }
3005 }
3006
3007 ASSERT_PASSED(validate_object_map, image);
3008 }
3009
3010 ioctx.close();
3011}
3012
3013
3014
3015TEST_F(TestLibRBD, TestIOToSnapshot)
3016{
3017 rados_ioctx_t ioctx;
3018 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3019
3020 rbd_image_t image;
3021 int order = 0;
3022 std::string name = get_temp_image_name();
3023 uint64_t isize = 2 << 20;
3024
3025 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
3026 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3027
3028 int i, r;
3029 rbd_image_t image_at_snap;
3030 char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
3031 char test_data[TEST_IO_TO_SNAP_SIZE + 1];
3032
3033 for (i = 0; i < TEST_IO_TO_SNAP_SIZE; ++i)
3034 test_data[i] = (char) (i + 48);
3035 test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
3036 orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
3037
3038 r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
3039 ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE);
3040
3041 ASSERT_EQ(0, test_ls_snaps(image, 0));
3042 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
3043 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
3044 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3045
3046 printf("write test data!\n");
3047 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3048 ASSERT_EQ(0, rbd_snap_create(image, "written"));
3049 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
3050
3051 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3052
3053 rbd_snap_set(image, "orig");
3054 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3055
3056 rbd_snap_set(image, "written");
3057 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3058
3059 rbd_snap_set(image, "orig");
3060
3061 r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
3062 printf("write to snapshot returned %d\n", r);
3063 ASSERT_LT(r, 0);
31f18b77 3064 cout << strerror(-r) << std::endl;
7c673cae
FG
3065
3066 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3067 rbd_snap_set(image, "written");
3068 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3069
3070 r = rbd_snap_rollback(image, "orig");
3071 ASSERT_EQ(r, -EROFS);
3072
3073 r = rbd_snap_set(image, NULL);
3074 ASSERT_EQ(r, 0);
3075 r = rbd_snap_rollback(image, "orig");
3076 ASSERT_EQ(r, 0);
3077
3078 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3079
3080 rbd_flush(image);
3081
3082 printf("opening testimg@orig\n");
3083 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_at_snap, "orig"));
3084 ASSERT_PASSED(read_test_data, image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
3085 r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
3086 printf("write to snapshot returned %d\n", r);
3087 ASSERT_LT(r, 0);
31f18b77 3088 cout << strerror(-r) << std::endl;
7c673cae
FG
3089 ASSERT_EQ(0, rbd_close(image_at_snap));
3090
f67539c2
TL
3091 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
3092 ASSERT_EQ(0, rbd_snap_remove(image, "written"));
3093 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
3094 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
3095 ASSERT_EQ(0, test_ls_snaps(image, 0));
3096
3097 ASSERT_PASSED(validate_object_map, image);
3098 ASSERT_EQ(0, rbd_close(image));
3099
3100 rados_ioctx_destroy(ioctx);
3101}
3102
3103TEST_F(TestLibRBD, TestSnapshotDeletedIo)
3104{
3105 rados_ioctx_t ioctx;
3106 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3107
3108 rbd_image_t image;
3109 int order = 0;
3110 std::string name = get_temp_image_name();
3111 uint64_t isize = 2 << 20;
3112
3113 int r;
3114
3115 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
3116 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3117 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
3118
3119 r = rbd_snap_set(image, "orig");
3120 ASSERT_EQ(r, 0);
3121
7c673cae 3122 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
f67539c2
TL
3123 char test[20];
3124 ASSERT_EQ(-ENOENT, rbd_read(image, 20, 20, test));
7c673cae 3125
f67539c2
TL
3126 r = rbd_snap_set(image, NULL);
3127 ASSERT_EQ(r, 0);
7c673cae 3128
f67539c2 3129 ASSERT_EQ(0, rbd_close(image));
7c673cae
FG
3130 rados_ioctx_destroy(ioctx);
3131}
3132
3133TEST_F(TestLibRBD, TestClone)
3134{
3135 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11fdf7f2
TL
3136 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "1"));
3137 BOOST_SCOPE_EXIT_ALL(&) {
3138 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
3139 };
7c673cae
FG
3140
3141 rados_ioctx_t ioctx;
3142 rbd_image_info_t pinfo, cinfo;
3143 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3144
3145 bool old_format;
3146 uint64_t features;
3147 rbd_image_t parent, child;
3148 int order = 0;
3149
3150 ASSERT_EQ(0, get_features(&old_format, &features));
3151 ASSERT_FALSE(old_format);
3152
3153 std::string parent_name = get_temp_image_name();
3154 std::string child_name = get_temp_image_name();
3155
3156 // make a parent to clone from
3157 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
3158 false, features));
3159 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
3160 printf("made parent image \"parent\"\n");
3161
3162 char *data = (char *)"testdata";
3163 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
3164
3165 // can't clone a non-snapshot, expect failure
3166 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
3167 child_name.c_str(), features, &order));
3168
3169 // verify that there is no parent info on "parent"
3170 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
3171 printf("parent has no parent info\n");
3172
b32b8144
FG
3173 // create 70 metadatas to verify we can clone all key/value pairs
3174 std::string key;
3175 std::string val;
3176 size_t sum_key_len = 0;
3177 size_t sum_value_len = 0;
3178 for (int i = 1; i <= 70; i++) {
3179 key = "key" + stringify(i);
3180 val = "value" + stringify(i);
3181 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
3182
3183 sum_key_len += (key.size() + 1);
3184 sum_value_len += (val.size() + 1);
3185 }
3186
3187 char keys[1024];
3188 char vals[1024];
3189 size_t keys_len = sizeof(keys);
3190 size_t vals_len = sizeof(vals);
3191
3192 char value[1024];
3193 size_t value_len = sizeof(value);
3194
7c673cae
FG
3195 // create a snapshot, reopen as the parent we're interested in
3196 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3197 printf("made snapshot \"parent@parent_snap\"\n");
3198 ASSERT_EQ(0, rbd_close(parent));
3199 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
3200
3201 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
3202 ioctx, child_name.c_str(), features, &order));
3203
3204 // unprotected image should fail unprotect
3205 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
3206 printf("can't unprotect an unprotected snap\n");
3207
3208 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
3209 // protecting again should fail
3210 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
3211 printf("can't protect a protected snap\n");
3212
3213 // This clone and open should work
3214 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
3215 ioctx, child_name.c_str(), features, &order));
3216 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
3217 printf("made and opened clone \"child\"\n");
3218
3219 // check read
3220 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
3221
3222 // check write
3223 ASSERT_EQ((ssize_t)strlen(data), rbd_write(child, 20, strlen(data), data));
3224 ASSERT_PASSED(read_test_data, child, data, 20, strlen(data), 0);
3225 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
3226
3227 // check attributes
3228 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
3229 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
3230 EXPECT_EQ(cinfo.size, pinfo.size);
3231 uint64_t overlap;
3232 rbd_get_overlap(child, &overlap);
3233 EXPECT_EQ(overlap, pinfo.size);
3234 EXPECT_EQ(cinfo.obj_size, pinfo.obj_size);
3235 EXPECT_EQ(cinfo.order, pinfo.order);
3236 printf("sizes and overlaps are good between parent and child\n");
3237
b32b8144 3238 // check key/value pairs in child image
f67539c2 3239 ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
b32b8144
FG
3240 &vals_len));
3241 ASSERT_EQ(sum_key_len, keys_len);
3242 ASSERT_EQ(sum_value_len, vals_len);
3243
3244 for (int i = 1; i <= 70; i++) {
3245 key = "key" + stringify(i);
3246 val = "value" + stringify(i);
3247 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
3248 ASSERT_STREQ(val.c_str(), value);
3249
3250 value_len = sizeof(value);
3251 }
3252 printf("child image successfully cloned all image-meta pairs\n");
3253
7c673cae
FG
3254 // sizing down child results in changing overlap and size, not parent size
3255 ASSERT_EQ(0, rbd_resize(child, 2UL<<20));
3256 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
3257 rbd_get_overlap(child, &overlap);
3258 ASSERT_EQ(overlap, 2UL<<20);
3259 ASSERT_EQ(cinfo.size, 2UL<<20);
3260 ASSERT_EQ(0, rbd_resize(child, 4UL<<20));
3261 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
3262 rbd_get_overlap(child, &overlap);
3263 ASSERT_EQ(overlap, 2UL<<20);
3264 ASSERT_EQ(cinfo.size, 4UL<<20);
3265 printf("sized down clone, changed overlap\n");
3266
3267 // sizing back up doesn't change that
3268 ASSERT_EQ(0, rbd_resize(child, 5UL<<20));
3269 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
3270 rbd_get_overlap(child, &overlap);
3271 ASSERT_EQ(overlap, 2UL<<20);
3272 ASSERT_EQ(cinfo.size, 5UL<<20);
3273 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
11fdf7f2 3274 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
7c673cae
FG
3275 (unsigned long long)pinfo.size, (unsigned long long)pinfo.obj_size,
3276 (unsigned long long)pinfo.parent_pool);
3277 ASSERT_EQ(pinfo.size, 4UL<<20);
3278 printf("sized up clone, changed size but not overlap or parent's size\n");
3279
3280 ASSERT_PASSED(validate_object_map, child);
3281 ASSERT_EQ(0, rbd_close(child));
3282
3283 ASSERT_PASSED(validate_object_map, parent);
3284 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
3285 printf("can't remove parent while child still exists\n");
3286 ASSERT_EQ(0, rbd_remove(ioctx, child_name.c_str()));
3287 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
3288 printf("can't remove parent while still protected\n");
3289 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3290 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3291 printf("removed parent snap after unprotecting\n");
3292
3293 ASSERT_EQ(0, rbd_close(parent));
3294 rados_ioctx_destroy(ioctx);
3295}
3296
3297TEST_F(TestLibRBD, TestClone2)
3298{
3299 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11fdf7f2
TL
3300 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
3301 BOOST_SCOPE_EXIT_ALL(&) {
3302 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
3303 };
7c673cae
FG
3304
3305 rados_ioctx_t ioctx;
3306 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3307
3308 bool old_format;
3309 uint64_t features;
3310 rbd_image_t parent, child;
3311 int order = 0;
3312
3313 ASSERT_EQ(0, get_features(&old_format, &features));
3314 ASSERT_FALSE(old_format);
3315
3316 std::string parent_name = get_temp_image_name();
3317 std::string child_name = get_temp_image_name();
3318
3319 // make a parent to clone from
3320 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
3321 false, features));
3322 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
3323 printf("made parent image \"parent\"\n");
3324
3325 char *data = (char *)"testdata";
3326 char *childata = (char *)"childata";
3327 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
3328 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
3329
3330 // can't clone a non-snapshot, expect failure
3331 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
3332 child_name.c_str(), features, &order));
3333
3334 // verify that there is no parent info on "parent"
3335 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
3336 printf("parent has no parent info\n");
3337
b32b8144
FG
3338 // create 70 metadatas to verify we can clone all key/value pairs
3339 std::string key;
3340 std::string val;
3341 size_t sum_key_len = 0;
3342 size_t sum_value_len = 0;
3343 for (int i = 1; i <= 70; i++) {
3344 key = "key" + stringify(i);
3345 val = "value" + stringify(i);
3346 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
3347
3348 sum_key_len += (key.size() + 1);
3349 sum_value_len += (val.size() + 1);
3350 }
3351
3352 char keys[1024];
3353 char vals[1024];
3354 size_t keys_len = sizeof(keys);
3355 size_t vals_len = sizeof(vals);
3356
3357 char value[1024];
3358 size_t value_len = sizeof(value);
3359
7c673cae
FG
3360 // create a snapshot, reopen as the parent we're interested in
3361 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3362 printf("made snapshot \"parent@parent_snap\"\n");
3363 ASSERT_EQ(0, rbd_close(parent));
3364 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
3365
7c673cae
FG
3366 // This clone and open should work
3367 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
3368 ioctx, child_name.c_str(), features, &order));
3369 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
3370 printf("made and opened clone \"child\"\n");
3371
b32b8144 3372 // check key/value pairs in child image
f67539c2 3373 ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
b32b8144
FG
3374 &vals_len));
3375 ASSERT_EQ(sum_key_len, keys_len);
3376 ASSERT_EQ(sum_value_len, vals_len);
3377
3378 for (int i = 1; i <= 70; i++) {
3379 key = "key" + stringify(i);
3380 val = "value" + stringify(i);
3381 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
3382 ASSERT_STREQ(val.c_str(), value);
3383
3384 value_len = sizeof(value);
3385 }
3386 printf("child image successfully cloned all image-meta pairs\n");
3387
7c673cae
FG
3388 // write something in
3389 ASSERT_EQ((ssize_t)strlen(childata), rbd_write(child, 20, strlen(childata), childata));
3390
3391 char test[strlen(data) * 2];
3392 ASSERT_EQ((ssize_t)strlen(data), rbd_read(child, 20, strlen(data), test));
3393 ASSERT_EQ(0, memcmp(test, childata, strlen(childata)));
3394
3395 // overlap
3396 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 20 - strlen(data), sizeof(test), test));
3397 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
3398 ASSERT_EQ(0, memcmp(test + strlen(data), childata, strlen(childata)));
3399
3400 // all parent
3401 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 0, sizeof(test), test));
3402 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
3403
3404 ASSERT_PASSED(validate_object_map, child);
3405 ASSERT_PASSED(validate_object_map, parent);
3406
11fdf7f2
TL
3407 rbd_snap_info_t snaps[2];
3408 int max_snaps = 2;
3409 ASSERT_EQ(1, rbd_snap_list(parent, snaps, &max_snaps));
3410 rbd_snap_list_end(snaps);
3411
3412 ASSERT_EQ(0, rbd_snap_remove_by_id(parent, snaps[0].id));
3413
3414 rbd_snap_namespace_type_t snap_namespace_type;
3415 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent, snaps[0].id,
3416 &snap_namespace_type));
3417 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH, snap_namespace_type);
3418
3419 char original_name[32];
3420 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent, snaps[0].id,
3421 original_name,
3422 sizeof(original_name)));
3423 ASSERT_EQ(0, strcmp("parent_snap", original_name));
3424
7c673cae
FG
3425 ASSERT_EQ(0, rbd_close(child));
3426 ASSERT_EQ(0, rbd_close(parent));
3427 rados_ioctx_destroy(ioctx);
3428}
3429
3430static void test_list_children(rbd_image_t image, ssize_t num_expected, ...)
3431{
3432 va_list ap;
3433 va_start(ap, num_expected);
3434 size_t pools_len = 100;
3435 size_t children_len = 100;
3436 char *pools = NULL;
3437 char *children = NULL;
3438 ssize_t num_children;
3439
3440 do {
3441 free(pools);
3442 free(children);
3443 pools = (char *) malloc(pools_len);
3444 children = (char *) malloc(children_len);
3445 num_children = rbd_list_children(image, pools, &pools_len,
3446 children, &children_len);
3447 } while (num_children == -ERANGE);
3448
3449 ASSERT_EQ(num_expected, num_children);
3450 for (ssize_t i = num_expected; i > 0; --i) {
3451 char *expected_pool = va_arg(ap, char *);
3452 char *expected_image = va_arg(ap, char *);
3453 char *pool = pools;
3454 char *image = children;
3455 bool found = 0;
3456 printf("\ntrying to find %s/%s\n", expected_pool, expected_image);
3457 for (ssize_t j = 0; j < num_children; ++j) {
3458 printf("checking %s/%s\n", pool, image);
3459 if (strcmp(expected_pool, pool) == 0 &&
3460 strcmp(expected_image, image) == 0) {
3461 printf("found child %s/%s\n\n", pool, image);
3462 found = 1;
3463 break;
3464 }
3465 pool += strlen(pool) + 1;
3466 image += strlen(image) + 1;
3467 if (j == num_children - 1) {
3468 ASSERT_EQ(pool - pools - 1, (ssize_t) pools_len);
3469 ASSERT_EQ(image - children - 1, (ssize_t) children_len);
3470 }
3471 }
3472 ASSERT_TRUE(found);
3473 }
3474 va_end(ap);
3475
3476 if (pools)
3477 free(pools);
3478 if (children)
3479 free(children);
3480}
3481
11fdf7f2 3482static void test_list_children2(rbd_image_t image, int num_expected, ...)
7c673cae 3483{
11fdf7f2
TL
3484 int num_children, i, j, max_size = 10;
3485 va_list ap;
3486 rbd_child_info_t children[max_size];
3487 num_children = rbd_list_children2(image, children, &max_size);
3488 printf("num children is: %d\nexpected: %d\n", num_children, num_expected);
7c673cae 3489
11fdf7f2
TL
3490 for (i = 0; i < num_children; i++) {
3491 printf("child: %s\n", children[i].image_name);
3492 }
7c673cae 3493
11fdf7f2
TL
3494 va_start(ap, num_expected);
3495 for (i = num_expected; i > 0; i--) {
3496 char *expected_id = va_arg(ap, char *);
3497 char *expected_pool = va_arg(ap, char *);
3498 char *expected_image = va_arg(ap, char *);
3499 bool expected_trash = va_arg(ap, int);
3500 bool found = false;
3501 for (j = 0; j < num_children; j++) {
3502 if (children[j].pool_name == NULL ||
3503 children[j].image_name == NULL ||
3504 children[j].image_id == NULL)
3505 continue;
3506 if (strcmp(children[j].image_id, expected_id) == 0 &&
3507 strcmp(children[j].pool_name, expected_pool) == 0 &&
3508 strcmp(children[j].image_name, expected_image) == 0 &&
3509 children[j].trash == expected_trash) {
3510 printf("found child %s/%s/%s\n\n", children[j].pool_name, children[j].image_name, children[j].image_id);
3511 rbd_list_child_cleanup(&children[j]);
3512 children[j].pool_name = NULL;
3513 children[j].image_name = NULL;
3514 children[j].image_id = NULL;
3515 found = true;
3516 break;
3517 }
3518 }
3519 EXPECT_TRUE(found);
3520 }
3521 va_end(ap);
3522
3523 for (i = 0; i < num_children; i++) {
3524 EXPECT_EQ((const char *)0, children[i].pool_name);
3525 EXPECT_EQ((const char *)0, children[i].image_name);
3526 EXPECT_EQ((const char *)0, children[i].image_id);
3527 }
3528}
3529
3530TEST_F(TestLibRBD, ListChildren)
3531{
3532 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3533
3534 librbd::RBD rbd;
3535 rados_ioctx_t ioctx1, ioctx2;
3536 string pool_name1 = create_pool(true);
3537 string pool_name2 = create_pool(true);
3538 ASSERT_NE("", pool_name2);
3539
3540 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
3541 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
3542
3543 rbd_image_t image1;
3544 rbd_image_t image2;
3545 rbd_image_t image3;
3546 rbd_image_t image4;
3547
3548 bool old_format;
3549 uint64_t features;
3550 rbd_image_t parent;
3551 int order = 0;
3552
3553 ASSERT_EQ(0, get_features(&old_format, &features));
3554 ASSERT_FALSE(old_format);
7c673cae
FG
3555
3556 std::string parent_name = get_temp_image_name();
3557 std::string child_name1 = get_temp_image_name();
3558 std::string child_name2 = get_temp_image_name();
3559 std::string child_name3 = get_temp_image_name();
3560 std::string child_name4 = get_temp_image_name();
3561
11fdf7f2
TL
3562 char child_id1[4096];
3563 char child_id2[4096];
3564 char child_id3[4096];
3565 char child_id4[4096];
3566
7c673cae
FG
3567 // make a parent to clone from
3568 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
3569 false, features));
3570 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
3571 // create a snapshot, reopen as the parent we're interested in
3572 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3573 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
3574 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
3575
3576 ASSERT_EQ(0, rbd_close(parent));
3577 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
3578
3579 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3580 ioctx2, child_name1.c_str(), features, &order));
11fdf7f2
TL
3581 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
3582 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
7c673cae 3583 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
11fdf7f2
TL
3584 test_list_children2(parent, 1,
3585 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
7c673cae
FG
3586
3587 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3588 ioctx1, child_name2.c_str(), features, &order));
11fdf7f2
TL
3589 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
3590 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
7c673cae
FG
3591 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3592 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
3593 test_list_children2(parent, 2,
3594 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3595 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae
FG
3596
3597 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3598 ioctx2, child_name3.c_str(), features, &order));
11fdf7f2
TL
3599 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
3600 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
7c673cae
FG
3601 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3602 pool_name1.c_str(), child_name2.c_str(),
3603 pool_name2.c_str(), child_name3.c_str());
11fdf7f2
TL
3604 test_list_children2(parent, 3,
3605 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3606 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3607 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
3608
3609 librados::IoCtx ioctx3;
3610 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
3611 ASSERT_EQ(0, rbd_close(image3));
3612 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
3613 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3614 pool_name1.c_str(), child_name2.c_str());
3615 test_list_children2(parent, 3,
3616 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3617 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3618 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
7c673cae
FG
3619
3620 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3621 ioctx2, child_name4.c_str(), features, &order));
11fdf7f2
TL
3622 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
3623 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
3624 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3625 pool_name1.c_str(), child_name2.c_str(),
3626 pool_name2.c_str(), child_name4.c_str());
3627 test_list_children2(parent, 4,
3628 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3629 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3630 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
3631 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3632
3633 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
7c673cae
FG
3634 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
3635 pool_name1.c_str(), child_name2.c_str(),
3636 pool_name2.c_str(), child_name3.c_str(),
3637 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
3638 test_list_children2(parent, 4,
3639 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3640 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3641 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3642 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 3643
11fdf7f2 3644 ASSERT_EQ(0, rbd_close(image1));
7c673cae
FG
3645 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
3646 test_list_children(parent, 3,
3647 pool_name1.c_str(), child_name2.c_str(),
3648 pool_name2.c_str(), child_name3.c_str(),
3649 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
3650 test_list_children2(parent, 3,
3651 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3652 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3653 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae
FG
3654
3655 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
3656 test_list_children(parent, 2,
3657 pool_name1.c_str(), child_name2.c_str(),
3658 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
3659 test_list_children2(parent, 2,
3660 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3661 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 3662
11fdf7f2 3663 ASSERT_EQ(0, rbd_close(image4));
7c673cae
FG
3664 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
3665 test_list_children(parent, 1,
3666 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
3667 test_list_children2(parent, 1,
3668 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
3669
7c673cae 3670
11fdf7f2 3671 ASSERT_EQ(0, rbd_close(image2));
7c673cae
FG
3672 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
3673 test_list_children(parent, 0);
11fdf7f2 3674 test_list_children2(parent, 0);
7c673cae
FG
3675
3676 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3677 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3678 ASSERT_EQ(0, rbd_close(parent));
3679 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
3680 rados_ioctx_destroy(ioctx1);
3681 rados_ioctx_destroy(ioctx2);
3682}
3683
3684TEST_F(TestLibRBD, ListChildrenTiered)
3685{
3686 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3687
11fdf7f2 3688 librbd::RBD rbd;
94b18763 3689 string pool_name1 = create_pool(true);
7c673cae
FG
3690 string pool_name2 = create_pool(true);
3691 string pool_name3 = create_pool(true);
94b18763 3692 ASSERT_NE("", pool_name1);
7c673cae
FG
3693 ASSERT_NE("", pool_name2);
3694 ASSERT_NE("", pool_name3);
3695
3696 std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" +
3697 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\", \"force_nonempty\":\"\"}";
3698 char *cmd[1];
3699 cmd[0] = (char *)cmdstr.c_str();
3700 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3701
3702 cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
3703 pool_name3 + "\", \"mode\":\"writeback\"}";
3704 cmd[0] = (char *)cmdstr.c_str();
3705 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3706
3707 cmdstr = "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
3708 pool_name1 + "\", \"overlaypool\":\"" + pool_name3 + "\"}";
3709 cmd[0] = (char *)cmdstr.c_str();
3710 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3711
3712 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
3713
3714 string parent_name = get_temp_image_name();
3715 string child_name1 = get_temp_image_name();
3716 string child_name2 = get_temp_image_name();
3717 string child_name3 = get_temp_image_name();
3718 string child_name4 = get_temp_image_name();
3719
11fdf7f2
TL
3720 char child_id1[4096];
3721 char child_id2[4096];
3722 char child_id3[4096];
3723 char child_id4[4096];
3724
3725 rbd_image_t image1;
3726 rbd_image_t image2;
3727 rbd_image_t image3;
3728 rbd_image_t image4;
3729
7c673cae
FG
3730 rados_ioctx_t ioctx1, ioctx2;
3731 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
3732 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
3733
3734 bool old_format;
3735 uint64_t features;
3736 rbd_image_t parent;
3737 int order = 0;
3738
3739 ASSERT_EQ(0, get_features(&old_format, &features));
3740 ASSERT_FALSE(old_format);
3741
3742 // make a parent to clone from
3743 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
3744 false, features));
3745 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
3746 // create a snapshot, reopen as the parent we're interested in
3747 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3748 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
3749 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
3750
3751 ASSERT_EQ(0, rbd_close(parent));
3752 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
3753
3754 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3755 ioctx2, child_name1.c_str(), features, &order));
11fdf7f2
TL
3756 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
3757 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
7c673cae 3758 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
11fdf7f2
TL
3759 test_list_children2(parent, 1,
3760 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
7c673cae
FG
3761
3762 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3763 ioctx1, child_name2.c_str(), features, &order));
11fdf7f2
TL
3764 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
3765 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
7c673cae
FG
3766 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3767 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
3768 test_list_children2(parent, 2,
3769 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3770 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae
FG
3771
3772 // read from the cache to populate it
3773 rbd_image_t tier_image;
3774 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &tier_image, NULL));
3775 size_t len = 4 * 1024 * 1024;
3776 char* buf = (char*)malloc(len);
3777 ssize_t size = rbd_read(tier_image, 0, len, buf);
3778 ASSERT_GT(size, 0);
3779 free(buf);
3780 ASSERT_EQ(0, rbd_close(tier_image));
3781
3782 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3783 ioctx2, child_name3.c_str(), features, &order));
11fdf7f2
TL
3784 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
3785 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
7c673cae
FG
3786 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3787 pool_name1.c_str(), child_name2.c_str(),
3788 pool_name2.c_str(), child_name3.c_str());
11fdf7f2
TL
3789 test_list_children2(parent, 3,
3790 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3791 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3792 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
3793
3794 librados::IoCtx ioctx3;
3795 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
3796 ASSERT_EQ(0, rbd_close(image3));
3797 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
3798 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3799 pool_name1.c_str(), child_name2.c_str());
3800 test_list_children2(parent, 3,
3801 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3802 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3803 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
7c673cae
FG
3804
3805 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3806 ioctx2, child_name4.c_str(), features, &order));
11fdf7f2
TL
3807 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
3808 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
3809 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3810 pool_name1.c_str(), child_name2.c_str(),
3811 pool_name2.c_str(), child_name4.c_str());
3812 test_list_children2(parent, 4,
3813 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3814 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3815 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
3816 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3817
3818 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
7c673cae
FG
3819 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
3820 pool_name1.c_str(), child_name2.c_str(),
3821 pool_name2.c_str(), child_name3.c_str(),
3822 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
3823 test_list_children2(parent, 4,
3824 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3825 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3826 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3827 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 3828
11fdf7f2 3829 ASSERT_EQ(0, rbd_close(image1));
7c673cae
FG
3830 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
3831 test_list_children(parent, 3,
3832 pool_name1.c_str(), child_name2.c_str(),
3833 pool_name2.c_str(), child_name3.c_str(),
3834 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
3835 test_list_children2(parent, 3,
3836 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3837 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3838 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae
FG
3839
3840 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
3841 test_list_children(parent, 2,
3842 pool_name1.c_str(), child_name2.c_str(),
3843 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
3844 test_list_children2(parent, 2,
3845 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3846 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 3847
11fdf7f2 3848 ASSERT_EQ(0, rbd_close(image4));
7c673cae
FG
3849 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
3850 test_list_children(parent, 1,
3851 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
3852 test_list_children2(parent, 1,
3853 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae 3854
11fdf7f2 3855 ASSERT_EQ(0, rbd_close(image2));
7c673cae
FG
3856 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
3857 test_list_children(parent, 0);
11fdf7f2 3858 test_list_children2(parent, 0);
7c673cae
FG
3859
3860 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3861 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3862 ASSERT_EQ(0, rbd_close(parent));
3863 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
3864 rados_ioctx_destroy(ioctx1);
3865 rados_ioctx_destroy(ioctx2);
3866 cmdstr = "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
3867 pool_name1 + "\"}";
3868 cmd[0] = (char *)cmdstr.c_str();
3869 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3870 cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
3871 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\"}";
3872 cmd[0] = (char *)cmdstr.c_str();
3873 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3874}
3875
3876TEST_F(TestLibRBD, LockingPP)
3877{
3878 librados::IoCtx ioctx;
3879 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3880
3881 {
3882 librbd::RBD rbd;
3883 librbd::Image image;
3884 int order = 0;
3885 std::string name = get_temp_image_name();
3886 uint64_t size = 2 << 20;
3887 std::string cookie1 = "foo";
3888 std::string cookie2 = "bar";
3889
3890 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3891 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3892
3893 // no lockers initially
3894 std::list<librbd::locker_t> lockers;
3895 std::string tag;
3896 bool exclusive;
3897 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3898 ASSERT_EQ(0u, lockers.size());
3899 ASSERT_EQ("", tag);
3900
3901 // exclusive lock is exclusive
3902 ASSERT_EQ(0, image.lock_exclusive(cookie1));
3903 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3904 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3905 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3906 ASSERT_EQ(-EBUSY, image.lock_shared(cookie1, "test"));
3907 ASSERT_EQ(-EBUSY, image.lock_shared("", "test"));
3908 ASSERT_EQ(-EBUSY, image.lock_shared("", ""));
3909
3910 // list exclusive
3911 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3912 ASSERT_TRUE(exclusive);
3913 ASSERT_EQ("", tag);
3914 ASSERT_EQ(1u, lockers.size());
3915 ASSERT_EQ(cookie1, lockers.front().cookie);
3916
3917 // unlock
3918 ASSERT_EQ(-ENOENT, image.unlock(""));
3919 ASSERT_EQ(-ENOENT, image.unlock(cookie2));
3920 ASSERT_EQ(0, image.unlock(cookie1));
3921 ASSERT_EQ(-ENOENT, image.unlock(cookie1));
3922 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3923 ASSERT_EQ(0u, lockers.size());
3924
3925 ASSERT_EQ(0, image.lock_shared(cookie1, ""));
3926 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3927 ASSERT_EQ(0, image.lock_shared(cookie2, ""));
3928 ASSERT_EQ(-EEXIST, image.lock_shared(cookie2, ""));
3929 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3930 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie2));
3931 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3932 ASSERT_EQ(-EBUSY, image.lock_exclusive("test"));
3933
3934 // list shared
3935 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3936 ASSERT_EQ(2u, lockers.size());
3937 }
3938
3939 ioctx.close();
3940}
3941
3942TEST_F(TestLibRBD, FlushAio)
3943{
3944 rados_ioctx_t ioctx;
3945 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3946
3947 rbd_image_t image;
3948 int order = 0;
3949 std::string name = get_temp_image_name();
3950 uint64_t size = 2 << 20;
3951 size_t num_aios = 256;
3952
3953 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3954 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3955
3956 char test_data[TEST_IO_SIZE + 1];
3957 size_t i;
3958 for (i = 0; i < TEST_IO_SIZE; ++i) {
3959 test_data[i] = (char) (rand() % (126 - 33) + 33);
3960 }
3961
3962 rbd_completion_t write_comps[num_aios];
3963 for (i = 0; i < num_aios; ++i) {
3964 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &write_comps[i]));
3965 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3966 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
3967 write_comps[i]));
3968 }
3969
3970 rbd_completion_t flush_comp;
3971 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &flush_comp));
3972 ASSERT_EQ(0, rbd_aio_flush(image, flush_comp));
3973 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp));
3974 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp));
3975 rbd_aio_release(flush_comp);
3976
3977 for (i = 0; i < num_aios; ++i) {
3978 ASSERT_EQ(1, rbd_aio_is_complete(write_comps[i]));
3979 rbd_aio_release(write_comps[i]);
3980 }
3981
3982 ASSERT_PASSED(validate_object_map, image);
3983 ASSERT_EQ(0, rbd_close(image));
3984 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
3985 rados_ioctx_destroy(ioctx);
3986}
3987
3988TEST_F(TestLibRBD, FlushAioPP)
3989{
3990 librados::IoCtx ioctx;
3991 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3992
3993 {
3994 librbd::RBD rbd;
3995 librbd::Image image;
3996 int order = 0;
3997 std::string name = get_temp_image_name();
3998 uint64_t size = 2 << 20;
3999 const size_t num_aios = 256;
4000
4001 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4002 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4003
4004 char test_data[TEST_IO_SIZE + 1];
4005 size_t i;
4006 for (i = 0; i < TEST_IO_SIZE; ++i) {
4007 test_data[i] = (char) (rand() % (126 - 33) + 33);
4008 }
4009 test_data[TEST_IO_SIZE] = '\0';
4010
4011 librbd::RBD::AioCompletion *write_comps[num_aios];
4012 ceph::bufferlist bls[num_aios];
4013 for (i = 0; i < num_aios; ++i) {
4014 bls[i].append(test_data, strlen(test_data));
4015 write_comps[i] = new librbd::RBD::AioCompletion(NULL, NULL);
4016 uint64_t offset = rand() % (size - TEST_IO_SIZE);
4017 ASSERT_EQ(0, image.aio_write(offset, TEST_IO_SIZE, bls[i],
4018 write_comps[i]));
4019 }
4020
4021 librbd::RBD::AioCompletion *flush_comp =
4022 new librbd::RBD::AioCompletion(NULL, NULL);
4023 ASSERT_EQ(0, image.aio_flush(flush_comp));
4024 ASSERT_EQ(0, flush_comp->wait_for_complete());
4025 ASSERT_EQ(1, flush_comp->is_complete());
4026 flush_comp->release();
4027
4028 for (i = 0; i < num_aios; ++i) {
4029 librbd::RBD::AioCompletion *comp = write_comps[i];
4030 ASSERT_EQ(1, comp->is_complete());
4031 comp->release();
4032 }
4033 ASSERT_PASSED(validate_object_map, image);
4034 }
4035
4036 ioctx.close();
4037}
4038
4039
4040int iterate_cb(uint64_t off, size_t len, int exists, void *arg)
4041{
4042 //cout << "iterate_cb " << off << "~" << len << std::endl;
4043 interval_set<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
4044 diff->insert(off, len);
4045 return 0;
4046}
4047
4048static int iterate_error_cb(uint64_t off, size_t len, int exists, void *arg)
4049{
4050 return -EINVAL;
4051}
4052
4053void scribble(librbd::Image& image, int n, int max, bool skip_discard,
4054 interval_set<uint64_t> *exists,
4055 interval_set<uint64_t> *what)
4056{
4057 uint64_t size;
4058 image.size(&size);
4059 interval_set<uint64_t> exists_at_start = *exists;
4060
4061 for (int i=0; i<n; i++) {
4062 uint64_t off = rand() % (size - max + 1);
4063 uint64_t len = 1 + rand() % max;
4064 if (!skip_discard && rand() % 4 == 0) {
4065 ASSERT_EQ((int)len, image.discard(off, len));
4066 interval_set<uint64_t> w;
4067 w.insert(off, len);
4068
4069 // the zeroed bit no longer exists...
4070 w.intersection_of(*exists);
4071 exists->subtract(w);
4072
4073 // the bits we discarded are no long written...
4074 interval_set<uint64_t> w2 = w;
4075 w2.intersection_of(*what);
4076 what->subtract(w2);
4077
4078 // except for the extents that existed at the start that we overwrote.
4079 interval_set<uint64_t> w3;
4080 w3.insert(off, len);
4081 w3.intersection_of(exists_at_start);
4082 what->union_of(w3);
4083
4084 } else {
4085 bufferlist bl;
4086 bl.append(buffer::create(len));
4087 bl.zero();
4088 ASSERT_EQ((int)len, image.write(off, len, bl));
4089 interval_set<uint64_t> w;
4090 w.insert(off, len);
4091 what->union_of(w);
4092 exists->union_of(w);
4093 }
4094 }
4095}
4096
4097interval_set<uint64_t> round_diff_interval(const interval_set<uint64_t>& diff,
4098 uint64_t object_size)
4099{
4100 if (object_size == 0) {
4101 return diff;
4102 }
4103
4104 interval_set<uint64_t> rounded_diff;
4105 for (interval_set<uint64_t>::const_iterator it = diff.begin();
4106 it != diff.end(); ++it) {
4107 uint64_t off = it.get_start();
4108 uint64_t len = it.get_len();
4109 off -= off % object_size;
4110 len += (object_size - (len % object_size));
4111 interval_set<uint64_t> interval;
4112 interval.insert(off, len);
4113 rounded_diff.union_of(interval);
4114 }
4115 return rounded_diff;
4116}
4117
4118template <typename T>
4119class DiffIterateTest : public TestLibRBD {
4120public:
4121 static const uint8_t whole_object = T::whole_object;
4122};
4123
4124template <bool _whole_object>
4125class DiffIterateParams {
4126public:
4127 static const uint8_t whole_object = _whole_object;
4128};
4129
4130typedef ::testing::Types<DiffIterateParams<false>,
4131 DiffIterateParams<true> > DiffIterateTypes;
9f95a23c 4132TYPED_TEST_SUITE(DiffIterateTest, DiffIterateTypes);
7c673cae
FG
4133
4134TYPED_TEST(DiffIterateTest, DiffIterate)
4135{
4136 librados::IoCtx ioctx;
4137 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4138
7c673cae
FG
4139 {
4140 librbd::RBD rbd;
4141 librbd::Image image;
4142 int order = 0;
4143 std::string name = this->get_temp_image_name();
4144 uint64_t size = 20 << 20;
4145
4146 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4147 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4148
f67539c2
TL
4149 bool skip_discard = this->is_skip_partial_discard_enabled(image);
4150
7c673cae
FG
4151 uint64_t object_size = 0;
4152 if (this->whole_object) {
4153 object_size = 1 << order;
4154 }
4155
4156 interval_set<uint64_t> exists;
4157 interval_set<uint64_t> one, two;
4158 scribble(image, 10, 102400, skip_discard, &exists, &one);
4159 cout << " wrote " << one << std::endl;
4160 ASSERT_EQ(0, image.snap_create("one"));
4161 scribble(image, 10, 102400, skip_discard, &exists, &two);
4162
4163 two = round_diff_interval(two, object_size);
4164 cout << " wrote " << two << std::endl;
4165
4166 interval_set<uint64_t> diff;
4167 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
4168 iterate_cb, (void *)&diff));
4169 cout << " diff was " << diff << std::endl;
4170 if (!two.subset_of(diff)) {
4171 interval_set<uint64_t> i;
4172 i.intersection_of(two, diff);
4173 interval_set<uint64_t> l = two;
4174 l.subtract(i);
4175 cout << " ... two - (two*diff) = " << l << std::endl;
4176 }
4177 ASSERT_TRUE(two.subset_of(diff));
4178 }
4179 ioctx.close();
4180}
4181
4182struct diff_extent {
4183 diff_extent(uint64_t _offset, uint64_t _length, bool _exists,
4184 uint64_t object_size) :
4185 offset(_offset), length(_length), exists(_exists)
4186 {
4187 if (object_size != 0) {
4188 offset -= offset % object_size;
4189 length = object_size;
4190 }
4191 }
4192 uint64_t offset;
4193 uint64_t length;
4194 bool exists;
4195 bool operator==(const diff_extent& o) const {
4196 return offset == o.offset && length == o.length && exists == o.exists;
4197 }
4198};
4199
4200ostream& operator<<(ostream & o, const diff_extent& e) {
4201 return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')';
4202}
4203
4204int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg)
4205{
4206 cout << "iterate_cb " << off << "~" << len << std::endl;
4207 vector<diff_extent> *diff = static_cast<vector<diff_extent> *>(arg);
4208 diff->push_back(diff_extent(off, len, exists, 0));
4209 return 0;
4210}
4211
4212TYPED_TEST(DiffIterateTest, DiffIterateDiscard)
4213{
4214 librados::IoCtx ioctx;
4215 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4216
4217 librbd::RBD rbd;
4218 librbd::Image image;
4219 int order = 0;
4220 std::string name = this->get_temp_image_name();
4221 uint64_t size = 20 << 20;
4222
4223 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4224 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4225
4226 uint64_t object_size = 0;
4227 if (this->whole_object) {
4228 object_size = 1 << order;
4229 }
4230 vector<diff_extent> extents;
4231 ceph::bufferlist bl;
4232
4233 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4234 vector_iterate_cb, (void *) &extents));
4235 ASSERT_EQ(0u, extents.size());
4236
4237 char data[256];
4238 memset(data, 1, sizeof(data));
4239 bl.append(data, 256);
4240 ASSERT_EQ(256, image.write(0, 256, bl));
4241 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4242 vector_iterate_cb, (void *) &extents));
4243 ASSERT_EQ(1u, extents.size());
4244 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4245
4246 int obj_ofs = 256;
4247 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
4248
4249 extents.clear();
4250 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4251 vector_iterate_cb, (void *) &extents));
4252 ASSERT_EQ(0u, extents.size());
4253
4254 ASSERT_EQ(0, image.snap_create("snap1"));
4255 ASSERT_EQ(256, image.write(0, 256, bl));
4256 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4257 vector_iterate_cb, (void *) &extents));
4258 ASSERT_EQ(1u, extents.size());
4259 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4260 ASSERT_EQ(0, image.snap_create("snap2"));
4261
4262 ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs));
4263
4264 extents.clear();
4265 ASSERT_EQ(0, image.snap_set("snap2"));
4266 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
4267 vector_iterate_cb, (void *) &extents));
4268 ASSERT_EQ(1u, extents.size());
4269 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4270
4271 ASSERT_EQ(0, image.snap_set(NULL));
4272 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
4273 ASSERT_EQ(0, image.snap_create("snap3"));
4274 ASSERT_EQ(0, image.snap_set("snap3"));
4275
4276 extents.clear();
4277 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
4278 vector_iterate_cb, (void *) &extents));
4279 ASSERT_EQ(1u, extents.size());
4280 ASSERT_EQ(diff_extent(0, 256, false, object_size), extents[0]);
4281 ASSERT_PASSED(this->validate_object_map, image);
4282}
4283
4284TYPED_TEST(DiffIterateTest, DiffIterateStress)
4285{
f67539c2 4286 REQUIRE(!is_rbd_pwl_enabled((CephContext *)this->_rados.cct()));
7c673cae
FG
4287 librados::IoCtx ioctx;
4288 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4289
7c673cae
FG
4290 librbd::RBD rbd;
4291 librbd::Image image;
4292 int order = 0;
4293 std::string name = this->get_temp_image_name();
4294 uint64_t size = 400 << 20;
4295
4296 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4297 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4298
f67539c2
TL
4299 bool skip_discard = this->is_skip_partial_discard_enabled(image);
4300
7c673cae
FG
4301 uint64_t object_size = 0;
4302 if (this->whole_object) {
4303 object_size = 1 << order;
4304 }
4305
4306 interval_set<uint64_t> curexists;
4307 vector<interval_set<uint64_t> > wrote;
4308 vector<interval_set<uint64_t> > exists;
4309 vector<string> snap;
4310 int n = 20;
4311 for (int i=0; i<n; i++) {
4312 interval_set<uint64_t> w;
4313 scribble(image, 10, 8192000, skip_discard, &curexists, &w);
4314 cout << " i=" << i << " exists " << curexists << " wrote " << w << std::endl;
4315 string s = "snap" + stringify(i);
4316 ASSERT_EQ(0, image.snap_create(s.c_str()));
4317 wrote.push_back(w);
4318 exists.push_back(curexists);
4319 snap.push_back(s);
4320 }
4321
4322 for (int h=0; h<n-1; h++) {
4323 for (int i=0; i<n-h-1; i++) {
4324 for (int j=(h==0 ? i+1 : n-1); j<n; j++) {
4325 interval_set<uint64_t> diff, actual, uex;
4326 for (int k=i+1; k<=j; k++)
4327 diff.union_of(wrote[k]);
4328 cout << "from " << i << " to "
4329 << (h != 0 ? string("HEAD") : stringify(j)) << " diff "
4330 << round_diff_interval(diff, object_size) << std::endl;
4331
4332 // limit to extents that exists both at the beginning and at the end
4333 uex.union_of(exists[i], exists[j]);
4334 diff.intersection_of(uex);
4335 diff = round_diff_interval(diff, object_size);
4336 cout << " limited diff " << diff << std::endl;
4337
4338 ASSERT_EQ(0, image.snap_set(h==0 ? snap[j].c_str() : NULL));
4339 ASSERT_EQ(0, image.diff_iterate2(snap[i].c_str(), 0, size, true,
4340 this->whole_object, iterate_cb,
4341 (void *)&actual));
4342 cout << " actual was " << actual << std::endl;
4343 if (!diff.subset_of(actual)) {
4344 interval_set<uint64_t> i;
4345 i.intersection_of(diff, actual);
4346 interval_set<uint64_t> l = diff;
4347 l.subtract(i);
4348 cout << " ... diff - (actual*diff) = " << l << std::endl;
4349 }
4350 ASSERT_TRUE(diff.subset_of(actual));
4351 }
4352 }
4353 ASSERT_EQ(0, image.snap_set(NULL));
4354 ASSERT_EQ(0, image.snap_remove(snap[n-h-1].c_str()));
4355 }
4356
4357 ASSERT_PASSED(this->validate_object_map, image);
4358}
4359
4360TYPED_TEST(DiffIterateTest, DiffIterateRegression6926)
4361{
4362 librados::IoCtx ioctx;
4363 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4364
4365 librbd::RBD rbd;
4366 librbd::Image image;
4367 int order = 0;
4368 std::string name = this->get_temp_image_name();
4369 uint64_t size = 20 << 20;
4370
4371 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4372 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4373
4374 uint64_t object_size = 0;
4375 if (this->whole_object) {
4376 object_size = 1 << order;
4377 }
4378 vector<diff_extent> extents;
4379 ceph::bufferlist bl;
4380
4381 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4382 vector_iterate_cb, (void *) &extents));
4383 ASSERT_EQ(0u, extents.size());
4384
4385 ASSERT_EQ(0, image.snap_create("snap1"));
4386 char data[256];
4387 memset(data, 1, sizeof(data));
4388 bl.append(data, 256);
4389 ASSERT_EQ(256, image.write(0, 256, bl));
4390
4391 extents.clear();
4392 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4393 vector_iterate_cb, (void *) &extents));
4394 ASSERT_EQ(1u, extents.size());
4395 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4396
4397 ASSERT_EQ(0, image.snap_set("snap1"));
4398 extents.clear();
4399 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4400 vector_iterate_cb, (void *) &extents));
4401 ASSERT_EQ(static_cast<size_t>(0), extents.size());
4402}
4403
4404TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
4405{
4406 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4407
4408 librados::IoCtx ioctx;
4409 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4410
7c673cae
FG
4411 librbd::RBD rbd;
4412 librbd::Image image;
4413 std::string name = this->get_temp_image_name();
4414 uint64_t size = 20 << 20;
4415 int order = 0;
4416
4417 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4418 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4419
f67539c2
TL
4420 bool skip_discard = this->is_skip_partial_discard_enabled(image);
4421
7c673cae
FG
4422 uint64_t object_size = 0;
4423 if (this->whole_object) {
4424 object_size = 1 << order;
4425 }
4426
4427 bufferlist bl;
4428 bl.append(buffer::create(size));
4429 bl.zero();
4430 interval_set<uint64_t> one;
4431 one.insert(0, size);
4432 ASSERT_EQ((int)size, image.write(0, size, bl));
4433 ASSERT_EQ(0, image.snap_create("one"));
4434 ASSERT_EQ(0, image.snap_protect("one"));
4435
4436 std::string clone_name = this->get_temp_image_name();
4437 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
4438 RBD_FEATURE_LAYERING, &order));
4439 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
4440
4441 interval_set<uint64_t> exists;
4442 interval_set<uint64_t> two;
4443 scribble(image, 10, 102400, skip_discard, &exists, &two);
4444 two = round_diff_interval(two, object_size);
4445 cout << " wrote " << two << " to clone" << std::endl;
4446
4447 interval_set<uint64_t> diff;
4448 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, false, this->whole_object,
4449 iterate_cb, (void *)&diff));
4450 cout << " diff was " << diff << std::endl;
4451 if (!this->whole_object) {
4452 ASSERT_FALSE(one.subset_of(diff));
4453 }
4454 ASSERT_TRUE(two.subset_of(diff));
4455}
4456
4457TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
4458{
4459 librados::IoCtx ioctx;
4460 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4461
7c673cae
FG
4462 {
4463 librbd::RBD rbd;
4464 librbd::Image image;
4465 int order = 0;
4466 std::string name = this->get_temp_image_name();
4467 uint64_t size = 20 << 20;
4468
4469 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4470 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4471
f67539c2
TL
4472 bool skip_discard = this->is_skip_partial_discard_enabled(image);
4473
7c673cae
FG
4474 interval_set<uint64_t> exists;
4475 interval_set<uint64_t> one;
4476 scribble(image, 10, 102400, skip_discard, &exists, &one);
4477 cout << " wrote " << one << std::endl;
4478
4479 interval_set<uint64_t> diff;
4480 ASSERT_EQ(-EINVAL, image.diff_iterate2(NULL, 0, size, true,
4481 this->whole_object,
4482 iterate_error_cb, NULL));
4483 }
4484 ioctx.close();
4485}
4486
4487TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
4488{
4489 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4490
4491 librados::IoCtx ioctx;
4492 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4493
7c673cae
FG
4494 librbd::RBD rbd;
4495 librbd::Image image;
4496 std::string name = this->get_temp_image_name();
4497 uint64_t size = 20 << 20;
4498 int order = 0;
4499
4500 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4501 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4502
f67539c2
TL
4503 bool skip_discard = this->is_skip_partial_discard_enabled(image);
4504
7c673cae
FG
4505 uint64_t object_size = 0;
4506 if (this->whole_object) {
4507 object_size = 1 << order;
4508 }
4509
4510 interval_set<uint64_t> exists;
4511 interval_set<uint64_t> one;
4512 scribble(image, 10, 102400, skip_discard, &exists, &one);
4513 ASSERT_EQ(0, image.snap_create("one"));
4514
4515 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
4516 ASSERT_EQ(0, image.snap_create("two"));
4517 ASSERT_EQ(0, image.snap_protect("two"));
4518 exists.clear();
4519 one.clear();
4520
4521 std::string clone_name = this->get_temp_image_name();
4522 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "two", ioctx,
4523 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
4524 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
4525
4526 interval_set<uint64_t> two;
4527 scribble(image, 10, 102400, skip_discard, &exists, &two);
4528 two = round_diff_interval(two, object_size);
4529
4530 interval_set<uint64_t> diff;
4531 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4532 iterate_cb, (void *)&diff));
4533 ASSERT_TRUE(two.subset_of(diff));
4534}
4535
4536TEST_F(TestLibRBD, ZeroLengthWrite)
4537{
4538 rados_ioctx_t ioctx;
4539 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4540
4541 rbd_image_t image;
4542 int order = 0;
4543 std::string name = get_temp_image_name();
4544 uint64_t size = 2 << 20;
4545
4546 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4547 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4548
4549 char read_data[1];
4550 ASSERT_EQ(0, rbd_write(image, 0, 0, NULL));
4551 ASSERT_EQ(1, rbd_read(image, 0, 1, read_data));
4552 ASSERT_EQ('\0', read_data[0]);
4553
4554 ASSERT_PASSED(validate_object_map, image);
4555 ASSERT_EQ(0, rbd_close(image));
4556
4557 rados_ioctx_destroy(ioctx);
4558}
4559
4560
4561TEST_F(TestLibRBD, ZeroLengthDiscard)
4562{
4563 rados_ioctx_t ioctx;
4564 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4565
4566 rbd_image_t image;
4567 int order = 0;
4568 std::string name = get_temp_image_name();
4569 uint64_t size = 2 << 20;
4570
4571 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4572 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4573
4574 const char data[] = "blah";
4575 char read_data[sizeof(data)];
4576 ASSERT_EQ((int)strlen(data), rbd_write(image, 0, strlen(data), data));
4577 ASSERT_EQ(0, rbd_discard(image, 0, 0));
4578 ASSERT_EQ((int)strlen(data), rbd_read(image, 0, strlen(data), read_data));
4579 ASSERT_EQ(0, memcmp(data, read_data, strlen(data)));
4580
4581 ASSERT_PASSED(validate_object_map, image);
4582 ASSERT_EQ(0, rbd_close(image));
4583
4584 rados_ioctx_destroy(ioctx);
4585}
4586
4587TEST_F(TestLibRBD, ZeroLengthRead)
4588{
4589 rados_ioctx_t ioctx;
4590 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4591
4592 rbd_image_t image;
4593 int order = 0;
4594 std::string name = get_temp_image_name();
4595 uint64_t size = 2 << 20;
4596
4597 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4598 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4599
4600 char read_data[1];
4601 ASSERT_EQ(0, rbd_read(image, 0, 0, read_data));
4602
4603 ASSERT_EQ(0, rbd_close(image));
4604
4605 rados_ioctx_destroy(ioctx);
4606}
4607
4608TEST_F(TestLibRBD, LargeCacheRead)
4609{
4610 std::string config_value;
4611 ASSERT_EQ(0, _rados.conf_get("rbd_cache", config_value));
4612 if (config_value == "false") {
4613 std::cout << "SKIPPING due to disabled cache" << std::endl;
4614 return;
4615 }
4616
4617 rados_ioctx_t ioctx;
4618 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4619
4620 uint32_t new_cache_size = 1 << 20;
4621 std::string orig_cache_size;
4622 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", orig_cache_size));
4623 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size",
4624 stringify(new_cache_size).c_str()));
4625 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", config_value));
4626 ASSERT_EQ(stringify(new_cache_size), config_value);
4627 BOOST_SCOPE_EXIT( (orig_cache_size) ) {
4628 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size", orig_cache_size.c_str()));
4629 } BOOST_SCOPE_EXIT_END;
4630
4631 rbd_image_t image;
4632 int order = 21;
4633 std::string name = get_temp_image_name();
4634 uint64_t size = 1 << order;
4635
4636 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4637 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4638
4639 std::string buffer(1 << order, '1');
4640
4641 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
4642 rbd_write(image, 0, buffer.size(), buffer.c_str()));
4643
4644 ASSERT_EQ(0, rbd_invalidate_cache(image));
4645
4646 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
4647 rbd_read(image, 0, buffer.size(), &buffer[0]));
4648
4649 ASSERT_EQ(0, rbd_close(image));
4650
4651 rados_ioctx_destroy(ioctx);
4652}
4653
4654TEST_F(TestLibRBD, TestPendingAio)
4655{
4656 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4657
4658 rados_ioctx_t ioctx;
4659 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4660
4661 bool old_format;
4662 uint64_t features;
4663 rbd_image_t image;
4664 int order = 0;
4665
4666 ASSERT_EQ(0, get_features(&old_format, &features));
4667 ASSERT_FALSE(old_format);
4668
4669 std::string name = get_temp_image_name();
4670
4671 uint64_t size = 4 << 20;
4672 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
4673 false, features));
4674 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4675
f67539c2
TL
4676 ASSERT_EQ(0, rbd_invalidate_cache(image));
4677
7c673cae
FG
4678 char test_data[TEST_IO_SIZE];
4679 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
4680 test_data[i] = (char) (rand() % (126 - 33) + 33);
4681 }
4682
4683 size_t num_aios = 256;
4684 rbd_completion_t comps[num_aios];
4685 for (size_t i = 0; i < num_aios; ++i) {
4686 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
4687 uint64_t offset = rand() % (size - TEST_IO_SIZE);
4688 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
4689 comps[i]));
4690 }
4691 for (size_t i = 0; i < num_aios; ++i) {
4692 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps[i]));
4693 rbd_aio_release(comps[i]);
4694 }
4695 ASSERT_EQ(0, rbd_invalidate_cache(image));
4696
4697 for (size_t i = 0; i < num_aios; ++i) {
4698 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
4699 uint64_t offset = rand() % (size - TEST_IO_SIZE);
4700 ASSERT_LE(0, rbd_aio_read(image, offset, TEST_IO_SIZE, test_data,
4701 comps[i]));
4702 }
4703
4704 ASSERT_PASSED(validate_object_map, image);
4705 ASSERT_EQ(0, rbd_close(image));
4706 for (size_t i = 0; i < num_aios; ++i) {
4707 ASSERT_EQ(1, rbd_aio_is_complete(comps[i]));
4708 rbd_aio_release(comps[i]);
4709 }
4710
4711 rados_ioctx_destroy(ioctx);
4712}
4713
11fdf7f2
TL
4714void compare_and_write_copyup(librados::IoCtx &ioctx, bool deep_copyup,
4715 bool *passed)
4716{
4717 librbd::RBD rbd;
4718 std::string parent_name = TestLibRBD::get_temp_image_name();
4719 uint64_t size = 2 << 20;
4720 int order = 0;
4721 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4722
4723 librbd::Image parent_image;
4724 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4725
4726 bufferlist bl;
4727 bl.append(std::string(4096, '1'));
4728 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
4729
4730 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4731 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4732
4733 uint64_t features;
4734 ASSERT_EQ(0, parent_image.features(&features));
4735
4736 std::string clone_name = TestLibRBD::get_temp_image_name();
4737 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4738 clone_name.c_str(), features, &order));
4739
4740 librbd::Image clone_image;
4741 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
4742 if (deep_copyup) {
4743 ASSERT_EQ(0, clone_image.snap_create("snap1"));
4744 }
4745
4746 bufferlist cmp_bl;
4747 cmp_bl.append(std::string(96, '1'));
4748 bufferlist write_bl;
4749 write_bl.append(std::string(512, '2'));
4750 uint64_t mismatch_off;
4751 ASSERT_EQ((ssize_t)write_bl.length(),
4752 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
4753 write_bl, &mismatch_off, 0));
4754
4755 bufferlist read_bl;
4756 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
4757
4758 bufferlist expected_bl;
4759 expected_bl.append(std::string(512, '1'));
4760 expected_bl.append(std::string(512, '2'));
4761 expected_bl.append(std::string(3072, '1'));
4762 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
4763 *passed = true;
4764}
4765
4766TEST_F(TestLibRBD, CompareAndWriteCopyup)
4767{
4768 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4769
4770 librados::IoCtx ioctx;
4771 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4772
4773 ASSERT_PASSED(compare_and_write_copyup, ioctx, false);
4774 ASSERT_PASSED(compare_and_write_copyup, ioctx, true);
4775}
4776
4777void compare_and_write_copyup_mismatch(librados::IoCtx &ioctx,
4778 bool deep_copyup, bool *passed)
4779{
4780 librbd::RBD rbd;
4781 std::string parent_name = TestLibRBD::get_temp_image_name();
4782 uint64_t size = 2 << 20;
4783 int order = 0;
4784 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4785
4786 librbd::Image parent_image;
4787 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4788
4789 bufferlist bl;
4790 bl.append(std::string(4096, '1'));
4791 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
4792
4793 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4794 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4795
4796 uint64_t features;
4797 ASSERT_EQ(0, parent_image.features(&features));
4798
4799 std::string clone_name = TestLibRBD::get_temp_image_name();
4800 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4801 clone_name.c_str(), features, &order));
4802
4803 librbd::Image clone_image;
4804 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
4805 if (deep_copyup) {
4806 ASSERT_EQ(0, clone_image.snap_create("snap1"));
4807 }
4808
4809 bufferlist cmp_bl;
4810 cmp_bl.append(std::string(48, '1'));
4811 cmp_bl.append(std::string(48, '3'));
4812 bufferlist write_bl;
4813 write_bl.append(std::string(512, '2'));
4814 uint64_t mismatch_off;
4815 ASSERT_EQ(-EILSEQ,
4816 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
4817 write_bl, &mismatch_off, 0));
4818 ASSERT_EQ(48U, mismatch_off);
4819
4820 bufferlist read_bl;
4821 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
4822
4823 ASSERT_TRUE(bl.contents_equal(read_bl));
4824 *passed = true;
4825}
4826
4827TEST_F(TestLibRBD, CompareAndWriteCopyupMismatch)
4828{
4829 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4830
4831 librados::IoCtx ioctx;
4832 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4833
4834 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, false);
4835 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, true);
4836}
4837
7c673cae
FG
4838TEST_F(TestLibRBD, Flatten)
4839{
4840 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4841
4842 librados::IoCtx ioctx;
4843 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4844
4845 librbd::RBD rbd;
4846 std::string parent_name = get_temp_image_name();
4847 uint64_t size = 2 << 20;
4848 int order = 0;
4849 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4850
4851 librbd::Image parent_image;
4852 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4853
4854 bufferlist bl;
4855 bl.append(std::string(4096, '1'));
4856 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
4857
4858 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4859 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4860
4861 uint64_t features;
4862 ASSERT_EQ(0, parent_image.features(&features));
4863
4864 std::string clone_name = get_temp_image_name();
4865 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4866 clone_name.c_str(), features, &order));
4867
4868 librbd::Image clone_image;
4869 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
4870 ASSERT_EQ(0, clone_image.flatten());
4871
4872 librbd::RBD::AioCompletion *read_comp =
4873 new librbd::RBD::AioCompletion(NULL, NULL);
4874 bufferlist read_bl;
4875 clone_image.aio_read(0, bl.length(), read_bl, read_comp);
4876 ASSERT_EQ(0, read_comp->wait_for_complete());
4877 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
4878 read_comp->release();
4879 ASSERT_TRUE(bl.contents_equal(read_bl));
4880
4881 ASSERT_PASSED(validate_object_map, clone_image);
4882}
4883
11fdf7f2
TL
4884TEST_F(TestLibRBD, Sparsify)
4885{
4886 rados_ioctx_t ioctx;
4887 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
4888 BOOST_SCOPE_EXIT_ALL(&ioctx) {
4889 rados_ioctx_destroy(ioctx);
4890 };
4891
4892 const size_t CHUNK_SIZE = 4096 * 2;
4893 rbd_image_t image;
4894 int order = 0;
4895 std::string name = get_temp_image_name();
4896 uint64_t size = CHUNK_SIZE * 1024;
4897
4898 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4899 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4900 BOOST_SCOPE_EXIT_ALL(&image) {
4901 rbd_close(image);
4902 };
4903
4904 char test_data[4 * CHUNK_SIZE + 1];
4905 for (size_t i = 0; i < 4 ; ++i) {
4906 for (size_t j = 0; j < CHUNK_SIZE; j++) {
4907 if (i % 2) {
4908 test_data[i * CHUNK_SIZE + j] = (char)(rand() % (126 - 33) + 33);
4909 } else {
4910 test_data[i * CHUNK_SIZE + j] = '\0';
4911 }
4912 }
4913 }
4914 test_data[4 * CHUNK_SIZE] = '\0';
4915
4916 ASSERT_PASSED(write_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
4917 ASSERT_EQ(0, rbd_flush(image));
4918
4919 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 16));
4920 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 1 << (order + 1)));
4921 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 4096 + 1));
4922 ASSERT_EQ(0, rbd_sparsify(image, 4096));
4923
4924 ASSERT_PASSED(read_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
4925}
4926
4927TEST_F(TestLibRBD, SparsifyPP)
4928{
4929 librados::IoCtx ioctx;
4930 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4931
4932 librbd::RBD rbd;
4933 std::string name = get_temp_image_name();
4934 uint64_t size = 12 * 1024 * 1024;
4935 int order = 0;
4936 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4937
4938 librbd::Image image;
4939 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
4940
4941 bufferlist bl;
4942 bl.append(std::string(4096, '\0'));
4943 bl.append(std::string(4096, '1'));
4944 bl.append(std::string(4096, '\0'));
4945 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
4946 ASSERT_EQ(0, image.flush());
4947
4948 ASSERT_EQ(-EINVAL, image.sparsify(16));
4949 ASSERT_EQ(-EINVAL, image.sparsify(1 << (order + 1)));
4950 ASSERT_EQ(-EINVAL, image.sparsify(4096 + 1));
4951 ASSERT_EQ(0, image.sparsify(4096));
4952
4953 bufferlist read_bl;
4954 ASSERT_EQ((ssize_t)bl.length(), image.read(0, bl.length(), read_bl));
4955 ASSERT_TRUE(bl.contents_equal(read_bl));
4956
4957 ASSERT_PASSED(validate_object_map, image);
4958}
4959
7c673cae
FG
4960TEST_F(TestLibRBD, SnapshotLimit)
4961{
4962 rados_ioctx_t ioctx;
4963 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4964
4965 rbd_image_t image;
4966 int order = 0;
4967 std::string name = get_temp_image_name();
4968 uint64_t size = 2 << 20;
4969 uint64_t limit;
4970
4971 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4972 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4973
4974 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
4975 ASSERT_EQ(UINT64_MAX, limit);
4976 ASSERT_EQ(0, rbd_snap_set_limit(image, 2));
4977 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
4978 ASSERT_EQ(2U, limit);
4979
4980 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
11fdf7f2 4981 ASSERT_EQ(-ERANGE, rbd_snap_set_limit(image, 0));
7c673cae
FG
4982 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
4983 ASSERT_EQ(-EDQUOT, rbd_snap_create(image, "snap3"));
4984 ASSERT_EQ(0, rbd_snap_set_limit(image, UINT64_MAX));
4985 ASSERT_EQ(0, rbd_snap_create(image, "snap3"));
4986 ASSERT_EQ(0, rbd_close(image));
4987
4988 rados_ioctx_destroy(ioctx);
4989}
4990
4991
4992TEST_F(TestLibRBD, SnapshotLimitPP)
4993{
4994 librados::IoCtx ioctx;
4995 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4996
4997 {
4998 librbd::RBD rbd;
4999 librbd::Image image;
5000 std::string name = get_temp_image_name();
5001 uint64_t size = 2 << 20;
5002 int order = 0;
5003 uint64_t limit;
5004
5005 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5006 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5007
5008 ASSERT_EQ(0, image.snap_get_limit(&limit));
5009 ASSERT_EQ(UINT64_MAX, limit);
5010 ASSERT_EQ(0, image.snap_set_limit(2));
5011 ASSERT_EQ(0, image.snap_get_limit(&limit));
5012 ASSERT_EQ(2U, limit);
5013
5014 ASSERT_EQ(0, image.snap_create("snap1"));
11fdf7f2 5015 ASSERT_EQ(-ERANGE, image.snap_set_limit(0));
7c673cae
FG
5016 ASSERT_EQ(0, image.snap_create("snap2"));
5017 ASSERT_EQ(-EDQUOT, image.snap_create("snap3"));
5018 ASSERT_EQ(0, image.snap_set_limit(UINT64_MAX));
5019 ASSERT_EQ(0, image.snap_create("snap3"));
5020 }
5021
5022 ioctx.close();
5023}
5024
5025TEST_F(TestLibRBD, RebuildObjectMapViaLockOwner)
5026{
5027 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
5028
5029 librados::IoCtx ioctx;
5030 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5031
5032 librbd::RBD rbd;
5033 std::string name = get_temp_image_name();
5034 uint64_t size = 2 << 20;
5035 int order = 0;
5036 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5037
5038 std::string object_map_oid;
5039 {
5040 librbd::Image image;
5041 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5042
5043 std::string image_id;
5044 ASSERT_EQ(0, get_image_id(image, &image_id));
5045 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
5046 }
5047
5048 // corrupt the object map
5049 bufferlist bl;
5050 bl.append("foo");
5051 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
5052
5053 librbd::Image image1;
5054 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5055
5056 bool lock_owner;
5057 bl.clear();
5058 ASSERT_EQ(0, image1.write(0, 0, bl));
5059 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5060 ASSERT_TRUE(lock_owner);
5061
5062 uint64_t flags;
5063 ASSERT_EQ(0, image1.get_flags(&flags));
5064 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
5065
5066 librbd::Image image2;
5067 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5068 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5069 ASSERT_FALSE(lock_owner);
5070
5071 PrintProgress prog_ctx;
5072 ASSERT_EQ(0, image2.rebuild_object_map(prog_ctx));
5073 ASSERT_PASSED(validate_object_map, image1);
5074 ASSERT_PASSED(validate_object_map, image2);
5075}
5076
5077TEST_F(TestLibRBD, RenameViaLockOwner)
5078{
cd265ab1 5079 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7c673cae
FG
5080
5081 librados::IoCtx ioctx;
5082 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5083
5084 librbd::RBD rbd;
5085 std::string name = get_temp_image_name();
5086 uint64_t size = 2 << 20;
5087 int order = 0;
5088 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5089
5090 librbd::Image image1;
5091 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5092
cd265ab1
TL
5093 bool lock_owner;
5094 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5095 ASSERT_FALSE(lock_owner);
5096
5097 std::string new_name = get_temp_image_name();
5098 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
5099 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5100 ASSERT_FALSE(lock_owner);
5101
7c673cae
FG
5102 bufferlist bl;
5103 ASSERT_EQ(0, image1.write(0, 0, bl));
7c673cae
FG
5104 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5105 ASSERT_TRUE(lock_owner);
5106
cd265ab1
TL
5107 name = new_name;
5108 new_name = get_temp_image_name();
7c673cae
FG
5109 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
5110 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5111 ASSERT_TRUE(lock_owner);
5112
5113 librbd::Image image2;
5114 ASSERT_EQ(0, rbd.open(ioctx, image2, new_name.c_str(), NULL));
5115}
5116
5117TEST_F(TestLibRBD, SnapCreateViaLockOwner)
5118{
94b18763 5119 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7c673cae
FG
5120
5121 librados::IoCtx ioctx;
5122 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5123
5124 librbd::RBD rbd;
5125 std::string name = get_temp_image_name();
5126 uint64_t size = 2 << 20;
5127 int order = 0;
5128 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5129
5130 librbd::Image image1;
5131 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5132
5133 // switch to writeback cache
5134 ASSERT_EQ(0, image1.flush());
5135
5136 bufferlist bl;
5137 bl.append(std::string(4096, '1'));
5138 ASSERT_EQ((ssize_t)bl.length(), image1.write(0, bl.length(), bl));
5139
5140 bool lock_owner;
5141 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5142 ASSERT_TRUE(lock_owner);
5143
5144 librbd::Image image2;
5145 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5146
5147 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5148 ASSERT_FALSE(lock_owner);
5149
5150 ASSERT_EQ(0, image2.snap_create("snap1"));
5151 bool exists;
5152 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5153 ASSERT_TRUE(exists);
5154 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
5155 ASSERT_TRUE(exists);
5156
5157 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5158 ASSERT_TRUE(lock_owner);
5159}
5160
5161TEST_F(TestLibRBD, SnapRemoveViaLockOwner)
5162{
94b18763 5163 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
7c673cae
FG
5164
5165 librados::IoCtx ioctx;
5166 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5167
5168 librbd::RBD rbd;
5169 std::string name = get_temp_image_name();
5170 uint64_t size = 2 << 20;
5171 int order = 0;
5172 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5173
5174 librbd::Image image1;
5175 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5176
5177 bufferlist bl;
5178 ASSERT_EQ(0, image1.write(0, 0, bl));
5179 ASSERT_EQ(0, image1.snap_create("snap1"));
5180
5181 bool lock_owner;
5182 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5183 ASSERT_TRUE(lock_owner);
5184
5185 librbd::Image image2;
5186 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5187
5188 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5189 ASSERT_FALSE(lock_owner);
5190
5191 ASSERT_EQ(0, image2.snap_remove("snap1"));
5192 bool exists;
5193 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5194 ASSERT_FALSE(exists);
5195 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
5196 ASSERT_FALSE(exists);
5197
5198 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5199 ASSERT_TRUE(lock_owner);
5200}
5201
91327a77
AA
5202TEST_F(TestLibRBD, EnableJournalingViaLockOwner)
5203{
5204 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
5205
5206 librados::IoCtx ioctx;
5207 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5208
5209 librbd::RBD rbd;
5210 std::string name = get_temp_image_name();
5211 uint64_t size = 2 << 20;
5212 int order = 0;
5213 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5214
5215 librbd::Image image1;
5216 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5217
5218 bufferlist bl;
5219 ASSERT_EQ(0, image1.write(0, 0, bl));
5220
5221 bool lock_owner;
5222 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5223 ASSERT_TRUE(lock_owner);
5224
5225 librbd::Image image2;
5226 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5227
5228 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, false));
5229
5230 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5231 ASSERT_TRUE(lock_owner);
5232 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5233 ASSERT_FALSE(lock_owner);
5234
5235 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, true));
5236
5237 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5238 ASSERT_FALSE(lock_owner);
5239 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5240 ASSERT_TRUE(lock_owner);
5241}
5242
7c673cae
FG
5243TEST_F(TestLibRBD, SnapRemove2)
5244{
5245 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5246
5247 librados::IoCtx ioctx;
5248 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5249
5250 librbd::RBD rbd;
5251 std::string name = get_temp_image_name();
5252 uint64_t size = 2 << 20;
5253 int order = 0;
5254 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5255
5256 librbd::Image image1;
5257 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5258
5259 bufferlist bl;
5260 ASSERT_EQ(0, image1.write(0, 0, bl));
5261 ASSERT_EQ(0, image1.snap_create("snap1"));
5262 bool exists;
5263 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5264 ASSERT_TRUE(exists);
5265 ASSERT_EQ(0, image1.snap_protect("snap1"));
5266 bool is_protected;
5267 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5268 ASSERT_TRUE(is_protected);
5269
5270 uint64_t features;
5271 ASSERT_EQ(0, image1.features(&features));
5272
5273 std::string child_name = get_temp_image_name();
5274 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
5275 child_name.c_str(), features, &order));
5276
5277 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5278 ASSERT_TRUE(exists);
5279 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5280 ASSERT_TRUE(is_protected);
5281
5282 ASSERT_EQ(-EBUSY, image1.snap_remove("snap1"));
5283 PrintProgress pp;
5284 ASSERT_EQ(0, image1.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE, pp));
5285 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5286 ASSERT_FALSE(exists);
5287}
5288
5289TEST_F(TestLibRBD, SnapRenameViaLockOwner)
5290{
5291 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
5292
5293 librados::IoCtx ioctx;
5294 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5295
5296 librbd::RBD rbd;
5297 std::string name = get_temp_image_name();
5298 uint64_t size = 2 << 20;
5299 int order = 0;
5300 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5301
5302 librbd::Image image1;
5303 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5304
5305 bufferlist bl;
5306 ASSERT_EQ(0, image1.write(0, 0, bl));
5307 ASSERT_EQ(0, image1.snap_create("snap1"));
5308
5309 bool lock_owner;
5310 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5311 ASSERT_TRUE(lock_owner);
5312
5313 librbd::Image image2;
5314 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5315
5316 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5317 ASSERT_FALSE(lock_owner);
5318
5319 ASSERT_EQ(0, image2.snap_rename("snap1", "snap1-rename"));
5320 bool exists;
5321 ASSERT_EQ(0, image1.snap_exists2("snap1-rename", &exists));
5322 ASSERT_TRUE(exists);
5323 ASSERT_EQ(0, image2.snap_exists2("snap1-rename", &exists));
5324 ASSERT_TRUE(exists);
5325
5326 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5327 ASSERT_TRUE(lock_owner);
5328}
5329
5330TEST_F(TestLibRBD, SnapProtectViaLockOwner)
5331{
5332 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
5333
5334 librados::IoCtx ioctx;
5335 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5336
5337 librbd::RBD rbd;
5338 std::string name = get_temp_image_name();
5339 uint64_t size = 2 << 20;
5340 int order = 0;
5341 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5342
5343 librbd::Image image1;
5344 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5345
5346 bufferlist bl;
5347 ASSERT_EQ(0, image1.write(0, 0, bl));
5348
5349 bool lock_owner;
5350 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5351 ASSERT_TRUE(lock_owner);
5352 ASSERT_EQ(0, image1.snap_create("snap1"));
5353
5354 librbd::Image image2;
5355 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5356
5357 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5358 ASSERT_FALSE(lock_owner);
5359
5360 ASSERT_EQ(0, image2.snap_protect("snap1"));
5361 bool is_protected;
5362 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
5363 ASSERT_TRUE(is_protected);
5364 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5365 ASSERT_TRUE(is_protected);
5366
5367 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5368 ASSERT_TRUE(lock_owner);
5369}
5370
5371TEST_F(TestLibRBD, SnapUnprotectViaLockOwner)
5372{
5373 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
5374
5375 librados::IoCtx ioctx;
5376 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5377
5378 librbd::RBD rbd;
5379 std::string name = get_temp_image_name();
5380 uint64_t size = 2 << 20;
5381 int order = 0;
5382 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5383
5384 librbd::Image image1;
5385 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5386
5387 bufferlist bl;
5388 ASSERT_EQ(0, image1.write(0, 0, bl));
5389
5390 bool lock_owner;
5391 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5392 ASSERT_TRUE(lock_owner);
5393 ASSERT_EQ(0, image1.snap_create("snap1"));
5394 ASSERT_EQ(0, image1.snap_protect("snap1"));
5395 bool is_protected;
5396 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5397 ASSERT_TRUE(is_protected);
5398
5399 librbd::Image image2;
5400 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5401
5402 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5403 ASSERT_FALSE(lock_owner);
5404
5405 ASSERT_EQ(0, image2.snap_unprotect("snap1"));
5406 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
5407 ASSERT_FALSE(is_protected);
5408 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5409 ASSERT_FALSE(is_protected);
5410
5411 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5412 ASSERT_TRUE(lock_owner);
5413}
5414
5415TEST_F(TestLibRBD, FlattenViaLockOwner)
5416{
5417 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5418
5419 librados::IoCtx ioctx;
5420 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5421
5422 librbd::RBD rbd;
5423 std::string parent_name = get_temp_image_name();
5424 uint64_t size = 2 << 20;
5425 int order = 0;
5426 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
5427
5428 librbd::Image parent_image;
5429 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
5430 ASSERT_EQ(0, parent_image.snap_create("snap1"));
5431 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
5432
5433 uint64_t features;
5434 ASSERT_EQ(0, parent_image.features(&features));
5435
5436 std::string name = get_temp_image_name();
5437 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
5438 name.c_str(), features, &order));
5439
5440 librbd::Image image1;
5441 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5442
5443 bufferlist bl;
5444 ASSERT_EQ(0, image1.write(0, 0, bl));
5445
5446 bool lock_owner;
5447 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5448 ASSERT_TRUE(lock_owner);
5449
5450 librbd::Image image2;
5451 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5452
5453 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5454 ASSERT_FALSE(lock_owner);
5455
5456 ASSERT_EQ(0, image2.flatten());
5457
5458 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5459 ASSERT_TRUE(lock_owner);
5460 ASSERT_PASSED(validate_object_map, image1);
5461}
5462
5463TEST_F(TestLibRBD, ResizeViaLockOwner)
5464{
5465 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5466
5467 librados::IoCtx ioctx;
5468 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5469
5470 librbd::RBD rbd;
5471 std::string name = get_temp_image_name();
5472 uint64_t size = 2 << 20;
5473 int order = 0;
5474 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5475
5476 librbd::Image image1;
5477 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5478
5479 bufferlist bl;
5480 ASSERT_EQ(0, image1.write(0, 0, bl));
5481
5482 bool lock_owner;
5483 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5484 ASSERT_TRUE(lock_owner);
5485
5486 librbd::Image image2;
5487 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5488
5489 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5490 ASSERT_FALSE(lock_owner);
5491
5492 ASSERT_EQ(0, image2.resize(0));
5493
5494 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5495 ASSERT_TRUE(lock_owner);
5496 ASSERT_PASSED(validate_object_map, image1);
5497}
5498
11fdf7f2
TL
5499TEST_F(TestLibRBD, SparsifyViaLockOwner)
5500{
5501 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5502
5503 librados::IoCtx ioctx;
5504 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5505
5506 librbd::RBD rbd;
5507 std::string name = get_temp_image_name();
5508 uint64_t size = 2 << 20;
5509 int order = 0;
5510 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5511
5512 librbd::Image image1;
5513 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5514
5515 bufferlist bl;
5516 ASSERT_EQ(0, image1.write(0, 0, bl));
5517
5518 bool lock_owner;
5519 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5520 ASSERT_TRUE(lock_owner);
5521
5522 librbd::Image image2;
5523 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5524
5525 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5526 ASSERT_FALSE(lock_owner);
5527
5528 ASSERT_EQ(0, image2.sparsify(4096));
5529
5530 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5531 ASSERT_TRUE(lock_owner);
5532 ASSERT_PASSED(validate_object_map, image1);
5533}
5534
7c673cae
FG
5535TEST_F(TestLibRBD, ObjectMapConsistentSnap)
5536{
5537 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
5538
5539 librados::IoCtx ioctx;
5540 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5541
5542 librbd::RBD rbd;
5543 std::string name = get_temp_image_name();
5544 uint64_t size = 1 << 20;
5545 int order = 12;
5546 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5547
5548 librbd::Image image1;
5549 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5550
7c673cae
FG
5551 int num_snaps = 10;
5552 for (int i = 0; i < num_snaps; ++i) {
5553 std::string snap_name = "snap" + stringify(i);
5554 ASSERT_EQ(0, image1.snap_create(snap_name.c_str()));
5555 }
5556
31f18b77
FG
5557
5558 thread writer([&image1](){
5559 librbd::image_info_t info;
5560 int r = image1.stat(info, sizeof(info));
11fdf7f2 5561 ceph_assert(r == 0);
31f18b77
FG
5562 bufferlist bl;
5563 bl.append("foo");
5564 for (unsigned i = 0; i < info.num_objs; ++i) {
5565 r = image1.write((1 << info.order) * i, bl.length(), bl);
11fdf7f2 5566 ceph_assert(r == (int) bl.length());
31f18b77
FG
5567 }
5568 });
7c673cae
FG
5569 writer.join();
5570
5571 for (int i = 0; i < num_snaps; ++i) {
5572 std::string snap_name = "snap" + stringify(i);
5573 ASSERT_EQ(0, image1.snap_set(snap_name.c_str()));
5574 ASSERT_PASSED(validate_object_map, image1);
5575 }
5576
5577 ASSERT_EQ(0, image1.snap_set(NULL));
5578 ASSERT_PASSED(validate_object_map, image1);
5579}
5580
5581void memset_rand(char *buf, size_t len) {
5582 for (size_t i = 0; i < len; ++i) {
5583 buf[i] = (char) (rand() % (126 - 33) + 33);
5584 }
5585}
5586
5587TEST_F(TestLibRBD, Metadata)
5588{
5589 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5590
5591 rados_ioctx_t ioctx;
5592 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5593
5594 std::string name = get_temp_image_name();
5595 uint64_t size = 2 << 20;
5596 int order = 0;
5597 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5598
5599 rbd_image_t image;
5600 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5601
5602 rbd_image_t image1;
5603 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
5604
5605 char keys[1024];
5606 char vals[1024];
5607 size_t keys_len = sizeof(keys);
5608 size_t vals_len = sizeof(vals);
5609
5610 memset_rand(keys, keys_len);
5611 memset_rand(vals, vals_len);
5612
f67539c2 5613 ASSERT_EQ(0, rbd_metadata_list(image, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5614 &vals_len));
5615 ASSERT_EQ(0U, keys_len);
5616 ASSERT_EQ(0U, vals_len);
5617
5618 char value[1024];
5619 size_t value_len = sizeof(value);
5620 memset_rand(value, value_len);
5621
5622 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
5623 ASSERT_EQ(0, rbd_metadata_set(image1, "key2", "value2"));
5624 ASSERT_EQ(0, rbd_metadata_get(image1, "key1", value, &value_len));
5625 ASSERT_STREQ(value, "value1");
5626 value_len = 1;
5627 ASSERT_EQ(-ERANGE, rbd_metadata_get(image1, "key1", value, &value_len));
5628 ASSERT_EQ(value_len, strlen("value1") + 1);
5629
f67539c2 5630 ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5631 &vals_len));
5632 keys_len = sizeof(keys);
5633 vals_len = sizeof(vals);
5634 memset_rand(keys, keys_len);
5635 memset_rand(vals, vals_len);
f67539c2 5636 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5637 &vals_len));
5638 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
5639 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
5640 ASSERT_STREQ(keys, "key1");
5641 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
5642 ASSERT_STREQ(vals, "value1");
5643 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
5644
5645 ASSERT_EQ(0, rbd_metadata_remove(image1, "key1"));
d2e6a577 5646 ASSERT_EQ(-ENOENT, rbd_metadata_remove(image1, "key3"));
7c673cae
FG
5647 value_len = sizeof(value);
5648 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key3", value, &value_len));
f67539c2 5649 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5650 &vals_len));
5651 ASSERT_EQ(keys_len, strlen("key2") + 1);
5652 ASSERT_EQ(vals_len, strlen("value2") + 1);
5653 ASSERT_STREQ(keys, "key2");
5654 ASSERT_STREQ(vals, "value2");
5655
5656 // test config setting
5657 ASSERT_EQ(0, rbd_metadata_set(image1, "conf_rbd_cache", "false"));
5658 ASSERT_EQ(-EINVAL, rbd_metadata_set(image1, "conf_rbd_cache", "INVALID_VAL"));
5659 ASSERT_EQ(0, rbd_metadata_remove(image1, "conf_rbd_cache"));
5660
5661 // test metadata with snapshot adding
5662 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
5663 ASSERT_EQ(0, rbd_snap_protect(image1, "snap1"));
5664 ASSERT_EQ(0, rbd_snap_set(image1, "snap1"));
5665
f67539c2
TL
5666 ASSERT_EQ(-EROFS, rbd_metadata_set(image1, "key1", "value1"));
5667 ASSERT_EQ(-EROFS, rbd_metadata_remove(image1, "key2"));
7c673cae
FG
5668
5669 keys_len = sizeof(keys);
5670 vals_len = sizeof(vals);
5671 memset_rand(keys, keys_len);
5672 memset_rand(vals, vals_len);
f67539c2 5673 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae 5674 &vals_len));
f67539c2
TL
5675 ASSERT_EQ(keys_len, strlen("key2") + 1);
5676 ASSERT_EQ(vals_len, strlen("value2") + 1);
5677 ASSERT_STREQ(keys, "key2");
5678 ASSERT_STREQ(vals, "value2");
7c673cae
FG
5679
5680 ASSERT_EQ(0, rbd_snap_set(image1, NULL));
f67539c2
TL
5681 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
5682 ASSERT_EQ(0, rbd_metadata_set(image1, "key3", "value3"));
7c673cae
FG
5683 keys_len = sizeof(keys);
5684 vals_len = sizeof(vals);
5685 memset_rand(keys, keys_len);
5686 memset_rand(vals, vals_len);
f67539c2 5687 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5688 &vals_len));
5689 ASSERT_EQ(keys_len,
5690 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5691 ASSERT_EQ(vals_len,
5692 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5693 ASSERT_STREQ(keys, "key1");
5694 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
5695 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
5696 ASSERT_STREQ(vals, "value1");
5697 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
5698 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
5699
5700 // test metadata with cloning
5701 uint64_t features;
5702 ASSERT_EQ(0, rbd_get_features(image1, &features));
5703
5704 string cname = get_temp_image_name();
5705 EXPECT_EQ(0, rbd_clone(ioctx, name.c_str(), "snap1", ioctx,
5706 cname.c_str(), features, &order));
5707 rbd_image_t image2;
5708 ASSERT_EQ(0, rbd_open(ioctx, cname.c_str(), &image2, NULL));
5709 ASSERT_EQ(0, rbd_metadata_set(image2, "key4", "value4"));
5710
5711 keys_len = sizeof(keys);
5712 vals_len = sizeof(vals);
5713 memset_rand(keys, keys_len);
5714 memset_rand(vals, vals_len);
f67539c2 5715 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5716 &vals_len));
5717 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5718 1 + strlen("key4") + 1);
5719 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
5720 strlen("value3") + 1 + strlen("value4") + 1);
5721 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5722 1, "key4");
5723 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1 +
5724 strlen("value3") + 1, "value4");
5725
f67539c2 5726 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5727 &vals_len));
5728 ASSERT_EQ(keys_len,
5729 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5730 ASSERT_EQ(vals_len,
5731 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5732 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key4", value, &value_len));
5733
5734 // test short buffer cases
5735 keys_len = strlen("key1") + 1;
5736 vals_len = strlen("value1") + 1;
5737 memset_rand(keys, keys_len);
5738 memset_rand(vals, vals_len);
f67539c2 5739 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 1, keys, &keys_len, vals,
7c673cae
FG
5740 &vals_len));
5741 ASSERT_EQ(keys_len, strlen("key1") + 1);
5742 ASSERT_EQ(vals_len, strlen("value1") + 1);
5743 ASSERT_STREQ(keys, "key1");
5744 ASSERT_STREQ(vals, "value1");
5745
f67539c2 5746 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 2, keys, &keys_len, vals,
7c673cae
FG
5747 &vals_len));
5748 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
5749 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
5750
f67539c2 5751 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
7c673cae
FG
5752 &vals_len));
5753 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5754 1 + strlen("key4") + 1);
5755 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
5756 strlen("value3") + 1 + strlen("value4") + 1);
5757
5758 // test `start` param
5759 keys_len = sizeof(keys);
5760 vals_len = sizeof(vals);
5761 memset_rand(keys, keys_len);
5762 memset_rand(vals, vals_len);
5763 ASSERT_EQ(0, rbd_metadata_list(image2, "key2", 0, keys, &keys_len, vals,
5764 &vals_len));
5765 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
5766 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
5767 ASSERT_STREQ(keys, "key3");
5768 ASSERT_STREQ(vals, "value3");
5769
5770 ASSERT_EQ(0, rbd_close(image));
5771 ASSERT_EQ(0, rbd_close(image1));
5772 ASSERT_EQ(0, rbd_close(image2));
31f18b77 5773 rados_ioctx_destroy(ioctx);
7c673cae
FG
5774}
5775
5776TEST_F(TestLibRBD, MetadataPP)
5777{
5778 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5779
5780 librados::IoCtx ioctx;
5781 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5782
5783 librbd::RBD rbd;
5784 string name = get_temp_image_name();
5785 uint64_t size = 2 << 20;
5786 int order = 0;
5787 uint64_t features;
5788 string value;
5789 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5790
5791 librbd::Image image1;
5792 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5793 map<string, bufferlist> pairs;
f67539c2 5794 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
5795 ASSERT_TRUE(pairs.empty());
5796
5797 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
5798 ASSERT_EQ(0, image1.metadata_set("key2", "value2"));
5799 ASSERT_EQ(0, image1.metadata_get("key1", &value));
5800 ASSERT_EQ(0, strcmp("value1", value.c_str()));
f67539c2 5801 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
5802 ASSERT_EQ(2U, pairs.size());
5803 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
5804 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
5805
5806 pairs.clear();
5807 ASSERT_EQ(0, image1.metadata_remove("key1"));
d2e6a577 5808 ASSERT_EQ(-ENOENT, image1.metadata_remove("key3"));
7c673cae 5809 ASSERT_TRUE(image1.metadata_get("key3", &value) < 0);
f67539c2 5810 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
5811 ASSERT_EQ(1U, pairs.size());
5812 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
5813
5814 // test config setting
5815 ASSERT_EQ(0, image1.metadata_set("conf_rbd_cache", "false"));
5816 ASSERT_EQ(-EINVAL, image1.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
5817 ASSERT_EQ(0, image1.metadata_remove("conf_rbd_cache"));
5818
5819 // test metadata with snapshot adding
5820 ASSERT_EQ(0, image1.snap_create("snap1"));
5821 ASSERT_EQ(0, image1.snap_protect("snap1"));
5822 ASSERT_EQ(0, image1.snap_set("snap1"));
5823
5824 pairs.clear();
f67539c2
TL
5825 ASSERT_EQ(-EROFS, image1.metadata_set("key1", "value1"));
5826 ASSERT_EQ(-EROFS, image1.metadata_remove("key2"));
5827 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
5828 ASSERT_EQ(1U, pairs.size());
7c673cae 5829 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7c673cae
FG
5830
5831 ASSERT_EQ(0, image1.snap_set(NULL));
f67539c2
TL
5832 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
5833 ASSERT_EQ(0, image1.metadata_set("key3", "value3"));
5834 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
5835 ASSERT_EQ(3U, pairs.size());
5836 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
5837 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
5838 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
5839
5840 // test metadata with cloning
5841 string cname = get_temp_image_name();
5842 librbd::Image image2;
5843 ASSERT_EQ(0, image1.features(&features));
5844 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
5845 cname.c_str(), features, &order));
5846 ASSERT_EQ(0, rbd.open(ioctx, image2, cname.c_str(), NULL));
5847 ASSERT_EQ(0, image2.metadata_set("key4", "value4"));
5848 pairs.clear();
f67539c2 5849 ASSERT_EQ(0, image2.metadata_list("key", 0, &pairs));
7c673cae
FG
5850 ASSERT_EQ(4U, pairs.size());
5851 pairs.clear();
f67539c2 5852 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
5853 ASSERT_EQ(3U, pairs.size());
5854 ASSERT_EQ(-ENOENT, image1.metadata_get("key4", &value));
5855}
5856
5857TEST_F(TestLibRBD, UpdateFeatures)
5858{
5859 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5860
5861 librados::IoCtx ioctx;
5862 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5863
5864 librbd::RBD rbd;
5865 std::string name = get_temp_image_name();
5866 uint64_t size = 1 << 20;
5867 int order = 0;
5868 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5869
5870 librbd::Image image;
5871 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5872
5873 uint8_t old_format;
5874 ASSERT_EQ(0, image.old_format(&old_format));
5875 if (old_format) {
5876 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
5877 return;
5878 }
5879
5880 uint64_t features;
5881 ASSERT_EQ(0, image.features(&features));
5882
5883 // must provide a single feature
5884 ASSERT_EQ(-EINVAL, image.update_features(0, true));
5885
5886 uint64_t disable_features;
5887 disable_features = features & (RBD_FEATURE_EXCLUSIVE_LOCK |
5888 RBD_FEATURE_OBJECT_MAP |
5889 RBD_FEATURE_FAST_DIFF |
5890 RBD_FEATURE_JOURNALING);
5891 if (disable_features != 0) {
5892 ASSERT_EQ(0, image.update_features(disable_features, false));
5893 }
5894
5895 ASSERT_EQ(0, image.features(&features));
5896 ASSERT_EQ(0U, features & disable_features);
5897
5898 // cannot enable object map nor journaling w/o exclusive lock
5899 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
5900 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_JOURNALING, true));
5901 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
5902
5903 ASSERT_EQ(0, image.features(&features));
5904 ASSERT_NE(0U, features & RBD_FEATURE_EXCLUSIVE_LOCK);
5905
11fdf7f2
TL
5906 // can enable fast diff w/o object map
5907 ASSERT_EQ(0, image.update_features(RBD_FEATURE_FAST_DIFF, true));
5908 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
7c673cae
FG
5909 ASSERT_EQ(0, image.features(&features));
5910 ASSERT_NE(0U, features & RBD_FEATURE_OBJECT_MAP);
5911
11fdf7f2
TL
5912 uint64_t expected_flags = RBD_FLAG_OBJECT_MAP_INVALID |
5913 RBD_FLAG_FAST_DIFF_INVALID;
7c673cae
FG
5914 uint64_t flags;
5915 ASSERT_EQ(0, image.get_flags(&flags));
5916 ASSERT_EQ(expected_flags, flags);
5917
5918 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
5919 ASSERT_EQ(0, image.features(&features));
5920 ASSERT_EQ(0U, features & RBD_FEATURE_OBJECT_MAP);
5921
11fdf7f2
TL
5922 // can disable object map w/ fast diff
5923 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
5924 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
5925 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_FAST_DIFF, false));
7c673cae
FG
5926 ASSERT_EQ(0, image.features(&features));
5927 ASSERT_EQ(0U, features & RBD_FEATURE_FAST_DIFF);
5928
7c673cae 5929 ASSERT_EQ(0, image.get_flags(&flags));
11fdf7f2 5930 ASSERT_EQ(0U, flags);
7c673cae
FG
5931
5932 // cannot disable exclusive lock w/ object map
11fdf7f2 5933 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
7c673cae
FG
5934 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
5935 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
5936
5937 // cannot disable exclusive lock w/ journaling
11fdf7f2 5938 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, true));
7c673cae
FG
5939 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
5940 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, false));
5941
5942 ASSERT_EQ(0, image.get_flags(&flags));
5943 ASSERT_EQ(0U, flags);
5944
5945 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
5946
5947 ASSERT_EQ(0, image.features(&features));
5948 if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0) {
5949 ASSERT_EQ(0, image.update_features(RBD_FEATURE_DEEP_FLATTEN, false));
5950 }
5951 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_DEEP_FLATTEN, true));
5952}
5953
9f95a23c
TL
5954TEST_F(TestLibRBD, FeaturesBitmaskString)
5955{
5956 librbd::RBD rbd;
5957 uint64_t features = RBD_FEATURES_DEFAULT;
5958
5959 std::string features_str;
5960 std::string expected_str = "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
5961 rbd.features_to_string(features, &features_str);
5962 ASSERT_EQ(expected_str, features_str);
5963
5964 features = RBD_FEATURE_LAYERING;
5965 features_str = "";
5966 expected_str = "layering";
5967 rbd.features_to_string(features, &features_str);
5968 ASSERT_EQ(expected_str, features_str);
5969
5970 uint64_t features_bitmask;
5971 features_str = "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
5972 rbd.features_from_string(features_str, &features_bitmask);
5973 ASSERT_EQ(features_bitmask, RBD_FEATURES_DEFAULT);
5974
5975 features_str = "layering";
5976 features_bitmask = 0;
5977 rbd.features_from_string(features_str, &features_bitmask);
5978 ASSERT_EQ(features_bitmask, RBD_FEATURE_LAYERING);
5979}
5980
7c673cae
FG
5981TEST_F(TestLibRBD, RebuildObjectMap)
5982{
5983 librados::IoCtx ioctx;
5984 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5985
5986 librbd::RBD rbd;
5987 std::string name = get_temp_image_name();
5988 uint64_t size = 1 << 20;
5989 int order = 18;
5990 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5991
5992 PrintProgress prog_ctx;
5993 std::string object_map_oid;
5994 bufferlist bl;
5995 bl.append("foo");
5996 {
5997 librbd::Image image;
5998 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5999
6000 uint64_t features;
6001 ASSERT_EQ(0, image.features(&features));
6002 if ((features & RBD_FEATURE_OBJECT_MAP) == 0) {
6003 ASSERT_EQ(-EINVAL, image.rebuild_object_map(prog_ctx));
6004 return;
6005 }
6006
6007 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
6008
6009 ASSERT_EQ(0, image.snap_create("snap1"));
6010 ASSERT_EQ((ssize_t)bl.length(), image.write(1<<order, bl.length(), bl));
6011
6012 std::string image_id;
6013 ASSERT_EQ(0, get_image_id(image, &image_id));
6014 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
6015 }
6016
6017 // corrupt the object map
6018 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
6019
6020 librbd::Image image1;
6021 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6022
6023 bool lock_owner;
6024 bl.clear();
6025 ASSERT_EQ(0, image1.write(0, 0, bl));
6026 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
6027 ASSERT_TRUE(lock_owner);
6028
6029 uint64_t flags;
6030 ASSERT_EQ(0, image1.get_flags(&flags));
6031 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
6032
6033 ASSERT_EQ(0, image1.rebuild_object_map(prog_ctx));
6034
6035 librbd::Image image2;
6036 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
6037
6038 bufferlist read_bl;
6039 ASSERT_EQ((ssize_t)bl.length(), image2.read(0, bl.length(), read_bl));
6040 ASSERT_TRUE(bl.contents_equal(read_bl));
6041
6042 read_bl.clear();
6043 ASSERT_EQ((ssize_t)bl.length(), image2.read(1<<order, bl.length(), read_bl));
6044 ASSERT_TRUE(bl.contents_equal(read_bl));
6045
6046 ASSERT_PASSED(validate_object_map, image1);
6047 ASSERT_PASSED(validate_object_map, image2);
6048}
6049
6050TEST_F(TestLibRBD, RebuildNewObjectMap)
6051{
6052 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
6053
6054 rados_ioctx_t ioctx;
6055 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6056
6057 std::string name = get_temp_image_name();
6058 uint64_t size = 1 << 20;
6059 int order = 18;
6060 uint64_t features = RBD_FEATURE_EXCLUSIVE_LOCK;
6061 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
6062 false, features));
6063
6064 rbd_image_t image;
6065 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6066 ASSERT_EQ(0, rbd_update_features(image, RBD_FEATURE_OBJECT_MAP, true));
6067 ASSERT_EQ(0, rbd_rebuild_object_map(image, print_progress_percent, NULL));
6068
6069 ASSERT_PASSED(validate_object_map, image);
6070
6071 ASSERT_EQ(0, rbd_close(image));
6072 rados_ioctx_destroy(ioctx);
6073}
6074
6075TEST_F(TestLibRBD, CheckObjectMap)
6076{
6077 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
6078
6079 librados::IoCtx ioctx;
6080 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6081
6082 librbd::RBD rbd;
6083 std::string name = get_temp_image_name();
6084 uint64_t size = 1 << 20;
6085 int order = 18;
6086 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6087
6088 PrintProgress prog_ctx;
6089 bufferlist bl1;
6090 bufferlist bl2;
6091 bl1.append("foo");
6092 {
6093 librbd::Image image;
6094 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6095
6096 uint64_t features;
6097 ASSERT_EQ(0, image.features(&features));
6098
6099 ASSERT_EQ((ssize_t)bl1.length(), image.write(0, bl1.length(), bl1));
6100
6101 ASSERT_EQ(0, image.snap_create("snap1"));
6102 ASSERT_EQ((ssize_t)bl1.length(), image.write(1<<order, bl1.length(), bl1));
6103 }
6104
6105 librbd::Image image1;
6106 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6107
6108 std::string image_id;
6109 ASSERT_EQ(0, get_image_id(image1, &image_id));
6110
6111 std::string object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
6112
6113 ASSERT_LT(0, ioctx.read(object_map_oid, bl2, 1024, 0));
6114
6115 bool lock_owner;
6116 ASSERT_EQ((ssize_t)bl1.length(), image1.write(3 * (1 << 18), bl1.length(), bl1));
6117 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
6118 ASSERT_TRUE(lock_owner);
6119
6120 //reopen image to reread now corrupt object map from disk
6121 image1.close();
6122
6123 bl1.clear();
6124 ASSERT_LT(0, ioctx.read(object_map_oid, bl1, 1024, 0));
6125 ASSERT_FALSE(bl1.contents_equal(bl2));
6126
6127 ASSERT_EQ(0, ioctx.write_full(object_map_oid, bl2));
6128 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6129
6130 uint64_t flags;
6131 ASSERT_EQ(0, image1.get_flags(&flags));
6132 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
6133
6134 ASSERT_EQ(0, image1.check_object_map(prog_ctx));
6135
6136 ASSERT_EQ(0, image1.get_flags(&flags));
6137 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
6138}
6139
6140TEST_F(TestLibRBD, BlockingAIO)
6141{
6142 librados::IoCtx ioctx;
6143 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6144
7c673cae
FG
6145 librbd::RBD rbd;
6146 std::string name = get_temp_image_name();
6147 uint64_t size = 1 << 20;
6148 int order = 18;
6149 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6150
6151 std::string non_blocking_aio;
6152 ASSERT_EQ(0, _rados.conf_get("rbd_non_blocking_aio", non_blocking_aio));
6153 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio", "0"));
6154 BOOST_SCOPE_EXIT( (non_blocking_aio) ) {
6155 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio",
6156 non_blocking_aio.c_str()));
6157 } BOOST_SCOPE_EXIT_END;
6158
6159 librbd::Image image;
6160 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6161
f67539c2
TL
6162 bool skip_discard = this->is_skip_partial_discard_enabled(image);
6163
7c673cae
FG
6164 bufferlist bl;
6165 ASSERT_EQ(0, image.write(0, bl.length(), bl));
6166
6167 bl.append(std::string(256, '1'));
6168 librbd::RBD::AioCompletion *write_comp =
6169 new librbd::RBD::AioCompletion(NULL, NULL);
6170 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
6171
6172 librbd::RBD::AioCompletion *flush_comp =
6173 new librbd::RBD::AioCompletion(NULL, NULL);
6174 ASSERT_EQ(0, image.aio_flush(flush_comp));
6175 ASSERT_EQ(0, flush_comp->wait_for_complete());
6176 ASSERT_EQ(0, flush_comp->get_return_value());
6177 flush_comp->release();
6178
6179 ASSERT_EQ(1, write_comp->is_complete());
6180 ASSERT_EQ(0, write_comp->get_return_value());
6181 write_comp->release();
6182
6183 librbd::RBD::AioCompletion *discard_comp =
6184 new librbd::RBD::AioCompletion(NULL, NULL);
6185 ASSERT_EQ(0, image.aio_discard(128, 128, discard_comp));
6186 ASSERT_EQ(0, discard_comp->wait_for_complete());
6187 discard_comp->release();
6188
6189 librbd::RBD::AioCompletion *read_comp =
6190 new librbd::RBD::AioCompletion(NULL, NULL);
6191 bufferlist read_bl;
6192 image.aio_read(0, bl.length(), read_bl, read_comp);
6193 ASSERT_EQ(0, read_comp->wait_for_complete());
6194 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
6195 read_comp->release();
6196
6197 bufferlist expected_bl;
6198 expected_bl.append(std::string(128, '1'));
6199 expected_bl.append(std::string(128, skip_discard ? '1' : '\0'));
6200 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
6201}
6202
6203TEST_F(TestLibRBD, ExclusiveLockTransition)
6204{
6205 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
6206
6207 librados::IoCtx ioctx;
6208 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6209
6210 librbd::RBD rbd;
6211 std::string name = get_temp_image_name();
6212
6213 uint64_t size = 1 << 18;
6214 int order = 12;
6215 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6216
6217 librbd::Image image1;
6218 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6219
6220 librbd::Image image2;
6221 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
6222
6223 std::list<librbd::RBD::AioCompletion *> comps;
6224 ceph::bufferlist bl;
6225 bl.append(std::string(1 << order, '1'));
6226 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
6227 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
6228 NULL);
6229 comps.push_back(comp);
6230 if (object_no % 2 == 0) {
6231 ASSERT_EQ(0, image1.aio_write(object_no << order, bl.length(), bl, comp));
6232 } else {
6233 ASSERT_EQ(0, image2.aio_write(object_no << order, bl.length(), bl, comp));
6234 }
6235 }
6236
6237 while (!comps.empty()) {
6238 librbd::RBD::AioCompletion *comp = comps.front();
6239 comps.pop_front();
6240 ASSERT_EQ(0, comp->wait_for_complete());
6241 ASSERT_EQ(1, comp->is_complete());
6242 comp->release();
6243 }
6244
6245 librbd::Image image3;
6246 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
6247 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
6248 bufferlist read_bl;
6249 ASSERT_EQ((ssize_t)bl.length(), image3.read(object_no << order, bl.length(),
6250 read_bl));
6251 ASSERT_TRUE(bl.contents_equal(read_bl));
6252 }
6253
6254 ASSERT_PASSED(validate_object_map, image1);
6255 ASSERT_PASSED(validate_object_map, image2);
6256 ASSERT_PASSED(validate_object_map, image3);
6257}
6258
6259TEST_F(TestLibRBD, ExclusiveLockReadTransition)
6260{
6261 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
6262
6263 librados::IoCtx ioctx;
6264 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6265
6266 librbd::RBD rbd;
6267 std::string name = get_temp_image_name();
6268
6269 uint64_t size = 1 << 18;
6270 int order = 12;
6271 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6272
6273 librbd::Image image1;
6274 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6275
6276 bool lock_owner;
6277 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
6278 ASSERT_FALSE(lock_owner);
6279
6280 // journaling should force read ops to acquire the lock
6281 bufferlist read_bl;
6282 ASSERT_EQ(0, image1.read(0, 0, read_bl));
6283
6284 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
6285 ASSERT_TRUE(lock_owner);
6286
6287 librbd::Image image2;
6288 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
6289
6290 std::list<librbd::RBD::AioCompletion *> comps;
6291 std::list<bufferlist> read_bls;
6292 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
6293 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
6294 NULL);
6295 comps.push_back(comp);
6296 read_bls.emplace_back();
6297 if (object_no % 2 == 0) {
6298 ASSERT_EQ(0, image1.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
6299 } else {
6300 ASSERT_EQ(0, image2.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
6301 }
6302 }
6303
6304 while (!comps.empty()) {
6305 librbd::RBD::AioCompletion *comp = comps.front();
6306 comps.pop_front();
6307 ASSERT_EQ(0, comp->wait_for_complete());
6308 ASSERT_EQ(1, comp->is_complete());
6309 comp->release();
6310 }
6311}
6312
6313TEST_F(TestLibRBD, CacheMayCopyOnWrite) {
6314 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6315
6316 librados::IoCtx ioctx;
6317 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6318
6319 librbd::RBD rbd;
6320 std::string name = get_temp_image_name();
6321
6322 uint64_t size = 1 << 18;
6323 int order = 12;
6324 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6325
6326 librbd::Image image;
6327 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6328 ASSERT_EQ(0, image.snap_create("one"));
6329 ASSERT_EQ(0, image.snap_protect("one"));
6330
6331 std::string clone_name = this->get_temp_image_name();
6332 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
6333 RBD_FEATURE_LAYERING, &order));
6334
6335 librbd::Image clone;
6336 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
6337 ASSERT_EQ(0, clone.flush());
6338
6339 bufferlist expect_bl;
6340 expect_bl.append(std::string(1024, '\0'));
6341
6342 // test double read path
6343 bufferlist read_bl;
6344 uint64_t offset = 0;
6345 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
6346 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
6347
6348 bufferlist write_bl;
6349 write_bl.append(std::string(1024, '1'));
6350 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
6351
6352 read_bl.clear();
6353 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
6354 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
6355
6356 // test read retry path
6357 offset = 1 << order;
6358 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
6359
6360 read_bl.clear();
6361 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
6362 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
6363}
6364
6365TEST_F(TestLibRBD, FlushEmptyOpsOnExternalSnapshot) {
6366 std::string cache_enabled;
6367 ASSERT_EQ(0, _rados.conf_get("rbd_cache", cache_enabled));
6368 ASSERT_EQ(0, _rados.conf_set("rbd_cache", "false"));
6369 BOOST_SCOPE_EXIT( (cache_enabled) ) {
6370 ASSERT_EQ(0, _rados.conf_set("rbd_cache", cache_enabled.c_str()));
6371 } BOOST_SCOPE_EXIT_END;
6372
6373 librados::IoCtx ioctx;
6374 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6375
6376 librbd::RBD rbd;
6377 std::string name = get_temp_image_name();
6378 uint64_t size = 1 << 18;
6379 int order = 0;
6380 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6381
6382 librbd::Image image1;
6383 librbd::Image image2;
6384 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6385 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
6386 ASSERT_EQ(0, image1.snap_create("snap1"));
6387
6388 librbd::RBD::AioCompletion *read_comp =
6389 new librbd::RBD::AioCompletion(NULL, NULL);
6390 bufferlist read_bl;
6391 image2.aio_read(0, 1024, read_bl, read_comp);
6392 ASSERT_EQ(0, read_comp->wait_for_complete());
6393 read_comp->release();
6394}
6395
6396TEST_F(TestLibRBD, TestImageOptions)
6397{
6398 rados_ioctx_t ioctx;
6399 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6400
6401 //make create image options
6402 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
6403 uint64_t order = 0;
6404 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
6405 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
6406 rbd_image_options_t opts;
6407 rbd_image_options_create(&opts);
6408
6409 bool is_set;
6410 ASSERT_EQ(-EINVAL, rbd_image_options_is_set(opts, 12345, &is_set));
6411 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
6412 &is_set));
6413 ASSERT_FALSE(is_set);
6414
6415 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
6416 2));
6417 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
6418 features));
6419 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
6420 order));
6421 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
6422 stripe_unit));
6423 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
6424 stripe_count));
6425
6426 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
6427 &is_set));
6428 ASSERT_TRUE(is_set);
6429
6430 std::string parent_name = get_temp_image_name();
6431
6432 // make parent
6433 ASSERT_EQ(0, rbd_create4(ioctx, parent_name.c_str(), 4<<20, opts));
6434
6435 // check order is returned in opts
6436 ASSERT_EQ(0, rbd_image_options_get_uint64(opts, RBD_IMAGE_OPTION_ORDER,
6437 &order));
6438 ASSERT_NE((uint64_t)0, order);
6439
6440 // write some data to parent
6441 rbd_image_t parent;
6442 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
6443 char *data = (char *)"testdata";
6444 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
6445 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
6446
6447 // create a snapshot, reopen as the parent we're interested in
6448 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
6449 ASSERT_EQ(0, rbd_close(parent));
6450 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
6451
6452 // clone
6453 std::string child_name = get_temp_image_name();
6454 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
6455 ASSERT_EQ(0, rbd_clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
6456 child_name.c_str(), opts));
6457
6458 // copy
6459 std::string copy1_name = get_temp_image_name();
6460 ASSERT_EQ(0, rbd_copy3(parent, ioctx, copy1_name.c_str(), opts));
6461 std::string copy2_name = get_temp_image_name();
6462 ASSERT_EQ(0, rbd_copy_with_progress3(parent, ioctx, copy2_name.c_str(), opts,
6463 print_progress_percent, NULL));
6464
6465 ASSERT_EQ(0, rbd_close(parent));
6466
6467 rbd_image_options_destroy(opts);
6468
6469 rados_ioctx_destroy(ioctx);
6470}
6471
6472TEST_F(TestLibRBD, TestImageOptionsPP)
6473{
6474 librados::IoCtx ioctx;
6475 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6476
6477 //make create image options
6478 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
6479 uint64_t order = 0;
6480 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
6481 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
6482 librbd::ImageOptions opts;
6483 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2)));
6484 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FEATURES, features));
6485 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_ORDER, order));
6486 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
6487 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
6488
6489 librbd::RBD rbd;
6490 std::string parent_name = get_temp_image_name();
6491
6492 // make parent
6493 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 4<<20, opts));
6494
6495 // check order is returned in opts
6496 ASSERT_EQ(0, opts.get(RBD_IMAGE_OPTION_ORDER, &order));
6497 ASSERT_NE((uint64_t)0, order);
6498
6499 // write some data to parent
6500 librbd::Image parent;
6501 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
6502
6503 ssize_t len = 1024;
6504 bufferlist bl;
6505 bl.append(buffer::create(len));
6506 bl.zero();
6507 ASSERT_EQ(len, parent.write(0, len, bl));
6508 ASSERT_EQ(len, parent.write(len, len, bl));
6509
6510 // create a snapshot, reopen as the parent we're interested in
6511 ASSERT_EQ(0, parent.snap_create("parent_snap"));
6512 ASSERT_EQ(0, parent.close());
6513 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
6514
6515 // clone
6516 std::string child_name = get_temp_image_name();
6517 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
6518 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
6519 child_name.c_str(), opts));
6520
6521 // copy
6522 std::string copy1_name = get_temp_image_name();
6523 ASSERT_EQ(0, parent.copy3(ioctx, copy1_name.c_str(), opts));
6524 std::string copy2_name = get_temp_image_name();
6525 PrintProgress pp;
6526 ASSERT_EQ(0, parent.copy_with_progress3(ioctx, copy2_name.c_str(), opts, pp));
6527
6528 ASSERT_EQ(0, parent.close());
6529}
6530
6531TEST_F(TestLibRBD, EventSocketPipe)
6532{
6533 EventSocket event_sock;
6534 int pipe_fd[2]; // read and write fd
6535 char buf[32];
6536
6537 ASSERT_EQ(0, pipe(pipe_fd));
6538
6539 ASSERT_FALSE(event_sock.is_valid());
6540
6541 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_NONE));
6542 ASSERT_FALSE(event_sock.is_valid());
6543
6544 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], 44));
6545 ASSERT_FALSE(event_sock.is_valid());
6546
6547#ifndef HAVE_EVENTFD
6548 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_EVENTFD));
6549 ASSERT_FALSE(event_sock.is_valid());
6550#endif
6551
6552 ASSERT_EQ(0, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_PIPE));
6553 ASSERT_TRUE(event_sock.is_valid());
6554 ASSERT_EQ(0, event_sock.notify());
6555 ASSERT_EQ(1, read(pipe_fd[0], buf, 32));
6556 ASSERT_EQ('i', buf[0]);
6557
6558 close(pipe_fd[0]);
6559 close(pipe_fd[1]);
6560}
6561
6562TEST_F(TestLibRBD, EventSocketEventfd)
6563{
6564#ifdef HAVE_EVENTFD
6565 EventSocket event_sock;
6566 int event_fd;
6567 struct pollfd poll_fd;
6568 char buf[32];
6569
6570 event_fd = eventfd(0, EFD_NONBLOCK);
6571 ASSERT_NE(-1, event_fd);
6572
6573 ASSERT_FALSE(event_sock.is_valid());
6574
6575 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, EVENT_SOCKET_TYPE_NONE));
6576 ASSERT_FALSE(event_sock.is_valid());
6577
6578 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, 44));
6579 ASSERT_FALSE(event_sock.is_valid());
6580
6581 ASSERT_EQ(0, event_sock.init(event_fd, EVENT_SOCKET_TYPE_EVENTFD));
6582 ASSERT_TRUE(event_sock.is_valid());
6583 ASSERT_EQ(0, event_sock.notify());
6584
6585 poll_fd.fd = event_fd;
6586 poll_fd.events = POLLIN;
6587 ASSERT_EQ(1, poll(&poll_fd, 1, -1));
6588 ASSERT_TRUE(poll_fd.revents & POLLIN);
6589
6590 ASSERT_EQ(static_cast<ssize_t>(sizeof(uint64_t)), read(event_fd, buf, 32));
6591 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf));
6592
6593 close(event_fd);
6594#endif
6595}
6596
6597TEST_F(TestLibRBD, ImagePollIO)
6598{
6599#ifdef HAVE_EVENTFD
6600 rados_ioctx_t ioctx;
6601 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6602
6603 rbd_image_t image;
6604 int order = 0;
6605 std::string name = get_temp_image_name();
6606 uint64_t size = 2 << 20;
6607 int fd = eventfd(0, EFD_NONBLOCK);
6608
6609 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6610 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6611
6612 ASSERT_EQ(0, rbd_set_image_notification(image, fd, EVENT_SOCKET_TYPE_EVENTFD));
6613
6614 char test_data[TEST_IO_SIZE + 1];
6615 char zero_data[TEST_IO_SIZE + 1];
6616 int i;
6617
6618 for (i = 0; i < TEST_IO_SIZE; ++i)
6619 test_data[i] = (char) (rand() % (126 - 33) + 33);
6620 test_data[TEST_IO_SIZE] = '\0';
6621 memset(zero_data, 0, sizeof(zero_data));
6622
6623 for (i = 0; i < 5; ++i)
6624 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
6625
6626 for (i = 5; i < 10; ++i)
6627 ASSERT_PASSED(aio_write_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
6628
6629 for (i = 5; i < 10; ++i)
6630 ASSERT_PASSED(aio_read_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
6631
6632 ASSERT_EQ(0, rbd_close(image));
6633 rados_ioctx_destroy(ioctx);
6634#endif
6635}
6636
6637namespace librbd {
6638
11fdf7f2
TL
6639static bool operator==(const image_spec_t &lhs, const image_spec_t &rhs) {
6640 return (lhs.id == rhs.id && lhs.name == rhs.name);
6641}
6642
6643static bool operator==(const linked_image_spec_t &lhs,
6644 const linked_image_spec_t &rhs) {
6645 return (lhs.pool_id == rhs.pool_id &&
6646 lhs.pool_name == rhs.pool_name &&
6647 lhs.pool_namespace == rhs.pool_namespace &&
6648 lhs.image_id == rhs.image_id &&
6649 lhs.image_name == rhs.image_name &&
6650 lhs.trash == rhs.trash);
6651}
6652
7c673cae
FG
6653static bool operator==(const mirror_peer_t &lhs, const mirror_peer_t &rhs) {
6654 return (lhs.uuid == rhs.uuid &&
6655 lhs.cluster_name == rhs.cluster_name &&
6656 lhs.client_name == rhs.client_name);
6657}
6658
6659static std::ostream& operator<<(std::ostream &os, const mirror_peer_t &peer) {
6660 os << "uuid=" << peer.uuid << ", "
6661 << "cluster=" << peer.cluster_name << ", "
6662 << "client=" << peer.client_name;
6663 return os;
6664}
6665
6666} // namespace librbd
6667
6668TEST_F(TestLibRBD, Mirror) {
6669 librados::IoCtx ioctx;
6670 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6671
6672 librbd::RBD rbd;
6673
6674 std::vector<librbd::mirror_peer_t> expected_peers;
6675 std::vector<librbd::mirror_peer_t> peers;
6676 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
6677 ASSERT_EQ(expected_peers, peers);
6678
6679 std::string uuid1;
6680 ASSERT_EQ(-EINVAL, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
6681
6682 rbd_mirror_mode_t mirror_mode;
6683 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
6684 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED, mirror_mode);
6685
6686 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
6687 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
6688
6689 // Add some images to the pool
6690 int order = 0;
6691 std::string parent_name = get_temp_image_name();
6692 std::string child_name = get_temp_image_name();
6693 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), 2 << 20,
6694 &order));
6695 bool old_format;
6696 uint64_t features;
6697 ASSERT_EQ(0, get_features(&old_format, &features));
6698 if ((features & RBD_FEATURE_LAYERING) != 0) {
6699 librbd::Image parent;
6700 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
6701 ASSERT_EQ(0, parent.snap_create("parent_snap"));
6702 ASSERT_EQ(0, parent.close());
6703 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
6704 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
6705 ASSERT_EQ(0, parent.close());
6706 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "parent_snap", ioctx,
6707 child_name.c_str(), features, &order));
6708 }
6709
6710 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE, mirror_mode);
6711
6712 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_POOL));
6713 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
6714 ASSERT_EQ(RBD_MIRROR_MODE_POOL, mirror_mode);
6715
6716 std::string uuid2;
6717 std::string uuid3;
6718 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
6719 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid2, "cluster2", "admin"));
6720 ASSERT_EQ(-EEXIST, rbd.mirror_peer_add(ioctx, &uuid3, "cluster1", "foo"));
6721 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid3, "cluster3", "admin"));
6722
6723 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
6724 auto sort_peers = [](const librbd::mirror_peer_t &lhs,
6725 const librbd::mirror_peer_t &rhs) {
6726 return lhs.uuid < rhs.uuid;
6727 };
6728 expected_peers = {
6729 {uuid1, "cluster1", "client"},
6730 {uuid2, "cluster2", "admin"},
6731 {uuid3, "cluster3", "admin"}};
6732 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
6733 ASSERT_EQ(expected_peers, peers);
6734
6735 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, "uuid4"));
6736 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid2));
6737
6738 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_client(ioctx, "uuid4", "new client"));
6739 ASSERT_EQ(0, rbd.mirror_peer_set_client(ioctx, uuid1, "new client"));
6740
6741 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_cluster(ioctx, "uuid4",
6742 "new cluster"));
6743 ASSERT_EQ(0, rbd.mirror_peer_set_cluster(ioctx, uuid3, "new cluster"));
6744
6745 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
6746 expected_peers = {
6747 {uuid1, "cluster1", "new client"},
6748 {uuid3, "new cluster", "admin"}};
6749 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
6750 ASSERT_EQ(expected_peers, peers);
6751
6752 ASSERT_EQ(-EBUSY, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
11fdf7f2
TL
6753 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid1));
6754 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid3));
6755 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
7c673cae
FG
6756}
6757
11fdf7f2
TL
6758TEST_F(TestLibRBD, MirrorPeerAttributes) {
6759 REQUIRE(!is_librados_test_stub(_rados));
7c673cae
FG
6760
6761 librados::IoCtx ioctx;
6762 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6763
6764 librbd::RBD rbd;
11fdf7f2 6765 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
7c673cae 6766
11fdf7f2
TL
6767 std::string uuid;
6768 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid, "remote_cluster", "client"));
7c673cae 6769
11fdf7f2
TL
6770 std::map<std::string, std::string> attributes;
6771 ASSERT_EQ(-ENOENT, rbd.mirror_peer_get_attributes(ioctx, uuid, &attributes));
6772 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_attributes(ioctx, "missing uuid",
6773 attributes));
7c673cae 6774
11fdf7f2
TL
6775 std::map<std::string, std::string> expected_attributes{
6776 {"mon_host", "1.2.3.4"},
6777 {"key", "ABC"}};
6778 ASSERT_EQ(0, rbd.mirror_peer_set_attributes(ioctx, uuid,
6779 expected_attributes));
6780
6781 ASSERT_EQ(0, rbd.mirror_peer_get_attributes(ioctx, uuid,
6782 &attributes));
6783 ASSERT_EQ(expected_attributes, attributes);
6784
6785 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid));
6786 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
6787}
6788
1911f103
TL
6789TEST_F(TestLibRBD, CreateWithMirrorEnabled) {
6790 REQUIRE_FORMAT_V2();
6791
6792 librados::IoCtx ioctx;
6793 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6794
6795 librbd::RBD rbd;
6796 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
6797
6798 librbd::ImageOptions image_options;
6799 ASSERT_EQ(0, image_options.set(
6800 RBD_IMAGE_OPTION_MIRROR_IMAGE_MODE,
6801 static_cast<uint64_t>(RBD_MIRROR_IMAGE_MODE_SNAPSHOT)));
6802
6803 std::string parent_name = get_temp_image_name();
6804 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 2<<20, image_options));
6805
6806 librbd::Image parent_image;
6807 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
6808
6809 librbd::mirror_image_mode_t mirror_image_mode;
6810 ASSERT_EQ(0, parent_image.mirror_image_get_mode(&mirror_image_mode));
6811 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mirror_image_mode);
6812
6813 ASSERT_EQ(0, parent_image.snap_create("parent_snap"));
6814 ASSERT_EQ(0, parent_image.snap_protect("parent_snap"));
6815
6816 std::string child_name = get_temp_image_name();
6817 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
6818 child_name.c_str(), image_options));
6819
6820 librbd::Image child_image;
6821 ASSERT_EQ(0, rbd.open(ioctx, child_image, child_name.c_str(), NULL));
6822
6823 ASSERT_EQ(0, child_image.mirror_image_get_mode(&mirror_image_mode));
6824 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mirror_image_mode);
6825
6826 ASSERT_EQ(0, child_image.mirror_image_disable(true));
6827 ASSERT_EQ(0, parent_image.mirror_image_disable(true));
6828 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
6829}
6830
11fdf7f2
TL
6831TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {
6832 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6833
6834 librados::IoCtx ioctx;
6835 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6836
6837 librbd::RBD rbd;
6838 librbd::Image image;
6839 std::string name = get_temp_image_name();
6840
6841 uint64_t size = 1 << 18;
6842 int order = 0;
6843
6844 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6845 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6846
6847 bufferlist bl;
6848 bl.append(std::string(size, '1'));
7c673cae
FG
6849 ASSERT_EQ((int)size, image.write(0, size, bl));
6850 ASSERT_EQ(0, image.snap_create("one"));
6851 ASSERT_EQ(0, image.snap_protect("one"));
6852
6853 std::string clone_name = this->get_temp_image_name();
6854 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
6855 RBD_FEATURE_LAYERING, &order));
6856 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
6857
6858 librbd::Image image2;
6859 ASSERT_EQ(0, rbd.open(ioctx, image2, clone_name.c_str(), NULL));
6860
6861 // prepare CoW writeback that will be flushed on next op
6862 bl.clear();
6863 bl.append(std::string(1, '1'));
6864 ASSERT_EQ(0, image.flush());
6865 ASSERT_EQ(1, image.write(0, 1, bl));
6866 ASSERT_EQ(0, image2.snap_create("snap1"));
6867
6868 librbd::RBD::AioCompletion *read_comp =
6869 new librbd::RBD::AioCompletion(NULL, NULL);
6870 bufferlist read_bl;
6871 image.aio_read(0, 1024, read_bl, read_comp);
6872 ASSERT_EQ(0, read_comp->wait_for_complete());
6873 read_comp->release();
6874}
6875
6876TEST_F(TestLibRBD, ExclusiveLock)
6877{
6878 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
6879
6880 static char buf[10];
6881
6882 rados_ioctx_t ioctx;
6883 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6884
6885 std::string name = get_temp_image_name();
6886 uint64_t size = 2 << 20;
6887 int order = 0;
6888 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6889
6890 rbd_image_t image1;
6891 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
6892
6893 int lock_owner;
6894 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
6895 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6896 ASSERT_TRUE(lock_owner);
6897
6898 rbd_lock_mode_t lock_mode;
6899 char *lock_owners[1];
6900 size_t max_lock_owners = 0;
6901 ASSERT_EQ(-ERANGE, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
6902 &max_lock_owners));
6903 ASSERT_EQ(1U, max_lock_owners);
6904
7c673cae
FG
6905 ASSERT_EQ(0, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
6906 &max_lock_owners));
6907 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
6908 ASSERT_STRNE("", lock_owners[0]);
6909 ASSERT_EQ(1U, max_lock_owners);
6910
6911 rbd_image_t image2;
6912 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
6913
6914 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
6915 ASSERT_FALSE(lock_owner);
6916
6917 ASSERT_EQ(-EOPNOTSUPP, rbd_lock_break(image1, RBD_LOCK_MODE_SHARED, ""));
6918 ASSERT_EQ(-EBUSY, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
6919 "not the owner"));
6920
6921 ASSERT_EQ(0, rbd_lock_release(image1));
6922 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6923 ASSERT_FALSE(lock_owner);
6924
6925 ASSERT_EQ(-ENOENT, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
6926 lock_owners[0]));
6927 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
6928
6929 ASSERT_EQ(-EROFS, rbd_write(image1, 0, sizeof(buf), buf));
6930 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image2, 0, sizeof(buf), buf));
6931
6932 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
6933 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
6934 ASSERT_TRUE(lock_owner);
6935
6936 ASSERT_EQ(0, rbd_lock_release(image2));
6937 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
6938 ASSERT_FALSE(lock_owner);
6939
6940 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
6941 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6942 ASSERT_TRUE(lock_owner);
6943
6944 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image1, 0, sizeof(buf), buf));
6945 ASSERT_EQ(-EROFS, rbd_write(image2, 0, sizeof(buf), buf));
6946
6947 ASSERT_EQ(0, rbd_lock_release(image1));
6948 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6949 ASSERT_FALSE(lock_owner);
6950
6951 int owner_id = -1;
f67539c2 6952 std::mutex lock;
11fdf7f2 6953 const auto pingpong = [&](int m_id, rbd_image_t &m_image) {
7c673cae
FG
6954 for (int i = 0; i < 10; i++) {
6955 {
f67539c2 6956 std::lock_guard<std::mutex> locker(lock);
31f18b77 6957 if (owner_id == m_id) {
7c673cae
FG
6958 std::cout << m_id << ": releasing exclusive lock" << std::endl;
6959 EXPECT_EQ(0, rbd_lock_release(m_image));
6960 int lock_owner;
6961 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
6962 EXPECT_FALSE(lock_owner);
31f18b77 6963 owner_id = -1;
7c673cae
FG
6964 std::cout << m_id << ": exclusive lock released" << std::endl;
6965 continue;
6966 }
6967 }
6968
6969 std::cout << m_id << ": acquiring exclusive lock" << std::endl;
6970 int r;
6971 do {
6972 r = rbd_lock_acquire(m_image, RBD_LOCK_MODE_EXCLUSIVE);
6973 if (r == -EROFS) {
6974 usleep(1000);
6975 }
6976 } while (r == -EROFS);
6977 EXPECT_EQ(0, r);
6978
6979 int lock_owner;
6980 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
6981 EXPECT_TRUE(lock_owner);
6982 std::cout << m_id << ": exclusive lock acquired" << std::endl;
6983 {
f67539c2 6984 std::lock_guard<std::mutex> locker(lock);
31f18b77 6985 owner_id = m_id;
7c673cae
FG
6986 }
6987 usleep(rand() % 50000);
6988 }
6989
f67539c2 6990 std::lock_guard<std::mutex> locker(lock);
31f18b77 6991 if (owner_id == m_id) {
7c673cae
FG
6992 EXPECT_EQ(0, rbd_lock_release(m_image));
6993 int lock_owner;
6994 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
6995 EXPECT_FALSE(lock_owner);
31f18b77 6996 owner_id = -1;
7c673cae 6997 }
31f18b77
FG
6998 };
6999 thread ping(bind(pingpong, 1, ref(image1)));
7000 thread pong(bind(pingpong, 2, ref(image2)));
7c673cae 7001
7c673cae
FG
7002 ping.join();
7003 pong.join();
7004
7005 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
7006 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
7007 ASSERT_TRUE(lock_owner);
7008
7009 ASSERT_EQ(0, rbd_close(image2));
7010
7011 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
7012 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
7013 ASSERT_TRUE(lock_owner);
7014
7015 ASSERT_EQ(0, rbd_close(image1));
7016 rados_ioctx_destroy(ioctx);
7017}
7018
7019TEST_F(TestLibRBD, BreakLock)
7020{
7021 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
f67539c2 7022 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
7c673cae
FG
7023
7024 static char buf[10];
7025
f67539c2
TL
7026 rados_t blocklist_cluster;
7027 ASSERT_EQ("", connect_cluster(&blocklist_cluster));
7c673cae 7028
f67539c2 7029 rados_ioctx_t ioctx, blocklist_ioctx;
7c673cae 7030 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
f67539c2
TL
7031 ASSERT_EQ(0, rados_ioctx_create(blocklist_cluster, m_pool_name.c_str(),
7032 &blocklist_ioctx));
7c673cae
FG
7033
7034 std::string name = get_temp_image_name();
7035 uint64_t size = 2 << 20;
7036 int order = 0;
7037 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7038
f67539c2 7039 rbd_image_t image, blocklist_image;
7c673cae 7040 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
f67539c2 7041 ASSERT_EQ(0, rbd_open(blocklist_ioctx, name.c_str(), &blocklist_image, NULL));
7c673cae 7042
f67539c2
TL
7043 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_blocklist_on_break_lock", "true"));
7044 ASSERT_EQ(0, rbd_lock_acquire(blocklist_image, RBD_LOCK_MODE_EXCLUSIVE));
7c673cae
FG
7045
7046 rbd_lock_mode_t lock_mode;
7047 char *lock_owners[1];
7048 size_t max_lock_owners = 1;
7049 ASSERT_EQ(0, rbd_lock_get_owners(image, &lock_mode, lock_owners,
7050 &max_lock_owners));
7051 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
7052 ASSERT_STRNE("", lock_owners[0]);
7053 ASSERT_EQ(1U, max_lock_owners);
7054
7055 ASSERT_EQ(0, rbd_lock_break(image, RBD_LOCK_MODE_EXCLUSIVE, lock_owners[0]));
7056 ASSERT_EQ(0, rbd_lock_acquire(image, RBD_LOCK_MODE_EXCLUSIVE));
f67539c2 7057 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blocklist_cluster));
7c673cae
FG
7058
7059 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image, 0, sizeof(buf), buf));
f67539c2 7060 ASSERT_EQ(-EBLOCKLISTED, rbd_write(blocklist_image, 0, sizeof(buf), buf));
7c673cae
FG
7061
7062 ASSERT_EQ(0, rbd_close(image));
f67539c2 7063 ASSERT_EQ(0, rbd_close(blocklist_image));
7c673cae
FG
7064
7065 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
7066
7067 rados_ioctx_destroy(ioctx);
f67539c2
TL
7068 rados_ioctx_destroy(blocklist_ioctx);
7069 rados_shutdown(blocklist_cluster);
7c673cae
FG
7070}
7071
7072TEST_F(TestLibRBD, DiscardAfterWrite)
7073{
7c673cae
FG
7074 librados::IoCtx ioctx;
7075 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7076
7077 librbd::RBD rbd;
7078 std::string name = get_temp_image_name();
7079 uint64_t size = 1 << 20;
7080 int order = 18;
7081 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7082
7083 librbd::Image image;
7084 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7085
f67539c2
TL
7086 if (this->is_skip_partial_discard_enabled(image)) {
7087 return;
7088 }
7089
7c673cae
FG
7090 // enable writeback cache
7091 ASSERT_EQ(0, image.flush());
7092
7093 bufferlist bl;
7094 bl.append(std::string(256, '1'));
7095
7096 librbd::RBD::AioCompletion *write_comp =
7097 new librbd::RBD::AioCompletion(NULL, NULL);
7098 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
7099 ASSERT_EQ(0, write_comp->wait_for_complete());
7100 write_comp->release();
7101
7102 librbd::RBD::AioCompletion *discard_comp =
7103 new librbd::RBD::AioCompletion(NULL, NULL);
7104 ASSERT_EQ(0, image.aio_discard(0, 256, discard_comp));
7105 ASSERT_EQ(0, discard_comp->wait_for_complete());
7106 discard_comp->release();
7107
7108 librbd::RBD::AioCompletion *read_comp =
7109 new librbd::RBD::AioCompletion(NULL, NULL);
7110 bufferlist read_bl;
7111 image.aio_read(0, bl.length(), read_bl, read_comp);
7112 ASSERT_EQ(0, read_comp->wait_for_complete());
7113 ASSERT_EQ(bl.length(), read_comp->get_return_value());
7114 ASSERT_TRUE(read_bl.is_zero());
7115 read_comp->release();
7116}
7117
7118TEST_F(TestLibRBD, DefaultFeatures) {
7119 std::string orig_default_features;
7120 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", orig_default_features));
7121 BOOST_SCOPE_EXIT_ALL(orig_default_features) {
7122 ASSERT_EQ(0, _rados.conf_set("rbd_default_features",
7123 orig_default_features.c_str()));
7124 };
7125
7126 std::list<std::pair<std::string, std::string> > feature_names_to_bitmask = {
7127 {"", orig_default_features},
7128 {"layering", "1"},
7129 {"layering, exclusive-lock", "5"},
7130 {"exclusive-lock,journaling", "68"},
7131 {"125", "125"}
7132 };
7133
7134 for (auto &pair : feature_names_to_bitmask) {
7135 ASSERT_EQ(0, _rados.conf_set("rbd_default_features", pair.first.c_str()));
7136 std::string features;
7137 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", features));
7138 ASSERT_EQ(pair.second, features);
7139 }
7140}
7141
7142TEST_F(TestLibRBD, TestTrashMoveAndPurge) {
11fdf7f2
TL
7143 REQUIRE_FORMAT_V2();
7144
7c673cae
FG
7145 librados::IoCtx ioctx;
7146 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7147
7148 librbd::RBD rbd;
7149 std::string name = get_temp_image_name();
7150
7151 uint64_t size = 1 << 18;
7152 int order = 12;
7153 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7154
7155 librbd::Image image;
7156 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 7157
7c673cae
FG
7158 std::string image_id;
7159 ASSERT_EQ(0, image.get_id(&image_id));
7160 image.close();
7161
7162 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 0));
7163
7164 std::vector<std::string> images;
7165 ASSERT_EQ(0, rbd.list(ioctx, images));
7166 for (const auto& image : images) {
7167 ASSERT_TRUE(image != name);
7168 }
7169
7170 librbd::trash_image_info_t info;
7171 ASSERT_EQ(-ENOENT, rbd.trash_get(ioctx, "dummy image id", &info));
7172 ASSERT_EQ(0, rbd.trash_get(ioctx, image_id.c_str(), &info));
7173 ASSERT_EQ(image_id, info.id);
7174
7175 std::vector<librbd::trash_image_info_t> entries;
7176 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
7177 ASSERT_FALSE(entries.empty());
7178 ASSERT_EQ(entries.begin()->id, image_id);
7179
7180 entries.clear();
7181 PrintProgress pp;
7182 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
7183 false, pp));
7184 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
7185 ASSERT_TRUE(entries.empty());
7186}
7187
7188TEST_F(TestLibRBD, TestTrashMoveAndPurgeNonExpiredDelay) {
11fdf7f2
TL
7189 REQUIRE_FORMAT_V2();
7190
7c673cae
FG
7191 librados::IoCtx ioctx;
7192 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7193
7194 librbd::RBD rbd;
7195 std::string name = get_temp_image_name();
7196
7197 uint64_t size = 1 << 18;
7198 int order = 12;
7199 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7200
7201 librbd::Image image;
7202 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 7203
7c673cae
FG
7204 std::string image_id;
7205 ASSERT_EQ(0, image.get_id(&image_id));
7206 image.close();
7207
7208 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 100));
7209
7210 PrintProgress pp;
7211 ASSERT_EQ(-EPERM, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
7212 false, pp));
7213
7214 PrintProgress pp2;
7215 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
7216 true, pp2));
7217}
7218
11fdf7f2
TL
7219TEST_F(TestLibRBD, TestTrashPurge) {
7220 REQUIRE_FORMAT_V2();
7221
7222 librados::IoCtx ioctx;
7223 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7224
7225 librbd::RBD rbd;
7226 std::string name1 = get_temp_image_name();
7227 std::string name2 = get_temp_image_name();
7228
7229 uint64_t size = 1 << 18;
7230 int order = 12;
7231 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name1.c_str(), size, &order));
7232 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
7233
7234 librbd::Image image1;
7235 ASSERT_EQ(0, rbd.open(ioctx, image1, name1.c_str(), nullptr));
7236
7237 std::string image_id1;
7238 ASSERT_EQ(0, image1.get_id(&image_id1));
7239 image1.close();
7240
7241 ASSERT_EQ(0, rbd.trash_move(ioctx, name1.c_str(), 0));
7242
7243 librbd::Image image2;
7244 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), nullptr));
7245 ceph::bufferlist bl;
7246 bl.append(std::string(1024, '0'));
7247 ASSERT_EQ(1024, image2.write(0, 1024, bl));
7248
7249 std::string image_id2;
7250 ASSERT_EQ(0, image2.get_id(&image_id2));
7251 image2.close();
7252
7253 ASSERT_EQ(0, rbd.trash_move(ioctx, name2.c_str(), 100));
7254 ASSERT_EQ(0, rbd.trash_purge(ioctx, 0, -1));
7255
7256 std::vector<librbd::trash_image_info_t> entries;
7257 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
7258 ASSERT_EQ(1U, entries.size());
7259 ASSERT_EQ(image_id2, entries[0].id);
7260 ASSERT_EQ(name2, entries[0].name);
7261 entries.clear();
7262
7263 struct timespec now;
7264 clock_gettime(CLOCK_REALTIME, &now);
7265 float threshold = 0.0;
7266 if (!is_librados_test_stub(_rados)) {
7267 // real cluster usage reports have a long latency to update
7268 threshold = -1.0;
7269 }
7270
7271 ASSERT_EQ(0, rbd.trash_purge(ioctx, now.tv_sec+1000, threshold));
7272 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
7273 ASSERT_EQ(0U, entries.size());
7274}
7275
7c673cae 7276TEST_F(TestLibRBD, TestTrashMoveAndRestore) {
11fdf7f2
TL
7277 REQUIRE_FORMAT_V2();
7278
7c673cae
FG
7279 librados::IoCtx ioctx;
7280 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7281
7282 librbd::RBD rbd;
7283 std::string name = get_temp_image_name();
7284
7285 uint64_t size = 1 << 18;
7286 int order = 12;
7287 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7288
7289 librbd::Image image;
7290 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 7291
7c673cae
FG
7292 std::string image_id;
7293 ASSERT_EQ(0, image.get_id(&image_id));
7294 image.close();
7295
7296 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 10));
7297
7298 std::vector<std::string> images;
7299 ASSERT_EQ(0, rbd.list(ioctx, images));
7300 for (const auto& image : images) {
7301 ASSERT_TRUE(image != name);
7302 }
7303
7304 std::vector<librbd::trash_image_info_t> entries;
7305 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
7306 ASSERT_FALSE(entries.empty());
7307 ASSERT_EQ(entries.begin()->id, image_id);
7308
7309 images.clear();
7310 ASSERT_EQ(0, rbd.trash_restore(ioctx, image_id.c_str(), ""));
7311 ASSERT_EQ(0, rbd.list(ioctx, images));
7312 ASSERT_FALSE(images.empty());
7313 bool found = false;
7314 for (const auto& image : images) {
7315 if (image == name) {
7316 found = true;
7317 break;
7318 }
7319 }
7320 ASSERT_TRUE(found);
7321}
31f18b77 7322
11fdf7f2
TL
7323TEST_F(TestLibRBD, TestListWatchers) {
7324 librados::IoCtx ioctx;
7325 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7326
7327 librbd::RBD rbd;
7328 std::string name = get_temp_image_name();
7329
7330 uint64_t size = 1 << 18;
7331 int order = 12;
7332 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7333
7334 librbd::Image image;
7335 std::list<librbd::image_watcher_t> watchers;
7336
7337 // No watchers
7338 ASSERT_EQ(0, rbd.open_read_only(ioctx, image, name.c_str(), nullptr));
7339 ASSERT_EQ(0, image.list_watchers(watchers));
7340 ASSERT_EQ(0U, watchers.size());
7341 ASSERT_EQ(0, image.close());
7342
7343 // One watcher
7344 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7345 ASSERT_EQ(0, image.list_watchers(watchers));
7346 ASSERT_EQ(1U, watchers.size());
7347 ASSERT_EQ(0, image.close());
7348}
7349
7350TEST_F(TestLibRBD, TestSetSnapById) {
7351 librados::IoCtx ioctx;
7352 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7353
7354 librbd::RBD rbd;
7355 std::string name = get_temp_image_name();
7356
7357 uint64_t size = 1 << 18;
7358 int order = 12;
7359 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7360
7361 librbd::Image image;
7362 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7363 ASSERT_EQ(0, image.snap_create("snap"));
7364
7365 vector<librbd::snap_info_t> snaps;
7366 ASSERT_EQ(0, image.snap_list(snaps));
7367 ASSERT_EQ(1U, snaps.size());
7368
7369 ASSERT_EQ(0, image.snap_set_by_id(snaps[0].id));
7370 ASSERT_EQ(0, image.snap_set_by_id(CEPH_NOSNAP));
7371}
7372
7373TEST_F(TestLibRBD, Namespaces) {
7374 rados_ioctx_t ioctx;
7375 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
7376 rados_remove(ioctx, RBD_NAMESPACE);
7377
7378 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name1"));
7379 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name2"));
7380 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name3"));
7381 ASSERT_EQ(0, rbd_namespace_remove(ioctx, "name2"));
7382
7383 char names[1024];
7384 size_t max_size = sizeof(names);
7385 int len = rbd_namespace_list(ioctx, names, &max_size);
7386
7387 std::vector<std::string> cpp_names;
7388 for (char* cur_name = names; cur_name < names + len; ) {
7389 cpp_names.push_back(cur_name);
7390 cur_name += strlen(cur_name) + 1;
7391 }
7392 ASSERT_EQ(2U, cpp_names.size());
7393 ASSERT_EQ("name1", cpp_names[0]);
7394 ASSERT_EQ("name3", cpp_names[1]);
7395 bool exists;
7396 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name2", &exists));
7397 ASSERT_FALSE(exists);
7398 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name3", &exists));
7399 ASSERT_TRUE(exists);
7400 rados_ioctx_destroy(ioctx);
7401}
7402
7403TEST_F(TestLibRBD, NamespacesPP) {
7404 librados::IoCtx ioctx;
7405 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7406 ioctx.remove(RBD_NAMESPACE);
7407
7408 librbd::RBD rbd;
7409 ASSERT_EQ(-EINVAL, rbd.namespace_create(ioctx, ""));
7410 ASSERT_EQ(-EINVAL, rbd.namespace_remove(ioctx, ""));
7411
7412 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name1"));
7413 ASSERT_EQ(-EEXIST, rbd.namespace_create(ioctx, "name1"));
7414 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name2"));
7415 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name3"));
7416 ASSERT_EQ(0, rbd.namespace_remove(ioctx, "name2"));
7417 ASSERT_EQ(-ENOENT, rbd.namespace_remove(ioctx, "name2"));
7418
7419 std::vector<std::string> names;
7420 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
7421 ASSERT_EQ(2U, names.size());
7422 ASSERT_EQ("name1", names[0]);
7423 ASSERT_EQ("name3", names[1]);
7424 bool exists;
7425 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name2", &exists));
7426 ASSERT_FALSE(exists);
7427 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name3", &exists));
7428 ASSERT_TRUE(exists);
7429
7430 librados::IoCtx ns_io_ctx;
7431 ns_io_ctx.dup(ioctx);
7432
7433 std::string name = get_temp_image_name();
7434 int order = 0;
7435 uint64_t features = 0;
7436 if (!get_features(&features)) {
7437 // old format doesn't support namespaces
7438 ns_io_ctx.set_namespace("name1");
7439 ASSERT_EQ(-EINVAL, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0,
7440 &order));
7441 return;
7442 }
7443
7444 ns_io_ctx.set_namespace("missing");
7445 ASSERT_EQ(-ENOENT, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
7446
7447 ns_io_ctx.set_namespace("name1");
7448 ASSERT_EQ(0, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
7449 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
7450
7451 std::string image_id;
7452 {
7453 librbd::Image image;
7454 ASSERT_EQ(-ENOENT, rbd.open(ioctx, image, name.c_str(), NULL));
7455 ASSERT_EQ(0, rbd.open(ns_io_ctx, image, name.c_str(), NULL));
7456 ASSERT_EQ(0, get_image_id(image, &image_id));
7457 }
7458
7459 ASSERT_EQ(-ENOENT, rbd.trash_move(ioctx, name.c_str(), 0));
7460 ASSERT_EQ(0, rbd.trash_move(ns_io_ctx, name.c_str(), 0));
7461 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
7462
7463 PrintProgress pp;
7464 ASSERT_EQ(-ENOENT, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
7465 false, pp));
7466 ASSERT_EQ(0, rbd.trash_remove_with_progress(ns_io_ctx, image_id.c_str(),
7467 false, pp));
7468 ASSERT_EQ(0, rbd.namespace_remove(ns_io_ctx, "name1"));
7469
7470 names.clear();
7471 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
7472 ASSERT_EQ(1U, names.size());
7473 ASSERT_EQ("name3", names[0]);
7474}
7475
7476TEST_F(TestLibRBD, Migration) {
7477 bool old_format;
7478 uint64_t features;
7479 ASSERT_EQ(0, get_features(&old_format, &features));
7480
7481 rados_ioctx_t ioctx;
7482 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7483 BOOST_SCOPE_EXIT(&ioctx) {
7484 rados_ioctx_destroy(ioctx);
7485 } BOOST_SCOPE_EXIT_END;
7486
7487 int order = 0;
7488 std::string name = get_temp_image_name();
7489 uint64_t size = 2 << 20;
7490 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7491
7492 rbd_image_options_t image_options;
7493 rbd_image_options_create(&image_options);
7494 BOOST_SCOPE_EXIT(&image_options) {
7495 rbd_image_options_destroy(image_options);
7496 } BOOST_SCOPE_EXIT_END;
7497
7498 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
7499 image_options));
7500
7501 rbd_image_migration_status_t status;
7502 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
7503 sizeof(status)));
7504 ASSERT_EQ(status.source_pool_id, rados_ioctx_get_id(ioctx));
7505 ASSERT_EQ(status.source_image_name, name);
7506 if (old_format) {
7507 ASSERT_EQ(status.source_image_id, string());
7508 } else {
7509 ASSERT_NE(status.source_image_id, string());
7510 ASSERT_EQ(-EROFS, rbd_trash_remove(ioctx, status.source_image_id, false));
7511 ASSERT_EQ(-EINVAL, rbd_trash_restore(ioctx, status.source_image_id, name.c_str()));
7512 }
7513 ASSERT_EQ(status.dest_pool_id, rados_ioctx_get_id(ioctx));
7514 ASSERT_EQ(status.dest_image_name, name);
7515 ASSERT_NE(status.dest_image_id, string());
7516 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
7517 rbd_migration_status_cleanup(&status);
7518
f67539c2
TL
7519 rbd_image_t image;
7520 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7521 char source_spec[2048];
7522 size_t source_spec_length = sizeof(source_spec);
7523 ASSERT_EQ(0, rbd_get_migration_source_spec(image, source_spec,
7524 &source_spec_length));
7525 json_spirit::mValue json_source_spec;
7526 json_spirit::read(source_spec, json_source_spec);
7527 EXPECT_EQ(0, rbd_close(image));
7528
11fdf7f2
TL
7529 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, name.c_str()));
7530 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, name.c_str(), 0));
7531
7532 ASSERT_EQ(0, rbd_migration_execute(ioctx, name.c_str()));
7533
7534 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
7535 sizeof(status)));
7536 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
7537 rbd_migration_status_cleanup(&status);
7538
7539 ASSERT_EQ(0, rbd_migration_commit(ioctx, name.c_str()));
7540
7541 std::string new_name = get_temp_image_name();
7542
7543 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx,
7544 new_name.c_str(), image_options));
7545
7546 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, new_name.c_str()));
7547 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, new_name.c_str(), 0));
7548
7549 ASSERT_EQ(0, rbd_migration_abort(ioctx, name.c_str()));
7550
11fdf7f2
TL
7551 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7552 EXPECT_EQ(0, rbd_close(image));
7553}
7554
7555TEST_F(TestLibRBD, MigrationPP) {
7556 bool old_format;
7557 uint64_t features;
7558 ASSERT_EQ(0, get_features(&old_format, &features));
7559
7560 librados::IoCtx ioctx;
7561 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7562
7563 int order = 0;
7564 std::string name = get_temp_image_name();
7565 uint64_t size = 2 << 20;
7566 librbd::RBD rbd;
7567 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7568
7569 librbd::ImageOptions image_options;
7570
7571 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
7572 image_options));
7573
7574 librbd::image_migration_status_t status;
7575 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
7576 sizeof(status)));
7577 ASSERT_EQ(status.source_pool_id, ioctx.get_id());
7578 ASSERT_EQ(status.source_image_name, name);
7579 if (old_format) {
7580 ASSERT_EQ(status.source_image_id, "");
7581 } else {
7582 ASSERT_NE(status.source_image_id, "");
7583 ASSERT_EQ(-EROFS, rbd.trash_remove(ioctx, status.source_image_id.c_str(), false));
7584 ASSERT_EQ(-EINVAL, rbd.trash_restore(ioctx, status.source_image_id.c_str(), name.c_str()));
7585 }
7586 ASSERT_EQ(status.dest_pool_id, ioctx.get_id());
7587 ASSERT_EQ(status.dest_image_name, name);
7588 ASSERT_NE(status.dest_image_id, "");
7589 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
7590
f67539c2
TL
7591 librbd::Image image;
7592 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7593 std::string source_spec;
7594 ASSERT_EQ(0, image.get_migration_source_spec(&source_spec));
7595 json_spirit::mValue json_source_spec;
7596 json_spirit::read(source_spec, json_source_spec);
7597 json_spirit::mObject json_source_spec_obj = json_source_spec.get_obj();
7598 ASSERT_EQ("native", json_source_spec_obj["type"].get_str());
7599 ASSERT_EQ(ioctx.get_id(), json_source_spec_obj["pool_id"].get_int64());
7600 ASSERT_EQ("", json_source_spec_obj["pool_namespace"].get_str());
7601 ASSERT_EQ(1, json_source_spec_obj.count("image_name"));
7602 if (!old_format) {
7603 ASSERT_EQ(1, json_source_spec_obj.count("image_id"));
7604 }
7605 ASSERT_EQ(0, image.close());
7606
11fdf7f2
TL
7607 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, name.c_str()));
7608 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, name.c_str(), 0));
7609
7610 ASSERT_EQ(0, rbd.migration_execute(ioctx, name.c_str()));
7611
7612 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
7613 sizeof(status)));
7614 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
7615
7616 ASSERT_EQ(0, rbd.migration_commit(ioctx, name.c_str()));
7617
7618 std::string new_name = get_temp_image_name();
7619
7620 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx,
7621 new_name.c_str(), image_options));
7622
7623 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, new_name.c_str()));
7624 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, new_name.c_str(), 0));
7625
7626 ASSERT_EQ(0, rbd.migration_abort(ioctx, name.c_str()));
7627
11fdf7f2
TL
7628 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7629}
7630
7631TEST_F(TestLibRBD, TestGetAccessTimestamp)
7632{
7633 REQUIRE_FORMAT_V2();
7634
7635 rados_ioctx_t ioctx;
7636 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7637
7638 rbd_image_t image;
7639 int order = 0;
7640 std::string name = get_temp_image_name();
7641 uint64_t size = 2 << 20;
7642 struct timespec timestamp;
7643
7644 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7645 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7646
7647 ASSERT_EQ(0, rbd_get_access_timestamp(image, &timestamp));
7648 ASSERT_LT(0, timestamp.tv_sec);
7649
7650 ASSERT_PASSED(validate_object_map, image);
7651 ASSERT_EQ(0, rbd_close(image));
7652
7653 rados_ioctx_destroy(ioctx);
7654}
7655
7656TEST_F(TestLibRBD, TestGetModifyTimestamp)
7657{
7658 REQUIRE_FORMAT_V2();
7659
7660 rados_ioctx_t ioctx;
7661 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7662
7663 rbd_image_t image;
7664 int order = 0;
7665 std::string name = get_temp_image_name();
7666 uint64_t size = 2 << 20;
7667 struct timespec timestamp;
7668
7669 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7670 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7671 ASSERT_EQ(0, rbd_get_modify_timestamp(image, &timestamp));
7672 ASSERT_LT(0, timestamp.tv_sec);
7673
7674 ASSERT_PASSED(validate_object_map, image);
7675 ASSERT_EQ(0, rbd_close(image));
7676
7677 rados_ioctx_destroy(ioctx);
7678}
7679
91327a77
AA
7680TEST_F(TestLibRBD, ZeroOverlapFlatten) {
7681 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7682
7683 librados::IoCtx ioctx;
7684 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7685
7686 librbd::RBD rbd;
7687 librbd::Image parent_image;
7688 std::string name = get_temp_image_name();
7689
7690 uint64_t size = 1;
7691 int order = 0;
7692
7693 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7694 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
7695
7696 uint64_t features;
7697 ASSERT_EQ(0, parent_image.features(&features));
7698
7699 ASSERT_EQ(0, parent_image.snap_create("snap"));
7700 ASSERT_EQ(0, parent_image.snap_protect("snap"));
7701
7702 std::string clone_name = this->get_temp_image_name();
7703 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
7704 features, &order));
7705
7706 librbd::Image clone_image;
7707 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
7708 ASSERT_EQ(0, clone_image.resize(0));
7709 ASSERT_EQ(0, clone_image.flatten());
7710}
7711
11fdf7f2
TL
7712TEST_F(TestLibRBD, PoolMetadata)
7713{
7714 REQUIRE_FORMAT_V2();
7715
7716 rados_ioctx_t ioctx;
7717 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7718
7719 char keys[1024];
7720 char vals[1024];
7721 size_t keys_len = sizeof(keys);
7722 size_t vals_len = sizeof(vals);
7723
7724 memset_rand(keys, keys_len);
7725 memset_rand(vals, vals_len);
7726
7727 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7728 &vals_len));
7729 ASSERT_EQ(0U, keys_len);
7730 ASSERT_EQ(0U, vals_len);
7731
7732 char value[1024];
7733 size_t value_len = sizeof(value);
7734 memset_rand(value, value_len);
7735
7736 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
7737 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key2", "value2"));
7738 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
7739 ASSERT_STREQ(value, "value1");
7740 value_len = 1;
7741 ASSERT_EQ(-ERANGE, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
7742 ASSERT_EQ(value_len, strlen("value1") + 1);
7743
7744 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7745 &vals_len));
7746 keys_len = sizeof(keys);
7747 vals_len = sizeof(vals);
7748 memset_rand(keys, keys_len);
7749 memset_rand(vals, vals_len);
7750 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7751 &vals_len));
7752 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
7753 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
7754 ASSERT_STREQ(keys, "key1");
7755 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
7756 ASSERT_STREQ(vals, "value1");
7757 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
7758
7759 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
7760 ASSERT_EQ(-ENOENT, rbd_pool_metadata_remove(ioctx, "key3"));
7761 value_len = sizeof(value);
7762 ASSERT_EQ(-ENOENT, rbd_pool_metadata_get(ioctx, "key3", value, &value_len));
7763 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7764 &vals_len));
7765 ASSERT_EQ(keys_len, strlen("key2") + 1);
7766 ASSERT_EQ(vals_len, strlen("value2") + 1);
7767 ASSERT_STREQ(keys, "key2");
7768 ASSERT_STREQ(vals, "value2");
7769
7770 // test config setting
7771 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
7772 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7773 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
7774 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
7775
7776 // test short buffer cases
7777 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
7778 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key3", "value3"));
7779 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key4", "value4"));
7780
7781 keys_len = strlen("key1") + 1;
7782 vals_len = strlen("value1") + 1;
7783 memset_rand(keys, keys_len);
7784 memset_rand(vals, vals_len);
7785 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 1, keys, &keys_len, vals,
7786 &vals_len));
7787 ASSERT_EQ(keys_len, strlen("key1") + 1);
7788 ASSERT_EQ(vals_len, strlen("value1") + 1);
7789 ASSERT_STREQ(keys, "key1");
7790 ASSERT_STREQ(vals, "value1");
7791
7792 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 2, keys, &keys_len, vals,
7793 &vals_len));
7794 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
7795 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
7796
7797 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7798 &vals_len));
7799 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
7800 1 + strlen("key4") + 1);
7801 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
7802 strlen("value3") + 1 + strlen("value4") + 1);
7803
7804 // test `start` param
7805 keys_len = sizeof(keys);
7806 vals_len = sizeof(vals);
7807 memset_rand(keys, keys_len);
7808 memset_rand(vals, vals_len);
7809 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "key2", 0, keys, &keys_len, vals,
7810 &vals_len));
7811 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
7812 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
7813 ASSERT_STREQ(keys, "key3");
7814 ASSERT_STREQ(vals, "value3");
7815
7816 //cleanup
7817 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
7818 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key2"));
7819 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key3"));
7820 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key4"));
7821 rados_ioctx_destroy(ioctx);
7822}
7823
7824TEST_F(TestLibRBD, PoolMetadataPP)
7825{
7826 REQUIRE_FORMAT_V2();
7827
7828 librbd::RBD rbd;
7829 string value;
7830 map<string, bufferlist> pairs;
7831
7832 librados::IoCtx ioctx;
7833 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7834
7835 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
7836 ASSERT_TRUE(pairs.empty());
7837
7838 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
7839 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key2", "value2"));
7840 ASSERT_EQ(0, rbd.pool_metadata_get(ioctx, "key1", &value));
7841 ASSERT_EQ(value, "value1");
7842 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
7843 ASSERT_EQ(2U, pairs.size());
7844 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
7845 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7846
7847 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
7848 ASSERT_EQ(-ENOENT, rbd.pool_metadata_remove(ioctx, "key3"));
7849 ASSERT_EQ(-ENOENT, rbd.pool_metadata_get(ioctx, "key3", &value));
7850 pairs.clear();
7851 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
7852 ASSERT_EQ(1U, pairs.size());
7853 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7854
7855 // test `start` param
7856 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
7857 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key3", "value3"));
7858
7859 pairs.clear();
7860 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "key2", 0, &pairs));
7861 ASSERT_EQ(1U, pairs.size());
7862 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
7863
7864 // test config setting
7865 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
7866 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7867 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
7868 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
7869
7870 // cleanup
7871 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
7872 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key2"));
7873 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key3"));
7874}
7875
7876TEST_F(TestLibRBD, Config)
7877{
7878 REQUIRE_FORMAT_V2();
7879
7880 rados_ioctx_t ioctx;
7881 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7882
7883 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7884
7885 rbd_config_option_t options[1024];
7886 int max_options = 0;
7887 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
7888 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
7889 ASSERT_GT(max_options, 0);
7890 ASSERT_LT(max_options, 1024);
7891 for (int i = 0; i < max_options; i++) {
7892 if (options[i].name == std::string("rbd_cache")) {
7893 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
7894 ASSERT_STREQ("false", options[i].value);
7895 } else {
7896 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7897 }
7898 }
7899 rbd_config_pool_list_cleanup(options, max_options);
7900
7901 rbd_image_t image;
7902 int order = 0;
7903 std::string name = get_temp_image_name();
7904 uint64_t size = 2 << 20;
7905
7906 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7907 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7908
7909 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
7910 for (int i = 0; i < max_options; i++) {
7911 if (options[i].name == std::string("rbd_cache")) {
7912 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
7913 ASSERT_STREQ("false", options[i].value);
7914 } else {
7915 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7916 }
7917 }
7918 rbd_config_image_list_cleanup(options, max_options);
7919
7920 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_cache", "true"));
7921
7922 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
7923 for (int i = 0; i < max_options; i++) {
7924 if (options[i].name == std::string("rbd_cache")) {
7925 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_IMAGE);
7926 ASSERT_STREQ("true", options[i].value);
7927 } else {
7928 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7929 }
7930 }
7931 rbd_config_image_list_cleanup(options, max_options);
7932
7933 ASSERT_EQ(0, rbd_metadata_remove(image, "conf_rbd_cache"));
7934
7935 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
7936 for (int i = 0; i < max_options; i++) {
7937 if (options[i].name == std::string("rbd_cache")) {
7938 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
7939 ASSERT_STREQ("false", options[i].value);
7940 } else {
7941 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7942 }
7943 }
7944 rbd_config_image_list_cleanup(options, max_options);
7945
7946 ASSERT_EQ(0, rbd_close(image));
7947
7948 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
7949
7950 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
7951 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
7952 for (int i = 0; i < max_options; i++) {
7953 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7954 }
7955 rbd_config_pool_list_cleanup(options, max_options);
7956
7957 rados_ioctx_destroy(ioctx);
7958}
7959
7960TEST_F(TestLibRBD, ConfigPP)
7961{
7962 REQUIRE_FORMAT_V2();
7963
7964 librbd::RBD rbd;
7965 string value;
7966
7967 librados::IoCtx ioctx;
7968 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7969
7970 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7971
7972 std::vector<librbd::config_option_t> options;
7973 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
7974 for (auto &option : options) {
7975 if (option.name == std::string("rbd_cache")) {
7976 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
7977 ASSERT_EQ("false", option.value);
7978 } else {
7979 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
7980 }
7981 }
7982
7983 int order = 0;
7984 std::string name = get_temp_image_name();
7985 uint64_t size = 2 << 20;
7986 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7987
7988 librbd::Image image;
7989 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7990
7991 options.clear();
7992 ASSERT_EQ(0, image.config_list(&options));
7993 for (auto &option : options) {
7994 if (option.name == std::string("rbd_cache")) {
7995 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
7996 ASSERT_EQ("false", option.value);
7997 } else {
7998 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
7999 }
8000 }
8001
8002 ASSERT_EQ(0, image.metadata_set("conf_rbd_cache", "true"));
8003
8004 options.clear();
8005 ASSERT_EQ(0, image.config_list(&options));
8006 for (auto &option : options) {
8007 if (option.name == std::string("rbd_cache")) {
8008 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_IMAGE);
8009 ASSERT_EQ("true", option.value);
8010 } else {
8011 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
8012 }
8013 }
8014
8015 ASSERT_EQ(0, image.metadata_remove("conf_rbd_cache"));
8016
8017 options.clear();
8018 ASSERT_EQ(0, image.config_list(&options));
8019 for (auto &option : options) {
8020 if (option.name == std::string("rbd_cache")) {
8021 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
8022 ASSERT_EQ("false", option.value);
8023 } else {
8024 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
8025 }
8026 }
8027
8028 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
8029
8030 options.clear();
8031 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
8032 for (auto &option : options) {
8033 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
8034 }
8035}
8036
8037TEST_F(TestLibRBD, PoolStatsPP)
8038{
8039 REQUIRE_FORMAT_V2();
8040
8041 librados::IoCtx ioctx;
8042 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
8043
8044 librbd::RBD rbd;
8045 std::string image_name;
8046 uint64_t size = 2 << 20;
8047 uint64_t expected_size = 0;
8048 for (size_t idx = 0; idx < 4; ++idx) {
8049 image_name = get_temp_image_name();
8050
8051 int order = 0;
8052 ASSERT_EQ(0, create_image_pp(rbd, ioctx, image_name.c_str(), size, &order));
8053 expected_size += size;
8054 }
8055
8056 librbd::Image image;
8057 ASSERT_EQ(0, rbd.open(ioctx, image, image_name.c_str(), NULL));
8058 ASSERT_EQ(0, image.snap_create("snap1"));
8059 ASSERT_EQ(0, image.resize(0));
8060 ASSERT_EQ(0, image.close());
8061 uint64_t expect_head_size = (expected_size - size);
8062
8063 uint64_t image_count;
8064 uint64_t provisioned_bytes;
8065 uint64_t max_provisioned_bytes;
8066 uint64_t snap_count;
8067 uint64_t trash_image_count;
8068 uint64_t trash_provisioned_bytes;
8069 uint64_t trash_max_provisioned_bytes;
8070 uint64_t trash_snap_count;
8071
8072 librbd::PoolStats pool_stats1;
8073 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGES, &image_count);
8074 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
8075 &provisioned_bytes);
8076 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
8077
8078 ASSERT_EQ(4U, image_count);
8079 ASSERT_EQ(expect_head_size, provisioned_bytes);
8080
8081 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
8082 &max_provisioned_bytes);
8083 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
8084 ASSERT_EQ(4U, image_count);
8085 ASSERT_EQ(expect_head_size, provisioned_bytes);
8086 ASSERT_EQ(expected_size, max_provisioned_bytes);
8087
8088 librbd::PoolStats pool_stats2;
8089 pool_stats2.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snap_count);
8090 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
8091 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
8092 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats2));
8093 ASSERT_EQ(1U, snap_count);
8094 ASSERT_EQ(0U, trash_image_count);
8095 ASSERT_EQ(0U, trash_snap_count);
8096
8097 ASSERT_EQ(0, rbd.trash_move(ioctx, image_name.c_str(), 0));
8098
8099 librbd::PoolStats pool_stats3;
8100 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
8101 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
8102 &trash_provisioned_bytes);
8103 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
8104 &trash_max_provisioned_bytes);
8105 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
8106 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats3));
8107 ASSERT_EQ(1U, trash_image_count);
8108 ASSERT_EQ(0U, trash_provisioned_bytes);
8109 ASSERT_EQ(size, trash_max_provisioned_bytes);
8110 ASSERT_EQ(1U, trash_snap_count);
8111}
8112
8113TEST_F(TestLibRBD, ImageSpec) {
8114 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8115
8116 librados::IoCtx ioctx;
8117 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
8118
8119 librbd::RBD rbd;
8120 librbd::Image parent_image;
8121 std::string name = get_temp_image_name();
8122
8123 uint64_t size = 1;
8124 int order = 0;
8125
8126 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8127 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
8128
8129 std::string parent_id;
8130 ASSERT_EQ(0, parent_image.get_id(&parent_id));
8131
8132 uint64_t features;
8133 ASSERT_EQ(0, parent_image.features(&features));
8134
8135 ASSERT_EQ(0, parent_image.snap_create("snap"));
8136 ASSERT_EQ(0, parent_image.snap_protect("snap"));
8137
8138 std::string clone_name = this->get_temp_image_name();
8139 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
8140 features, &order));
8141
8142 librbd::Image clone_image;
8143 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
8144
8145 std::string clone_id;
8146 ASSERT_EQ(0, clone_image.get_id(&clone_id));
8147
8148 std::vector<librbd::image_spec_t> images;
8149 ASSERT_EQ(0, rbd.list2(ioctx, &images));
8150
8151 std::vector<librbd::image_spec_t> expected_images{
8152 {.id = parent_id, .name = name},
8153 {.id = clone_id, .name = clone_name}
8154 };
8155 std::sort(expected_images.begin(), expected_images.end(),
8156 [](const librbd::image_spec_t& lhs, const librbd::image_spec_t &rhs) {
8157 return lhs.name < rhs.name;
8158 });
8159 ASSERT_EQ(expected_images, images);
8160
8161 librbd::linked_image_spec_t parent_image_spec;
8162 librbd::snap_spec_t parent_snap_spec;
8163 ASSERT_EQ(0, clone_image.get_parent(&parent_image_spec, &parent_snap_spec));
8164
8165 librbd::linked_image_spec_t expected_parent_image_spec{
8166 .pool_id = ioctx.get_id(),
8167 .pool_name = ioctx.get_pool_name(),
8168 .pool_namespace = ioctx.get_namespace(),
8169 .image_id = parent_id,
8170 .image_name = name,
8171 .trash = false
8172 };
8173 ASSERT_EQ(expected_parent_image_spec, parent_image_spec);
8174 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER, parent_snap_spec.namespace_type);
8175 ASSERT_EQ("snap", parent_snap_spec.name);
8176
8177 std::vector<librbd::linked_image_spec_t> children;
8178 ASSERT_EQ(0, parent_image.list_children3(&children));
8179
8180 std::vector<librbd::linked_image_spec_t> expected_children{
8181 {
8182 .pool_id = ioctx.get_id(),
8183 .pool_name = ioctx.get_pool_name(),
8184 .pool_namespace = ioctx.get_namespace(),
8185 .image_id = clone_id,
8186 .image_name = clone_name,
8187 .trash = false
8188 }
8189 };
8190 ASSERT_EQ(expected_children, children);
8191
8192 children.clear();
8193 ASSERT_EQ(0, parent_image.list_descendants(&children));
8194 ASSERT_EQ(expected_children, children);
8195
8196 ASSERT_EQ(0, clone_image.snap_create("snap"));
8197 ASSERT_EQ(0, clone_image.snap_protect("snap"));
8198
8199 auto grand_clone_name = this->get_temp_image_name();
8200 ASSERT_EQ(0, rbd.clone(ioctx, clone_name.c_str(), "snap", ioctx,
8201 grand_clone_name.c_str(), features, &order));
8202 librbd::Image grand_clone_image;
8203 ASSERT_EQ(0, rbd.open(ioctx, grand_clone_image, grand_clone_name.c_str(),
8204 nullptr));
8205 std::string grand_clone_id;
8206 ASSERT_EQ(0, grand_clone_image.get_id(&grand_clone_id));
8207
8208 children.clear();
8209 ASSERT_EQ(0, parent_image.list_children3(&children));
8210 ASSERT_EQ(expected_children, children);
8211
8212 children.clear();
8213 ASSERT_EQ(0, parent_image.list_descendants(&children));
8214 expected_children.push_back(
8215 {
8216 .pool_id = ioctx.get_id(),
8217 .pool_name = ioctx.get_pool_name(),
8218 .pool_namespace = ioctx.get_namespace(),
8219 .image_id = grand_clone_id,
8220 .image_name = grand_clone_name,
8221 .trash = false
8222 }
8223 );
8224 ASSERT_EQ(expected_children, children);
8225}
8226
9f95a23c
TL
8227void super_simple_write_cb_pp(librbd::completion_t cb, void *arg)
8228{
8229}
8230
8231TEST_F(TestLibRBD, DISABLED_TestSeqWriteAIOPP)
8232{
8233 librados::IoCtx ioctx;
8234 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8235
8236 {
8237 librbd::RBD rbd;
8238 librbd::Image image;
8239 int order = 21;
8240 std::string name = get_temp_image_name();
8241 uint64_t size = 5 * (1 << order);
8242
8243 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8244 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8245
8246 char test_data[(TEST_IO_SIZE + 1) * 10];
8247
8248 for (int i = 0; i < 10; i++) {
8249 for (uint64_t j = 0; j < TEST_IO_SIZE; j++) {
8250 test_data[(TEST_IO_SIZE + 1) * i + j] = (char)(rand() % (126 - 33) + 33);
8251 }
8252 test_data[(TEST_IO_SIZE + 1) * i + TEST_IO_SIZE] = '\0';
8253 }
8254
8255 struct timespec start_time;
8256 clock_gettime(CLOCK_REALTIME, &start_time);
8257
8258 std::list<librbd::RBD::AioCompletion *> comps;
8259 for (uint64_t i = 0; i < size / TEST_IO_SIZE; ++i) {
8260 char *p = test_data + (TEST_IO_SIZE + 1) * (i % 10);
8261 ceph::bufferlist bl;
8262 bl.append(p, strlen(p));
8263 auto comp = new librbd::RBD::AioCompletion(
8264 NULL, (librbd::callback_t) super_simple_write_cb_pp);
8265 image.aio_write(strlen(p) * i, strlen(p), bl, comp);
8266 comps.push_back(comp);
8267 if (i % 1000 == 0) {
8268 cout << i << " reqs sent" << std::endl;
8269 image.flush();
8270 for (auto comp : comps) {
8271 comp->wait_for_complete();
8272 ASSERT_EQ(0, comp->get_return_value());
8273 comp->release();
8274 }
8275 comps.clear();
8276 }
8277 }
8278 int i = 0;
8279 for (auto comp : comps) {
8280 comp->wait_for_complete();
8281 ASSERT_EQ(0, comp->get_return_value());
8282 comp->release();
8283 if (i % 1000 == 0) {
8284 std::cout << i << " reqs completed" << std::endl;
8285 }
8286 i++;
8287 }
8288 comps.clear();
8289
f67539c2
TL
8290 struct timespec end_time;
8291 clock_gettime(CLOCK_REALTIME, &end_time);
8292 int duration = end_time.tv_sec * 1000 + end_time.tv_nsec / 1000000 -
8293 start_time.tv_sec * 1000 - start_time.tv_nsec / 1000000;
8294 std::cout << "duration: " << duration << " msec" << std::endl;
8295
8296 for (uint64_t i = 0; i < size / TEST_IO_SIZE; ++i) {
8297 char *p = test_data + (TEST_IO_SIZE + 1) * (i % 10);
8298 ASSERT_PASSED(read_test_data, image, p, strlen(p) * i, TEST_IO_SIZE, 0);
8299 }
8300
8301 ASSERT_PASSED(validate_object_map, image);
8302 }
8303
8304 ioctx.close();
8305}
8306
8307TEST_F(TestLibRBD, SnapRemoveWithChildMissing)
8308{
8309 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8310 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
8311 BOOST_SCOPE_EXIT_ALL(&) {
8312 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
8313 };
8314
8315 librbd::RBD rbd;
8316 rados_ioctx_t ioctx1, ioctx2;
8317 string pool_name1 = create_pool(true);
8318 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
8319 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx2));
8320
8321 bool old_format;
8322 uint64_t features;
8323 rbd_image_t parent, child1, child2, child3;
8324 int order = 0;
8325 char child_id1[4096];
8326 char child_id2[4096];
8327 char child_id3[4096];
8328
8329 ASSERT_EQ(0, get_features(&old_format, &features));
8330 ASSERT_FALSE(old_format);
8331 std::string parent_name = get_temp_image_name();
8332 std::string child_name1 = get_temp_image_name();
8333 std::string child_name2 = get_temp_image_name();
8334 std::string child_name3 = get_temp_image_name();
8335 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
8336 false, features));
8337 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
8338 ASSERT_EQ(0, rbd_snap_create(parent, "snap1"));
8339 ASSERT_EQ(0, rbd_snap_create(parent, "snap2"));
8340
8341 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap1",
8342 ioctx2, child_name1.c_str(), features, &order));
8343 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
8344 ioctx1, child_name2.c_str(), features, &order));
8345 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
8346 ioctx2, child_name3.c_str(), features, &order));
8347
8348 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &child1, NULL));
8349 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &child2, NULL));
8350 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &child3, NULL));
8351 ASSERT_EQ(0, rbd_get_id(child1, child_id1, sizeof(child_id1)));
8352 ASSERT_EQ(0, rbd_get_id(child2, child_id2, sizeof(child_id2)));
8353 ASSERT_EQ(0, rbd_get_id(child3, child_id3, sizeof(child_id3)));
8354 test_list_children2(parent, 3,
8355 child_id1, m_pool_name.c_str(), child_name1.c_str(), false,
8356 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
8357 child_id3, m_pool_name.c_str(), child_name3.c_str(), false);
8358
8359 size_t max_size = 10;
8360 rbd_linked_image_spec_t children[max_size];
8361 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
8362 ASSERT_EQ(3, static_cast<int>(max_size));
8363 rbd_linked_image_spec_list_cleanup(children, max_size);
8364
8365 ASSERT_EQ(0, rbd_close(child1));
8366 ASSERT_EQ(0, rbd_close(child2));
8367 ASSERT_EQ(0, rbd_close(child3));
8368 rados_ioctx_destroy(ioctx2);
8369 ASSERT_EQ(0, rados_pool_delete(_cluster, m_pool_name.c_str()));
8370 _pool_names.erase(std::remove(_pool_names.begin(),
8371 _pool_names.end(), m_pool_name),
8372 _pool_names.end());
8373 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
8374
8375 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
8376 ASSERT_EQ(3, static_cast<int>(max_size));
8377 rbd_linked_image_spec_list_cleanup(children, max_size);
8378 ASSERT_EQ(0, rbd_snap_remove(parent, "snap1"));
8379 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
8380 ASSERT_EQ(2, static_cast<int>(max_size));
8381 rbd_linked_image_spec_list_cleanup(children, max_size);
8382
8383 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
8384 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
8385 ASSERT_EQ(1, static_cast<int>(max_size));
8386 rbd_linked_image_spec_list_cleanup(children, max_size);
8387
8388 ASSERT_EQ(0, rbd_snap_remove(parent, "snap2"));
8389 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
8390 ASSERT_EQ(0, static_cast<int>(max_size));
8391 rbd_linked_image_spec_list_cleanup(children, max_size);
8392 test_list_children2(parent, 0);
8393 ASSERT_EQ(0, test_ls_snaps(parent, 0));
8394
8395 ASSERT_EQ(0, rbd_close(parent));
8396 rados_ioctx_destroy(ioctx1);
8397}
8398
8399TEST_F(TestLibRBD, QuiesceWatch)
8400{
8401 rados_ioctx_t ioctx;
8402 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8403
8404 int order = 0;
8405 std::string name = get_temp_image_name();
8406 uint64_t size = 2 << 20;
8407 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8408
8409 rbd_image_t image1, image2;
8410 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
8411 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
8412
8413 struct Watcher {
8414 static void quiesce_cb(void *arg) {
8415 Watcher *watcher = static_cast<Watcher *>(arg);
8416 watcher->handle_quiesce();
8417 }
8418 static void unquiesce_cb(void *arg) {
8419 Watcher *watcher = static_cast<Watcher *>(arg);
8420 watcher->handle_unquiesce();
8421 }
8422
8423 rbd_image_t &image;
8424 uint64_t handle = 0;
8425 size_t quiesce_count = 0;
8426 size_t unquiesce_count = 0;
8427
8428 ceph::mutex lock = ceph::make_mutex("lock");
8429 ceph::condition_variable cv;
8430
8431 Watcher(rbd_image_t &image) : image(image) {
8432 }
8433
8434 void handle_quiesce() {
8435 ASSERT_EQ(quiesce_count, unquiesce_count);
8436 quiesce_count++;
8437 rbd_quiesce_complete(image, handle, 0);
8438 }
8439 void handle_unquiesce() {
8440 std::unique_lock locker(lock);
8441 unquiesce_count++;
8442 ASSERT_EQ(quiesce_count, unquiesce_count);
8443 cv.notify_one();
8444 }
8445 bool wait_for_unquiesce(size_t c) {
8446 std::unique_lock locker(lock);
8447 return cv.wait_for(locker, seconds(60),
8448 [this, c]() { return unquiesce_count >= c; });
8449 }
8450 } watcher1(image1), watcher2(image2);
8451
8452 ASSERT_EQ(0, rbd_quiesce_watch(image1, Watcher::quiesce_cb,
8453 Watcher::unquiesce_cb, &watcher1,
8454 &watcher1.handle));
8455 ASSERT_EQ(0, rbd_quiesce_watch(image2, Watcher::quiesce_cb,
8456 Watcher::unquiesce_cb, &watcher2,
8457 &watcher2.handle));
8458
8459 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
8460 ASSERT_EQ(1U, watcher1.quiesce_count);
8461 ASSERT_TRUE(watcher1.wait_for_unquiesce(1U));
8462 ASSERT_EQ(1U, watcher2.quiesce_count);
8463 ASSERT_TRUE(watcher2.wait_for_unquiesce(1U));
8464
8465 ASSERT_EQ(0, rbd_snap_create(image2, "snap2"));
8466 ASSERT_EQ(2U, watcher1.quiesce_count);
8467 ASSERT_TRUE(watcher1.wait_for_unquiesce(2U));
8468 ASSERT_EQ(2U, watcher2.quiesce_count);
8469 ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
8470
8471 ASSERT_EQ(0, rbd_quiesce_unwatch(image1, watcher1.handle));
8472
8473 ASSERT_EQ(0, rbd_snap_create(image1, "snap3"));
8474 ASSERT_EQ(2U, watcher1.quiesce_count);
8475 ASSERT_EQ(2U, watcher1.unquiesce_count);
8476 ASSERT_EQ(3U, watcher2.quiesce_count);
8477 ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
8478
8479 ASSERT_EQ(0, rbd_quiesce_unwatch(image2, watcher2.handle));
8480
8481 ASSERT_EQ(0, rbd_snap_remove(image1, "snap1"));
8482 ASSERT_EQ(0, rbd_snap_remove(image1, "snap2"));
8483 ASSERT_EQ(0, rbd_snap_remove(image1, "snap3"));
8484 ASSERT_EQ(0, rbd_close(image1));
8485 ASSERT_EQ(0, rbd_close(image2));
8486 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
8487 rados_ioctx_destroy(ioctx);
8488}
8489
8490TEST_F(TestLibRBD, QuiesceWatchPP)
8491{
8492 librbd::RBD rbd;
8493 librados::IoCtx ioctx;
8494 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8495 std::string name = get_temp_image_name();
8496 int order = 0;
8497 uint64_t size = 2 << 20;
8498 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8499
8500 {
8501 librbd::Image image1, image2;
8502 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8503 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8504
8505 struct Watcher : public librbd::QuiesceWatchCtx {
8506 librbd::Image &image;
8507 uint64_t handle = 0;
8508 size_t quiesce_count = 0;
8509 size_t unquiesce_count = 0;
8510
8511 ceph::mutex lock = ceph::make_mutex("lock");
8512 ceph::condition_variable cv;
8513
8514 Watcher(librbd::Image &image) : image(image) {
8515 }
8516
8517 void handle_quiesce() override {
8518 ASSERT_EQ(quiesce_count, unquiesce_count);
8519 quiesce_count++;
8520 image.quiesce_complete(handle, 0);
8521 }
8522 void handle_unquiesce() override {
8523 std::unique_lock locker(lock);
8524 unquiesce_count++;
8525 ASSERT_EQ(quiesce_count, unquiesce_count);
8526 cv.notify_one();
8527 }
8528 bool wait_for_unquiesce(size_t c) {
8529 std::unique_lock locker(lock);
8530 return cv.wait_for(locker, seconds(60),
8531 [this, c]() { return unquiesce_count >= c; });
8532 }
8533 } watcher1(image1), watcher2(image2);
8534
8535 ASSERT_EQ(0, image1.quiesce_watch(&watcher1, &watcher1.handle));
8536 ASSERT_EQ(0, image2.quiesce_watch(&watcher2, &watcher2.handle));
8537
8538 ASSERT_EQ(0, image1.snap_create("snap1"));
8539 ASSERT_EQ(1U, watcher1.quiesce_count);
8540 ASSERT_TRUE(watcher1.wait_for_unquiesce(1U));
8541 ASSERT_EQ(1U, watcher2.quiesce_count);
8542 ASSERT_TRUE(watcher2.wait_for_unquiesce(1U));
8543
8544 ASSERT_EQ(0, image2.snap_create("snap2"));
8545 ASSERT_EQ(2U, watcher1.quiesce_count);
8546 ASSERT_TRUE(watcher1.wait_for_unquiesce(2U));
8547 ASSERT_EQ(2U, watcher2.quiesce_count);
8548 ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
8549
8550 ASSERT_EQ(0, image1.quiesce_unwatch(watcher1.handle));
8551
8552 ASSERT_EQ(0, image1.snap_create("snap3"));
8553 ASSERT_EQ(2U, watcher1.quiesce_count);
8554 ASSERT_EQ(2U, watcher1.unquiesce_count);
8555 ASSERT_EQ(3U, watcher2.quiesce_count);
8556 ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
8557
8558 ASSERT_EQ(0, image2.quiesce_unwatch(watcher2.handle));
8559
8560 ASSERT_EQ(0, image1.snap_remove("snap1"));
8561 ASSERT_EQ(0, image1.snap_remove("snap2"));
8562 ASSERT_EQ(0, image1.snap_remove("snap3"));
8563 }
8564
8565 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
8566 ioctx.close();
8567}
8568
8569TEST_F(TestLibRBD, QuiesceWatchError)
8570{
8571 librbd::RBD rbd;
8572 librados::IoCtx ioctx;
8573 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8574 std::string name = get_temp_image_name();
8575 int order = 0;
8576 uint64_t size = 2 << 20;
8577 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8578
8579 {
8580 librbd::Image image1, image2;
8581 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8582 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8583
8584 struct Watcher : public librbd::QuiesceWatchCtx {
8585 librbd::Image &image;
8586 int r;
8587 uint64_t handle;
8588 size_t quiesce_count = 0;
8589 size_t unquiesce_count = 0;
8590
8591 ceph::mutex lock = ceph::make_mutex("lock");
8592 ceph::condition_variable cv;
8593
8594 Watcher(librbd::Image &image, int r) : image(image), r(r) {
8595 }
8596
8597 void reset_counters() {
8598 quiesce_count = 0;
8599 unquiesce_count = 0;
8600 }
9f95a23c 8601
f67539c2
TL
8602 void handle_quiesce() override {
8603 quiesce_count++;
8604 image.quiesce_complete(handle, r);
8605 }
9f95a23c 8606
f67539c2
TL
8607 void handle_unquiesce() override {
8608 std::unique_lock locker(lock);
8609 unquiesce_count++;
8610 cv.notify_one();
8611 }
9f95a23c 8612
f67539c2
TL
8613 bool wait_for_unquiesce() {
8614 std::unique_lock locker(lock);
8615 return cv.wait_for(locker, seconds(60),
8616 [this]() {
8617 return quiesce_count == unquiesce_count;
8618 });
8619 }
8620 } watcher10(image1, -EINVAL), watcher11(image1, 0), watcher20(image2, 0);
8621
8622 ASSERT_EQ(0, image1.quiesce_watch(&watcher10, &watcher10.handle));
8623 ASSERT_EQ(0, image1.quiesce_watch(&watcher11, &watcher11.handle));
8624 ASSERT_EQ(0, image2.quiesce_watch(&watcher20, &watcher20.handle));
8625
8626 ASSERT_EQ(-EINVAL, image1.snap_create("snap1"));
8627 ASSERT_GT(watcher10.quiesce_count, 0U);
8628 ASSERT_EQ(watcher10.unquiesce_count, 0U);
8629 ASSERT_GT(watcher11.quiesce_count, 0U);
8630 ASSERT_TRUE(watcher11.wait_for_unquiesce());
8631 ASSERT_GT(watcher20.quiesce_count, 0U);
8632 ASSERT_TRUE(watcher20.wait_for_unquiesce());
8633
8634 PrintProgress prog_ctx;
8635 watcher10.reset_counters();
8636 watcher11.reset_counters();
8637 watcher20.reset_counters();
8638 ASSERT_EQ(0, image2.snap_create2("snap2",
8639 RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
8640 prog_ctx));
8641 ASSERT_GT(watcher10.quiesce_count, 0U);
8642 ASSERT_EQ(watcher10.unquiesce_count, 0U);
8643 ASSERT_GT(watcher11.quiesce_count, 0U);
8644 ASSERT_TRUE(watcher11.wait_for_unquiesce());
8645 ASSERT_GT(watcher20.quiesce_count, 0U);
8646 ASSERT_TRUE(watcher20.wait_for_unquiesce());
8647
8648 ASSERT_EQ(0, image1.quiesce_unwatch(watcher10.handle));
8649
8650 watcher11.reset_counters();
8651 watcher20.reset_counters();
8652 ASSERT_EQ(0, image1.snap_create("snap3"));
8653 ASSERT_GT(watcher11.quiesce_count, 0U);
8654 ASSERT_TRUE(watcher11.wait_for_unquiesce());
8655 ASSERT_GT(watcher20.quiesce_count, 0U);
8656 ASSERT_TRUE(watcher20.wait_for_unquiesce());
8657
8658 ASSERT_EQ(0, image1.quiesce_unwatch(watcher11.handle));
8659
8660 watcher20.reset_counters();
8661 ASSERT_EQ(0, image2.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE,
8662 prog_ctx));
8663 ASSERT_EQ(watcher20.quiesce_count, 0U);
8664 ASSERT_EQ(watcher20.unquiesce_count, 0U);
8665
8666 ASSERT_EQ(0, image2.quiesce_unwatch(watcher20.handle));
8667
8668 ASSERT_EQ(0, image1.snap_remove("snap2"));
8669 ASSERT_EQ(0, image1.snap_remove("snap3"));
8670 ASSERT_EQ(0, image1.snap_remove("snap4"));
8671 }
8672
8673 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
9f95a23c
TL
8674 ioctx.close();
8675}
8676
f67539c2 8677TEST_F(TestLibRBD, QuiesceWatchTimeout)
92f5a8d4 8678{
f67539c2 8679 REQUIRE(!is_librados_test_stub(_rados));
92f5a8d4 8680
f67539c2 8681 ASSERT_EQ(0, _rados.conf_set("rbd_quiesce_notification_attempts", "2"));
92f5a8d4 8682
f67539c2
TL
8683 librbd::RBD rbd;
8684 librados::IoCtx ioctx;
8685 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8686 std::string name = get_temp_image_name();
92f5a8d4 8687 int order = 0;
f67539c2
TL
8688 uint64_t size = 2 << 20;
8689 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
92f5a8d4 8690
f67539c2
TL
8691 {
8692 librbd::Image image;
8693 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
92f5a8d4 8694
f67539c2
TL
8695 struct Watcher : public librbd::QuiesceWatchCtx {
8696 librbd::Image &image;
8697 std::mutex m_lock;
8698 std::condition_variable m_cond;
8699 size_t quiesce_count = 0;
8700 size_t unquiesce_count = 0;
92f5a8d4 8701
f67539c2
TL
8702 Watcher(librbd::Image &image) : image(image) {
8703 }
92f5a8d4 8704
f67539c2
TL
8705 void handle_quiesce() override {
8706 std::lock_guard<std::mutex> locker(m_lock);
8707 quiesce_count++;
8708 m_cond.notify_one();
8709 }
92f5a8d4 8710
f67539c2
TL
8711 void handle_unquiesce() override {
8712 std::lock_guard<std::mutex> locker(m_lock);
8713 unquiesce_count++;
8714 m_cond.notify_one();
8715 }
92f5a8d4 8716
f67539c2
TL
8717 void wait_for_quiesce() {
8718 std::unique_lock<std::mutex> locker(m_lock);
8719 ASSERT_TRUE(m_cond.wait_for(locker, seconds(60),
8720 [this] {
8721 return quiesce_count >= 1;
8722 }));
8723 }
92f5a8d4 8724
f67539c2
TL
8725 void wait_for_unquiesce() {
8726 std::unique_lock<std::mutex> locker(m_lock);
8727 ASSERT_TRUE(m_cond.wait_for(locker, seconds(60),
8728 [this] {
8729 return quiesce_count == unquiesce_count;
8730 }));
8731 quiesce_count = unquiesce_count = 0;
8732 }
8733 } watcher(image);
8734 uint64_t handle;
92f5a8d4 8735
f67539c2 8736 ASSERT_EQ(0, image.quiesce_watch(&watcher, &handle));
92f5a8d4 8737
f67539c2
TL
8738 std::cerr << "test quiesce is not long enough to time out" << std::endl;
8739
8740 thread quiesce1([&image, &watcher, handle]() {
8741 watcher.wait_for_quiesce();
8742 sleep(8);
8743 image.quiesce_complete(handle, 0);
8744 });
8745
8746 ASSERT_EQ(0, image.snap_create("snap1"));
8747 quiesce1.join();
8748 ASSERT_GE(watcher.quiesce_count, 1U);
8749 watcher.wait_for_unquiesce();
8750
8751 std::cerr << "test quiesce is timed out" << std::endl;
8752
8753 bool timed_out = false;
8754 thread quiesce2([&image, &watcher, handle, &timed_out]() {
8755 watcher.wait_for_quiesce();
8756 for (int i = 0; !timed_out && i < 60; i++) {
8757 std::cerr << "waiting for timed out ... " << i << std::endl;
8758 sleep(1);
8759 }
8760 image.quiesce_complete(handle, 0);
8761 });
8762
8763 ASSERT_EQ(-ETIMEDOUT, image.snap_create("snap2"));
8764 timed_out = true;
8765 quiesce2.join();
8766 ASSERT_GE(watcher.quiesce_count, 1U);
8767 watcher.wait_for_unquiesce();
8768
8769 thread quiesce3([&image, handle, &watcher]() {
8770 watcher.wait_for_quiesce();
8771 image.quiesce_complete(handle, 0);
8772 });
8773
8774 std::cerr << "test retry succeeds" << std::endl;
8775
8776 ASSERT_EQ(0, image.snap_create("snap2"));
8777 quiesce3.join();
8778 ASSERT_GE(watcher.quiesce_count, 1U);
8779 watcher.wait_for_unquiesce();
8780
8781 ASSERT_EQ(0, image.snap_remove("snap1"));
8782 ASSERT_EQ(0, image.snap_remove("snap2"));
8783 }
8784
8785 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
8786 ioctx.close();
92f5a8d4
TL
8787}
8788
f6b5b4d7
TL
8789TEST_F(TestLibRBD, WriteZeroes) {
8790 librbd::RBD rbd;
8791 librados::IoCtx ioctx;
8792 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8793 std::string name = get_temp_image_name();
8794 int order = 0;
8795 uint64_t size = 2 << 20;
8796 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8797
8798 librbd::Image image;
8799 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8800
8801 // 1s from [0, 256) / length 256
8802 char data[256];
8803 memset(data, 1, sizeof(data));
8804 bufferlist bl;
8805 bl.append(data, 256);
8806 ASSERT_EQ(256, image.write(0, 256, bl));
8807
8808 interval_set<uint64_t> diff;
8809 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8810 iterate_cb, (void *)&diff));
8811 auto expected_diff = interval_set<uint64_t>{{{0, 256}}};
8812 ASSERT_EQ(expected_diff, diff);
8813
8814 // writes zero passed the current end extents.
8815 // Now 1s from [0, 192) / length 192
8816 ASSERT_EQ(size - 192,
8817 image.write_zeroes(192, size - 192, 0U, 0));
8818 diff.clear();
8819 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8820 iterate_cb, (void *)&diff));
8821 expected_diff = interval_set<uint64_t>{{{0, 192}}};
8822 ASSERT_EQ(expected_diff, diff);
8823
8824 // zero an existing extent and truncate some off the end
8825 // Now 1s from [64, 192) / length 192
8826 ASSERT_EQ(64, image.write_zeroes(0, 64, 0U, 0));
8827
8828 diff.clear();
8829 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8830 iterate_cb, (void *)&diff));
8831 expected_diff = interval_set<uint64_t>{{{0, 192}}};
8832 ASSERT_EQ(expected_diff, diff);
8833
8834 bufferlist expected_bl;
8835 expected_bl.append_zero(64);
8836 bufferlist sub_bl;
8837 sub_bl.substr_of(bl, 0, 128);
8838 expected_bl.claim_append(sub_bl);
8839 expected_bl.append_zero(size - 192);
8840
8841 bufferlist read_bl;
8842 EXPECT_EQ(size, image.read(0, size, read_bl));
8843 EXPECT_EQ(expected_bl, read_bl);
8844
8845 ASSERT_EQ(0, image.close());
8846}
8847
f67539c2
TL
8848TEST_F(TestLibRBD, WriteZeroesThickProvision) {
8849 librbd::RBD rbd;
8850 librados::IoCtx ioctx;
8851 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8852 std::string name = get_temp_image_name();
8853 int order = 0;
8854 uint64_t size = 2 << 20;
8855 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8856
8857 librbd::Image image;
8858 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8859
8860 interval_set<uint64_t> diff;
8861 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8862 iterate_cb, (void *)&diff));
8863 auto expected_diff = interval_set<uint64_t>{{}};
8864 ASSERT_EQ(expected_diff, diff);
8865
8866 // writes unaligned zeroes as a prepend
8867 ASSERT_EQ(128, image.write_zeroes(
8868 0, 128, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
8869 diff.clear();
8870 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8871 iterate_cb, (void *)&diff));
8872 expected_diff = interval_set<uint64_t>{{{0, 128}}};
8873 ASSERT_EQ(expected_diff, diff);
8874
8875 ASSERT_EQ(512, image.write_zeroes(
8876 384, 512, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
8877 diff.clear();
8878 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8879 iterate_cb, (void *)&diff));
8880 expected_diff = interval_set<uint64_t>{{{0, 896}}};
8881 ASSERT_EQ(expected_diff, diff);
8882
8883 // prepend with write-same
8884 ASSERT_EQ(640, image.write_zeroes(
8885 896, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
8886 diff.clear();
8887 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8888 iterate_cb, (void *)&diff));
8889 expected_diff = interval_set<uint64_t>{{{0, 1536}}};
8890 ASSERT_EQ(expected_diff, diff);
8891
8892 // write-same with append
8893 ASSERT_EQ(640, image.write_zeroes(
8894 1536, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
8895 diff.clear();
8896 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8897 iterate_cb, (void *)&diff));
8898 expected_diff = interval_set<uint64_t>{{{0, 2176}}};
8899 ASSERT_EQ(expected_diff, diff);
8900
8901 // prepend + write-same + append
8902 ASSERT_EQ(768, image.write_zeroes(
8903 2176, 768, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
8904 diff.clear();
8905 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8906 iterate_cb, (void *)&diff));
8907 expected_diff = interval_set<uint64_t>{{{0, 2944}}};
8908
8909 // write-same
8910 ASSERT_EQ(1024, image.write_zeroes(
8911 3072, 1024, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
8912 diff.clear();
8913 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
8914 iterate_cb, (void *)&diff));
8915 expected_diff = interval_set<uint64_t>{{{0, 4096}}};
8916
8917 bufferlist expected_bl;
8918 expected_bl.append_zero(size);
8919
8920 bufferlist read_bl;
8921 EXPECT_EQ(size, image.read(0, size, read_bl));
8922 EXPECT_EQ(expected_bl, read_bl);
8923
8924 ASSERT_EQ(0, image.close());
8925}
8926
8927TEST_F(TestLibRBD, ConcurentOperations)
8928{
8929 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
8930
8931 librbd::RBD rbd;
8932 librados::IoCtx ioctx;
8933 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8934 std::string name = get_temp_image_name();
8935 int order = 0;
8936 uint64_t size = 2 << 20;
8937 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8938
8939 // Test creating/removing many snapshots simultaneously
8940
8941 std::vector<librbd::Image> images(10);
8942 std::vector<librbd::RBD::AioCompletion *> comps;
8943
8944 for (auto &image : images) {
8945 auto comp = new librbd::RBD::AioCompletion(NULL, NULL);
8946 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, comp));
8947 comps.push_back(comp);
8948 }
8949
8950 for (auto &comp : comps) {
8951 ASSERT_EQ(0, comp->wait_for_complete());
8952 ASSERT_EQ(1, comp->is_complete());
8953 ASSERT_EQ(0, comp->get_return_value());
8954 comp->release();
8955 }
8956 comps.clear();
8957
8958 std::vector<std::thread> threads;
8959 int i = 0;
8960 for (auto &image : images) {
8961 std::string snap_name = "snap" + stringify(i++);
8962 threads.emplace_back([&image, snap_name]() {
8963 int r = image.snap_create(snap_name.c_str());
8964 ceph_assert(r == 0);
8965 });
8966 }
8967
8968 for (auto &t : threads) {
8969 t.join();
8970 }
8971 threads.clear();
8972
8973 i = 0;
8974 for (auto &image : images) {
8975 std::string snap_name = "snap" + stringify(i++);
8976 threads.emplace_back([&image, snap_name](){
8977 int r = image.snap_remove(snap_name.c_str());
8978 ceph_assert(r == 0);
8979 });
8980 }
8981
8982 for (auto &t : threads) {
8983 t.join();
8984 }
8985 threads.clear();
8986
8987 for (auto &image : images) {
8988 auto comp = new librbd::RBD::AioCompletion(NULL, NULL);
8989 ASSERT_EQ(0, image.aio_close(comp));
8990 comps.push_back(comp);
8991 }
8992
8993 for (auto &comp : comps) {
8994 ASSERT_EQ(0, comp->wait_for_complete());
8995 ASSERT_EQ(1, comp->is_complete());
8996 ASSERT_EQ(0, comp->get_return_value());
8997 comp->release();
8998 }
8999 comps.clear();
9000
9001 // Test shutdown
9002 {
9003 librbd::Image image1, image2, image3;
9004 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9005 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
9006 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
9007
9008 ASSERT_EQ(0, image1.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE));
9009
9010 struct Watcher : public librbd::QuiesceWatchCtx {
9011 size_t count = 0;
9012
9013 ceph::mutex lock = ceph::make_mutex("lock");
9014 ceph::condition_variable cv;
9015
9016 void handle_quiesce() override {
9017 std::unique_lock locker(lock);
9018 count++;
9019 cv.notify_one();
9020 }
9021
9022 void handle_unquiesce() override {
9023 }
9024
9025 bool wait_for_quiesce(size_t c) {
9026 std::unique_lock locker(lock);
9027 return cv.wait_for(locker, seconds(60),
9028 [this, c]() { return count >= c; });
9029 }
9030 } watcher;
9031 uint64_t handle;
9032 ASSERT_EQ(0, image2.quiesce_watch(&watcher, &handle));
9033
9034 auto close1_comp = new librbd::RBD::AioCompletion(NULL, NULL);
9035
9036 std::thread create_snap1([&image1, close1_comp]() {
9037 int r = image1.snap_create("snap1");
9038 ceph_assert(r == 0);
9039 r = image1.aio_close(close1_comp);
9040 ceph_assert(r == 0);
9041 });
9042
9043 ASSERT_TRUE(watcher.wait_for_quiesce(1));
9044
9045 std::thread create_snap2([&image2]() {
9046 int r = image2.snap_create("snap2");
9047 ceph_assert(r == 0);
9048 });
9049
9050 std::thread create_snap3([&image3]() {
9051 int r = image3.snap_create("snap3");
9052 ceph_assert(r == 0);
9053 });
9054
9055 image2.quiesce_complete(handle, 0);
9056 create_snap1.join();
9057
9058 ASSERT_TRUE(watcher.wait_for_quiesce(2));
9059 image2.quiesce_complete(handle, 0);
9060
9061 ASSERT_TRUE(watcher.wait_for_quiesce(3));
9062 image2.quiesce_complete(handle, 0);
9063
9064 ASSERT_EQ(0, close1_comp->wait_for_complete());
9065 ASSERT_EQ(1, close1_comp->is_complete());
9066 ASSERT_EQ(0, close1_comp->get_return_value());
9067 close1_comp->release();
9068
9069 create_snap2.join();
9070 create_snap3.join();
9071
9072 ASSERT_EQ(0, image2.quiesce_unwatch(handle));
9073 ASSERT_EQ(0, image2.snap_remove("snap1"));
9074 ASSERT_EQ(0, image2.snap_remove("snap2"));
9075 ASSERT_EQ(0, image2.snap_remove("snap3"));
9076 }
9077
9078 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
9079 ioctx.close();
9080}
9081
9082
11fdf7f2 9083// poorman's ceph_assert()
31f18b77
FG
9084namespace ceph {
9085 void __ceph_assert_fail(const char *assertion, const char *file, int line,
9086 const char *func) {
11fdf7f2 9087 ceph_abort();
31f18b77
FG
9088 }
9089}
11fdf7f2
TL
9090
9091#pragma GCC diagnostic pop
9092#pragma GCC diagnostic warning "-Wpragmas"