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