]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_librbd.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librbd / test_librbd.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License version 2, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include "include/int_types.h"
16#include "include/rados/librados.h"
17#include "include/rbd_types.h"
18#include "include/rbd/librbd.h"
19#include "include/rbd/librbd.hpp"
20#include "include/event_type.h"
c07f9fc5 21#include "include/err.h"
f67539c2
TL
22#include "common/ceph_mutex.h"
23#include "json_spirit/json_spirit.h"
1e59de90 24#include "test/librados/crimson_utils.h"
7c673cae 25
7c673cae
FG
26#include "gtest/gtest.h"
27
7c673cae
FG
28#include <errno.h>
29#include <stdarg.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <sys/types.h>
33#include <poll.h>
34#include <time.h>
35#include <unistd.h>
7c673cae 36#include <algorithm>
31f18b77
FG
37#include <chrono>
38#include <condition_variable>
39#include <iostream>
7c673cae
FG
40#include <sstream>
41#include <list>
42#include <set>
31f18b77 43#include <thread>
7c673cae 44#include <vector>
1d09f67e 45#include <limits>
7c673cae
FG
46
47#include "test/librados/test.h"
11fdf7f2 48#include "test/librados/test_cxx.h"
7c673cae 49#include "test/librbd/test_support.h"
7c673cae
FG
50#include "common/event_socket.h"
51#include "include/interval_set.h"
52#include "include/stringify.h"
53
54#include <boost/assign/list_of.hpp>
55#include <boost/scope_exit.hpp>
56
57#ifdef HAVE_EVENTFD
58#include <sys/eventfd.h>
59#endif
60
11fdf7f2
TL
61#pragma GCC diagnostic ignored "-Wpragmas"
62#pragma GCC diagnostic push
63#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
64
7c673cae
FG
65using namespace std;
66
67using std::chrono::seconds;
68
1e59de90
TL
69#define ASSERT_PASSED0(x) \
70 do { \
71 bool passed = false; \
72 x(&passed); \
73 ASSERT_TRUE(passed); \
74 } while(0)
75
7c673cae
FG
76#define ASSERT_PASSED(x, args...) \
77 do { \
78 bool passed = false; \
79 x(args, &passed); \
80 ASSERT_TRUE(passed); \
81 } while(0)
82
83void register_test_librbd() {
84}
85
86static int get_features(bool *old_format, uint64_t *features)
87{
88 const char *c = getenv("RBD_FEATURES");
11fdf7f2 89 if (c && strlen(c) > 0) {
7c673cae
FG
90 stringstream ss;
91 ss << c;
92 ss >> *features;
93 if (ss.fail())
94 return -EINVAL;
95 *old_format = false;
96 cout << "using new format!" << std::endl;
97 } else {
98 *old_format = true;
99 *features = 0;
100 cout << "using old format" << std::endl;
101 }
102
103 return 0;
104}
105
106static int create_image_full(rados_ioctx_t ioctx, const char *name,
107 uint64_t size, int *order, int old_format,
108 uint64_t features)
109{
110 if (old_format) {
111 // ensure old-format tests actually use the old format
112 int r = rados_conf_set(rados_ioctx_get_cluster(ioctx),
113 "rbd_default_format", "1");
114 if (r < 0) {
115 return r;
116 }
117 return rbd_create(ioctx, name, size, order);
118 } else if ((features & RBD_FEATURE_STRIPINGV2) != 0) {
119 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
120 if (*order) {
121 // use a conservative stripe_unit for non default order
122 stripe_unit = (1ull << (*order-1));
123 }
124
125 printf("creating image with stripe unit: %" PRIu64 ", "
126 "stripe count: %" PRIu64 "\n",
127 stripe_unit, IMAGE_STRIPE_COUNT);
128 return rbd_create3(ioctx, name, size, features, order,
129 stripe_unit, IMAGE_STRIPE_COUNT);
130 } else {
131 return rbd_create2(ioctx, name, size, features, order);
132 }
133}
134
135static int clone_image(rados_ioctx_t p_ioctx,
136 rbd_image_t p_image, const char *p_name,
137 const char *p_snap_name, rados_ioctx_t c_ioctx,
138 const char *c_name, uint64_t features, int *c_order)
139{
140 uint64_t stripe_unit, stripe_count;
141
142 int r;
143 r = rbd_get_stripe_unit(p_image, &stripe_unit);
144 if (r != 0) {
145 return r;
146 }
147
148 r = rbd_get_stripe_count(p_image, &stripe_count);
149 if (r != 0) {
150 return r;
151 }
152
153 return rbd_clone2(p_ioctx, p_name, p_snap_name, c_ioctx,
154 c_name, features, c_order, stripe_unit, stripe_count);
155}
156
157
158static int create_image(rados_ioctx_t ioctx, const char *name,
159 uint64_t size, int *order)
160{
161 bool old_format;
162 uint64_t features;
163
164 int r = get_features(&old_format, &features);
165 if (r < 0)
166 return r;
167 return create_image_full(ioctx, name, size, order, old_format, features);
168}
169
170static int create_image_pp(librbd::RBD &rbd,
171 librados::IoCtx &ioctx,
172 const char *name,
173 uint64_t size, int *order) {
174 bool old_format;
175 uint64_t features;
176 int r = get_features(&old_format, &features);
177 if (r < 0)
178 return r;
179 if (old_format) {
180 librados::Rados rados(ioctx);
181 int r = rados.conf_set("rbd_default_format", "1");
182 if (r < 0) {
183 return r;
184 }
185 return rbd.create(ioctx, name, size, order);
186 } else {
187 return rbd.create2(ioctx, name, size, features, order);
188 }
189}
190
f67539c2
TL
191
192
193void simple_write_cb(rbd_completion_t cb, void *arg)
194{
195 printf("write completion cb called!\n");
196}
197
198void simple_read_cb(rbd_completion_t cb, void *arg)
199{
200 printf("read completion cb called!\n");
201}
202
203void aio_write_test_data_and_poll(rbd_image_t image, int fd, const char *test_data,
204 uint64_t off, size_t len, uint32_t iohint, bool *passed)
205{
206 rbd_completion_t comp;
207 uint64_t data = 0x123;
208 rbd_aio_create_completion((void*)&data, (rbd_callback_t) simple_write_cb, &comp);
209 printf("created completion\n");
210 printf("started write\n");
211 if (iohint)
212 rbd_aio_write2(image, off, len, test_data, comp, iohint);
213 else
214 rbd_aio_write(image, off, len, test_data, comp);
215
216 struct pollfd pfd;
217 pfd.fd = fd;
218 pfd.events = POLLIN;
219
220 ASSERT_EQ(1, poll(&pfd, 1, -1));
221 ASSERT_TRUE(pfd.revents & POLLIN);
222
223 rbd_completion_t comps[1];
224 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
225 uint64_t count;
226 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
227 read(fd, &count, sizeof(count)));
228 int r = rbd_aio_get_return_value(comps[0]);
229 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
230 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps[0]) == data);
231 printf("return value is: %d\n", r);
232 ASSERT_EQ(0, r);
233 printf("finished write\n");
234 rbd_aio_release(comps[0]);
235 *passed = true;
236}
237
238void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
239{
240 rbd_completion_t comp;
241 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
242 printf("created completion\n");
243 if (iohint)
244 rbd_aio_write2(image, off, len, test_data, comp, iohint);
245 else
246 rbd_aio_write(image, off, len, test_data, comp);
247 printf("started write\n");
248 rbd_aio_wait_for_complete(comp);
249 int r = rbd_aio_get_return_value(comp);
250 printf("return value is: %d\n", r);
251 ASSERT_EQ(0, r);
252 printf("finished write\n");
253 rbd_aio_release(comp);
254 *passed = true;
255}
256
257void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
258{
259 ssize_t written;
260 if (iohint)
261 written = rbd_write2(image, off, len, test_data, iohint);
262 else
263 written = rbd_write(image, off, len, test_data);
264 printf("wrote: %d\n", (int) written);
265 ASSERT_EQ(len, static_cast<size_t>(written));
266 *passed = true;
267}
268
269void aio_discard_test_data(rbd_image_t image, uint64_t off, uint64_t len, bool *passed)
270{
271 rbd_completion_t comp;
272 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
273 rbd_aio_discard(image, off, len, comp);
274 rbd_aio_wait_for_complete(comp);
275 int r = rbd_aio_get_return_value(comp);
276 ASSERT_EQ(0, r);
277 printf("aio discard: %d~%d = %d\n", (int)off, (int)len, (int)r);
278 rbd_aio_release(comp);
279 *passed = true;
280}
281
282void discard_test_data(rbd_image_t image, uint64_t off, size_t len, bool *passed)
283{
284 ssize_t written;
285 written = rbd_discard(image, off, len);
286 printf("discard: %d~%d = %d\n", (int)off, (int)len, (int)written);
287 ASSERT_EQ(len, static_cast<size_t>(written));
288 *passed = true;
289}
290
291void aio_read_test_data_and_poll(rbd_image_t image, int fd, const char *expected,
292 uint64_t off, size_t len, uint32_t iohint, bool *passed)
293{
294 rbd_completion_t comp;
295 char *result = (char *)malloc(len + 1);
296
297 ASSERT_NE(static_cast<char *>(NULL), result);
298 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
299 printf("created completion\n");
300 printf("started read\n");
301 if (iohint)
302 rbd_aio_read2(image, off, len, result, comp, iohint);
303 else
304 rbd_aio_read(image, off, len, result, comp);
305
306 struct pollfd pfd;
307 pfd.fd = fd;
308 pfd.events = POLLIN;
309
310 ASSERT_EQ(1, poll(&pfd, 1, -1));
311 ASSERT_TRUE(pfd.revents & POLLIN);
312
313 rbd_completion_t comps[1];
314 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
315 uint64_t count;
316 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
317 read(fd, &count, sizeof(count)));
318
319 int r = rbd_aio_get_return_value(comps[0]);
320 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
321 printf("return value is: %d\n", r);
322 ASSERT_EQ(len, static_cast<size_t>(r));
323 rbd_aio_release(comps[0]);
324 if (memcmp(result, expected, len)) {
325 printf("read: %s\nexpected: %s\n", result, expected);
326 ASSERT_EQ(0, memcmp(result, expected, len));
327 }
328 free(result);
329 *passed = true;
330}
331
332void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
333{
334 rbd_completion_t comp;
335 char *result = (char *)malloc(len + 1);
336
337 ASSERT_NE(static_cast<char *>(NULL), result);
338 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
339 printf("created completion\n");
340 if (iohint)
341 rbd_aio_read2(image, off, len, result, comp, iohint);
342 else
343 rbd_aio_read(image, off, len, result, comp);
344 printf("started read\n");
345 rbd_aio_wait_for_complete(comp);
346 int r = rbd_aio_get_return_value(comp);
347 printf("return value is: %d\n", r);
348 ASSERT_EQ(len, static_cast<size_t>(r));
349 rbd_aio_release(comp);
350 if (memcmp(result, expected, len)) {
351 printf("read: %s\nexpected: %s\n", result, expected);
352 ASSERT_EQ(0, memcmp(result, expected, len));
353 }
354 free(result);
355 *passed = true;
356}
357
358void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
359{
360 ssize_t read;
361 char *result = (char *)malloc(len + 1);
362
363 ASSERT_NE(static_cast<char *>(NULL), result);
364 if (iohint)
365 read = rbd_read2(image, off, len, result, iohint);
366 else
367 read = rbd_read(image, off, len, result);
368 printf("read: %d\n", (int) read);
369 ASSERT_EQ(len, static_cast<size_t>(read));
370 result[len] = '\0';
371 if (memcmp(result, expected, len)) {
372 printf("read: %s\nexpected: %s\n", result, expected);
373 ASSERT_EQ(0, memcmp(result, expected, len));
374 }
375 free(result);
376 *passed = true;
377}
378
379void aio_writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
380 uint64_t data_len, uint32_t iohint, bool *passed)
381{
382 rbd_completion_t comp;
383 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
384 printf("created completion\n");
385 int r;
386 r = rbd_aio_writesame(image, off, len, test_data, data_len, comp, iohint);
387 printf("started writesame\n");
388 if (len % data_len) {
389 ASSERT_EQ(-EINVAL, r);
390 printf("expected fail, finished writesame\n");
391 rbd_aio_release(comp);
392 *passed = true;
393 return;
394 }
395
396 rbd_aio_wait_for_complete(comp);
397 r = rbd_aio_get_return_value(comp);
398 printf("return value is: %d\n", r);
399 ASSERT_EQ(0, r);
400 printf("finished writesame\n");
401 rbd_aio_release(comp);
402
403 //verify data
404 printf("to verify the data\n");
405 ssize_t read;
406 char *result = (char *)malloc(data_len+ 1);
407 ASSERT_NE(static_cast<char *>(NULL), result);
408 uint64_t left = len;
409 while (left > 0) {
410 read = rbd_read(image, off, data_len, result);
411 ASSERT_EQ(data_len, static_cast<size_t>(read));
412 result[data_len] = '\0';
413 if (memcmp(result, test_data, data_len)) {
414 printf("read: %d ~ %d\n", (int) off, (int) read);
415 printf("read: %s\nexpected: %s\n", result, test_data);
416 ASSERT_EQ(0, memcmp(result, test_data, data_len));
417 }
418 off += data_len;
419 left -= data_len;
420 }
421 ASSERT_EQ(0U, left);
422 free(result);
423 printf("verified\n");
424
425 *passed = true;
426}
427
428void writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
429 uint64_t data_len, uint32_t iohint, bool *passed)
430{
431 ssize_t written;
432 written = rbd_writesame(image, off, len, test_data, data_len, iohint);
433 if (len % data_len) {
434 ASSERT_EQ(-EINVAL, written);
435 printf("expected fail, finished writesame\n");
436 *passed = true;
437 return;
438 }
439 ASSERT_EQ(len, static_cast<size_t>(written));
440 printf("wrote: %d\n", (int) written);
441
442 //verify data
443 printf("to verify the data\n");
444 ssize_t read;
445 char *result = (char *)malloc(data_len+ 1);
446 ASSERT_NE(static_cast<char *>(NULL), result);
447 uint64_t left = len;
448 while (left > 0) {
449 read = rbd_read(image, off, data_len, result);
450 ASSERT_EQ(data_len, static_cast<size_t>(read));
451 result[data_len] = '\0';
452 if (memcmp(result, test_data, data_len)) {
453 printf("read: %d ~ %d\n", (int) off, (int) read);
454 printf("read: %s\nexpected: %s\n", result, test_data);
455 ASSERT_EQ(0, memcmp(result, test_data, data_len));
456 }
457 off += data_len;
458 left -= data_len;
459 }
460 ASSERT_EQ(0U, left);
461 free(result);
462 printf("verified\n");
463
464 *passed = true;
465}
466
467void aio_compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
468 const char *test_data, uint64_t off,
469 size_t len, uint32_t iohint, bool *passed)
470{
471 rbd_completion_t comp;
472 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
473 printf("created completion\n");
474
475 uint64_t mismatch_offset;
476 rbd_aio_compare_and_write(image, off, len, cmp_data, test_data, comp, &mismatch_offset, iohint);
477 printf("started aio compare and write\n");
478 rbd_aio_wait_for_complete(comp);
479 int r = rbd_aio_get_return_value(comp);
480 printf("return value is: %d\n", r);
481 ASSERT_EQ(0, r);
482 printf("finished aio compare and write\n");
483 rbd_aio_release(comp);
484 *passed = true;
485}
486
487void compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
488 const char *test_data, uint64_t off, size_t len,
489 uint64_t *mismatch_off, uint32_t iohint, bool *passed)
490{
491 printf("start compare and write\n");
492 ssize_t written;
493 written = rbd_compare_and_write(image, off, len, cmp_data, test_data, mismatch_off, iohint);
494 printf("compare and wrote: %d\n", (int) written);
495 ASSERT_EQ(len, static_cast<size_t>(written));
496 *passed = true;
497}
498
7c673cae
FG
499class TestLibRBD : public ::testing::Test {
500public:
501
502 TestLibRBD() : m_pool_number() {
503 }
504
505 static void SetUpTestCase() {
7c673cae
FG
506 _pool_names.clear();
507 _unique_pool_names.clear();
508 _image_number = 0;
509 ASSERT_EQ("", connect_cluster(&_cluster));
510 ASSERT_EQ("", connect_cluster_pp(_rados));
511
512 create_optional_data_pool();
513 }
514
515 static void TearDownTestCase() {
516 rados_shutdown(_cluster);
517 _rados.wait_for_latest_osdmap();
518 _pool_names.insert(_pool_names.end(), _unique_pool_names.begin(),
f67539c2 519 _unique_pool_names.end());
7c673cae
FG
520 for (size_t i = 1; i < _pool_names.size(); ++i) {
521 ASSERT_EQ(0, _rados.pool_delete(_pool_names[i].c_str()));
522 }
523 if (!_pool_names.empty()) {
524 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names[0], _rados));
525 }
526 }
527
528 void SetUp() override {
529 ASSERT_NE("", m_pool_name = create_pool());
530 }
531
532 bool is_skip_partial_discard_enabled() {
533 std::string value;
534 EXPECT_EQ(0, _rados.conf_get("rbd_skip_partial_discard", value));
535 return value == "true";
536 }
537
f67539c2
TL
538 bool is_skip_partial_discard_enabled(rbd_image_t image) {
539 if (is_skip_partial_discard_enabled()) {
540 rbd_flush(image);
541 uint64_t features;
542 EXPECT_EQ(0, rbd_get_features(image, &features));
543 return !(features & RBD_FEATURE_DIRTY_CACHE);
544 }
545 return false;
546 }
547
548 bool is_skip_partial_discard_enabled(librbd::Image& image) {
549 if (is_skip_partial_discard_enabled()) {
550 image.flush();
551 uint64_t features;
552 EXPECT_EQ(0, image.features(&features));
553 return !(features & RBD_FEATURE_DIRTY_CACHE);
554 }
555 return false;
556 }
557
7c673cae
FG
558 void validate_object_map(rbd_image_t image, bool *passed) {
559 uint64_t flags;
560 ASSERT_EQ(0, rbd_get_flags(image, &flags));
561 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
562 }
563
564 void validate_object_map(librbd::Image &image, bool *passed) {
565 uint64_t flags;
566 ASSERT_EQ(0, image.get_flags(&flags));
567 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
568 }
569
11fdf7f2 570 static std::string get_temp_image_name() {
7c673cae
FG
571 ++_image_number;
572 return "image" + stringify(_image_number);
573 }
574
575 static void create_optional_data_pool() {
576 bool created = false;
577 std::string data_pool;
578 ASSERT_EQ(0, create_image_data_pool(_rados, data_pool, &created));
579 if (!data_pool.empty()) {
580 printf("using image data pool: %s\n", data_pool.c_str());
581 if (created) {
582 _unique_pool_names.push_back(data_pool);
583 }
584 }
585 }
586
587 std::string create_pool(bool unique = false) {
588 librados::Rados rados;
589 std::string pool_name;
590 if (unique) {
591 pool_name = get_temp_pool_name("test-librbd-");
592 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
593 _unique_pool_names.push_back(pool_name);
594 } else if (m_pool_number < _pool_names.size()) {
595 pool_name = _pool_names[m_pool_number];
596 } else {
597 pool_name = get_temp_pool_name("test-librbd-");
598 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
599 _pool_names.push_back(pool_name);
600 }
601 ++m_pool_number;
602 return pool_name;
603 }
604
f67539c2
TL
605 void test_io(rbd_image_t image) {
606 bool skip_discard = is_skip_partial_discard_enabled(image);
607
608 char test_data[TEST_IO_SIZE + 1];
609 char zero_data[TEST_IO_SIZE + 1];
610 char mismatch_data[TEST_IO_SIZE + 1];
611 int i;
612 uint64_t mismatch_offset;
613
614 for (i = 0; i < TEST_IO_SIZE; ++i) {
615 test_data[i] = (char) (rand() % (126 - 33) + 33);
616 }
617 test_data[TEST_IO_SIZE] = '\0';
618 memset(zero_data, 0, sizeof(zero_data));
619 memset(mismatch_data, 9, sizeof(mismatch_data));
620
621 for (i = 0; i < 5; ++i)
622 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
623 TEST_IO_SIZE, 0);
624
625 for (i = 5; i < 10; ++i)
626 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
627 TEST_IO_SIZE, 0);
628
629 for (i = 0; i < 5; ++i)
630 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
631 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, 0);
632
633 for (i = 5; i < 10; ++i)
634 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
635 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
636
637 for (i = 0; i < 5; ++i)
638 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i,
639 TEST_IO_SIZE, 0);
640
641 for (i = 5; i < 10; ++i)
642 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
643 TEST_IO_SIZE, 0);
644
645 // discard 2nd, 4th sections.
646 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
647 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
648
649 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
650 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
651 TEST_IO_SIZE, TEST_IO_SIZE, 0);
652 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2,
653 TEST_IO_SIZE, 0);
654 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
655 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
656 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4,
657 TEST_IO_SIZE, 0);
658
659 for (i = 0; i < 15; ++i) {
660 if (i % 3 == 2) {
661 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
662 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
663 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
664 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
665 } else if (i % 3 == 1) {
666 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
667 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
668 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
669 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
670 } else {
671 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
672 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
673 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
674 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
675 }
676 }
677 for (i = 0; i < 15; ++i) {
678 if (i % 3 == 2) {
679 ASSERT_PASSED(aio_writesame_test_data, image, test_data,
680 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE,
681 0);
682 ASSERT_PASSED(aio_writesame_test_data, image, zero_data,
683 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE,
684 0);
685 } else if (i % 3 == 1) {
686 ASSERT_PASSED(aio_writesame_test_data, image, test_data,
687 TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
688 ASSERT_PASSED(aio_writesame_test_data, image, zero_data,
689 TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
690 } else {
691 ASSERT_PASSED(aio_writesame_test_data, image, test_data,
692 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
693 ASSERT_PASSED(aio_writesame_test_data, image, zero_data,
694 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
695 }
696 }
697
698 rbd_image_info_t info;
699 rbd_completion_t comp;
700 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
701 // can't read or write starting past end
702 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
703 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
704 // reading through end returns amount up to end
705 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
706 // writing through end returns amount up to end
707 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
708
709 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
710 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
711 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
712 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
713 rbd_aio_release(comp);
714
715 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
716 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
717 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
718 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
719 rbd_aio_release(comp);
720
721 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE,
722 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
39ae355f 723 mismatch_offset = 123;
f67539c2
TL
724 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE,
725 mismatch_data, mismatch_data, &mismatch_offset, 0));
726 ASSERT_EQ(0U, mismatch_offset);
727 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
39ae355f 728 mismatch_offset = 123;
f67539c2
TL
729 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data,
730 mismatch_data, comp, &mismatch_offset, 0));
731 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
39ae355f 732 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
f67539c2
TL
733 ASSERT_EQ(0U, mismatch_offset);
734 rbd_aio_release(comp);
735
736 ASSERT_PASSED(validate_object_map, image);
737 }
738
7c673cae
FG
739 static std::vector<std::string> _pool_names;
740 static std::vector<std::string> _unique_pool_names;
741 static rados_t _cluster;
742 static librados::Rados _rados;
743 static uint64_t _image_number;
744
745 std::string m_pool_name;
746 uint32_t m_pool_number;
747
748};
749
750std::vector<std::string> TestLibRBD::_pool_names;
751std::vector<std::string> TestLibRBD::_unique_pool_names;
752rados_t TestLibRBD::_cluster;
753librados::Rados TestLibRBD::_rados;
754uint64_t TestLibRBD::_image_number = 0;
755
756TEST_F(TestLibRBD, CreateAndStat)
757{
758 rados_ioctx_t ioctx;
759 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
760
761 rbd_image_info_t info;
762 rbd_image_t image;
763 int order = 0;
764 std::string name = get_temp_image_name();
765 uint64_t size = 2 << 20;
766
767 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
768 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
769 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
770 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
771 ASSERT_EQ(info.size, size);
772 ASSERT_EQ(info.order, order);
773 ASSERT_EQ(0, rbd_close(image));
774
775 rados_ioctx_destroy(ioctx);
776}
777
778TEST_F(TestLibRBD, CreateWithSameDataPool)
779{
780 REQUIRE_FORMAT_V2();
781
782 rados_ioctx_t ioctx;
783 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
784
785 rbd_image_t image;
786 std::string name = get_temp_image_name();
787 uint64_t size = 2 << 20;
788
789 bool old_format;
790 uint64_t features;
791 ASSERT_EQ(0, get_features(&old_format, &features));
792 ASSERT_FALSE(old_format);
793
794 rbd_image_options_t image_options;
795 rbd_image_options_create(&image_options);
796 BOOST_SCOPE_EXIT( (&image_options) ) {
797 rbd_image_options_destroy(image_options);
798 } BOOST_SCOPE_EXIT_END;
799
800 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
801 RBD_IMAGE_OPTION_FEATURES,
802 features));
803 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
804 RBD_IMAGE_OPTION_DATA_POOL,
805 m_pool_name.c_str()));
806
807 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
808 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
809
810 ASSERT_EQ(0, rbd_close(image));
811
812 rados_ioctx_destroy(ioctx);
813}
814
815TEST_F(TestLibRBD, CreateAndStatPP)
816{
817 librados::IoCtx ioctx;
818 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
819
820 {
821 librbd::RBD rbd;
822 librbd::image_info_t info;
823 librbd::Image image;
824 int order = 0;
825 std::string name = get_temp_image_name();
826 uint64_t size = 2 << 20;
827
828 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
829 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
830 ASSERT_EQ(0, image.stat(info, sizeof(info)));
831 ASSERT_EQ(info.size, size);
832 ASSERT_EQ(info.order, order);
833 }
834
835 ioctx.close();
836}
837
838TEST_F(TestLibRBD, GetId)
839{
840 rados_ioctx_t ioctx;
841 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
842
843 rbd_image_t image;
844 int order = 0;
845 std::string name = get_temp_image_name();
846
847 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
848 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
849
850 char id[4096];
851 if (!is_feature_enabled(0)) {
852 // V1 image
853 ASSERT_EQ(-EINVAL, rbd_get_id(image, id, sizeof(id)));
854 } else {
855 ASSERT_EQ(-ERANGE, rbd_get_id(image, id, 0));
856 ASSERT_EQ(0, rbd_get_id(image, id, sizeof(id)));
857 ASSERT_LT(0U, strlen(id));
11fdf7f2
TL
858
859 ASSERT_EQ(0, rbd_close(image));
860 ASSERT_EQ(0, rbd_open_by_id(ioctx, id, &image, NULL));
861 size_t name_len = 0;
862 ASSERT_EQ(-ERANGE, rbd_get_name(image, NULL, &name_len));
863 ASSERT_EQ(name_len, name.size() + 1);
864 char image_name[name_len];
865 ASSERT_EQ(0, rbd_get_name(image, image_name, &name_len));
866 ASSERT_STREQ(name.c_str(), image_name);
7c673cae
FG
867 }
868
869 ASSERT_EQ(0, rbd_close(image));
870 rados_ioctx_destroy(ioctx);
871}
872
873TEST_F(TestLibRBD, GetIdPP)
874{
875 librados::IoCtx ioctx;
876 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
877
878 librbd::RBD rbd;
879 librbd::Image image;
880 int order = 0;
881 std::string name = get_temp_image_name();
882
883 std::string id;
884 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
885 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
886 if (!is_feature_enabled(0)) {
887 // V1 image
888 ASSERT_EQ(-EINVAL, image.get_id(&id));
889 } else {
890 ASSERT_EQ(0, image.get_id(&id));
891 ASSERT_LT(0U, id.size());
11fdf7f2
TL
892
893 ASSERT_EQ(0, image.close());
894 ASSERT_EQ(0, rbd.open_by_id(ioctx, image, id.c_str(), NULL));
895 std::string image_name;
896 ASSERT_EQ(0, image.get_name(&image_name));
897 ASSERT_EQ(name, image_name);
7c673cae
FG
898 }
899}
900
901TEST_F(TestLibRBD, GetBlockNamePrefix)
902{
903 rados_ioctx_t ioctx;
904 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
905
906 rbd_image_t image;
907 int order = 0;
908 std::string name = get_temp_image_name();
909
910 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
911 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
912
913 char prefix[4096];
914 ASSERT_EQ(-ERANGE, rbd_get_block_name_prefix(image, prefix, 0));
915 ASSERT_EQ(0, rbd_get_block_name_prefix(image, prefix, sizeof(prefix)));
916 ASSERT_LT(0U, strlen(prefix));
917
918 ASSERT_EQ(0, rbd_close(image));
919 rados_ioctx_destroy(ioctx);
920}
921
922TEST_F(TestLibRBD, GetBlockNamePrefixPP)
923{
924 librados::IoCtx ioctx;
925 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
926
927 librbd::RBD rbd;
928 librbd::Image image;
929 int order = 0;
930 std::string name = get_temp_image_name();
931
932 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
933 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
934 ASSERT_LT(0U, image.get_block_name_prefix().size());
935}
936
31f18b77
FG
937TEST_F(TestLibRBD, TestGetCreateTimestamp)
938{
939 REQUIRE_FORMAT_V2();
940
941 rados_ioctx_t ioctx;
942 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
943
944 rbd_image_t image;
945 int order = 0;
946 std::string name = get_temp_image_name();
947
948 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
949 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
950
951 struct timespec timestamp;
952 ASSERT_EQ(0, rbd_get_create_timestamp(image, &timestamp));
953 ASSERT_LT(0, timestamp.tv_sec);
954
955 ASSERT_EQ(0, rbd_close(image));
956
957 rados_ioctx_destroy(ioctx);
958}
959
960TEST_F(TestLibRBD, GetCreateTimestampPP)
961{
962 REQUIRE_FORMAT_V2();
963
964 librados::IoCtx ioctx;
965 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
966
967 librbd::RBD rbd;
968 librbd::Image image;
969 int order = 0;
970 std::string name = get_temp_image_name();
971
972 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
973 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
974
975 struct timespec timestamp;
976 ASSERT_EQ(0, image.get_create_timestamp(&timestamp));
977 ASSERT_LT(0, timestamp.tv_sec);
978}
979
7c673cae
FG
980TEST_F(TestLibRBD, OpenAio)
981{
982 rados_ioctx_t ioctx;
983 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
984
985 rbd_image_info_t info;
986 rbd_image_t image;
987 int order = 0;
988 std::string name = get_temp_image_name();
989 uint64_t size = 2 << 20;
990
991 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
992
993 rbd_completion_t open_comp;
994 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
995 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
996 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
997 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
998 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp));
999 rbd_aio_release(open_comp);
1000
1001 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1002 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
1003 ASSERT_EQ(info.size, size);
1004 ASSERT_EQ(info.order, order);
1005
1006 rbd_completion_t close_comp;
1007 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &close_comp));
1008 ASSERT_EQ(0, rbd_aio_close(image, close_comp));
1009 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp));
1010 ASSERT_EQ(1, rbd_aio_is_complete(close_comp));
1011 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp));
1012 rbd_aio_release(close_comp);
1013
1014 rados_ioctx_destroy(ioctx);
1015}
1016
1017TEST_F(TestLibRBD, OpenAioFail)
1018{
1019 rados_ioctx_t ioctx;
1020 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
1021
1022 std::string name = get_temp_image_name();
1023 rbd_image_t image;
1024 rbd_completion_t open_comp;
1025 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
1026 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
1027 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
1028 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
1029 ASSERT_EQ(-ENOENT, rbd_aio_get_return_value(open_comp));
1030 rbd_aio_release(open_comp);
1031
1032 rados_ioctx_destroy(ioctx);
1033}
1034
1035TEST_F(TestLibRBD, OpenAioPP)
1036{
1037 librados::IoCtx ioctx;
1038 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1039
1040 librbd::RBD rbd;
1041 librbd::image_info_t info;
1042 librbd::Image image;
1043 int order = 0;
1044 std::string name = get_temp_image_name();
1045 uint64_t size = 2 << 20;
1046
1047 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1048
1049 librbd::RBD::AioCompletion *open_comp =
1050 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 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1058 ASSERT_EQ(info.size, size);
1059 ASSERT_EQ(info.order, order);
1060
1061 // reopen
1062 open_comp = new librbd::RBD::AioCompletion(NULL, NULL);
1063 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
1064 ASSERT_EQ(0, open_comp->wait_for_complete());
1065 ASSERT_EQ(1, open_comp->is_complete());
1066 ASSERT_EQ(0, open_comp->get_return_value());
1067 open_comp->release();
1068
1069 // close
1070 librbd::RBD::AioCompletion *close_comp =
1071 new librbd::RBD::AioCompletion(NULL, NULL);
1072 ASSERT_EQ(0, image.aio_close(close_comp));
1073 ASSERT_EQ(0, close_comp->wait_for_complete());
1074 ASSERT_EQ(1, close_comp->is_complete());
1075 ASSERT_EQ(0, close_comp->get_return_value());
1076 close_comp->release();
1077
1078 // close closed image
1079 close_comp = new librbd::RBD::AioCompletion(NULL, NULL);
1080 ASSERT_EQ(-EINVAL, image.aio_close(close_comp));
1081 close_comp->release();
1082
1083 ioctx.close();
1084}
1085
1086TEST_F(TestLibRBD, OpenAioFailPP)
1087{
1088 librados::IoCtx ioctx;
1089 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1090
1091 {
1092 librbd::RBD rbd;
1093 librbd::Image image;
1094 std::string name = get_temp_image_name();
1095
1096 librbd::RBD::AioCompletion *open_comp =
1097 new librbd::RBD::AioCompletion(NULL, NULL);
1098 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
1099 ASSERT_EQ(0, open_comp->wait_for_complete());
1100 ASSERT_EQ(1, open_comp->is_complete());
1101 ASSERT_EQ(-ENOENT, open_comp->get_return_value());
1102 open_comp->release();
1103 }
1104
1105 ioctx.close();
1106}
1107
1108TEST_F(TestLibRBD, ResizeAndStat)
1109{
1110 rados_ioctx_t ioctx;
1111 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1112
1113 rbd_image_info_t info;
1114 rbd_image_t image;
1115 int order = 0;
1116 std::string name = get_temp_image_name();
1117 uint64_t size = 2 << 20;
1118
1119 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1120 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1121
1122 ASSERT_EQ(0, rbd_resize(image, size * 4));
1123 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1124 ASSERT_EQ(info.size, size * 4);
1125
1126 ASSERT_EQ(0, rbd_resize(image, size / 2));
1127 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1128 ASSERT_EQ(info.size, size / 2);
1129
1130 // downsizing without allowing shrink should fail
1131 // and image size should not change
1132 ASSERT_EQ(-EINVAL, rbd_resize2(image, size / 4, false, NULL, NULL));
1133 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1134 ASSERT_EQ(info.size, size / 2);
1135
1136 ASSERT_EQ(0, rbd_resize2(image, size / 4, true, NULL, NULL));
1137 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1138 ASSERT_EQ(info.size, size / 4);
1139
1140 ASSERT_PASSED(validate_object_map, image);
1141 ASSERT_EQ(0, rbd_close(image));
1142
1143 rados_ioctx_destroy(ioctx);
1144}
1145
1146TEST_F(TestLibRBD, ResizeAndStatPP)
1147{
1148 librados::IoCtx ioctx;
1149 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1150
1151 {
1152 librbd::RBD rbd;
1153 librbd::image_info_t info;
1154 librbd::Image image;
1155 int order = 0;
1156 std::string name = get_temp_image_name();
1157 uint64_t size = 2 << 20;
1158
1159 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1160 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1161
1162 ASSERT_EQ(0, image.resize(size * 4));
1163 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1164 ASSERT_EQ(info.size, size * 4);
1165
1166 ASSERT_EQ(0, image.resize(size / 2));
1167 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1168 ASSERT_EQ(info.size, size / 2);
1169 ASSERT_PASSED(validate_object_map, image);
1170 }
1171
1172 ioctx.close();
1173}
1174
1175TEST_F(TestLibRBD, UpdateWatchAndResize)
1176{
1177 rados_ioctx_t ioctx;
1178 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1179
1180 rbd_image_t image;
1181 int order = 0;
1182 std::string name = get_temp_image_name();
1183 uint64_t size = 2 << 20;
1184 struct Watcher {
31f18b77 1185 rbd_image_t &m_image;
f67539c2
TL
1186 std::mutex m_lock;
1187 std::condition_variable m_cond;
31f18b77 1188 size_t m_size = 0;
7c673cae
FG
1189 static void cb(void *arg) {
1190 Watcher *watcher = static_cast<Watcher *>(arg);
1191 watcher->handle_notify();
1192 }
11fdf7f2 1193 explicit Watcher(rbd_image_t &image) : m_image(image) {}
7c673cae
FG
1194 void handle_notify() {
1195 rbd_image_info_t info;
1196 ASSERT_EQ(0, rbd_stat(m_image, &info, sizeof(info)));
f67539c2 1197 std::lock_guard<std::mutex> locker(m_lock);
7c673cae 1198 m_size = info.size;
31f18b77 1199 m_cond.notify_one();
7c673cae
FG
1200 }
1201 void wait_for_size(size_t size) {
f67539c2 1202 std::unique_lock<std::mutex> locker(m_lock);
31f18b77
FG
1203 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
1204 [size, this] {
1205 return this->m_size == size;}));
7c673cae 1206 }
7c673cae
FG
1207 } watcher(image);
1208 uint64_t handle;
1209
1210 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1211 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1212
1213 ASSERT_EQ(0, rbd_update_watch(image, &handle, Watcher::cb, &watcher));
1214
1215 ASSERT_EQ(0, rbd_resize(image, size * 4));
1216 watcher.wait_for_size(size * 4);
1217
1218 ASSERT_EQ(0, rbd_resize(image, size / 2));
1219 watcher.wait_for_size(size / 2);
1220
1221 ASSERT_EQ(0, rbd_update_unwatch(image, handle));
1222
1223 ASSERT_EQ(0, rbd_close(image));
1224 rados_ioctx_destroy(ioctx);
1225}
1226
1227TEST_F(TestLibRBD, UpdateWatchAndResizePP)
1228{
1229 librados::IoCtx ioctx;
1230 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1231
1232 {
1233 librbd::RBD rbd;
1234 librbd::Image image;
1235 int order = 0;
1236 std::string name = get_temp_image_name();
1237 uint64_t size = 2 << 20;
1238 struct Watcher : public librbd::UpdateWatchCtx {
11fdf7f2 1239 explicit Watcher(librbd::Image &image) : m_image(image) {
7c673cae
FG
1240 }
1241 void handle_notify() override {
1242 librbd::image_info_t info;
1243 ASSERT_EQ(0, m_image.stat(info, sizeof(info)));
f67539c2 1244 std::lock_guard<std::mutex> locker(m_lock);
7c673cae 1245 m_size = info.size;
31f18b77 1246 m_cond.notify_one();
7c673cae
FG
1247 }
1248 void wait_for_size(size_t size) {
f67539c2 1249 std::unique_lock<std::mutex> locker(m_lock);
31f18b77
FG
1250 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
1251 [size, this] {
1252 return this->m_size == size;}));
7c673cae
FG
1253 }
1254 librbd::Image &m_image;
f67539c2
TL
1255 std::mutex m_lock;
1256 std::condition_variable m_cond;
7c673cae
FG
1257 size_t m_size = 0;
1258 } watcher(image);
1259 uint64_t handle;
1260
1261 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1262 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1263
1264 ASSERT_EQ(0, image.update_watch(&watcher, &handle));
1265
1266 ASSERT_EQ(0, image.resize(size * 4));
1267 watcher.wait_for_size(size * 4);
1268
1269 ASSERT_EQ(0, image.resize(size / 2));
1270 watcher.wait_for_size(size / 2);
1271
1272 ASSERT_EQ(0, image.update_unwatch(handle));
1273 }
1274
1275 ioctx.close();
1276}
1277
1278int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
1279{
1280 int num_images, i;
1281 char *names, *cur_name;
1282 va_list ap;
1283 size_t max_size = 1024;
1284
1285 names = (char *) malloc(sizeof(char) * 1024);
1286 int len = rbd_list(io_ctx, names, &max_size);
1287
1288 std::set<std::string> image_names;
1289 for (i = 0, num_images = 0, cur_name = names; cur_name < names + len; i++) {
1290 printf("image: %s\n", cur_name);
1291 image_names.insert(cur_name);
1292 cur_name += strlen(cur_name) + 1;
1293 num_images++;
1294 }
1295 free(names);
1296
1297 va_start(ap, num_expected);
1298 for (i = num_expected; i > 0; i--) {
1299 char *expected = va_arg(ap, char *);
1300 printf("expected = %s\n", expected);
1301 std::set<std::string>::iterator it = image_names.find(expected);
1302 if (it != image_names.end()) {
1303 printf("found %s\n", expected);
1304 image_names.erase(it);
1305 printf("erased %s\n", expected);
1306 } else {
1307 ADD_FAILURE() << "Unable to find image " << expected;
1308 va_end(ap);
1309 return -ENOENT;
1310 }
1311 }
1312 va_end(ap);
1313
1314 if (!image_names.empty()) {
1315 ADD_FAILURE() << "Unexpected images discovered";
1316 return -EINVAL;
1317 }
1318 return num_images;
1319}
1320
1321TEST_F(TestLibRBD, TestCreateLsDelete)
1322{
1323 rados_ioctx_t ioctx;
1324 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
1325
1326 int order = 0;
1327 std::string name = get_temp_image_name();
1328 std::string name2 = get_temp_image_name();
1329 uint64_t size = 2 << 20;
11fdf7f2
TL
1330
1331 ASSERT_EQ(0, test_ls(ioctx, 0));
7c673cae
FG
1332 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1333 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
1334 ASSERT_EQ(0, create_image(ioctx, name2.c_str(), size, &order));
1335 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
1336 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
1337 ASSERT_EQ(1, test_ls(ioctx, 1, name2.c_str()));
1338
1339 ASSERT_EQ(-ENOENT, rbd_remove(ioctx, name.c_str()));
1340
1341 rados_ioctx_destroy(ioctx);
1342}
1343
1344int test_ls_pp(librbd::RBD& rbd, librados::IoCtx& io_ctx, size_t num_expected, ...)
1345{
1346 int r;
1347 size_t i;
1348 va_list ap;
1349 vector<string> names;
1350 r = rbd.list(io_ctx, names);
1351 if (r == -ENOENT)
1352 r = 0;
1353 EXPECT_TRUE(r >= 0);
1354 cout << "num images is: " << names.size() << std::endl
1355 << "expected: " << num_expected << std::endl;
1356 int num = names.size();
1357
1358 for (i = 0; i < names.size(); i++) {
1359 cout << "image: " << names[i] << std::endl;
1360 }
1361
1362 va_start(ap, num_expected);
1363 for (i = num_expected; i > 0; i--) {
1364 char *expected = va_arg(ap, char *);
1365 cout << "expected = " << expected << std::endl;
1366 vector<string>::iterator listed_name = find(names.begin(), names.end(), string(expected));
1367 if (listed_name == names.end()) {
1368 ADD_FAILURE() << "Unable to find image " << expected;
1369 va_end(ap);
1370 return -ENOENT;
1371 }
1372 names.erase(listed_name);
1373 }
f67539c2 1374 va_end(ap);
7c673cae 1375
f67539c2
TL
1376 if (!names.empty()) {
1377 ADD_FAILURE() << "Unexpected images discovered";
1378 return -EINVAL;
7c673cae 1379 }
f67539c2
TL
1380 return num;
1381}
7c673cae 1382
f67539c2 1383TEST_F(TestLibRBD, TestCreateLsDeletePP)
7c673cae
FG
1384{
1385 librados::IoCtx ioctx;
1386 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
1387
1388 {
1389 librbd::RBD rbd;
1390 librbd::Image image;
1391 int order = 0;
1392 std::string name = get_temp_image_name();
1393 std::string name2 = get_temp_image_name();
7c673cae 1394 uint64_t size = 2 << 20;
7c673cae
FG
1395
1396 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7c673cae 1397 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
f67539c2 1398 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
7c673cae 1399 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
f67539c2
TL
1400 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
1401 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name2.c_str()));
7c673cae
FG
1402 }
1403
1404 ioctx.close();
1405}
1406
f67539c2
TL
1407
1408static int print_progress_percent(uint64_t offset, uint64_t src_size,
1409 void *data)
11fdf7f2 1410{
f67539c2
TL
1411 float percent = ((float)offset * 100) / src_size;
1412 printf("%3.2f%% done\n", percent);
1413 return 0;
1414}
11fdf7f2 1415
f67539c2
TL
1416TEST_F(TestLibRBD, TestCopy)
1417{
11fdf7f2
TL
1418 rados_ioctx_t ioctx;
1419 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
11fdf7f2
TL
1420
1421 rbd_image_t image;
1422 rbd_image_t image2;
1423 rbd_image_t image3;
11fdf7f2
TL
1424 int order = 0;
1425 std::string name = get_temp_image_name();
1426 std::string name2 = get_temp_image_name();
1427 std::string name3 = get_temp_image_name();
11fdf7f2
TL
1428
1429 uint64_t size = 2 << 20;
1430
11fdf7f2
TL
1431 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1432 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11fdf7f2
TL
1433 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
1434
1435 size_t sum_key_len = 0;
1436 size_t sum_value_len = 0;
1437 std::string key;
1438 std::string val;
1439 for (int i = 1; i <= 70; i++) {
1440 key = "key" + stringify(i);
1441 val = "value" + stringify(i);
1442 ASSERT_EQ(0, rbd_metadata_set(image, key.c_str(), val.c_str()));
1443
1444 sum_key_len += (key.size() + 1);
1445 sum_value_len += (val.size() + 1);
1446 }
1447
1448 char keys[1024];
1449 char vals[1024];
1450 size_t keys_len = sizeof(keys);
1451 size_t vals_len = sizeof(vals);
1452
1453 char value[1024];
1454 size_t value_len = sizeof(value);
1455
f67539c2 1456 ASSERT_EQ(0, rbd_copy(image, ioctx, name2.c_str()));
11fdf7f2
TL
1457 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
1458 ASSERT_EQ(0, rbd_open(ioctx, name2.c_str(), &image2, NULL));
f67539c2 1459 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
11fdf7f2
TL
1460 &vals_len));
1461 ASSERT_EQ(keys_len, sum_key_len);
1462 ASSERT_EQ(vals_len, sum_value_len);
1463
1464 for (int i = 1; i <= 70; i++) {
1465 key = "key" + stringify(i);
1466 val = "value" + stringify(i);
1467 ASSERT_EQ(0, rbd_metadata_get(image2, key.c_str(), value, &value_len));
1468 ASSERT_STREQ(val.c_str(), value);
1469
1470 value_len = sizeof(value);
1471 }
1472
f67539c2
TL
1473 ASSERT_EQ(0, rbd_copy_with_progress(image, ioctx, name3.c_str(),
1474 print_progress_percent, NULL));
11fdf7f2
TL
1475 ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
1476
1477 keys_len = sizeof(keys);
1478 vals_len = sizeof(vals);
1479 ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
f67539c2 1480 ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
11fdf7f2
TL
1481 &vals_len));
1482 ASSERT_EQ(keys_len, sum_key_len);
1483 ASSERT_EQ(vals_len, sum_value_len);
1484
1485 for (int i = 1; i <= 70; i++) {
1486 key = "key" + stringify(i);
1487 val = "value" + stringify(i);
1488 ASSERT_EQ(0, rbd_metadata_get(image3, key.c_str(), value, &value_len));
1489 ASSERT_STREQ(val.c_str(), value);
1490
1491 value_len = sizeof(value);
1492 }
1493
11fdf7f2 1494 ASSERT_EQ(0, rbd_close(image));
f67539c2
TL
1495 ASSERT_EQ(0, rbd_close(image2));
1496 ASSERT_EQ(0, rbd_close(image3));
1497 rados_ioctx_destroy(ioctx);
11fdf7f2
TL
1498}
1499
f67539c2 1500class PrintProgress : public librbd::ProgressContext
11fdf7f2 1501{
f67539c2
TL
1502public:
1503 int update_progress(uint64_t offset, uint64_t src_size) override
1504 {
1505 float percent = ((float)offset * 100) / src_size;
1506 printf("%3.2f%% done\n", percent);
1507 return 0;
1508 }
1509};
11fdf7f2 1510
f67539c2
TL
1511TEST_F(TestLibRBD, TestCopyPP)
1512{
11fdf7f2
TL
1513 librados::IoCtx ioctx;
1514 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
1515
1516 {
1517 librbd::RBD rbd;
1518 librbd::Image image;
1519 librbd::Image image2;
1520 librbd::Image image3;
1521 int order = 0;
1522 std::string name = get_temp_image_name();
1523 std::string name2 = get_temp_image_name();
1524 std::string name3 = get_temp_image_name();
1525 uint64_t size = 2 << 20;
11fdf7f2
TL
1526 PrintProgress pp;
1527
1528 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1529 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1530
1531 std::string key;
1532 std::string val;
1533 for (int i = 1; i <= 70; i++) {
1534 key = "key" + stringify(i);
1535 val = "value" + stringify(i);
1536 ASSERT_EQ(0, image.metadata_set(key, val));
1537 }
1538
1539 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
f67539c2 1540 ASSERT_EQ(0, image.copy(ioctx, name2.c_str()));
11fdf7f2
TL
1541 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
1542 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), NULL));
1543
1544 map<string, bufferlist> pairs;
1545 std::string value;
1546 ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
1547 ASSERT_EQ(70U, pairs.size());
1548
1549 for (int i = 1; i <= 70; i++) {
1550 key = "key" + stringify(i);
1551 val = "value" + stringify(i);
f67539c2
TL
1552 ASSERT_EQ(0, image2.metadata_get(key.c_str(), &value));
1553 ASSERT_STREQ(val.c_str(), value.c_str());
1554 }
7c673cae 1555
f67539c2
TL
1556 ASSERT_EQ(0, image.copy_with_progress(ioctx, name3.c_str(), pp));
1557 ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name.c_str(), name2.c_str(),
1558 name3.c_str()));
1559 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
7c673cae 1560
f67539c2
TL
1561 pairs.clear();
1562 ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
1563 ASSERT_EQ(70U, pairs.size());
7c673cae 1564
f67539c2
TL
1565 for (int i = 1; i <= 70; i++) {
1566 key = "key" + stringify(i);
1567 val = "value" + stringify(i);
1568 ASSERT_EQ(0, image3.metadata_get(key.c_str(), &value));
1569 ASSERT_STREQ(val.c_str(), value.c_str());
1570 }
1571 }
7c673cae 1572
f67539c2 1573 ioctx.close();
7c673cae
FG
1574}
1575
f67539c2 1576TEST_F(TestLibRBD, TestDeepCopy)
7c673cae
FG
1577{
1578 REQUIRE_FORMAT_V2();
f67539c2 1579 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7c673cae
FG
1580
1581 rados_ioctx_t ioctx;
f67539c2
TL
1582 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
1583 BOOST_SCOPE_EXIT_ALL( (&ioctx) ) {
1584 rados_ioctx_destroy(ioctx);
1585 };
7c673cae
FG
1586
1587 rbd_image_t image;
f67539c2
TL
1588 rbd_image_t image2;
1589 rbd_image_t image3;
1590 rbd_image_t image4;
1591 rbd_image_t image5;
1592 rbd_image_t image6;
31f18b77 1593 int order = 0;
7c673cae 1594 std::string name = get_temp_image_name();
f67539c2
TL
1595 std::string name2 = get_temp_image_name();
1596 std::string name3 = get_temp_image_name();
1597 std::string name4 = get_temp_image_name();
1598 std::string name5 = get_temp_image_name();
1599 std::string name6 = get_temp_image_name();
1600
7c673cae 1601 uint64_t size = 2 << 20;
f67539c2
TL
1602
1603 rbd_image_options_t opts;
1604 rbd_image_options_create(&opts);
1605 BOOST_SCOPE_EXIT_ALL( (&opts) ) {
1606 rbd_image_options_destroy(opts);
1607 };
31f18b77 1608
7c673cae
FG
1609 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1610 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
f67539c2
TL
1611 BOOST_SCOPE_EXIT_ALL( (&image) ) {
1612 ASSERT_EQ(0, rbd_close(image));
1613 };
1614 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
7c673cae 1615
f67539c2
TL
1616 size_t sum_key_len = 0;
1617 size_t sum_value_len = 0;
1618 std::string key;
1619 std::string val;
1620 for (int i = 1; i <= 70; i++) {
1621 key = "key" + stringify(i);
1622 val = "value" + stringify(i);
1623 ASSERT_EQ(0, rbd_metadata_set(image, key.c_str(), val.c_str()));
7c673cae 1624
f67539c2
TL
1625 sum_key_len += (key.size() + 1);
1626 sum_value_len += (val.size() + 1);
1627 }
7c673cae 1628
f67539c2
TL
1629 char keys[1024];
1630 char vals[1024];
1631 size_t keys_len = sizeof(keys);
1632 size_t vals_len = sizeof(vals);
7c673cae 1633
f67539c2
TL
1634 char value[1024];
1635 size_t value_len = sizeof(value);
7c673cae 1636
f67539c2
TL
1637 ASSERT_EQ(0, rbd_deep_copy(image, ioctx, name2.c_str(), opts));
1638 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
1639 ASSERT_EQ(0, rbd_open(ioctx, name2.c_str(), &image2, NULL));
1640 BOOST_SCOPE_EXIT_ALL( (&image2) ) {
1641 ASSERT_EQ(0, rbd_close(image2));
1642 };
1643 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
1644 &vals_len));
1645 ASSERT_EQ(keys_len, sum_key_len);
1646 ASSERT_EQ(vals_len, sum_value_len);
7c673cae 1647
f67539c2
TL
1648 for (int i = 1; i <= 70; i++) {
1649 key = "key" + stringify(i);
1650 val = "value" + stringify(i);
1651 ASSERT_EQ(0, rbd_metadata_get(image2, key.c_str(), value, &value_len));
1652 ASSERT_STREQ(val.c_str(), value);
7c673cae 1653
f67539c2 1654 value_len = sizeof(value);
7c673cae
FG
1655 }
1656
f67539c2
TL
1657 ASSERT_EQ(0, rbd_deep_copy_with_progress(image, ioctx, name3.c_str(), opts,
1658 print_progress_percent, NULL));
1659 ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
7c673cae 1660
f67539c2
TL
1661 keys_len = sizeof(keys);
1662 vals_len = sizeof(vals);
1663 ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
1664 BOOST_SCOPE_EXIT_ALL( (&image3) ) {
1665 ASSERT_EQ(0, rbd_close(image3));
1666 };
1667 ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
1668 &vals_len));
1669 ASSERT_EQ(keys_len, sum_key_len);
1670 ASSERT_EQ(vals_len, sum_value_len);
1671
1672 for (int i = 1; i <= 70; i++) {
1673 key = "key" + stringify(i);
1674 val = "value" + stringify(i);
1675 ASSERT_EQ(0, rbd_metadata_get(image3, key.c_str(), value, &value_len));
1676 ASSERT_STREQ(val.c_str(), value);
1677
1678 value_len = sizeof(value);
7c673cae
FG
1679 }
1680
f67539c2
TL
1681 ASSERT_EQ(0, rbd_snap_create(image, "deep_snap"));
1682 ASSERT_EQ(0, rbd_close(image));
1683 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, "deep_snap"));
1684 ASSERT_EQ(0, rbd_snap_protect(image, "deep_snap"));
1685 ASSERT_EQ(0, rbd_clone3(ioctx, name.c_str(), "deep_snap", ioctx,
1686 name4.c_str(), opts));
7c673cae 1687
f67539c2
TL
1688 ASSERT_EQ(4, test_ls(ioctx, 4, name.c_str(), name2.c_str(), name3.c_str(),
1689 name4.c_str()));
1690 ASSERT_EQ(0, rbd_open(ioctx, name4.c_str(), &image4, NULL));
1691 BOOST_SCOPE_EXIT_ALL( (&image4) ) {
1692 ASSERT_EQ(0, rbd_close(image4));
1693 };
1694 ASSERT_EQ(0, rbd_snap_create(image4, "deep_snap"));
7c673cae 1695
f67539c2
TL
1696 ASSERT_EQ(0, rbd_deep_copy(image4, ioctx, name5.c_str(), opts));
1697 ASSERT_EQ(5, test_ls(ioctx, 5, name.c_str(), name2.c_str(), name3.c_str(),
1698 name4.c_str(), name5.c_str()));
1699 ASSERT_EQ(0, rbd_open(ioctx, name5.c_str(), &image5, NULL));
1700 BOOST_SCOPE_EXIT_ALL( (&image5) ) {
1701 ASSERT_EQ(0, rbd_close(image5));
1702 };
1703 ASSERT_EQ(0, rbd_metadata_list(image5, "key", 70, keys, &keys_len, vals,
1704 &vals_len));
1705 ASSERT_EQ(keys_len, sum_key_len);
1706 ASSERT_EQ(vals_len, sum_value_len);
1707
1708 for (int i = 1; i <= 70; i++) {
1709 key = "key" + stringify(i);
1710 val = "value" + stringify(i);
1711 ASSERT_EQ(0, rbd_metadata_get(image5, key.c_str(), value, &value_len));
1712 ASSERT_STREQ(val.c_str(), value);
1713
1714 value_len = sizeof(value);
7c673cae
FG
1715 }
1716
f67539c2
TL
1717 ASSERT_EQ(0, rbd_deep_copy_with_progress(image4, ioctx, name6.c_str(), opts,
1718 print_progress_percent, NULL));
1719 ASSERT_EQ(6, test_ls(ioctx, 6, name.c_str(), name2.c_str(), name3.c_str(),
1720 name4.c_str(), name5.c_str(), name6.c_str()));
1721
1722 keys_len = sizeof(keys);
1723 vals_len = sizeof(vals);
1724 ASSERT_EQ(0, rbd_open(ioctx, name6.c_str(), &image6, NULL));
1725 BOOST_SCOPE_EXIT_ALL( (&image6) ) {
1726 ASSERT_EQ(0, rbd_close(image6));
1727 };
1728 ASSERT_EQ(0, rbd_metadata_list(image6, "key", 70, keys, &keys_len, vals,
1729 &vals_len));
1730 ASSERT_EQ(keys_len, sum_key_len);
1731 ASSERT_EQ(vals_len, sum_value_len);
1732
1733 for (int i = 1; i <= 70; i++) {
1734 key = "key" + stringify(i);
1735 val = "value" + stringify(i);
1736 ASSERT_EQ(0, rbd_metadata_get(image6, key.c_str(), value, &value_len));
1737 ASSERT_STREQ(val.c_str(), value);
1738
1739 value_len = sizeof(value);
1740 }
7c673cae
FG
1741}
1742
f67539c2 1743TEST_F(TestLibRBD, TestDeepCopyPP)
9f95a23c 1744{
f67539c2
TL
1745 REQUIRE_FORMAT_V2();
1746
9f95a23c 1747 librados::IoCtx ioctx;
f67539c2 1748 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
9f95a23c
TL
1749
1750 {
1751 librbd::RBD rbd;
1752 librbd::Image image;
f67539c2
TL
1753 librbd::Image image2;
1754 librbd::Image image3;
9f95a23c
TL
1755 int order = 0;
1756 std::string name = get_temp_image_name();
f67539c2
TL
1757 std::string name2 = get_temp_image_name();
1758 std::string name3 = get_temp_image_name();
9f95a23c 1759 uint64_t size = 2 << 20;
f67539c2
TL
1760 librbd::ImageOptions opts;
1761 PrintProgress pp;
9f95a23c
TL
1762
1763 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1764 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1765
f67539c2
TL
1766 std::string key;
1767 std::string val;
1768 for (int i = 1; i <= 70; i++) {
1769 key = "key" + stringify(i);
1770 val = "value" + stringify(i);
1771 ASSERT_EQ(0, image.metadata_set(key, val));
9f95a23c
TL
1772 }
1773
f67539c2
TL
1774 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
1775 ASSERT_EQ(0, image.deep_copy(ioctx, name2.c_str(), opts));
1776 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
1777 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), NULL));
9f95a23c 1778
f67539c2
TL
1779 map<string, bufferlist> pairs;
1780 std::string value;
1781 ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
1782 ASSERT_EQ(70U, pairs.size());
9f95a23c 1783
f67539c2
TL
1784 for (int i = 1; i <= 70; i++) {
1785 key = "key" + stringify(i);
1786 val = "value" + stringify(i);
1787 ASSERT_EQ(0, image2.metadata_get(key.c_str(), &value));
1788 ASSERT_STREQ(val.c_str(), value.c_str());
1789 }
9f95a23c 1790
f67539c2
TL
1791 ASSERT_EQ(0, image.deep_copy_with_progress(ioctx, name3.c_str(), opts, pp));
1792 ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name.c_str(), name2.c_str(),
1793 name3.c_str()));
1794 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
7c673cae 1795
f67539c2
TL
1796 pairs.clear();
1797 ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
1798 ASSERT_EQ(70U, pairs.size());
1799
1800 for (int i = 1; i <= 70; i++) {
1801 key = "key" + stringify(i);
1802 val = "value" + stringify(i);
1803 ASSERT_EQ(0, image3.metadata_get(key.c_str(), &value));
1804 ASSERT_STREQ(val.c_str(), value.c_str());
1805 }
7c673cae
FG
1806 }
1807
1808 ioctx.close();
1809}
1810
f67539c2 1811int test_ls_snaps(rbd_image_t image, int num_expected, ...)
7c673cae 1812{
f67539c2
TL
1813 int num_snaps, i, j, max_size = 10;
1814 va_list ap;
1815 rbd_snap_info_t snaps[max_size];
1816 num_snaps = rbd_snap_list(image, snaps, &max_size);
1817 printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected);
7c673cae 1818
f67539c2
TL
1819 for (i = 0; i < num_snaps; i++) {
1820 printf("snap: %s\n", snaps[i].name);
1821 }
7c673cae 1822
f67539c2
TL
1823 va_start(ap, num_expected);
1824 for (i = num_expected; i > 0; i--) {
1825 char *expected = va_arg(ap, char *);
1826 uint64_t expected_size = va_arg(ap, uint64_t);
1827 bool found = false;
1828 for (j = 0; j < num_snaps; j++) {
1829 if (snaps[j].name == NULL)
1830 continue;
1831 if (strcmp(snaps[j].name, expected) == 0) {
1832 printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size);
1833 EXPECT_EQ(expected_size, snaps[j].size);
1834 free((void *) snaps[j].name);
1835 snaps[j].name = NULL;
1836 found = true;
1837 break;
1838 }
1839 }
1840 EXPECT_TRUE(found);
1841 }
1842 va_end(ap);
7c673cae 1843
f67539c2
TL
1844 for (i = 0; i < num_snaps; i++) {
1845 EXPECT_EQ((const char *)0, snaps[i].name);
1846 }
7c673cae 1847
f67539c2 1848 return num_snaps;
7c673cae
FG
1849}
1850
f67539c2 1851TEST_F(TestLibRBD, TestCreateLsDeleteSnap)
7c673cae 1852{
f67539c2
TL
1853 rados_ioctx_t ioctx;
1854 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 1855
f67539c2
TL
1856 rbd_image_t image;
1857 int order = 0;
1858 std::string name = get_temp_image_name();
1859 uint64_t size = 2 << 20;
1860 uint64_t size2 = 4 << 20;
1861
1862 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1863 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 1864
f67539c2
TL
1865 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1866 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1867 ASSERT_EQ(0, rbd_resize(image, size2));
1868 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1869 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1870 ASSERT_EQ(0, rbd_snap_remove(image, "snap1"));
1871 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
1872 ASSERT_EQ(0, rbd_snap_remove(image, "snap2"));
1873 ASSERT_EQ(0, test_ls_snaps(image, 0));
1874
1875 ASSERT_EQ(0, rbd_close(image));
1876
1877 rados_ioctx_destroy(ioctx);
7c673cae
FG
1878}
1879
f67539c2 1880int test_get_snapshot_timestamp(rbd_image_t image, uint64_t snap_id)
7c673cae 1881{
f67539c2
TL
1882 struct timespec timestamp;
1883 EXPECT_EQ(0, rbd_snap_get_timestamp(image, snap_id, &timestamp));
1884 EXPECT_LT(0, timestamp.tv_sec);
1885 return 0;
7c673cae
FG
1886}
1887
f67539c2 1888TEST_F(TestLibRBD, TestGetSnapShotTimeStamp)
7c673cae 1889{
f67539c2 1890 REQUIRE_FORMAT_V2();
7c673cae 1891
f67539c2
TL
1892 rados_ioctx_t ioctx;
1893 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 1894
f67539c2
TL
1895 rbd_image_t image;
1896 int order = 0;
1897 std::string name = get_temp_image_name();
1898 uint64_t size = 2 << 20;
1899 int num_snaps, max_size = 10;
1900 rbd_snap_info_t snaps[max_size];
7c673cae 1901
f67539c2
TL
1902 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1903 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 1904
f67539c2
TL
1905 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1906 num_snaps = rbd_snap_list(image, snaps, &max_size);
1907 ASSERT_EQ(1, num_snaps);
1908 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1909 free((void *)snaps[0].name);
7c673cae 1910
f67539c2
TL
1911 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1912 num_snaps = rbd_snap_list(image, snaps, &max_size);
1913 ASSERT_EQ(2, num_snaps);
1914 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1915 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[1].id));
1916 free((void *)snaps[0].name);
1917 free((void *)snaps[1].name);
7c673cae 1918
f67539c2 1919 ASSERT_EQ(0, rbd_close(image));
7c673cae 1920
f67539c2 1921 rados_ioctx_destroy(ioctx);
7c673cae
FG
1922}
1923
7c673cae 1924
f67539c2 1925int test_ls_snaps(librbd::Image& image, size_t num_expected, ...)
7c673cae 1926{
7c673cae 1927 int r;
f67539c2
TL
1928 size_t i, j;
1929 va_list ap;
1930 vector<librbd::snap_info_t> snaps;
1931 r = image.snap_list(snaps);
1932 EXPECT_TRUE(r >= 0);
1933 cout << "num snaps is: " << snaps.size() << std::endl
1934 << "expected: " << num_expected << std::endl;
7c673cae 1935
f67539c2
TL
1936 for (i = 0; i < snaps.size(); i++) {
1937 cout << "snap: " << snaps[i].name << std::endl;
1938 }
7c673cae 1939
f67539c2
TL
1940 va_start(ap, num_expected);
1941 for (i = num_expected; i > 0; i--) {
1942 char *expected = va_arg(ap, char *);
1943 uint64_t expected_size = va_arg(ap, uint64_t);
1944 int found = 0;
1945 for (j = 0; j < snaps.size(); j++) {
1946 if (snaps[j].name == "")
1947 continue;
1948 if (strcmp(snaps[j].name.c_str(), expected) == 0) {
1949 cout << "found " << snaps[j].name << " with size " << snaps[j].size
1950 << std::endl;
1951 EXPECT_EQ(expected_size, snaps[j].size);
1952 snaps[j].name = "";
1953 found = 1;
1954 break;
1955 }
7c673cae 1956 }
f67539c2 1957 EXPECT_TRUE(found);
7c673cae 1958 }
f67539c2 1959 va_end(ap);
7c673cae 1960
f67539c2
TL
1961 for (i = 0; i < snaps.size(); i++) {
1962 EXPECT_EQ("", snaps[i].name);
1963 }
1964
1965 return snaps.size();
7c673cae
FG
1966}
1967
f67539c2 1968TEST_F(TestLibRBD, TestCreateLsDeleteSnapPP)
7c673cae 1969{
f67539c2
TL
1970 librados::IoCtx ioctx;
1971 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 1972
f67539c2
TL
1973 {
1974 librbd::RBD rbd;
1975 librbd::Image image;
1976 int order = 0;
1977 std::string name = get_temp_image_name();
1978 uint64_t size = 2 << 20;
1979 uint64_t size2 = 4 << 20;
1980
1981 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1982 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1983
1984 bool exists;
1985 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1986 ASSERT_FALSE(exists);
1987 ASSERT_EQ(0, image.snap_create("snap1"));
1988 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1989 ASSERT_TRUE(exists);
1990 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1991 ASSERT_EQ(0, image.resize(size2));
1992 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1993 ASSERT_FALSE(exists);
1994 ASSERT_EQ(0, image.snap_create("snap2"));
1995 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1996 ASSERT_TRUE(exists);
1997 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1998 ASSERT_EQ(0, image.snap_remove("snap1"));
1999 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
2000 ASSERT_FALSE(exists);
2001 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
2002 ASSERT_EQ(0, image.snap_remove("snap2"));
2003 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
2004 ASSERT_FALSE(exists);
2005 ASSERT_EQ(0, test_ls_snaps(image, 0));
7c673cae 2006 }
7c673cae 2007
f67539c2 2008 ioctx.close();
7c673cae
FG
2009}
2010
f67539c2 2011TEST_F(TestLibRBD, TestGetNameIdSnapPP)
c07f9fc5 2012{
f67539c2
TL
2013 librados::IoCtx ioctx;
2014 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
c07f9fc5 2015
f67539c2
TL
2016 {
2017 librbd::RBD rbd;
2018 librbd::Image image;
2019 int order = 0;
2020 std::string name = get_temp_image_name();
2021 uint64_t size = 2 << 20;
2022
2023 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2024 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2025
2026 ASSERT_EQ(0, image.snap_create("snap1"));
2027 ASSERT_EQ(0, image.snap_create("snap2"));
2028 ASSERT_EQ(0, image.snap_create("snap3"));
2029 vector<librbd::snap_info_t> snaps;
2030 int r = image.snap_list(snaps);
2031 EXPECT_TRUE(r >= 0);
2032
2033 for (size_t i = 0; i < snaps.size(); ++i) {
2034 std::string expected_snap_name;
2035 image.snap_get_name(snaps[i].id, &expected_snap_name);
2036 ASSERT_EQ(expected_snap_name, snaps[i].name);
2037 }
2038
2039 for (size_t i = 0; i < snaps.size(); ++i) {
2040 uint64_t expected_snap_id;
2041 image.snap_get_id(snaps[i].name, &expected_snap_id);
2042 ASSERT_EQ(expected_snap_id, snaps[i].id);
2043 }
2044
2045 ASSERT_EQ(0, image.snap_remove("snap1"));
2046 ASSERT_EQ(0, image.snap_remove("snap2"));
2047 ASSERT_EQ(0, image.snap_remove("snap3"));
2048 ASSERT_EQ(0, test_ls_snaps(image, 0));
2049 }
2050
2051 ioctx.close();
c07f9fc5
FG
2052}
2053
f67539c2 2054TEST_F(TestLibRBD, TestCreateLsRenameSnapPP)
c07f9fc5 2055{
f67539c2
TL
2056 librados::IoCtx ioctx;
2057 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2058
2059 {
2060 librbd::RBD rbd;
2061 librbd::Image image;
2062 int order = 0;
2063 std::string name = get_temp_image_name();
2064 uint64_t size = 2 << 20;
2065 uint64_t size2 = 4 << 20;
2066
2067 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2068 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2069
2070 bool exists;
2071 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
2072 ASSERT_FALSE(exists);
2073 ASSERT_EQ(0, image.snap_create("snap1"));
2074 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
2075 ASSERT_TRUE(exists);
2076 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
2077 ASSERT_EQ(0, image.resize(size2));
2078 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
2079 ASSERT_FALSE(exists);
2080 ASSERT_EQ(0, image.snap_create("snap2"));
2081 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
2082 ASSERT_TRUE(exists);
2083 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
2084 ASSERT_EQ(0, image.snap_rename("snap1","snap1-rename"));
2085 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1-rename", size, "snap2", size2));
2086 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
2087 ASSERT_FALSE(exists);
2088 ASSERT_EQ(0, image.snap_exists2("snap1-rename", &exists));
2089 ASSERT_TRUE(exists);
2090 ASSERT_EQ(0, image.snap_remove("snap1-rename"));
2091 ASSERT_EQ(0, image.snap_rename("snap2","snap2-rename"));
2092 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2-rename", size2));
2093 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
2094 ASSERT_FALSE(exists);
2095 ASSERT_EQ(0, image.snap_exists2("snap2-rename", &exists));
2096 ASSERT_TRUE(exists);
2097 ASSERT_EQ(0, image.snap_remove("snap2-rename"));
2098 ASSERT_EQ(0, test_ls_snaps(image, 0));
2099 }
c07f9fc5 2100
f67539c2
TL
2101 ioctx.close();
2102}
c07f9fc5 2103
a4b75251
TL
2104TEST_F(TestLibRBD, ConcurrentCreatesUnvalidatedPool)
2105{
2106 rados_ioctx_t ioctx;
2107 ASSERT_EQ(0, rados_ioctx_create(_cluster, create_pool(true).c_str(),
2108 &ioctx));
2109
1e59de90
TL
2110 std::vector<std::string> names;
2111 for (int i = 0; i < 4; i++) {
2112 names.push_back(get_temp_image_name());
2113 }
2114 uint64_t size = 2 << 20;
2115
2116 std::vector<std::thread> threads;
2117 for (const auto& name : names) {
2118 threads.emplace_back([ioctx, &name, size]() {
2119 int order = 0;
2120 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2121 });
2122 }
2123 for (auto& thread : threads) {
2124 thread.join();
2125 }
2126
2127 for (const auto& name : names) {
2128 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
2129 }
2130 rados_ioctx_destroy(ioctx);
2131}
2132
2133static void remove_full_try(rados_ioctx_t ioctx, const std::string& image_name,
2134 const std::string& data_pool_name)
2135{
2136 int order = 0;
2137 uint64_t quota = 10 << 20;
2138 uint64_t size = 5 * quota;
2139 ASSERT_EQ(0, create_image(ioctx, image_name.c_str(), size, &order));
2140
2141 std::string cmdstr = "{\"prefix\": \"osd pool set-quota\", \"pool\": \"" +
2142 data_pool_name + "\", \"field\": \"max_bytes\", \"val\": \"" +
2143 std::to_string(quota) + "\"}";
2144 char *cmd[1];
2145 cmd[0] = (char *)cmdstr.c_str();
2146 ASSERT_EQ(0, rados_mon_command(rados_ioctx_get_cluster(ioctx),
2147 (const char **)cmd, 1, "", 0, nullptr, 0,
2148 nullptr, 0));
2149
2150 rados_set_pool_full_try(ioctx);
2151
2152 rbd_image_t image;
2153 ASSERT_EQ(0, rbd_open(ioctx, image_name.c_str(), &image, nullptr));
2154
2155 uint64_t off;
2156 size_t len = 1 << 20;
2157 ssize_t ret;
2158 for (off = 0; off < size; off += len) {
2159 ret = rbd_write_zeroes(image, off, len,
2160 RBD_WRITE_ZEROES_FLAG_THICK_PROVISION,
2161 LIBRADOS_OP_FLAG_FADVISE_FUA);
2162 if (ret < 0) {
2163 break;
2164 }
2165 ASSERT_EQ(ret, len);
2166 sleep(1);
2167 }
2168 ASSERT_TRUE(off >= quota && off < size);
2169 ASSERT_EQ(ret, -EDQUOT);
2170
2171 ASSERT_EQ(0, rbd_close(image));
2172
2173 // make sure we have latest map that marked the pool full
2174 ASSERT_EQ(0, rados_wait_for_latest_osdmap(rados_ioctx_get_cluster(ioctx)));
2175 ASSERT_EQ(0, rbd_remove(ioctx, image_name.c_str()));
2176}
2177
2178TEST_F(TestLibRBD, RemoveFullTry)
2179{
2180 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2181 REQUIRE(!is_librados_test_stub(_rados));
2182
2183 rados_ioctx_t ioctx;
2184 auto pool_name = create_pool(true);
2185 ASSERT_EQ(0, rados_ioctx_create(_cluster, pool_name.c_str(), &ioctx));
2186 // cancel out rbd_default_data_pool -- we need an image without
2187 // a separate data pool
2188 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_default_data_pool",
2189 pool_name.c_str()));
2190
2191 int order = 0;
2192 auto image_name = get_temp_image_name();
2193 // FIXME: this is a workaround for rbd_trash object being created
2194 // on the first remove -- pre-create it to avoid bumping into quota
2195 ASSERT_EQ(0, create_image(ioctx, image_name.c_str(), 0, &order));
2196 ASSERT_EQ(0, rbd_remove(ioctx, image_name.c_str()));
2197 remove_full_try(ioctx, image_name, pool_name);
2198
2199 rados_ioctx_destroy(ioctx);
2200}
2201
2202TEST_F(TestLibRBD, RemoveFullTryDataPool)
2203{
2204 REQUIRE_FORMAT_V2();
2205 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2206 REQUIRE(!is_librados_test_stub(_rados));
2207
2208 rados_ioctx_t ioctx;
2209 auto pool_name = create_pool(true);
2210 auto data_pool_name = create_pool(true);
2211 ASSERT_EQ(0, rados_ioctx_create(_cluster, pool_name.c_str(), &ioctx));
2212 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_default_data_pool",
2213 data_pool_name.c_str()));
2214
2215 auto image_name = get_temp_image_name();
2216 remove_full_try(ioctx, image_name, data_pool_name);
2217
2218 rados_ioctx_destroy(ioctx);
2219}
2220
2221TEST_F(TestLibRBD, TestIO)
2222{
2223 rados_ioctx_t ioctx;
2224 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2225
2226 rbd_image_t image;
2227 int order = 0;
2228 std::string name = get_temp_image_name();
2229 uint64_t size = 2 << 20;
2230
2231 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2232 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_read_from_replica_policy", "balance"));
2233 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2234
2235 test_io(image);
2236
2237 ASSERT_EQ(0, rbd_close(image));
2238
2239 rados_ioctx_destroy(ioctx);
2240}
2241
2242TEST_F(TestLibRBD, TestEncryptionLUKS1)
2243{
2244 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2245
2246 rados_ioctx_t ioctx;
2247 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2248
2249 int order = 0;
2250 std::string name = get_temp_image_name();
2251 uint64_t size = 32 << 20;
2252
2253 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2254 ASSERT_EQ(0, rados_conf_set(
2255 _cluster, "rbd_read_from_replica_policy", "balance"));
2256
2257 rbd_image_t image;
2258 rbd_encryption_luks1_format_options_t luks1_opts = {
2259 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2260 .passphrase = "password",
2261 .passphrase_size = 8,
2262 };
2263 rbd_encryption_luks2_format_options_t luks2_opts = {
2264 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2265 .passphrase = "password",
2266 .passphrase_size = 8,
2267 };
2268 rbd_encryption_luks_format_options_t luks_opts = {
2269 .passphrase = "password",
2270 .passphrase_size = 8,
2271 };
2272 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2273
2274#ifndef HAVE_LIBCRYPTSETUP
2275 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2276 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2277 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2278 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2279 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2280 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2281 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2282 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2283 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2284 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2285 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2286 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2287#else
2288 ASSERT_EQ(-EINVAL, rbd_encryption_format(
2289 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2290 ASSERT_EQ(0, rbd_encryption_format(
2291 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2292 ASSERT_EQ(-EEXIST, rbd_encryption_load(
2293 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2294
2295 test_io(image);
2296
2297 ASSERT_PASSED(write_test_data, image, "test", 0, 4, 0);
2298 ASSERT_EQ(0, rbd_close(image));
2299
2300 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2301 ASSERT_EQ(-EINVAL, rbd_encryption_load(
2302 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2303 ASSERT_EQ(0, rbd_encryption_load(
2304 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2305 ASSERT_PASSED(read_test_data, image, "test", 0, 4, 0);
2306 ASSERT_EQ(0, rbd_close(image));
2307
2308 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2309 ASSERT_EQ(-EINVAL, rbd_encryption_load(
2310 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2311 ASSERT_EQ(0, rbd_encryption_load(
2312 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2313 ASSERT_PASSED(read_test_data, image, "test", 0, 4, 0);
2314#endif
2315
2316 ASSERT_EQ(0, rbd_close(image));
2317 rados_ioctx_destroy(ioctx);
2318}
2319
2320TEST_F(TestLibRBD, TestEncryptionLUKS2)
2321{
2322 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2323
2324 rados_ioctx_t ioctx;
2325 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2326
2327 int order = 0;
2328 std::string name = get_temp_image_name();
2329 uint64_t size = 32 << 20;
2330
2331 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2332 ASSERT_EQ(0, rados_conf_set(
2333 _cluster, "rbd_read_from_replica_policy", "balance"));
2334
2335 rbd_image_t image;
2336 rbd_encryption_luks1_format_options_t luks1_opts = {
2337 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2338 .passphrase = "password",
2339 .passphrase_size = 8,
2340 };
2341 rbd_encryption_luks2_format_options_t luks2_opts = {
2342 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2343 .passphrase = "password",
2344 .passphrase_size = 8,
2345 };
2346 rbd_encryption_luks_format_options_t luks_opts = {
2347 .passphrase = "password",
2348 .passphrase_size = 8,
2349 };
2350 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2351
2352#ifndef HAVE_LIBCRYPTSETUP
2353 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2354 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2355 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2356 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2357 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2358 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2359 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2360 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2361 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2362 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2363 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2364 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2365#else
2366 ASSERT_EQ(-EINVAL, rbd_encryption_format(
2367 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2368 ASSERT_EQ(0, rbd_encryption_format(
2369 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2370 ASSERT_EQ(-EEXIST, rbd_encryption_load(
2371 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2372
2373 test_io(image);
2374
2375 ASSERT_PASSED(write_test_data, image, "test", 0, 4, 0);
2376 ASSERT_EQ(0, rbd_close(image));
2377
2378 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2379 ASSERT_EQ(-EINVAL, rbd_encryption_load(
2380 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2381 ASSERT_EQ(0, rbd_encryption_load(
2382 image, RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)));
2383 ASSERT_PASSED(read_test_data, image, "test", 0, 4, 0);
2384 ASSERT_EQ(0, rbd_close(image));
2385
2386 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2387 ASSERT_EQ(-EINVAL, rbd_encryption_load(
2388 image, RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)));
2389 ASSERT_EQ(0, rbd_encryption_load(
2390 image, RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)));
2391 ASSERT_PASSED(read_test_data, image, "test", 0, 4, 0);
2392#endif
2393
2394 ASSERT_EQ(0, rbd_close(image));
2395 rados_ioctx_destroy(ioctx);
2396}
2397
2398#ifdef HAVE_LIBCRYPTSETUP
2399
2400TEST_F(TestLibRBD, TestCloneEncryption)
2401{
2402 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2403 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
2404 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2405
2406 rados_ioctx_t ioctx;
2407 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2408 ASSERT_EQ(0, rados_conf_set(
2409 _cluster, "rbd_read_from_replica_policy", "balance"));
2410
2411 // create base image, write 'a's
2412 int order = 0;
2413 std::string name = get_temp_image_name();
2414 uint64_t size = 256 << 20;
2415 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2416
2417 rbd_image_t image;
2418 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2419 ASSERT_PASSED(write_test_data, image, "aaaa", 0, 4, 0);
2420 ASSERT_EQ(0, rbd_flush(image));
2421
2422 // clone, encrypt with LUKS1, write 'b's
2423 ASSERT_EQ(0, rbd_snap_create(image, "snap"));
2424 ASSERT_EQ(0, rbd_snap_protect(image, "snap"));
2425
2426 rbd_image_options_t image_opts;
2427 rbd_image_options_create(&image_opts);
2428 BOOST_SCOPE_EXIT_ALL( (&image_opts) ) {
2429 rbd_image_options_destroy(image_opts);
2430 };
2431 std::string child1_name = get_temp_image_name();
2432 ASSERT_EQ(0, rbd_clone3(ioctx, name.c_str(), "snap", ioctx,
2433 child1_name.c_str(), image_opts));
2434
2435 rbd_image_t child1;
2436 ASSERT_EQ(0, rbd_open(ioctx, child1_name.c_str(), &child1, NULL));
2437
2438 rbd_encryption_luks1_format_options_t child1_opts = {
2439 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2440 .passphrase = "password",
2441 .passphrase_size = 8,
2442 };
2443 ASSERT_EQ(-EINVAL, rbd_encryption_load(
2444 child1, RBD_ENCRYPTION_FORMAT_LUKS1, &child1_opts,
2445 sizeof(child1_opts)));
2446 ASSERT_EQ(0, rbd_encryption_format(
2447 child1, RBD_ENCRYPTION_FORMAT_LUKS1, &child1_opts,
2448 sizeof(child1_opts)));
2449 ASSERT_EQ(0, rbd_encryption_load(
2450 child1, RBD_ENCRYPTION_FORMAT_LUKS1, &child1_opts,
2451 sizeof(child1_opts)));
2452 ASSERT_PASSED(write_test_data, child1, "bbbb", 64 << 20, 4, 0);
2453 ASSERT_EQ(0, rbd_flush(child1));
2454
2455 // clone, encrypt with LUKS2 (same passphrase), write 'c's
2456 ASSERT_EQ(0, rbd_snap_create(child1, "snap"));
2457 ASSERT_EQ(0, rbd_snap_protect(child1, "snap"));
2458
2459 std::string child2_name = get_temp_image_name();
2460 ASSERT_EQ(0, rbd_clone3(ioctx, child1_name.c_str(), "snap", ioctx,
2461 child2_name.c_str(), image_opts));
2462
2463 rbd_image_t child2;
2464 ASSERT_EQ(0, rbd_open(ioctx, child2_name.c_str(), &child2, NULL));
2465
2466 rbd_encryption_luks2_format_options_t child2_opts = {
2467 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2468 .passphrase = "password",
2469 .passphrase_size = 8,
2470 };
2471 ASSERT_EQ(0, rbd_encryption_format(
2472 child2, RBD_ENCRYPTION_FORMAT_LUKS2, &child2_opts,
2473 sizeof(child2_opts)));
2474 rbd_encryption_luks_format_options_t child2_lopts = {
2475 .passphrase = "password",
2476 .passphrase_size = 8,
2477 };
2478 ASSERT_EQ(0, rbd_encryption_load(
2479 child2, RBD_ENCRYPTION_FORMAT_LUKS, &child2_lopts,
2480 sizeof(child2_lopts)));
2481 ASSERT_PASSED(write_test_data, child2, "cccc", 128 << 20, 4, 0);
2482 ASSERT_EQ(0, rbd_flush(child2));
2483
2484 // clone, encrypt with LUKS2 (different passphrase)
2485 ASSERT_EQ(0, rbd_snap_create(child2, "snap"));
2486 ASSERT_EQ(0, rbd_snap_protect(child2, "snap"));
2487
2488 std::string child3_name = get_temp_image_name();
2489 ASSERT_EQ(0, rbd_clone3(ioctx, child2_name.c_str(), "snap", ioctx,
2490 child3_name.c_str(), image_opts));
2491
2492 rbd_image_t child3;
2493 ASSERT_EQ(0, rbd_open(ioctx, child3_name.c_str(), &child3, NULL));
2494
2495 rbd_encryption_luks2_format_options_t child3_opts = {
2496 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2497 .passphrase = "12345678",
2498 .passphrase_size = 8,
2499 };
2500 ASSERT_EQ(0, rbd_encryption_format(
2501 child3, RBD_ENCRYPTION_FORMAT_LUKS2, &child3_opts,
2502 sizeof(child3_opts)));
2503 ASSERT_EQ(-EPERM, rbd_encryption_load(
2504 child3, RBD_ENCRYPTION_FORMAT_LUKS2, &child3_opts,
2505 sizeof(child3_opts)));
2506
2507 // verify child3 data
2508 rbd_encryption_spec_t specs[] = {
2509 { .format = RBD_ENCRYPTION_FORMAT_LUKS2,
2510 .opts = &child3_opts,
2511 .opts_size = sizeof(child3_opts)},
2512 { .format = RBD_ENCRYPTION_FORMAT_LUKS2,
2513 .opts = &child2_opts,
2514 .opts_size = sizeof(child2_opts)},
2515 { .format = RBD_ENCRYPTION_FORMAT_LUKS1,
2516 .opts = &child1_opts,
2517 .opts_size = sizeof(child1_opts)}
2518 };
2519
2520 ASSERT_EQ(0, rbd_encryption_load2(child3, specs, 3));
2521
2522 ASSERT_PASSED(read_test_data, child3, "aaaa", 0, 4, 0);
2523 ASSERT_PASSED(read_test_data, child3, "bbbb", 64 << 20, 4, 0);
2524 ASSERT_PASSED(read_test_data, child3, "cccc", 128 << 20, 4, 0);
2525
2526 // clone without formatting
2527 ASSERT_EQ(0, rbd_snap_create(child3, "snap"));
2528 ASSERT_EQ(0, rbd_snap_protect(child3, "snap"));
2529
2530 std::string child4_name = get_temp_image_name();
2531 ASSERT_EQ(0, rbd_clone3(ioctx, child3_name.c_str(), "snap", ioctx,
2532 child4_name.c_str(), image_opts));
2533
2534 rbd_image_t child4;
2535 ASSERT_EQ(0, rbd_open(ioctx, child4_name.c_str(), &child4, NULL));
2536
2537 rbd_encryption_spec_t child4_specs[] = {
2538 { .format = RBD_ENCRYPTION_FORMAT_LUKS2,
2539 .opts = &child3_opts,
2540 .opts_size = sizeof(child3_opts)},
2541 { .format = RBD_ENCRYPTION_FORMAT_LUKS2,
2542 .opts = &child3_opts,
2543 .opts_size = sizeof(child3_opts)},
2544 { .format = RBD_ENCRYPTION_FORMAT_LUKS2,
2545 .opts = &child2_opts,
2546 .opts_size = sizeof(child2_opts)},
2547 { .format = RBD_ENCRYPTION_FORMAT_LUKS1,
2548 .opts = &child1_opts,
2549 .opts_size = sizeof(child1_opts)}
2550 };
2551
2552 ASSERT_EQ(0, rbd_encryption_load2(child4, child4_specs, 4));
2553
2554 // flatten child4
2555 ASSERT_EQ(0, rbd_flatten(child4));
2556
2557 // reopen child4 and load encryption
2558 ASSERT_EQ(0, rbd_close(child4));
2559 ASSERT_EQ(0, rbd_open(ioctx, child4_name.c_str(), &child4, NULL));
2560 ASSERT_EQ(0, rbd_encryption_load(
2561 child4, RBD_ENCRYPTION_FORMAT_LUKS2, &child3_opts,
2562 sizeof(child3_opts)));
2563
2564 // verify flattend image
2565 ASSERT_PASSED(read_test_data, child4, "aaaa", 0, 4, 0);
2566 ASSERT_PASSED(read_test_data, child4, "bbbb", 64 << 20, 4, 0);
2567 ASSERT_PASSED(read_test_data, child4, "cccc", 128 << 20, 4, 0);
2568
2569 ASSERT_EQ(0, rbd_close(child4));
2570 ASSERT_EQ(0, rbd_remove(ioctx, child4_name.c_str()));
2571 ASSERT_EQ(0, rbd_snap_unprotect(child3, "snap"));
2572 ASSERT_EQ(0, rbd_snap_remove(child3, "snap"));
2573 ASSERT_EQ(0, rbd_close(child3));
2574 ASSERT_EQ(0, rbd_remove(ioctx, child3_name.c_str()));
2575 ASSERT_EQ(0, rbd_snap_unprotect(child2, "snap"));
2576 ASSERT_EQ(0, rbd_snap_remove(child2, "snap"));
2577 ASSERT_EQ(0, rbd_close(child2));
2578 ASSERT_EQ(0, rbd_remove(ioctx, child2_name.c_str()));
2579 ASSERT_EQ(0, rbd_snap_unprotect(child1, "snap"));
2580 ASSERT_EQ(0, rbd_snap_remove(child1, "snap"));
2581 ASSERT_EQ(0, rbd_close(child1));
2582 ASSERT_EQ(0, rbd_remove(ioctx, child1_name.c_str()));
2583 ASSERT_EQ(0, rbd_snap_unprotect(image, "snap"));
2584 ASSERT_EQ(0, rbd_snap_remove(image, "snap"));
2585 ASSERT_EQ(0, rbd_close(image));
2586 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
2587 rados_ioctx_destroy(ioctx);
2588}
2589
2590TEST_F(TestLibRBD, LUKS1UnderLUKS2WithoutResize)
2591{
2592 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2593 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
2594 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2595
2596 librados::IoCtx ioctx;
2597 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2598
2599 librbd::RBD rbd;
2600 std::string parent_name = get_temp_image_name();
2601 std::string clone_name = get_temp_image_name();
2602 uint64_t data_size = 25 << 20;
2603 uint64_t luks1_meta_size = 4 << 20;
2604 uint64_t luks2_meta_size = 16 << 20;
2605 std::string parent_passphrase = "parent passphrase";
2606 std::string clone_passphrase = "clone passphrase";
2607
2608 {
2609 int order = 22;
2610 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(),
2611 luks1_meta_size + data_size, &order));
2612 librbd::Image parent;
2613 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), nullptr));
2614
2615 librbd::encryption_luks1_format_options_t fopts = {
2616 RBD_ENCRYPTION_ALGORITHM_AES256, parent_passphrase};
2617 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
2618 sizeof(fopts)));
2619
2620 ceph::bufferlist bl;
2621 bl.append(std::string(data_size, 'a'));
2622 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
2623
2624 ASSERT_EQ(0, parent.snap_create("snap"));
2625 ASSERT_EQ(0, parent.snap_protect("snap"));
2626 uint64_t features;
2627 ASSERT_EQ(0, parent.features(&features));
2628 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap", ioctx,
2629 clone_name.c_str(), features, &order));
2630 }
2631
2632 {
2633 librbd::Image clone;
2634 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), nullptr));
2635
2636 librbd::encryption_luks2_format_options_t fopts =
2637 {RBD_ENCRYPTION_ALGORITHM_AES256, clone_passphrase};
2638 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
2639 sizeof(fopts)));
2640
2641 librbd::encryption_luks_format_options_t opts1 = {parent_passphrase};
2642 librbd::encryption_luks_format_options_t opts2 = {clone_passphrase};
2643 librbd::encryption_spec_t specs[] = {
2644 {RBD_ENCRYPTION_FORMAT_LUKS, &opts2, sizeof(opts2)},
2645 {RBD_ENCRYPTION_FORMAT_LUKS, &opts1, sizeof(opts1)}};
2646 ASSERT_EQ(0, clone.encryption_load2(specs, std::size(specs)));
2647
2648 uint64_t size;
2649 ASSERT_EQ(0, clone.size(&size));
2650 EXPECT_EQ(data_size + luks1_meta_size - luks2_meta_size, size);
2651 uint64_t overlap;
2652 ASSERT_EQ(0, clone.overlap(&overlap));
2653 EXPECT_EQ(data_size + luks1_meta_size - luks2_meta_size, overlap);
2654
2655 ceph::bufferlist expected_bl;
2656 expected_bl.append(std::string(
2657 data_size + luks1_meta_size - luks2_meta_size, 'a'));
2658
2659 ceph::bufferlist read_bl;
2660 ASSERT_EQ(expected_bl.length(),
2661 clone.read(0, expected_bl.length(), read_bl));
2662 EXPECT_TRUE(expected_bl.contents_equal(read_bl));
2663 }
2664}
2665
2666TEST_F(TestLibRBD, LUKS2UnderLUKS1WithoutResize)
2667{
2668 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2669 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
2670 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2671
2672 librados::IoCtx ioctx;
2673 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2674
2675 librbd::RBD rbd;
2676 std::string parent_name = get_temp_image_name();
2677 std::string clone_name = get_temp_image_name();
2678 uint64_t data_size = 25 << 20;
2679 uint64_t luks1_meta_size = 4 << 20;
2680 uint64_t luks2_meta_size = 16 << 20;
2681 std::string parent_passphrase = "parent passphrase";
2682 std::string clone_passphrase = "clone passphrase";
2683
2684 {
2685 int order = 22;
2686 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(),
2687 luks2_meta_size + data_size, &order));
2688 librbd::Image parent;
2689 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), nullptr));
2690
2691 librbd::encryption_luks2_format_options_t fopts = {
2692 RBD_ENCRYPTION_ALGORITHM_AES256, parent_passphrase};
2693 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
2694 sizeof(fopts)));
2695
2696 ceph::bufferlist bl;
2697 bl.append(std::string(data_size, 'a'));
2698 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
2699
2700 ASSERT_EQ(0, parent.snap_create("snap"));
2701 ASSERT_EQ(0, parent.snap_protect("snap"));
2702 uint64_t features;
2703 ASSERT_EQ(0, parent.features(&features));
2704 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap", ioctx,
2705 clone_name.c_str(), features, &order));
2706 }
2707
2708 {
2709 librbd::Image clone;
2710 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), nullptr));
2711
2712 librbd::encryption_luks1_format_options_t fopts =
2713 {RBD_ENCRYPTION_ALGORITHM_AES256, clone_passphrase};
2714 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
2715 sizeof(fopts)));
2716
2717 librbd::encryption_luks_format_options_t opts1 = {parent_passphrase};
2718 librbd::encryption_luks_format_options_t opts2 = {clone_passphrase};
2719 librbd::encryption_spec_t specs[] = {
2720 {RBD_ENCRYPTION_FORMAT_LUKS, &opts2, sizeof(opts2)},
2721 {RBD_ENCRYPTION_FORMAT_LUKS, &opts1, sizeof(opts1)}};
2722 ASSERT_EQ(0, clone.encryption_load2(specs, std::size(specs)));
2723
2724 uint64_t size;
2725 ASSERT_EQ(0, clone.size(&size));
2726 EXPECT_EQ(data_size + luks2_meta_size - luks1_meta_size, size);
2727 uint64_t overlap;
2728 ASSERT_EQ(0, clone.overlap(&overlap));
2729 EXPECT_EQ(data_size, overlap);
2730
2731 ceph::bufferlist expected_bl;
2732 expected_bl.append(std::string(data_size, 'a'));
2733 expected_bl.append_zero(luks2_meta_size - luks1_meta_size);
2734
2735 ceph::bufferlist read_bl;
2736 ASSERT_EQ(expected_bl.length(),
2737 clone.read(0, expected_bl.length(), read_bl));
2738 EXPECT_TRUE(expected_bl.contents_equal(read_bl));
2739 }
2740}
2741
2742TEST_F(TestLibRBD, EncryptionFormatNoData)
2743{
2744 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2745
2746 librados::IoCtx ioctx;
2747 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2748
2749 librbd::RBD rbd;
2750 auto name = get_temp_image_name();
2751 uint64_t luks1_meta_size = 4 << 20;
2752 std::string passphrase = "some passphrase";
2753
2754 {
2755 int order = 0;
2756 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), luks1_meta_size - 1,
2757 &order));
2758 librbd::Image image;
2759 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
2760
2761 librbd::encryption_luks1_format_options_t opts = {
2762 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
2763 ASSERT_EQ(-ENOSPC, image.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1,
2764 &opts, sizeof(opts)));
2765 uint64_t size;
2766 ASSERT_EQ(0, image.size(&size));
2767 ASSERT_EQ(luks1_meta_size - 1, size);
2768 }
2769
2770 {
2771 librbd::Image image;
2772 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
2773 ASSERT_EQ(0, image.resize(luks1_meta_size));
2774
2775 librbd::encryption_luks1_format_options_t opts = {
2776 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
2777 ASSERT_EQ(0, image.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &opts,
2778 sizeof(opts)));
2779 uint64_t size;
2780 ASSERT_EQ(0, image.size(&size));
2781 ASSERT_EQ(0, size);
2782 }
2783}
2784
2785TEST_F(TestLibRBD, EncryptionLoadBadSize)
2786{
2787 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2788
2789 librados::IoCtx ioctx;
2790 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2791
2792 librbd::RBD rbd;
2793 auto name = get_temp_image_name();
2794 uint64_t luks1_meta_size = 4 << 20;
2795 std::string passphrase = "some passphrase";
2796
2797 {
2798 int order = 0;
2799 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), luks1_meta_size,
2800 &order));
2801 librbd::Image image;
2802 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
2803
2804 librbd::encryption_luks1_format_options_t opts = {
2805 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
2806 ASSERT_EQ(0, image.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &opts,
2807 sizeof(opts)));
2808 }
2809
2810 {
2811 librbd::Image image;
2812 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
2813
2814 librbd::encryption_luks_format_options_t opts = {passphrase};
2815 ASSERT_EQ(0, image.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
2816 sizeof(opts)));
2817 uint64_t size;
2818 ASSERT_EQ(0, image.size(&size));
2819 ASSERT_EQ(0, size);
2820 }
2821
2822 {
2823 librbd::Image image;
2824 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
2825 ASSERT_EQ(0, image.resize(luks1_meta_size - 1));
2826
2827 librbd::encryption_luks_format_options_t opts = {passphrase};
2828 ASSERT_EQ(-EINVAL, image.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
2829 sizeof(opts)));
2830 uint64_t size;
2831 ASSERT_EQ(0, image.size(&size));
2832 ASSERT_EQ(luks1_meta_size - 1, size);
2833 }
2834}
2835
2836TEST_F(TestLibRBD, EncryptionLoadBadStripePattern)
2837{
2838 REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2);
2839 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2840
2841 librados::IoCtx ioctx;
2842 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2843
2844 bool old_format;
2845 uint64_t features;
2846 ASSERT_EQ(0, get_features(&old_format, &features));
2847 ASSERT_FALSE(old_format);
2848
2849 librbd::RBD rbd;
2850 auto name1 = get_temp_image_name();
2851 auto name2 = get_temp_image_name();
2852 auto name3 = get_temp_image_name();
2853 std::string passphrase = "some passphrase";
2854
2855 {
2856 int order = 22;
2857 ASSERT_EQ(0, rbd.create3(ioctx, name1.c_str(), 20 << 20, features, &order,
2858 2 << 20, 2));
2859 librbd::Image image;
2860 ASSERT_EQ(0, rbd.open(ioctx, image, name1.c_str(), nullptr));
2861
2862 librbd::encryption_luks1_format_options_t opts = {
2863 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
2864 ASSERT_EQ(0, image.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &opts,
2865 sizeof(opts)));
2866 uint64_t size;
2867 ASSERT_EQ(0, image.size(&size));
2868 ASSERT_EQ(12 << 20, size);
2869 }
2870
2871 {
2872 librbd::Image image;
2873 ASSERT_EQ(0, rbd.open(ioctx, image, name1.c_str(), nullptr));
2874
2875 // different but compatible striping pattern
2876 librbd::ImageOptions image_opts;
2877 ASSERT_EQ(0, image_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, 1 << 20));
2878 ASSERT_EQ(0, image_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, 2));
2879 ASSERT_EQ(0, image.deep_copy(ioctx, name2.c_str(), image_opts));
2880 }
2881 {
2882 librbd::Image image;
2883 ASSERT_EQ(0, rbd.open(ioctx, image, name2.c_str(), nullptr));
2884
2885 librbd::encryption_luks_format_options_t opts = {passphrase};
2886 ASSERT_EQ(0, image.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
2887 sizeof(opts)));
2888 uint64_t size;
2889 ASSERT_EQ(0, image.size(&size));
2890 ASSERT_EQ(12 << 20, size);
2891 }
2892
2893 {
2894 librbd::Image image;
2895 ASSERT_EQ(0, rbd.open(ioctx, image, name1.c_str(), nullptr));
2896
2897 // incompatible striping pattern
2898 librbd::ImageOptions image_opts;
2899 ASSERT_EQ(0, image_opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, 1 << 20));
2900 ASSERT_EQ(0, image_opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, 3));
2901 ASSERT_EQ(0, image.deep_copy(ioctx, name3.c_str(), image_opts));
2902 }
2903 {
2904 librbd::Image image;
2905 ASSERT_EQ(0, rbd.open(ioctx, image, name3.c_str(), nullptr));
2906
2907 librbd::encryption_luks_format_options_t opts = {passphrase};
2908 ASSERT_EQ(-EINVAL, image.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
2909 sizeof(opts)));
2910 uint64_t size;
2911 ASSERT_EQ(0, image.size(&size));
2912 ASSERT_EQ(20 << 20, size);
2913 }
2914}
2915
2916TEST_F(TestLibRBD, EncryptionLoadFormatMismatch)
2917{
2918 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2919 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
2920
2921 librados::IoCtx ioctx;
2922 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2923
2924 librbd::RBD rbd;
2925 std::string name1 = get_temp_image_name();
2926 std::string name2 = get_temp_image_name();
2927 std::string name3 = get_temp_image_name();
2928 std::string passphrase = "some passphrase";
2929
2930 librbd::encryption_luks1_format_options_t luks1_opts = {
2931 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
2932 librbd::encryption_luks2_format_options_t luks2_opts = {
2933 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
2934 librbd::encryption_luks_format_options_t luks_opts = {passphrase};
2935
2936#define LUKS_ONE {RBD_ENCRYPTION_FORMAT_LUKS1, &luks1_opts, sizeof(luks1_opts)}
2937#define LUKS_TWO {RBD_ENCRYPTION_FORMAT_LUKS2, &luks2_opts, sizeof(luks2_opts)}
2938#define LUKS_ANY {RBD_ENCRYPTION_FORMAT_LUKS, &luks_opts, sizeof(luks_opts)}
2939
2940 const std::vector<librbd::encryption_spec_t> bad_specs[] = {
2941 {},
2942 {LUKS_ONE},
2943 {LUKS_TWO},
2944 {LUKS_ONE, LUKS_ONE},
2945 {LUKS_ONE, LUKS_TWO},
2946 {LUKS_ONE, LUKS_ANY},
2947 {LUKS_TWO, LUKS_TWO},
2948 {LUKS_ANY, LUKS_TWO},
2949 {LUKS_ONE, LUKS_ONE, LUKS_ONE},
2950 {LUKS_ONE, LUKS_ONE, LUKS_TWO},
2951 {LUKS_ONE, LUKS_ONE, LUKS_ANY},
2952 {LUKS_ONE, LUKS_TWO, LUKS_ONE},
2953 {LUKS_ONE, LUKS_TWO, LUKS_TWO},
2954 {LUKS_ONE, LUKS_TWO, LUKS_ANY},
2955 {LUKS_ONE, LUKS_ANY, LUKS_ONE},
2956 {LUKS_ONE, LUKS_ANY, LUKS_TWO},
2957 {LUKS_ONE, LUKS_ANY, LUKS_ANY},
2958 {LUKS_TWO, LUKS_ONE, LUKS_TWO},
2959 {LUKS_TWO, LUKS_TWO, LUKS_ONE},
2960 {LUKS_TWO, LUKS_TWO, LUKS_TWO},
2961 {LUKS_TWO, LUKS_TWO, LUKS_ANY},
2962 {LUKS_TWO, LUKS_ANY, LUKS_TWO},
2963 {LUKS_ANY, LUKS_ONE, LUKS_TWO},
2964 {LUKS_ANY, LUKS_TWO, LUKS_ONE},
2965 {LUKS_ANY, LUKS_TWO, LUKS_TWO},
2966 {LUKS_ANY, LUKS_TWO, LUKS_ANY},
2967 {LUKS_ANY, LUKS_ANY, LUKS_TWO},
2968 {LUKS_ANY, LUKS_ANY, LUKS_ANY, LUKS_ANY}};
2969
2970 const std::vector<librbd::encryption_spec_t> good_specs[] = {
2971 {LUKS_ANY},
2972 {LUKS_TWO, LUKS_ONE},
2973 {LUKS_TWO, LUKS_ANY},
2974 {LUKS_ANY, LUKS_ONE},
2975 {LUKS_ANY, LUKS_ANY},
2976 {LUKS_TWO, LUKS_ONE, LUKS_ONE},
2977 {LUKS_TWO, LUKS_ONE, LUKS_ANY},
2978 {LUKS_TWO, LUKS_ANY, LUKS_ONE},
2979 {LUKS_TWO, LUKS_ANY, LUKS_ANY},
2980 {LUKS_ANY, LUKS_ONE, LUKS_ONE},
2981 {LUKS_ANY, LUKS_ONE, LUKS_ANY},
2982 {LUKS_ANY, LUKS_ANY, LUKS_ONE},
2983 {LUKS_ANY, LUKS_ANY, LUKS_ANY}};
2984
2985 static_assert(std::size(bad_specs) + std::size(good_specs) == 1 + 3 + 9 + 27 + 1);
2986
2987#undef LUKS_ONE
2988#undef LUKS_TWO
2989#undef LUKS_ANY
2990
2991 {
2992 int order = 0;
2993 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name1.c_str(), 20 << 20, &order));
2994 librbd::Image image1;
2995 ASSERT_EQ(0, rbd.open(ioctx, image1, name1.c_str(), nullptr));
2996 ASSERT_EQ(0, image1.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1,
2997 &luks1_opts, sizeof(luks1_opts)));
2998
2999 ASSERT_EQ(0, image1.snap_create("snap"));
3000 ASSERT_EQ(0, image1.snap_protect("snap"));
3001 uint64_t features;
3002 ASSERT_EQ(0, image1.features(&features));
3003 ASSERT_EQ(0, rbd.clone(ioctx, name1.c_str(), "snap", ioctx, name2.c_str(),
3004 features, &order));
3005
3006 librbd::Image image2;
3007 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), nullptr));
3008 ASSERT_EQ(0, image2.snap_create("snap"));
3009 ASSERT_EQ(0, image2.snap_protect("snap"));
3010 ASSERT_EQ(0, rbd.clone(ioctx, name2.c_str(), "snap", ioctx, name3.c_str(),
3011 features, &order));
3012
3013 librbd::Image image3;
3014 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), nullptr));
3015 ASSERT_EQ(0, image3.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2,
3016 &luks2_opts, sizeof(luks2_opts)));
3017 }
3018
3019 {
3020 librbd::Image image3;
3021 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), nullptr));
3022 for (auto& specs : bad_specs) {
3023 ASSERT_EQ(-EINVAL, image3.encryption_load2(specs.data(), specs.size()));
3024 }
3025 }
3026
3027 for (auto& specs : good_specs) {
3028 librbd::Image image3;
3029 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), nullptr));
3030 ASSERT_EQ(0, image3.encryption_load2(specs.data(), specs.size()));
3031 }
3032}
3033
3034TEST_F(TestLibRBD, EncryptedResize)
3035{
3036 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
3037
3038 librados::IoCtx ioctx;
3039 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3040
3041 librbd::RBD rbd;
3042 auto name = get_temp_image_name();
3043 uint64_t luks2_meta_size = 16 << 20;
3044 uint64_t data_size = 10 << 20;
3045 std::string passphrase = "some passphrase";
3046
3047 {
3048 int order = 0;
3049 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(),
3050 luks2_meta_size + data_size, &order));
3051 librbd::Image image;
3052 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
3053
3054 uint64_t size;
3055 ASSERT_EQ(0, image.size(&size));
3056 ASSERT_EQ(luks2_meta_size + data_size, size);
3057
3058 librbd::encryption_luks2_format_options_t opts = {
3059 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
3060 ASSERT_EQ(0, image.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &opts,
3061 sizeof(opts)));
3062 ASSERT_EQ(0, image.size(&size));
3063 ASSERT_EQ(data_size, size);
3064 ASSERT_EQ(0, image.resize(data_size * 3));
3065 ASSERT_EQ(0, image.size(&size));
3066 ASSERT_EQ(data_size * 3, size);
3067 }
3068
3069 {
3070 librbd::Image image;
3071 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
3072
3073 uint64_t size;
3074 ASSERT_EQ(0, image.size(&size));
3075 ASSERT_EQ(luks2_meta_size + data_size * 3, size);
3076
3077 librbd::encryption_luks_format_options_t opts = {passphrase};
3078 ASSERT_EQ(0, image.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
3079 sizeof(opts)));
3080 ASSERT_EQ(0, image.size(&size));
3081 ASSERT_EQ(data_size * 3, size);
3082 ASSERT_EQ(0, image.resize(data_size / 2));
3083 ASSERT_EQ(0, image.size(&size));
3084 ASSERT_EQ(data_size / 2, size);
3085 }
3086
3087 {
3088 librbd::Image image;
3089 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
3090
3091 uint64_t size;
3092 ASSERT_EQ(0, image.size(&size));
3093 ASSERT_EQ(luks2_meta_size + data_size / 2, size);
3094
3095 librbd::encryption_luks_format_options_t opts = {passphrase};
3096 ASSERT_EQ(0, image.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
3097 sizeof(opts)));
3098 ASSERT_EQ(0, image.size(&size));
3099 ASSERT_EQ(data_size / 2, size);
3100 ASSERT_EQ(0, image.resize(0));
3101 ASSERT_EQ(0, image.size(&size));
3102 ASSERT_EQ(0, size);
3103 }
3104
3105 {
3106 librbd::Image image;
3107 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
3108
3109 uint64_t size;
3110 ASSERT_EQ(0, image.size(&size));
3111 ASSERT_EQ(luks2_meta_size, size);
3112
3113 librbd::encryption_luks_format_options_t opts = {passphrase};
3114 ASSERT_EQ(0, image.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
3115 sizeof(opts)));
3116 ASSERT_EQ(0, image.size(&size));
3117 ASSERT_EQ(0, size);
3118 ASSERT_EQ(0, image.resize(data_size));
3119 ASSERT_EQ(0, image.size(&size));
3120 ASSERT_EQ(data_size, size);
3121 }
3122
3123 {
3124 librbd::Image image;
3125 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
3126
3127 uint64_t size;
3128 ASSERT_EQ(0, image.size(&size));
3129 ASSERT_EQ(luks2_meta_size + data_size, size);
3130 }
3131}
3132
3133TEST_F(TestLibRBD, EncryptedFlattenSmallData)
3134{
3135 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3136 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
3137 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
3138
3139 librados::IoCtx ioctx;
3140 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3141
3142 librbd::RBD rbd;
3143 std::string parent_name = get_temp_image_name();
3144 std::string clone_name = get_temp_image_name();
3145 uint64_t data_size = 5000;
3146 uint64_t luks2_meta_size = 16 << 20;
3147 std::string passphrase = "some passphrase";
3148
3149 {
3150 int order = 22;
3151 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(),
3152 luks2_meta_size + data_size, &order));
3153 librbd::Image parent;
3154 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), nullptr));
3155
3156 librbd::encryption_luks2_format_options_t opts = {
3157 RBD_ENCRYPTION_ALGORITHM_AES256, passphrase};
3158 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &opts,
3159 sizeof(opts)));
3160
3161 ceph::bufferlist bl;
3162 bl.append(std::string(data_size, 'a'));
3163 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3164
3165 ASSERT_EQ(0, parent.snap_create("snap"));
3166 ASSERT_EQ(0, parent.snap_protect("snap"));
3167 uint64_t features;
3168 ASSERT_EQ(0, parent.features(&features));
3169 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap", ioctx,
3170 clone_name.c_str(), features, &order));
3171 }
3172
3173 {
3174 librbd::Image clone;
3175 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), nullptr));
3176
3177 librbd::encryption_luks_format_options_t opts = {passphrase};
3178 ASSERT_EQ(0, clone.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
3179 sizeof(opts)));
3180 uint64_t size;
3181 ASSERT_EQ(0, clone.size(&size));
3182 ASSERT_EQ(data_size, size);
3183 uint64_t overlap;
3184 ASSERT_EQ(0, clone.overlap(&overlap));
3185 ASSERT_EQ(data_size, overlap);
3186
3187 ceph::bufferlist expected_bl;
3188 expected_bl.append(std::string(data_size, 'a'));
3189
3190 ceph::bufferlist read_bl1;
3191 ASSERT_EQ(data_size, clone.read(0, data_size, read_bl1));
3192 ASSERT_TRUE(expected_bl.contents_equal(read_bl1));
3193
3194 ASSERT_EQ(0, clone.flatten());
3195
3196 ceph::bufferlist read_bl2;
3197 ASSERT_EQ(data_size, clone.read(0, data_size, read_bl2));
3198 ASSERT_TRUE(expected_bl.contents_equal(read_bl2));
3199 }
3200
3201 {
3202 librbd::Image clone;
3203 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), nullptr));
3204
3205 librbd::encryption_luks_format_options_t opts = {passphrase};
3206 ASSERT_EQ(0, clone.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
3207 sizeof(opts)));
3208 uint64_t size;
3209 ASSERT_EQ(0, clone.size(&size));
3210 ASSERT_EQ(data_size, size);
3211 uint64_t overlap;
3212 ASSERT_EQ(0, clone.overlap(&overlap));
3213 ASSERT_EQ(0, overlap);
3214
3215 ceph::bufferlist expected_bl;
3216 expected_bl.append(std::string(data_size, 'a'));
3217
3218 ceph::bufferlist read_bl;
3219 ASSERT_EQ(data_size, clone.read(0, data_size, read_bl));
3220 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
3221 }
3222}
3223
3224struct LUKSOnePassphrase {
3225 int load(librbd::Image& clone) {
3226 librbd::encryption_luks_format_options_t opts = {m_passphrase};
3227 return clone.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
3228 sizeof(opts));
3229 }
3230
3231 int load_flattened(librbd::Image& clone) {
3232 return load(clone);
3233 }
3234
3235 std::string m_passphrase = "some passphrase";
3236};
3237
3238struct LUKSTwoPassphrases {
3239 int load(librbd::Image& clone) {
3240 librbd::encryption_luks_format_options_t opts1 = {m_parent_passphrase};
3241 librbd::encryption_luks_format_options_t opts2 = {m_clone_passphrase};
3242 librbd::encryption_spec_t specs[] = {
3243 {RBD_ENCRYPTION_FORMAT_LUKS, &opts2, sizeof(opts2)},
3244 {RBD_ENCRYPTION_FORMAT_LUKS, &opts1, sizeof(opts1)}};
3245 return clone.encryption_load2(specs, std::size(specs));
3246 }
3247
3248 int load_flattened(librbd::Image& clone) {
3249 librbd::encryption_luks_format_options_t opts = {m_clone_passphrase};
3250 return clone.encryption_load(RBD_ENCRYPTION_FORMAT_LUKS, &opts,
3251 sizeof(opts));
3252 }
3253
3254 std::string m_parent_passphrase = "parent passphrase";
3255 std::string m_clone_passphrase = "clone passphrase";
3256};
3257
3258struct PlaintextUnderLUKS1 : LUKSOnePassphrase {
3259protected:
3260 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3261 ceph::bufferlist bl;
3262 bl.append(std::string(data_size, 'a'));
3263 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3264
3265 // before taking a parent snapshot, (temporarily) add extra space
3266 // to the parent to account for upcoming LUKS1 header in the clone,
3267 // making the clone able to reach all parent data
3268 uint64_t luks1_meta_size = 4 << 20;
3269 ASSERT_EQ(0, parent.resize(data_size + luks1_meta_size));
3270 *passed = true;
3271 }
3272
3273 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3274 librbd::encryption_luks1_format_options_t fopts =
3275 {RBD_ENCRYPTION_ALGORITHM_AES256, m_passphrase};
3276 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
3277 sizeof(fopts)));
3278 *passed = true;
3279 }
3280};
3281
3282struct PlaintextUnderLUKS2 : LUKSOnePassphrase {
3283 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3284 ceph::bufferlist bl;
3285 bl.append(std::string(data_size, 'a'));
3286 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3287
3288 // before taking a parent snapshot, (temporarily) add extra space
3289 // to the parent to account for upcoming LUKS2 header in the clone,
3290 // making the clone able to reach all parent data
3291 uint64_t luks2_meta_size = 16 << 20;
3292 ASSERT_EQ(0, parent.resize(data_size + luks2_meta_size));
3293 *passed = true;
3294 }
3295
3296 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3297 librbd::encryption_luks2_format_options_t fopts =
3298 {RBD_ENCRYPTION_ALGORITHM_AES256, m_passphrase};
3299 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
3300 sizeof(fopts)));
3301 *passed = true;
3302 }
3303};
3304
3305struct UnformattedLUKS1 : LUKSOnePassphrase {
3306 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3307 uint64_t luks1_meta_size = 4 << 20;
3308 ASSERT_EQ(0, parent.resize(data_size + luks1_meta_size));
3309 librbd::encryption_luks1_format_options_t fopts = {
3310 RBD_ENCRYPTION_ALGORITHM_AES256, m_passphrase};
3311 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
3312 sizeof(fopts)));
3313
3314 ceph::bufferlist bl;
3315 bl.append(std::string(data_size, 'a'));
3316 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3317 *passed = true;
3318 }
3319
3320 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3321 *passed = true;
3322 }
3323};
3324
3325struct LUKS1UnderLUKS1 : LUKSTwoPassphrases {
3326 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3327 uint64_t luks1_meta_size = 4 << 20;
3328 ASSERT_EQ(0, parent.resize(data_size + luks1_meta_size));
3329 librbd::encryption_luks1_format_options_t fopts = {
3330 RBD_ENCRYPTION_ALGORITHM_AES256, m_parent_passphrase};
3331 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
3332 sizeof(fopts)));
3333
3334 ceph::bufferlist bl;
3335 bl.append(std::string(data_size, 'a'));
3336 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3337 *passed = true;
3338 }
3339
3340 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3341 librbd::encryption_luks1_format_options_t fopts =
3342 {RBD_ENCRYPTION_ALGORITHM_AES256, m_clone_passphrase};
3343 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
3344 sizeof(fopts)));
3345 *passed = true;
3346 }
3347};
3348
3349struct LUKS1UnderLUKS2 : LUKSTwoPassphrases {
3350 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3351 uint64_t luks1_meta_size = 4 << 20;
3352 ASSERT_EQ(0, parent.resize(data_size + luks1_meta_size));
3353 librbd::encryption_luks1_format_options_t fopts = {
3354 RBD_ENCRYPTION_ALGORITHM_AES256, m_parent_passphrase};
3355 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
3356 sizeof(fopts)));
3357
3358 ceph::bufferlist bl;
3359 bl.append(std::string(data_size, 'a'));
3360 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3361
3362 // before taking a parent snapshot, (temporarily) add extra space
3363 // to the parent to account for upcoming LUKS2 header in the clone,
3364 // making the clone able to reach all parent data
3365 // space taken by LUKS1 header in the parent would be reused
3366 uint64_t luks2_meta_size = 16 << 20;
3367 ASSERT_EQ(0, parent.resize(data_size + luks2_meta_size - luks1_meta_size));
3368 *passed = true;
3369 }
3370
3371 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3372 librbd::encryption_luks2_format_options_t fopts =
3373 {RBD_ENCRYPTION_ALGORITHM_AES256, m_clone_passphrase};
3374 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
3375 sizeof(fopts)));
3376 *passed = true;
3377 }
3378};
3379
3380struct UnformattedLUKS2 : LUKSOnePassphrase {
3381 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3382 uint64_t luks2_meta_size = 16 << 20;
3383 ASSERT_EQ(0, parent.resize(data_size + luks2_meta_size));
3384 librbd::encryption_luks2_format_options_t fopts = {
3385 RBD_ENCRYPTION_ALGORITHM_AES256, m_passphrase};
3386 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
3387 sizeof(fopts)));
3388
3389 ceph::bufferlist bl;
3390 bl.append(std::string(data_size, 'a'));
3391 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3392 *passed = true;
3393 }
3394
3395 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3396 *passed = true;
3397 }
3398};
3399
3400struct LUKS2UnderLUKS2 : LUKSTwoPassphrases {
3401 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3402 uint64_t luks2_meta_size = 16 << 20;
3403 ASSERT_EQ(0, parent.resize(data_size + luks2_meta_size));
3404 librbd::encryption_luks2_format_options_t fopts = {
3405 RBD_ENCRYPTION_ALGORITHM_AES256, m_parent_passphrase};
3406 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
3407 sizeof(fopts)));
3408
3409 ceph::bufferlist bl;
3410 bl.append(std::string(data_size, 'a'));
3411 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3412 *passed = true;
a4b75251 3413 }
a4b75251 3414
1e59de90
TL
3415 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3416 librbd::encryption_luks2_format_options_t fopts =
3417 {RBD_ENCRYPTION_ALGORITHM_AES256, m_clone_passphrase};
3418 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
3419 sizeof(fopts)));
3420 *passed = true;
a4b75251 3421 }
1e59de90
TL
3422};
3423
3424struct LUKS2UnderLUKS1 : LUKSTwoPassphrases {
3425 void setup_parent(librbd::Image& parent, uint64_t data_size, bool* passed) {
3426 uint64_t luks2_meta_size = 16 << 20;
3427 ASSERT_EQ(0, parent.resize(data_size + luks2_meta_size));
3428 librbd::encryption_luks2_format_options_t fopts = {
3429 RBD_ENCRYPTION_ALGORITHM_AES256, m_parent_passphrase};
3430 ASSERT_EQ(0, parent.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS2, &fopts,
3431 sizeof(fopts)));
3432
3433 ceph::bufferlist bl;
3434 bl.append(std::string(data_size, 'a'));
3435 ASSERT_EQ(data_size, parent.write(0, data_size, bl));
3436 *passed = true;
a4b75251
TL
3437 }
3438
1e59de90
TL
3439 void setup_clone(librbd::Image& clone, uint64_t data_size, bool* passed) {
3440 librbd::encryption_luks1_format_options_t fopts =
3441 {RBD_ENCRYPTION_ALGORITHM_AES256, m_clone_passphrase};
3442 ASSERT_EQ(0, clone.encryption_format(RBD_ENCRYPTION_FORMAT_LUKS1, &fopts,
3443 sizeof(fopts)));
3444
3445 // after loading encryption on the clone, one can get rid of
3446 // unneeded space allowance in the clone arising from LUKS2 header
3447 // in the parent being bigger than LUKS1 header in the clone
3448 ASSERT_EQ(0, load(clone));
3449 ASSERT_EQ(0, clone.resize(data_size));
3450 *passed = true;
a4b75251 3451 }
1e59de90 3452};
a4b75251 3453
1e59de90
TL
3454template <typename FormatPolicy>
3455class EncryptedFlattenTest : public TestLibRBD, FormatPolicy {
3456protected:
3457 void create_and_setup(bool* passed) {
3458 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), m_ioctx));
20effc67 3459
1e59de90
TL
3460 int order = 22;
3461 ASSERT_EQ(0, create_image_pp(m_rbd, m_ioctx, m_parent_name.c_str(),
3462 m_data_size, &order));
3463 librbd::Image parent;
3464 ASSERT_EQ(0, m_rbd.open(m_ioctx, parent, m_parent_name.c_str(), nullptr));
3465 ASSERT_PASSED(FormatPolicy::setup_parent, parent, m_data_size);
20effc67 3466
1e59de90
TL
3467 ASSERT_EQ(0, parent.snap_create("snap"));
3468 ASSERT_EQ(0, parent.snap_protect("snap"));
3469 uint64_t features;
3470 ASSERT_EQ(0, parent.features(&features));
3471 ASSERT_EQ(0, m_rbd.clone(m_ioctx, m_parent_name.c_str(), "snap", m_ioctx,
3472 m_clone_name.c_str(), features, &order));
3473 librbd::Image clone;
3474 ASSERT_EQ(0, m_rbd.open(m_ioctx, clone, m_clone_name.c_str(), nullptr));
3475 ASSERT_PASSED(FormatPolicy::setup_clone, clone, m_data_size);
20effc67 3476
1e59de90
TL
3477 *passed = true;
3478 }
20effc67 3479
1e59de90
TL
3480 void open_and_load(librbd::Image& clone, bool* passed) {
3481 ASSERT_EQ(0, m_rbd.open(m_ioctx, clone, m_clone_name.c_str(), nullptr));
3482 ASSERT_EQ(0, FormatPolicy::load(clone));
3483 *passed = true;
20effc67 3484 }
20effc67 3485
1e59de90
TL
3486 void open_and_load_flattened(librbd::Image& clone, bool* passed) {
3487 ASSERT_EQ(0, m_rbd.open(m_ioctx, clone, m_clone_name.c_str(), nullptr));
3488 ASSERT_EQ(0, FormatPolicy::load_flattened(clone));
3489 *passed = true;
3490 }
20effc67 3491
1e59de90
TL
3492 void verify_size_and_overlap(librbd::Image& image, uint64_t expected_size,
3493 uint64_t expected_overlap) {
3494 uint64_t size;
3495 ASSERT_EQ(0, image.size(&size));
3496 EXPECT_EQ(expected_size, size);
3497 uint64_t overlap;
3498 ASSERT_EQ(0, image.overlap(&overlap));
3499 EXPECT_EQ(expected_overlap, overlap);
3500 }
20effc67 3501
1e59de90
TL
3502 void verify_data(librbd::Image& image, const ceph::bufferlist& expected_bl) {
3503 ceph::bufferlist read_bl;
3504 ASSERT_EQ(expected_bl.length(),
3505 image.read(0, expected_bl.length(), read_bl));
3506 EXPECT_TRUE(expected_bl.contents_equal(read_bl));
3507 }
3508
3509 librados::IoCtx m_ioctx;
3510 librbd::RBD m_rbd;
3511 std::string m_parent_name = get_temp_image_name();
3512 std::string m_clone_name = get_temp_image_name();
3513 uint64_t m_data_size = 25 << 20;
3514};
3515
3516using EncryptedFlattenTestTypes =
3517 ::testing::Types<PlaintextUnderLUKS1, PlaintextUnderLUKS2,
3518 UnformattedLUKS1, LUKS1UnderLUKS1, LUKS1UnderLUKS2,
3519 UnformattedLUKS2, LUKS2UnderLUKS2, LUKS2UnderLUKS1>;
3520TYPED_TEST_SUITE(EncryptedFlattenTest, EncryptedFlattenTestTypes);
3521
3522TYPED_TEST(EncryptedFlattenTest, Simple)
20effc67 3523{
1e59de90
TL
3524 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3525 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
3526 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
20effc67 3527
1e59de90 3528 ASSERT_PASSED0(this->create_and_setup);
20effc67 3529
1e59de90
TL
3530 ceph::bufferlist expected_bl;
3531 expected_bl.append(std::string(this->m_data_size, 'a'));
20effc67 3532
1e59de90
TL
3533 {
3534 librbd::Image clone;
3535 ASSERT_PASSED(this->open_and_load, clone);
3536 this->verify_size_and_overlap(clone, this->m_data_size, this->m_data_size);
3537 this->verify_data(clone, expected_bl);
3538 ASSERT_EQ(0, clone.flatten());
3539 this->verify_data(clone, expected_bl);
3540 }
3541
3542 {
3543 librbd::Image clone;
3544 ASSERT_PASSED(this->open_and_load_flattened, clone);
3545 this->verify_size_and_overlap(clone, this->m_data_size, 0);
3546 this->verify_data(clone, expected_bl);
3547 }
20effc67
TL
3548}
3549
1e59de90 3550TYPED_TEST(EncryptedFlattenTest, Grow)
20effc67 3551{
1e59de90
TL
3552 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3553 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
3554 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
20effc67 3555
1e59de90 3556 ASSERT_PASSED0(this->create_and_setup);
20effc67 3557
1e59de90
TL
3558 ceph::bufferlist expected_bl;
3559 expected_bl.append(std::string(this->m_data_size, 'a'));
3560 expected_bl.append_zero(1);
20effc67 3561
1e59de90
TL
3562 {
3563 librbd::Image clone;
3564 ASSERT_PASSED(this->open_and_load, clone);
3565 ASSERT_EQ(0, clone.resize(this->m_data_size + 1));
3566 this->verify_size_and_overlap(clone, this->m_data_size + 1,
3567 this->m_data_size);
3568 this->verify_data(clone, expected_bl);
3569 ASSERT_EQ(0, clone.flatten());
3570 this->verify_data(clone, expected_bl);
3571 }
3572
3573 {
3574 librbd::Image clone;
3575 ASSERT_PASSED(this->open_and_load_flattened, clone);
3576 this->verify_size_and_overlap(clone, this->m_data_size + 1, 0);
3577 this->verify_data(clone, expected_bl);
3578 }
20effc67
TL
3579}
3580
1e59de90 3581TYPED_TEST(EncryptedFlattenTest, Shrink)
7c673cae 3582{
1e59de90
TL
3583 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3584 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
3585 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
7c673cae 3586
1e59de90 3587 ASSERT_PASSED0(this->create_and_setup);
7c673cae 3588
1e59de90
TL
3589 ceph::bufferlist expected_bl;
3590 expected_bl.append(std::string(this->m_data_size - 1, 'a'));
7c673cae 3591
1e59de90
TL
3592 {
3593 librbd::Image clone;
3594 ASSERT_PASSED(this->open_and_load, clone);
3595 ASSERT_EQ(0, clone.resize(this->m_data_size - 1));
3596 this->verify_size_and_overlap(clone, this->m_data_size - 1,
3597 this->m_data_size - 1);
3598 this->verify_data(clone, expected_bl);
3599 ASSERT_EQ(0, clone.flatten());
3600 this->verify_data(clone, expected_bl);
3601 }
7c673cae 3602
1e59de90
TL
3603 {
3604 librbd::Image clone;
3605 ASSERT_PASSED(this->open_and_load_flattened, clone);
3606 this->verify_size_and_overlap(clone, this->m_data_size - 1, 0);
3607 this->verify_data(clone, expected_bl);
3608 }
f67539c2 3609}
7c673cae 3610
1e59de90 3611TYPED_TEST(EncryptedFlattenTest, ShrinkToOne)
f67539c2 3612{
1e59de90
TL
3613 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3614 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
f67539c2 3615 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
c07f9fc5 3616
1e59de90 3617 ASSERT_PASSED0(this->create_and_setup);
c07f9fc5 3618
1e59de90
TL
3619 ceph::bufferlist expected_bl;
3620 expected_bl.append(std::string(1, 'a'));
7c673cae 3621
1e59de90
TL
3622 {
3623 librbd::Image clone;
3624 ASSERT_PASSED(this->open_and_load, clone);
3625 ASSERT_EQ(0, clone.resize(1));
3626 this->verify_size_and_overlap(clone, 1, 1);
3627 this->verify_data(clone, expected_bl);
3628 ASSERT_EQ(0, clone.flatten());
3629 this->verify_data(clone, expected_bl);
3630 }
7c673cae 3631
1e59de90
TL
3632 {
3633 librbd::Image clone;
3634 ASSERT_PASSED(this->open_and_load_flattened, clone);
3635 this->verify_size_and_overlap(clone, 1, 0);
3636 this->verify_data(clone, expected_bl);
3637 }
3638}
7c673cae 3639
1e59de90
TL
3640TYPED_TEST(EncryptedFlattenTest, ShrinkToOneAfterSnapshot)
3641{
3642 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3643 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
3644 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
f67539c2 3645
1e59de90 3646 ASSERT_PASSED0(this->create_and_setup);
f67539c2 3647
1e59de90
TL
3648 ceph::bufferlist expected_bl;
3649 expected_bl.append(std::string(1, 'a'));
7c673cae 3650
1e59de90
TL
3651 {
3652 librbd::Image clone;
3653 ASSERT_PASSED(this->open_and_load, clone);
3654 ASSERT_EQ(0, clone.snap_create("snap"));
3655 ASSERT_EQ(0, clone.resize(1));
3656 this->verify_size_and_overlap(clone, 1, 1);
3657 this->verify_data(clone, expected_bl);
3658 ASSERT_EQ(0, clone.flatten());
3659 this->verify_data(clone, expected_bl);
3660 }
7c673cae 3661
1e59de90
TL
3662 {
3663 librbd::Image clone;
3664 ASSERT_PASSED(this->open_and_load_flattened, clone);
3665 this->verify_size_and_overlap(clone, 1, 0);
3666 this->verify_data(clone, expected_bl);
3667 }
f67539c2 3668}
7c673cae 3669
1e59de90 3670TYPED_TEST(EncryptedFlattenTest, MinOverlap)
f67539c2 3671{
1e59de90
TL
3672 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3673 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
f67539c2 3674 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
7c673cae 3675
1e59de90 3676 ASSERT_PASSED0(this->create_and_setup);
7c673cae 3677
1e59de90
TL
3678 ceph::bufferlist expected_bl;
3679 expected_bl.append(std::string(1, 'a'));
3680 expected_bl.append_zero(this->m_data_size - 1);
c07f9fc5 3681
1e59de90
TL
3682 {
3683 librbd::Image clone;
3684 ASSERT_PASSED(this->open_and_load, clone);
3685 ASSERT_EQ(0, clone.resize(1));
3686 ASSERT_EQ(0, clone.resize(this->m_data_size));
3687 this->verify_size_and_overlap(clone, this->m_data_size, 1);
3688 this->verify_data(clone, expected_bl);
3689 ASSERT_EQ(0, clone.flatten());
3690 this->verify_data(clone, expected_bl);
3691 }
f67539c2 3692
1e59de90
TL
3693 {
3694 librbd::Image clone;
3695 ASSERT_PASSED(this->open_and_load_flattened, clone);
3696 this->verify_size_and_overlap(clone, this->m_data_size, 0);
3697 this->verify_data(clone, expected_bl);
3698 }
3699}
f67539c2 3700
1e59de90
TL
3701TYPED_TEST(EncryptedFlattenTest, ZeroOverlap)
3702{
3703 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3704 REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
3705 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
f67539c2 3706
1e59de90 3707 ASSERT_PASSED0(this->create_and_setup);
f67539c2 3708
1e59de90
TL
3709 ceph::bufferlist expected_bl;
3710 expected_bl.append_zero(this->m_data_size);
7c673cae 3711
1e59de90
TL
3712 {
3713 librbd::Image clone;
3714 ASSERT_PASSED(this->open_and_load, clone);
3715 ASSERT_EQ(0, clone.resize(0));
3716 ASSERT_EQ(0, clone.resize(this->m_data_size));
3717 this->verify_size_and_overlap(clone, this->m_data_size, 0);
3718 this->verify_data(clone, expected_bl);
3719 ASSERT_EQ(0, clone.flatten());
3720 this->verify_data(clone, expected_bl);
3721 }
f67539c2 3722
1e59de90
TL
3723 {
3724 librbd::Image clone;
3725 ASSERT_PASSED(this->open_and_load_flattened, clone);
3726 this->verify_size_and_overlap(clone, this->m_data_size, 0);
3727 this->verify_data(clone, expected_bl);
3728 }
7c673cae
FG
3729}
3730
1e59de90
TL
3731#endif
3732
7c673cae
FG
3733TEST_F(TestLibRBD, TestIOWithIOHint)
3734{
3735 rados_ioctx_t ioctx;
3736 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3737
7c673cae
FG
3738 rbd_image_t image;
3739 int order = 0;
3740 std::string name = get_temp_image_name();
3741 uint64_t size = 2 << 20;
3742
3743 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3744 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3745
f67539c2
TL
3746 bool skip_discard = is_skip_partial_discard_enabled(image);
3747
7c673cae
FG
3748 char test_data[TEST_IO_SIZE + 1];
3749 char zero_data[TEST_IO_SIZE + 1];
c07f9fc5 3750 char mismatch_data[TEST_IO_SIZE + 1];
7c673cae 3751 int i;
c07f9fc5 3752 uint64_t mismatch_offset;
7c673cae
FG
3753
3754 for (i = 0; i < TEST_IO_SIZE; ++i) {
3755 test_data[i] = (char) (rand() % (126 - 33) + 33);
3756 }
3757 test_data[TEST_IO_SIZE] = '\0';
3758 memset(zero_data, 0, sizeof(zero_data));
c07f9fc5 3759 memset(mismatch_data, 9, sizeof(mismatch_data));
7c673cae
FG
3760
3761 for (i = 0; i < 5; ++i)
3762 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
3763 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
3764
3765 for (i = 5; i < 10; ++i)
3766 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
3767 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3768
c07f9fc5
FG
3769 for (i = 0; i < 5; ++i)
3770 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
3771 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3772
3773 for (i = 5; i < 10; ++i)
3774 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
3775 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3776
7c673cae
FG
3777 for (i = 0; i < 5; ++i)
3778 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE,
3779 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
3780
3781 for (i = 5; i < 10; ++i)
3782 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
3783 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3784
3785 // discard 2nd, 4th sections.
3786 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
3787 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
3788
3789 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE,
3790 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
3791 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
3792 TEST_IO_SIZE, TEST_IO_SIZE,
3793 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
3794 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE,
3795 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
3796 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
3797 TEST_IO_SIZE*3, TEST_IO_SIZE,
3798 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
3799 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
3800
3801 for (i = 0; i < 15; ++i) {
3802 if (i % 3 == 2) {
3803 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
3804 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
3805 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
3806 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
3807 } else if (i % 3 == 1) {
3808 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
3809 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
3810 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
3811 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
3812 } else {
3813 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
3814 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
3815 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
3816 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
3817 }
3818 }
3819 for (i = 0; i < 15; ++i) {
3820 if (i % 3 == 2) {
3821 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
3822 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3823 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
3824 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3825 } else if (i % 3 == 1) {
3826 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
3827 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3828 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
3829 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3830 } else {
3831 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
3832 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3833 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
3834 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
3835 }
3836 }
3837
3838 rbd_image_info_t info;
3839 rbd_completion_t comp;
3840 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
3841 // can't read or write starting past end
3842 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
3843 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
3844 // reading through end returns amount up to end
3845 ASSERT_EQ(10, rbd_read2(image, info.size - 10, 100, test_data,
3846 LIBRADOS_OP_FLAG_FADVISE_NOCACHE));
3847 // writing through end returns amount up to end
3848 ASSERT_EQ(10, rbd_write2(image, info.size - 10, 100, test_data,
3849 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
3850
3851 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
3852 ASSERT_EQ(0, rbd_aio_read2(image, info.size, 1, test_data, comp,
3853 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
3854 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3855 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
3856 rbd_aio_release(comp);
3857
c07f9fc5 3858 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
39ae355f 3859 mismatch_offset = 123;
c07f9fc5
FG
3860 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
3861 &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
3862 ASSERT_EQ(0U, mismatch_offset);
3863 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
39ae355f 3864 mismatch_offset = 123;
c07f9fc5
FG
3865 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
3866 comp, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
3867 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
39ae355f 3868 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
c07f9fc5
FG
3869 ASSERT_EQ(0U, mismatch_offset);
3870 rbd_aio_release(comp);
3871
7c673cae
FG
3872 ASSERT_PASSED(validate_object_map, image);
3873 ASSERT_EQ(0, rbd_close(image));
3874
3875 rados_ioctx_destroy(ioctx);
3876}
3877
3878TEST_F(TestLibRBD, TestDataPoolIO)
3879{
3880 REQUIRE_FORMAT_V2();
3881
3882 rados_ioctx_t ioctx;
3883 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3884
3885 std::string data_pool_name = create_pool(true);
3886
7c673cae
FG
3887 rbd_image_t image;
3888 std::string name = get_temp_image_name();
3889 uint64_t size = 2 << 20;
3890
3891 bool old_format;
3892 uint64_t features;
3893 ASSERT_EQ(0, get_features(&old_format, &features));
3894 ASSERT_FALSE(old_format);
3895
3896 rbd_image_options_t image_options;
3897 rbd_image_options_create(&image_options);
3898 BOOST_SCOPE_EXIT( (&image_options) ) {
3899 rbd_image_options_destroy(image_options);
3900 } BOOST_SCOPE_EXIT_END;
3901
3902 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
3903 RBD_IMAGE_OPTION_FEATURES,
3904 features));
3905 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
3906 RBD_IMAGE_OPTION_DATA_POOL,
3907 data_pool_name.c_str()));
3908
3909 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
3910 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3911 ASSERT_NE(-1, rbd_get_data_pool_id(image));
3912
f67539c2
TL
3913 bool skip_discard = is_skip_partial_discard_enabled(image);
3914
7c673cae
FG
3915 char test_data[TEST_IO_SIZE + 1];
3916 char zero_data[TEST_IO_SIZE + 1];
3917 int i;
3918
3919 for (i = 0; i < TEST_IO_SIZE; ++i) {
3920 test_data[i] = (char) (rand() % (126 - 33) + 33);
3921 }
3922 test_data[TEST_IO_SIZE] = '\0';
3923 memset(zero_data, 0, sizeof(zero_data));
3924
3925 for (i = 0; i < 5; ++i)
3926 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
3927
3928 for (i = 5; i < 10; ++i)
3929 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
3930
3931 for (i = 0; i < 5; ++i)
3932 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
3933
3934 for (i = 5; i < 10; ++i)
3935 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
3936
3937 // discard 2nd, 4th sections.
3938 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
3939 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
3940
3941 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
3942 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
3943 TEST_IO_SIZE, TEST_IO_SIZE, 0);
3944 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
3945 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
3946 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
3947 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
3948
3949 rbd_image_info_t info;
3950 rbd_completion_t comp;
3951 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
3952 // can't read or write starting past end
3953 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
3954 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
3955 // reading through end returns amount up to end
3956 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
3957 // writing through end returns amount up to end
3958 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
3959
3960 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
3961 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
3962 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3963 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
3964 rbd_aio_release(comp);
3965
3966 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
3967 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
3968 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3969 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
3970 rbd_aio_release(comp);
3971
3972 ASSERT_PASSED(validate_object_map, image);
3973 ASSERT_EQ(0, rbd_close(image));
3974
3975 rados_ioctx_destroy(ioctx);
3976}
3977
39ae355f 3978TEST_F(TestLibRBD, TestCompareAndWriteMismatch)
7c673cae
FG
3979{
3980 rados_ioctx_t ioctx;
3981 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3982
3983 rbd_image_t image;
3984 int order = 0;
3985 std::string name = get_temp_image_name();
39ae355f
TL
3986 uint64_t size = 20 << 20; /* 20MiB */
3987 off_t off = 512;
7c673cae
FG
3988
3989 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3990 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3991
39ae355f
TL
3992 // We only support to compare and write the same amount of (len) bytes
3993 std::string cmp_buffer("This is a test");
3994 std::string write_buffer("Write this !!!");
3995 std::string mismatch_buffer("This will fail");
3996 std::string read_buffer(cmp_buffer.length(), '1');
3997
3998 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
3999 cmp_buffer.data());
4000 ASSERT_EQ(cmp_buffer.length(), written);
4001
4002 // Compare should fail because of mismatch
4003 uint64_t mismatch_off = 0;
4004 written = rbd_compare_and_write(image, off, write_buffer.length(),
4005 mismatch_buffer.data(), write_buffer.data(),
4006 &mismatch_off, 0);
4007 ASSERT_EQ(-EILSEQ, written);
4008 ASSERT_EQ(5U, mismatch_off);
4009
4010 // check nothing was written
4011 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
4012 ASSERT_EQ(read_buffer.length(), read);
4013 ASSERT_EQ(cmp_buffer, read_buffer);
7c673cae 4014
39ae355f
TL
4015 ASSERT_PASSED(validate_object_map, image);
4016 ASSERT_EQ(0, rbd_close(image));
7c673cae 4017
39ae355f
TL
4018 rados_ioctx_destroy(ioctx);
4019}
7c673cae 4020
39ae355f
TL
4021TEST_F(TestLibRBD, TestAioCompareAndWriteMismatch)
4022{
4023 rados_ioctx_t ioctx;
4024 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 4025
39ae355f
TL
4026 rbd_image_t image;
4027 int order = 0;
4028 std::string name = get_temp_image_name();
4029 uint64_t size = 20 << 20; /* 20MiB */
4030 off_t off = 512;
4031
4032 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4033 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4034
4035 // We only support to compare and write the same amount of (len) bytes
4036 std::string cmp_buffer("This is a test");
4037 std::string write_buffer("Write this !!!");
4038 std::string mismatch_buffer("This will fail");
4039 std::string read_buffer(cmp_buffer.length(), '1');
4040
4041 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
4042 cmp_buffer.data());
4043 ASSERT_EQ(cmp_buffer.length(), written);
4044
4045 // Compare should fail because of mismatch
4046 rbd_completion_t comp;
7c673cae 4047 rbd_aio_create_completion(NULL, NULL, &comp);
39ae355f
TL
4048 uint64_t mismatch_off = 0;
4049 int ret = rbd_aio_compare_and_write(image, off, write_buffer.length(),
4050 mismatch_buffer.data(),
4051 write_buffer.data(), comp,
4052 &mismatch_off, 0);
4053 ASSERT_EQ(0, ret);
7c673cae 4054 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
39ae355f
TL
4055 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
4056 ASSERT_EQ(5U, mismatch_off);
7c673cae 4057 rbd_aio_release(comp);
39ae355f
TL
4058
4059 // check nothing was written
4060 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
4061 ASSERT_EQ(read_buffer.length(), read);
4062 ASSERT_EQ(cmp_buffer, read_buffer);
7c673cae
FG
4063
4064 ASSERT_PASSED(validate_object_map, image);
4065 ASSERT_EQ(0, rbd_close(image));
4066
4067 rados_ioctx_destroy(ioctx);
4068}
4069
39ae355f 4070TEST_F(TestLibRBD, TestCompareAndWriteSuccess)
7c673cae
FG
4071{
4072 rados_ioctx_t ioctx;
4073 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4074
4075 rbd_image_t image;
4076 int order = 0;
4077 std::string name = get_temp_image_name();
39ae355f
TL
4078 uint64_t size = 20 << 20; /* 20MiB */
4079 off_t off = 512;
31f18b77 4080
7c673cae
FG
4081 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4082 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4083
39ae355f
TL
4084 // We only support to compare and write the same amount of (len) bytes
4085 std::string cmp_buffer("This is a test");
4086 std::string write_buffer("Write this !!!");
4087 std::string read_buffer(cmp_buffer.length(), '1');
4088
4089 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
4090 cmp_buffer.data());
4091 ASSERT_EQ(cmp_buffer.length(), written);
4092
4093 /*
4094 * we compare against the written buffer (cmp_buffer) and write the buffer
4095 * We expect: len bytes written
4096 */
4097 uint64_t mismatch_off = 0;
4098 written = rbd_compare_and_write(image, off, write_buffer.length(),
4099 cmp_buffer.data(), write_buffer.data(),
4100 &mismatch_off, 0);
4101 ASSERT_EQ(write_buffer.length(), written);
4102 ASSERT_EQ(0U, mismatch_off);
4103
4104 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
4105 ASSERT_EQ(read_buffer.length(), read);
4106 ASSERT_EQ(write_buffer, read_buffer);
7c673cae
FG
4107
4108 ASSERT_PASSED(validate_object_map, image);
4109 ASSERT_EQ(0, rbd_close(image));
4110
4111 rados_ioctx_destroy(ioctx);
4112}
4113
39ae355f 4114TEST_F(TestLibRBD, TestAioCompareAndWriteSuccess)
11fdf7f2
TL
4115{
4116 rados_ioctx_t ioctx;
4117 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4118
39ae355f 4119 rbd_image_t image;
11fdf7f2
TL
4120 int order = 0;
4121 std::string name = get_temp_image_name();
39ae355f
TL
4122 uint64_t size = 20 << 20; /* 20MiB */
4123 off_t off = 512;
11fdf7f2
TL
4124
4125 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
39ae355f 4126 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11fdf7f2 4127
39ae355f
TL
4128 // We only support to compare and write the same amount of (len) bytes
4129 std::string cmp_buffer("This is a test");
4130 std::string write_buffer("Write this !!!");
4131 std::string read_buffer(cmp_buffer.length(), '1');
11fdf7f2 4132
39ae355f
TL
4133 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
4134 cmp_buffer.data());
4135 ASSERT_EQ(cmp_buffer.length(), written);
11fdf7f2 4136
39ae355f
TL
4137 /*
4138 * we compare against the written buffer (cmp_buffer) and write the buffer
4139 * We expect: len bytes written
4140 */
4141 rbd_completion_t comp;
4142 rbd_aio_create_completion(NULL, NULL, &comp);
4143 uint64_t mismatch_off = 0;
4144 int ret = rbd_aio_compare_and_write(image, off, write_buffer.length(),
4145 cmp_buffer.data(), write_buffer.data(),
4146 comp, &mismatch_off, 0);
4147 ASSERT_EQ(0, ret);
4148 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4149 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
4150 ASSERT_EQ(0U, mismatch_off);
4151 rbd_aio_release(comp);
11fdf7f2 4152
39ae355f
TL
4153 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
4154 ASSERT_EQ(read_buffer.length(), read);
4155 ASSERT_EQ(write_buffer, read_buffer);
11fdf7f2 4156
39ae355f
TL
4157 ASSERT_PASSED(validate_object_map, image);
4158 ASSERT_EQ(0, rbd_close(image));
11fdf7f2 4159
11fdf7f2
TL
4160 rados_ioctx_destroy(ioctx);
4161}
7c673cae 4162
39ae355f
TL
4163
4164TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitUnaligned)
7c673cae 4165{
39ae355f
TL
4166 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
4167
4168 rados_ioctx_t ioctx;
4169 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4170
4171 rbd_image_t image;
4172 int order = 0;
4173 std::string name = get_temp_image_name();
4174 uint64_t size = 20 << 20; /* 20MiB */
4175
4176 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4177 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4178
4179 // large write test => we allow stripe unit size writes (aligned)
4180 uint64_t stripe_unit;
4181 rbd_get_stripe_unit(image, &stripe_unit);
4182 std::string large_write_buffer(stripe_unit, '2');
4183 std::string large_cmp_buffer(stripe_unit * 2, '4');
4184
4185 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
4186 large_cmp_buffer.data());
4187 ASSERT_EQ(large_cmp_buffer.length(), written);
4188
4189 /*
4190 * compare and write at offset stripe_unit + 1 and stripe unit size
4191 * Expect fail because access exceeds stripe (unaligned)
4192 */
4193 uint64_t mismatch_off = 0;
4194 written = rbd_compare_and_write(image, stripe_unit + 1, stripe_unit,
4195 large_cmp_buffer.data(),
4196 large_write_buffer.data(),
4197 &mismatch_off, 0);
4198 ASSERT_EQ(-EINVAL, written);
4199 ASSERT_EQ(0U, mismatch_off);
4200
4201 // check nothing has been written
4202 std::string large_read_buffer(large_cmp_buffer.length(), '5');
4203 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
4204 large_read_buffer.data());
4205 ASSERT_EQ(large_read_buffer.length(), read);
4206 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
4207 large_cmp_buffer.end(),
4208 large_read_buffer.begin());
4209 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
4210
4211 ASSERT_PASSED(validate_object_map, image);
4212 ASSERT_EQ(0, rbd_close(image));
4213
4214 rados_ioctx_destroy(ioctx);
7c673cae
FG
4215}
4216
39ae355f 4217TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitUnaligned)
7c673cae 4218{
39ae355f
TL
4219 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
4220
4221 rados_ioctx_t ioctx;
4222 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4223
4224 rbd_image_t image;
4225 int order = 0;
4226 std::string name = get_temp_image_name();
4227 uint64_t size = 20 << 20; /* 20MiB */
4228
4229 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4230 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4231
4232 // large write test => we allow stripe unit size writes (aligned)
4233 uint64_t stripe_unit;
4234 rbd_get_stripe_unit(image, &stripe_unit);
4235 std::string large_write_buffer(stripe_unit, '2');
4236 std::string large_cmp_buffer(stripe_unit * 2, '4');
4237
4238 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
4239 large_cmp_buffer.data());
4240 ASSERT_EQ(large_cmp_buffer.length(), written);
4241
4242 /*
4243 * compare and write at offset stripe_unit + 1 and stripe unit size
4244 * Expect fail because access spans stripe unit boundary (unaligned)
4245 */
4246 rbd_completion_t comp;
4247 rbd_aio_create_completion(NULL, NULL, &comp);
4248 uint64_t mismatch_off = 0;
4249 int ret = rbd_aio_compare_and_write(image, stripe_unit + 1, stripe_unit,
4250 large_cmp_buffer.data(),
4251 large_write_buffer.data(),
4252 comp, &mismatch_off, 0);
4253 ASSERT_EQ(0, ret);
4254 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4255 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
4256 ASSERT_EQ(0U, mismatch_off);
4257 rbd_aio_release(comp);
4258
4259 // check nothing has been written
4260 std::string large_read_buffer(large_cmp_buffer.length(), '5');
4261 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
4262 large_read_buffer.data());
4263 ASSERT_EQ(large_read_buffer.length(), read);
4264 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
4265 large_cmp_buffer.end(),
4266 large_read_buffer.begin());
4267 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
4268
4269 ASSERT_PASSED(validate_object_map, image);
4270 ASSERT_EQ(0, rbd_close(image));
4271
4272 rados_ioctx_destroy(ioctx);
7c673cae
FG
4273}
4274
39ae355f 4275TEST_F(TestLibRBD, TestCompareAndWriteTooLarge)
7c673cae 4276{
39ae355f
TL
4277 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
4278
4279 rados_ioctx_t ioctx;
4280 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4281
4282 rbd_image_t image;
4283 int order = 0;
4284 std::string name = get_temp_image_name();
4285 uint64_t size = 20 << 20; /* 20MiB */
4286
4287 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4288 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4289
4290 // large write test => we allow stripe unit size writes (aligned)
4291 uint64_t stripe_unit;
4292 rbd_get_stripe_unit(image, &stripe_unit);
4293 std::string large_write_buffer(stripe_unit * 2, '2');
4294 std::string large_cmp_buffer(large_write_buffer.length(), '4');
4295
4296 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
4297 large_cmp_buffer.data());
4298 ASSERT_EQ(large_cmp_buffer.length(), written);
4299
4300 /*
4301 * compare and write at offset stripe_unit and stripe unit size + 1
4302 * Expect fail because access is larger than stripe unit size
4303 */
4304 uint64_t mismatch_off = 0;
4305 written = rbd_compare_and_write(image, stripe_unit, stripe_unit + 1,
4306 large_cmp_buffer.data(),
4307 large_write_buffer.data(),
4308 &mismatch_off, 0);
4309 ASSERT_EQ(-EINVAL, written);
4310 ASSERT_EQ(0U, mismatch_off);
4311
4312 // check nothing has been written
4313 std::string large_read_buffer(large_cmp_buffer.length(), '5');
4314 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
4315 large_read_buffer.data());
4316 ASSERT_EQ(large_read_buffer.length(), read);
4317 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
4318 large_cmp_buffer.end(),
4319 large_read_buffer.begin());
4320 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
4321
4322 ASSERT_PASSED(validate_object_map, image);
4323 ASSERT_EQ(0, rbd_close(image));
4324
4325 rados_ioctx_destroy(ioctx);
7c673cae
FG
4326}
4327
39ae355f 4328TEST_F(TestLibRBD, TestAioCompareAndWriteTooLarge)
7c673cae 4329{
39ae355f
TL
4330 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
4331
4332 rados_ioctx_t ioctx;
4333 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4334
4335 rbd_image_t image;
4336 int order = 0;
4337 std::string name = get_temp_image_name();
4338 uint64_t size = 20 << 20; /* 20MiB */
4339
4340 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4341 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4342
4343 // large write test => we allow stripe unit size writes (aligned)
4344 uint64_t stripe_unit;
4345 rbd_get_stripe_unit(image, &stripe_unit);
4346 std::string large_write_buffer(stripe_unit * 2, '2');
4347 std::string large_cmp_buffer(large_write_buffer.length(), '4');
4348
4349 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
4350 large_cmp_buffer.data());
4351 ASSERT_EQ(large_cmp_buffer.length(), written);
4352
4353 /*
4354 * compare and write at offset stripe_unit and stripe unit size + 1
4355 * Expect fail because access is larger than stripe unit size
4356 */
4357 rbd_completion_t comp;
4358 rbd_aio_create_completion(NULL, NULL, &comp);
4359 uint64_t mismatch_off = 0;
4360 int ret = rbd_aio_compare_and_write(image, stripe_unit, stripe_unit + 1,
4361 large_cmp_buffer.data(),
4362 large_write_buffer.data(),
4363 comp, &mismatch_off, 0);
4364 ASSERT_EQ(0, ret);
4365 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4366 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
4367 ASSERT_EQ(0U, mismatch_off);
4368 rbd_aio_release(comp);
4369
4370 // check nothing has been written
4371 std::string large_read_buffer(large_cmp_buffer.length(), '5');
4372 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
4373 large_read_buffer.data());
4374 ASSERT_EQ(large_read_buffer.length(), read);
4375 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
4376 large_cmp_buffer.end(),
4377 large_read_buffer.begin());
4378 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
4379
4380 ASSERT_PASSED(validate_object_map, image);
4381 ASSERT_EQ(0, rbd_close(image));
4382
4383 rados_ioctx_destroy(ioctx);
7c673cae
FG
4384}
4385
39ae355f 4386TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitSuccess)
7c673cae 4387{
39ae355f
TL
4388 rados_ioctx_t ioctx;
4389 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4390
4391 rbd_image_t image;
4392 int order = 0;
4393 std::string name = get_temp_image_name();
4394 uint64_t size = 20 << 20; /* 20MiB */
4395
4396 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4397 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4398
4399 // large write test => we allow stripe unit size writes (aligned)
4400 uint64_t stripe_unit;
4401 rbd_get_stripe_unit(image, &stripe_unit);
4402 std::string large_write_buffer(stripe_unit, '2');
4403 std::string large_cmp_buffer(stripe_unit * 2, '4');
4404
4405 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
4406 large_cmp_buffer.data());
4407 ASSERT_EQ(large_cmp_buffer.length(), written);
4408
4409 // aligned stripe unit size access => expect success
4410 uint64_t mismatch_off = 0;
4411 written = rbd_compare_and_write(image, stripe_unit, stripe_unit,
4412 large_cmp_buffer.data(),
4413 large_write_buffer.data(),
4414 &mismatch_off, 0);
4415 ASSERT_EQ(stripe_unit, written);
4416 ASSERT_EQ(0U, mismatch_off);
4417
4418 // check stripe_unit bytes of large_write_buffer were written
4419 std::string large_read_buffer(large_cmp_buffer.length(), '5');
4420 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
4421 large_read_buffer.data());
4422 ASSERT_EQ(large_read_buffer.length(), read);
4423 auto buffer_mismatch = std::mismatch(large_read_buffer.begin(),
4424 large_read_buffer.begin() + stripe_unit,
4425 large_write_buffer.begin());
4426 ASSERT_EQ(large_write_buffer.end(), buffer_mismatch.second);
4427 // check data beyond stripe_unit size was not overwritten
4428 buffer_mismatch = std::mismatch(large_read_buffer.begin() + stripe_unit,
4429 large_read_buffer.end(),
4430 large_cmp_buffer.begin());
4431 ASSERT_EQ(large_cmp_buffer.begin() + stripe_unit, buffer_mismatch.second);
4432
4433 ASSERT_PASSED(validate_object_map, image);
4434 ASSERT_EQ(0, rbd_close(image));
4435
4436 rados_ioctx_destroy(ioctx);
7c673cae
FG
4437}
4438
39ae355f
TL
4439TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitSuccess)
4440{
4441 rados_ioctx_t ioctx;
4442 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4443
4444 rbd_image_t image;
4445 int order = 0;
4446 std::string name = get_temp_image_name();
4447 uint64_t size = 20 << 20; /* 20MiB */
4448
4449 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4450 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4451
4452 // large write test => we allow stripe unit size writes (aligned)
4453 uint64_t stripe_unit;
4454 rbd_get_stripe_unit(image, &stripe_unit);
4455 std::string large_write_buffer(stripe_unit, '2');
4456 std::string large_cmp_buffer(stripe_unit * 2, '4');
4457
4458 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
4459 large_cmp_buffer.data());
4460 ASSERT_EQ(large_cmp_buffer.length(), written);
4461
4462 // aligned stripe unit size access => expect success
4463 rbd_completion_t comp;
4464 rbd_aio_create_completion(NULL, NULL, &comp);
4465 uint64_t mismatch_off = 0;
4466 int ret = rbd_aio_compare_and_write(image, stripe_unit, stripe_unit,
4467 large_cmp_buffer.data(),
4468 large_write_buffer.data(),
4469 comp, &mismatch_off, 0);
4470 ASSERT_EQ(0, ret);
4471 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4472 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
4473 ASSERT_EQ(0U, mismatch_off);
4474 rbd_aio_release(comp);
4475
4476 // check stripe_unit bytes of large_write_buffer were written
4477 std::string large_read_buffer(large_cmp_buffer.length(), '5');
4478 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
4479 large_read_buffer.data());
4480 ASSERT_EQ(large_read_buffer.length(), read);
4481 auto buffer_mismatch = std::mismatch(large_read_buffer.begin(),
4482 large_read_buffer.begin() + stripe_unit,
4483 large_write_buffer.begin());
4484 ASSERT_EQ(large_write_buffer.end(), buffer_mismatch.second);
4485 // check data beyond stripe_unit size was not overwritten
4486 buffer_mismatch = std::mismatch(large_read_buffer.begin() + stripe_unit,
4487 large_read_buffer.end(),
4488 large_cmp_buffer.begin());
4489 ASSERT_EQ(large_cmp_buffer.begin() + stripe_unit, buffer_mismatch.second);
4490
4491 ASSERT_PASSED(validate_object_map, image);
4492 ASSERT_EQ(0, rbd_close(image));
4493
4494 rados_ioctx_destroy(ioctx);
4495}
4496
4497TEST_F(TestLibRBD, TestAioCompareAndWriteVIovecLenDiffers)
4498{
4499 rados_ioctx_t ioctx;
4500 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4501
4502 rbd_image_t image;
4503 int order = 0;
4504 std::string name = get_temp_image_name();
4505 uint64_t size = 20 << 20; /* 20MiB */
4506 off_t off = 512;
4507
4508 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4509 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4510
4511 std::string cmp_buffer("This is a test");
4512 size_t cmp_len = cmp_buffer.length();
4513
4514 std::string write_buffer("Write this !!!");
4515 struct iovec write_iovs[] = {
4516 {.iov_base = &write_buffer[0], .iov_len = 6},
4517 {.iov_base = &write_buffer[6], .iov_len = 5},
4518 {.iov_base = &write_buffer[11], .iov_len = 3}
4519 };
4520
4521 ASSERT_EQ(cmp_len, rbd_write(image, off, cmp_len, cmp_buffer.data()));
4522
4523 // should fail because compare iovec len cannot be different to write iovec len
4524 rbd_completion_t comp;
4525 rbd_aio_create_completion(NULL, NULL, &comp);
4526 uint64_t mismatch_off = 0;
4527 int ret = rbd_aio_compare_and_writev(image, off,
4528 write_iovs /* cmp_iovs */, 1,
4529 write_iovs, std::size(write_iovs),
4530 comp, &mismatch_off, 0);
4531 ASSERT_EQ(-EINVAL, ret);
4532 ASSERT_EQ(0U, mismatch_off);
4533 rbd_aio_release(comp);
4534
4535 // check nothing was written
4536 std::string read_buffer(cmp_buffer.length(), '1');
4537 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
4538 ASSERT_EQ(read_buffer.length(), read);
4539 ASSERT_EQ(cmp_buffer, read_buffer);
4540
4541 ASSERT_PASSED(validate_object_map, image);
4542 ASSERT_EQ(0, rbd_close(image));
4543
4544 rados_ioctx_destroy(ioctx);
4545}
4546
4547TEST_F(TestLibRBD, TestAioCompareAndWriteVMismatch)
4548{
4549 rados_ioctx_t ioctx;
4550 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4551
4552 rbd_image_t image;
4553 int order = 0;
4554 std::string name = get_temp_image_name();
4555 uint64_t size = 20 << 20; /* 20MiB */
4556 off_t off = 512;
4557
4558 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4559 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4560
4561 std::string cmp_buffer("This is a test");
4562 int cmp_len = cmp_buffer.length();
4563
4564 std::string write_buffer("Write this !!!");
4565 struct iovec write_iovs[] = {
4566 {.iov_base = &write_buffer[0], .iov_len = 6},
4567 {.iov_base = &write_buffer[6], .iov_len = 5},
4568 {.iov_base = &write_buffer[11], .iov_len = 3}
4569 };
4570
4571 std::string mismatch_buffer("This will fail");
4572 struct iovec mismatch_iovs[] = {
4573 {.iov_base = &mismatch_buffer[0], .iov_len = 5},
4574 {.iov_base = &mismatch_buffer[5], .iov_len = 5},
4575 {.iov_base = &mismatch_buffer[10], .iov_len = 4}
4576 };
4577
4578 ASSERT_EQ(cmp_len, rbd_write(image, off, cmp_len, cmp_buffer.data()));
4579
4580 // this should execute the compare but fail because of mismatch
4581 rbd_completion_t comp;
4582 rbd_aio_create_completion(NULL, NULL, &comp);
4583 uint64_t mismatch_off = 0;
4584 int ret = rbd_aio_compare_and_writev(image, off,
4585 mismatch_iovs /* cmp_iovs */,
4586 std::size(mismatch_iovs),
4587 write_iovs, std::size(write_iovs),
4588 comp, &mismatch_off, 0);
4589 ASSERT_EQ(0, ret);
4590 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4591 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
4592 ASSERT_EQ(5U, mismatch_off);
4593 rbd_aio_release(comp);
4594
4595 // check nothing was written
4596 std::string read_buffer(cmp_buffer.length(), '1');
4597 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
4598 ASSERT_EQ(read_buffer.length(), read);
4599 ASSERT_EQ(cmp_buffer, read_buffer);
4600
4601 ASSERT_PASSED(validate_object_map, image);
4602 ASSERT_EQ(0, rbd_close(image));
4603
4604 rados_ioctx_destroy(ioctx);
4605}
4606
4607TEST_F(TestLibRBD, TestAioCompareAndWriteVSuccess)
4608{
4609 rados_ioctx_t ioctx;
4610 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4611
4612 rbd_image_t image;
4613 int order = 0;
4614 std::string name = get_temp_image_name();
4615 uint64_t size = 20 << 20; /* 20MiB */
4616 off_t off = 512;
4617
4618 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4619 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4620
4621 std::string cmp_buffer("This is a test");
4622 struct iovec cmp_iovs[] = {
4623 {.iov_base = &cmp_buffer[0], .iov_len = 5},
4624 {.iov_base = &cmp_buffer[5], .iov_len = 3},
4625 {.iov_base = &cmp_buffer[8], .iov_len = 2},
4626 {.iov_base = &cmp_buffer[10], .iov_len = 4}
4627 };
4628 size_t cmp_len = cmp_buffer.length();
4629
4630 std::string write_buffer("Write this !!!");
4631 struct iovec write_iovs[] = {
4632 {.iov_base = &write_buffer[0], .iov_len = 6},
4633 {.iov_base = &write_buffer[6], .iov_len = 5},
4634 {.iov_base = &write_buffer[11], .iov_len = 3}
4635 };
4636
4637 ASSERT_EQ(cmp_len, rbd_write(image, off, cmp_len, cmp_buffer.data()));
4638
4639 // compare against the buffer written before => should succeed
4640 rbd_completion_t comp;
4641 rbd_aio_create_completion(NULL, NULL, &comp);
4642 uint64_t mismatch_off = 0;
4643 int ret = rbd_aio_compare_and_writev(image, off,
4644 cmp_iovs, std::size(cmp_iovs),
4645 write_iovs, std::size(write_iovs),
4646 comp, &mismatch_off, 0);
4647 ASSERT_EQ(0, ret);
4648 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4649 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
4650 ASSERT_EQ(0U, mismatch_off);
4651 rbd_aio_release(comp);
4652
4653 // check data was successfully written
4654 std::string read_buffer(cmp_buffer.length(), '1');
4655 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
4656 ASSERT_EQ(read_buffer.length(), read);
4657 ASSERT_EQ(write_buffer, read_buffer);
4658
4659 ASSERT_PASSED(validate_object_map, image);
4660 ASSERT_EQ(0, rbd_close(image));
4661
4662 rados_ioctx_destroy(ioctx);
4663}
4664
4665TEST_F(TestLibRBD, TestScatterGatherIO)
4666{
4667 rados_ioctx_t ioctx;
4668 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4669
4670 rbd_image_t image;
4671 int order = 0;
4672 std::string name = get_temp_image_name();
4673 uint64_t size = 20 << 20;
4674
4675 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4676 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4677
4678 std::string write_buffer("This is a test");
4679 // These iovecs should produce a length overflow
4680 struct iovec bad_iovs[] = {
4681 {.iov_base = &write_buffer[0], .iov_len = 5},
4682 {.iov_base = NULL, .iov_len = std::numeric_limits<size_t>::max()}
4683 };
4684 struct iovec write_iovs[] = {
4685 {.iov_base = &write_buffer[0], .iov_len = 5},
4686 {.iov_base = &write_buffer[5], .iov_len = 3},
4687 {.iov_base = &write_buffer[8], .iov_len = 2},
4688 {.iov_base = &write_buffer[10], .iov_len = 4}
4689 };
4690
4691 rbd_completion_t comp;
4692 rbd_aio_create_completion(NULL, NULL, &comp);
4693 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, write_iovs, 0, 0, comp));
4694 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 2, 0, comp));
4695 ASSERT_EQ(0, rbd_aio_writev(image, write_iovs,
4696 sizeof(write_iovs) / sizeof(struct iovec),
4697 1<<order, comp));
4698 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4699 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
4700 rbd_aio_release(comp);
4701
4702 std::string read_buffer(write_buffer.size(), '1');
4703 struct iovec read_iovs[] = {
4704 {.iov_base = &read_buffer[0], .iov_len = 4},
4705 {.iov_base = &read_buffer[8], .iov_len = 4},
4706 {.iov_base = &read_buffer[12], .iov_len = 2}
4707 };
4708
4709 rbd_aio_create_completion(NULL, NULL, &comp);
4710 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, read_iovs, 0, 0, comp));
4711 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 2, 0, comp));
4712 ASSERT_EQ(0, rbd_aio_readv(image, read_iovs,
4713 sizeof(read_iovs) / sizeof(struct iovec),
4714 1<<order, comp));
4715 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4716 ASSERT_EQ(10, rbd_aio_get_return_value(comp));
4717 rbd_aio_release(comp);
4718 ASSERT_EQ("This1111 is a ", read_buffer);
4719
4720 std::string linear_buffer(write_buffer.size(), '1');
4721 struct iovec linear_iovs[] = {
4722 {.iov_base = &linear_buffer[4], .iov_len = 4}
4723 };
4724 rbd_aio_create_completion(NULL, NULL, &comp);
4725 ASSERT_EQ(0, rbd_aio_readv(image, linear_iovs,
4726 sizeof(linear_iovs) / sizeof(struct iovec),
4727 1<<order, comp));
4728 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
4729 ASSERT_EQ(4, rbd_aio_get_return_value(comp));
4730 rbd_aio_release(comp);
4731 ASSERT_EQ("1111This111111", linear_buffer);
4732
4733 ASSERT_PASSED(validate_object_map, image);
4734 ASSERT_EQ(0, rbd_close(image));
4735
4736 rados_ioctx_destroy(ioctx);
4737}
4738
4739TEST_F(TestLibRBD, TestEmptyDiscard)
4740{
4741 rados_ioctx_t ioctx;
4742 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4743
4744 rbd_image_t image;
4745 int order = 0;
4746 std::string name = get_temp_image_name();
4747 uint64_t size = 20 << 20;
4748
4749 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4750 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4751
4752 ASSERT_PASSED(aio_discard_test_data, image, 0, 1*1024*1024);
4753 ASSERT_PASSED(aio_discard_test_data, image, 0, 4*1024*1024);
4754 ASSERT_PASSED(aio_discard_test_data, image, 3*1024*1024, 1*1024*1024);
4755
4756 ASSERT_PASSED(validate_object_map, image);
4757 ASSERT_EQ(0, rbd_close(image));
4758
4759 rados_ioctx_destroy(ioctx);
4760}
4761
4762TEST_F(TestLibRBD, TestFUA)
4763{
4764 rados_ioctx_t ioctx;
4765 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4766
4767 rbd_image_t image_write;
4768 rbd_image_t image_read;
4769 int order = 0;
4770 std::string name = get_temp_image_name();
4771 uint64_t size = 2 << 20;
4772
4773 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4774 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_write, NULL));
4775 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_read, NULL));
4776
4777 // enable writeback cache
4778 rbd_flush(image_write);
4779
4780 char test_data[TEST_IO_SIZE + 1];
4781 int i;
4782
4783 for (i = 0; i < TEST_IO_SIZE; ++i) {
4784 test_data[i] = (char) (rand() % (126 - 33) + 33);
4785 }
4786 test_data[TEST_IO_SIZE] = '\0';
4787 for (i = 0; i < 5; ++i)
4788 ASSERT_PASSED(write_test_data, image_write, test_data,
4789 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
4790
4791 for (i = 0; i < 5; ++i)
4792 ASSERT_PASSED(read_test_data, image_read, test_data,
4793 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
4794
4795 for (i = 5; i < 10; ++i)
4796 ASSERT_PASSED(aio_write_test_data, image_write, test_data,
4797 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
4798
4799 for (i = 5; i < 10; ++i)
4800 ASSERT_PASSED(aio_read_test_data, image_read, test_data,
4801 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
4802
4803 ASSERT_PASSED(validate_object_map, image_write);
4804 ASSERT_PASSED(validate_object_map, image_read);
4805 ASSERT_EQ(0, rbd_close(image_write));
4806 ASSERT_EQ(0, rbd_close(image_read));
4807 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
4808 rados_ioctx_destroy(ioctx);
4809}
4810
4811void simple_write_cb_pp(librbd::completion_t cb, void *arg)
4812{
4813 cout << "write completion cb called!" << std::endl;
4814}
4815
4816void simple_read_cb_pp(librbd::completion_t cb, void *arg)
4817{
4818 cout << "read completion cb called!" << std::endl;
4819}
4820
4821void aio_write_test_data(librbd::Image& image, const char *test_data,
4822 off_t off, uint32_t iohint, bool *passed)
4823{
4824 ceph::bufferlist bl;
4825 bl.append(test_data, strlen(test_data));
4826 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
4827 printf("created completion\n");
4828 if (iohint)
4829 image.aio_write2(off, strlen(test_data), bl, comp, iohint);
4830 else
4831 image.aio_write(off, strlen(test_data), bl, comp);
4832 printf("started write\n");
4833 comp->wait_for_complete();
4834 int r = comp->get_return_value();
4835 printf("return value is: %d\n", r);
4836 ASSERT_EQ(0, r);
4837 printf("finished write\n");
4838 comp->release();
4839 *passed = true;
4840}
4841
4842void aio_discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
4843{
4844 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
4845 image.aio_discard(off, len, comp);
4846 comp->wait_for_complete();
4847 int r = comp->get_return_value();
4848 ASSERT_EQ(0, r);
4849 comp->release();
4850 *passed = true;
4851}
4852
4853void write_test_data(librbd::Image& image, const char *test_data, off_t off, uint32_t iohint, bool *passed)
4854{
4855 size_t written;
4856 size_t len = strlen(test_data);
4857 ceph::bufferlist bl;
4858 bl.append(test_data, len);
4859 if (iohint)
4860 written = image.write2(off, len, bl, iohint);
4861 else
4862 written = image.write(off, len, bl);
4863 printf("wrote: %u\n", (unsigned int) written);
4864 ASSERT_EQ(bl.length(), written);
4865 *passed = true;
4866}
4867
4868void discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
7c673cae
FG
4869{
4870 size_t written;
4871 written = image.discard(off, len);
4872 printf("discard: %u~%u\n", (unsigned)off, (unsigned)len);
4873 ASSERT_EQ(len, written);
4874 *passed = true;
4875}
4876
39ae355f
TL
4877void aio_read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
4878{
4879 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_read_cb_pp);
4880 ceph::bufferlist bl;
4881 printf("created completion\n");
4882 if (iohint)
4883 image.aio_read2(off, expected_len, bl, comp, iohint);
4884 else
4885 image.aio_read(off, expected_len, bl, comp);
4886 printf("started read\n");
4887 comp->wait_for_complete();
4888 int r = comp->get_return_value();
4889 printf("return value is: %d\n", r);
4890 ASSERT_EQ(TEST_IO_SIZE, r);
4891 ASSERT_EQ(0, memcmp(expected, bl.c_str(), TEST_IO_SIZE));
4892 printf("finished read\n");
4893 comp->release();
4894 *passed = true;
4895}
4896
4897void read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
4898{
4899 int read;
4900 size_t len = expected_len;
4901 ceph::bufferlist bl;
4902 if (iohint)
4903 read = image.read2(off, len, bl, iohint);
4904 else
4905 read = image.read(off, len, bl);
4906 ASSERT_TRUE(read >= 0);
4907 std::string bl_str(bl.c_str(), read);
4908
4909 printf("read: %u\n", (unsigned int) read);
4910 int result = memcmp(bl_str.c_str(), expected, expected_len);
4911 if (result != 0) {
4912 printf("read: %s\nexpected: %s\n", bl_str.c_str(), expected);
4913 ASSERT_EQ(0, result);
4914 }
4915 *passed = true;
4916}
4917
4918void aio_writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
4919 size_t len, size_t data_len, uint32_t iohint, bool *passed)
4920{
4921 ceph::bufferlist bl;
4922 bl.append(test_data, data_len);
4923 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
4924 printf("created completion\n");
4925 int r;
4926 r = image.aio_writesame(off, len, bl, comp, iohint);
4927 printf("started writesame\n");
4928 if (len % data_len) {
4929 ASSERT_EQ(-EINVAL, r);
4930 printf("expected fail, finished writesame\n");
4931 comp->release();
4932 *passed = true;
4933 return;
4934 }
4935
4936 comp->wait_for_complete();
4937 r = comp->get_return_value();
4938 printf("return value is: %d\n", r);
4939 ASSERT_EQ(0, r);
4940 printf("finished writesame\n");
4941 comp->release();
4942
4943 //verify data
4944 printf("to verify the data\n");
4945 int read;
4946 uint64_t left = len;
4947 while (left > 0) {
4948 ceph::bufferlist bl;
4949 read = image.read(off, data_len, bl);
4950 ASSERT_EQ(data_len, static_cast<size_t>(read));
4951 std::string bl_str(bl.c_str(), read);
4952 int result = memcmp(bl_str.c_str(), test_data, data_len);
4953 if (result !=0 ) {
4954 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
4955 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
4956 ASSERT_EQ(0, result);
4957 }
4958 off += data_len;
4959 left -= data_len;
4960 }
4961 ASSERT_EQ(0U, left);
4962 printf("verified\n");
4963
4964 *passed = true;
4965}
4966
4967void writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
4968 ssize_t len, size_t data_len, uint32_t iohint,
4969 bool *passed)
4970{
4971 ssize_t written;
4972 ceph::bufferlist bl;
4973 bl.append(test_data, data_len);
4974 written = image.writesame(off, len, bl, iohint);
4975 if (len % data_len) {
4976 ASSERT_EQ(-EINVAL, written);
4977 printf("expected fail, finished writesame\n");
4978 *passed = true;
4979 return;
4980 }
4981 ASSERT_EQ(len, written);
4982 printf("wrote: %u\n", (unsigned int) written);
4983 *passed = true;
4984
4985 //verify data
4986 printf("to verify the data\n");
4987 int read;
4988 uint64_t left = len;
4989 while (left > 0) {
4990 ceph::bufferlist bl;
4991 read = image.read(off, data_len, bl);
4992 ASSERT_EQ(data_len, static_cast<size_t>(read));
4993 std::string bl_str(bl.c_str(), read);
4994 int result = memcmp(bl_str.c_str(), test_data, data_len);
4995 if (result !=0 ) {
4996 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
4997 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
4998 ASSERT_EQ(0, result);
4999 }
5000 off += data_len;
5001 left -= data_len;
5002 }
5003 ASSERT_EQ(0U, left);
5004 printf("verified\n");
5005
5006 *passed = true;
5007}
5008
5009void aio_compare_and_write_test_data(librbd::Image& image, const char *cmp_data,
5010 const char *test_data, off_t off, ssize_t len,
5011 uint32_t iohint, bool *passed)
5012{
5013 ceph::bufferlist cmp_bl;
5014 cmp_bl.append(cmp_data, strlen(cmp_data));
5015 ceph::bufferlist test_bl;
5016 test_bl.append(test_data, strlen(test_data));
5017 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
5018 printf("created completion\n");
5019
5020 uint64_t mismatch_offset;
5021 image.aio_compare_and_write(off, len, cmp_bl, test_bl, comp, &mismatch_offset, iohint);
5022 printf("started aio compare and write\n");
5023 comp->wait_for_complete();
5024 int r = comp->get_return_value();
5025 printf("return value is: %d\n", r);
5026 ASSERT_EQ(0, r);
5027 printf("finished aio compare and write\n");
5028 comp->release();
5029 *passed = true;
5030}
5031
5032void compare_and_write_test_data(librbd::Image& image, const char *cmp_data, const char *test_data,
5033 off_t off, ssize_t len, uint64_t *mismatch_off, uint32_t iohint, bool *passed)
5034{
5035 size_t written;
5036 ceph::bufferlist cmp_bl;
5037 cmp_bl.append(cmp_data, strlen(cmp_data));
5038 ceph::bufferlist test_bl;
5039 test_bl.append(test_data, strlen(test_data));
5040 printf("start compare and write\n");
5041 written = image.compare_and_write(off, len, cmp_bl, test_bl, mismatch_off, iohint);
5042 printf("compare and wrote: %d\n", (int) written);
5043 ASSERT_EQ(len, static_cast<ssize_t>(written));
5044 *passed = true;
5045}
5046
5047TEST_F(TestLibRBD, TestIOPP)
5048{
5049 librados::IoCtx ioctx;
5050 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5051
5052 {
5053 librbd::RBD rbd;
5054 librbd::Image image;
5055 int order = 0;
5056 std::string name = get_temp_image_name();
5057 uint64_t size = 2 << 20;
5058
5059 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5060 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5061
5062 bool skip_discard = this->is_skip_partial_discard_enabled(image);
5063
5064 char test_data[TEST_IO_SIZE + 1];
5065 char zero_data[TEST_IO_SIZE + 1];
5066 int i;
5067 uint64_t mismatch_offset;
5068
5069 for (i = 0; i < TEST_IO_SIZE; ++i) {
5070 test_data[i] = (char) (rand() % (126 - 33) + 33);
5071 }
5072 test_data[TEST_IO_SIZE] = '\0';
5073 memset(zero_data, 0, sizeof(zero_data));
5074
5075 for (i = 0; i < 5; ++i)
5076 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i, 0);
5077
5078 for (i = 5; i < 10; ++i)
5079 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i, 0);
5080
5081 for (i = 0; i < 5; ++i)
5082 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
5083 TEST_IO_SIZE, &mismatch_offset, 0);
5084
5085 for (i = 5; i < 10; ++i)
5086 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
5087 TEST_IO_SIZE, 0);
5088
5089 for (i = 0; i < 5; ++i)
5090 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
5091
5092 for (i = 5; i < 10; ++i)
5093 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
5094
5095 // discard 2nd, 4th sections.
5096 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
5097 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
5098
5099 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
5100 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
5101 TEST_IO_SIZE, TEST_IO_SIZE, 0);
5102 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
5103 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
5104 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
5105 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
5106
5107 for (i = 0; i < 15; ++i) {
5108 if (i % 3 == 2) {
5109 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
5110 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
5111 } else if (i % 3 == 1) {
5112 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5113 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5114 } else {
5115 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5116 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5117 }
5118 }
5119 for (i = 0; i < 15; ++i) {
5120 if (i % 3 == 2) {
5121 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
5122 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
5123 } else if (i % 3 == 1) {
5124 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5125 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5126 } else {
5127 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5128 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
5129 }
5130 }
5131
5132 ASSERT_PASSED(validate_object_map, image);
5133 }
5134
5135 ioctx.close();
5136}
5137
5138static void compare_written(librbd::Image& image, off_t off, size_t len,
5139 const std::string& buffer, bool *passed)
5140{
5141 bufferlist read_bl;
5142 ssize_t read = image.read(off, len, read_bl);
5143 ASSERT_EQ(len, read);
5144 std::string read_buffer(read_bl.c_str(), read);
5145 ASSERT_EQ(buffer.substr(0, len), read_buffer);
5146 *passed = true;
5147}
5148
5149TEST_F(TestLibRBD, TestCompareAndWriteCompareTooSmallPP)
5150{
5151 librados::IoCtx ioctx;
5152 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5153
5154 {
5155 librbd::RBD rbd;
5156 librbd::Image image;
5157 int order = 0;
5158 std::string name = get_temp_image_name();
5159 uint64_t size = 20 << 20; /* 20MiB */
5160 off_t off = 512;
5161
5162 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5163 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5164
5165 std::string cmp_buffer("This is a test");
5166 ceph::bufferlist cmp_bl;
5167 cmp_bl.append(&cmp_buffer[0], 5);
5168 cmp_bl.append(&cmp_buffer[5], 3);
5169 cmp_bl.append(&cmp_buffer[8], 2);
5170 cmp_bl.append(&cmp_buffer[10], 4);
5171
5172 std::string write_buffer("Write this !!!");
5173 ceph::bufferlist write_bl;
5174 write_bl.append(&write_buffer[0], 6);
5175 write_bl.append(&write_buffer[6], 5);
5176 write_bl.append(&write_buffer[11], 3);
5177
5178 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5179 ASSERT_EQ(cmp_bl.length(), written);
5180
5181 std::string small_buffer("Too small");
5182 ceph::bufferlist small_bl;
5183 small_bl.append(&small_buffer[0], 4);
5184 small_bl.append(&small_buffer[4], 4);
5185
5186 // should fail because compare bufferlist cannot be smaller than len
5187 uint64_t mismatch_off = 0;
5188 written = image.compare_and_write(off, cmp_bl.length(),
5189 small_bl, /* cmp_bl */
5190 write_bl,
5191 &mismatch_off, 0);
5192 ASSERT_EQ(-EINVAL, written);
5193 ASSERT_EQ(0U, mismatch_off);
5194
5195 ASSERT_PASSED(validate_object_map, image);
5196 }
5197
5198 ioctx.close();
5199}
5200
5201TEST_F(TestLibRBD, TestAioCompareAndWriteCompareTooSmallPP)
7c673cae 5202{
39ae355f
TL
5203 librados::IoCtx ioctx;
5204 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5205
5206 {
5207 librbd::RBD rbd;
5208 librbd::Image image;
5209 int order = 0;
5210 std::string name = get_temp_image_name();
5211 uint64_t size = 20 << 20; /* 20MiB */
5212 off_t off = 512;
5213
5214 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5215 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5216
5217 std::string cmp_buffer("This is a test");
5218 ceph::bufferlist cmp_bl;
5219 cmp_bl.append(&cmp_buffer[0], 5);
5220 cmp_bl.append(&cmp_buffer[5], 3);
5221 cmp_bl.append(&cmp_buffer[8], 2);
5222 cmp_bl.append(&cmp_buffer[10], 4);
5223
5224 std::string write_buffer("Write this !!!");
5225 ceph::bufferlist write_bl;
5226 write_bl.append(&write_buffer[0], 6);
5227 write_bl.append(&write_buffer[6], 5);
5228 write_bl.append(&write_buffer[11], 3);
5229
5230 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5231 ASSERT_EQ(cmp_bl.length(), written);
5232
5233 std::string small_buffer("Too small");
5234 ceph::bufferlist small_bl;
5235 small_bl.append(&small_buffer[0], 4);
5236 small_bl.append(&small_buffer[4], 4);
5237
5238 // should fail because compare bufferlist cannot be smaller than len
5239 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
5240 NULL, (librbd::callback_t) simple_write_cb_pp);
5241 uint64_t mismatch_off = 0;
5242 int ret = image.aio_compare_and_write(off, cmp_bl.length(),
5243 small_bl, /* cmp_bl */
5244 write_bl,
5245 comp, &mismatch_off, 0);
5246 ASSERT_EQ(-EINVAL, ret);
5247 ASSERT_EQ(0U, mismatch_off);
5248 comp->release();
5249
5250 ASSERT_PASSED(validate_object_map, image);
5251 }
5252
5253 ioctx.close();
7c673cae
FG
5254}
5255
39ae355f 5256TEST_F(TestLibRBD, TestCompareAndWriteWriteTooSmallPP)
7c673cae 5257{
39ae355f
TL
5258 librados::IoCtx ioctx;
5259 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 5260
39ae355f
TL
5261 {
5262 librbd::RBD rbd;
5263 librbd::Image image;
5264 int order = 0;
5265 std::string name = get_temp_image_name();
5266 uint64_t size = 20 << 20; /* 20MiB */
5267 off_t off = 512;
5268
5269 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5270 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5271
5272 std::string cmp_buffer("This is a test");
5273 ceph::bufferlist cmp_bl;
5274 cmp_bl.append(&cmp_buffer[0], 5);
5275 cmp_bl.append(&cmp_buffer[5], 3);
5276 cmp_bl.append(&cmp_buffer[8], 2);
5277 cmp_bl.append(&cmp_buffer[10], 4);
5278
5279 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5280 ASSERT_EQ(cmp_bl.length(), written);
5281
5282 std::string small_buffer("Too small");
5283 ceph::bufferlist small_bl;
5284 small_bl.append(&small_buffer[0], 4);
5285 small_bl.append(&small_buffer[4], 4);
5286
5287 // should fail because write bufferlist cannot be smaller than len
5288 uint64_t mismatch_off = 0;
5289 written = image.compare_and_write(off, cmp_bl.length(),
5290 cmp_bl,
5291 small_bl, /* write_bl */
5292 &mismatch_off, 0);
5293 ASSERT_EQ(-EINVAL, written);
5294 ASSERT_EQ(0U, mismatch_off);
5295
5296 ASSERT_PASSED(validate_object_map, image);
7c673cae 5297 }
39ae355f
TL
5298
5299 ioctx.close();
7c673cae
FG
5300}
5301
39ae355f 5302TEST_F(TestLibRBD, TestAioCompareAndWriteWriteTooSmallPP)
7c673cae 5303{
39ae355f
TL
5304 librados::IoCtx ioctx;
5305 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5306
5307 {
5308 librbd::RBD rbd;
5309 librbd::Image image;
5310 int order = 0;
5311 std::string name = get_temp_image_name();
5312 uint64_t size = 20 << 20; /* 20MiB */
5313 off_t off = 512;
5314
5315 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5316 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5317
5318 std::string cmp_buffer("This is a test");
5319 ceph::bufferlist cmp_bl;
5320 cmp_bl.append(&cmp_buffer[0], 5);
5321 cmp_bl.append(&cmp_buffer[5], 3);
5322 cmp_bl.append(&cmp_buffer[8], 2);
5323 cmp_bl.append(&cmp_buffer[10], 4);
5324
5325 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5326 ASSERT_EQ(cmp_bl.length(), written);
5327
5328 std::string small_buffer("Too small");
5329 ceph::bufferlist small_bl;
5330 small_bl.append(&small_buffer[0], 4);
5331 small_bl.append(&small_buffer[4], 4);
5332
5333 // should fail because write bufferlist cannot be smaller than len
5334 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
5335 NULL, (librbd::callback_t) simple_write_cb_pp);
5336 uint64_t mismatch_off = 0;
5337 int ret = image.aio_compare_and_write(off, cmp_bl.length(),
5338 cmp_bl,
5339 small_bl, /* write_bl */
5340 comp, &mismatch_off, 0);
5341 ASSERT_EQ(-EINVAL, ret);
5342 ASSERT_EQ(0U, mismatch_off);
5343 comp->release();
5344
5345 ASSERT_PASSED(validate_object_map, image);
5346 }
5347
5348 ioctx.close();
5349}
5350
5351TEST_F(TestLibRBD, TestCompareAndWriteMismatchPP)
5352{
5353 librados::IoCtx ioctx;
5354 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5355
5356 {
5357 librbd::RBD rbd;
5358 librbd::Image image;
5359 int order = 0;
5360 std::string name = get_temp_image_name();
5361 uint64_t size = 20 << 20; /* 20MiB */
5362 off_t off = 512;
5363
5364 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5365 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5366
5367 std::string cmp_buffer("This is a test");
5368 ceph::bufferlist cmp_bl;
5369 cmp_bl.append(&cmp_buffer[0], 5);
5370 cmp_bl.append(&cmp_buffer[5], 3);
5371 cmp_bl.append(&cmp_buffer[8], 2);
5372 cmp_bl.append(&cmp_buffer[10], 4);
5373
5374 std::string write_buffer("Write this !!!");
5375 ceph::bufferlist write_bl;
5376 write_bl.append(&write_buffer[0], 6);
5377 write_bl.append(&write_buffer[6], 5);
5378 write_bl.append(&write_buffer[11], 3);
5379
5380 std::string mismatch_buffer("This will fail");
5381 ceph::bufferlist mismatch_bl;
5382 mismatch_bl.append(&mismatch_buffer[0], 5);
5383 mismatch_bl.append(&mismatch_buffer[5], 5);
5384 mismatch_bl.append(&mismatch_buffer[10], 4);
5385
5386 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5387 ASSERT_EQ(cmp_bl.length(), written);
5388
5389 // this should execute the compare but fail because of mismatch
5390 uint64_t mismatch_off = 0;
5391 written = image.compare_and_write(off, write_bl.length(),
5392 mismatch_bl, /* cmp_bl */
5393 write_bl,
5394 &mismatch_off, 0);
5395 ASSERT_EQ(-EILSEQ, written);
5396 ASSERT_EQ(5U, mismatch_off);
5397
5398 // check that nothing was written
5399 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
5400
5401 ASSERT_PASSED(validate_object_map, image);
5402 }
5403
5404 ioctx.close();
5405}
5406
5407TEST_F(TestLibRBD, TestAioCompareAndWriteMismatchPP)
5408{
5409 librados::IoCtx ioctx;
5410 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5411
5412 {
5413 librbd::RBD rbd;
5414 librbd::Image image;
5415 int order = 0;
5416 std::string name = get_temp_image_name();
5417 uint64_t size = 20 << 20; /* 20MiB */
5418 off_t off = 512;
5419
5420 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5421 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5422
5423 std::string cmp_buffer("This is a test");
5424 ceph::bufferlist cmp_bl;
5425 cmp_bl.append(&cmp_buffer[0], 5);
5426 cmp_bl.append(&cmp_buffer[5], 3);
5427 cmp_bl.append(&cmp_buffer[8], 2);
5428 cmp_bl.append(&cmp_buffer[10], 4);
5429
5430 std::string write_buffer("Write this !!!");
5431 ceph::bufferlist write_bl;
5432 write_bl.append(&write_buffer[0], 6);
5433 write_bl.append(&write_buffer[6], 5);
5434 write_bl.append(&write_buffer[11], 3);
5435
5436 std::string mismatch_buffer("This will fail");
5437 ceph::bufferlist mismatch_bl;
5438 mismatch_bl.append(&mismatch_buffer[0], 5);
5439 mismatch_bl.append(&mismatch_buffer[5], 5);
5440 mismatch_bl.append(&mismatch_buffer[10], 4);
5441
5442 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5443 ASSERT_EQ(cmp_bl.length(), written);
5444
5445 // this should execute the compare but fail because of mismatch
5446 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
5447 NULL, (librbd::callback_t) simple_write_cb_pp);
5448 uint64_t mismatch_off = 0;
5449 int ret = image.aio_compare_and_write(off, write_bl.length(),
5450 mismatch_bl, /* cmp_bl */
5451 write_bl,
5452 comp, &mismatch_off, 0);
5453 ASSERT_EQ(0, ret);
5454 comp->wait_for_complete();
5455 ssize_t aio_ret = comp->get_return_value();
5456 ASSERT_EQ(-EILSEQ, aio_ret);
5457 ASSERT_EQ(5U, mismatch_off);
5458 comp->release();
5459
5460 // check that nothing was written
5461 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
5462
5463 ASSERT_PASSED(validate_object_map, image);
5464 }
5465
5466 ioctx.close();
5467}
5468
5469TEST_F(TestLibRBD, TestCompareAndWriteMismatchBufferlistGreaterLenPP)
5470{
5471 librados::IoCtx ioctx;
5472 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5473
5474 {
5475 librbd::RBD rbd;
5476 librbd::Image image;
5477 int order = 0;
5478 std::string name = get_temp_image_name();
5479 uint64_t size = 20 << 20; /* 20MiB */
5480 off_t off = 512;
5481
5482 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5483 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5484
5485 std::string cmp_buffer("This is a test");
5486 ceph::bufferlist cmp_bl;
5487 cmp_bl.append(&cmp_buffer[0], 5);
5488 cmp_bl.append(&cmp_buffer[5], 3);
5489 cmp_bl.append(&cmp_buffer[8], 2);
5490 cmp_bl.append(&cmp_buffer[10], 4);
5491
5492 std::string write_buffer("Write this !!!");
5493 ceph::bufferlist write_bl;
5494 write_bl.append(&write_buffer[0], 6);
5495 write_bl.append(&write_buffer[6], 5);
5496 write_bl.append(&write_buffer[11], 3);
5497
5498 std::string mismatch_buffer("This will fail");
5499 ceph::bufferlist mismatch_bl;
5500 mismatch_bl.append(&mismatch_buffer[0], 5);
5501 mismatch_bl.append(&mismatch_buffer[5], 5);
5502 mismatch_bl.append(&mismatch_buffer[10], 4);
5503
5504 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5505 ASSERT_EQ(cmp_bl.length(), written);
5506
5507 /*
5508 * we allow cmp_bl and write_bl to be greater than len so this
5509 * should execute the compare but fail because of mismatch
5510 */
5511 uint64_t mismatch_off = 0;
5512 written = image.compare_and_write(off, cmp_bl.length() - 1,
5513 mismatch_bl, /* cmp_bl */
5514 write_bl,
5515 &mismatch_off, 0);
5516 ASSERT_EQ(-EILSEQ, written);
5517 ASSERT_EQ(5U, mismatch_off);
5518
5519 // check that nothing was written
5520 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
5521
5522 ASSERT_PASSED(validate_object_map, image);
5523 }
5524
5525 ioctx.close();
5526}
5527
5528TEST_F(TestLibRBD, TestAioCompareAndWriteMismatchBufferlistGreaterLenPP)
5529{
5530 librados::IoCtx ioctx;
5531 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5532
5533 {
5534 librbd::RBD rbd;
5535 librbd::Image image;
5536 int order = 0;
5537 std::string name = get_temp_image_name();
5538 uint64_t size = 20 << 20; /* 20MiB */
5539 off_t off = 512;
5540
5541 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5542 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5543
5544 std::string cmp_buffer("This is a test");
5545 ceph::bufferlist cmp_bl;
5546 cmp_bl.append(&cmp_buffer[0], 5);
5547 cmp_bl.append(&cmp_buffer[5], 3);
5548 cmp_bl.append(&cmp_buffer[8], 2);
5549 cmp_bl.append(&cmp_buffer[10], 4);
5550
5551 std::string write_buffer("Write this !!!");
5552 ceph::bufferlist write_bl;
5553 write_bl.append(&write_buffer[0], 6);
5554 write_bl.append(&write_buffer[6], 5);
5555 write_bl.append(&write_buffer[11], 3);
5556
5557 std::string mismatch_buffer("This will fail");
5558 ceph::bufferlist mismatch_bl;
5559 mismatch_bl.append(&mismatch_buffer[0], 5);
5560 mismatch_bl.append(&mismatch_buffer[5], 5);
5561 mismatch_bl.append(&mismatch_buffer[10], 4);
5562
5563 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5564 ASSERT_EQ(cmp_bl.length(), written);
5565
5566 /*
5567 * we allow cmp_bl and write_bl to be greater than len so this
5568 * should execute the compare but fail because of mismatch
5569 */
5570 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
5571 NULL, (librbd::callback_t) simple_write_cb_pp);
5572 uint64_t mismatch_off = 0;
5573 int ret = image.aio_compare_and_write(off, cmp_bl.length() - 1,
5574 mismatch_bl, /* cmp_bl */
5575 write_bl,
5576 comp, &mismatch_off, 0);
5577 ASSERT_EQ(0, ret);
5578 comp->wait_for_complete();
5579 ssize_t aio_ret = comp->get_return_value();
5580 ASSERT_EQ(-EILSEQ, aio_ret);
5581 ASSERT_EQ(5U, mismatch_off);
5582 comp->release();
5583
5584 // check that nothing was written
5585 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
5586
5587 ASSERT_PASSED(validate_object_map, image);
5588 }
5589
5590 ioctx.close();
5591}
5592
5593TEST_F(TestLibRBD, TestCompareAndWriteSuccessPP)
5594{
5595 librados::IoCtx ioctx;
5596 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5597
5598 {
5599 librbd::RBD rbd;
5600 librbd::Image image;
5601 int order = 0;
5602 std::string name = get_temp_image_name();
5603 uint64_t size = 20 << 20; /* 20MiB */
5604 off_t off = 512;
5605
5606 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5607 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5608
5609 std::string cmp_buffer("This is a test");
5610 ceph::bufferlist cmp_bl;
5611 cmp_bl.append(&cmp_buffer[0], 5);
5612 cmp_bl.append(&cmp_buffer[5], 3);
5613 cmp_bl.append(&cmp_buffer[8], 2);
5614 cmp_bl.append(&cmp_buffer[10], 4);
5615
5616 std::string write_buffer("Write this !!!");
5617 ceph::bufferlist write_bl;
5618 write_bl.append(&write_buffer[0], 6);
5619 write_bl.append(&write_buffer[6], 5);
5620 write_bl.append(&write_buffer[11], 3);
5621
5622 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5623 ASSERT_EQ(cmp_bl.length(), written);
5624
5625 // compare against the buffer written before => should succeed
5626 uint64_t mismatch_off = 0;
5627 written = image.compare_and_write(off, cmp_bl.length(),
5628 cmp_bl,
5629 write_bl,
5630 &mismatch_off, 0);
5631 ASSERT_EQ(write_bl.length(), written);
5632 ASSERT_EQ(0U, mismatch_off);
5633
5634 // check write_bl was written
5635 ASSERT_PASSED(compare_written, image, off, write_bl.length(), write_buffer);
5636
5637 ASSERT_PASSED(validate_object_map, image);
5638 }
5639
5640 ioctx.close();
5641}
5642
5643TEST_F(TestLibRBD, TestAioCompareAndWriteSuccessPP)
5644{
5645 librados::IoCtx ioctx;
5646 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5647
5648 {
5649 librbd::RBD rbd;
5650 librbd::Image image;
5651 int order = 0;
5652 std::string name = get_temp_image_name();
5653 uint64_t size = 20 << 20; /* 20MiB */
5654 off_t off = 512;
5655
5656 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5657 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5658
5659 std::string cmp_buffer("This is a test");
5660 ceph::bufferlist cmp_bl;
5661 cmp_bl.append(&cmp_buffer[0], 5);
5662 cmp_bl.append(&cmp_buffer[5], 3);
5663 cmp_bl.append(&cmp_buffer[8], 2);
5664 cmp_bl.append(&cmp_buffer[10], 4);
5665
5666 std::string write_buffer("Write this !!!");
5667 ceph::bufferlist write_bl;
5668 write_bl.append(&write_buffer[0], 6);
5669 write_bl.append(&write_buffer[6], 5);
5670 write_bl.append(&write_buffer[11], 3);
5671
5672 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
5673 ASSERT_EQ(cmp_bl.length(), written);
5674
5675 // compare against the buffer written before => should succeed
5676 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
5677 NULL, (librbd::callback_t) simple_write_cb_pp);
5678 uint64_t mismatch_off = 0;
5679 int ret = image.aio_compare_and_write(off, write_bl.length(),
5680 cmp_bl,
5681 write_bl,
5682 comp, &mismatch_off, 0);
5683 ASSERT_EQ(0, ret);
5684 comp->wait_for_complete();
5685 ssize_t aio_ret = comp->get_return_value();
5686 ASSERT_EQ(0, aio_ret);
5687 ASSERT_EQ(0U, mismatch_off);
5688 comp->release();
5689
5690 // check write_bl was written
5691 ASSERT_PASSED(compare_written, image, off, write_bl.length(), write_buffer);
5692
5693 ASSERT_PASSED(validate_object_map, image);
5694 }
5695
5696 ioctx.close();
5697}
5698
5699TEST_F(TestLibRBD, TestCompareAndWriteSuccessBufferlistGreaterLenPP)
5700{
5701 librados::IoCtx ioctx;
5702 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5703
5704 {
5705 librbd::RBD rbd;
5706 librbd::Image image;
5707 int order = 0;
5708 std::string name = get_temp_image_name();
5709 uint64_t size = 20 << 20; /* 20MiB */
5710 off_t off = 512;
5711
5712 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5713 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5714
5715 std::string cmp_buffer("This is a test");
5716 ceph::bufferlist cmp_bl;
5717 cmp_bl.append(&cmp_buffer[0], 5);
5718 cmp_bl.append(&cmp_buffer[5], 3);
5719 cmp_bl.append(&cmp_buffer[8], 2);
5720 cmp_bl.append(&cmp_buffer[10], 4);
5721
5722 std::string write_buffer("Write this !!!");
5723 ceph::bufferlist write_bl;
5724 write_bl.append(&write_buffer[0], 6);
5725 write_bl.append(&write_buffer[6], 5);
5726 write_bl.append(&write_buffer[11], 3);
5727
5728 std::string mismatch_buffer("This will fail");
5729 ceph::bufferlist mismatch_bl;
5730 mismatch_bl.append(&mismatch_buffer[0], 5);
5731 mismatch_bl.append(&mismatch_buffer[5], 5);
5732 mismatch_bl.append(&mismatch_buffer[10], 4);
5733
5734 /*
5735 * Test len < cmp_bl & write_bl => should succeed but only compare
5736 * len bytes resp. only write len bytes
5737 */
5738 ssize_t written = image.write(off, mismatch_bl.length(), mismatch_bl);
5739 ASSERT_EQ(mismatch_bl.length(), written);
5740
5741 size_t len_m1 = cmp_bl.length() - 1;
5742 written = image.write(off, len_m1, cmp_bl);
5743 ASSERT_EQ(len_m1, written);
5744 // the content of the image at off should now be "This is a tesl"
5745
5746 uint64_t mismatch_off = 0;
5747 written = image.compare_and_write(off, len_m1,
5748 cmp_bl,
5749 write_bl,
5750 &mismatch_off, 0);
5751 ASSERT_EQ(len_m1, written);
5752 ASSERT_EQ(0U, mismatch_off);
5753
5754 // check that only write_bl.length() - 1 bytes were written
5755 ASSERT_PASSED(compare_written, image, off, len_m1, write_buffer);
5756 ASSERT_PASSED(compare_written, image, off + len_m1, 1, std::string("l"));
5757
5758 ASSERT_PASSED(validate_object_map, image);
5759 }
5760
5761 ioctx.close();
5762}
5763
5764TEST_F(TestLibRBD, TestAioCompareAndWriteSuccessBufferlistGreaterLenPP)
5765{
5766 librados::IoCtx ioctx;
5767 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5768
5769 {
5770 librbd::RBD rbd;
5771 librbd::Image image;
5772 int order = 0;
5773 std::string name = get_temp_image_name();
5774 uint64_t size = 20 << 20; /* 20MiB */
5775 off_t off = 512;
5776
5777 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5778 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5779
5780 std::string cmp_buffer("This is a test");
5781 ceph::bufferlist cmp_bl;
5782 cmp_bl.append(&cmp_buffer[0], 5);
5783 cmp_bl.append(&cmp_buffer[5], 3);
5784 cmp_bl.append(&cmp_buffer[8], 2);
5785 cmp_bl.append(&cmp_buffer[10], 4);
5786
5787 std::string write_buffer("Write this !!!");
5788 ceph::bufferlist write_bl;
5789 write_bl.append(&write_buffer[0], 6);
5790 write_bl.append(&write_buffer[6], 5);
5791 write_bl.append(&write_buffer[11], 3);
5792
5793 std::string mismatch_buffer("This will fail");
5794 ceph::bufferlist mismatch_bl;
5795 mismatch_bl.append(&mismatch_buffer[0], 5);
5796 mismatch_bl.append(&mismatch_buffer[5], 5);
5797 mismatch_bl.append(&mismatch_buffer[10], 4);
5798
39ae355f
TL
5799 /*
5800 * Test len < cmp_bl & write_bl => should succeed but only compare
5801 * len bytes resp. only write len bytes
5802 */
1e59de90 5803 ssize_t written = image.write(off, mismatch_bl.length(), mismatch_bl);
39ae355f
TL
5804 ASSERT_EQ(mismatch_bl.length(), written);
5805
5806 size_t len_m1 = cmp_bl.length() - 1;
5807 written = image.write(off, len_m1, cmp_bl);
5808 ASSERT_EQ(len_m1, written);
5809 // the content of the image at off should now be "This is a tesl"
5810
5811 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
5812 NULL, (librbd::callback_t) simple_write_cb_pp);
5813 uint64_t mismatch_off = 0;
5814 int ret = image.aio_compare_and_write(off, len_m1,
5815 cmp_bl,
5816 write_bl,
5817 comp, &mismatch_off, 0);
5818 ASSERT_EQ(0, ret);
5819 comp->wait_for_complete();
5820 ssize_t aio_ret = comp->get_return_value();
5821 ASSERT_EQ(0, aio_ret);
5822 ASSERT_EQ(0U, mismatch_off);
7c673cae 5823 comp->release();
7c673cae 5824
39ae355f
TL
5825 // check that only write_bl.length() - 1 bytes were written
5826 ASSERT_PASSED(compare_written, image, off, len_m1, write_buffer);
5827 ASSERT_PASSED(compare_written, image, off + len_m1, 1, std::string("l"));
7c673cae 5828
39ae355f 5829 ASSERT_PASSED(validate_object_map, image);
7c673cae 5830 }
7c673cae 5831
39ae355f 5832 ioctx.close();
7c673cae
FG
5833}
5834
39ae355f 5835TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitUnalignedPP)
7c673cae 5836{
39ae355f
TL
5837 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
5838
5839 librados::IoCtx ioctx;
5840 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5841
5842 {
5843 librbd::RBD rbd;
5844 librbd::Image image;
5845 int order = 0;
5846 std::string name = get_temp_image_name();
5847 uint64_t size = 20 << 20; /* 20MiB */
5848
5849 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5850 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5851
5852 // large write test => we allow stripe unit size writes (aligned)
5853 uint64_t stripe_unit = image.get_stripe_unit();
5854 std::string large_write_buffer(stripe_unit, '2');
5855 ceph::bufferlist large_write_bl;
5856 large_write_bl.append(large_write_buffer.data(),
5857 large_write_buffer.length());
5858
5859 std::string large_cmp_buffer(stripe_unit * 2, '3');
5860 ceph::bufferlist large_cmp_bl;
5861 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
5862
5863 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
5864 large_cmp_bl);
5865 ASSERT_EQ(large_cmp_bl.length(), written);
5866
5867 /*
5868 * compare and write at offset stripe_unit + 1 and stripe unit size
5869 * Expect fail because access exceeds stripe
5870 */
5871 uint64_t mismatch_off = 0;
5872 written = image.compare_and_write(stripe_unit + 1, stripe_unit,
5873 large_cmp_bl,
5874 large_write_bl,
5875 &mismatch_off, 0);
7c673cae 5876 ASSERT_EQ(-EINVAL, written);
39ae355f 5877 ASSERT_EQ(0U, mismatch_off);
7c673cae 5878
39ae355f
TL
5879 // check nothing has been written
5880 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
5881 large_cmp_buffer);
5882
5883 ASSERT_PASSED(validate_object_map, image);
7c673cae 5884 }
7c673cae 5885
39ae355f 5886 ioctx.close();
7c673cae
FG
5887}
5888
39ae355f 5889TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitUnalignedPP)
c07f9fc5 5890{
39ae355f 5891 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
c07f9fc5 5892
39ae355f
TL
5893 librados::IoCtx ioctx;
5894 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5895
5896 {
5897 librbd::RBD rbd;
5898 librbd::Image image;
5899 int order = 0;
5900 std::string name = get_temp_image_name();
5901 uint64_t size = 20 << 20; /* 20MiB */
5902
5903 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5904 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5905
5906 // large write test => we allow stripe unit size writes (aligned)
5907 uint64_t stripe_unit = image.get_stripe_unit();
5908 std::string large_write_buffer(stripe_unit, '2');
5909 ceph::bufferlist large_write_bl;
5910 large_write_bl.append(large_write_buffer.data(),
5911 large_write_buffer.length());
5912
5913 std::string large_cmp_buffer(stripe_unit * 2, '3');
5914 ceph::bufferlist large_cmp_bl;
5915 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
5916
5917 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
5918 large_cmp_bl);
5919 ASSERT_EQ(large_cmp_bl.length(), written);
5920
5921 /*
5922 * compare and write at offset stripe_unit + 1 and stripe unit size
5923 * Expect fail because access exceeds stripe
5924 */
5925 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
5926 NULL, (librbd::callback_t) simple_write_cb_pp);
5927 uint64_t mismatch_off = 0;
5928 int ret = image.aio_compare_and_write(stripe_unit + 1, stripe_unit,
5929 large_cmp_bl,
5930 large_write_bl,
5931 comp, &mismatch_off, 0);
5932 ASSERT_EQ(0, ret);
5933 comp->wait_for_complete();
5934 ssize_t aio_ret = comp->get_return_value();
5935 ASSERT_EQ(-EINVAL, aio_ret);
5936 ASSERT_EQ(0U, mismatch_off);
5937 comp->release();
5938
5939 // check nothing has been written
5940 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
5941 large_cmp_buffer);
5942
5943 ASSERT_PASSED(validate_object_map, image);
5944 }
5945
5946 ioctx.close();
c07f9fc5
FG
5947}
5948
39ae355f 5949TEST_F(TestLibRBD, TestCompareAndWriteTooLargePP)
c07f9fc5 5950{
39ae355f
TL
5951 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
5952
5953 librados::IoCtx ioctx;
5954 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5955
5956 {
5957 librbd::RBD rbd;
5958 librbd::Image image;
5959 int order = 0;
5960 std::string name = get_temp_image_name();
5961 uint64_t size = 20 << 20; /* 20MiB */
5962
5963 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5964 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5965
5966 // large write test => we allow stripe unit size writes (aligned)
5967 uint64_t stripe_unit = image.get_stripe_unit();
5968 std::string large_write_buffer(stripe_unit * 2, '2');
5969 ceph::bufferlist large_write_bl;
5970 large_write_bl.append(large_write_buffer.data(),
5971 large_write_buffer.length());
5972
5973 std::string large_cmp_buffer(stripe_unit * 2, '3');
5974 ceph::bufferlist large_cmp_bl;
5975 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
5976
5977 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
5978 large_cmp_bl);
5979 ASSERT_EQ(large_cmp_bl.length(), written);
5980
5981 /*
5982 * compare and write at offset stripe_unit and stripe unit size + 1
5983 * Expect fail because access is larger than stripe unit size
5984 */
5985 uint64_t mismatch_off = 0;
5986 written = image.compare_and_write(stripe_unit, stripe_unit + 1,
5987 large_cmp_bl,
5988 large_write_bl,
5989 &mismatch_off, 0);
5990 ASSERT_EQ(-EINVAL, written);
5991 ASSERT_EQ(0U, mismatch_off);
5992
5993 // check nothing has been written
5994 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
5995 large_cmp_buffer);
5996
5997 ASSERT_PASSED(validate_object_map, image);
5998 }
5999
6000 ioctx.close();
c07f9fc5
FG
6001}
6002
39ae355f 6003TEST_F(TestLibRBD, TestAioCompareAndWriteTooLargePP)
7c673cae 6004{
39ae355f
TL
6005 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
6006
7c673cae
FG
6007 librados::IoCtx ioctx;
6008 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6009
7c673cae
FG
6010 {
6011 librbd::RBD rbd;
6012 librbd::Image image;
6013 int order = 0;
6014 std::string name = get_temp_image_name();
39ae355f 6015 uint64_t size = 20 << 20; /* 20MiB */
7c673cae
FG
6016
6017 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6018 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6019
39ae355f
TL
6020 // large write test => we allow stripe unit size writes (aligned)
6021 uint64_t stripe_unit = image.get_stripe_unit();
6022 std::string large_write_buffer(stripe_unit * 2, '2');
6023 ceph::bufferlist large_write_bl;
6024 large_write_bl.append(large_write_buffer.data(),
6025 large_write_buffer.length());
6026
6027 std::string large_cmp_buffer(stripe_unit * 2, '3');
6028 ceph::bufferlist large_cmp_bl;
6029 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
6030
6031 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
6032 large_cmp_bl);
6033 ASSERT_EQ(large_cmp_bl.length(), written);
6034
6035 /*
6036 * compare and write at offset stripe_unit and stripe unit size + 1
6037 * Expect fail because access is larger than stripe unit size
6038 */
6039 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
6040 NULL, (librbd::callback_t) simple_write_cb_pp);
6041 uint64_t mismatch_off = 0;
6042 int ret = image.aio_compare_and_write(stripe_unit, stripe_unit + 1,
6043 large_cmp_bl,
6044 large_write_bl,
6045 comp, &mismatch_off, 0);
6046 ASSERT_EQ(0, ret);
6047 comp->wait_for_complete();
6048 ssize_t aio_ret = comp->get_return_value();
6049 ASSERT_EQ(-EINVAL, aio_ret);
6050 ASSERT_EQ(0U, mismatch_off);
6051 comp->release();
f67539c2 6052
39ae355f
TL
6053 // check nothing has been written
6054 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
6055 large_cmp_buffer);
7c673cae 6056
39ae355f
TL
6057 ASSERT_PASSED(validate_object_map, image);
6058 }
7c673cae 6059
39ae355f
TL
6060 ioctx.close();
6061}
7c673cae 6062
39ae355f
TL
6063TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitSuccessPP)
6064{
6065 librados::IoCtx ioctx;
6066 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 6067
39ae355f
TL
6068 {
6069 librbd::RBD rbd;
6070 librbd::Image image;
6071 int order = 0;
6072 std::string name = get_temp_image_name();
6073 uint64_t size = 20 << 20; /* 20MiB */
c07f9fc5 6074
39ae355f
TL
6075 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6076 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
c07f9fc5 6077
39ae355f
TL
6078 // large write test => we allow stripe unit size writes (aligned)
6079 uint64_t stripe_unit = image.get_stripe_unit();
6080 std::string large_write_buffer(stripe_unit * 2, '2');
6081 ceph::bufferlist large_write_bl;
6082 large_write_bl.append(large_write_buffer.data(),
6083 large_write_buffer.length());
6084
6085 std::string large_cmp_buffer(stripe_unit * 2, '3');
6086 ceph::bufferlist large_cmp_bl;
6087 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
6088
6089 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
6090 large_cmp_bl);
6091 ASSERT_EQ(large_cmp_bl.length(), written);
6092
6093 // aligned stripe unit size access => expect success
6094 uint64_t mismatch_off = 0;
6095 written = image.compare_and_write(stripe_unit, stripe_unit,
6096 large_cmp_bl,
6097 large_write_bl,
6098 &mismatch_off, 0);
6099 ASSERT_EQ(stripe_unit, written);
6100 ASSERT_EQ(0U, mismatch_off);
6101
6102 // check large_write_bl was written and nothing beyond
6103 ASSERT_PASSED(compare_written, image, stripe_unit, stripe_unit,
6104 large_write_buffer);
6105 ASSERT_PASSED(compare_written, image, stripe_unit * 2, stripe_unit,
6106 large_cmp_buffer);
7c673cae 6107
39ae355f
TL
6108 ASSERT_PASSED(validate_object_map, image);
6109 }
7c673cae 6110
39ae355f
TL
6111 ioctx.close();
6112}
7c673cae 6113
39ae355f
TL
6114TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitSuccessPP)
6115{
6116 librados::IoCtx ioctx;
6117 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 6118
39ae355f
TL
6119 {
6120 librbd::RBD rbd;
6121 librbd::Image image;
6122 int order = 0;
6123 std::string name = get_temp_image_name();
6124 uint64_t size = 20 << 20; /* 20MiB */
6125
6126 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6127 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6128
6129 // large write test => we allow stripe unit size writes (aligned)
6130 uint64_t stripe_unit = image.get_stripe_unit();
6131 std::string large_write_buffer(stripe_unit * 2, '2');
6132 ceph::bufferlist large_write_bl;
6133 large_write_bl.append(large_write_buffer.data(),
6134 large_write_buffer.length());
6135
6136 std::string large_cmp_buffer(stripe_unit * 2, '3');
6137 ceph::bufferlist large_cmp_bl;
6138 large_cmp_bl.append(large_cmp_buffer.data(),
6139 large_cmp_buffer.length());
6140
6141 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
6142 large_cmp_bl);
6143 ASSERT_EQ(large_cmp_bl.length(), written);
6144
6145 // aligned stripe unit size access => expect success
6146 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
6147 NULL, (librbd::callback_t) simple_write_cb_pp);
6148 uint64_t mismatch_off = 0;
6149 int ret = image.aio_compare_and_write(stripe_unit, stripe_unit,
6150 large_cmp_bl,
6151 large_write_bl,
6152 comp, &mismatch_off, 0);
6153 ASSERT_EQ(0, ret);
6154 comp->wait_for_complete();
6155 ssize_t aio_ret = comp->get_return_value();
6156 ASSERT_EQ(0, aio_ret);
6157 ASSERT_EQ(0U, mismatch_off);
6158 comp->release();
6159
6160 // check large_write_bl was written and nothing beyond
6161 ASSERT_PASSED(compare_written, image, stripe_unit, stripe_unit,
6162 large_write_buffer);
6163 ASSERT_PASSED(compare_written, image, stripe_unit * 2, stripe_unit,
6164 large_cmp_buffer);
7c673cae
FG
6165
6166 ASSERT_PASSED(validate_object_map, image);
6167 }
6168
6169 ioctx.close();
6170}
6171
6172TEST_F(TestLibRBD, TestIOPPWithIOHint)
6173{
6174 librados::IoCtx ioctx;
6175 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6176
6177 {
6178 librbd::RBD rbd;
6179 librbd::Image image;
6180 int order = 0;
6181 std::string name = get_temp_image_name();
6182 uint64_t size = 2 << 20;
6183
6184 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6185 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6186
6187 char test_data[TEST_IO_SIZE + 1];
6188 char zero_data[TEST_IO_SIZE + 1];
6189 test_data[TEST_IO_SIZE] = '\0';
6190 int i;
6191
6192 for (i = 0; i < TEST_IO_SIZE; ++i) {
6193 test_data[i] = (char) (rand() % (126 - 33) + 33);
6194 }
6195 memset(zero_data, 0, sizeof(zero_data));
6196
6197 for (i = 0; i < 5; ++i)
6198 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i,
6199 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
6200
6201 for (i = 5; i < 10; ++i)
6202 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i,
6203 LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6204
6205 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data),
6206 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_RANDOM);
6207
6208 for (i = 5; i < 10; ++i)
6209 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i,
6210 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6211
6212 for (i = 0; i < 15; ++i) {
6213 if (i % 3 == 2) {
6214 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
6215 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
6216 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
6217 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
6218 } else if (i % 3 == 1) {
6219 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
6220 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
6221 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
6222 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
6223 } else {
6224 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
6225 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
6226 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
6227 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
6228 }
6229 }
6230 for (i = 0; i < 15; ++i) {
6231 if (i % 3 == 2) {
6232 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
6233 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6234 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
6235 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6236 } else if (i % 3 == 1) {
6237 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i,
6238 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6239 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
6240 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6241 } else {
6242 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
6243 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6244 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
6245 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
6246 }
6247 }
6248
6249 ASSERT_PASSED(validate_object_map, image);
6250 }
6251
6252 ioctx.close();
6253}
6254
6255
6256
6257TEST_F(TestLibRBD, TestIOToSnapshot)
6258{
6259 rados_ioctx_t ioctx;
6260 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6261
6262 rbd_image_t image;
6263 int order = 0;
6264 std::string name = get_temp_image_name();
6265 uint64_t isize = 2 << 20;
6266
6267 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
6268 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6269
6270 int i, r;
6271 rbd_image_t image_at_snap;
6272 char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
6273 char test_data[TEST_IO_TO_SNAP_SIZE + 1];
6274
6275 for (i = 0; i < TEST_IO_TO_SNAP_SIZE; ++i)
6276 test_data[i] = (char) (i + 48);
6277 test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
6278 orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
6279
6280 r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
6281 ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE);
6282
6283 ASSERT_EQ(0, test_ls_snaps(image, 0));
6284 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
6285 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
6286 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6287
6288 printf("write test data!\n");
6289 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6290 ASSERT_EQ(0, rbd_snap_create(image, "written"));
6291 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
6292
6293 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6294
6295 rbd_snap_set(image, "orig");
6296 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6297
6298 rbd_snap_set(image, "written");
6299 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6300
6301 rbd_snap_set(image, "orig");
6302
6303 r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
6304 printf("write to snapshot returned %d\n", r);
6305 ASSERT_LT(r, 0);
31f18b77 6306 cout << strerror(-r) << std::endl;
7c673cae
FG
6307
6308 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6309 rbd_snap_set(image, "written");
6310 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6311
6312 r = rbd_snap_rollback(image, "orig");
6313 ASSERT_EQ(r, -EROFS);
6314
6315 r = rbd_snap_set(image, NULL);
6316 ASSERT_EQ(r, 0);
6317 r = rbd_snap_rollback(image, "orig");
6318 ASSERT_EQ(r, 0);
6319
6320 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6321
6322 rbd_flush(image);
6323
6324 printf("opening testimg@orig\n");
6325 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_at_snap, "orig"));
6326 ASSERT_PASSED(read_test_data, image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
6327 r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
6328 printf("write to snapshot returned %d\n", r);
6329 ASSERT_LT(r, 0);
31f18b77 6330 cout << strerror(-r) << std::endl;
7c673cae
FG
6331 ASSERT_EQ(0, rbd_close(image_at_snap));
6332
f67539c2
TL
6333 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
6334 ASSERT_EQ(0, rbd_snap_remove(image, "written"));
6335 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
6336 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
6337 ASSERT_EQ(0, test_ls_snaps(image, 0));
6338
6339 ASSERT_PASSED(validate_object_map, image);
6340 ASSERT_EQ(0, rbd_close(image));
6341
6342 rados_ioctx_destroy(ioctx);
6343}
6344
6345TEST_F(TestLibRBD, TestSnapshotDeletedIo)
6346{
6347 rados_ioctx_t ioctx;
6348 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6349
6350 rbd_image_t image;
6351 int order = 0;
6352 std::string name = get_temp_image_name();
6353 uint64_t isize = 2 << 20;
6354
6355 int r;
6356
6357 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
6358 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6359 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
6360
6361 r = rbd_snap_set(image, "orig");
6362 ASSERT_EQ(r, 0);
6363
7c673cae 6364 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
f67539c2
TL
6365 char test[20];
6366 ASSERT_EQ(-ENOENT, rbd_read(image, 20, 20, test));
7c673cae 6367
f67539c2
TL
6368 r = rbd_snap_set(image, NULL);
6369 ASSERT_EQ(r, 0);
7c673cae 6370
f67539c2 6371 ASSERT_EQ(0, rbd_close(image));
7c673cae
FG
6372 rados_ioctx_destroy(ioctx);
6373}
6374
6375TEST_F(TestLibRBD, TestClone)
6376{
6377 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11fdf7f2
TL
6378 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "1"));
6379 BOOST_SCOPE_EXIT_ALL(&) {
6380 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
6381 };
7c673cae
FG
6382
6383 rados_ioctx_t ioctx;
6384 rbd_image_info_t pinfo, cinfo;
6385 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6386
6387 bool old_format;
6388 uint64_t features;
6389 rbd_image_t parent, child;
6390 int order = 0;
6391
6392 ASSERT_EQ(0, get_features(&old_format, &features));
6393 ASSERT_FALSE(old_format);
6394
6395 std::string parent_name = get_temp_image_name();
6396 std::string child_name = get_temp_image_name();
6397
6398 // make a parent to clone from
6399 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
6400 false, features));
6401 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
6402 printf("made parent image \"parent\"\n");
6403
6404 char *data = (char *)"testdata";
6405 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
6406
6407 // can't clone a non-snapshot, expect failure
6408 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
6409 child_name.c_str(), features, &order));
6410
6411 // verify that there is no parent info on "parent"
6412 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
6413 printf("parent has no parent info\n");
6414
b32b8144
FG
6415 // create 70 metadatas to verify we can clone all key/value pairs
6416 std::string key;
6417 std::string val;
6418 size_t sum_key_len = 0;
6419 size_t sum_value_len = 0;
6420 for (int i = 1; i <= 70; i++) {
6421 key = "key" + stringify(i);
6422 val = "value" + stringify(i);
6423 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
6424
6425 sum_key_len += (key.size() + 1);
6426 sum_value_len += (val.size() + 1);
6427 }
6428
6429 char keys[1024];
6430 char vals[1024];
6431 size_t keys_len = sizeof(keys);
6432 size_t vals_len = sizeof(vals);
6433
6434 char value[1024];
6435 size_t value_len = sizeof(value);
6436
7c673cae
FG
6437 // create a snapshot, reopen as the parent we're interested in
6438 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
6439 printf("made snapshot \"parent@parent_snap\"\n");
6440 ASSERT_EQ(0, rbd_close(parent));
6441 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
6442
6443 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
6444 ioctx, child_name.c_str(), features, &order));
6445
6446 // unprotected image should fail unprotect
6447 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
6448 printf("can't unprotect an unprotected snap\n");
6449
6450 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
6451 // protecting again should fail
6452 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
6453 printf("can't protect a protected snap\n");
6454
6455 // This clone and open should work
6456 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
6457 ioctx, child_name.c_str(), features, &order));
6458 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
6459 printf("made and opened clone \"child\"\n");
6460
6461 // check read
6462 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
6463
6464 // check write
6465 ASSERT_EQ((ssize_t)strlen(data), rbd_write(child, 20, strlen(data), data));
6466 ASSERT_PASSED(read_test_data, child, data, 20, strlen(data), 0);
6467 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
6468
6469 // check attributes
6470 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
6471 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
6472 EXPECT_EQ(cinfo.size, pinfo.size);
6473 uint64_t overlap;
6474 rbd_get_overlap(child, &overlap);
6475 EXPECT_EQ(overlap, pinfo.size);
6476 EXPECT_EQ(cinfo.obj_size, pinfo.obj_size);
6477 EXPECT_EQ(cinfo.order, pinfo.order);
6478 printf("sizes and overlaps are good between parent and child\n");
6479
b32b8144 6480 // check key/value pairs in child image
f67539c2 6481 ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
b32b8144
FG
6482 &vals_len));
6483 ASSERT_EQ(sum_key_len, keys_len);
6484 ASSERT_EQ(sum_value_len, vals_len);
6485
6486 for (int i = 1; i <= 70; i++) {
6487 key = "key" + stringify(i);
6488 val = "value" + stringify(i);
6489 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
6490 ASSERT_STREQ(val.c_str(), value);
6491
6492 value_len = sizeof(value);
6493 }
6494 printf("child image successfully cloned all image-meta pairs\n");
6495
7c673cae
FG
6496 // sizing down child results in changing overlap and size, not parent size
6497 ASSERT_EQ(0, rbd_resize(child, 2UL<<20));
6498 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
6499 rbd_get_overlap(child, &overlap);
6500 ASSERT_EQ(overlap, 2UL<<20);
6501 ASSERT_EQ(cinfo.size, 2UL<<20);
6502 ASSERT_EQ(0, rbd_resize(child, 4UL<<20));
6503 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
6504 rbd_get_overlap(child, &overlap);
6505 ASSERT_EQ(overlap, 2UL<<20);
6506 ASSERT_EQ(cinfo.size, 4UL<<20);
6507 printf("sized down clone, changed overlap\n");
6508
6509 // sizing back up doesn't change that
6510 ASSERT_EQ(0, rbd_resize(child, 5UL<<20));
6511 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
6512 rbd_get_overlap(child, &overlap);
6513 ASSERT_EQ(overlap, 2UL<<20);
6514 ASSERT_EQ(cinfo.size, 5UL<<20);
6515 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
11fdf7f2 6516 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
7c673cae
FG
6517 (unsigned long long)pinfo.size, (unsigned long long)pinfo.obj_size,
6518 (unsigned long long)pinfo.parent_pool);
6519 ASSERT_EQ(pinfo.size, 4UL<<20);
6520 printf("sized up clone, changed size but not overlap or parent's size\n");
6521
6522 ASSERT_PASSED(validate_object_map, child);
6523 ASSERT_EQ(0, rbd_close(child));
6524
6525 ASSERT_PASSED(validate_object_map, parent);
6526 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
6527 printf("can't remove parent while child still exists\n");
6528 ASSERT_EQ(0, rbd_remove(ioctx, child_name.c_str()));
6529 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
6530 printf("can't remove parent while still protected\n");
6531 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
6532 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
6533 printf("removed parent snap after unprotecting\n");
6534
6535 ASSERT_EQ(0, rbd_close(parent));
6536 rados_ioctx_destroy(ioctx);
6537}
6538
6539TEST_F(TestLibRBD, TestClone2)
6540{
6541 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11fdf7f2
TL
6542 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
6543 BOOST_SCOPE_EXIT_ALL(&) {
6544 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
6545 };
7c673cae
FG
6546
6547 rados_ioctx_t ioctx;
6548 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6549
6550 bool old_format;
6551 uint64_t features;
6552 rbd_image_t parent, child;
6553 int order = 0;
6554
6555 ASSERT_EQ(0, get_features(&old_format, &features));
6556 ASSERT_FALSE(old_format);
6557
6558 std::string parent_name = get_temp_image_name();
6559 std::string child_name = get_temp_image_name();
6560
6561 // make a parent to clone from
6562 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
6563 false, features));
6564 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
6565 printf("made parent image \"parent\"\n");
6566
6567 char *data = (char *)"testdata";
6568 char *childata = (char *)"childata";
6569 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
6570 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
6571
6572 // can't clone a non-snapshot, expect failure
6573 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
6574 child_name.c_str(), features, &order));
6575
6576 // verify that there is no parent info on "parent"
6577 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
6578 printf("parent has no parent info\n");
6579
b32b8144
FG
6580 // create 70 metadatas to verify we can clone all key/value pairs
6581 std::string key;
6582 std::string val;
6583 size_t sum_key_len = 0;
6584 size_t sum_value_len = 0;
6585 for (int i = 1; i <= 70; i++) {
6586 key = "key" + stringify(i);
6587 val = "value" + stringify(i);
6588 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
6589
6590 sum_key_len += (key.size() + 1);
6591 sum_value_len += (val.size() + 1);
6592 }
6593
6594 char keys[1024];
6595 char vals[1024];
6596 size_t keys_len = sizeof(keys);
6597 size_t vals_len = sizeof(vals);
6598
6599 char value[1024];
6600 size_t value_len = sizeof(value);
6601
7c673cae
FG
6602 // create a snapshot, reopen as the parent we're interested in
6603 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
6604 printf("made snapshot \"parent@parent_snap\"\n");
6605 ASSERT_EQ(0, rbd_close(parent));
6606 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
6607
7c673cae
FG
6608 // This clone and open should work
6609 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
6610 ioctx, child_name.c_str(), features, &order));
6611 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
6612 printf("made and opened clone \"child\"\n");
6613
b32b8144 6614 // check key/value pairs in child image
f67539c2 6615 ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
b32b8144
FG
6616 &vals_len));
6617 ASSERT_EQ(sum_key_len, keys_len);
6618 ASSERT_EQ(sum_value_len, vals_len);
6619
6620 for (int i = 1; i <= 70; i++) {
6621 key = "key" + stringify(i);
6622 val = "value" + stringify(i);
6623 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
6624 ASSERT_STREQ(val.c_str(), value);
6625
6626 value_len = sizeof(value);
6627 }
6628 printf("child image successfully cloned all image-meta pairs\n");
6629
7c673cae
FG
6630 // write something in
6631 ASSERT_EQ((ssize_t)strlen(childata), rbd_write(child, 20, strlen(childata), childata));
6632
6633 char test[strlen(data) * 2];
6634 ASSERT_EQ((ssize_t)strlen(data), rbd_read(child, 20, strlen(data), test));
6635 ASSERT_EQ(0, memcmp(test, childata, strlen(childata)));
6636
6637 // overlap
6638 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 20 - strlen(data), sizeof(test), test));
6639 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
6640 ASSERT_EQ(0, memcmp(test + strlen(data), childata, strlen(childata)));
6641
6642 // all parent
6643 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 0, sizeof(test), test));
6644 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
6645
6646 ASSERT_PASSED(validate_object_map, child);
6647 ASSERT_PASSED(validate_object_map, parent);
6648
11fdf7f2
TL
6649 rbd_snap_info_t snaps[2];
6650 int max_snaps = 2;
6651 ASSERT_EQ(1, rbd_snap_list(parent, snaps, &max_snaps));
6652 rbd_snap_list_end(snaps);
6653
6654 ASSERT_EQ(0, rbd_snap_remove_by_id(parent, snaps[0].id));
6655
6656 rbd_snap_namespace_type_t snap_namespace_type;
6657 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent, snaps[0].id,
6658 &snap_namespace_type));
6659 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH, snap_namespace_type);
6660
6661 char original_name[32];
6662 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent, snaps[0].id,
6663 original_name,
6664 sizeof(original_name)));
6665 ASSERT_EQ(0, strcmp("parent_snap", original_name));
6666
7c673cae
FG
6667 ASSERT_EQ(0, rbd_close(child));
6668 ASSERT_EQ(0, rbd_close(parent));
6669 rados_ioctx_destroy(ioctx);
6670}
6671
6672static void test_list_children(rbd_image_t image, ssize_t num_expected, ...)
6673{
6674 va_list ap;
6675 va_start(ap, num_expected);
6676 size_t pools_len = 100;
6677 size_t children_len = 100;
6678 char *pools = NULL;
6679 char *children = NULL;
6680 ssize_t num_children;
6681
6682 do {
6683 free(pools);
6684 free(children);
6685 pools = (char *) malloc(pools_len);
6686 children = (char *) malloc(children_len);
6687 num_children = rbd_list_children(image, pools, &pools_len,
6688 children, &children_len);
6689 } while (num_children == -ERANGE);
6690
6691 ASSERT_EQ(num_expected, num_children);
6692 for (ssize_t i = num_expected; i > 0; --i) {
6693 char *expected_pool = va_arg(ap, char *);
6694 char *expected_image = va_arg(ap, char *);
6695 char *pool = pools;
6696 char *image = children;
6697 bool found = 0;
6698 printf("\ntrying to find %s/%s\n", expected_pool, expected_image);
6699 for (ssize_t j = 0; j < num_children; ++j) {
6700 printf("checking %s/%s\n", pool, image);
6701 if (strcmp(expected_pool, pool) == 0 &&
6702 strcmp(expected_image, image) == 0) {
6703 printf("found child %s/%s\n\n", pool, image);
6704 found = 1;
6705 break;
6706 }
6707 pool += strlen(pool) + 1;
6708 image += strlen(image) + 1;
6709 if (j == num_children - 1) {
6710 ASSERT_EQ(pool - pools - 1, (ssize_t) pools_len);
6711 ASSERT_EQ(image - children - 1, (ssize_t) children_len);
6712 }
6713 }
6714 ASSERT_TRUE(found);
6715 }
6716 va_end(ap);
6717
6718 if (pools)
6719 free(pools);
6720 if (children)
6721 free(children);
6722}
6723
11fdf7f2 6724static void test_list_children2(rbd_image_t image, int num_expected, ...)
7c673cae 6725{
11fdf7f2
TL
6726 int num_children, i, j, max_size = 10;
6727 va_list ap;
6728 rbd_child_info_t children[max_size];
6729 num_children = rbd_list_children2(image, children, &max_size);
6730 printf("num children is: %d\nexpected: %d\n", num_children, num_expected);
7c673cae 6731
11fdf7f2
TL
6732 for (i = 0; i < num_children; i++) {
6733 printf("child: %s\n", children[i].image_name);
6734 }
7c673cae 6735
11fdf7f2
TL
6736 va_start(ap, num_expected);
6737 for (i = num_expected; i > 0; i--) {
6738 char *expected_id = va_arg(ap, char *);
6739 char *expected_pool = va_arg(ap, char *);
6740 char *expected_image = va_arg(ap, char *);
6741 bool expected_trash = va_arg(ap, int);
6742 bool found = false;
6743 for (j = 0; j < num_children; j++) {
6744 if (children[j].pool_name == NULL ||
6745 children[j].image_name == NULL ||
6746 children[j].image_id == NULL)
6747 continue;
6748 if (strcmp(children[j].image_id, expected_id) == 0 &&
6749 strcmp(children[j].pool_name, expected_pool) == 0 &&
6750 strcmp(children[j].image_name, expected_image) == 0 &&
6751 children[j].trash == expected_trash) {
6752 printf("found child %s/%s/%s\n\n", children[j].pool_name, children[j].image_name, children[j].image_id);
6753 rbd_list_child_cleanup(&children[j]);
6754 children[j].pool_name = NULL;
6755 children[j].image_name = NULL;
6756 children[j].image_id = NULL;
6757 found = true;
6758 break;
6759 }
6760 }
6761 EXPECT_TRUE(found);
6762 }
6763 va_end(ap);
6764
6765 for (i = 0; i < num_children; i++) {
6766 EXPECT_EQ((const char *)0, children[i].pool_name);
6767 EXPECT_EQ((const char *)0, children[i].image_name);
6768 EXPECT_EQ((const char *)0, children[i].image_id);
6769 }
6770}
6771
6772TEST_F(TestLibRBD, ListChildren)
6773{
6774 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6775
6776 librbd::RBD rbd;
6777 rados_ioctx_t ioctx1, ioctx2;
6778 string pool_name1 = create_pool(true);
6779 string pool_name2 = create_pool(true);
6780 ASSERT_NE("", pool_name2);
6781
6782 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
6783 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
6784
6785 rbd_image_t image1;
6786 rbd_image_t image2;
6787 rbd_image_t image3;
6788 rbd_image_t image4;
6789
6790 bool old_format;
6791 uint64_t features;
6792 rbd_image_t parent;
6793 int order = 0;
6794
6795 ASSERT_EQ(0, get_features(&old_format, &features));
6796 ASSERT_FALSE(old_format);
7c673cae
FG
6797
6798 std::string parent_name = get_temp_image_name();
6799 std::string child_name1 = get_temp_image_name();
6800 std::string child_name2 = get_temp_image_name();
6801 std::string child_name3 = get_temp_image_name();
6802 std::string child_name4 = get_temp_image_name();
6803
11fdf7f2
TL
6804 char child_id1[4096];
6805 char child_id2[4096];
6806 char child_id3[4096];
6807 char child_id4[4096];
6808
7c673cae
FG
6809 // make a parent to clone from
6810 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
6811 false, features));
6812 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
6813 // create a snapshot, reopen as the parent we're interested in
6814 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
6815 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
6816 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
6817
6818 ASSERT_EQ(0, rbd_close(parent));
6819 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
6820
6821 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
6822 ioctx2, child_name1.c_str(), features, &order));
11fdf7f2
TL
6823 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
6824 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
7c673cae 6825 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
11fdf7f2
TL
6826 test_list_children2(parent, 1,
6827 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
7c673cae
FG
6828
6829 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
6830 ioctx1, child_name2.c_str(), features, &order));
11fdf7f2
TL
6831 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
6832 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
7c673cae
FG
6833 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
6834 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
6835 test_list_children2(parent, 2,
6836 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
6837 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae
FG
6838
6839 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
6840 ioctx2, child_name3.c_str(), features, &order));
11fdf7f2
TL
6841 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
6842 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
7c673cae
FG
6843 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
6844 pool_name1.c_str(), child_name2.c_str(),
6845 pool_name2.c_str(), child_name3.c_str());
11fdf7f2
TL
6846 test_list_children2(parent, 3,
6847 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
6848 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
6849 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
6850
6851 librados::IoCtx ioctx3;
6852 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
6853 ASSERT_EQ(0, rbd_close(image3));
6854 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
6855 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
6856 pool_name1.c_str(), child_name2.c_str());
6857 test_list_children2(parent, 3,
6858 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
6859 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
6860 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
7c673cae
FG
6861
6862 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
6863 ioctx2, child_name4.c_str(), features, &order));
11fdf7f2
TL
6864 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
6865 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
6866 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
6867 pool_name1.c_str(), child_name2.c_str(),
6868 pool_name2.c_str(), child_name4.c_str());
6869 test_list_children2(parent, 4,
6870 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
6871 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
6872 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
6873 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
6874
6875 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
7c673cae
FG
6876 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
6877 pool_name1.c_str(), child_name2.c_str(),
6878 pool_name2.c_str(), child_name3.c_str(),
6879 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
6880 test_list_children2(parent, 4,
6881 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
6882 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
6883 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
6884 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 6885
11fdf7f2 6886 ASSERT_EQ(0, rbd_close(image1));
7c673cae
FG
6887 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
6888 test_list_children(parent, 3,
6889 pool_name1.c_str(), child_name2.c_str(),
6890 pool_name2.c_str(), child_name3.c_str(),
6891 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
6892 test_list_children2(parent, 3,
6893 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
6894 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
6895 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae
FG
6896
6897 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
6898 test_list_children(parent, 2,
6899 pool_name1.c_str(), child_name2.c_str(),
6900 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
6901 test_list_children2(parent, 2,
6902 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
6903 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 6904
11fdf7f2 6905 ASSERT_EQ(0, rbd_close(image4));
7c673cae
FG
6906 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
6907 test_list_children(parent, 1,
6908 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
6909 test_list_children2(parent, 1,
6910 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
6911
7c673cae 6912
11fdf7f2 6913 ASSERT_EQ(0, rbd_close(image2));
7c673cae
FG
6914 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
6915 test_list_children(parent, 0);
11fdf7f2 6916 test_list_children2(parent, 0);
7c673cae
FG
6917
6918 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
6919 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
6920 ASSERT_EQ(0, rbd_close(parent));
6921 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
6922 rados_ioctx_destroy(ioctx1);
6923 rados_ioctx_destroy(ioctx2);
6924}
6925
6926TEST_F(TestLibRBD, ListChildrenTiered)
6927{
1e59de90 6928 SKIP_IF_CRIMSON();
7c673cae
FG
6929 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6930
11fdf7f2 6931 librbd::RBD rbd;
94b18763 6932 string pool_name1 = create_pool(true);
7c673cae
FG
6933 string pool_name2 = create_pool(true);
6934 string pool_name3 = create_pool(true);
94b18763 6935 ASSERT_NE("", pool_name1);
7c673cae
FG
6936 ASSERT_NE("", pool_name2);
6937 ASSERT_NE("", pool_name3);
6938
6939 std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" +
6940 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\", \"force_nonempty\":\"\"}";
6941 char *cmd[1];
6942 cmd[0] = (char *)cmdstr.c_str();
6943 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
6944
6945 cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
6946 pool_name3 + "\", \"mode\":\"writeback\"}";
6947 cmd[0] = (char *)cmdstr.c_str();
6948 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
6949
6950 cmdstr = "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
6951 pool_name1 + "\", \"overlaypool\":\"" + pool_name3 + "\"}";
6952 cmd[0] = (char *)cmdstr.c_str();
6953 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
6954
6955 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
6956
6957 string parent_name = get_temp_image_name();
6958 string child_name1 = get_temp_image_name();
6959 string child_name2 = get_temp_image_name();
6960 string child_name3 = get_temp_image_name();
6961 string child_name4 = get_temp_image_name();
6962
11fdf7f2
TL
6963 char child_id1[4096];
6964 char child_id2[4096];
6965 char child_id3[4096];
6966 char child_id4[4096];
6967
6968 rbd_image_t image1;
6969 rbd_image_t image2;
6970 rbd_image_t image3;
6971 rbd_image_t image4;
6972
7c673cae
FG
6973 rados_ioctx_t ioctx1, ioctx2;
6974 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
6975 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
6976
6977 bool old_format;
6978 uint64_t features;
6979 rbd_image_t parent;
6980 int order = 0;
6981
6982 ASSERT_EQ(0, get_features(&old_format, &features));
6983 ASSERT_FALSE(old_format);
6984
6985 // make a parent to clone from
6986 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
6987 false, features));
6988 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
6989 // create a snapshot, reopen as the parent we're interested in
6990 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
6991 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
6992 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
6993
6994 ASSERT_EQ(0, rbd_close(parent));
6995 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
6996
6997 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
6998 ioctx2, child_name1.c_str(), features, &order));
11fdf7f2
TL
6999 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
7000 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
7c673cae 7001 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
11fdf7f2
TL
7002 test_list_children2(parent, 1,
7003 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
7c673cae
FG
7004
7005 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
7006 ioctx1, child_name2.c_str(), features, &order));
11fdf7f2
TL
7007 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
7008 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
7c673cae
FG
7009 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
7010 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
7011 test_list_children2(parent, 2,
7012 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
7013 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae
FG
7014
7015 // read from the cache to populate it
7016 rbd_image_t tier_image;
7017 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &tier_image, NULL));
7018 size_t len = 4 * 1024 * 1024;
7019 char* buf = (char*)malloc(len);
7020 ssize_t size = rbd_read(tier_image, 0, len, buf);
7021 ASSERT_GT(size, 0);
7022 free(buf);
7023 ASSERT_EQ(0, rbd_close(tier_image));
7024
7025 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
7026 ioctx2, child_name3.c_str(), features, &order));
11fdf7f2
TL
7027 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
7028 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
7c673cae
FG
7029 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
7030 pool_name1.c_str(), child_name2.c_str(),
7031 pool_name2.c_str(), child_name3.c_str());
11fdf7f2
TL
7032 test_list_children2(parent, 3,
7033 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
7034 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
7035 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
7036
7037 librados::IoCtx ioctx3;
7038 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
7039 ASSERT_EQ(0, rbd_close(image3));
7040 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
7041 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
7042 pool_name1.c_str(), child_name2.c_str());
7043 test_list_children2(parent, 3,
7044 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
7045 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
7046 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
7c673cae
FG
7047
7048 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
7049 ioctx2, child_name4.c_str(), features, &order));
11fdf7f2
TL
7050 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
7051 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
7052 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
7053 pool_name1.c_str(), child_name2.c_str(),
7054 pool_name2.c_str(), child_name4.c_str());
7055 test_list_children2(parent, 4,
7056 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
7057 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
7058 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
7059 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7060
7061 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
7c673cae
FG
7062 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
7063 pool_name1.c_str(), child_name2.c_str(),
7064 pool_name2.c_str(), child_name3.c_str(),
7065 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
7066 test_list_children2(parent, 4,
7067 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
7068 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
7069 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
7070 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 7071
11fdf7f2 7072 ASSERT_EQ(0, rbd_close(image1));
7c673cae
FG
7073 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
7074 test_list_children(parent, 3,
7075 pool_name1.c_str(), child_name2.c_str(),
7076 pool_name2.c_str(), child_name3.c_str(),
7077 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
7078 test_list_children2(parent, 3,
7079 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
7080 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
7081 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae
FG
7082
7083 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
7084 test_list_children(parent, 2,
7085 pool_name1.c_str(), child_name2.c_str(),
7086 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
7087 test_list_children2(parent, 2,
7088 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
7089 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 7090
11fdf7f2 7091 ASSERT_EQ(0, rbd_close(image4));
7c673cae
FG
7092 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
7093 test_list_children(parent, 1,
7094 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
7095 test_list_children2(parent, 1,
7096 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae 7097
11fdf7f2 7098 ASSERT_EQ(0, rbd_close(image2));
7c673cae
FG
7099 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
7100 test_list_children(parent, 0);
11fdf7f2 7101 test_list_children2(parent, 0);
7c673cae
FG
7102
7103 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
7104 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
7105 ASSERT_EQ(0, rbd_close(parent));
7106 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
7107 rados_ioctx_destroy(ioctx1);
7108 rados_ioctx_destroy(ioctx2);
7109 cmdstr = "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
7110 pool_name1 + "\"}";
7111 cmd[0] = (char *)cmdstr.c_str();
7112 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
7113 cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
7114 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\"}";
7115 cmd[0] = (char *)cmdstr.c_str();
7116 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
7117}
7118
7119TEST_F(TestLibRBD, LockingPP)
7120{
7121 librados::IoCtx ioctx;
7122 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7123
7124 {
7125 librbd::RBD rbd;
7126 librbd::Image image;
7127 int order = 0;
7128 std::string name = get_temp_image_name();
7129 uint64_t size = 2 << 20;
7130 std::string cookie1 = "foo";
7131 std::string cookie2 = "bar";
7132
7133 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7134 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7135
7136 // no lockers initially
7137 std::list<librbd::locker_t> lockers;
7138 std::string tag;
7139 bool exclusive;
7140 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
7141 ASSERT_EQ(0u, lockers.size());
7142 ASSERT_EQ("", tag);
7143
7144 // exclusive lock is exclusive
7145 ASSERT_EQ(0, image.lock_exclusive(cookie1));
7146 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
7147 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
7148 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
7149 ASSERT_EQ(-EBUSY, image.lock_shared(cookie1, "test"));
7150 ASSERT_EQ(-EBUSY, image.lock_shared("", "test"));
7151 ASSERT_EQ(-EBUSY, image.lock_shared("", ""));
7152
7153 // list exclusive
7154 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
7155 ASSERT_TRUE(exclusive);
7156 ASSERT_EQ("", tag);
7157 ASSERT_EQ(1u, lockers.size());
7158 ASSERT_EQ(cookie1, lockers.front().cookie);
7159
7160 // unlock
7161 ASSERT_EQ(-ENOENT, image.unlock(""));
7162 ASSERT_EQ(-ENOENT, image.unlock(cookie2));
7163 ASSERT_EQ(0, image.unlock(cookie1));
7164 ASSERT_EQ(-ENOENT, image.unlock(cookie1));
7165 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
7166 ASSERT_EQ(0u, lockers.size());
7167
7168 ASSERT_EQ(0, image.lock_shared(cookie1, ""));
7169 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
7170 ASSERT_EQ(0, image.lock_shared(cookie2, ""));
7171 ASSERT_EQ(-EEXIST, image.lock_shared(cookie2, ""));
7172 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
7173 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie2));
7174 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
7175 ASSERT_EQ(-EBUSY, image.lock_exclusive("test"));
7176
7177 // list shared
7178 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
7179 ASSERT_EQ(2u, lockers.size());
7180 }
7181
7182 ioctx.close();
7183}
7184
7185TEST_F(TestLibRBD, FlushAio)
7186{
7187 rados_ioctx_t ioctx;
7188 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7189
7190 rbd_image_t image;
7191 int order = 0;
7192 std::string name = get_temp_image_name();
7193 uint64_t size = 2 << 20;
7194 size_t num_aios = 256;
7195
7196 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7197 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7198
7199 char test_data[TEST_IO_SIZE + 1];
7200 size_t i;
7201 for (i = 0; i < TEST_IO_SIZE; ++i) {
7202 test_data[i] = (char) (rand() % (126 - 33) + 33);
7203 }
7204
7205 rbd_completion_t write_comps[num_aios];
7206 for (i = 0; i < num_aios; ++i) {
7207 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &write_comps[i]));
7208 uint64_t offset = rand() % (size - TEST_IO_SIZE);
7209 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
7210 write_comps[i]));
7211 }
7212
7213 rbd_completion_t flush_comp;
7214 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &flush_comp));
7215 ASSERT_EQ(0, rbd_aio_flush(image, flush_comp));
7216 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp));
7217 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp));
7218 rbd_aio_release(flush_comp);
7219
7220 for (i = 0; i < num_aios; ++i) {
7221 ASSERT_EQ(1, rbd_aio_is_complete(write_comps[i]));
7222 rbd_aio_release(write_comps[i]);
7223 }
7224
7225 ASSERT_PASSED(validate_object_map, image);
7226 ASSERT_EQ(0, rbd_close(image));
7227 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
7228 rados_ioctx_destroy(ioctx);
7229}
7230
7231TEST_F(TestLibRBD, FlushAioPP)
7232{
7233 librados::IoCtx ioctx;
7234 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7235
7236 {
7237 librbd::RBD rbd;
7238 librbd::Image image;
7239 int order = 0;
7240 std::string name = get_temp_image_name();
7241 uint64_t size = 2 << 20;
7242 const size_t num_aios = 256;
7243
7244 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7245 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7246
7247 char test_data[TEST_IO_SIZE + 1];
7248 size_t i;
7249 for (i = 0; i < TEST_IO_SIZE; ++i) {
7250 test_data[i] = (char) (rand() % (126 - 33) + 33);
7251 }
7252 test_data[TEST_IO_SIZE] = '\0';
7253
7254 librbd::RBD::AioCompletion *write_comps[num_aios];
7255 ceph::bufferlist bls[num_aios];
7256 for (i = 0; i < num_aios; ++i) {
7257 bls[i].append(test_data, strlen(test_data));
7258 write_comps[i] = new librbd::RBD::AioCompletion(NULL, NULL);
7259 uint64_t offset = rand() % (size - TEST_IO_SIZE);
7260 ASSERT_EQ(0, image.aio_write(offset, TEST_IO_SIZE, bls[i],
7261 write_comps[i]));
7262 }
7263
7264 librbd::RBD::AioCompletion *flush_comp =
7265 new librbd::RBD::AioCompletion(NULL, NULL);
7266 ASSERT_EQ(0, image.aio_flush(flush_comp));
7267 ASSERT_EQ(0, flush_comp->wait_for_complete());
7268 ASSERT_EQ(1, flush_comp->is_complete());
7269 flush_comp->release();
7270
7271 for (i = 0; i < num_aios; ++i) {
7272 librbd::RBD::AioCompletion *comp = write_comps[i];
7273 ASSERT_EQ(1, comp->is_complete());
7274 comp->release();
7275 }
7276 ASSERT_PASSED(validate_object_map, image);
7277 }
7278
7279 ioctx.close();
7280}
7281
7282
7283int iterate_cb(uint64_t off, size_t len, int exists, void *arg)
7284{
7285 //cout << "iterate_cb " << off << "~" << len << std::endl;
7286 interval_set<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
7287 diff->insert(off, len);
7288 return 0;
7289}
7290
7291static int iterate_error_cb(uint64_t off, size_t len, int exists, void *arg)
7292{
7293 return -EINVAL;
7294}
7295
7296void scribble(librbd::Image& image, int n, int max, bool skip_discard,
7297 interval_set<uint64_t> *exists,
7298 interval_set<uint64_t> *what)
7299{
7300 uint64_t size;
7301 image.size(&size);
7302 interval_set<uint64_t> exists_at_start = *exists;
7303
7304 for (int i=0; i<n; i++) {
7305 uint64_t off = rand() % (size - max + 1);
7306 uint64_t len = 1 + rand() % max;
7307 if (!skip_discard && rand() % 4 == 0) {
7308 ASSERT_EQ((int)len, image.discard(off, len));
7309 interval_set<uint64_t> w;
7310 w.insert(off, len);
7311
7312 // the zeroed bit no longer exists...
7313 w.intersection_of(*exists);
7314 exists->subtract(w);
7315
7316 // the bits we discarded are no long written...
7317 interval_set<uint64_t> w2 = w;
7318 w2.intersection_of(*what);
7319 what->subtract(w2);
7320
7321 // except for the extents that existed at the start that we overwrote.
7322 interval_set<uint64_t> w3;
7323 w3.insert(off, len);
7324 w3.intersection_of(exists_at_start);
7325 what->union_of(w3);
7326
7327 } else {
7328 bufferlist bl;
7329 bl.append(buffer::create(len));
7330 bl.zero();
7331 ASSERT_EQ((int)len, image.write(off, len, bl));
7332 interval_set<uint64_t> w;
7333 w.insert(off, len);
7334 what->union_of(w);
7335 exists->union_of(w);
7336 }
7337 }
7338}
7339
7340interval_set<uint64_t> round_diff_interval(const interval_set<uint64_t>& diff,
7341 uint64_t object_size)
7342{
7343 if (object_size == 0) {
7344 return diff;
7345 }
7346
7347 interval_set<uint64_t> rounded_diff;
7348 for (interval_set<uint64_t>::const_iterator it = diff.begin();
7349 it != diff.end(); ++it) {
7350 uint64_t off = it.get_start();
7351 uint64_t len = it.get_len();
7352 off -= off % object_size;
7353 len += (object_size - (len % object_size));
7354 interval_set<uint64_t> interval;
7355 interval.insert(off, len);
7356 rounded_diff.union_of(interval);
7357 }
7358 return rounded_diff;
7359}
7360
1d09f67e
TL
7361TEST_F(TestLibRBD, SnapDiff)
7362{
7363 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
7364
7365 rados_ioctx_t ioctx;
7366 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7367
7368 rbd_image_t image;
7369 int order = 0;
7370 std::string image_name = get_temp_image_name();
7371 uint64_t size = 100 << 20;
7372 ASSERT_EQ(0, create_image(ioctx, image_name.c_str(), size, &order));
7373 ASSERT_EQ(0, rbd_open(ioctx, image_name.c_str(), &image, nullptr));
7374
7375 char test_data[TEST_IO_SIZE + 1];
7376 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
7377 test_data[i] = (char) (rand() % (126 - 33) + 33);
7378 }
7379 test_data[TEST_IO_SIZE] = '\0';
7380
7381 ASSERT_PASSED(write_test_data, image, test_data, 0,
7382 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
7383
7384 interval_set<uint64_t> diff;
7385 ASSERT_EQ(0, rbd_diff_iterate2(image, nullptr, 0, size, true, true,
7386 iterate_cb, &diff));
7387 EXPECT_EQ(1 << order, diff.size());
7388
7389 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
7390 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
7391
7392 diff.clear();
7393 ASSERT_EQ(0, rbd_diff_iterate2(image, nullptr, 0, size, true, true,
7394 iterate_cb, &diff));
7395 EXPECT_EQ(1 << order, diff.size());
7396
7397 diff.clear();
7398 ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, true,
7399 iterate_cb, &diff));
7400 EXPECT_EQ(0, diff.size());
7401
7402 diff.clear();
7403 ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, true,
7404 iterate_cb, &diff));
7405 EXPECT_EQ(0, diff.size());
7406
7407 ASSERT_EQ(0, rbd_snap_remove(image, "snap1"));
7408 ASSERT_EQ(0, rbd_snap_remove(image, "snap2"));
7409
7410 ASSERT_EQ(0, rbd_close(image));
7411 ASSERT_EQ(0, rbd_remove(ioctx, image_name.c_str()));
7412
7413 rados_ioctx_destroy(ioctx);
7414}
7415
7c673cae
FG
7416template <typename T>
7417class DiffIterateTest : public TestLibRBD {
7418public:
7419 static const uint8_t whole_object = T::whole_object;
7420};
7421
7422template <bool _whole_object>
7423class DiffIterateParams {
7424public:
7425 static const uint8_t whole_object = _whole_object;
7426};
7427
7428typedef ::testing::Types<DiffIterateParams<false>,
7429 DiffIterateParams<true> > DiffIterateTypes;
9f95a23c 7430TYPED_TEST_SUITE(DiffIterateTest, DiffIterateTypes);
7c673cae
FG
7431
7432TYPED_TEST(DiffIterateTest, DiffIterate)
7433{
7434 librados::IoCtx ioctx;
7435 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7436
7c673cae
FG
7437 {
7438 librbd::RBD rbd;
7439 librbd::Image image;
7440 int order = 0;
7441 std::string name = this->get_temp_image_name();
7442 uint64_t size = 20 << 20;
7443
7444 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7445 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7446
f67539c2
TL
7447 bool skip_discard = this->is_skip_partial_discard_enabled(image);
7448
7c673cae
FG
7449 uint64_t object_size = 0;
7450 if (this->whole_object) {
7451 object_size = 1 << order;
7452 }
7453
7454 interval_set<uint64_t> exists;
7455 interval_set<uint64_t> one, two;
7456 scribble(image, 10, 102400, skip_discard, &exists, &one);
7457 cout << " wrote " << one << std::endl;
7458 ASSERT_EQ(0, image.snap_create("one"));
7459 scribble(image, 10, 102400, skip_discard, &exists, &two);
7460
7461 two = round_diff_interval(two, object_size);
7462 cout << " wrote " << two << std::endl;
7463
7464 interval_set<uint64_t> diff;
7465 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
7466 iterate_cb, (void *)&diff));
7467 cout << " diff was " << diff << std::endl;
7468 if (!two.subset_of(diff)) {
7469 interval_set<uint64_t> i;
7470 i.intersection_of(two, diff);
7471 interval_set<uint64_t> l = two;
7472 l.subtract(i);
7473 cout << " ... two - (two*diff) = " << l << std::endl;
7474 }
7475 ASSERT_TRUE(two.subset_of(diff));
7476 }
7477 ioctx.close();
7478}
7479
7480struct diff_extent {
7481 diff_extent(uint64_t _offset, uint64_t _length, bool _exists,
7482 uint64_t object_size) :
7483 offset(_offset), length(_length), exists(_exists)
7484 {
7485 if (object_size != 0) {
7486 offset -= offset % object_size;
7487 length = object_size;
7488 }
7489 }
7490 uint64_t offset;
7491 uint64_t length;
7492 bool exists;
7493 bool operator==(const diff_extent& o) const {
7494 return offset == o.offset && length == o.length && exists == o.exists;
7495 }
7496};
7497
7498ostream& operator<<(ostream & o, const diff_extent& e) {
7499 return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')';
7500}
7501
7502int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg)
7503{
7504 cout << "iterate_cb " << off << "~" << len << std::endl;
7505 vector<diff_extent> *diff = static_cast<vector<diff_extent> *>(arg);
7506 diff->push_back(diff_extent(off, len, exists, 0));
7507 return 0;
7508}
7509
7510TYPED_TEST(DiffIterateTest, DiffIterateDiscard)
7511{
7512 librados::IoCtx ioctx;
7513 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7514
7515 librbd::RBD rbd;
7516 librbd::Image image;
7517 int order = 0;
7518 std::string name = this->get_temp_image_name();
7519 uint64_t size = 20 << 20;
7520
7521 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7522 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7523
7524 uint64_t object_size = 0;
7525 if (this->whole_object) {
7526 object_size = 1 << order;
7527 }
7528 vector<diff_extent> extents;
7529 ceph::bufferlist bl;
7530
7531 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7532 vector_iterate_cb, (void *) &extents));
7533 ASSERT_EQ(0u, extents.size());
7534
7535 char data[256];
7536 memset(data, 1, sizeof(data));
7537 bl.append(data, 256);
7538 ASSERT_EQ(256, image.write(0, 256, bl));
7539 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7540 vector_iterate_cb, (void *) &extents));
7541 ASSERT_EQ(1u, extents.size());
7542 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
7543
7544 int obj_ofs = 256;
7545 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
7546
7547 extents.clear();
7548 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7549 vector_iterate_cb, (void *) &extents));
7550 ASSERT_EQ(0u, extents.size());
7551
7552 ASSERT_EQ(0, image.snap_create("snap1"));
7553 ASSERT_EQ(256, image.write(0, 256, bl));
7554 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7555 vector_iterate_cb, (void *) &extents));
7556 ASSERT_EQ(1u, extents.size());
7557 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
7558 ASSERT_EQ(0, image.snap_create("snap2"));
7559
7560 ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs));
7561
7562 extents.clear();
7563 ASSERT_EQ(0, image.snap_set("snap2"));
7564 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
7565 vector_iterate_cb, (void *) &extents));
7566 ASSERT_EQ(1u, extents.size());
7567 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
7568
7569 ASSERT_EQ(0, image.snap_set(NULL));
7570 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
7571 ASSERT_EQ(0, image.snap_create("snap3"));
7572 ASSERT_EQ(0, image.snap_set("snap3"));
7573
7574 extents.clear();
7575 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
7576 vector_iterate_cb, (void *) &extents));
7577 ASSERT_EQ(1u, extents.size());
7578 ASSERT_EQ(diff_extent(0, 256, false, object_size), extents[0]);
7579 ASSERT_PASSED(this->validate_object_map, image);
7580}
7581
7582TYPED_TEST(DiffIterateTest, DiffIterateStress)
7583{
f67539c2 7584 REQUIRE(!is_rbd_pwl_enabled((CephContext *)this->_rados.cct()));
7c673cae
FG
7585 librados::IoCtx ioctx;
7586 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7587
7c673cae
FG
7588 librbd::RBD rbd;
7589 librbd::Image image;
7590 int order = 0;
7591 std::string name = this->get_temp_image_name();
7592 uint64_t size = 400 << 20;
7593
7594 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7595 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7596
f67539c2
TL
7597 bool skip_discard = this->is_skip_partial_discard_enabled(image);
7598
7c673cae
FG
7599 uint64_t object_size = 0;
7600 if (this->whole_object) {
7601 object_size = 1 << order;
7602 }
7603
7604 interval_set<uint64_t> curexists;
7605 vector<interval_set<uint64_t> > wrote;
7606 vector<interval_set<uint64_t> > exists;
7607 vector<string> snap;
7608 int n = 20;
7609 for (int i=0; i<n; i++) {
7610 interval_set<uint64_t> w;
7611 scribble(image, 10, 8192000, skip_discard, &curexists, &w);
7612 cout << " i=" << i << " exists " << curexists << " wrote " << w << std::endl;
7613 string s = "snap" + stringify(i);
7614 ASSERT_EQ(0, image.snap_create(s.c_str()));
7615 wrote.push_back(w);
7616 exists.push_back(curexists);
7617 snap.push_back(s);
7618 }
7619
7620 for (int h=0; h<n-1; h++) {
7621 for (int i=0; i<n-h-1; i++) {
7622 for (int j=(h==0 ? i+1 : n-1); j<n; j++) {
7623 interval_set<uint64_t> diff, actual, uex;
7624 for (int k=i+1; k<=j; k++)
7625 diff.union_of(wrote[k]);
7626 cout << "from " << i << " to "
7627 << (h != 0 ? string("HEAD") : stringify(j)) << " diff "
7628 << round_diff_interval(diff, object_size) << std::endl;
7629
7630 // limit to extents that exists both at the beginning and at the end
7631 uex.union_of(exists[i], exists[j]);
7632 diff.intersection_of(uex);
7633 diff = round_diff_interval(diff, object_size);
7634 cout << " limited diff " << diff << std::endl;
7635
7636 ASSERT_EQ(0, image.snap_set(h==0 ? snap[j].c_str() : NULL));
7637 ASSERT_EQ(0, image.diff_iterate2(snap[i].c_str(), 0, size, true,
7638 this->whole_object, iterate_cb,
7639 (void *)&actual));
7640 cout << " actual was " << actual << std::endl;
7641 if (!diff.subset_of(actual)) {
7642 interval_set<uint64_t> i;
7643 i.intersection_of(diff, actual);
7644 interval_set<uint64_t> l = diff;
7645 l.subtract(i);
7646 cout << " ... diff - (actual*diff) = " << l << std::endl;
7647 }
7648 ASSERT_TRUE(diff.subset_of(actual));
7649 }
7650 }
7651 ASSERT_EQ(0, image.snap_set(NULL));
7652 ASSERT_EQ(0, image.snap_remove(snap[n-h-1].c_str()));
7653 }
7654
7655 ASSERT_PASSED(this->validate_object_map, image);
7656}
7657
7658TYPED_TEST(DiffIterateTest, DiffIterateRegression6926)
7659{
7660 librados::IoCtx ioctx;
7661 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7662
7663 librbd::RBD rbd;
7664 librbd::Image image;
7665 int order = 0;
7666 std::string name = this->get_temp_image_name();
7667 uint64_t size = 20 << 20;
7668
7669 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7670 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7671
7672 uint64_t object_size = 0;
7673 if (this->whole_object) {
7674 object_size = 1 << order;
7675 }
7676 vector<diff_extent> extents;
7677 ceph::bufferlist bl;
7678
7679 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7680 vector_iterate_cb, (void *) &extents));
7681 ASSERT_EQ(0u, extents.size());
7682
7683 ASSERT_EQ(0, image.snap_create("snap1"));
7684 char data[256];
7685 memset(data, 1, sizeof(data));
7686 bl.append(data, 256);
7687 ASSERT_EQ(256, image.write(0, 256, bl));
7688
7689 extents.clear();
7690 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7691 vector_iterate_cb, (void *) &extents));
7692 ASSERT_EQ(1u, extents.size());
7693 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
7694
7695 ASSERT_EQ(0, image.snap_set("snap1"));
7696 extents.clear();
7697 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7698 vector_iterate_cb, (void *) &extents));
7699 ASSERT_EQ(static_cast<size_t>(0), extents.size());
7700}
7701
20effc67
TL
7702TYPED_TEST(DiffIterateTest, DiffIterateParent)
7703{
7704 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7705
7706 librados::IoCtx ioctx;
7707 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7708
7709 {
7710 librbd::RBD rbd;
7711 librbd::Image image;
7712 int order = 22;
7713 std::string name = this->get_temp_image_name();
7714 ssize_t size = 20 << 20;
7715
7716 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7717 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7718
7719 uint64_t features;
7720 ASSERT_EQ(0, image.features(&features));
7721 uint64_t object_size = 0;
7722 if (this->whole_object) {
7723 object_size = 1 << order;
7724 }
7725
7726 ceph::bufferlist bl;
7727 bl.append(std::string(size, '1'));
7728 ASSERT_EQ(size, image.write(0, size, bl));
7729 ASSERT_EQ(0, image.snap_create("snap"));
7730 ASSERT_EQ(0, image.snap_protect("snap"));
7731
7732 std::string clone_name = this->get_temp_image_name();
7733 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx,
7734 clone_name.c_str(), features, &order));
7735 librbd::Image clone;
7736 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
7737
7738 std::vector<diff_extent> extents;
7739 ASSERT_EQ(0, clone.diff_iterate2(NULL, 0, size, true, this->whole_object,
7740 vector_iterate_cb, &extents));
7741 ASSERT_EQ(5u, extents.size());
7742 ASSERT_EQ(diff_extent(0, 4194304, true, object_size), extents[0]);
7743 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size), extents[1]);
7744 ASSERT_EQ(diff_extent(8388608, 4194304, true, object_size), extents[2]);
7745 ASSERT_EQ(diff_extent(12582912, 4194304, true, object_size), extents[3]);
7746 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size), extents[4]);
7747 extents.clear();
7748
7749 ASSERT_EQ(0, clone.resize(size / 2));
7750 ASSERT_EQ(0, clone.resize(size));
7751 ASSERT_EQ(1, clone.write(size - 1, 1, bl));
7752
7753 ASSERT_EQ(0, clone.diff_iterate2(NULL, 0, size, true, this->whole_object,
7754 vector_iterate_cb, &extents));
7755 ASSERT_EQ(4u, extents.size());
7756 ASSERT_EQ(diff_extent(0, 4194304, true, object_size), extents[0]);
7757 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size), extents[1]);
7758 ASSERT_EQ(diff_extent(8388608, 2097152, true, object_size), extents[2]);
7759 // hole (parent overlap = 10M) followed by copyup'ed object
7760 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size), extents[3]);
7761
7762 ASSERT_PASSED(this->validate_object_map, image);
7763 ASSERT_PASSED(this->validate_object_map, clone);
7764 }
7765
7766 ioctx.close();
7767}
7768
7c673cae
FG
7769TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
7770{
7771 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7772
7773 librados::IoCtx ioctx;
7774 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7775
7c673cae
FG
7776 librbd::RBD rbd;
7777 librbd::Image image;
7778 std::string name = this->get_temp_image_name();
7779 uint64_t size = 20 << 20;
7780 int order = 0;
7781
7782 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7783 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7784
f67539c2
TL
7785 bool skip_discard = this->is_skip_partial_discard_enabled(image);
7786
20effc67
TL
7787 uint64_t features;
7788 ASSERT_EQ(0, image.features(&features));
7c673cae
FG
7789 uint64_t object_size = 0;
7790 if (this->whole_object) {
7791 object_size = 1 << order;
7792 }
7793
7794 bufferlist bl;
7795 bl.append(buffer::create(size));
7796 bl.zero();
7797 interval_set<uint64_t> one;
7798 one.insert(0, size);
7799 ASSERT_EQ((int)size, image.write(0, size, bl));
7800 ASSERT_EQ(0, image.snap_create("one"));
7801 ASSERT_EQ(0, image.snap_protect("one"));
7802
7803 std::string clone_name = this->get_temp_image_name();
7804 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
20effc67 7805 features, &order));
7c673cae
FG
7806 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
7807
7808 interval_set<uint64_t> exists;
7809 interval_set<uint64_t> two;
7810 scribble(image, 10, 102400, skip_discard, &exists, &two);
7811 two = round_diff_interval(two, object_size);
7812 cout << " wrote " << two << " to clone" << std::endl;
7813
7814 interval_set<uint64_t> diff;
7815 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, false, this->whole_object,
7816 iterate_cb, (void *)&diff));
7817 cout << " diff was " << diff << std::endl;
7818 if (!this->whole_object) {
7819 ASSERT_FALSE(one.subset_of(diff));
7820 }
7821 ASSERT_TRUE(two.subset_of(diff));
7822}
7823
7824TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
7825{
7826 librados::IoCtx ioctx;
7827 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7828
7c673cae
FG
7829 {
7830 librbd::RBD rbd;
7831 librbd::Image image;
7832 int order = 0;
7833 std::string name = this->get_temp_image_name();
7834 uint64_t size = 20 << 20;
7835
7836 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7837 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7838
f67539c2
TL
7839 bool skip_discard = this->is_skip_partial_discard_enabled(image);
7840
7c673cae
FG
7841 interval_set<uint64_t> exists;
7842 interval_set<uint64_t> one;
7843 scribble(image, 10, 102400, skip_discard, &exists, &one);
7844 cout << " wrote " << one << std::endl;
7845
7846 interval_set<uint64_t> diff;
7847 ASSERT_EQ(-EINVAL, image.diff_iterate2(NULL, 0, size, true,
7848 this->whole_object,
7849 iterate_error_cb, NULL));
7850 }
7851 ioctx.close();
7852}
7853
7854TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
7855{
7856 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7857
7858 librados::IoCtx ioctx;
7859 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7860
7c673cae
FG
7861 librbd::RBD rbd;
7862 librbd::Image image;
7863 std::string name = this->get_temp_image_name();
7864 uint64_t size = 20 << 20;
7865 int order = 0;
7866
7867 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7868 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7869
f67539c2
TL
7870 bool skip_discard = this->is_skip_partial_discard_enabled(image);
7871
20effc67
TL
7872 uint64_t features;
7873 ASSERT_EQ(0, image.features(&features));
7c673cae
FG
7874 uint64_t object_size = 0;
7875 if (this->whole_object) {
7876 object_size = 1 << order;
7877 }
7878
7879 interval_set<uint64_t> exists;
7880 interval_set<uint64_t> one;
7881 scribble(image, 10, 102400, skip_discard, &exists, &one);
7882 ASSERT_EQ(0, image.snap_create("one"));
7883
7884 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
7885 ASSERT_EQ(0, image.snap_create("two"));
7886 ASSERT_EQ(0, image.snap_protect("two"));
7887 exists.clear();
7888 one.clear();
7889
7890 std::string clone_name = this->get_temp_image_name();
7891 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "two", ioctx,
20effc67 7892 clone_name.c_str(), features, &order));
7c673cae
FG
7893 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
7894
7895 interval_set<uint64_t> two;
7896 scribble(image, 10, 102400, skip_discard, &exists, &two);
7897 two = round_diff_interval(two, object_size);
7898
7899 interval_set<uint64_t> diff;
7900 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
7901 iterate_cb, (void *)&diff));
7902 ASSERT_TRUE(two.subset_of(diff));
7903}
7904
20effc67
TL
7905TYPED_TEST(DiffIterateTest, DiffIterateUnalignedSmall)
7906{
7907 librados::IoCtx ioctx;
7908 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7909
7910 {
7911 librbd::RBD rbd;
7912 librbd::Image image;
7913 int order = 0;
7914 std::string name = this->get_temp_image_name();
7915 ssize_t size = 10 << 20;
7916
7917 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7918 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7919
7920 ceph::bufferlist bl;
7921 bl.append(std::string(size, '1'));
7922 ASSERT_EQ(size, image.write(0, size, bl));
7923
7924 std::vector<diff_extent> extents;
7925 ASSERT_EQ(0, image.diff_iterate2(NULL, 5000005, 1234, true,
7926 this->whole_object, vector_iterate_cb,
7927 &extents));
7928 ASSERT_EQ(1u, extents.size());
7929 ASSERT_EQ(diff_extent(5000005, 1234, true, 0), extents[0]);
7930
7931 ASSERT_PASSED(this->validate_object_map, image);
7932 }
7933
7934 ioctx.close();
7935}
7936
7937TYPED_TEST(DiffIterateTest, DiffIterateUnaligned)
7938{
7939 librados::IoCtx ioctx;
7940 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7941
7942 {
7943 librbd::RBD rbd;
7944 librbd::Image image;
7945 int order = 22;
7946 std::string name = this->get_temp_image_name();
7947 ssize_t size = 20 << 20;
7948
7949 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7950 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7951
7952 ceph::bufferlist bl;
7953 bl.append(std::string(size, '1'));
7954 ASSERT_EQ(size, image.write(0, size, bl));
7955
7956 std::vector<diff_extent> extents;
7957 ASSERT_EQ(0, image.diff_iterate2(NULL, 8376263, 4260970, true,
7958 this->whole_object, vector_iterate_cb,
7959 &extents));
7960 ASSERT_EQ(3u, extents.size());
7961 ASSERT_EQ(diff_extent(8376263, 12345, true, 0), extents[0]);
7962 ASSERT_EQ(diff_extent(8388608, 4194304, true, 0), extents[1]);
7963 ASSERT_EQ(diff_extent(12582912, 54321, true, 0), extents[2]);
7964
7965 ASSERT_PASSED(this->validate_object_map, image);
7966 }
7967
7968 ioctx.close();
7969}
7970
1d09f67e
TL
7971TYPED_TEST(DiffIterateTest, DiffIterateStriping)
7972{
7973 REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2);
7974
7975 librados::IoCtx ioctx;
7976 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
7977
7978 bool old_format;
7979 uint64_t features;
7980 ASSERT_EQ(0, get_features(&old_format, &features));
7981 ASSERT_FALSE(old_format);
7982
7983 {
7984 librbd::RBD rbd;
7985 librbd::Image image;
7986 int order = 22;
7987 std::string name = this->get_temp_image_name();
7988 ssize_t size = 24 << 20;
7989
7990 ASSERT_EQ(0, rbd.create3(ioctx, name.c_str(), size, features, &order,
7991 1 << 20, 3));
7992 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7993
7994 ceph::bufferlist bl;
7995 bl.append(std::string(size, '1'));
7996 ASSERT_EQ(size, image.write(0, size, bl));
7997
7998 std::vector<diff_extent> extents;
7999 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
8000 vector_iterate_cb, &extents));
8001 ASSERT_EQ(2u, extents.size());
8002 ASSERT_EQ(diff_extent(0, 12 << 20, true, 0), extents[0]);
8003 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents[1]);
8004 extents.clear();
8005
8006 ASSERT_EQ(0, image.snap_create("one"));
8007 ASSERT_EQ(size, image.discard(0, size));
8008
8009 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
8010 vector_iterate_cb, &extents));
8011 ASSERT_EQ(2u, extents.size());
8012 ASSERT_EQ(diff_extent(0, 12 << 20, false, 0), extents[0]);
8013 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, false, 0), extents[1]);
8014 extents.clear();
8015
8016 ASSERT_EQ(1 << 20, image.write(0, 1 << 20, bl));
8017 ASSERT_EQ(2 << 20, image.write(2 << 20, 2 << 20, bl));
8018 ASSERT_EQ(2 << 20, image.write(5 << 20, 2 << 20, bl));
8019 ASSERT_EQ(2 << 20, image.write(8 << 20, 2 << 20, bl));
8020 ASSERT_EQ(13 << 20, image.write(11 << 20, 13 << 20, bl));
8021
8022 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
8023 vector_iterate_cb, &extents));
8024 ASSERT_EQ(10u, extents.size());
8025 ASSERT_EQ(diff_extent(0, 1 << 20, true, 0), extents[0]);
8026 ASSERT_EQ(diff_extent(1 << 20, 1 << 20, false, 0), extents[1]);
8027 ASSERT_EQ(diff_extent(2 << 20, 2 << 20, true, 0), extents[2]);
8028 ASSERT_EQ(diff_extent(4 << 20, 1 << 20, false, 0), extents[3]);
8029 ASSERT_EQ(diff_extent(5 << 20, 2 << 20, true, 0), extents[4]);
8030 ASSERT_EQ(diff_extent(7 << 20, 1 << 20, false, 0), extents[5]);
8031 ASSERT_EQ(diff_extent(8 << 20, 2 << 20, true, 0), extents[6]);
8032 ASSERT_EQ(diff_extent(10 << 20, 1 << 20, false, 0), extents[7]);
8033 ASSERT_EQ(diff_extent(11 << 20, 1 << 20, true, 0), extents[8]);
8034 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents[9]);
8035
8036 ASSERT_PASSED(this->validate_object_map, image);
8037 }
8038
8039 ioctx.close();
8040}
8041
7c673cae
FG
8042TEST_F(TestLibRBD, ZeroLengthWrite)
8043{
8044 rados_ioctx_t ioctx;
8045 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8046
8047 rbd_image_t image;
8048 int order = 0;
8049 std::string name = get_temp_image_name();
8050 uint64_t size = 2 << 20;
8051
8052 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8053 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8054
8055 char read_data[1];
8056 ASSERT_EQ(0, rbd_write(image, 0, 0, NULL));
8057 ASSERT_EQ(1, rbd_read(image, 0, 1, read_data));
8058 ASSERT_EQ('\0', read_data[0]);
8059
8060 ASSERT_PASSED(validate_object_map, image);
8061 ASSERT_EQ(0, rbd_close(image));
8062
8063 rados_ioctx_destroy(ioctx);
8064}
8065
8066
8067TEST_F(TestLibRBD, ZeroLengthDiscard)
8068{
8069 rados_ioctx_t ioctx;
8070 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8071
8072 rbd_image_t image;
8073 int order = 0;
8074 std::string name = get_temp_image_name();
8075 uint64_t size = 2 << 20;
8076
8077 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8078 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8079
8080 const char data[] = "blah";
8081 char read_data[sizeof(data)];
8082 ASSERT_EQ((int)strlen(data), rbd_write(image, 0, strlen(data), data));
8083 ASSERT_EQ(0, rbd_discard(image, 0, 0));
8084 ASSERT_EQ((int)strlen(data), rbd_read(image, 0, strlen(data), read_data));
8085 ASSERT_EQ(0, memcmp(data, read_data, strlen(data)));
8086
8087 ASSERT_PASSED(validate_object_map, image);
8088 ASSERT_EQ(0, rbd_close(image));
8089
8090 rados_ioctx_destroy(ioctx);
8091}
8092
8093TEST_F(TestLibRBD, ZeroLengthRead)
8094{
8095 rados_ioctx_t ioctx;
8096 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8097
8098 rbd_image_t image;
8099 int order = 0;
8100 std::string name = get_temp_image_name();
8101 uint64_t size = 2 << 20;
8102
8103 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8104 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8105
8106 char read_data[1];
8107 ASSERT_EQ(0, rbd_read(image, 0, 0, read_data));
8108
8109 ASSERT_EQ(0, rbd_close(image));
8110
8111 rados_ioctx_destroy(ioctx);
8112}
8113
8114TEST_F(TestLibRBD, LargeCacheRead)
8115{
8116 std::string config_value;
8117 ASSERT_EQ(0, _rados.conf_get("rbd_cache", config_value));
8118 if (config_value == "false") {
1e59de90 8119 GTEST_SKIP() << "Skipping due to disabled cache";
7c673cae
FG
8120 }
8121
8122 rados_ioctx_t ioctx;
8123 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8124
8125 uint32_t new_cache_size = 1 << 20;
8126 std::string orig_cache_size;
8127 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", orig_cache_size));
8128 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size",
8129 stringify(new_cache_size).c_str()));
8130 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", config_value));
8131 ASSERT_EQ(stringify(new_cache_size), config_value);
8132 BOOST_SCOPE_EXIT( (orig_cache_size) ) {
8133 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size", orig_cache_size.c_str()));
8134 } BOOST_SCOPE_EXIT_END;
8135
8136 rbd_image_t image;
8137 int order = 21;
8138 std::string name = get_temp_image_name();
8139 uint64_t size = 1 << order;
8140
8141 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8142 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8143
8144 std::string buffer(1 << order, '1');
8145
8146 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
8147 rbd_write(image, 0, buffer.size(), buffer.c_str()));
8148
8149 ASSERT_EQ(0, rbd_invalidate_cache(image));
8150
8151 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
8152 rbd_read(image, 0, buffer.size(), &buffer[0]));
8153
8154 ASSERT_EQ(0, rbd_close(image));
8155
8156 rados_ioctx_destroy(ioctx);
8157}
8158
8159TEST_F(TestLibRBD, TestPendingAio)
8160{
8161 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8162
8163 rados_ioctx_t ioctx;
8164 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8165
8166 bool old_format;
8167 uint64_t features;
8168 rbd_image_t image;
8169 int order = 0;
8170
8171 ASSERT_EQ(0, get_features(&old_format, &features));
8172 ASSERT_FALSE(old_format);
8173
8174 std::string name = get_temp_image_name();
8175
8176 uint64_t size = 4 << 20;
8177 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
8178 false, features));
8179 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8180
f67539c2
TL
8181 ASSERT_EQ(0, rbd_invalidate_cache(image));
8182
7c673cae
FG
8183 char test_data[TEST_IO_SIZE];
8184 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
8185 test_data[i] = (char) (rand() % (126 - 33) + 33);
8186 }
8187
8188 size_t num_aios = 256;
8189 rbd_completion_t comps[num_aios];
8190 for (size_t i = 0; i < num_aios; ++i) {
8191 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
8192 uint64_t offset = rand() % (size - TEST_IO_SIZE);
8193 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
8194 comps[i]));
8195 }
8196 for (size_t i = 0; i < num_aios; ++i) {
8197 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps[i]));
8198 rbd_aio_release(comps[i]);
8199 }
8200 ASSERT_EQ(0, rbd_invalidate_cache(image));
8201
8202 for (size_t i = 0; i < num_aios; ++i) {
8203 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
8204 uint64_t offset = rand() % (size - TEST_IO_SIZE);
8205 ASSERT_LE(0, rbd_aio_read(image, offset, TEST_IO_SIZE, test_data,
8206 comps[i]));
8207 }
8208
8209 ASSERT_PASSED(validate_object_map, image);
8210 ASSERT_EQ(0, rbd_close(image));
8211 for (size_t i = 0; i < num_aios; ++i) {
8212 ASSERT_EQ(1, rbd_aio_is_complete(comps[i]));
8213 rbd_aio_release(comps[i]);
8214 }
8215
8216 rados_ioctx_destroy(ioctx);
8217}
8218
11fdf7f2
TL
8219void compare_and_write_copyup(librados::IoCtx &ioctx, bool deep_copyup,
8220 bool *passed)
8221{
8222 librbd::RBD rbd;
8223 std::string parent_name = TestLibRBD::get_temp_image_name();
8224 uint64_t size = 2 << 20;
8225 int order = 0;
8226 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
8227
8228 librbd::Image parent_image;
8229 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
8230
8231 bufferlist bl;
8232 bl.append(std::string(4096, '1'));
8233 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
8234
8235 ASSERT_EQ(0, parent_image.snap_create("snap1"));
8236 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
8237
8238 uint64_t features;
8239 ASSERT_EQ(0, parent_image.features(&features));
8240
8241 std::string clone_name = TestLibRBD::get_temp_image_name();
8242 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
8243 clone_name.c_str(), features, &order));
8244
8245 librbd::Image clone_image;
8246 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
8247 if (deep_copyup) {
8248 ASSERT_EQ(0, clone_image.snap_create("snap1"));
8249 }
8250
8251 bufferlist cmp_bl;
39ae355f 8252 cmp_bl.append(std::string(512, '1'));
11fdf7f2
TL
8253 bufferlist write_bl;
8254 write_bl.append(std::string(512, '2'));
39ae355f 8255 uint64_t mismatch_off = 0;
11fdf7f2
TL
8256 ASSERT_EQ((ssize_t)write_bl.length(),
8257 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
8258 write_bl, &mismatch_off, 0));
39ae355f 8259 ASSERT_EQ(0U, mismatch_off);
11fdf7f2
TL
8260 bufferlist read_bl;
8261 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
8262
8263 bufferlist expected_bl;
8264 expected_bl.append(std::string(512, '1'));
8265 expected_bl.append(std::string(512, '2'));
8266 expected_bl.append(std::string(3072, '1'));
8267 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
8268 *passed = true;
8269}
8270
8271TEST_F(TestLibRBD, CompareAndWriteCopyup)
8272{
8273 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8274
8275 librados::IoCtx ioctx;
8276 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8277
8278 ASSERT_PASSED(compare_and_write_copyup, ioctx, false);
8279 ASSERT_PASSED(compare_and_write_copyup, ioctx, true);
8280}
8281
8282void compare_and_write_copyup_mismatch(librados::IoCtx &ioctx,
8283 bool deep_copyup, bool *passed)
8284{
8285 librbd::RBD rbd;
8286 std::string parent_name = TestLibRBD::get_temp_image_name();
8287 uint64_t size = 2 << 20;
8288 int order = 0;
8289 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
8290
8291 librbd::Image parent_image;
8292 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
8293
8294 bufferlist bl;
8295 bl.append(std::string(4096, '1'));
8296 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
8297
8298 ASSERT_EQ(0, parent_image.snap_create("snap1"));
8299 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
8300
8301 uint64_t features;
8302 ASSERT_EQ(0, parent_image.features(&features));
8303
8304 std::string clone_name = TestLibRBD::get_temp_image_name();
8305 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
8306 clone_name.c_str(), features, &order));
8307
8308 librbd::Image clone_image;
8309 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
8310 if (deep_copyup) {
8311 ASSERT_EQ(0, clone_image.snap_create("snap1"));
8312 }
8313
8314 bufferlist cmp_bl;
8315 cmp_bl.append(std::string(48, '1'));
39ae355f 8316 cmp_bl.append(std::string(464, '3'));
11fdf7f2
TL
8317 bufferlist write_bl;
8318 write_bl.append(std::string(512, '2'));
39ae355f 8319 uint64_t mismatch_off = 0;
11fdf7f2
TL
8320 ASSERT_EQ(-EILSEQ,
8321 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
8322 write_bl, &mismatch_off, 0));
8323 ASSERT_EQ(48U, mismatch_off);
8324
8325 bufferlist read_bl;
8326 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
8327
8328 ASSERT_TRUE(bl.contents_equal(read_bl));
8329 *passed = true;
8330}
8331
8332TEST_F(TestLibRBD, CompareAndWriteCopyupMismatch)
8333{
8334 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8335
8336 librados::IoCtx ioctx;
8337 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8338
8339 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, false);
8340 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, true);
8341}
8342
7c673cae
FG
8343TEST_F(TestLibRBD, Flatten)
8344{
8345 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8346
8347 librados::IoCtx ioctx;
8348 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8349
8350 librbd::RBD rbd;
8351 std::string parent_name = get_temp_image_name();
8352 uint64_t size = 2 << 20;
8353 int order = 0;
8354 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
8355
8356 librbd::Image parent_image;
8357 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
8358
8359 bufferlist bl;
8360 bl.append(std::string(4096, '1'));
8361 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
8362
8363 ASSERT_EQ(0, parent_image.snap_create("snap1"));
8364 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
8365
8366 uint64_t features;
8367 ASSERT_EQ(0, parent_image.features(&features));
8368
8369 std::string clone_name = get_temp_image_name();
8370 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
8371 clone_name.c_str(), features, &order));
8372
8373 librbd::Image clone_image;
8374 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
8375 ASSERT_EQ(0, clone_image.flatten());
8376
8377 librbd::RBD::AioCompletion *read_comp =
8378 new librbd::RBD::AioCompletion(NULL, NULL);
8379 bufferlist read_bl;
8380 clone_image.aio_read(0, bl.length(), read_bl, read_comp);
8381 ASSERT_EQ(0, read_comp->wait_for_complete());
8382 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
8383 read_comp->release();
8384 ASSERT_TRUE(bl.contents_equal(read_bl));
8385
8386 ASSERT_PASSED(validate_object_map, clone_image);
8387}
8388
11fdf7f2
TL
8389TEST_F(TestLibRBD, Sparsify)
8390{
8391 rados_ioctx_t ioctx;
8392 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
8393 BOOST_SCOPE_EXIT_ALL(&ioctx) {
8394 rados_ioctx_destroy(ioctx);
8395 };
8396
8397 const size_t CHUNK_SIZE = 4096 * 2;
8398 rbd_image_t image;
8399 int order = 0;
8400 std::string name = get_temp_image_name();
8401 uint64_t size = CHUNK_SIZE * 1024;
8402
8403 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8404 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8405 BOOST_SCOPE_EXIT_ALL(&image) {
8406 rbd_close(image);
8407 };
8408
8409 char test_data[4 * CHUNK_SIZE + 1];
8410 for (size_t i = 0; i < 4 ; ++i) {
8411 for (size_t j = 0; j < CHUNK_SIZE; j++) {
8412 if (i % 2) {
8413 test_data[i * CHUNK_SIZE + j] = (char)(rand() % (126 - 33) + 33);
8414 } else {
8415 test_data[i * CHUNK_SIZE + j] = '\0';
8416 }
8417 }
8418 }
8419 test_data[4 * CHUNK_SIZE] = '\0';
8420
8421 ASSERT_PASSED(write_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
8422 ASSERT_EQ(0, rbd_flush(image));
8423
8424 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 16));
8425 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 1 << (order + 1)));
8426 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 4096 + 1));
8427 ASSERT_EQ(0, rbd_sparsify(image, 4096));
8428
8429 ASSERT_PASSED(read_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
8430}
8431
8432TEST_F(TestLibRBD, SparsifyPP)
8433{
8434 librados::IoCtx ioctx;
8435 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8436
8437 librbd::RBD rbd;
8438 std::string name = get_temp_image_name();
8439 uint64_t size = 12 * 1024 * 1024;
8440 int order = 0;
8441 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8442
8443 librbd::Image image;
8444 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
8445
8446 bufferlist bl;
8447 bl.append(std::string(4096, '\0'));
8448 bl.append(std::string(4096, '1'));
8449 bl.append(std::string(4096, '\0'));
8450 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
8451 ASSERT_EQ(0, image.flush());
8452
8453 ASSERT_EQ(-EINVAL, image.sparsify(16));
8454 ASSERT_EQ(-EINVAL, image.sparsify(1 << (order + 1)));
8455 ASSERT_EQ(-EINVAL, image.sparsify(4096 + 1));
8456 ASSERT_EQ(0, image.sparsify(4096));
8457
8458 bufferlist read_bl;
8459 ASSERT_EQ((ssize_t)bl.length(), image.read(0, bl.length(), read_bl));
8460 ASSERT_TRUE(bl.contents_equal(read_bl));
8461
8462 ASSERT_PASSED(validate_object_map, image);
8463}
8464
7c673cae
FG
8465TEST_F(TestLibRBD, SnapshotLimit)
8466{
8467 rados_ioctx_t ioctx;
8468 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8469
8470 rbd_image_t image;
8471 int order = 0;
8472 std::string name = get_temp_image_name();
8473 uint64_t size = 2 << 20;
8474 uint64_t limit;
8475
8476 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8477 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8478
8479 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
8480 ASSERT_EQ(UINT64_MAX, limit);
8481 ASSERT_EQ(0, rbd_snap_set_limit(image, 2));
8482 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
8483 ASSERT_EQ(2U, limit);
8484
8485 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
11fdf7f2 8486 ASSERT_EQ(-ERANGE, rbd_snap_set_limit(image, 0));
7c673cae
FG
8487 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
8488 ASSERT_EQ(-EDQUOT, rbd_snap_create(image, "snap3"));
8489 ASSERT_EQ(0, rbd_snap_set_limit(image, UINT64_MAX));
8490 ASSERT_EQ(0, rbd_snap_create(image, "snap3"));
8491 ASSERT_EQ(0, rbd_close(image));
8492
8493 rados_ioctx_destroy(ioctx);
8494}
8495
8496
8497TEST_F(TestLibRBD, SnapshotLimitPP)
8498{
8499 librados::IoCtx ioctx;
8500 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8501
8502 {
8503 librbd::RBD rbd;
8504 librbd::Image image;
8505 std::string name = get_temp_image_name();
8506 uint64_t size = 2 << 20;
8507 int order = 0;
8508 uint64_t limit;
8509
8510 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8511 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8512
8513 ASSERT_EQ(0, image.snap_get_limit(&limit));
8514 ASSERT_EQ(UINT64_MAX, limit);
8515 ASSERT_EQ(0, image.snap_set_limit(2));
8516 ASSERT_EQ(0, image.snap_get_limit(&limit));
8517 ASSERT_EQ(2U, limit);
8518
8519 ASSERT_EQ(0, image.snap_create("snap1"));
11fdf7f2 8520 ASSERT_EQ(-ERANGE, image.snap_set_limit(0));
7c673cae
FG
8521 ASSERT_EQ(0, image.snap_create("snap2"));
8522 ASSERT_EQ(-EDQUOT, image.snap_create("snap3"));
8523 ASSERT_EQ(0, image.snap_set_limit(UINT64_MAX));
8524 ASSERT_EQ(0, image.snap_create("snap3"));
8525 }
8526
8527 ioctx.close();
8528}
8529
8530TEST_F(TestLibRBD, RebuildObjectMapViaLockOwner)
8531{
8532 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
8533
8534 librados::IoCtx ioctx;
8535 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8536
8537 librbd::RBD rbd;
8538 std::string name = get_temp_image_name();
8539 uint64_t size = 2 << 20;
8540 int order = 0;
8541 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8542
8543 std::string object_map_oid;
8544 {
8545 librbd::Image image;
8546 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8547
8548 std::string image_id;
8549 ASSERT_EQ(0, get_image_id(image, &image_id));
8550 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
8551 }
8552
8553 // corrupt the object map
8554 bufferlist bl;
8555 bl.append("foo");
8556 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
8557
8558 librbd::Image image1;
8559 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8560
8561 bool lock_owner;
8562 bl.clear();
8563 ASSERT_EQ(0, image1.write(0, 0, bl));
8564 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8565 ASSERT_TRUE(lock_owner);
8566
8567 uint64_t flags;
8568 ASSERT_EQ(0, image1.get_flags(&flags));
8569 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
8570
8571 librbd::Image image2;
8572 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8573 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8574 ASSERT_FALSE(lock_owner);
8575
8576 PrintProgress prog_ctx;
8577 ASSERT_EQ(0, image2.rebuild_object_map(prog_ctx));
8578 ASSERT_PASSED(validate_object_map, image1);
8579 ASSERT_PASSED(validate_object_map, image2);
8580}
8581
8582TEST_F(TestLibRBD, RenameViaLockOwner)
8583{
cd265ab1 8584 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7c673cae
FG
8585
8586 librados::IoCtx ioctx;
8587 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8588
8589 librbd::RBD rbd;
8590 std::string name = get_temp_image_name();
8591 uint64_t size = 2 << 20;
8592 int order = 0;
8593 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8594
8595 librbd::Image image1;
8596 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8597
cd265ab1
TL
8598 bool lock_owner;
8599 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8600 ASSERT_FALSE(lock_owner);
8601
8602 std::string new_name = get_temp_image_name();
8603 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
8604 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8605 ASSERT_FALSE(lock_owner);
8606
7c673cae
FG
8607 bufferlist bl;
8608 ASSERT_EQ(0, image1.write(0, 0, bl));
7c673cae
FG
8609 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8610 ASSERT_TRUE(lock_owner);
8611
cd265ab1
TL
8612 name = new_name;
8613 new_name = get_temp_image_name();
7c673cae
FG
8614 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
8615 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8616 ASSERT_TRUE(lock_owner);
8617
8618 librbd::Image image2;
8619 ASSERT_EQ(0, rbd.open(ioctx, image2, new_name.c_str(), NULL));
8620}
8621
8622TEST_F(TestLibRBD, SnapCreateViaLockOwner)
8623{
94b18763 8624 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7c673cae
FG
8625
8626 librados::IoCtx ioctx;
8627 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8628
8629 librbd::RBD rbd;
8630 std::string name = get_temp_image_name();
8631 uint64_t size = 2 << 20;
8632 int order = 0;
8633 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8634
8635 librbd::Image image1;
8636 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8637
8638 // switch to writeback cache
8639 ASSERT_EQ(0, image1.flush());
8640
8641 bufferlist bl;
8642 bl.append(std::string(4096, '1'));
8643 ASSERT_EQ((ssize_t)bl.length(), image1.write(0, bl.length(), bl));
8644
8645 bool lock_owner;
8646 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8647 ASSERT_TRUE(lock_owner);
8648
8649 librbd::Image image2;
8650 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8651
8652 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8653 ASSERT_FALSE(lock_owner);
8654
8655 ASSERT_EQ(0, image2.snap_create("snap1"));
8656 bool exists;
8657 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
8658 ASSERT_TRUE(exists);
8659 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
8660 ASSERT_TRUE(exists);
8661
8662 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8663 ASSERT_TRUE(lock_owner);
8664}
8665
8666TEST_F(TestLibRBD, SnapRemoveViaLockOwner)
8667{
94b18763 8668 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
7c673cae
FG
8669
8670 librados::IoCtx ioctx;
8671 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8672
8673 librbd::RBD rbd;
8674 std::string name = get_temp_image_name();
8675 uint64_t size = 2 << 20;
8676 int order = 0;
8677 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8678
8679 librbd::Image image1;
8680 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8681
8682 bufferlist bl;
8683 ASSERT_EQ(0, image1.write(0, 0, bl));
8684 ASSERT_EQ(0, image1.snap_create("snap1"));
8685
8686 bool lock_owner;
8687 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8688 ASSERT_TRUE(lock_owner);
8689
8690 librbd::Image image2;
8691 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8692
8693 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8694 ASSERT_FALSE(lock_owner);
8695
8696 ASSERT_EQ(0, image2.snap_remove("snap1"));
8697 bool exists;
8698 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
8699 ASSERT_FALSE(exists);
8700 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
8701 ASSERT_FALSE(exists);
8702
8703 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8704 ASSERT_TRUE(lock_owner);
8705}
8706
20effc67 8707TEST_F(TestLibRBD, UpdateFeaturesViaLockOwner) {
20effc67
TL
8708 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
8709
8710 librados::IoCtx ioctx;
8711 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8712
8713 std::string name = get_temp_image_name();
8714 uint64_t size = 2 << 20;
8715 librbd::RBD rbd;
8716 int order = 0;
8717 //creates full with rbd default features
8718 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8719
8720 bool lock_owner;
8721 librbd::Image image1;
8722 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8723 bufferlist bl;
8724 ASSERT_EQ(0, image1.write(0, 0, bl));
8725 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8726 ASSERT_TRUE(lock_owner);
8727
8728 librbd::Image image2;
8729 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8730 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8731 ASSERT_FALSE(lock_owner);
8732
8733 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_OBJECT_MAP, false));
8734 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8735 ASSERT_FALSE(lock_owner);
8736
8737 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_OBJECT_MAP, true));
8738 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8739 ASSERT_FALSE(lock_owner);
8740
8741}
8742
91327a77
AA
8743TEST_F(TestLibRBD, EnableJournalingViaLockOwner)
8744{
8745 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
8746
8747 librados::IoCtx ioctx;
8748 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8749
8750 librbd::RBD rbd;
8751 std::string name = get_temp_image_name();
8752 uint64_t size = 2 << 20;
8753 int order = 0;
8754 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8755
8756 librbd::Image image1;
8757 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8758
8759 bufferlist bl;
8760 ASSERT_EQ(0, image1.write(0, 0, bl));
8761
8762 bool lock_owner;
8763 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8764 ASSERT_TRUE(lock_owner);
8765
8766 librbd::Image image2;
8767 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8768
8769 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, false));
8770
8771 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8772 ASSERT_TRUE(lock_owner);
8773 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8774 ASSERT_FALSE(lock_owner);
8775
8776 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, true));
8777
8778 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8779 ASSERT_FALSE(lock_owner);
8780 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8781 ASSERT_TRUE(lock_owner);
8782}
8783
7c673cae
FG
8784TEST_F(TestLibRBD, SnapRemove2)
8785{
8786 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8787
8788 librados::IoCtx ioctx;
8789 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8790
8791 librbd::RBD rbd;
8792 std::string name = get_temp_image_name();
8793 uint64_t size = 2 << 20;
8794 int order = 0;
8795 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8796
8797 librbd::Image image1;
8798 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8799
8800 bufferlist bl;
8801 ASSERT_EQ(0, image1.write(0, 0, bl));
8802 ASSERT_EQ(0, image1.snap_create("snap1"));
8803 bool exists;
8804 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
8805 ASSERT_TRUE(exists);
8806 ASSERT_EQ(0, image1.snap_protect("snap1"));
8807 bool is_protected;
8808 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
8809 ASSERT_TRUE(is_protected);
8810
8811 uint64_t features;
8812 ASSERT_EQ(0, image1.features(&features));
8813
8814 std::string child_name = get_temp_image_name();
8815 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
8816 child_name.c_str(), features, &order));
8817
8818 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
8819 ASSERT_TRUE(exists);
8820 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
8821 ASSERT_TRUE(is_protected);
8822
8823 ASSERT_EQ(-EBUSY, image1.snap_remove("snap1"));
8824 PrintProgress pp;
8825 ASSERT_EQ(0, image1.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE, pp));
8826 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
8827 ASSERT_FALSE(exists);
8828}
8829
8830TEST_F(TestLibRBD, SnapRenameViaLockOwner)
8831{
8832 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
8833
8834 librados::IoCtx ioctx;
8835 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8836
8837 librbd::RBD rbd;
8838 std::string name = get_temp_image_name();
8839 uint64_t size = 2 << 20;
8840 int order = 0;
8841 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8842
8843 librbd::Image image1;
8844 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8845
8846 bufferlist bl;
8847 ASSERT_EQ(0, image1.write(0, 0, bl));
8848 ASSERT_EQ(0, image1.snap_create("snap1"));
8849
8850 bool lock_owner;
8851 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8852 ASSERT_TRUE(lock_owner);
8853
8854 librbd::Image image2;
8855 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8856
8857 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8858 ASSERT_FALSE(lock_owner);
8859
8860 ASSERT_EQ(0, image2.snap_rename("snap1", "snap1-rename"));
8861 bool exists;
8862 ASSERT_EQ(0, image1.snap_exists2("snap1-rename", &exists));
8863 ASSERT_TRUE(exists);
8864 ASSERT_EQ(0, image2.snap_exists2("snap1-rename", &exists));
8865 ASSERT_TRUE(exists);
8866
8867 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8868 ASSERT_TRUE(lock_owner);
8869}
8870
8871TEST_F(TestLibRBD, SnapProtectViaLockOwner)
8872{
8873 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
8874
8875 librados::IoCtx ioctx;
8876 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8877
8878 librbd::RBD rbd;
8879 std::string name = get_temp_image_name();
8880 uint64_t size = 2 << 20;
8881 int order = 0;
8882 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8883
8884 librbd::Image image1;
8885 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8886
8887 bufferlist bl;
8888 ASSERT_EQ(0, image1.write(0, 0, bl));
8889
8890 bool lock_owner;
8891 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8892 ASSERT_TRUE(lock_owner);
8893 ASSERT_EQ(0, image1.snap_create("snap1"));
8894
8895 librbd::Image image2;
8896 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8897
8898 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8899 ASSERT_FALSE(lock_owner);
8900
8901 ASSERT_EQ(0, image2.snap_protect("snap1"));
8902 bool is_protected;
8903 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
8904 ASSERT_TRUE(is_protected);
8905 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
8906 ASSERT_TRUE(is_protected);
8907
8908 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8909 ASSERT_TRUE(lock_owner);
8910}
8911
8912TEST_F(TestLibRBD, SnapUnprotectViaLockOwner)
8913{
8914 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
8915
8916 librados::IoCtx ioctx;
8917 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8918
8919 librbd::RBD rbd;
8920 std::string name = get_temp_image_name();
8921 uint64_t size = 2 << 20;
8922 int order = 0;
8923 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8924
8925 librbd::Image image1;
8926 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8927
8928 bufferlist bl;
8929 ASSERT_EQ(0, image1.write(0, 0, bl));
8930
8931 bool lock_owner;
8932 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8933 ASSERT_TRUE(lock_owner);
8934 ASSERT_EQ(0, image1.snap_create("snap1"));
8935 ASSERT_EQ(0, image1.snap_protect("snap1"));
8936 bool is_protected;
8937 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
8938 ASSERT_TRUE(is_protected);
8939
8940 librbd::Image image2;
8941 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8942
8943 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8944 ASSERT_FALSE(lock_owner);
8945
8946 ASSERT_EQ(0, image2.snap_unprotect("snap1"));
8947 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
8948 ASSERT_FALSE(is_protected);
8949 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
8950 ASSERT_FALSE(is_protected);
8951
8952 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8953 ASSERT_TRUE(lock_owner);
8954}
8955
8956TEST_F(TestLibRBD, FlattenViaLockOwner)
8957{
8958 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
8959
8960 librados::IoCtx ioctx;
8961 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8962
8963 librbd::RBD rbd;
8964 std::string parent_name = get_temp_image_name();
8965 uint64_t size = 2 << 20;
8966 int order = 0;
8967 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
8968
8969 librbd::Image parent_image;
8970 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
8971 ASSERT_EQ(0, parent_image.snap_create("snap1"));
8972 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
8973
8974 uint64_t features;
8975 ASSERT_EQ(0, parent_image.features(&features));
8976
8977 std::string name = get_temp_image_name();
8978 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
8979 name.c_str(), features, &order));
8980
8981 librbd::Image image1;
8982 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8983
8984 bufferlist bl;
8985 ASSERT_EQ(0, image1.write(0, 0, bl));
8986
8987 bool lock_owner;
8988 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8989 ASSERT_TRUE(lock_owner);
8990
8991 librbd::Image image2;
8992 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8993
8994 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
8995 ASSERT_FALSE(lock_owner);
8996
8997 ASSERT_EQ(0, image2.flatten());
8998
8999 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9000 ASSERT_TRUE(lock_owner);
9001 ASSERT_PASSED(validate_object_map, image1);
9002}
9003
9004TEST_F(TestLibRBD, ResizeViaLockOwner)
9005{
9006 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
9007
9008 librados::IoCtx ioctx;
9009 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9010
9011 librbd::RBD rbd;
9012 std::string name = get_temp_image_name();
9013 uint64_t size = 2 << 20;
9014 int order = 0;
9015 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9016
9017 librbd::Image image1;
9018 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9019
9020 bufferlist bl;
9021 ASSERT_EQ(0, image1.write(0, 0, bl));
9022
9023 bool lock_owner;
9024 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9025 ASSERT_TRUE(lock_owner);
9026
9027 librbd::Image image2;
9028 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
9029
9030 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
9031 ASSERT_FALSE(lock_owner);
9032
9033 ASSERT_EQ(0, image2.resize(0));
9034
9035 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9036 ASSERT_TRUE(lock_owner);
9037 ASSERT_PASSED(validate_object_map, image1);
9038}
9039
11fdf7f2
TL
9040TEST_F(TestLibRBD, SparsifyViaLockOwner)
9041{
9042 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
9043
9044 librados::IoCtx ioctx;
9045 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9046
9047 librbd::RBD rbd;
9048 std::string name = get_temp_image_name();
9049 uint64_t size = 2 << 20;
9050 int order = 0;
9051 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9052
9053 librbd::Image image1;
9054 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9055
9056 bufferlist bl;
9057 ASSERT_EQ(0, image1.write(0, 0, bl));
9058
9059 bool lock_owner;
9060 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9061 ASSERT_TRUE(lock_owner);
9062
9063 librbd::Image image2;
9064 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
9065
9066 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
9067 ASSERT_FALSE(lock_owner);
9068
9069 ASSERT_EQ(0, image2.sparsify(4096));
9070
9071 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9072 ASSERT_TRUE(lock_owner);
9073 ASSERT_PASSED(validate_object_map, image1);
9074}
9075
7c673cae
FG
9076TEST_F(TestLibRBD, ObjectMapConsistentSnap)
9077{
9078 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
9079
9080 librados::IoCtx ioctx;
9081 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9082
9083 librbd::RBD rbd;
9084 std::string name = get_temp_image_name();
9085 uint64_t size = 1 << 20;
9086 int order = 12;
9087 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9088
9089 librbd::Image image1;
9090 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9091
7c673cae
FG
9092 int num_snaps = 10;
9093 for (int i = 0; i < num_snaps; ++i) {
9094 std::string snap_name = "snap" + stringify(i);
9095 ASSERT_EQ(0, image1.snap_create(snap_name.c_str()));
9096 }
9097
31f18b77
FG
9098
9099 thread writer([&image1](){
9100 librbd::image_info_t info;
9101 int r = image1.stat(info, sizeof(info));
11fdf7f2 9102 ceph_assert(r == 0);
31f18b77
FG
9103 bufferlist bl;
9104 bl.append("foo");
9105 for (unsigned i = 0; i < info.num_objs; ++i) {
9106 r = image1.write((1 << info.order) * i, bl.length(), bl);
11fdf7f2 9107 ceph_assert(r == (int) bl.length());
31f18b77
FG
9108 }
9109 });
7c673cae
FG
9110 writer.join();
9111
9112 for (int i = 0; i < num_snaps; ++i) {
9113 std::string snap_name = "snap" + stringify(i);
9114 ASSERT_EQ(0, image1.snap_set(snap_name.c_str()));
9115 ASSERT_PASSED(validate_object_map, image1);
9116 }
9117
9118 ASSERT_EQ(0, image1.snap_set(NULL));
9119 ASSERT_PASSED(validate_object_map, image1);
9120}
9121
9122void memset_rand(char *buf, size_t len) {
9123 for (size_t i = 0; i < len; ++i) {
9124 buf[i] = (char) (rand() % (126 - 33) + 33);
9125 }
9126}
9127
9128TEST_F(TestLibRBD, Metadata)
9129{
9130 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
9131
9132 rados_ioctx_t ioctx;
9133 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9134
9135 std::string name = get_temp_image_name();
9136 uint64_t size = 2 << 20;
9137 int order = 0;
9138 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9139
9140 rbd_image_t image;
9141 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
9142
9143 rbd_image_t image1;
9144 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
9145
9146 char keys[1024];
9147 char vals[1024];
9148 size_t keys_len = sizeof(keys);
9149 size_t vals_len = sizeof(vals);
9150
9151 memset_rand(keys, keys_len);
9152 memset_rand(vals, vals_len);
9153
f67539c2 9154 ASSERT_EQ(0, rbd_metadata_list(image, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9155 &vals_len));
9156 ASSERT_EQ(0U, keys_len);
9157 ASSERT_EQ(0U, vals_len);
9158
9159 char value[1024];
9160 size_t value_len = sizeof(value);
9161 memset_rand(value, value_len);
9162
9163 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
9164 ASSERT_EQ(0, rbd_metadata_set(image1, "key2", "value2"));
9165 ASSERT_EQ(0, rbd_metadata_get(image1, "key1", value, &value_len));
9166 ASSERT_STREQ(value, "value1");
9167 value_len = 1;
9168 ASSERT_EQ(-ERANGE, rbd_metadata_get(image1, "key1", value, &value_len));
9169 ASSERT_EQ(value_len, strlen("value1") + 1);
9170
f67539c2 9171 ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9172 &vals_len));
9173 keys_len = sizeof(keys);
9174 vals_len = sizeof(vals);
9175 memset_rand(keys, keys_len);
9176 memset_rand(vals, vals_len);
f67539c2 9177 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9178 &vals_len));
9179 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
9180 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
9181 ASSERT_STREQ(keys, "key1");
9182 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
9183 ASSERT_STREQ(vals, "value1");
9184 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
9185
9186 ASSERT_EQ(0, rbd_metadata_remove(image1, "key1"));
d2e6a577 9187 ASSERT_EQ(-ENOENT, rbd_metadata_remove(image1, "key3"));
7c673cae
FG
9188 value_len = sizeof(value);
9189 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key3", value, &value_len));
f67539c2 9190 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9191 &vals_len));
9192 ASSERT_EQ(keys_len, strlen("key2") + 1);
9193 ASSERT_EQ(vals_len, strlen("value2") + 1);
9194 ASSERT_STREQ(keys, "key2");
9195 ASSERT_STREQ(vals, "value2");
9196
9197 // test config setting
9198 ASSERT_EQ(0, rbd_metadata_set(image1, "conf_rbd_cache", "false"));
9199 ASSERT_EQ(-EINVAL, rbd_metadata_set(image1, "conf_rbd_cache", "INVALID_VAL"));
9200 ASSERT_EQ(0, rbd_metadata_remove(image1, "conf_rbd_cache"));
9201
9202 // test metadata with snapshot adding
9203 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
9204 ASSERT_EQ(0, rbd_snap_protect(image1, "snap1"));
9205 ASSERT_EQ(0, rbd_snap_set(image1, "snap1"));
9206
f67539c2
TL
9207 ASSERT_EQ(-EROFS, rbd_metadata_set(image1, "key1", "value1"));
9208 ASSERT_EQ(-EROFS, rbd_metadata_remove(image1, "key2"));
7c673cae
FG
9209
9210 keys_len = sizeof(keys);
9211 vals_len = sizeof(vals);
9212 memset_rand(keys, keys_len);
9213 memset_rand(vals, vals_len);
f67539c2 9214 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae 9215 &vals_len));
f67539c2
TL
9216 ASSERT_EQ(keys_len, strlen("key2") + 1);
9217 ASSERT_EQ(vals_len, strlen("value2") + 1);
9218 ASSERT_STREQ(keys, "key2");
9219 ASSERT_STREQ(vals, "value2");
7c673cae
FG
9220
9221 ASSERT_EQ(0, rbd_snap_set(image1, NULL));
f67539c2
TL
9222 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
9223 ASSERT_EQ(0, rbd_metadata_set(image1, "key3", "value3"));
7c673cae
FG
9224 keys_len = sizeof(keys);
9225 vals_len = sizeof(vals);
9226 memset_rand(keys, keys_len);
9227 memset_rand(vals, vals_len);
f67539c2 9228 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9229 &vals_len));
9230 ASSERT_EQ(keys_len,
9231 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
9232 ASSERT_EQ(vals_len,
9233 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
9234 ASSERT_STREQ(keys, "key1");
9235 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
9236 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
9237 ASSERT_STREQ(vals, "value1");
9238 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
9239 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
9240
9241 // test metadata with cloning
9242 uint64_t features;
9243 ASSERT_EQ(0, rbd_get_features(image1, &features));
9244
9245 string cname = get_temp_image_name();
9246 EXPECT_EQ(0, rbd_clone(ioctx, name.c_str(), "snap1", ioctx,
9247 cname.c_str(), features, &order));
9248 rbd_image_t image2;
9249 ASSERT_EQ(0, rbd_open(ioctx, cname.c_str(), &image2, NULL));
9250 ASSERT_EQ(0, rbd_metadata_set(image2, "key4", "value4"));
9251
9252 keys_len = sizeof(keys);
9253 vals_len = sizeof(vals);
9254 memset_rand(keys, keys_len);
9255 memset_rand(vals, vals_len);
f67539c2 9256 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9257 &vals_len));
9258 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
9259 1 + strlen("key4") + 1);
9260 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
9261 strlen("value3") + 1 + strlen("value4") + 1);
9262 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
9263 1, "key4");
9264 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1 +
9265 strlen("value3") + 1, "value4");
9266
f67539c2 9267 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9268 &vals_len));
9269 ASSERT_EQ(keys_len,
9270 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
9271 ASSERT_EQ(vals_len,
9272 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
9273 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key4", value, &value_len));
9274
9275 // test short buffer cases
9276 keys_len = strlen("key1") + 1;
9277 vals_len = strlen("value1") + 1;
9278 memset_rand(keys, keys_len);
9279 memset_rand(vals, vals_len);
f67539c2 9280 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 1, keys, &keys_len, vals,
7c673cae
FG
9281 &vals_len));
9282 ASSERT_EQ(keys_len, strlen("key1") + 1);
9283 ASSERT_EQ(vals_len, strlen("value1") + 1);
9284 ASSERT_STREQ(keys, "key1");
9285 ASSERT_STREQ(vals, "value1");
9286
f67539c2 9287 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 2, keys, &keys_len, vals,
7c673cae
FG
9288 &vals_len));
9289 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
9290 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
9291
f67539c2 9292 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
7c673cae
FG
9293 &vals_len));
9294 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
9295 1 + strlen("key4") + 1);
9296 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
9297 strlen("value3") + 1 + strlen("value4") + 1);
9298
9299 // test `start` param
9300 keys_len = sizeof(keys);
9301 vals_len = sizeof(vals);
9302 memset_rand(keys, keys_len);
9303 memset_rand(vals, vals_len);
9304 ASSERT_EQ(0, rbd_metadata_list(image2, "key2", 0, keys, &keys_len, vals,
9305 &vals_len));
9306 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
9307 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
9308 ASSERT_STREQ(keys, "key3");
9309 ASSERT_STREQ(vals, "value3");
9310
9311 ASSERT_EQ(0, rbd_close(image));
9312 ASSERT_EQ(0, rbd_close(image1));
9313 ASSERT_EQ(0, rbd_close(image2));
31f18b77 9314 rados_ioctx_destroy(ioctx);
7c673cae
FG
9315}
9316
9317TEST_F(TestLibRBD, MetadataPP)
9318{
9319 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
9320
9321 librados::IoCtx ioctx;
9322 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9323
9324 librbd::RBD rbd;
9325 string name = get_temp_image_name();
9326 uint64_t size = 2 << 20;
9327 int order = 0;
9328 uint64_t features;
9329 string value;
9330 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9331
9332 librbd::Image image1;
9333 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9334 map<string, bufferlist> pairs;
f67539c2 9335 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
9336 ASSERT_TRUE(pairs.empty());
9337
9338 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
9339 ASSERT_EQ(0, image1.metadata_set("key2", "value2"));
9340 ASSERT_EQ(0, image1.metadata_get("key1", &value));
9341 ASSERT_EQ(0, strcmp("value1", value.c_str()));
f67539c2 9342 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
9343 ASSERT_EQ(2U, pairs.size());
9344 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
9345 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
9346
9347 pairs.clear();
9348 ASSERT_EQ(0, image1.metadata_remove("key1"));
d2e6a577 9349 ASSERT_EQ(-ENOENT, image1.metadata_remove("key3"));
7c673cae 9350 ASSERT_TRUE(image1.metadata_get("key3", &value) < 0);
f67539c2 9351 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
9352 ASSERT_EQ(1U, pairs.size());
9353 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
9354
9355 // test config setting
9356 ASSERT_EQ(0, image1.metadata_set("conf_rbd_cache", "false"));
9357 ASSERT_EQ(-EINVAL, image1.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
9358 ASSERT_EQ(0, image1.metadata_remove("conf_rbd_cache"));
9359
9360 // test metadata with snapshot adding
9361 ASSERT_EQ(0, image1.snap_create("snap1"));
9362 ASSERT_EQ(0, image1.snap_protect("snap1"));
9363 ASSERT_EQ(0, image1.snap_set("snap1"));
9364
9365 pairs.clear();
f67539c2
TL
9366 ASSERT_EQ(-EROFS, image1.metadata_set("key1", "value1"));
9367 ASSERT_EQ(-EROFS, image1.metadata_remove("key2"));
9368 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
9369 ASSERT_EQ(1U, pairs.size());
7c673cae 9370 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7c673cae
FG
9371
9372 ASSERT_EQ(0, image1.snap_set(NULL));
f67539c2
TL
9373 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
9374 ASSERT_EQ(0, image1.metadata_set("key3", "value3"));
9375 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
9376 ASSERT_EQ(3U, pairs.size());
9377 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
9378 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
9379 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
9380
9381 // test metadata with cloning
9382 string cname = get_temp_image_name();
9383 librbd::Image image2;
9384 ASSERT_EQ(0, image1.features(&features));
9385 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
9386 cname.c_str(), features, &order));
9387 ASSERT_EQ(0, rbd.open(ioctx, image2, cname.c_str(), NULL));
9388 ASSERT_EQ(0, image2.metadata_set("key4", "value4"));
9389 pairs.clear();
f67539c2 9390 ASSERT_EQ(0, image2.metadata_list("key", 0, &pairs));
7c673cae
FG
9391 ASSERT_EQ(4U, pairs.size());
9392 pairs.clear();
f67539c2 9393 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
9394 ASSERT_EQ(3U, pairs.size());
9395 ASSERT_EQ(-ENOENT, image1.metadata_get("key4", &value));
9396}
9397
9398TEST_F(TestLibRBD, UpdateFeatures)
9399{
9400 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
9401
9402 librados::IoCtx ioctx;
9403 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9404
9405 librbd::RBD rbd;
9406 std::string name = get_temp_image_name();
9407 uint64_t size = 1 << 20;
9408 int order = 0;
9409 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9410
9411 librbd::Image image;
9412 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9413
9414 uint8_t old_format;
9415 ASSERT_EQ(0, image.old_format(&old_format));
9416 if (old_format) {
9417 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
9418 return;
9419 }
9420
9421 uint64_t features;
9422 ASSERT_EQ(0, image.features(&features));
9423
9424 // must provide a single feature
9425 ASSERT_EQ(-EINVAL, image.update_features(0, true));
9426
9427 uint64_t disable_features;
9428 disable_features = features & (RBD_FEATURE_EXCLUSIVE_LOCK |
9429 RBD_FEATURE_OBJECT_MAP |
9430 RBD_FEATURE_FAST_DIFF |
9431 RBD_FEATURE_JOURNALING);
9432 if (disable_features != 0) {
9433 ASSERT_EQ(0, image.update_features(disable_features, false));
9434 }
9435
9436 ASSERT_EQ(0, image.features(&features));
9437 ASSERT_EQ(0U, features & disable_features);
9438
9439 // cannot enable object map nor journaling w/o exclusive lock
9440 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
9441 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_JOURNALING, true));
9442 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
9443
9444 ASSERT_EQ(0, image.features(&features));
9445 ASSERT_NE(0U, features & RBD_FEATURE_EXCLUSIVE_LOCK);
9446
11fdf7f2
TL
9447 // can enable fast diff w/o object map
9448 ASSERT_EQ(0, image.update_features(RBD_FEATURE_FAST_DIFF, true));
9449 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
7c673cae
FG
9450 ASSERT_EQ(0, image.features(&features));
9451 ASSERT_NE(0U, features & RBD_FEATURE_OBJECT_MAP);
9452
11fdf7f2
TL
9453 uint64_t expected_flags = RBD_FLAG_OBJECT_MAP_INVALID |
9454 RBD_FLAG_FAST_DIFF_INVALID;
7c673cae
FG
9455 uint64_t flags;
9456 ASSERT_EQ(0, image.get_flags(&flags));
9457 ASSERT_EQ(expected_flags, flags);
9458
9459 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
9460 ASSERT_EQ(0, image.features(&features));
9461 ASSERT_EQ(0U, features & RBD_FEATURE_OBJECT_MAP);
9462
11fdf7f2
TL
9463 // can disable object map w/ fast diff
9464 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
9465 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
9466 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_FAST_DIFF, false));
7c673cae
FG
9467 ASSERT_EQ(0, image.features(&features));
9468 ASSERT_EQ(0U, features & RBD_FEATURE_FAST_DIFF);
9469
7c673cae 9470 ASSERT_EQ(0, image.get_flags(&flags));
11fdf7f2 9471 ASSERT_EQ(0U, flags);
7c673cae
FG
9472
9473 // cannot disable exclusive lock w/ object map
11fdf7f2 9474 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
7c673cae
FG
9475 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
9476 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
9477
9478 // cannot disable exclusive lock w/ journaling
11fdf7f2 9479 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, true));
7c673cae
FG
9480 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
9481 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, false));
9482
9483 ASSERT_EQ(0, image.get_flags(&flags));
9484 ASSERT_EQ(0U, flags);
9485
9486 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
9487
9488 ASSERT_EQ(0, image.features(&features));
9489 if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0) {
9490 ASSERT_EQ(0, image.update_features(RBD_FEATURE_DEEP_FLATTEN, false));
9491 }
9492 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_DEEP_FLATTEN, true));
9493}
9494
9f95a23c
TL
9495TEST_F(TestLibRBD, FeaturesBitmaskString)
9496{
9497 librbd::RBD rbd;
9498 uint64_t features = RBD_FEATURES_DEFAULT;
9499
9500 std::string features_str;
9501 std::string expected_str = "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
9502 rbd.features_to_string(features, &features_str);
9503 ASSERT_EQ(expected_str, features_str);
9504
9505 features = RBD_FEATURE_LAYERING;
9506 features_str = "";
9507 expected_str = "layering";
9508 rbd.features_to_string(features, &features_str);
9509 ASSERT_EQ(expected_str, features_str);
9510
9511 uint64_t features_bitmask;
9512 features_str = "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
9513 rbd.features_from_string(features_str, &features_bitmask);
9514 ASSERT_EQ(features_bitmask, RBD_FEATURES_DEFAULT);
9515
9516 features_str = "layering";
9517 features_bitmask = 0;
9518 rbd.features_from_string(features_str, &features_bitmask);
9519 ASSERT_EQ(features_bitmask, RBD_FEATURE_LAYERING);
9520}
9521
7c673cae
FG
9522TEST_F(TestLibRBD, RebuildObjectMap)
9523{
9524 librados::IoCtx ioctx;
9525 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9526
9527 librbd::RBD rbd;
9528 std::string name = get_temp_image_name();
9529 uint64_t size = 1 << 20;
9530 int order = 18;
9531 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9532
9533 PrintProgress prog_ctx;
9534 std::string object_map_oid;
9535 bufferlist bl;
9536 bl.append("foo");
9537 {
9538 librbd::Image image;
9539 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9540
9541 uint64_t features;
9542 ASSERT_EQ(0, image.features(&features));
9543 if ((features & RBD_FEATURE_OBJECT_MAP) == 0) {
9544 ASSERT_EQ(-EINVAL, image.rebuild_object_map(prog_ctx));
9545 return;
9546 }
9547
9548 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
9549
9550 ASSERT_EQ(0, image.snap_create("snap1"));
9551 ASSERT_EQ((ssize_t)bl.length(), image.write(1<<order, bl.length(), bl));
9552
9553 std::string image_id;
9554 ASSERT_EQ(0, get_image_id(image, &image_id));
9555 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
9556 }
9557
9558 // corrupt the object map
9559 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
9560
9561 librbd::Image image1;
9562 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9563
9564 bool lock_owner;
9565 bl.clear();
9566 ASSERT_EQ(0, image1.write(0, 0, bl));
9567 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9568 ASSERT_TRUE(lock_owner);
9569
9570 uint64_t flags;
9571 ASSERT_EQ(0, image1.get_flags(&flags));
9572 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
9573
9574 ASSERT_EQ(0, image1.rebuild_object_map(prog_ctx));
9575
9576 librbd::Image image2;
9577 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
9578
9579 bufferlist read_bl;
9580 ASSERT_EQ((ssize_t)bl.length(), image2.read(0, bl.length(), read_bl));
9581 ASSERT_TRUE(bl.contents_equal(read_bl));
9582
9583 read_bl.clear();
9584 ASSERT_EQ((ssize_t)bl.length(), image2.read(1<<order, bl.length(), read_bl));
9585 ASSERT_TRUE(bl.contents_equal(read_bl));
9586
9587 ASSERT_PASSED(validate_object_map, image1);
9588 ASSERT_PASSED(validate_object_map, image2);
9589}
9590
9591TEST_F(TestLibRBD, RebuildNewObjectMap)
9592{
9593 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
9594
9595 rados_ioctx_t ioctx;
9596 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9597
9598 std::string name = get_temp_image_name();
9599 uint64_t size = 1 << 20;
9600 int order = 18;
9601 uint64_t features = RBD_FEATURE_EXCLUSIVE_LOCK;
9602 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
9603 false, features));
9604
9605 rbd_image_t image;
9606 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
9607 ASSERT_EQ(0, rbd_update_features(image, RBD_FEATURE_OBJECT_MAP, true));
9608 ASSERT_EQ(0, rbd_rebuild_object_map(image, print_progress_percent, NULL));
9609
9610 ASSERT_PASSED(validate_object_map, image);
9611
9612 ASSERT_EQ(0, rbd_close(image));
9613 rados_ioctx_destroy(ioctx);
9614}
9615
9616TEST_F(TestLibRBD, CheckObjectMap)
9617{
9618 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
9619
9620 librados::IoCtx ioctx;
9621 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9622
9623 librbd::RBD rbd;
9624 std::string name = get_temp_image_name();
9625 uint64_t size = 1 << 20;
9626 int order = 18;
9627 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9628
9629 PrintProgress prog_ctx;
9630 bufferlist bl1;
9631 bufferlist bl2;
9632 bl1.append("foo");
9633 {
9634 librbd::Image image;
9635 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9636
9637 uint64_t features;
9638 ASSERT_EQ(0, image.features(&features));
9639
9640 ASSERT_EQ((ssize_t)bl1.length(), image.write(0, bl1.length(), bl1));
9641
9642 ASSERT_EQ(0, image.snap_create("snap1"));
9643 ASSERT_EQ((ssize_t)bl1.length(), image.write(1<<order, bl1.length(), bl1));
9644 }
9645
9646 librbd::Image image1;
9647 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9648
9649 std::string image_id;
9650 ASSERT_EQ(0, get_image_id(image1, &image_id));
9651
9652 std::string object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
9653
9654 ASSERT_LT(0, ioctx.read(object_map_oid, bl2, 1024, 0));
9655
9656 bool lock_owner;
9657 ASSERT_EQ((ssize_t)bl1.length(), image1.write(3 * (1 << 18), bl1.length(), bl1));
9658 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9659 ASSERT_TRUE(lock_owner);
9660
9661 //reopen image to reread now corrupt object map from disk
9662 image1.close();
9663
9664 bl1.clear();
9665 ASSERT_LT(0, ioctx.read(object_map_oid, bl1, 1024, 0));
9666 ASSERT_FALSE(bl1.contents_equal(bl2));
9667
9668 ASSERT_EQ(0, ioctx.write_full(object_map_oid, bl2));
9669 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9670
9671 uint64_t flags;
9672 ASSERT_EQ(0, image1.get_flags(&flags));
9673 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
9674
9675 ASSERT_EQ(0, image1.check_object_map(prog_ctx));
9676
9677 ASSERT_EQ(0, image1.get_flags(&flags));
9678 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
9679}
9680
9681TEST_F(TestLibRBD, BlockingAIO)
9682{
9683 librados::IoCtx ioctx;
9684 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9685
7c673cae
FG
9686 librbd::RBD rbd;
9687 std::string name = get_temp_image_name();
9688 uint64_t size = 1 << 20;
9689 int order = 18;
9690 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9691
9692 std::string non_blocking_aio;
9693 ASSERT_EQ(0, _rados.conf_get("rbd_non_blocking_aio", non_blocking_aio));
9694 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio", "0"));
9695 BOOST_SCOPE_EXIT( (non_blocking_aio) ) {
9696 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio",
9697 non_blocking_aio.c_str()));
9698 } BOOST_SCOPE_EXIT_END;
9699
9700 librbd::Image image;
9701 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9702
f67539c2
TL
9703 bool skip_discard = this->is_skip_partial_discard_enabled(image);
9704
7c673cae
FG
9705 bufferlist bl;
9706 ASSERT_EQ(0, image.write(0, bl.length(), bl));
9707
9708 bl.append(std::string(256, '1'));
9709 librbd::RBD::AioCompletion *write_comp =
9710 new librbd::RBD::AioCompletion(NULL, NULL);
9711 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
9712
9713 librbd::RBD::AioCompletion *flush_comp =
9714 new librbd::RBD::AioCompletion(NULL, NULL);
9715 ASSERT_EQ(0, image.aio_flush(flush_comp));
9716 ASSERT_EQ(0, flush_comp->wait_for_complete());
9717 ASSERT_EQ(0, flush_comp->get_return_value());
9718 flush_comp->release();
9719
9720 ASSERT_EQ(1, write_comp->is_complete());
9721 ASSERT_EQ(0, write_comp->get_return_value());
9722 write_comp->release();
9723
9724 librbd::RBD::AioCompletion *discard_comp =
9725 new librbd::RBD::AioCompletion(NULL, NULL);
9726 ASSERT_EQ(0, image.aio_discard(128, 128, discard_comp));
9727 ASSERT_EQ(0, discard_comp->wait_for_complete());
9728 discard_comp->release();
9729
9730 librbd::RBD::AioCompletion *read_comp =
9731 new librbd::RBD::AioCompletion(NULL, NULL);
9732 bufferlist read_bl;
9733 image.aio_read(0, bl.length(), read_bl, read_comp);
9734 ASSERT_EQ(0, read_comp->wait_for_complete());
9735 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
9736 read_comp->release();
9737
9738 bufferlist expected_bl;
9739 expected_bl.append(std::string(128, '1'));
9740 expected_bl.append(std::string(128, skip_discard ? '1' : '\0'));
9741 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
9742}
9743
9744TEST_F(TestLibRBD, ExclusiveLockTransition)
9745{
9746 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
9747
9748 librados::IoCtx ioctx;
9749 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9750
9751 librbd::RBD rbd;
9752 std::string name = get_temp_image_name();
9753
9754 uint64_t size = 1 << 18;
9755 int order = 12;
9756 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9757
9758 librbd::Image image1;
9759 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9760
9761 librbd::Image image2;
9762 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
9763
9764 std::list<librbd::RBD::AioCompletion *> comps;
9765 ceph::bufferlist bl;
9766 bl.append(std::string(1 << order, '1'));
9767 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
9768 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
9769 NULL);
9770 comps.push_back(comp);
9771 if (object_no % 2 == 0) {
9772 ASSERT_EQ(0, image1.aio_write(object_no << order, bl.length(), bl, comp));
9773 } else {
9774 ASSERT_EQ(0, image2.aio_write(object_no << order, bl.length(), bl, comp));
9775 }
9776 }
9777
9778 while (!comps.empty()) {
9779 librbd::RBD::AioCompletion *comp = comps.front();
9780 comps.pop_front();
9781 ASSERT_EQ(0, comp->wait_for_complete());
9782 ASSERT_EQ(1, comp->is_complete());
9783 comp->release();
9784 }
9785
9786 librbd::Image image3;
9787 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
9788 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
9789 bufferlist read_bl;
9790 ASSERT_EQ((ssize_t)bl.length(), image3.read(object_no << order, bl.length(),
9791 read_bl));
9792 ASSERT_TRUE(bl.contents_equal(read_bl));
9793 }
9794
9795 ASSERT_PASSED(validate_object_map, image1);
9796 ASSERT_PASSED(validate_object_map, image2);
9797 ASSERT_PASSED(validate_object_map, image3);
9798}
9799
9800TEST_F(TestLibRBD, ExclusiveLockReadTransition)
9801{
9802 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
9803
9804 librados::IoCtx ioctx;
9805 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9806
9807 librbd::RBD rbd;
9808 std::string name = get_temp_image_name();
9809
9810 uint64_t size = 1 << 18;
9811 int order = 12;
9812 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9813
9814 librbd::Image image1;
9815 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9816
9817 bool lock_owner;
9818 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9819 ASSERT_FALSE(lock_owner);
9820
9821 // journaling should force read ops to acquire the lock
9822 bufferlist read_bl;
9823 ASSERT_EQ(0, image1.read(0, 0, read_bl));
9824
9825 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
9826 ASSERT_TRUE(lock_owner);
9827
9828 librbd::Image image2;
9829 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
9830
9831 std::list<librbd::RBD::AioCompletion *> comps;
9832 std::list<bufferlist> read_bls;
9833 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
9834 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
9835 NULL);
9836 comps.push_back(comp);
9837 read_bls.emplace_back();
9838 if (object_no % 2 == 0) {
9839 ASSERT_EQ(0, image1.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
9840 } else {
9841 ASSERT_EQ(0, image2.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
9842 }
9843 }
9844
9845 while (!comps.empty()) {
9846 librbd::RBD::AioCompletion *comp = comps.front();
9847 comps.pop_front();
9848 ASSERT_EQ(0, comp->wait_for_complete());
9849 ASSERT_EQ(1, comp->is_complete());
9850 comp->release();
9851 }
9852}
9853
9854TEST_F(TestLibRBD, CacheMayCopyOnWrite) {
9855 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
9856
9857 librados::IoCtx ioctx;
9858 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9859
9860 librbd::RBD rbd;
9861 std::string name = get_temp_image_name();
9862
9863 uint64_t size = 1 << 18;
9864 int order = 12;
9865 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9866
9867 librbd::Image image;
9868 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9869 ASSERT_EQ(0, image.snap_create("one"));
9870 ASSERT_EQ(0, image.snap_protect("one"));
9871
9872 std::string clone_name = this->get_temp_image_name();
9873 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
9874 RBD_FEATURE_LAYERING, &order));
9875
9876 librbd::Image clone;
9877 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
9878 ASSERT_EQ(0, clone.flush());
9879
9880 bufferlist expect_bl;
9881 expect_bl.append(std::string(1024, '\0'));
9882
9883 // test double read path
9884 bufferlist read_bl;
9885 uint64_t offset = 0;
9886 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
9887 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
9888
9889 bufferlist write_bl;
9890 write_bl.append(std::string(1024, '1'));
9891 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
9892
9893 read_bl.clear();
9894 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
9895 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
9896
9897 // test read retry path
9898 offset = 1 << order;
9899 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
9900
9901 read_bl.clear();
9902 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
9903 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
9904}
9905
9906TEST_F(TestLibRBD, FlushEmptyOpsOnExternalSnapshot) {
9907 std::string cache_enabled;
9908 ASSERT_EQ(0, _rados.conf_get("rbd_cache", cache_enabled));
9909 ASSERT_EQ(0, _rados.conf_set("rbd_cache", "false"));
9910 BOOST_SCOPE_EXIT( (cache_enabled) ) {
9911 ASSERT_EQ(0, _rados.conf_set("rbd_cache", cache_enabled.c_str()));
9912 } BOOST_SCOPE_EXIT_END;
9913
9914 librados::IoCtx ioctx;
9915 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9916
9917 librbd::RBD rbd;
9918 std::string name = get_temp_image_name();
9919 uint64_t size = 1 << 18;
9920 int order = 0;
9921 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9922
9923 librbd::Image image1;
9924 librbd::Image image2;
9925 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
9926 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
9927 ASSERT_EQ(0, image1.snap_create("snap1"));
9928
9929 librbd::RBD::AioCompletion *read_comp =
9930 new librbd::RBD::AioCompletion(NULL, NULL);
9931 bufferlist read_bl;
9932 image2.aio_read(0, 1024, read_bl, read_comp);
9933 ASSERT_EQ(0, read_comp->wait_for_complete());
9934 read_comp->release();
9935}
9936
9937TEST_F(TestLibRBD, TestImageOptions)
9938{
9939 rados_ioctx_t ioctx;
9940 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9941
9942 //make create image options
9943 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
9944 uint64_t order = 0;
9945 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
9946 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
9947 rbd_image_options_t opts;
9948 rbd_image_options_create(&opts);
9949
9950 bool is_set;
9951 ASSERT_EQ(-EINVAL, rbd_image_options_is_set(opts, 12345, &is_set));
9952 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
9953 &is_set));
9954 ASSERT_FALSE(is_set);
9955
9956 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
9957 2));
9958 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
9959 features));
9960 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
9961 order));
9962 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
9963 stripe_unit));
9964 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
9965 stripe_count));
9966
9967 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
9968 &is_set));
9969 ASSERT_TRUE(is_set);
9970
9971 std::string parent_name = get_temp_image_name();
9972
9973 // make parent
9974 ASSERT_EQ(0, rbd_create4(ioctx, parent_name.c_str(), 4<<20, opts));
9975
9976 // check order is returned in opts
9977 ASSERT_EQ(0, rbd_image_options_get_uint64(opts, RBD_IMAGE_OPTION_ORDER,
9978 &order));
9979 ASSERT_NE((uint64_t)0, order);
9980
9981 // write some data to parent
9982 rbd_image_t parent;
9983 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
9984 char *data = (char *)"testdata";
9985 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
9986 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
9987
9988 // create a snapshot, reopen as the parent we're interested in
9989 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
9990 ASSERT_EQ(0, rbd_close(parent));
9991 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
9992
9993 // clone
9994 std::string child_name = get_temp_image_name();
9995 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
9996 ASSERT_EQ(0, rbd_clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
9997 child_name.c_str(), opts));
9998
9999 // copy
10000 std::string copy1_name = get_temp_image_name();
10001 ASSERT_EQ(0, rbd_copy3(parent, ioctx, copy1_name.c_str(), opts));
10002 std::string copy2_name = get_temp_image_name();
10003 ASSERT_EQ(0, rbd_copy_with_progress3(parent, ioctx, copy2_name.c_str(), opts,
10004 print_progress_percent, NULL));
10005
10006 ASSERT_EQ(0, rbd_close(parent));
10007
10008 rbd_image_options_destroy(opts);
10009
10010 rados_ioctx_destroy(ioctx);
10011}
10012
10013TEST_F(TestLibRBD, TestImageOptionsPP)
10014{
10015 librados::IoCtx ioctx;
10016 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10017
10018 //make create image options
10019 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
10020 uint64_t order = 0;
10021 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
10022 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
10023 librbd::ImageOptions opts;
10024 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2)));
10025 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FEATURES, features));
10026 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_ORDER, order));
10027 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
10028 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
10029
10030 librbd::RBD rbd;
10031 std::string parent_name = get_temp_image_name();
10032
10033 // make parent
10034 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 4<<20, opts));
10035
10036 // check order is returned in opts
10037 ASSERT_EQ(0, opts.get(RBD_IMAGE_OPTION_ORDER, &order));
10038 ASSERT_NE((uint64_t)0, order);
10039
10040 // write some data to parent
10041 librbd::Image parent;
10042 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
10043
10044 ssize_t len = 1024;
10045 bufferlist bl;
10046 bl.append(buffer::create(len));
10047 bl.zero();
10048 ASSERT_EQ(len, parent.write(0, len, bl));
10049 ASSERT_EQ(len, parent.write(len, len, bl));
10050
10051 // create a snapshot, reopen as the parent we're interested in
10052 ASSERT_EQ(0, parent.snap_create("parent_snap"));
10053 ASSERT_EQ(0, parent.close());
10054 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
10055
10056 // clone
10057 std::string child_name = get_temp_image_name();
10058 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
10059 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
10060 child_name.c_str(), opts));
10061
10062 // copy
10063 std::string copy1_name = get_temp_image_name();
10064 ASSERT_EQ(0, parent.copy3(ioctx, copy1_name.c_str(), opts));
10065 std::string copy2_name = get_temp_image_name();
10066 PrintProgress pp;
10067 ASSERT_EQ(0, parent.copy_with_progress3(ioctx, copy2_name.c_str(), opts, pp));
10068
10069 ASSERT_EQ(0, parent.close());
10070}
10071
10072TEST_F(TestLibRBD, EventSocketPipe)
10073{
10074 EventSocket event_sock;
10075 int pipe_fd[2]; // read and write fd
10076 char buf[32];
10077
10078 ASSERT_EQ(0, pipe(pipe_fd));
10079
10080 ASSERT_FALSE(event_sock.is_valid());
10081
10082 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_NONE));
10083 ASSERT_FALSE(event_sock.is_valid());
10084
10085 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], 44));
10086 ASSERT_FALSE(event_sock.is_valid());
10087
10088#ifndef HAVE_EVENTFD
10089 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_EVENTFD));
10090 ASSERT_FALSE(event_sock.is_valid());
10091#endif
10092
10093 ASSERT_EQ(0, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_PIPE));
10094 ASSERT_TRUE(event_sock.is_valid());
10095 ASSERT_EQ(0, event_sock.notify());
10096 ASSERT_EQ(1, read(pipe_fd[0], buf, 32));
10097 ASSERT_EQ('i', buf[0]);
10098
10099 close(pipe_fd[0]);
10100 close(pipe_fd[1]);
10101}
10102
10103TEST_F(TestLibRBD, EventSocketEventfd)
10104{
10105#ifdef HAVE_EVENTFD
10106 EventSocket event_sock;
10107 int event_fd;
10108 struct pollfd poll_fd;
10109 char buf[32];
10110
10111 event_fd = eventfd(0, EFD_NONBLOCK);
10112 ASSERT_NE(-1, event_fd);
10113
10114 ASSERT_FALSE(event_sock.is_valid());
10115
10116 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, EVENT_SOCKET_TYPE_NONE));
10117 ASSERT_FALSE(event_sock.is_valid());
10118
10119 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, 44));
10120 ASSERT_FALSE(event_sock.is_valid());
10121
10122 ASSERT_EQ(0, event_sock.init(event_fd, EVENT_SOCKET_TYPE_EVENTFD));
10123 ASSERT_TRUE(event_sock.is_valid());
10124 ASSERT_EQ(0, event_sock.notify());
10125
10126 poll_fd.fd = event_fd;
10127 poll_fd.events = POLLIN;
10128 ASSERT_EQ(1, poll(&poll_fd, 1, -1));
10129 ASSERT_TRUE(poll_fd.revents & POLLIN);
10130
10131 ASSERT_EQ(static_cast<ssize_t>(sizeof(uint64_t)), read(event_fd, buf, 32));
10132 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf));
10133
10134 close(event_fd);
10135#endif
10136}
10137
10138TEST_F(TestLibRBD, ImagePollIO)
10139{
10140#ifdef HAVE_EVENTFD
10141 rados_ioctx_t ioctx;
10142 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
10143
10144 rbd_image_t image;
10145 int order = 0;
10146 std::string name = get_temp_image_name();
10147 uint64_t size = 2 << 20;
10148 int fd = eventfd(0, EFD_NONBLOCK);
10149
10150 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
10151 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
10152
10153 ASSERT_EQ(0, rbd_set_image_notification(image, fd, EVENT_SOCKET_TYPE_EVENTFD));
10154
10155 char test_data[TEST_IO_SIZE + 1];
10156 char zero_data[TEST_IO_SIZE + 1];
10157 int i;
10158
10159 for (i = 0; i < TEST_IO_SIZE; ++i)
10160 test_data[i] = (char) (rand() % (126 - 33) + 33);
10161 test_data[TEST_IO_SIZE] = '\0';
10162 memset(zero_data, 0, sizeof(zero_data));
10163
10164 for (i = 0; i < 5; ++i)
10165 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
10166
10167 for (i = 5; i < 10; ++i)
10168 ASSERT_PASSED(aio_write_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
10169
10170 for (i = 5; i < 10; ++i)
10171 ASSERT_PASSED(aio_read_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
10172
10173 ASSERT_EQ(0, rbd_close(image));
10174 rados_ioctx_destroy(ioctx);
10175#endif
10176}
10177
10178namespace librbd {
10179
11fdf7f2
TL
10180static bool operator==(const image_spec_t &lhs, const image_spec_t &rhs) {
10181 return (lhs.id == rhs.id && lhs.name == rhs.name);
10182}
10183
10184static bool operator==(const linked_image_spec_t &lhs,
10185 const linked_image_spec_t &rhs) {
10186 return (lhs.pool_id == rhs.pool_id &&
10187 lhs.pool_name == rhs.pool_name &&
10188 lhs.pool_namespace == rhs.pool_namespace &&
10189 lhs.image_id == rhs.image_id &&
10190 lhs.image_name == rhs.image_name &&
10191 lhs.trash == rhs.trash);
10192}
10193
7c673cae
FG
10194static bool operator==(const mirror_peer_t &lhs, const mirror_peer_t &rhs) {
10195 return (lhs.uuid == rhs.uuid &&
10196 lhs.cluster_name == rhs.cluster_name &&
10197 lhs.client_name == rhs.client_name);
10198}
10199
10200static std::ostream& operator<<(std::ostream &os, const mirror_peer_t &peer) {
10201 os << "uuid=" << peer.uuid << ", "
10202 << "cluster=" << peer.cluster_name << ", "
10203 << "client=" << peer.client_name;
10204 return os;
10205}
10206
10207} // namespace librbd
10208
10209TEST_F(TestLibRBD, Mirror) {
10210 librados::IoCtx ioctx;
10211 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10212
10213 librbd::RBD rbd;
10214
10215 std::vector<librbd::mirror_peer_t> expected_peers;
10216 std::vector<librbd::mirror_peer_t> peers;
10217 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
10218 ASSERT_EQ(expected_peers, peers);
10219
10220 std::string uuid1;
10221 ASSERT_EQ(-EINVAL, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
10222
10223 rbd_mirror_mode_t mirror_mode;
10224 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
10225 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED, mirror_mode);
10226
10227 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
10228 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
10229
10230 // Add some images to the pool
10231 int order = 0;
10232 std::string parent_name = get_temp_image_name();
10233 std::string child_name = get_temp_image_name();
10234 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), 2 << 20,
10235 &order));
10236 bool old_format;
10237 uint64_t features;
10238 ASSERT_EQ(0, get_features(&old_format, &features));
10239 if ((features & RBD_FEATURE_LAYERING) != 0) {
10240 librbd::Image parent;
10241 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
10242 ASSERT_EQ(0, parent.snap_create("parent_snap"));
10243 ASSERT_EQ(0, parent.close());
10244 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
10245 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
10246 ASSERT_EQ(0, parent.close());
10247 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "parent_snap", ioctx,
10248 child_name.c_str(), features, &order));
10249 }
10250
10251 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE, mirror_mode);
10252
10253 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_POOL));
10254 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
10255 ASSERT_EQ(RBD_MIRROR_MODE_POOL, mirror_mode);
10256
10257 std::string uuid2;
10258 std::string uuid3;
10259 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
10260 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid2, "cluster2", "admin"));
10261 ASSERT_EQ(-EEXIST, rbd.mirror_peer_add(ioctx, &uuid3, "cluster1", "foo"));
10262 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid3, "cluster3", "admin"));
10263
10264 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
10265 auto sort_peers = [](const librbd::mirror_peer_t &lhs,
10266 const librbd::mirror_peer_t &rhs) {
10267 return lhs.uuid < rhs.uuid;
10268 };
10269 expected_peers = {
10270 {uuid1, "cluster1", "client"},
10271 {uuid2, "cluster2", "admin"},
10272 {uuid3, "cluster3", "admin"}};
10273 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
10274 ASSERT_EQ(expected_peers, peers);
10275
10276 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, "uuid4"));
10277 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid2));
10278
10279 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_client(ioctx, "uuid4", "new client"));
10280 ASSERT_EQ(0, rbd.mirror_peer_set_client(ioctx, uuid1, "new client"));
10281
10282 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_cluster(ioctx, "uuid4",
10283 "new cluster"));
10284 ASSERT_EQ(0, rbd.mirror_peer_set_cluster(ioctx, uuid3, "new cluster"));
10285
10286 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
10287 expected_peers = {
10288 {uuid1, "cluster1", "new client"},
10289 {uuid3, "new cluster", "admin"}};
10290 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
10291 ASSERT_EQ(expected_peers, peers);
10292
10293 ASSERT_EQ(-EBUSY, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
11fdf7f2
TL
10294 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid1));
10295 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid3));
10296 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
7c673cae
FG
10297}
10298
11fdf7f2
TL
10299TEST_F(TestLibRBD, MirrorPeerAttributes) {
10300 REQUIRE(!is_librados_test_stub(_rados));
7c673cae
FG
10301
10302 librados::IoCtx ioctx;
10303 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10304
10305 librbd::RBD rbd;
11fdf7f2 10306 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
7c673cae 10307
11fdf7f2
TL
10308 std::string uuid;
10309 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid, "remote_cluster", "client"));
7c673cae 10310
11fdf7f2
TL
10311 std::map<std::string, std::string> attributes;
10312 ASSERT_EQ(-ENOENT, rbd.mirror_peer_get_attributes(ioctx, uuid, &attributes));
10313 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_attributes(ioctx, "missing uuid",
10314 attributes));
7c673cae 10315
11fdf7f2
TL
10316 std::map<std::string, std::string> expected_attributes{
10317 {"mon_host", "1.2.3.4"},
10318 {"key", "ABC"}};
10319 ASSERT_EQ(0, rbd.mirror_peer_set_attributes(ioctx, uuid,
10320 expected_attributes));
10321
10322 ASSERT_EQ(0, rbd.mirror_peer_get_attributes(ioctx, uuid,
10323 &attributes));
10324 ASSERT_EQ(expected_attributes, attributes);
10325
10326 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid));
10327 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
10328}
10329
1911f103
TL
10330TEST_F(TestLibRBD, CreateWithMirrorEnabled) {
10331 REQUIRE_FORMAT_V2();
10332
10333 librados::IoCtx ioctx;
10334 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10335
10336 librbd::RBD rbd;
10337 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
10338
10339 librbd::ImageOptions image_options;
10340 ASSERT_EQ(0, image_options.set(
10341 RBD_IMAGE_OPTION_MIRROR_IMAGE_MODE,
10342 static_cast<uint64_t>(RBD_MIRROR_IMAGE_MODE_SNAPSHOT)));
10343
10344 std::string parent_name = get_temp_image_name();
10345 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 2<<20, image_options));
10346
10347 librbd::Image parent_image;
10348 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
10349
10350 librbd::mirror_image_mode_t mirror_image_mode;
10351 ASSERT_EQ(0, parent_image.mirror_image_get_mode(&mirror_image_mode));
10352 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mirror_image_mode);
10353
10354 ASSERT_EQ(0, parent_image.snap_create("parent_snap"));
10355 ASSERT_EQ(0, parent_image.snap_protect("parent_snap"));
10356
10357 std::string child_name = get_temp_image_name();
10358 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
10359 child_name.c_str(), image_options));
10360
10361 librbd::Image child_image;
10362 ASSERT_EQ(0, rbd.open(ioctx, child_image, child_name.c_str(), NULL));
10363
10364 ASSERT_EQ(0, child_image.mirror_image_get_mode(&mirror_image_mode));
10365 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mirror_image_mode);
10366
10367 ASSERT_EQ(0, child_image.mirror_image_disable(true));
10368 ASSERT_EQ(0, parent_image.mirror_image_disable(true));
10369 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
10370}
10371
11fdf7f2
TL
10372TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {
10373 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
10374
10375 librados::IoCtx ioctx;
10376 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10377
10378 librbd::RBD rbd;
10379 librbd::Image image;
10380 std::string name = get_temp_image_name();
10381
10382 uint64_t size = 1 << 18;
10383 int order = 0;
10384
10385 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10386 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
10387
10388 bufferlist bl;
10389 bl.append(std::string(size, '1'));
7c673cae
FG
10390 ASSERT_EQ((int)size, image.write(0, size, bl));
10391 ASSERT_EQ(0, image.snap_create("one"));
10392 ASSERT_EQ(0, image.snap_protect("one"));
10393
10394 std::string clone_name = this->get_temp_image_name();
10395 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
10396 RBD_FEATURE_LAYERING, &order));
10397 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
10398
10399 librbd::Image image2;
10400 ASSERT_EQ(0, rbd.open(ioctx, image2, clone_name.c_str(), NULL));
10401
10402 // prepare CoW writeback that will be flushed on next op
10403 bl.clear();
10404 bl.append(std::string(1, '1'));
10405 ASSERT_EQ(0, image.flush());
10406 ASSERT_EQ(1, image.write(0, 1, bl));
10407 ASSERT_EQ(0, image2.snap_create("snap1"));
10408
10409 librbd::RBD::AioCompletion *read_comp =
10410 new librbd::RBD::AioCompletion(NULL, NULL);
10411 bufferlist read_bl;
10412 image.aio_read(0, 1024, read_bl, read_comp);
10413 ASSERT_EQ(0, read_comp->wait_for_complete());
10414 read_comp->release();
10415}
10416
10417TEST_F(TestLibRBD, ExclusiveLock)
10418{
10419 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
10420
10421 static char buf[10];
10422
10423 rados_ioctx_t ioctx;
10424 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
10425
10426 std::string name = get_temp_image_name();
10427 uint64_t size = 2 << 20;
10428 int order = 0;
10429 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
10430
10431 rbd_image_t image1;
10432 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
10433
10434 int lock_owner;
10435 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
10436 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
10437 ASSERT_TRUE(lock_owner);
10438
10439 rbd_lock_mode_t lock_mode;
10440 char *lock_owners[1];
10441 size_t max_lock_owners = 0;
10442 ASSERT_EQ(-ERANGE, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
10443 &max_lock_owners));
10444 ASSERT_EQ(1U, max_lock_owners);
10445
7c673cae
FG
10446 ASSERT_EQ(0, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
10447 &max_lock_owners));
10448 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
10449 ASSERT_STRNE("", lock_owners[0]);
10450 ASSERT_EQ(1U, max_lock_owners);
10451
10452 rbd_image_t image2;
10453 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
10454
10455 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
10456 ASSERT_FALSE(lock_owner);
10457
10458 ASSERT_EQ(-EOPNOTSUPP, rbd_lock_break(image1, RBD_LOCK_MODE_SHARED, ""));
10459 ASSERT_EQ(-EBUSY, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
10460 "not the owner"));
10461
10462 ASSERT_EQ(0, rbd_lock_release(image1));
10463 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
10464 ASSERT_FALSE(lock_owner);
10465
10466 ASSERT_EQ(-ENOENT, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
10467 lock_owners[0]));
10468 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
10469
10470 ASSERT_EQ(-EROFS, rbd_write(image1, 0, sizeof(buf), buf));
10471 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image2, 0, sizeof(buf), buf));
10472
10473 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
10474 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
10475 ASSERT_TRUE(lock_owner);
10476
10477 ASSERT_EQ(0, rbd_lock_release(image2));
10478 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
10479 ASSERT_FALSE(lock_owner);
10480
10481 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
10482 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
10483 ASSERT_TRUE(lock_owner);
10484
10485 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image1, 0, sizeof(buf), buf));
10486 ASSERT_EQ(-EROFS, rbd_write(image2, 0, sizeof(buf), buf));
10487
10488 ASSERT_EQ(0, rbd_lock_release(image1));
10489 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
10490 ASSERT_FALSE(lock_owner);
10491
10492 int owner_id = -1;
f67539c2 10493 std::mutex lock;
11fdf7f2 10494 const auto pingpong = [&](int m_id, rbd_image_t &m_image) {
7c673cae
FG
10495 for (int i = 0; i < 10; i++) {
10496 {
f67539c2 10497 std::lock_guard<std::mutex> locker(lock);
31f18b77 10498 if (owner_id == m_id) {
7c673cae
FG
10499 std::cout << m_id << ": releasing exclusive lock" << std::endl;
10500 EXPECT_EQ(0, rbd_lock_release(m_image));
10501 int lock_owner;
10502 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
10503 EXPECT_FALSE(lock_owner);
31f18b77 10504 owner_id = -1;
7c673cae
FG
10505 std::cout << m_id << ": exclusive lock released" << std::endl;
10506 continue;
10507 }
10508 }
10509
10510 std::cout << m_id << ": acquiring exclusive lock" << std::endl;
10511 int r;
10512 do {
10513 r = rbd_lock_acquire(m_image, RBD_LOCK_MODE_EXCLUSIVE);
10514 if (r == -EROFS) {
10515 usleep(1000);
10516 }
10517 } while (r == -EROFS);
10518 EXPECT_EQ(0, r);
10519
10520 int lock_owner;
10521 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
10522 EXPECT_TRUE(lock_owner);
10523 std::cout << m_id << ": exclusive lock acquired" << std::endl;
10524 {
f67539c2 10525 std::lock_guard<std::mutex> locker(lock);
31f18b77 10526 owner_id = m_id;
7c673cae
FG
10527 }
10528 usleep(rand() % 50000);
10529 }
10530
f67539c2 10531 std::lock_guard<std::mutex> locker(lock);
31f18b77 10532 if (owner_id == m_id) {
7c673cae
FG
10533 EXPECT_EQ(0, rbd_lock_release(m_image));
10534 int lock_owner;
10535 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
10536 EXPECT_FALSE(lock_owner);
31f18b77 10537 owner_id = -1;
7c673cae 10538 }
31f18b77
FG
10539 };
10540 thread ping(bind(pingpong, 1, ref(image1)));
10541 thread pong(bind(pingpong, 2, ref(image2)));
7c673cae 10542
7c673cae
FG
10543 ping.join();
10544 pong.join();
10545
10546 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
10547 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
10548 ASSERT_TRUE(lock_owner);
10549
10550 ASSERT_EQ(0, rbd_close(image2));
10551
10552 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
10553 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
10554 ASSERT_TRUE(lock_owner);
10555
10556 ASSERT_EQ(0, rbd_close(image1));
10557 rados_ioctx_destroy(ioctx);
10558}
10559
10560TEST_F(TestLibRBD, BreakLock)
10561{
1e59de90 10562 SKIP_IF_CRIMSON();
7c673cae 10563 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
f67539c2 10564 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
7c673cae
FG
10565
10566 static char buf[10];
10567
f67539c2
TL
10568 rados_t blocklist_cluster;
10569 ASSERT_EQ("", connect_cluster(&blocklist_cluster));
7c673cae 10570
f67539c2 10571 rados_ioctx_t ioctx, blocklist_ioctx;
7c673cae 10572 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
f67539c2
TL
10573 ASSERT_EQ(0, rados_ioctx_create(blocklist_cluster, m_pool_name.c_str(),
10574 &blocklist_ioctx));
7c673cae
FG
10575
10576 std::string name = get_temp_image_name();
10577 uint64_t size = 2 << 20;
10578 int order = 0;
10579 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
10580
f67539c2 10581 rbd_image_t image, blocklist_image;
7c673cae 10582 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
f67539c2 10583 ASSERT_EQ(0, rbd_open(blocklist_ioctx, name.c_str(), &blocklist_image, NULL));
7c673cae 10584
f67539c2
TL
10585 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_blocklist_on_break_lock", "true"));
10586 ASSERT_EQ(0, rbd_lock_acquire(blocklist_image, RBD_LOCK_MODE_EXCLUSIVE));
7c673cae
FG
10587
10588 rbd_lock_mode_t lock_mode;
10589 char *lock_owners[1];
10590 size_t max_lock_owners = 1;
10591 ASSERT_EQ(0, rbd_lock_get_owners(image, &lock_mode, lock_owners,
10592 &max_lock_owners));
10593 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
10594 ASSERT_STRNE("", lock_owners[0]);
10595 ASSERT_EQ(1U, max_lock_owners);
10596
10597 ASSERT_EQ(0, rbd_lock_break(image, RBD_LOCK_MODE_EXCLUSIVE, lock_owners[0]));
10598 ASSERT_EQ(0, rbd_lock_acquire(image, RBD_LOCK_MODE_EXCLUSIVE));
f67539c2 10599 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blocklist_cluster));
7c673cae
FG
10600
10601 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image, 0, sizeof(buf), buf));
f67539c2 10602 ASSERT_EQ(-EBLOCKLISTED, rbd_write(blocklist_image, 0, sizeof(buf), buf));
7c673cae
FG
10603
10604 ASSERT_EQ(0, rbd_close(image));
f67539c2 10605 ASSERT_EQ(0, rbd_close(blocklist_image));
7c673cae
FG
10606
10607 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
10608
10609 rados_ioctx_destroy(ioctx);
f67539c2
TL
10610 rados_ioctx_destroy(blocklist_ioctx);
10611 rados_shutdown(blocklist_cluster);
7c673cae
FG
10612}
10613
10614TEST_F(TestLibRBD, DiscardAfterWrite)
10615{
7c673cae
FG
10616 librados::IoCtx ioctx;
10617 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10618
10619 librbd::RBD rbd;
10620 std::string name = get_temp_image_name();
10621 uint64_t size = 1 << 20;
10622 int order = 18;
10623 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10624
10625 librbd::Image image;
10626 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
10627
f67539c2
TL
10628 if (this->is_skip_partial_discard_enabled(image)) {
10629 return;
10630 }
10631
7c673cae
FG
10632 // enable writeback cache
10633 ASSERT_EQ(0, image.flush());
10634
10635 bufferlist bl;
10636 bl.append(std::string(256, '1'));
10637
10638 librbd::RBD::AioCompletion *write_comp =
10639 new librbd::RBD::AioCompletion(NULL, NULL);
10640 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
10641 ASSERT_EQ(0, write_comp->wait_for_complete());
10642 write_comp->release();
10643
10644 librbd::RBD::AioCompletion *discard_comp =
10645 new librbd::RBD::AioCompletion(NULL, NULL);
10646 ASSERT_EQ(0, image.aio_discard(0, 256, discard_comp));
10647 ASSERT_EQ(0, discard_comp->wait_for_complete());
10648 discard_comp->release();
10649
10650 librbd::RBD::AioCompletion *read_comp =
10651 new librbd::RBD::AioCompletion(NULL, NULL);
10652 bufferlist read_bl;
10653 image.aio_read(0, bl.length(), read_bl, read_comp);
10654 ASSERT_EQ(0, read_comp->wait_for_complete());
10655 ASSERT_EQ(bl.length(), read_comp->get_return_value());
10656 ASSERT_TRUE(read_bl.is_zero());
10657 read_comp->release();
10658}
10659
10660TEST_F(TestLibRBD, DefaultFeatures) {
10661 std::string orig_default_features;
10662 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", orig_default_features));
10663 BOOST_SCOPE_EXIT_ALL(orig_default_features) {
10664 ASSERT_EQ(0, _rados.conf_set("rbd_default_features",
10665 orig_default_features.c_str()));
10666 };
10667
10668 std::list<std::pair<std::string, std::string> > feature_names_to_bitmask = {
10669 {"", orig_default_features},
10670 {"layering", "1"},
10671 {"layering, exclusive-lock", "5"},
10672 {"exclusive-lock,journaling", "68"},
10673 {"125", "125"}
10674 };
10675
10676 for (auto &pair : feature_names_to_bitmask) {
10677 ASSERT_EQ(0, _rados.conf_set("rbd_default_features", pair.first.c_str()));
10678 std::string features;
10679 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", features));
10680 ASSERT_EQ(pair.second, features);
10681 }
10682}
10683
10684TEST_F(TestLibRBD, TestTrashMoveAndPurge) {
11fdf7f2
TL
10685 REQUIRE_FORMAT_V2();
10686
7c673cae
FG
10687 librados::IoCtx ioctx;
10688 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10689
10690 librbd::RBD rbd;
10691 std::string name = get_temp_image_name();
10692
10693 uint64_t size = 1 << 18;
10694 int order = 12;
10695 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10696
10697 librbd::Image image;
10698 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 10699
7c673cae
FG
10700 std::string image_id;
10701 ASSERT_EQ(0, image.get_id(&image_id));
10702 image.close();
10703
10704 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 0));
10705
10706 std::vector<std::string> images;
10707 ASSERT_EQ(0, rbd.list(ioctx, images));
10708 for (const auto& image : images) {
10709 ASSERT_TRUE(image != name);
10710 }
10711
10712 librbd::trash_image_info_t info;
10713 ASSERT_EQ(-ENOENT, rbd.trash_get(ioctx, "dummy image id", &info));
10714 ASSERT_EQ(0, rbd.trash_get(ioctx, image_id.c_str(), &info));
10715 ASSERT_EQ(image_id, info.id);
10716
10717 std::vector<librbd::trash_image_info_t> entries;
10718 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
10719 ASSERT_FALSE(entries.empty());
10720 ASSERT_EQ(entries.begin()->id, image_id);
10721
10722 entries.clear();
10723 PrintProgress pp;
10724 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
10725 false, pp));
10726 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
10727 ASSERT_TRUE(entries.empty());
10728}
10729
10730TEST_F(TestLibRBD, TestTrashMoveAndPurgeNonExpiredDelay) {
11fdf7f2
TL
10731 REQUIRE_FORMAT_V2();
10732
7c673cae
FG
10733 librados::IoCtx ioctx;
10734 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10735
10736 librbd::RBD rbd;
10737 std::string name = get_temp_image_name();
10738
10739 uint64_t size = 1 << 18;
10740 int order = 12;
10741 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10742
10743 librbd::Image image;
10744 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 10745
7c673cae
FG
10746 std::string image_id;
10747 ASSERT_EQ(0, image.get_id(&image_id));
10748 image.close();
10749
10750 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 100));
10751
10752 PrintProgress pp;
10753 ASSERT_EQ(-EPERM, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
10754 false, pp));
10755
10756 PrintProgress pp2;
10757 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
10758 true, pp2));
10759}
10760
11fdf7f2
TL
10761TEST_F(TestLibRBD, TestTrashPurge) {
10762 REQUIRE_FORMAT_V2();
10763
10764 librados::IoCtx ioctx;
10765 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10766
10767 librbd::RBD rbd;
10768 std::string name1 = get_temp_image_name();
10769 std::string name2 = get_temp_image_name();
10770
10771 uint64_t size = 1 << 18;
10772 int order = 12;
10773 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name1.c_str(), size, &order));
10774 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
10775
10776 librbd::Image image1;
10777 ASSERT_EQ(0, rbd.open(ioctx, image1, name1.c_str(), nullptr));
10778
10779 std::string image_id1;
10780 ASSERT_EQ(0, image1.get_id(&image_id1));
10781 image1.close();
10782
10783 ASSERT_EQ(0, rbd.trash_move(ioctx, name1.c_str(), 0));
10784
10785 librbd::Image image2;
10786 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), nullptr));
10787 ceph::bufferlist bl;
10788 bl.append(std::string(1024, '0'));
10789 ASSERT_EQ(1024, image2.write(0, 1024, bl));
10790
10791 std::string image_id2;
10792 ASSERT_EQ(0, image2.get_id(&image_id2));
10793 image2.close();
10794
10795 ASSERT_EQ(0, rbd.trash_move(ioctx, name2.c_str(), 100));
10796 ASSERT_EQ(0, rbd.trash_purge(ioctx, 0, -1));
10797
10798 std::vector<librbd::trash_image_info_t> entries;
10799 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
10800 ASSERT_EQ(1U, entries.size());
10801 ASSERT_EQ(image_id2, entries[0].id);
10802 ASSERT_EQ(name2, entries[0].name);
10803 entries.clear();
10804
10805 struct timespec now;
10806 clock_gettime(CLOCK_REALTIME, &now);
10807 float threshold = 0.0;
10808 if (!is_librados_test_stub(_rados)) {
10809 // real cluster usage reports have a long latency to update
10810 threshold = -1.0;
10811 }
10812
10813 ASSERT_EQ(0, rbd.trash_purge(ioctx, now.tv_sec+1000, threshold));
10814 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
10815 ASSERT_EQ(0U, entries.size());
10816}
10817
7c673cae 10818TEST_F(TestLibRBD, TestTrashMoveAndRestore) {
11fdf7f2
TL
10819 REQUIRE_FORMAT_V2();
10820
7c673cae
FG
10821 librados::IoCtx ioctx;
10822 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10823
10824 librbd::RBD rbd;
10825 std::string name = get_temp_image_name();
10826
10827 uint64_t size = 1 << 18;
10828 int order = 12;
10829 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10830
10831 librbd::Image image;
10832 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 10833
7c673cae
FG
10834 std::string image_id;
10835 ASSERT_EQ(0, image.get_id(&image_id));
10836 image.close();
10837
10838 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 10));
10839
10840 std::vector<std::string> images;
10841 ASSERT_EQ(0, rbd.list(ioctx, images));
10842 for (const auto& image : images) {
10843 ASSERT_TRUE(image != name);
10844 }
10845
10846 std::vector<librbd::trash_image_info_t> entries;
10847 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
10848 ASSERT_FALSE(entries.empty());
10849 ASSERT_EQ(entries.begin()->id, image_id);
10850
10851 images.clear();
10852 ASSERT_EQ(0, rbd.trash_restore(ioctx, image_id.c_str(), ""));
10853 ASSERT_EQ(0, rbd.list(ioctx, images));
10854 ASSERT_FALSE(images.empty());
10855 bool found = false;
10856 for (const auto& image : images) {
10857 if (image == name) {
10858 found = true;
10859 break;
10860 }
10861 }
10862 ASSERT_TRUE(found);
10863}
31f18b77 10864
11fdf7f2
TL
10865TEST_F(TestLibRBD, TestListWatchers) {
10866 librados::IoCtx ioctx;
10867 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10868
10869 librbd::RBD rbd;
10870 std::string name = get_temp_image_name();
10871
10872 uint64_t size = 1 << 18;
10873 int order = 12;
10874 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10875
10876 librbd::Image image;
10877 std::list<librbd::image_watcher_t> watchers;
10878
10879 // No watchers
10880 ASSERT_EQ(0, rbd.open_read_only(ioctx, image, name.c_str(), nullptr));
10881 ASSERT_EQ(0, image.list_watchers(watchers));
10882 ASSERT_EQ(0U, watchers.size());
10883 ASSERT_EQ(0, image.close());
10884
10885 // One watcher
10886 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
10887 ASSERT_EQ(0, image.list_watchers(watchers));
10888 ASSERT_EQ(1U, watchers.size());
1e59de90
TL
10889 auto watcher1 = watchers.front();
10890 ASSERT_EQ(0, image.close());
10891
10892 // (Still) one watcher
10893 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
10894 ASSERT_EQ(0, image.list_watchers(watchers));
10895 ASSERT_EQ(1U, watchers.size());
10896 auto watcher2 = watchers.front();
11fdf7f2 10897 ASSERT_EQ(0, image.close());
1e59de90
TL
10898
10899 EXPECT_EQ(watcher1.addr, watcher2.addr);
10900 EXPECT_EQ(watcher1.id, watcher2.id);
11fdf7f2
TL
10901}
10902
10903TEST_F(TestLibRBD, TestSetSnapById) {
10904 librados::IoCtx ioctx;
10905 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10906
10907 librbd::RBD rbd;
10908 std::string name = get_temp_image_name();
10909
10910 uint64_t size = 1 << 18;
10911 int order = 12;
10912 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10913
10914 librbd::Image image;
10915 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
10916 ASSERT_EQ(0, image.snap_create("snap"));
10917
10918 vector<librbd::snap_info_t> snaps;
10919 ASSERT_EQ(0, image.snap_list(snaps));
10920 ASSERT_EQ(1U, snaps.size());
10921
10922 ASSERT_EQ(0, image.snap_set_by_id(snaps[0].id));
10923 ASSERT_EQ(0, image.snap_set_by_id(CEPH_NOSNAP));
10924}
10925
10926TEST_F(TestLibRBD, Namespaces) {
10927 rados_ioctx_t ioctx;
10928 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
10929 rados_remove(ioctx, RBD_NAMESPACE);
10930
10931 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name1"));
10932 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name2"));
10933 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name3"));
10934 ASSERT_EQ(0, rbd_namespace_remove(ioctx, "name2"));
10935
10936 char names[1024];
10937 size_t max_size = sizeof(names);
10938 int len = rbd_namespace_list(ioctx, names, &max_size);
10939
10940 std::vector<std::string> cpp_names;
10941 for (char* cur_name = names; cur_name < names + len; ) {
10942 cpp_names.push_back(cur_name);
10943 cur_name += strlen(cur_name) + 1;
10944 }
10945 ASSERT_EQ(2U, cpp_names.size());
10946 ASSERT_EQ("name1", cpp_names[0]);
10947 ASSERT_EQ("name3", cpp_names[1]);
10948 bool exists;
10949 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name2", &exists));
10950 ASSERT_FALSE(exists);
10951 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name3", &exists));
10952 ASSERT_TRUE(exists);
10953 rados_ioctx_destroy(ioctx);
10954}
10955
10956TEST_F(TestLibRBD, NamespacesPP) {
10957 librados::IoCtx ioctx;
10958 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10959 ioctx.remove(RBD_NAMESPACE);
10960
10961 librbd::RBD rbd;
10962 ASSERT_EQ(-EINVAL, rbd.namespace_create(ioctx, ""));
10963 ASSERT_EQ(-EINVAL, rbd.namespace_remove(ioctx, ""));
10964
10965 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name1"));
10966 ASSERT_EQ(-EEXIST, rbd.namespace_create(ioctx, "name1"));
10967 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name2"));
10968 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name3"));
10969 ASSERT_EQ(0, rbd.namespace_remove(ioctx, "name2"));
10970 ASSERT_EQ(-ENOENT, rbd.namespace_remove(ioctx, "name2"));
10971
10972 std::vector<std::string> names;
10973 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
10974 ASSERT_EQ(2U, names.size());
10975 ASSERT_EQ("name1", names[0]);
10976 ASSERT_EQ("name3", names[1]);
10977 bool exists;
10978 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name2", &exists));
10979 ASSERT_FALSE(exists);
10980 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name3", &exists));
10981 ASSERT_TRUE(exists);
10982
10983 librados::IoCtx ns_io_ctx;
10984 ns_io_ctx.dup(ioctx);
10985
10986 std::string name = get_temp_image_name();
10987 int order = 0;
10988 uint64_t features = 0;
10989 if (!get_features(&features)) {
10990 // old format doesn't support namespaces
10991 ns_io_ctx.set_namespace("name1");
10992 ASSERT_EQ(-EINVAL, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0,
10993 &order));
10994 return;
10995 }
10996
10997 ns_io_ctx.set_namespace("missing");
10998 ASSERT_EQ(-ENOENT, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
10999
11000 ns_io_ctx.set_namespace("name1");
11001 ASSERT_EQ(0, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
11002 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
11003
11004 std::string image_id;
11005 {
11006 librbd::Image image;
11007 ASSERT_EQ(-ENOENT, rbd.open(ioctx, image, name.c_str(), NULL));
11008 ASSERT_EQ(0, rbd.open(ns_io_ctx, image, name.c_str(), NULL));
11009 ASSERT_EQ(0, get_image_id(image, &image_id));
11010 }
11011
11012 ASSERT_EQ(-ENOENT, rbd.trash_move(ioctx, name.c_str(), 0));
11013 ASSERT_EQ(0, rbd.trash_move(ns_io_ctx, name.c_str(), 0));
11014 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
11015
11016 PrintProgress pp;
11017 ASSERT_EQ(-ENOENT, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
11018 false, pp));
11019 ASSERT_EQ(0, rbd.trash_remove_with_progress(ns_io_ctx, image_id.c_str(),
11020 false, pp));
11021 ASSERT_EQ(0, rbd.namespace_remove(ns_io_ctx, "name1"));
11022
11023 names.clear();
11024 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
11025 ASSERT_EQ(1U, names.size());
11026 ASSERT_EQ("name3", names[0]);
11027}
11028
11029TEST_F(TestLibRBD, Migration) {
11030 bool old_format;
11031 uint64_t features;
11032 ASSERT_EQ(0, get_features(&old_format, &features));
11033
11034 rados_ioctx_t ioctx;
11035 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
11036 BOOST_SCOPE_EXIT(&ioctx) {
11037 rados_ioctx_destroy(ioctx);
11038 } BOOST_SCOPE_EXIT_END;
11039
11040 int order = 0;
11041 std::string name = get_temp_image_name();
11042 uint64_t size = 2 << 20;
11043 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
11044
11045 rbd_image_options_t image_options;
11046 rbd_image_options_create(&image_options);
11047 BOOST_SCOPE_EXIT(&image_options) {
11048 rbd_image_options_destroy(image_options);
11049 } BOOST_SCOPE_EXIT_END;
11050
11051 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
11052 image_options));
11053
11054 rbd_image_migration_status_t status;
11055 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
11056 sizeof(status)));
11057 ASSERT_EQ(status.source_pool_id, rados_ioctx_get_id(ioctx));
11058 ASSERT_EQ(status.source_image_name, name);
11059 if (old_format) {
11060 ASSERT_EQ(status.source_image_id, string());
11061 } else {
11062 ASSERT_NE(status.source_image_id, string());
11063 ASSERT_EQ(-EROFS, rbd_trash_remove(ioctx, status.source_image_id, false));
11064 ASSERT_EQ(-EINVAL, rbd_trash_restore(ioctx, status.source_image_id, name.c_str()));
11065 }
11066 ASSERT_EQ(status.dest_pool_id, rados_ioctx_get_id(ioctx));
11067 ASSERT_EQ(status.dest_image_name, name);
11068 ASSERT_NE(status.dest_image_id, string());
11069 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
11070 rbd_migration_status_cleanup(&status);
11071
f67539c2
TL
11072 rbd_image_t image;
11073 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11074 char source_spec[2048];
11075 size_t source_spec_length = sizeof(source_spec);
11076 ASSERT_EQ(0, rbd_get_migration_source_spec(image, source_spec,
11077 &source_spec_length));
11078 json_spirit::mValue json_source_spec;
11079 json_spirit::read(source_spec, json_source_spec);
11080 EXPECT_EQ(0, rbd_close(image));
11081
11fdf7f2
TL
11082 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, name.c_str()));
11083 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, name.c_str(), 0));
11084
11085 ASSERT_EQ(0, rbd_migration_execute(ioctx, name.c_str()));
11086
11087 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
11088 sizeof(status)));
11089 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
11090 rbd_migration_status_cleanup(&status);
11091
11092 ASSERT_EQ(0, rbd_migration_commit(ioctx, name.c_str()));
11093
11094 std::string new_name = get_temp_image_name();
11095
11096 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx,
11097 new_name.c_str(), image_options));
11098
11099 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, new_name.c_str()));
11100 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, new_name.c_str(), 0));
11101
11102 ASSERT_EQ(0, rbd_migration_abort(ioctx, name.c_str()));
11103
11fdf7f2
TL
11104 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11105 EXPECT_EQ(0, rbd_close(image));
11106}
11107
11108TEST_F(TestLibRBD, MigrationPP) {
11109 bool old_format;
11110 uint64_t features;
11111 ASSERT_EQ(0, get_features(&old_format, &features));
11112
11113 librados::IoCtx ioctx;
11114 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
11115
11116 int order = 0;
11117 std::string name = get_temp_image_name();
11118 uint64_t size = 2 << 20;
11119 librbd::RBD rbd;
11120 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
11121
11122 librbd::ImageOptions image_options;
11123
11124 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
11125 image_options));
11126
11127 librbd::image_migration_status_t status;
11128 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
11129 sizeof(status)));
11130 ASSERT_EQ(status.source_pool_id, ioctx.get_id());
11131 ASSERT_EQ(status.source_image_name, name);
11132 if (old_format) {
11133 ASSERT_EQ(status.source_image_id, "");
11134 } else {
11135 ASSERT_NE(status.source_image_id, "");
11136 ASSERT_EQ(-EROFS, rbd.trash_remove(ioctx, status.source_image_id.c_str(), false));
11137 ASSERT_EQ(-EINVAL, rbd.trash_restore(ioctx, status.source_image_id.c_str(), name.c_str()));
11138 }
11139 ASSERT_EQ(status.dest_pool_id, ioctx.get_id());
11140 ASSERT_EQ(status.dest_image_name, name);
11141 ASSERT_NE(status.dest_image_id, "");
11142 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
11143
f67539c2
TL
11144 librbd::Image image;
11145 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
11146 std::string source_spec;
11147 ASSERT_EQ(0, image.get_migration_source_spec(&source_spec));
11148 json_spirit::mValue json_source_spec;
11149 json_spirit::read(source_spec, json_source_spec);
11150 json_spirit::mObject json_source_spec_obj = json_source_spec.get_obj();
11151 ASSERT_EQ("native", json_source_spec_obj["type"].get_str());
11152 ASSERT_EQ(ioctx.get_id(), json_source_spec_obj["pool_id"].get_int64());
11153 ASSERT_EQ("", json_source_spec_obj["pool_namespace"].get_str());
11154 ASSERT_EQ(1, json_source_spec_obj.count("image_name"));
11155 if (!old_format) {
11156 ASSERT_EQ(1, json_source_spec_obj.count("image_id"));
11157 }
11158 ASSERT_EQ(0, image.close());
11159
11fdf7f2
TL
11160 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, name.c_str()));
11161 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, name.c_str(), 0));
11162
11163 ASSERT_EQ(0, rbd.migration_execute(ioctx, name.c_str()));
11164
11165 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
11166 sizeof(status)));
11167 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
11168
11169 ASSERT_EQ(0, rbd.migration_commit(ioctx, name.c_str()));
11170
11171 std::string new_name = get_temp_image_name();
11172
11173 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx,
11174 new_name.c_str(), image_options));
11175
11176 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, new_name.c_str()));
11177 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, new_name.c_str(), 0));
11178
11179 ASSERT_EQ(0, rbd.migration_abort(ioctx, name.c_str()));
11180
11fdf7f2
TL
11181 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
11182}
11183
11184TEST_F(TestLibRBD, TestGetAccessTimestamp)
11185{
11186 REQUIRE_FORMAT_V2();
11187
11188 rados_ioctx_t ioctx;
11189 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
11190
11191 rbd_image_t image;
11192 int order = 0;
11193 std::string name = get_temp_image_name();
11194 uint64_t size = 2 << 20;
11195 struct timespec timestamp;
11196
11197 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
11198 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11199
11200 ASSERT_EQ(0, rbd_get_access_timestamp(image, &timestamp));
11201 ASSERT_LT(0, timestamp.tv_sec);
11202
11203 ASSERT_PASSED(validate_object_map, image);
11204 ASSERT_EQ(0, rbd_close(image));
11205
11206 rados_ioctx_destroy(ioctx);
11207}
11208
11209TEST_F(TestLibRBD, TestGetModifyTimestamp)
11210{
11211 REQUIRE_FORMAT_V2();
11212
11213 rados_ioctx_t ioctx;
11214 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
11215
11216 rbd_image_t image;
11217 int order = 0;
11218 std::string name = get_temp_image_name();
11219 uint64_t size = 2 << 20;
11220 struct timespec timestamp;
11221
11222 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
11223 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11224 ASSERT_EQ(0, rbd_get_modify_timestamp(image, &timestamp));
11225 ASSERT_LT(0, timestamp.tv_sec);
11226
11227 ASSERT_PASSED(validate_object_map, image);
11228 ASSERT_EQ(0, rbd_close(image));
11229
11230 rados_ioctx_destroy(ioctx);
11231}
11232
91327a77
AA
11233TEST_F(TestLibRBD, ZeroOverlapFlatten) {
11234 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11235
11236 librados::IoCtx ioctx;
11237 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
11238
11239 librbd::RBD rbd;
11240 librbd::Image parent_image;
11241 std::string name = get_temp_image_name();
11242
11243 uint64_t size = 1;
11244 int order = 0;
11245
11246 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
11247 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
11248
11249 uint64_t features;
11250 ASSERT_EQ(0, parent_image.features(&features));
11251
11252 ASSERT_EQ(0, parent_image.snap_create("snap"));
11253 ASSERT_EQ(0, parent_image.snap_protect("snap"));
11254
11255 std::string clone_name = this->get_temp_image_name();
11256 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
11257 features, &order));
11258
11259 librbd::Image clone_image;
11260 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
11261 ASSERT_EQ(0, clone_image.resize(0));
11262 ASSERT_EQ(0, clone_image.flatten());
11263}
11264
11fdf7f2
TL
11265TEST_F(TestLibRBD, PoolMetadata)
11266{
11267 REQUIRE_FORMAT_V2();
11268
11269 rados_ioctx_t ioctx;
11270 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
11271
11272 char keys[1024];
11273 char vals[1024];
11274 size_t keys_len = sizeof(keys);
11275 size_t vals_len = sizeof(vals);
11276
11277 memset_rand(keys, keys_len);
11278 memset_rand(vals, vals_len);
11279
11280 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
11281 &vals_len));
11282 ASSERT_EQ(0U, keys_len);
11283 ASSERT_EQ(0U, vals_len);
11284
11285 char value[1024];
11286 size_t value_len = sizeof(value);
11287 memset_rand(value, value_len);
11288
11289 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
11290 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key2", "value2"));
11291 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
11292 ASSERT_STREQ(value, "value1");
11293 value_len = 1;
11294 ASSERT_EQ(-ERANGE, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
11295 ASSERT_EQ(value_len, strlen("value1") + 1);
11296
11297 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
11298 &vals_len));
11299 keys_len = sizeof(keys);
11300 vals_len = sizeof(vals);
11301 memset_rand(keys, keys_len);
11302 memset_rand(vals, vals_len);
11303 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
11304 &vals_len));
11305 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
11306 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
11307 ASSERT_STREQ(keys, "key1");
11308 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
11309 ASSERT_STREQ(vals, "value1");
11310 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
11311
11312 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
11313 ASSERT_EQ(-ENOENT, rbd_pool_metadata_remove(ioctx, "key3"));
11314 value_len = sizeof(value);
11315 ASSERT_EQ(-ENOENT, rbd_pool_metadata_get(ioctx, "key3", value, &value_len));
11316 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
11317 &vals_len));
11318 ASSERT_EQ(keys_len, strlen("key2") + 1);
11319 ASSERT_EQ(vals_len, strlen("value2") + 1);
11320 ASSERT_STREQ(keys, "key2");
11321 ASSERT_STREQ(vals, "value2");
11322
11323 // test config setting
11324 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
11325 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
11326 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
11327 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
11328
11329 // test short buffer cases
11330 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
11331 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key3", "value3"));
11332 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key4", "value4"));
11333
11334 keys_len = strlen("key1") + 1;
11335 vals_len = strlen("value1") + 1;
11336 memset_rand(keys, keys_len);
11337 memset_rand(vals, vals_len);
11338 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 1, keys, &keys_len, vals,
11339 &vals_len));
11340 ASSERT_EQ(keys_len, strlen("key1") + 1);
11341 ASSERT_EQ(vals_len, strlen("value1") + 1);
11342 ASSERT_STREQ(keys, "key1");
11343 ASSERT_STREQ(vals, "value1");
11344
11345 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 2, keys, &keys_len, vals,
11346 &vals_len));
11347 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
11348 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
11349
11350 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
11351 &vals_len));
11352 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
11353 1 + strlen("key4") + 1);
11354 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
11355 strlen("value3") + 1 + strlen("value4") + 1);
11356
11357 // test `start` param
11358 keys_len = sizeof(keys);
11359 vals_len = sizeof(vals);
11360 memset_rand(keys, keys_len);
11361 memset_rand(vals, vals_len);
11362 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "key2", 0, keys, &keys_len, vals,
11363 &vals_len));
11364 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
11365 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
11366 ASSERT_STREQ(keys, "key3");
11367 ASSERT_STREQ(vals, "value3");
11368
11369 //cleanup
11370 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
11371 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key2"));
11372 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key3"));
11373 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key4"));
11374 rados_ioctx_destroy(ioctx);
11375}
11376
11377TEST_F(TestLibRBD, PoolMetadataPP)
11378{
11379 REQUIRE_FORMAT_V2();
11380
11381 librbd::RBD rbd;
11382 string value;
11383 map<string, bufferlist> pairs;
11384
11385 librados::IoCtx ioctx;
11386 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
11387
11388 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
11389 ASSERT_TRUE(pairs.empty());
11390
11391 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
11392 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key2", "value2"));
11393 ASSERT_EQ(0, rbd.pool_metadata_get(ioctx, "key1", &value));
11394 ASSERT_EQ(value, "value1");
11395 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
11396 ASSERT_EQ(2U, pairs.size());
11397 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
11398 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
11399
11400 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
11401 ASSERT_EQ(-ENOENT, rbd.pool_metadata_remove(ioctx, "key3"));
11402 ASSERT_EQ(-ENOENT, rbd.pool_metadata_get(ioctx, "key3", &value));
11403 pairs.clear();
11404 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
11405 ASSERT_EQ(1U, pairs.size());
11406 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
11407
11408 // test `start` param
11409 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
11410 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key3", "value3"));
11411
11412 pairs.clear();
11413 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "key2", 0, &pairs));
11414 ASSERT_EQ(1U, pairs.size());
11415 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
11416
11417 // test config setting
11418 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
11419 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
11420 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
11421 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
11422
11423 // cleanup
11424 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
11425 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key2"));
11426 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key3"));
11427}
11428
11429TEST_F(TestLibRBD, Config)
11430{
11431 REQUIRE_FORMAT_V2();
11432
11433 rados_ioctx_t ioctx;
11434 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
11435
11436 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
11437
11438 rbd_config_option_t options[1024];
11439 int max_options = 0;
11440 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
11441 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
11442 ASSERT_GT(max_options, 0);
11443 ASSERT_LT(max_options, 1024);
11444 for (int i = 0; i < max_options; i++) {
11445 if (options[i].name == std::string("rbd_cache")) {
11446 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
11447 ASSERT_STREQ("false", options[i].value);
11448 } else {
11449 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
11450 }
11451 }
11452 rbd_config_pool_list_cleanup(options, max_options);
11453
11454 rbd_image_t image;
11455 int order = 0;
11456 std::string name = get_temp_image_name();
11457 uint64_t size = 2 << 20;
11458
11459 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
11460 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11461
11462 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
11463 for (int i = 0; i < max_options; i++) {
11464 if (options[i].name == std::string("rbd_cache")) {
11465 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
11466 ASSERT_STREQ("false", options[i].value);
11467 } else {
11468 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
11469 }
11470 }
11471 rbd_config_image_list_cleanup(options, max_options);
11472
11473 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_cache", "true"));
11474
11475 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
11476 for (int i = 0; i < max_options; i++) {
11477 if (options[i].name == std::string("rbd_cache")) {
11478 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_IMAGE);
11479 ASSERT_STREQ("true", options[i].value);
11480 } else {
11481 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
11482 }
11483 }
11484 rbd_config_image_list_cleanup(options, max_options);
11485
11486 ASSERT_EQ(0, rbd_metadata_remove(image, "conf_rbd_cache"));
11487
11488 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
11489 for (int i = 0; i < max_options; i++) {
11490 if (options[i].name == std::string("rbd_cache")) {
11491 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
11492 ASSERT_STREQ("false", options[i].value);
11493 } else {
11494 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
11495 }
11496 }
11497 rbd_config_image_list_cleanup(options, max_options);
11498
11499 ASSERT_EQ(0, rbd_close(image));
11500
11501 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
11502
11503 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
11504 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
11505 for (int i = 0; i < max_options; i++) {
11506 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
11507 }
11508 rbd_config_pool_list_cleanup(options, max_options);
11509
11510 rados_ioctx_destroy(ioctx);
11511}
11512
11513TEST_F(TestLibRBD, ConfigPP)
11514{
11515 REQUIRE_FORMAT_V2();
11516
11517 librbd::RBD rbd;
11518 string value;
11519
11520 librados::IoCtx ioctx;
11521 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
11522
11523 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
11524
11525 std::vector<librbd::config_option_t> options;
11526 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
11527 for (auto &option : options) {
11528 if (option.name == std::string("rbd_cache")) {
11529 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
11530 ASSERT_EQ("false", option.value);
11531 } else {
11532 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
11533 }
11534 }
11535
11536 int order = 0;
11537 std::string name = get_temp_image_name();
11538 uint64_t size = 2 << 20;
11539 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
11540
11541 librbd::Image image;
11542 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
11543
11544 options.clear();
11545 ASSERT_EQ(0, image.config_list(&options));
11546 for (auto &option : options) {
11547 if (option.name == std::string("rbd_cache")) {
11548 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
11549 ASSERT_EQ("false", option.value);
11550 } else {
11551 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
11552 }
11553 }
11554
11555 ASSERT_EQ(0, image.metadata_set("conf_rbd_cache", "true"));
11556
11557 options.clear();
11558 ASSERT_EQ(0, image.config_list(&options));
11559 for (auto &option : options) {
11560 if (option.name == std::string("rbd_cache")) {
11561 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_IMAGE);
11562 ASSERT_EQ("true", option.value);
11563 } else {
11564 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
11565 }
11566 }
11567
11568 ASSERT_EQ(0, image.metadata_remove("conf_rbd_cache"));
11569
11570 options.clear();
11571 ASSERT_EQ(0, image.config_list(&options));
11572 for (auto &option : options) {
11573 if (option.name == std::string("rbd_cache")) {
11574 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
11575 ASSERT_EQ("false", option.value);
11576 } else {
11577 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
11578 }
11579 }
11580
11581 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
11582
11583 options.clear();
11584 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
11585 for (auto &option : options) {
11586 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
11587 }
11588}
11589
11590TEST_F(TestLibRBD, PoolStatsPP)
11591{
11592 REQUIRE_FORMAT_V2();
11593
11594 librados::IoCtx ioctx;
11595 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
11596
11597 librbd::RBD rbd;
11598 std::string image_name;
11599 uint64_t size = 2 << 20;
11600 uint64_t expected_size = 0;
11601 for (size_t idx = 0; idx < 4; ++idx) {
11602 image_name = get_temp_image_name();
11603
11604 int order = 0;
11605 ASSERT_EQ(0, create_image_pp(rbd, ioctx, image_name.c_str(), size, &order));
11606 expected_size += size;
11607 }
11608
11609 librbd::Image image;
11610 ASSERT_EQ(0, rbd.open(ioctx, image, image_name.c_str(), NULL));
11611 ASSERT_EQ(0, image.snap_create("snap1"));
11612 ASSERT_EQ(0, image.resize(0));
11613 ASSERT_EQ(0, image.close());
11614 uint64_t expect_head_size = (expected_size - size);
11615
11616 uint64_t image_count;
11617 uint64_t provisioned_bytes;
11618 uint64_t max_provisioned_bytes;
11619 uint64_t snap_count;
11620 uint64_t trash_image_count;
11621 uint64_t trash_provisioned_bytes;
11622 uint64_t trash_max_provisioned_bytes;
11623 uint64_t trash_snap_count;
11624
11625 librbd::PoolStats pool_stats1;
11626 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGES, &image_count);
11627 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
11628 &provisioned_bytes);
11629 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
11630
11631 ASSERT_EQ(4U, image_count);
11632 ASSERT_EQ(expect_head_size, provisioned_bytes);
11633
11634 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
11635 &max_provisioned_bytes);
11636 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
11637 ASSERT_EQ(4U, image_count);
11638 ASSERT_EQ(expect_head_size, provisioned_bytes);
11639 ASSERT_EQ(expected_size, max_provisioned_bytes);
11640
11641 librbd::PoolStats pool_stats2;
11642 pool_stats2.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snap_count);
11643 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
11644 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
11645 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats2));
11646 ASSERT_EQ(1U, snap_count);
11647 ASSERT_EQ(0U, trash_image_count);
11648 ASSERT_EQ(0U, trash_snap_count);
11649
11650 ASSERT_EQ(0, rbd.trash_move(ioctx, image_name.c_str(), 0));
11651
11652 librbd::PoolStats pool_stats3;
11653 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
11654 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
11655 &trash_provisioned_bytes);
11656 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
11657 &trash_max_provisioned_bytes);
11658 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
11659 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats3));
11660 ASSERT_EQ(1U, trash_image_count);
11661 ASSERT_EQ(0U, trash_provisioned_bytes);
11662 ASSERT_EQ(size, trash_max_provisioned_bytes);
11663 ASSERT_EQ(1U, trash_snap_count);
11664}
11665
11666TEST_F(TestLibRBD, ImageSpec) {
11667 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11668
11669 librados::IoCtx ioctx;
11670 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
11671
11672 librbd::RBD rbd;
11673 librbd::Image parent_image;
11674 std::string name = get_temp_image_name();
11675
11676 uint64_t size = 1;
11677 int order = 0;
11678
11679 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
11680 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
11681
11682 std::string parent_id;
11683 ASSERT_EQ(0, parent_image.get_id(&parent_id));
11684
11685 uint64_t features;
11686 ASSERT_EQ(0, parent_image.features(&features));
11687
11688 ASSERT_EQ(0, parent_image.snap_create("snap"));
11689 ASSERT_EQ(0, parent_image.snap_protect("snap"));
11690
11691 std::string clone_name = this->get_temp_image_name();
11692 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
11693 features, &order));
11694
11695 librbd::Image clone_image;
11696 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
11697
11698 std::string clone_id;
11699 ASSERT_EQ(0, clone_image.get_id(&clone_id));
11700
11701 std::vector<librbd::image_spec_t> images;
11702 ASSERT_EQ(0, rbd.list2(ioctx, &images));
11703
11704 std::vector<librbd::image_spec_t> expected_images{
11705 {.id = parent_id, .name = name},
11706 {.id = clone_id, .name = clone_name}
11707 };
11708 std::sort(expected_images.begin(), expected_images.end(),
11709 [](const librbd::image_spec_t& lhs, const librbd::image_spec_t &rhs) {
11710 return lhs.name < rhs.name;
11711 });
11712 ASSERT_EQ(expected_images, images);
11713
11714 librbd::linked_image_spec_t parent_image_spec;
11715 librbd::snap_spec_t parent_snap_spec;
11716 ASSERT_EQ(0, clone_image.get_parent(&parent_image_spec, &parent_snap_spec));
11717
11718 librbd::linked_image_spec_t expected_parent_image_spec{
11719 .pool_id = ioctx.get_id(),
11720 .pool_name = ioctx.get_pool_name(),
11721 .pool_namespace = ioctx.get_namespace(),
11722 .image_id = parent_id,
11723 .image_name = name,
11724 .trash = false
11725 };
11726 ASSERT_EQ(expected_parent_image_spec, parent_image_spec);
11727 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER, parent_snap_spec.namespace_type);
11728 ASSERT_EQ("snap", parent_snap_spec.name);
11729
11730 std::vector<librbd::linked_image_spec_t> children;
11731 ASSERT_EQ(0, parent_image.list_children3(&children));
11732
11733 std::vector<librbd::linked_image_spec_t> expected_children{
11734 {
11735 .pool_id = ioctx.get_id(),
11736 .pool_name = ioctx.get_pool_name(),
11737 .pool_namespace = ioctx.get_namespace(),
11738 .image_id = clone_id,
11739 .image_name = clone_name,
11740 .trash = false
11741 }
11742 };
11743 ASSERT_EQ(expected_children, children);
11744
11745 children.clear();
11746 ASSERT_EQ(0, parent_image.list_descendants(&children));
11747 ASSERT_EQ(expected_children, children);
11748
11749 ASSERT_EQ(0, clone_image.snap_create("snap"));
11750 ASSERT_EQ(0, clone_image.snap_protect("snap"));
11751
11752 auto grand_clone_name = this->get_temp_image_name();
11753 ASSERT_EQ(0, rbd.clone(ioctx, clone_name.c_str(), "snap", ioctx,
11754 grand_clone_name.c_str(), features, &order));
11755 librbd::Image grand_clone_image;
11756 ASSERT_EQ(0, rbd.open(ioctx, grand_clone_image, grand_clone_name.c_str(),
11757 nullptr));
11758 std::string grand_clone_id;
11759 ASSERT_EQ(0, grand_clone_image.get_id(&grand_clone_id));
11760
11761 children.clear();
11762 ASSERT_EQ(0, parent_image.list_children3(&children));
11763 ASSERT_EQ(expected_children, children);
11764
11765 children.clear();
11766 ASSERT_EQ(0, parent_image.list_descendants(&children));
11767 expected_children.push_back(
11768 {
11769 .pool_id = ioctx.get_id(),
11770 .pool_name = ioctx.get_pool_name(),
11771 .pool_namespace = ioctx.get_namespace(),
11772 .image_id = grand_clone_id,
11773 .image_name = grand_clone_name,
11774 .trash = false
11775 }
11776 );
11777 ASSERT_EQ(expected_children, children);
11778}
11779
9f95a23c
TL
11780void super_simple_write_cb_pp(librbd::completion_t cb, void *arg)
11781{
11782}
11783
11784TEST_F(TestLibRBD, DISABLED_TestSeqWriteAIOPP)
11785{
11786 librados::IoCtx ioctx;
11787 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
11788
11789 {
11790 librbd::RBD rbd;
11791 librbd::Image image;
11792 int order = 21;
11793 std::string name = get_temp_image_name();
11794 uint64_t size = 5 * (1 << order);
11795
11796 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
11797 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
11798
11799 char test_data[(TEST_IO_SIZE + 1) * 10];
11800
11801 for (int i = 0; i < 10; i++) {
11802 for (uint64_t j = 0; j < TEST_IO_SIZE; j++) {
11803 test_data[(TEST_IO_SIZE + 1) * i + j] = (char)(rand() % (126 - 33) + 33);
11804 }
11805 test_data[(TEST_IO_SIZE + 1) * i + TEST_IO_SIZE] = '\0';
11806 }
11807
11808 struct timespec start_time;
11809 clock_gettime(CLOCK_REALTIME, &start_time);
11810
11811 std::list<librbd::RBD::AioCompletion *> comps;
11812 for (uint64_t i = 0; i < size / TEST_IO_SIZE; ++i) {
11813 char *p = test_data + (TEST_IO_SIZE + 1) * (i % 10);
11814 ceph::bufferlist bl;
11815 bl.append(p, strlen(p));
11816 auto comp = new librbd::RBD::AioCompletion(
11817 NULL, (librbd::callback_t) super_simple_write_cb_pp);
11818 image.aio_write(strlen(p) * i, strlen(p), bl, comp);
11819 comps.push_back(comp);
11820 if (i % 1000 == 0) {
11821 cout << i << " reqs sent" << std::endl;
11822 image.flush();
11823 for (auto comp : comps) {
11824 comp->wait_for_complete();
11825 ASSERT_EQ(0, comp->get_return_value());
11826 comp->release();
11827 }
11828 comps.clear();
11829 }
11830 }
11831 int i = 0;
11832 for (auto comp : comps) {
11833 comp->wait_for_complete();
11834 ASSERT_EQ(0, comp->get_return_value());
11835 comp->release();
11836 if (i % 1000 == 0) {
11837 std::cout << i << " reqs completed" << std::endl;
11838 }
11839 i++;
11840 }
11841 comps.clear();
11842
f67539c2
TL
11843 struct timespec end_time;
11844 clock_gettime(CLOCK_REALTIME, &end_time);
11845 int duration = end_time.tv_sec * 1000 + end_time.tv_nsec / 1000000 -
11846 start_time.tv_sec * 1000 - start_time.tv_nsec / 1000000;
11847 std::cout << "duration: " << duration << " msec" << std::endl;
11848
11849 for (uint64_t i = 0; i < size / TEST_IO_SIZE; ++i) {
11850 char *p = test_data + (TEST_IO_SIZE + 1) * (i % 10);
11851 ASSERT_PASSED(read_test_data, image, p, strlen(p) * i, TEST_IO_SIZE, 0);
11852 }
11853
11854 ASSERT_PASSED(validate_object_map, image);
11855 }
11856
11857 ioctx.close();
11858}
11859
11860TEST_F(TestLibRBD, SnapRemoveWithChildMissing)
11861{
11862 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11863 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
11864 BOOST_SCOPE_EXIT_ALL(&) {
11865 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
11866 };
11867
11868 librbd::RBD rbd;
11869 rados_ioctx_t ioctx1, ioctx2;
11870 string pool_name1 = create_pool(true);
11871 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
11872 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx2));
11873
11874 bool old_format;
11875 uint64_t features;
11876 rbd_image_t parent, child1, child2, child3;
11877 int order = 0;
11878 char child_id1[4096];
11879 char child_id2[4096];
11880 char child_id3[4096];
11881
11882 ASSERT_EQ(0, get_features(&old_format, &features));
11883 ASSERT_FALSE(old_format);
11884 std::string parent_name = get_temp_image_name();
11885 std::string child_name1 = get_temp_image_name();
11886 std::string child_name2 = get_temp_image_name();
11887 std::string child_name3 = get_temp_image_name();
11888 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
11889 false, features));
11890 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
11891 ASSERT_EQ(0, rbd_snap_create(parent, "snap1"));
11892 ASSERT_EQ(0, rbd_snap_create(parent, "snap2"));
11893
11894 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap1",
11895 ioctx2, child_name1.c_str(), features, &order));
11896 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
11897 ioctx1, child_name2.c_str(), features, &order));
11898 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
11899 ioctx2, child_name3.c_str(), features, &order));
11900
11901 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &child1, NULL));
11902 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &child2, NULL));
11903 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &child3, NULL));
11904 ASSERT_EQ(0, rbd_get_id(child1, child_id1, sizeof(child_id1)));
11905 ASSERT_EQ(0, rbd_get_id(child2, child_id2, sizeof(child_id2)));
11906 ASSERT_EQ(0, rbd_get_id(child3, child_id3, sizeof(child_id3)));
11907 test_list_children2(parent, 3,
11908 child_id1, m_pool_name.c_str(), child_name1.c_str(), false,
11909 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
11910 child_id3, m_pool_name.c_str(), child_name3.c_str(), false);
11911
11912 size_t max_size = 10;
11913 rbd_linked_image_spec_t children[max_size];
11914 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
11915 ASSERT_EQ(3, static_cast<int>(max_size));
11916 rbd_linked_image_spec_list_cleanup(children, max_size);
11917
11918 ASSERT_EQ(0, rbd_close(child1));
11919 ASSERT_EQ(0, rbd_close(child2));
11920 ASSERT_EQ(0, rbd_close(child3));
11921 rados_ioctx_destroy(ioctx2);
11922 ASSERT_EQ(0, rados_pool_delete(_cluster, m_pool_name.c_str()));
11923 _pool_names.erase(std::remove(_pool_names.begin(),
11924 _pool_names.end(), m_pool_name),
11925 _pool_names.end());
11926 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
11927
11928 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
11929 ASSERT_EQ(3, static_cast<int>(max_size));
11930 rbd_linked_image_spec_list_cleanup(children, max_size);
11931 ASSERT_EQ(0, rbd_snap_remove(parent, "snap1"));
11932 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
11933 ASSERT_EQ(2, static_cast<int>(max_size));
11934 rbd_linked_image_spec_list_cleanup(children, max_size);
11935
11936 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
11937 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
11938 ASSERT_EQ(1, static_cast<int>(max_size));
11939 rbd_linked_image_spec_list_cleanup(children, max_size);
11940
11941 ASSERT_EQ(0, rbd_snap_remove(parent, "snap2"));
11942 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
11943 ASSERT_EQ(0, static_cast<int>(max_size));
11944 rbd_linked_image_spec_list_cleanup(children, max_size);
11945 test_list_children2(parent, 0);
11946 ASSERT_EQ(0, test_ls_snaps(parent, 0));
11947
11948 ASSERT_EQ(0, rbd_close(parent));
11949 rados_ioctx_destroy(ioctx1);
11950}
11951
11952TEST_F(TestLibRBD, QuiesceWatch)
11953{
11954 rados_ioctx_t ioctx;
11955 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
11956
11957 int order = 0;
11958 std::string name = get_temp_image_name();
11959 uint64_t size = 2 << 20;
11960 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
11961
11962 rbd_image_t image1, image2;
11963 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
11964 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
11965
11966 struct Watcher {
11967 static void quiesce_cb(void *arg) {
11968 Watcher *watcher = static_cast<Watcher *>(arg);
11969 watcher->handle_quiesce();
11970 }
11971 static void unquiesce_cb(void *arg) {
11972 Watcher *watcher = static_cast<Watcher *>(arg);
11973 watcher->handle_unquiesce();
11974 }
11975
11976 rbd_image_t &image;
11977 uint64_t handle = 0;
11978 size_t quiesce_count = 0;
11979 size_t unquiesce_count = 0;
11980
11981 ceph::mutex lock = ceph::make_mutex("lock");
11982 ceph::condition_variable cv;
11983
11984 Watcher(rbd_image_t &image) : image(image) {
11985 }
11986
11987 void handle_quiesce() {
11988 ASSERT_EQ(quiesce_count, unquiesce_count);
11989 quiesce_count++;
11990 rbd_quiesce_complete(image, handle, 0);
11991 }
11992 void handle_unquiesce() {
11993 std::unique_lock locker(lock);
11994 unquiesce_count++;
11995 ASSERT_EQ(quiesce_count, unquiesce_count);
11996 cv.notify_one();
11997 }
11998 bool wait_for_unquiesce(size_t c) {
11999 std::unique_lock locker(lock);
12000 return cv.wait_for(locker, seconds(60),
12001 [this, c]() { return unquiesce_count >= c; });
12002 }
12003 } watcher1(image1), watcher2(image2);
12004
12005 ASSERT_EQ(0, rbd_quiesce_watch(image1, Watcher::quiesce_cb,
12006 Watcher::unquiesce_cb, &watcher1,
12007 &watcher1.handle));
12008 ASSERT_EQ(0, rbd_quiesce_watch(image2, Watcher::quiesce_cb,
12009 Watcher::unquiesce_cb, &watcher2,
12010 &watcher2.handle));
12011
12012 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
12013 ASSERT_EQ(1U, watcher1.quiesce_count);
12014 ASSERT_TRUE(watcher1.wait_for_unquiesce(1U));
12015 ASSERT_EQ(1U, watcher2.quiesce_count);
12016 ASSERT_TRUE(watcher2.wait_for_unquiesce(1U));
12017
12018 ASSERT_EQ(0, rbd_snap_create(image2, "snap2"));
12019 ASSERT_EQ(2U, watcher1.quiesce_count);
12020 ASSERT_TRUE(watcher1.wait_for_unquiesce(2U));
12021 ASSERT_EQ(2U, watcher2.quiesce_count);
12022 ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
12023
12024 ASSERT_EQ(0, rbd_quiesce_unwatch(image1, watcher1.handle));
12025
12026 ASSERT_EQ(0, rbd_snap_create(image1, "snap3"));
12027 ASSERT_EQ(2U, watcher1.quiesce_count);
12028 ASSERT_EQ(2U, watcher1.unquiesce_count);
12029 ASSERT_EQ(3U, watcher2.quiesce_count);
12030 ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
12031
12032 ASSERT_EQ(0, rbd_quiesce_unwatch(image2, watcher2.handle));
12033
12034 ASSERT_EQ(0, rbd_snap_remove(image1, "snap1"));
12035 ASSERT_EQ(0, rbd_snap_remove(image1, "snap2"));
12036 ASSERT_EQ(0, rbd_snap_remove(image1, "snap3"));
12037 ASSERT_EQ(0, rbd_close(image1));
12038 ASSERT_EQ(0, rbd_close(image2));
12039 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
12040 rados_ioctx_destroy(ioctx);
12041}
12042
12043TEST_F(TestLibRBD, QuiesceWatchPP)
12044{
12045 librbd::RBD rbd;
12046 librados::IoCtx ioctx;
12047 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
12048 std::string name = get_temp_image_name();
12049 int order = 0;
12050 uint64_t size = 2 << 20;
12051 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
12052
12053 {
12054 librbd::Image image1, image2;
12055 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
12056 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
12057
12058 struct Watcher : public librbd::QuiesceWatchCtx {
12059 librbd::Image &image;
12060 uint64_t handle = 0;
12061 size_t quiesce_count = 0;
12062 size_t unquiesce_count = 0;
12063
12064 ceph::mutex lock = ceph::make_mutex("lock");
12065 ceph::condition_variable cv;
12066
12067 Watcher(librbd::Image &image) : image(image) {
12068 }
12069
12070 void handle_quiesce() override {
12071 ASSERT_EQ(quiesce_count, unquiesce_count);
12072 quiesce_count++;
12073 image.quiesce_complete(handle, 0);
12074 }
12075 void handle_unquiesce() override {
12076 std::unique_lock locker(lock);
12077 unquiesce_count++;
12078 ASSERT_EQ(quiesce_count, unquiesce_count);
12079 cv.notify_one();
12080 }
12081 bool wait_for_unquiesce(size_t c) {
12082 std::unique_lock locker(lock);
12083 return cv.wait_for(locker, seconds(60),
12084 [this, c]() { return unquiesce_count >= c; });
12085 }
12086 } watcher1(image1), watcher2(image2);
12087
12088 ASSERT_EQ(0, image1.quiesce_watch(&watcher1, &watcher1.handle));
12089 ASSERT_EQ(0, image2.quiesce_watch(&watcher2, &watcher2.handle));
12090
12091 ASSERT_EQ(0, image1.snap_create("snap1"));
12092 ASSERT_EQ(1U, watcher1.quiesce_count);
12093 ASSERT_TRUE(watcher1.wait_for_unquiesce(1U));
12094 ASSERT_EQ(1U, watcher2.quiesce_count);
12095 ASSERT_TRUE(watcher2.wait_for_unquiesce(1U));
12096
12097 ASSERT_EQ(0, image2.snap_create("snap2"));
12098 ASSERT_EQ(2U, watcher1.quiesce_count);
12099 ASSERT_TRUE(watcher1.wait_for_unquiesce(2U));
12100 ASSERT_EQ(2U, watcher2.quiesce_count);
12101 ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
12102
12103 ASSERT_EQ(0, image1.quiesce_unwatch(watcher1.handle));
12104
12105 ASSERT_EQ(0, image1.snap_create("snap3"));
12106 ASSERT_EQ(2U, watcher1.quiesce_count);
12107 ASSERT_EQ(2U, watcher1.unquiesce_count);
12108 ASSERT_EQ(3U, watcher2.quiesce_count);
12109 ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
12110
12111 ASSERT_EQ(0, image2.quiesce_unwatch(watcher2.handle));
12112
12113 ASSERT_EQ(0, image1.snap_remove("snap1"));
12114 ASSERT_EQ(0, image1.snap_remove("snap2"));
12115 ASSERT_EQ(0, image1.snap_remove("snap3"));
12116 }
12117
12118 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
12119 ioctx.close();
12120}
12121
12122TEST_F(TestLibRBD, QuiesceWatchError)
12123{
1e59de90 12124 SKIP_IF_CRIMSON();
f67539c2
TL
12125 librbd::RBD rbd;
12126 librados::IoCtx ioctx;
12127 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
12128 std::string name = get_temp_image_name();
12129 int order = 0;
12130 uint64_t size = 2 << 20;
12131 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
12132
12133 {
12134 librbd::Image image1, image2;
12135 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
12136 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
12137
12138 struct Watcher : public librbd::QuiesceWatchCtx {
12139 librbd::Image &image;
12140 int r;
12141 uint64_t handle;
12142 size_t quiesce_count = 0;
12143 size_t unquiesce_count = 0;
12144
12145 ceph::mutex lock = ceph::make_mutex("lock");
12146 ceph::condition_variable cv;
12147
12148 Watcher(librbd::Image &image, int r) : image(image), r(r) {
12149 }
12150
12151 void reset_counters() {
12152 quiesce_count = 0;
12153 unquiesce_count = 0;
12154 }
9f95a23c 12155
f67539c2
TL
12156 void handle_quiesce() override {
12157 quiesce_count++;
12158 image.quiesce_complete(handle, r);
12159 }
9f95a23c 12160
f67539c2
TL
12161 void handle_unquiesce() override {
12162 std::unique_lock locker(lock);
12163 unquiesce_count++;
12164 cv.notify_one();
12165 }
9f95a23c 12166
f67539c2
TL
12167 bool wait_for_unquiesce() {
12168 std::unique_lock locker(lock);
12169 return cv.wait_for(locker, seconds(60),
12170 [this]() {
12171 return quiesce_count == unquiesce_count;
12172 });
12173 }
12174 } watcher10(image1, -EINVAL), watcher11(image1, 0), watcher20(image2, 0);
12175
12176 ASSERT_EQ(0, image1.quiesce_watch(&watcher10, &watcher10.handle));
12177 ASSERT_EQ(0, image1.quiesce_watch(&watcher11, &watcher11.handle));
12178 ASSERT_EQ(0, image2.quiesce_watch(&watcher20, &watcher20.handle));
12179
12180 ASSERT_EQ(-EINVAL, image1.snap_create("snap1"));
12181 ASSERT_GT(watcher10.quiesce_count, 0U);
12182 ASSERT_EQ(watcher10.unquiesce_count, 0U);
12183 ASSERT_GT(watcher11.quiesce_count, 0U);
12184 ASSERT_TRUE(watcher11.wait_for_unquiesce());
12185 ASSERT_GT(watcher20.quiesce_count, 0U);
12186 ASSERT_TRUE(watcher20.wait_for_unquiesce());
12187
12188 PrintProgress prog_ctx;
12189 watcher10.reset_counters();
12190 watcher11.reset_counters();
12191 watcher20.reset_counters();
12192 ASSERT_EQ(0, image2.snap_create2("snap2",
12193 RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
12194 prog_ctx));
12195 ASSERT_GT(watcher10.quiesce_count, 0U);
12196 ASSERT_EQ(watcher10.unquiesce_count, 0U);
12197 ASSERT_GT(watcher11.quiesce_count, 0U);
12198 ASSERT_TRUE(watcher11.wait_for_unquiesce());
12199 ASSERT_GT(watcher20.quiesce_count, 0U);
12200 ASSERT_TRUE(watcher20.wait_for_unquiesce());
12201
12202 ASSERT_EQ(0, image1.quiesce_unwatch(watcher10.handle));
12203
12204 watcher11.reset_counters();
12205 watcher20.reset_counters();
12206 ASSERT_EQ(0, image1.snap_create("snap3"));
12207 ASSERT_GT(watcher11.quiesce_count, 0U);
12208 ASSERT_TRUE(watcher11.wait_for_unquiesce());
12209 ASSERT_GT(watcher20.quiesce_count, 0U);
12210 ASSERT_TRUE(watcher20.wait_for_unquiesce());
12211
12212 ASSERT_EQ(0, image1.quiesce_unwatch(watcher11.handle));
12213
12214 watcher20.reset_counters();
12215 ASSERT_EQ(0, image2.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE,
12216 prog_ctx));
12217 ASSERT_EQ(watcher20.quiesce_count, 0U);
12218 ASSERT_EQ(watcher20.unquiesce_count, 0U);
12219
12220 ASSERT_EQ(0, image2.quiesce_unwatch(watcher20.handle));
12221
12222 ASSERT_EQ(0, image1.snap_remove("snap2"));
12223 ASSERT_EQ(0, image1.snap_remove("snap3"));
12224 ASSERT_EQ(0, image1.snap_remove("snap4"));
12225 }
12226
12227 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
9f95a23c
TL
12228 ioctx.close();
12229}
12230
f67539c2 12231TEST_F(TestLibRBD, QuiesceWatchTimeout)
92f5a8d4 12232{
f67539c2 12233 REQUIRE(!is_librados_test_stub(_rados));
92f5a8d4 12234
f67539c2 12235 ASSERT_EQ(0, _rados.conf_set("rbd_quiesce_notification_attempts", "2"));
92f5a8d4 12236
f67539c2
TL
12237 librbd::RBD rbd;
12238 librados::IoCtx ioctx;
12239 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
12240 std::string name = get_temp_image_name();
92f5a8d4 12241 int order = 0;
f67539c2
TL
12242 uint64_t size = 2 << 20;
12243 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
92f5a8d4 12244
f67539c2
TL
12245 {
12246 librbd::Image image;
12247 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
92f5a8d4 12248
f67539c2
TL
12249 struct Watcher : public librbd::QuiesceWatchCtx {
12250 librbd::Image &image;
12251 std::mutex m_lock;
12252 std::condition_variable m_cond;
12253 size_t quiesce_count = 0;
12254 size_t unquiesce_count = 0;
92f5a8d4 12255
f67539c2
TL
12256 Watcher(librbd::Image &image) : image(image) {
12257 }
92f5a8d4 12258
f67539c2
TL
12259 void handle_quiesce() override {
12260 std::lock_guard<std::mutex> locker(m_lock);
12261 quiesce_count++;
12262 m_cond.notify_one();
12263 }
92f5a8d4 12264
f67539c2
TL
12265 void handle_unquiesce() override {
12266 std::lock_guard<std::mutex> locker(m_lock);
12267 unquiesce_count++;
12268 m_cond.notify_one();
12269 }
92f5a8d4 12270
f67539c2
TL
12271 void wait_for_quiesce() {
12272 std::unique_lock<std::mutex> locker(m_lock);
12273 ASSERT_TRUE(m_cond.wait_for(locker, seconds(60),
12274 [this] {
12275 return quiesce_count >= 1;
12276 }));
12277 }
92f5a8d4 12278
f67539c2
TL
12279 void wait_for_unquiesce() {
12280 std::unique_lock<std::mutex> locker(m_lock);
12281 ASSERT_TRUE(m_cond.wait_for(locker, seconds(60),
12282 [this] {
12283 return quiesce_count == unquiesce_count;
12284 }));
12285 quiesce_count = unquiesce_count = 0;
12286 }
12287 } watcher(image);
12288 uint64_t handle;
92f5a8d4 12289
f67539c2 12290 ASSERT_EQ(0, image.quiesce_watch(&watcher, &handle));
92f5a8d4 12291
f67539c2
TL
12292 std::cerr << "test quiesce is not long enough to time out" << std::endl;
12293
12294 thread quiesce1([&image, &watcher, handle]() {
12295 watcher.wait_for_quiesce();
12296 sleep(8);
12297 image.quiesce_complete(handle, 0);
12298 });
12299
12300 ASSERT_EQ(0, image.snap_create("snap1"));
12301 quiesce1.join();
12302 ASSERT_GE(watcher.quiesce_count, 1U);
12303 watcher.wait_for_unquiesce();
12304
12305 std::cerr << "test quiesce is timed out" << std::endl;
12306
12307 bool timed_out = false;
12308 thread quiesce2([&image, &watcher, handle, &timed_out]() {
12309 watcher.wait_for_quiesce();
12310 for (int i = 0; !timed_out && i < 60; i++) {
12311 std::cerr << "waiting for timed out ... " << i << std::endl;
12312 sleep(1);
12313 }
12314 image.quiesce_complete(handle, 0);
12315 });
12316
12317 ASSERT_EQ(-ETIMEDOUT, image.snap_create("snap2"));
12318 timed_out = true;
12319 quiesce2.join();
12320 ASSERT_GE(watcher.quiesce_count, 1U);
12321 watcher.wait_for_unquiesce();
12322
12323 thread quiesce3([&image, handle, &watcher]() {
12324 watcher.wait_for_quiesce();
12325 image.quiesce_complete(handle, 0);
12326 });
12327
12328 std::cerr << "test retry succeeds" << std::endl;
12329
12330 ASSERT_EQ(0, image.snap_create("snap2"));
12331 quiesce3.join();
12332 ASSERT_GE(watcher.quiesce_count, 1U);
12333 watcher.wait_for_unquiesce();
12334
12335 ASSERT_EQ(0, image.snap_remove("snap1"));
12336 ASSERT_EQ(0, image.snap_remove("snap2"));
12337 }
12338
12339 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
12340 ioctx.close();
92f5a8d4
TL
12341}
12342
f6b5b4d7
TL
12343TEST_F(TestLibRBD, WriteZeroes) {
12344 librbd::RBD rbd;
12345 librados::IoCtx ioctx;
12346 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
12347 std::string name = get_temp_image_name();
12348 int order = 0;
12349 uint64_t size = 2 << 20;
12350 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
12351
12352 librbd::Image image;
12353 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
12354
12355 // 1s from [0, 256) / length 256
12356 char data[256];
12357 memset(data, 1, sizeof(data));
12358 bufferlist bl;
12359 bl.append(data, 256);
12360 ASSERT_EQ(256, image.write(0, 256, bl));
12361
12362 interval_set<uint64_t> diff;
12363 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12364 iterate_cb, (void *)&diff));
12365 auto expected_diff = interval_set<uint64_t>{{{0, 256}}};
12366 ASSERT_EQ(expected_diff, diff);
12367
12368 // writes zero passed the current end extents.
12369 // Now 1s from [0, 192) / length 192
12370 ASSERT_EQ(size - 192,
12371 image.write_zeroes(192, size - 192, 0U, 0));
12372 diff.clear();
12373 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12374 iterate_cb, (void *)&diff));
12375 expected_diff = interval_set<uint64_t>{{{0, 192}}};
12376 ASSERT_EQ(expected_diff, diff);
12377
12378 // zero an existing extent and truncate some off the end
12379 // Now 1s from [64, 192) / length 192
12380 ASSERT_EQ(64, image.write_zeroes(0, 64, 0U, 0));
12381
12382 diff.clear();
12383 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12384 iterate_cb, (void *)&diff));
12385 expected_diff = interval_set<uint64_t>{{{0, 192}}};
12386 ASSERT_EQ(expected_diff, diff);
12387
12388 bufferlist expected_bl;
12389 expected_bl.append_zero(64);
12390 bufferlist sub_bl;
12391 sub_bl.substr_of(bl, 0, 128);
12392 expected_bl.claim_append(sub_bl);
12393 expected_bl.append_zero(size - 192);
12394
12395 bufferlist read_bl;
12396 EXPECT_EQ(size, image.read(0, size, read_bl));
12397 EXPECT_EQ(expected_bl, read_bl);
12398
12399 ASSERT_EQ(0, image.close());
12400}
12401
f67539c2
TL
12402TEST_F(TestLibRBD, WriteZeroesThickProvision) {
12403 librbd::RBD rbd;
12404 librados::IoCtx ioctx;
12405 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
12406 std::string name = get_temp_image_name();
12407 int order = 0;
12408 uint64_t size = 2 << 20;
12409 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
12410
12411 librbd::Image image;
12412 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
12413
12414 interval_set<uint64_t> diff;
12415 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12416 iterate_cb, (void *)&diff));
12417 auto expected_diff = interval_set<uint64_t>{{}};
12418 ASSERT_EQ(expected_diff, diff);
12419
12420 // writes unaligned zeroes as a prepend
12421 ASSERT_EQ(128, image.write_zeroes(
12422 0, 128, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
12423 diff.clear();
12424 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12425 iterate_cb, (void *)&diff));
12426 expected_diff = interval_set<uint64_t>{{{0, 128}}};
12427 ASSERT_EQ(expected_diff, diff);
12428
12429 ASSERT_EQ(512, image.write_zeroes(
12430 384, 512, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
12431 diff.clear();
12432 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12433 iterate_cb, (void *)&diff));
12434 expected_diff = interval_set<uint64_t>{{{0, 896}}};
12435 ASSERT_EQ(expected_diff, diff);
12436
12437 // prepend with write-same
12438 ASSERT_EQ(640, image.write_zeroes(
12439 896, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
12440 diff.clear();
12441 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12442 iterate_cb, (void *)&diff));
12443 expected_diff = interval_set<uint64_t>{{{0, 1536}}};
12444 ASSERT_EQ(expected_diff, diff);
12445
12446 // write-same with append
12447 ASSERT_EQ(640, image.write_zeroes(
12448 1536, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
12449 diff.clear();
12450 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12451 iterate_cb, (void *)&diff));
12452 expected_diff = interval_set<uint64_t>{{{0, 2176}}};
12453 ASSERT_EQ(expected_diff, diff);
12454
12455 // prepend + write-same + append
12456 ASSERT_EQ(768, image.write_zeroes(
12457 2176, 768, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
12458 diff.clear();
12459 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12460 iterate_cb, (void *)&diff));
12461 expected_diff = interval_set<uint64_t>{{{0, 2944}}};
12462
12463 // write-same
12464 ASSERT_EQ(1024, image.write_zeroes(
12465 3072, 1024, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
12466 diff.clear();
12467 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
12468 iterate_cb, (void *)&diff));
12469 expected_diff = interval_set<uint64_t>{{{0, 4096}}};
12470
12471 bufferlist expected_bl;
12472 expected_bl.append_zero(size);
12473
12474 bufferlist read_bl;
12475 EXPECT_EQ(size, image.read(0, size, read_bl));
12476 EXPECT_EQ(expected_bl, read_bl);
12477
12478 ASSERT_EQ(0, image.close());
12479}
12480
12481TEST_F(TestLibRBD, ConcurentOperations)
12482{
1e59de90 12483 SKIP_IF_CRIMSON();
f67539c2
TL
12484 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
12485
12486 librbd::RBD rbd;
12487 librados::IoCtx ioctx;
12488 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
12489 std::string name = get_temp_image_name();
12490 int order = 0;
12491 uint64_t size = 2 << 20;
12492 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
12493
12494 // Test creating/removing many snapshots simultaneously
12495
12496 std::vector<librbd::Image> images(10);
12497 std::vector<librbd::RBD::AioCompletion *> comps;
12498
12499 for (auto &image : images) {
12500 auto comp = new librbd::RBD::AioCompletion(NULL, NULL);
12501 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, comp));
12502 comps.push_back(comp);
12503 }
12504
12505 for (auto &comp : comps) {
12506 ASSERT_EQ(0, comp->wait_for_complete());
12507 ASSERT_EQ(1, comp->is_complete());
12508 ASSERT_EQ(0, comp->get_return_value());
12509 comp->release();
12510 }
12511 comps.clear();
12512
12513 std::vector<std::thread> threads;
12514 int i = 0;
12515 for (auto &image : images) {
12516 std::string snap_name = "snap" + stringify(i++);
12517 threads.emplace_back([&image, snap_name]() {
12518 int r = image.snap_create(snap_name.c_str());
12519 ceph_assert(r == 0);
12520 });
12521 }
12522
12523 for (auto &t : threads) {
12524 t.join();
12525 }
12526 threads.clear();
12527
12528 i = 0;
12529 for (auto &image : images) {
12530 std::string snap_name = "snap" + stringify(i++);
12531 threads.emplace_back([&image, snap_name](){
12532 int r = image.snap_remove(snap_name.c_str());
12533 ceph_assert(r == 0);
12534 });
12535 }
12536
12537 for (auto &t : threads) {
12538 t.join();
12539 }
12540 threads.clear();
12541
12542 for (auto &image : images) {
12543 auto comp = new librbd::RBD::AioCompletion(NULL, NULL);
12544 ASSERT_EQ(0, image.aio_close(comp));
12545 comps.push_back(comp);
12546 }
12547
12548 for (auto &comp : comps) {
12549 ASSERT_EQ(0, comp->wait_for_complete());
12550 ASSERT_EQ(1, comp->is_complete());
12551 ASSERT_EQ(0, comp->get_return_value());
12552 comp->release();
12553 }
12554 comps.clear();
12555
12556 // Test shutdown
12557 {
12558 librbd::Image image1, image2, image3;
12559 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
12560 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
12561 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
12562
12563 ASSERT_EQ(0, image1.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE));
12564
12565 struct Watcher : public librbd::QuiesceWatchCtx {
12566 size_t count = 0;
12567
12568 ceph::mutex lock = ceph::make_mutex("lock");
12569 ceph::condition_variable cv;
12570
12571 void handle_quiesce() override {
12572 std::unique_lock locker(lock);
12573 count++;
12574 cv.notify_one();
12575 }
12576
12577 void handle_unquiesce() override {
12578 }
12579
12580 bool wait_for_quiesce(size_t c) {
12581 std::unique_lock locker(lock);
12582 return cv.wait_for(locker, seconds(60),
12583 [this, c]() { return count >= c; });
12584 }
12585 } watcher;
12586 uint64_t handle;
12587 ASSERT_EQ(0, image2.quiesce_watch(&watcher, &handle));
12588
12589 auto close1_comp = new librbd::RBD::AioCompletion(NULL, NULL);
12590
12591 std::thread create_snap1([&image1, close1_comp]() {
12592 int r = image1.snap_create("snap1");
12593 ceph_assert(r == 0);
12594 r = image1.aio_close(close1_comp);
12595 ceph_assert(r == 0);
12596 });
12597
12598 ASSERT_TRUE(watcher.wait_for_quiesce(1));
12599
12600 std::thread create_snap2([&image2]() {
12601 int r = image2.snap_create("snap2");
12602 ceph_assert(r == 0);
12603 });
12604
12605 std::thread create_snap3([&image3]() {
12606 int r = image3.snap_create("snap3");
12607 ceph_assert(r == 0);
12608 });
12609
12610 image2.quiesce_complete(handle, 0);
12611 create_snap1.join();
12612
12613 ASSERT_TRUE(watcher.wait_for_quiesce(2));
12614 image2.quiesce_complete(handle, 0);
12615
12616 ASSERT_TRUE(watcher.wait_for_quiesce(3));
12617 image2.quiesce_complete(handle, 0);
12618
12619 ASSERT_EQ(0, close1_comp->wait_for_complete());
12620 ASSERT_EQ(1, close1_comp->is_complete());
12621 ASSERT_EQ(0, close1_comp->get_return_value());
12622 close1_comp->release();
12623
12624 create_snap2.join();
12625 create_snap3.join();
12626
12627 ASSERT_EQ(0, image2.quiesce_unwatch(handle));
12628 ASSERT_EQ(0, image2.snap_remove("snap1"));
12629 ASSERT_EQ(0, image2.snap_remove("snap2"));
12630 ASSERT_EQ(0, image2.snap_remove("snap3"));
12631 }
12632
12633 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
12634 ioctx.close();
12635}
12636
12637
11fdf7f2 12638// poorman's ceph_assert()
31f18b77
FG
12639namespace ceph {
12640 void __ceph_assert_fail(const char *assertion, const char *file, int line,
12641 const char *func) {
11fdf7f2 12642 ceph_abort();
31f18b77
FG
12643 }
12644}
11fdf7f2
TL
12645
12646#pragma GCC diagnostic pop
12647#pragma GCC diagnostic warning "-Wpragmas"