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