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