]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_librbd.cc
buildsys: change download over to reef release
[ceph.git] / ceph / src / test / librbd / test_librbd.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License version 2, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include "include/int_types.h"
16#include "include/rados/librados.h"
17#include "include/rbd_types.h"
18#include "include/rbd/librbd.h"
19#include "include/rbd/librbd.hpp"
20#include "include/event_type.h"
c07f9fc5 21#include "include/err.h"
f67539c2
TL
22#include "common/ceph_mutex.h"
23#include "json_spirit/json_spirit.h"
7c673cae 24
7c673cae
FG
25#include "gtest/gtest.h"
26
7c673cae
FG
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <sys/types.h>
32#include <poll.h>
33#include <time.h>
34#include <unistd.h>
7c673cae 35#include <algorithm>
31f18b77
FG
36#include <chrono>
37#include <condition_variable>
38#include <iostream>
7c673cae
FG
39#include <sstream>
40#include <list>
41#include <set>
31f18b77 42#include <thread>
7c673cae 43#include <vector>
1d09f67e 44#include <limits>
7c673cae
FG
45
46#include "test/librados/test.h"
11fdf7f2 47#include "test/librados/test_cxx.h"
7c673cae 48#include "test/librbd/test_support.h"
7c673cae
FG
49#include "common/event_socket.h"
50#include "include/interval_set.h"
51#include "include/stringify.h"
52
53#include <boost/assign/list_of.hpp>
54#include <boost/scope_exit.hpp>
55
56#ifdef HAVE_EVENTFD
57#include <sys/eventfd.h>
58#endif
59
11fdf7f2
TL
60#pragma GCC diagnostic ignored "-Wpragmas"
61#pragma GCC diagnostic push
62#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
63
7c673cae
FG
64using namespace std;
65
66using std::chrono::seconds;
67
68#define ASSERT_PASSED(x, args...) \
69 do { \
70 bool passed = false; \
71 x(args, &passed); \
72 ASSERT_TRUE(passed); \
73 } while(0)
74
75void register_test_librbd() {
76}
77
78static int get_features(bool *old_format, uint64_t *features)
79{
80 const char *c = getenv("RBD_FEATURES");
11fdf7f2 81 if (c && strlen(c) > 0) {
7c673cae
FG
82 stringstream ss;
83 ss << c;
84 ss >> *features;
85 if (ss.fail())
86 return -EINVAL;
87 *old_format = false;
88 cout << "using new format!" << std::endl;
89 } else {
90 *old_format = true;
91 *features = 0;
92 cout << "using old format" << std::endl;
93 }
94
95 return 0;
96}
97
98static int create_image_full(rados_ioctx_t ioctx, const char *name,
99 uint64_t size, int *order, int old_format,
100 uint64_t features)
101{
102 if (old_format) {
103 // ensure old-format tests actually use the old format
104 int r = rados_conf_set(rados_ioctx_get_cluster(ioctx),
105 "rbd_default_format", "1");
106 if (r < 0) {
107 return r;
108 }
109 return rbd_create(ioctx, name, size, order);
110 } else if ((features & RBD_FEATURE_STRIPINGV2) != 0) {
111 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
112 if (*order) {
113 // use a conservative stripe_unit for non default order
114 stripe_unit = (1ull << (*order-1));
115 }
116
117 printf("creating image with stripe unit: %" PRIu64 ", "
118 "stripe count: %" PRIu64 "\n",
119 stripe_unit, IMAGE_STRIPE_COUNT);
120 return rbd_create3(ioctx, name, size, features, order,
121 stripe_unit, IMAGE_STRIPE_COUNT);
122 } else {
123 return rbd_create2(ioctx, name, size, features, order);
124 }
125}
126
127static int clone_image(rados_ioctx_t p_ioctx,
128 rbd_image_t p_image, const char *p_name,
129 const char *p_snap_name, rados_ioctx_t c_ioctx,
130 const char *c_name, uint64_t features, int *c_order)
131{
132 uint64_t stripe_unit, stripe_count;
133
134 int r;
135 r = rbd_get_stripe_unit(p_image, &stripe_unit);
136 if (r != 0) {
137 return r;
138 }
139
140 r = rbd_get_stripe_count(p_image, &stripe_count);
141 if (r != 0) {
142 return r;
143 }
144
145 return rbd_clone2(p_ioctx, p_name, p_snap_name, c_ioctx,
146 c_name, features, c_order, stripe_unit, stripe_count);
147}
148
149
150static int create_image(rados_ioctx_t ioctx, const char *name,
151 uint64_t size, int *order)
152{
153 bool old_format;
154 uint64_t features;
155
156 int r = get_features(&old_format, &features);
157 if (r < 0)
158 return r;
159 return create_image_full(ioctx, name, size, order, old_format, features);
160}
161
162static int create_image_pp(librbd::RBD &rbd,
163 librados::IoCtx &ioctx,
164 const char *name,
165 uint64_t size, int *order) {
166 bool old_format;
167 uint64_t features;
168 int r = get_features(&old_format, &features);
169 if (r < 0)
170 return r;
171 if (old_format) {
172 librados::Rados rados(ioctx);
173 int r = rados.conf_set("rbd_default_format", "1");
174 if (r < 0) {
175 return r;
176 }
177 return rbd.create(ioctx, name, size, order);
178 } else {
179 return rbd.create2(ioctx, name, size, features, order);
180 }
181}
182
f67539c2
TL
183
184
185void simple_write_cb(rbd_completion_t cb, void *arg)
186{
187 printf("write completion cb called!\n");
188}
189
190void simple_read_cb(rbd_completion_t cb, void *arg)
191{
192 printf("read completion cb called!\n");
193}
194
195void aio_write_test_data_and_poll(rbd_image_t image, int fd, const char *test_data,
196 uint64_t off, size_t len, uint32_t iohint, bool *passed)
197{
198 rbd_completion_t comp;
199 uint64_t data = 0x123;
200 rbd_aio_create_completion((void*)&data, (rbd_callback_t) simple_write_cb, &comp);
201 printf("created completion\n");
202 printf("started write\n");
203 if (iohint)
204 rbd_aio_write2(image, off, len, test_data, comp, iohint);
205 else
206 rbd_aio_write(image, off, len, test_data, comp);
207
208 struct pollfd pfd;
209 pfd.fd = fd;
210 pfd.events = POLLIN;
211
212 ASSERT_EQ(1, poll(&pfd, 1, -1));
213 ASSERT_TRUE(pfd.revents & POLLIN);
214
215 rbd_completion_t comps[1];
216 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
217 uint64_t count;
218 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
219 read(fd, &count, sizeof(count)));
220 int r = rbd_aio_get_return_value(comps[0]);
221 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
222 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps[0]) == data);
223 printf("return value is: %d\n", r);
224 ASSERT_EQ(0, r);
225 printf("finished write\n");
226 rbd_aio_release(comps[0]);
227 *passed = true;
228}
229
230void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
231{
232 rbd_completion_t comp;
233 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
234 printf("created completion\n");
235 if (iohint)
236 rbd_aio_write2(image, off, len, test_data, comp, iohint);
237 else
238 rbd_aio_write(image, off, len, test_data, comp);
239 printf("started write\n");
240 rbd_aio_wait_for_complete(comp);
241 int r = rbd_aio_get_return_value(comp);
242 printf("return value is: %d\n", r);
243 ASSERT_EQ(0, r);
244 printf("finished write\n");
245 rbd_aio_release(comp);
246 *passed = true;
247}
248
249void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
250{
251 ssize_t written;
252 if (iohint)
253 written = rbd_write2(image, off, len, test_data, iohint);
254 else
255 written = rbd_write(image, off, len, test_data);
256 printf("wrote: %d\n", (int) written);
257 ASSERT_EQ(len, static_cast<size_t>(written));
258 *passed = true;
259}
260
261void aio_discard_test_data(rbd_image_t image, uint64_t off, uint64_t len, bool *passed)
262{
263 rbd_completion_t comp;
264 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
265 rbd_aio_discard(image, off, len, comp);
266 rbd_aio_wait_for_complete(comp);
267 int r = rbd_aio_get_return_value(comp);
268 ASSERT_EQ(0, r);
269 printf("aio discard: %d~%d = %d\n", (int)off, (int)len, (int)r);
270 rbd_aio_release(comp);
271 *passed = true;
272}
273
274void discard_test_data(rbd_image_t image, uint64_t off, size_t len, bool *passed)
275{
276 ssize_t written;
277 written = rbd_discard(image, off, len);
278 printf("discard: %d~%d = %d\n", (int)off, (int)len, (int)written);
279 ASSERT_EQ(len, static_cast<size_t>(written));
280 *passed = true;
281}
282
283void aio_read_test_data_and_poll(rbd_image_t image, int fd, const char *expected,
284 uint64_t off, size_t len, uint32_t iohint, bool *passed)
285{
286 rbd_completion_t comp;
287 char *result = (char *)malloc(len + 1);
288
289 ASSERT_NE(static_cast<char *>(NULL), result);
290 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
291 printf("created completion\n");
292 printf("started read\n");
293 if (iohint)
294 rbd_aio_read2(image, off, len, result, comp, iohint);
295 else
296 rbd_aio_read(image, off, len, result, comp);
297
298 struct pollfd pfd;
299 pfd.fd = fd;
300 pfd.events = POLLIN;
301
302 ASSERT_EQ(1, poll(&pfd, 1, -1));
303 ASSERT_TRUE(pfd.revents & POLLIN);
304
305 rbd_completion_t comps[1];
306 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
307 uint64_t count;
308 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
309 read(fd, &count, sizeof(count)));
310
311 int r = rbd_aio_get_return_value(comps[0]);
312 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
313 printf("return value is: %d\n", r);
314 ASSERT_EQ(len, static_cast<size_t>(r));
315 rbd_aio_release(comps[0]);
316 if (memcmp(result, expected, len)) {
317 printf("read: %s\nexpected: %s\n", result, expected);
318 ASSERT_EQ(0, memcmp(result, expected, len));
319 }
320 free(result);
321 *passed = true;
322}
323
324void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
325{
326 rbd_completion_t comp;
327 char *result = (char *)malloc(len + 1);
328
329 ASSERT_NE(static_cast<char *>(NULL), result);
330 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
331 printf("created completion\n");
332 if (iohint)
333 rbd_aio_read2(image, off, len, result, comp, iohint);
334 else
335 rbd_aio_read(image, off, len, result, comp);
336 printf("started read\n");
337 rbd_aio_wait_for_complete(comp);
338 int r = rbd_aio_get_return_value(comp);
339 printf("return value is: %d\n", r);
340 ASSERT_EQ(len, static_cast<size_t>(r));
341 rbd_aio_release(comp);
342 if (memcmp(result, expected, len)) {
343 printf("read: %s\nexpected: %s\n", result, expected);
344 ASSERT_EQ(0, memcmp(result, expected, len));
345 }
346 free(result);
347 *passed = true;
348}
349
350void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
351{
352 ssize_t read;
353 char *result = (char *)malloc(len + 1);
354
355 ASSERT_NE(static_cast<char *>(NULL), result);
356 if (iohint)
357 read = rbd_read2(image, off, len, result, iohint);
358 else
359 read = rbd_read(image, off, len, result);
360 printf("read: %d\n", (int) read);
361 ASSERT_EQ(len, static_cast<size_t>(read));
362 result[len] = '\0';
363 if (memcmp(result, expected, len)) {
364 printf("read: %s\nexpected: %s\n", result, expected);
365 ASSERT_EQ(0, memcmp(result, expected, len));
366 }
367 free(result);
368 *passed = true;
369}
370
371void aio_writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
372 uint64_t data_len, uint32_t iohint, bool *passed)
373{
374 rbd_completion_t comp;
375 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
376 printf("created completion\n");
377 int r;
378 r = rbd_aio_writesame(image, off, len, test_data, data_len, comp, iohint);
379 printf("started writesame\n");
380 if (len % data_len) {
381 ASSERT_EQ(-EINVAL, r);
382 printf("expected fail, finished writesame\n");
383 rbd_aio_release(comp);
384 *passed = true;
385 return;
386 }
387
388 rbd_aio_wait_for_complete(comp);
389 r = rbd_aio_get_return_value(comp);
390 printf("return value is: %d\n", r);
391 ASSERT_EQ(0, r);
392 printf("finished writesame\n");
393 rbd_aio_release(comp);
394
395 //verify data
396 printf("to verify the data\n");
397 ssize_t read;
398 char *result = (char *)malloc(data_len+ 1);
399 ASSERT_NE(static_cast<char *>(NULL), result);
400 uint64_t left = len;
401 while (left > 0) {
402 read = rbd_read(image, off, data_len, result);
403 ASSERT_EQ(data_len, static_cast<size_t>(read));
404 result[data_len] = '\0';
405 if (memcmp(result, test_data, data_len)) {
406 printf("read: %d ~ %d\n", (int) off, (int) read);
407 printf("read: %s\nexpected: %s\n", result, test_data);
408 ASSERT_EQ(0, memcmp(result, test_data, data_len));
409 }
410 off += data_len;
411 left -= data_len;
412 }
413 ASSERT_EQ(0U, left);
414 free(result);
415 printf("verified\n");
416
417 *passed = true;
418}
419
420void writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
421 uint64_t data_len, uint32_t iohint, bool *passed)
422{
423 ssize_t written;
424 written = rbd_writesame(image, off, len, test_data, data_len, iohint);
425 if (len % data_len) {
426 ASSERT_EQ(-EINVAL, written);
427 printf("expected fail, finished writesame\n");
428 *passed = true;
429 return;
430 }
431 ASSERT_EQ(len, static_cast<size_t>(written));
432 printf("wrote: %d\n", (int) written);
433
434 //verify data
435 printf("to verify the data\n");
436 ssize_t read;
437 char *result = (char *)malloc(data_len+ 1);
438 ASSERT_NE(static_cast<char *>(NULL), result);
439 uint64_t left = len;
440 while (left > 0) {
441 read = rbd_read(image, off, data_len, result);
442 ASSERT_EQ(data_len, static_cast<size_t>(read));
443 result[data_len] = '\0';
444 if (memcmp(result, test_data, data_len)) {
445 printf("read: %d ~ %d\n", (int) off, (int) read);
446 printf("read: %s\nexpected: %s\n", result, test_data);
447 ASSERT_EQ(0, memcmp(result, test_data, data_len));
448 }
449 off += data_len;
450 left -= data_len;
451 }
452 ASSERT_EQ(0U, left);
453 free(result);
454 printf("verified\n");
455
456 *passed = true;
457}
458
459void aio_compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
460 const char *test_data, uint64_t off,
461 size_t len, uint32_t iohint, bool *passed)
462{
463 rbd_completion_t comp;
464 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
465 printf("created completion\n");
466
467 uint64_t mismatch_offset;
468 rbd_aio_compare_and_write(image, off, len, cmp_data, test_data, comp, &mismatch_offset, iohint);
469 printf("started aio compare and write\n");
470 rbd_aio_wait_for_complete(comp);
471 int r = rbd_aio_get_return_value(comp);
472 printf("return value is: %d\n", r);
473 ASSERT_EQ(0, r);
474 printf("finished aio compare and write\n");
475 rbd_aio_release(comp);
476 *passed = true;
477}
478
479void compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
480 const char *test_data, uint64_t off, size_t len,
481 uint64_t *mismatch_off, uint32_t iohint, bool *passed)
482{
483 printf("start compare and write\n");
484 ssize_t written;
485 written = rbd_compare_and_write(image, off, len, cmp_data, test_data, mismatch_off, iohint);
486 printf("compare and wrote: %d\n", (int) written);
487 ASSERT_EQ(len, static_cast<size_t>(written));
488 *passed = true;
489}
490
7c673cae
FG
491class TestLibRBD : public ::testing::Test {
492public:
493
494 TestLibRBD() : m_pool_number() {
495 }
496
497 static void SetUpTestCase() {
7c673cae
FG
498 _pool_names.clear();
499 _unique_pool_names.clear();
500 _image_number = 0;
501 ASSERT_EQ("", connect_cluster(&_cluster));
502 ASSERT_EQ("", connect_cluster_pp(_rados));
503
504 create_optional_data_pool();
505 }
506
507 static void TearDownTestCase() {
508 rados_shutdown(_cluster);
509 _rados.wait_for_latest_osdmap();
510 _pool_names.insert(_pool_names.end(), _unique_pool_names.begin(),
f67539c2 511 _unique_pool_names.end());
7c673cae
FG
512 for (size_t i = 1; i < _pool_names.size(); ++i) {
513 ASSERT_EQ(0, _rados.pool_delete(_pool_names[i].c_str()));
514 }
515 if (!_pool_names.empty()) {
516 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names[0], _rados));
517 }
518 }
519
520 void SetUp() override {
521 ASSERT_NE("", m_pool_name = create_pool());
522 }
523
524 bool is_skip_partial_discard_enabled() {
525 std::string value;
526 EXPECT_EQ(0, _rados.conf_get("rbd_skip_partial_discard", value));
527 return value == "true";
528 }
529
f67539c2
TL
530 bool is_skip_partial_discard_enabled(rbd_image_t image) {
531 if (is_skip_partial_discard_enabled()) {
532 rbd_flush(image);
533 uint64_t features;
534 EXPECT_EQ(0, rbd_get_features(image, &features));
535 return !(features & RBD_FEATURE_DIRTY_CACHE);
536 }
537 return false;
538 }
539
540 bool is_skip_partial_discard_enabled(librbd::Image& image) {
541 if (is_skip_partial_discard_enabled()) {
542 image.flush();
543 uint64_t features;
544 EXPECT_EQ(0, image.features(&features));
545 return !(features & RBD_FEATURE_DIRTY_CACHE);
546 }
547 return false;
548 }
549
7c673cae
FG
550 void validate_object_map(rbd_image_t image, bool *passed) {
551 uint64_t flags;
552 ASSERT_EQ(0, rbd_get_flags(image, &flags));
553 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
554 }
555
556 void validate_object_map(librbd::Image &image, bool *passed) {
557 uint64_t flags;
558 ASSERT_EQ(0, image.get_flags(&flags));
559 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
560 }
561
11fdf7f2 562 static std::string get_temp_image_name() {
7c673cae
FG
563 ++_image_number;
564 return "image" + stringify(_image_number);
565 }
566
567 static void create_optional_data_pool() {
568 bool created = false;
569 std::string data_pool;
570 ASSERT_EQ(0, create_image_data_pool(_rados, data_pool, &created));
571 if (!data_pool.empty()) {
572 printf("using image data pool: %s\n", data_pool.c_str());
573 if (created) {
574 _unique_pool_names.push_back(data_pool);
575 }
576 }
577 }
578
579 std::string create_pool(bool unique = false) {
580 librados::Rados rados;
581 std::string pool_name;
582 if (unique) {
583 pool_name = get_temp_pool_name("test-librbd-");
584 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
585 _unique_pool_names.push_back(pool_name);
586 } else if (m_pool_number < _pool_names.size()) {
587 pool_name = _pool_names[m_pool_number];
588 } else {
589 pool_name = get_temp_pool_name("test-librbd-");
590 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
591 _pool_names.push_back(pool_name);
592 }
593 ++m_pool_number;
594 return pool_name;
595 }
596
f67539c2
TL
597 void test_io(rbd_image_t image) {
598 bool skip_discard = is_skip_partial_discard_enabled(image);
599
600 char test_data[TEST_IO_SIZE + 1];
601 char zero_data[TEST_IO_SIZE + 1];
602 char mismatch_data[TEST_IO_SIZE + 1];
603 int i;
604 uint64_t mismatch_offset;
605
606 for (i = 0; i < TEST_IO_SIZE; ++i) {
607 test_data[i] = (char) (rand() % (126 - 33) + 33);
608 }
609 test_data[TEST_IO_SIZE] = '\0';
610 memset(zero_data, 0, sizeof(zero_data));
611 memset(mismatch_data, 9, sizeof(mismatch_data));
612
613 for (i = 0; i < 5; ++i)
614 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
615 TEST_IO_SIZE, 0);
616
617 for (i = 5; i < 10; ++i)
618 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
619 TEST_IO_SIZE, 0);
620
621 for (i = 0; i < 5; ++i)
622 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
623 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, 0);
624
625 for (i = 5; i < 10; ++i)
626 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
627 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
628
629 for (i = 0; i < 5; ++i)
630 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i,
631 TEST_IO_SIZE, 0);
632
633 for (i = 5; i < 10; ++i)
634 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
635 TEST_IO_SIZE, 0);
636
637 // discard 2nd, 4th sections.
638 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
639 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
640
641 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
642 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
643 TEST_IO_SIZE, TEST_IO_SIZE, 0);
644 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2,
645 TEST_IO_SIZE, 0);
646 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
647 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
648 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4,
649 TEST_IO_SIZE, 0);
650
651 for (i = 0; i < 15; ++i) {
652 if (i % 3 == 2) {
653 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
654 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
655 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
656 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
657 } else if (i % 3 == 1) {
658 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
659 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
660 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
661 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
662 } else {
663 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
664 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
665 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
666 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
667 }
668 }
669 for (i = 0; i < 15; ++i) {
670 if (i % 3 == 2) {
671 ASSERT_PASSED(aio_writesame_test_data, image, test_data,
672 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE,
673 0);
674 ASSERT_PASSED(aio_writesame_test_data, image, zero_data,
675 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE,
676 0);
677 } else if (i % 3 == 1) {
678 ASSERT_PASSED(aio_writesame_test_data, image, test_data,
679 TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
680 ASSERT_PASSED(aio_writesame_test_data, image, zero_data,
681 TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
682 } else {
683 ASSERT_PASSED(aio_writesame_test_data, image, test_data,
684 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
685 ASSERT_PASSED(aio_writesame_test_data, image, zero_data,
686 TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
687 }
688 }
689
690 rbd_image_info_t info;
691 rbd_completion_t comp;
692 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
693 // can't read or write starting past end
694 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
695 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
696 // reading through end returns amount up to end
697 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
698 // writing through end returns amount up to end
699 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
700
701 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
702 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
703 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
704 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
705 rbd_aio_release(comp);
706
707 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
708 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
709 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
710 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
711 rbd_aio_release(comp);
712
713 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE,
714 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
39ae355f 715 mismatch_offset = 123;
f67539c2
TL
716 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE,
717 mismatch_data, mismatch_data, &mismatch_offset, 0));
718 ASSERT_EQ(0U, mismatch_offset);
719 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
39ae355f 720 mismatch_offset = 123;
f67539c2
TL
721 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data,
722 mismatch_data, comp, &mismatch_offset, 0));
723 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
39ae355f 724 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
f67539c2
TL
725 ASSERT_EQ(0U, mismatch_offset);
726 rbd_aio_release(comp);
727
728 ASSERT_PASSED(validate_object_map, image);
729 }
730
7c673cae
FG
731 static std::vector<std::string> _pool_names;
732 static std::vector<std::string> _unique_pool_names;
733 static rados_t _cluster;
734 static librados::Rados _rados;
735 static uint64_t _image_number;
736
737 std::string m_pool_name;
738 uint32_t m_pool_number;
739
740};
741
742std::vector<std::string> TestLibRBD::_pool_names;
743std::vector<std::string> TestLibRBD::_unique_pool_names;
744rados_t TestLibRBD::_cluster;
745librados::Rados TestLibRBD::_rados;
746uint64_t TestLibRBD::_image_number = 0;
747
748TEST_F(TestLibRBD, CreateAndStat)
749{
750 rados_ioctx_t ioctx;
751 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
752
753 rbd_image_info_t info;
754 rbd_image_t image;
755 int order = 0;
756 std::string name = get_temp_image_name();
757 uint64_t size = 2 << 20;
758
759 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
760 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
761 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
762 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
763 ASSERT_EQ(info.size, size);
764 ASSERT_EQ(info.order, order);
765 ASSERT_EQ(0, rbd_close(image));
766
767 rados_ioctx_destroy(ioctx);
768}
769
770TEST_F(TestLibRBD, CreateWithSameDataPool)
771{
772 REQUIRE_FORMAT_V2();
773
774 rados_ioctx_t ioctx;
775 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
776
777 rbd_image_t image;
778 std::string name = get_temp_image_name();
779 uint64_t size = 2 << 20;
780
781 bool old_format;
782 uint64_t features;
783 ASSERT_EQ(0, get_features(&old_format, &features));
784 ASSERT_FALSE(old_format);
785
786 rbd_image_options_t image_options;
787 rbd_image_options_create(&image_options);
788 BOOST_SCOPE_EXIT( (&image_options) ) {
789 rbd_image_options_destroy(image_options);
790 } BOOST_SCOPE_EXIT_END;
791
792 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
793 RBD_IMAGE_OPTION_FEATURES,
794 features));
795 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
796 RBD_IMAGE_OPTION_DATA_POOL,
797 m_pool_name.c_str()));
798
799 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
800 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
801
802 ASSERT_EQ(0, rbd_close(image));
803
804 rados_ioctx_destroy(ioctx);
805}
806
807TEST_F(TestLibRBD, CreateAndStatPP)
808{
809 librados::IoCtx ioctx;
810 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
811
812 {
813 librbd::RBD rbd;
814 librbd::image_info_t info;
815 librbd::Image image;
816 int order = 0;
817 std::string name = get_temp_image_name();
818 uint64_t size = 2 << 20;
819
820 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
821 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
822 ASSERT_EQ(0, image.stat(info, sizeof(info)));
823 ASSERT_EQ(info.size, size);
824 ASSERT_EQ(info.order, order);
825 }
826
827 ioctx.close();
828}
829
830TEST_F(TestLibRBD, GetId)
831{
832 rados_ioctx_t ioctx;
833 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
834
835 rbd_image_t image;
836 int order = 0;
837 std::string name = get_temp_image_name();
838
839 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
840 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
841
842 char id[4096];
843 if (!is_feature_enabled(0)) {
844 // V1 image
845 ASSERT_EQ(-EINVAL, rbd_get_id(image, id, sizeof(id)));
846 } else {
847 ASSERT_EQ(-ERANGE, rbd_get_id(image, id, 0));
848 ASSERT_EQ(0, rbd_get_id(image, id, sizeof(id)));
849 ASSERT_LT(0U, strlen(id));
11fdf7f2
TL
850
851 ASSERT_EQ(0, rbd_close(image));
852 ASSERT_EQ(0, rbd_open_by_id(ioctx, id, &image, NULL));
853 size_t name_len = 0;
854 ASSERT_EQ(-ERANGE, rbd_get_name(image, NULL, &name_len));
855 ASSERT_EQ(name_len, name.size() + 1);
856 char image_name[name_len];
857 ASSERT_EQ(0, rbd_get_name(image, image_name, &name_len));
858 ASSERT_STREQ(name.c_str(), image_name);
7c673cae
FG
859 }
860
861 ASSERT_EQ(0, rbd_close(image));
862 rados_ioctx_destroy(ioctx);
863}
864
865TEST_F(TestLibRBD, GetIdPP)
866{
867 librados::IoCtx ioctx;
868 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
869
870 librbd::RBD rbd;
871 librbd::Image image;
872 int order = 0;
873 std::string name = get_temp_image_name();
874
875 std::string id;
876 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
877 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
878 if (!is_feature_enabled(0)) {
879 // V1 image
880 ASSERT_EQ(-EINVAL, image.get_id(&id));
881 } else {
882 ASSERT_EQ(0, image.get_id(&id));
883 ASSERT_LT(0U, id.size());
11fdf7f2
TL
884
885 ASSERT_EQ(0, image.close());
886 ASSERT_EQ(0, rbd.open_by_id(ioctx, image, id.c_str(), NULL));
887 std::string image_name;
888 ASSERT_EQ(0, image.get_name(&image_name));
889 ASSERT_EQ(name, image_name);
7c673cae
FG
890 }
891}
892
893TEST_F(TestLibRBD, GetBlockNamePrefix)
894{
895 rados_ioctx_t ioctx;
896 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
897
898 rbd_image_t image;
899 int order = 0;
900 std::string name = get_temp_image_name();
901
902 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
903 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
904
905 char prefix[4096];
906 ASSERT_EQ(-ERANGE, rbd_get_block_name_prefix(image, prefix, 0));
907 ASSERT_EQ(0, rbd_get_block_name_prefix(image, prefix, sizeof(prefix)));
908 ASSERT_LT(0U, strlen(prefix));
909
910 ASSERT_EQ(0, rbd_close(image));
911 rados_ioctx_destroy(ioctx);
912}
913
914TEST_F(TestLibRBD, GetBlockNamePrefixPP)
915{
916 librados::IoCtx ioctx;
917 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
918
919 librbd::RBD rbd;
920 librbd::Image image;
921 int order = 0;
922 std::string name = get_temp_image_name();
923
924 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
925 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
926 ASSERT_LT(0U, image.get_block_name_prefix().size());
927}
928
31f18b77
FG
929TEST_F(TestLibRBD, TestGetCreateTimestamp)
930{
931 REQUIRE_FORMAT_V2();
932
933 rados_ioctx_t ioctx;
934 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
935
936 rbd_image_t image;
937 int order = 0;
938 std::string name = get_temp_image_name();
939
940 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
941 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
942
943 struct timespec timestamp;
944 ASSERT_EQ(0, rbd_get_create_timestamp(image, &timestamp));
945 ASSERT_LT(0, timestamp.tv_sec);
946
947 ASSERT_EQ(0, rbd_close(image));
948
949 rados_ioctx_destroy(ioctx);
950}
951
952TEST_F(TestLibRBD, GetCreateTimestampPP)
953{
954 REQUIRE_FORMAT_V2();
955
956 librados::IoCtx ioctx;
957 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
958
959 librbd::RBD rbd;
960 librbd::Image image;
961 int order = 0;
962 std::string name = get_temp_image_name();
963
964 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
965 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
966
967 struct timespec timestamp;
968 ASSERT_EQ(0, image.get_create_timestamp(&timestamp));
969 ASSERT_LT(0, timestamp.tv_sec);
970}
971
7c673cae
FG
972TEST_F(TestLibRBD, OpenAio)
973{
974 rados_ioctx_t ioctx;
975 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
976
977 rbd_image_info_t info;
978 rbd_image_t image;
979 int order = 0;
980 std::string name = get_temp_image_name();
981 uint64_t size = 2 << 20;
982
983 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
984
985 rbd_completion_t open_comp;
986 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
987 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
988 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
989 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
990 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp));
991 rbd_aio_release(open_comp);
992
993 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
994 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
995 ASSERT_EQ(info.size, size);
996 ASSERT_EQ(info.order, order);
997
998 rbd_completion_t close_comp;
999 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &close_comp));
1000 ASSERT_EQ(0, rbd_aio_close(image, close_comp));
1001 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp));
1002 ASSERT_EQ(1, rbd_aio_is_complete(close_comp));
1003 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp));
1004 rbd_aio_release(close_comp);
1005
1006 rados_ioctx_destroy(ioctx);
1007}
1008
1009TEST_F(TestLibRBD, OpenAioFail)
1010{
1011 rados_ioctx_t ioctx;
1012 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
1013
1014 std::string name = get_temp_image_name();
1015 rbd_image_t image;
1016 rbd_completion_t open_comp;
1017 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
1018 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
1019 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
1020 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
1021 ASSERT_EQ(-ENOENT, rbd_aio_get_return_value(open_comp));
1022 rbd_aio_release(open_comp);
1023
1024 rados_ioctx_destroy(ioctx);
1025}
1026
1027TEST_F(TestLibRBD, OpenAioPP)
1028{
1029 librados::IoCtx ioctx;
1030 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1031
1032 librbd::RBD rbd;
1033 librbd::image_info_t info;
1034 librbd::Image image;
1035 int order = 0;
1036 std::string name = get_temp_image_name();
1037 uint64_t size = 2 << 20;
1038
1039 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1040
1041 librbd::RBD::AioCompletion *open_comp =
1042 new librbd::RBD::AioCompletion(NULL, NULL);
1043 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
1044 ASSERT_EQ(0, open_comp->wait_for_complete());
1045 ASSERT_EQ(1, open_comp->is_complete());
1046 ASSERT_EQ(0, open_comp->get_return_value());
1047 open_comp->release();
1048
1049 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1050 ASSERT_EQ(info.size, size);
1051 ASSERT_EQ(info.order, order);
1052
1053 // reopen
1054 open_comp = new librbd::RBD::AioCompletion(NULL, NULL);
1055 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
1056 ASSERT_EQ(0, open_comp->wait_for_complete());
1057 ASSERT_EQ(1, open_comp->is_complete());
1058 ASSERT_EQ(0, open_comp->get_return_value());
1059 open_comp->release();
1060
1061 // close
1062 librbd::RBD::AioCompletion *close_comp =
1063 new librbd::RBD::AioCompletion(NULL, NULL);
1064 ASSERT_EQ(0, image.aio_close(close_comp));
1065 ASSERT_EQ(0, close_comp->wait_for_complete());
1066 ASSERT_EQ(1, close_comp->is_complete());
1067 ASSERT_EQ(0, close_comp->get_return_value());
1068 close_comp->release();
1069
1070 // close closed image
1071 close_comp = new librbd::RBD::AioCompletion(NULL, NULL);
1072 ASSERT_EQ(-EINVAL, image.aio_close(close_comp));
1073 close_comp->release();
1074
1075 ioctx.close();
1076}
1077
1078TEST_F(TestLibRBD, OpenAioFailPP)
1079{
1080 librados::IoCtx ioctx;
1081 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1082
1083 {
1084 librbd::RBD rbd;
1085 librbd::Image image;
1086 std::string name = get_temp_image_name();
1087
1088 librbd::RBD::AioCompletion *open_comp =
1089 new librbd::RBD::AioCompletion(NULL, NULL);
1090 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
1091 ASSERT_EQ(0, open_comp->wait_for_complete());
1092 ASSERT_EQ(1, open_comp->is_complete());
1093 ASSERT_EQ(-ENOENT, open_comp->get_return_value());
1094 open_comp->release();
1095 }
1096
1097 ioctx.close();
1098}
1099
1100TEST_F(TestLibRBD, ResizeAndStat)
1101{
1102 rados_ioctx_t ioctx;
1103 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1104
1105 rbd_image_info_t info;
1106 rbd_image_t image;
1107 int order = 0;
1108 std::string name = get_temp_image_name();
1109 uint64_t size = 2 << 20;
1110
1111 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1112 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1113
1114 ASSERT_EQ(0, rbd_resize(image, size * 4));
1115 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1116 ASSERT_EQ(info.size, size * 4);
1117
1118 ASSERT_EQ(0, rbd_resize(image, size / 2));
1119 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1120 ASSERT_EQ(info.size, size / 2);
1121
1122 // downsizing without allowing shrink should fail
1123 // and image size should not change
1124 ASSERT_EQ(-EINVAL, rbd_resize2(image, size / 4, false, NULL, NULL));
1125 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1126 ASSERT_EQ(info.size, size / 2);
1127
1128 ASSERT_EQ(0, rbd_resize2(image, size / 4, true, NULL, NULL));
1129 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1130 ASSERT_EQ(info.size, size / 4);
1131
1132 ASSERT_PASSED(validate_object_map, image);
1133 ASSERT_EQ(0, rbd_close(image));
1134
1135 rados_ioctx_destroy(ioctx);
1136}
1137
1138TEST_F(TestLibRBD, ResizeAndStatPP)
1139{
1140 librados::IoCtx ioctx;
1141 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1142
1143 {
1144 librbd::RBD rbd;
1145 librbd::image_info_t info;
1146 librbd::Image image;
1147 int order = 0;
1148 std::string name = get_temp_image_name();
1149 uint64_t size = 2 << 20;
1150
1151 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1152 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1153
1154 ASSERT_EQ(0, image.resize(size * 4));
1155 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1156 ASSERT_EQ(info.size, size * 4);
1157
1158 ASSERT_EQ(0, image.resize(size / 2));
1159 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1160 ASSERT_EQ(info.size, size / 2);
1161 ASSERT_PASSED(validate_object_map, image);
1162 }
1163
1164 ioctx.close();
1165}
1166
1167TEST_F(TestLibRBD, UpdateWatchAndResize)
1168{
1169 rados_ioctx_t ioctx;
1170 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1171
1172 rbd_image_t image;
1173 int order = 0;
1174 std::string name = get_temp_image_name();
1175 uint64_t size = 2 << 20;
1176 struct Watcher {
31f18b77 1177 rbd_image_t &m_image;
f67539c2
TL
1178 std::mutex m_lock;
1179 std::condition_variable m_cond;
31f18b77 1180 size_t m_size = 0;
7c673cae
FG
1181 static void cb(void *arg) {
1182 Watcher *watcher = static_cast<Watcher *>(arg);
1183 watcher->handle_notify();
1184 }
11fdf7f2 1185 explicit Watcher(rbd_image_t &image) : m_image(image) {}
7c673cae
FG
1186 void handle_notify() {
1187 rbd_image_info_t info;
1188 ASSERT_EQ(0, rbd_stat(m_image, &info, sizeof(info)));
f67539c2 1189 std::lock_guard<std::mutex> locker(m_lock);
7c673cae 1190 m_size = info.size;
31f18b77 1191 m_cond.notify_one();
7c673cae
FG
1192 }
1193 void wait_for_size(size_t size) {
f67539c2 1194 std::unique_lock<std::mutex> locker(m_lock);
31f18b77
FG
1195 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
1196 [size, this] {
1197 return this->m_size == size;}));
7c673cae 1198 }
7c673cae
FG
1199 } watcher(image);
1200 uint64_t handle;
1201
1202 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1203 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1204
1205 ASSERT_EQ(0, rbd_update_watch(image, &handle, Watcher::cb, &watcher));
1206
1207 ASSERT_EQ(0, rbd_resize(image, size * 4));
1208 watcher.wait_for_size(size * 4);
1209
1210 ASSERT_EQ(0, rbd_resize(image, size / 2));
1211 watcher.wait_for_size(size / 2);
1212
1213 ASSERT_EQ(0, rbd_update_unwatch(image, handle));
1214
1215 ASSERT_EQ(0, rbd_close(image));
1216 rados_ioctx_destroy(ioctx);
1217}
1218
1219TEST_F(TestLibRBD, UpdateWatchAndResizePP)
1220{
1221 librados::IoCtx ioctx;
1222 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1223
1224 {
1225 librbd::RBD rbd;
1226 librbd::Image image;
1227 int order = 0;
1228 std::string name = get_temp_image_name();
1229 uint64_t size = 2 << 20;
1230 struct Watcher : public librbd::UpdateWatchCtx {
11fdf7f2 1231 explicit Watcher(librbd::Image &image) : m_image(image) {
7c673cae
FG
1232 }
1233 void handle_notify() override {
1234 librbd::image_info_t info;
1235 ASSERT_EQ(0, m_image.stat(info, sizeof(info)));
f67539c2 1236 std::lock_guard<std::mutex> locker(m_lock);
7c673cae 1237 m_size = info.size;
31f18b77 1238 m_cond.notify_one();
7c673cae
FG
1239 }
1240 void wait_for_size(size_t size) {
f67539c2 1241 std::unique_lock<std::mutex> locker(m_lock);
31f18b77
FG
1242 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
1243 [size, this] {
1244 return this->m_size == size;}));
7c673cae
FG
1245 }
1246 librbd::Image &m_image;
f67539c2
TL
1247 std::mutex m_lock;
1248 std::condition_variable m_cond;
7c673cae
FG
1249 size_t m_size = 0;
1250 } watcher(image);
1251 uint64_t handle;
1252
1253 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1254 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1255
1256 ASSERT_EQ(0, image.update_watch(&watcher, &handle));
1257
1258 ASSERT_EQ(0, image.resize(size * 4));
1259 watcher.wait_for_size(size * 4);
1260
1261 ASSERT_EQ(0, image.resize(size / 2));
1262 watcher.wait_for_size(size / 2);
1263
1264 ASSERT_EQ(0, image.update_unwatch(handle));
1265 }
1266
1267 ioctx.close();
1268}
1269
1270int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
1271{
1272 int num_images, i;
1273 char *names, *cur_name;
1274 va_list ap;
1275 size_t max_size = 1024;
1276
1277 names = (char *) malloc(sizeof(char) * 1024);
1278 int len = rbd_list(io_ctx, names, &max_size);
1279
1280 std::set<std::string> image_names;
1281 for (i = 0, num_images = 0, cur_name = names; cur_name < names + len; i++) {
1282 printf("image: %s\n", cur_name);
1283 image_names.insert(cur_name);
1284 cur_name += strlen(cur_name) + 1;
1285 num_images++;
1286 }
1287 free(names);
1288
1289 va_start(ap, num_expected);
1290 for (i = num_expected; i > 0; i--) {
1291 char *expected = va_arg(ap, char *);
1292 printf("expected = %s\n", expected);
1293 std::set<std::string>::iterator it = image_names.find(expected);
1294 if (it != image_names.end()) {
1295 printf("found %s\n", expected);
1296 image_names.erase(it);
1297 printf("erased %s\n", expected);
1298 } else {
1299 ADD_FAILURE() << "Unable to find image " << expected;
1300 va_end(ap);
1301 return -ENOENT;
1302 }
1303 }
1304 va_end(ap);
1305
1306 if (!image_names.empty()) {
1307 ADD_FAILURE() << "Unexpected images discovered";
1308 return -EINVAL;
1309 }
1310 return num_images;
1311}
1312
1313TEST_F(TestLibRBD, TestCreateLsDelete)
1314{
1315 rados_ioctx_t ioctx;
1316 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
1317
1318 int order = 0;
1319 std::string name = get_temp_image_name();
1320 std::string name2 = get_temp_image_name();
1321 uint64_t size = 2 << 20;
11fdf7f2
TL
1322
1323 ASSERT_EQ(0, test_ls(ioctx, 0));
7c673cae
FG
1324 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1325 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
1326 ASSERT_EQ(0, create_image(ioctx, name2.c_str(), size, &order));
1327 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
1328 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
1329 ASSERT_EQ(1, test_ls(ioctx, 1, name2.c_str()));
1330
1331 ASSERT_EQ(-ENOENT, rbd_remove(ioctx, name.c_str()));
1332
1333 rados_ioctx_destroy(ioctx);
1334}
1335
1336int test_ls_pp(librbd::RBD& rbd, librados::IoCtx& io_ctx, size_t num_expected, ...)
1337{
1338 int r;
1339 size_t i;
1340 va_list ap;
1341 vector<string> names;
1342 r = rbd.list(io_ctx, names);
1343 if (r == -ENOENT)
1344 r = 0;
1345 EXPECT_TRUE(r >= 0);
1346 cout << "num images is: " << names.size() << std::endl
1347 << "expected: " << num_expected << std::endl;
1348 int num = names.size();
1349
1350 for (i = 0; i < names.size(); i++) {
1351 cout << "image: " << names[i] << std::endl;
1352 }
1353
1354 va_start(ap, num_expected);
1355 for (i = num_expected; i > 0; i--) {
1356 char *expected = va_arg(ap, char *);
1357 cout << "expected = " << expected << std::endl;
1358 vector<string>::iterator listed_name = find(names.begin(), names.end(), string(expected));
1359 if (listed_name == names.end()) {
1360 ADD_FAILURE() << "Unable to find image " << expected;
1361 va_end(ap);
1362 return -ENOENT;
1363 }
1364 names.erase(listed_name);
1365 }
f67539c2 1366 va_end(ap);
7c673cae 1367
f67539c2
TL
1368 if (!names.empty()) {
1369 ADD_FAILURE() << "Unexpected images discovered";
1370 return -EINVAL;
7c673cae 1371 }
f67539c2
TL
1372 return num;
1373}
7c673cae 1374
f67539c2 1375TEST_F(TestLibRBD, TestCreateLsDeletePP)
7c673cae
FG
1376{
1377 librados::IoCtx ioctx;
1378 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
1379
1380 {
1381 librbd::RBD rbd;
1382 librbd::Image image;
1383 int order = 0;
1384 std::string name = get_temp_image_name();
1385 std::string name2 = get_temp_image_name();
7c673cae 1386 uint64_t size = 2 << 20;
7c673cae
FG
1387
1388 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7c673cae 1389 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
f67539c2 1390 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
7c673cae 1391 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
f67539c2
TL
1392 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
1393 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name2.c_str()));
7c673cae
FG
1394 }
1395
1396 ioctx.close();
1397}
1398
f67539c2
TL
1399
1400static int print_progress_percent(uint64_t offset, uint64_t src_size,
1401 void *data)
11fdf7f2 1402{
f67539c2
TL
1403 float percent = ((float)offset * 100) / src_size;
1404 printf("%3.2f%% done\n", percent);
1405 return 0;
1406}
11fdf7f2 1407
f67539c2
TL
1408TEST_F(TestLibRBD, TestCopy)
1409{
11fdf7f2
TL
1410 rados_ioctx_t ioctx;
1411 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
11fdf7f2
TL
1412
1413 rbd_image_t image;
1414 rbd_image_t image2;
1415 rbd_image_t image3;
11fdf7f2
TL
1416 int order = 0;
1417 std::string name = get_temp_image_name();
1418 std::string name2 = get_temp_image_name();
1419 std::string name3 = get_temp_image_name();
11fdf7f2
TL
1420
1421 uint64_t size = 2 << 20;
1422
11fdf7f2
TL
1423 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1424 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11fdf7f2
TL
1425 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
1426
1427 size_t sum_key_len = 0;
1428 size_t sum_value_len = 0;
1429 std::string key;
1430 std::string val;
1431 for (int i = 1; i <= 70; i++) {
1432 key = "key" + stringify(i);
1433 val = "value" + stringify(i);
1434 ASSERT_EQ(0, rbd_metadata_set(image, key.c_str(), val.c_str()));
1435
1436 sum_key_len += (key.size() + 1);
1437 sum_value_len += (val.size() + 1);
1438 }
1439
1440 char keys[1024];
1441 char vals[1024];
1442 size_t keys_len = sizeof(keys);
1443 size_t vals_len = sizeof(vals);
1444
1445 char value[1024];
1446 size_t value_len = sizeof(value);
1447
f67539c2 1448 ASSERT_EQ(0, rbd_copy(image, ioctx, name2.c_str()));
11fdf7f2
TL
1449 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
1450 ASSERT_EQ(0, rbd_open(ioctx, name2.c_str(), &image2, NULL));
f67539c2 1451 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
11fdf7f2
TL
1452 &vals_len));
1453 ASSERT_EQ(keys_len, sum_key_len);
1454 ASSERT_EQ(vals_len, sum_value_len);
1455
1456 for (int i = 1; i <= 70; i++) {
1457 key = "key" + stringify(i);
1458 val = "value" + stringify(i);
1459 ASSERT_EQ(0, rbd_metadata_get(image2, key.c_str(), value, &value_len));
1460 ASSERT_STREQ(val.c_str(), value);
1461
1462 value_len = sizeof(value);
1463 }
1464
f67539c2
TL
1465 ASSERT_EQ(0, rbd_copy_with_progress(image, ioctx, name3.c_str(),
1466 print_progress_percent, NULL));
11fdf7f2
TL
1467 ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
1468
1469 keys_len = sizeof(keys);
1470 vals_len = sizeof(vals);
1471 ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
f67539c2 1472 ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
11fdf7f2
TL
1473 &vals_len));
1474 ASSERT_EQ(keys_len, sum_key_len);
1475 ASSERT_EQ(vals_len, sum_value_len);
1476
1477 for (int i = 1; i <= 70; i++) {
1478 key = "key" + stringify(i);
1479 val = "value" + stringify(i);
1480 ASSERT_EQ(0, rbd_metadata_get(image3, key.c_str(), value, &value_len));
1481 ASSERT_STREQ(val.c_str(), value);
1482
1483 value_len = sizeof(value);
1484 }
1485
11fdf7f2 1486 ASSERT_EQ(0, rbd_close(image));
f67539c2
TL
1487 ASSERT_EQ(0, rbd_close(image2));
1488 ASSERT_EQ(0, rbd_close(image3));
1489 rados_ioctx_destroy(ioctx);
11fdf7f2
TL
1490}
1491
f67539c2 1492class PrintProgress : public librbd::ProgressContext
11fdf7f2 1493{
f67539c2
TL
1494public:
1495 int update_progress(uint64_t offset, uint64_t src_size) override
1496 {
1497 float percent = ((float)offset * 100) / src_size;
1498 printf("%3.2f%% done\n", percent);
1499 return 0;
1500 }
1501};
11fdf7f2 1502
f67539c2
TL
1503TEST_F(TestLibRBD, TestCopyPP)
1504{
11fdf7f2
TL
1505 librados::IoCtx ioctx;
1506 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
1507
1508 {
1509 librbd::RBD rbd;
1510 librbd::Image image;
1511 librbd::Image image2;
1512 librbd::Image image3;
1513 int order = 0;
1514 std::string name = get_temp_image_name();
1515 std::string name2 = get_temp_image_name();
1516 std::string name3 = get_temp_image_name();
1517 uint64_t size = 2 << 20;
11fdf7f2
TL
1518 PrintProgress pp;
1519
1520 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1521 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1522
1523 std::string key;
1524 std::string val;
1525 for (int i = 1; i <= 70; i++) {
1526 key = "key" + stringify(i);
1527 val = "value" + stringify(i);
1528 ASSERT_EQ(0, image.metadata_set(key, val));
1529 }
1530
1531 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
f67539c2 1532 ASSERT_EQ(0, image.copy(ioctx, name2.c_str()));
11fdf7f2
TL
1533 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
1534 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), NULL));
1535
1536 map<string, bufferlist> pairs;
1537 std::string value;
1538 ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
1539 ASSERT_EQ(70U, pairs.size());
1540
1541 for (int i = 1; i <= 70; i++) {
1542 key = "key" + stringify(i);
1543 val = "value" + stringify(i);
f67539c2
TL
1544 ASSERT_EQ(0, image2.metadata_get(key.c_str(), &value));
1545 ASSERT_STREQ(val.c_str(), value.c_str());
1546 }
7c673cae 1547
f67539c2
TL
1548 ASSERT_EQ(0, image.copy_with_progress(ioctx, name3.c_str(), pp));
1549 ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name.c_str(), name2.c_str(),
1550 name3.c_str()));
1551 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
7c673cae 1552
f67539c2
TL
1553 pairs.clear();
1554 ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
1555 ASSERT_EQ(70U, pairs.size());
7c673cae 1556
f67539c2
TL
1557 for (int i = 1; i <= 70; i++) {
1558 key = "key" + stringify(i);
1559 val = "value" + stringify(i);
1560 ASSERT_EQ(0, image3.metadata_get(key.c_str(), &value));
1561 ASSERT_STREQ(val.c_str(), value.c_str());
1562 }
1563 }
7c673cae 1564
f67539c2 1565 ioctx.close();
7c673cae
FG
1566}
1567
f67539c2 1568TEST_F(TestLibRBD, TestDeepCopy)
7c673cae
FG
1569{
1570 REQUIRE_FORMAT_V2();
f67539c2 1571 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7c673cae
FG
1572
1573 rados_ioctx_t ioctx;
f67539c2
TL
1574 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
1575 BOOST_SCOPE_EXIT_ALL( (&ioctx) ) {
1576 rados_ioctx_destroy(ioctx);
1577 };
7c673cae
FG
1578
1579 rbd_image_t image;
f67539c2
TL
1580 rbd_image_t image2;
1581 rbd_image_t image3;
1582 rbd_image_t image4;
1583 rbd_image_t image5;
1584 rbd_image_t image6;
31f18b77 1585 int order = 0;
7c673cae 1586 std::string name = get_temp_image_name();
f67539c2
TL
1587 std::string name2 = get_temp_image_name();
1588 std::string name3 = get_temp_image_name();
1589 std::string name4 = get_temp_image_name();
1590 std::string name5 = get_temp_image_name();
1591 std::string name6 = get_temp_image_name();
1592
7c673cae 1593 uint64_t size = 2 << 20;
f67539c2
TL
1594
1595 rbd_image_options_t opts;
1596 rbd_image_options_create(&opts);
1597 BOOST_SCOPE_EXIT_ALL( (&opts) ) {
1598 rbd_image_options_destroy(opts);
1599 };
31f18b77 1600
7c673cae
FG
1601 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1602 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
f67539c2
TL
1603 BOOST_SCOPE_EXIT_ALL( (&image) ) {
1604 ASSERT_EQ(0, rbd_close(image));
1605 };
1606 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
7c673cae 1607
f67539c2
TL
1608 size_t sum_key_len = 0;
1609 size_t sum_value_len = 0;
1610 std::string key;
1611 std::string val;
1612 for (int i = 1; i <= 70; i++) {
1613 key = "key" + stringify(i);
1614 val = "value" + stringify(i);
1615 ASSERT_EQ(0, rbd_metadata_set(image, key.c_str(), val.c_str()));
7c673cae 1616
f67539c2
TL
1617 sum_key_len += (key.size() + 1);
1618 sum_value_len += (val.size() + 1);
1619 }
7c673cae 1620
f67539c2
TL
1621 char keys[1024];
1622 char vals[1024];
1623 size_t keys_len = sizeof(keys);
1624 size_t vals_len = sizeof(vals);
7c673cae 1625
f67539c2
TL
1626 char value[1024];
1627 size_t value_len = sizeof(value);
7c673cae 1628
f67539c2
TL
1629 ASSERT_EQ(0, rbd_deep_copy(image, ioctx, name2.c_str(), opts));
1630 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
1631 ASSERT_EQ(0, rbd_open(ioctx, name2.c_str(), &image2, NULL));
1632 BOOST_SCOPE_EXIT_ALL( (&image2) ) {
1633 ASSERT_EQ(0, rbd_close(image2));
1634 };
1635 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 70, keys, &keys_len, vals,
1636 &vals_len));
1637 ASSERT_EQ(keys_len, sum_key_len);
1638 ASSERT_EQ(vals_len, sum_value_len);
7c673cae 1639
f67539c2
TL
1640 for (int i = 1; i <= 70; i++) {
1641 key = "key" + stringify(i);
1642 val = "value" + stringify(i);
1643 ASSERT_EQ(0, rbd_metadata_get(image2, key.c_str(), value, &value_len));
1644 ASSERT_STREQ(val.c_str(), value);
7c673cae 1645
f67539c2 1646 value_len = sizeof(value);
7c673cae
FG
1647 }
1648
f67539c2
TL
1649 ASSERT_EQ(0, rbd_deep_copy_with_progress(image, ioctx, name3.c_str(), opts,
1650 print_progress_percent, NULL));
1651 ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
7c673cae 1652
f67539c2
TL
1653 keys_len = sizeof(keys);
1654 vals_len = sizeof(vals);
1655 ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
1656 BOOST_SCOPE_EXIT_ALL( (&image3) ) {
1657 ASSERT_EQ(0, rbd_close(image3));
1658 };
1659 ASSERT_EQ(0, rbd_metadata_list(image3, "key", 70, keys, &keys_len, vals,
1660 &vals_len));
1661 ASSERT_EQ(keys_len, sum_key_len);
1662 ASSERT_EQ(vals_len, sum_value_len);
1663
1664 for (int i = 1; i <= 70; i++) {
1665 key = "key" + stringify(i);
1666 val = "value" + stringify(i);
1667 ASSERT_EQ(0, rbd_metadata_get(image3, key.c_str(), value, &value_len));
1668 ASSERT_STREQ(val.c_str(), value);
1669
1670 value_len = sizeof(value);
7c673cae
FG
1671 }
1672
f67539c2
TL
1673 ASSERT_EQ(0, rbd_snap_create(image, "deep_snap"));
1674 ASSERT_EQ(0, rbd_close(image));
1675 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, "deep_snap"));
1676 ASSERT_EQ(0, rbd_snap_protect(image, "deep_snap"));
1677 ASSERT_EQ(0, rbd_clone3(ioctx, name.c_str(), "deep_snap", ioctx,
1678 name4.c_str(), opts));
7c673cae 1679
f67539c2
TL
1680 ASSERT_EQ(4, test_ls(ioctx, 4, name.c_str(), name2.c_str(), name3.c_str(),
1681 name4.c_str()));
1682 ASSERT_EQ(0, rbd_open(ioctx, name4.c_str(), &image4, NULL));
1683 BOOST_SCOPE_EXIT_ALL( (&image4) ) {
1684 ASSERT_EQ(0, rbd_close(image4));
1685 };
1686 ASSERT_EQ(0, rbd_snap_create(image4, "deep_snap"));
7c673cae 1687
f67539c2
TL
1688 ASSERT_EQ(0, rbd_deep_copy(image4, ioctx, name5.c_str(), opts));
1689 ASSERT_EQ(5, test_ls(ioctx, 5, name.c_str(), name2.c_str(), name3.c_str(),
1690 name4.c_str(), name5.c_str()));
1691 ASSERT_EQ(0, rbd_open(ioctx, name5.c_str(), &image5, NULL));
1692 BOOST_SCOPE_EXIT_ALL( (&image5) ) {
1693 ASSERT_EQ(0, rbd_close(image5));
1694 };
1695 ASSERT_EQ(0, rbd_metadata_list(image5, "key", 70, keys, &keys_len, vals,
1696 &vals_len));
1697 ASSERT_EQ(keys_len, sum_key_len);
1698 ASSERT_EQ(vals_len, sum_value_len);
1699
1700 for (int i = 1; i <= 70; i++) {
1701 key = "key" + stringify(i);
1702 val = "value" + stringify(i);
1703 ASSERT_EQ(0, rbd_metadata_get(image5, key.c_str(), value, &value_len));
1704 ASSERT_STREQ(val.c_str(), value);
1705
1706 value_len = sizeof(value);
7c673cae
FG
1707 }
1708
f67539c2
TL
1709 ASSERT_EQ(0, rbd_deep_copy_with_progress(image4, ioctx, name6.c_str(), opts,
1710 print_progress_percent, NULL));
1711 ASSERT_EQ(6, test_ls(ioctx, 6, name.c_str(), name2.c_str(), name3.c_str(),
1712 name4.c_str(), name5.c_str(), name6.c_str()));
1713
1714 keys_len = sizeof(keys);
1715 vals_len = sizeof(vals);
1716 ASSERT_EQ(0, rbd_open(ioctx, name6.c_str(), &image6, NULL));
1717 BOOST_SCOPE_EXIT_ALL( (&image6) ) {
1718 ASSERT_EQ(0, rbd_close(image6));
1719 };
1720 ASSERT_EQ(0, rbd_metadata_list(image6, "key", 70, keys, &keys_len, vals,
1721 &vals_len));
1722 ASSERT_EQ(keys_len, sum_key_len);
1723 ASSERT_EQ(vals_len, sum_value_len);
1724
1725 for (int i = 1; i <= 70; i++) {
1726 key = "key" + stringify(i);
1727 val = "value" + stringify(i);
1728 ASSERT_EQ(0, rbd_metadata_get(image6, key.c_str(), value, &value_len));
1729 ASSERT_STREQ(val.c_str(), value);
1730
1731 value_len = sizeof(value);
1732 }
7c673cae
FG
1733}
1734
f67539c2 1735TEST_F(TestLibRBD, TestDeepCopyPP)
9f95a23c 1736{
f67539c2
TL
1737 REQUIRE_FORMAT_V2();
1738
9f95a23c 1739 librados::IoCtx ioctx;
f67539c2 1740 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
9f95a23c
TL
1741
1742 {
1743 librbd::RBD rbd;
1744 librbd::Image image;
f67539c2
TL
1745 librbd::Image image2;
1746 librbd::Image image3;
9f95a23c
TL
1747 int order = 0;
1748 std::string name = get_temp_image_name();
f67539c2
TL
1749 std::string name2 = get_temp_image_name();
1750 std::string name3 = get_temp_image_name();
9f95a23c 1751 uint64_t size = 2 << 20;
f67539c2
TL
1752 librbd::ImageOptions opts;
1753 PrintProgress pp;
9f95a23c
TL
1754
1755 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1756 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1757
f67539c2
TL
1758 std::string key;
1759 std::string val;
1760 for (int i = 1; i <= 70; i++) {
1761 key = "key" + stringify(i);
1762 val = "value" + stringify(i);
1763 ASSERT_EQ(0, image.metadata_set(key, val));
9f95a23c
TL
1764 }
1765
f67539c2
TL
1766 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
1767 ASSERT_EQ(0, image.deep_copy(ioctx, name2.c_str(), opts));
1768 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
1769 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), NULL));
9f95a23c 1770
f67539c2
TL
1771 map<string, bufferlist> pairs;
1772 std::string value;
1773 ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
1774 ASSERT_EQ(70U, pairs.size());
9f95a23c 1775
f67539c2
TL
1776 for (int i = 1; i <= 70; i++) {
1777 key = "key" + stringify(i);
1778 val = "value" + stringify(i);
1779 ASSERT_EQ(0, image2.metadata_get(key.c_str(), &value));
1780 ASSERT_STREQ(val.c_str(), value.c_str());
1781 }
9f95a23c 1782
f67539c2
TL
1783 ASSERT_EQ(0, image.deep_copy_with_progress(ioctx, name3.c_str(), opts, pp));
1784 ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name.c_str(), name2.c_str(),
1785 name3.c_str()));
1786 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
7c673cae 1787
f67539c2
TL
1788 pairs.clear();
1789 ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
1790 ASSERT_EQ(70U, pairs.size());
1791
1792 for (int i = 1; i <= 70; i++) {
1793 key = "key" + stringify(i);
1794 val = "value" + stringify(i);
1795 ASSERT_EQ(0, image3.metadata_get(key.c_str(), &value));
1796 ASSERT_STREQ(val.c_str(), value.c_str());
1797 }
7c673cae
FG
1798 }
1799
1800 ioctx.close();
1801}
1802
f67539c2 1803int test_ls_snaps(rbd_image_t image, int num_expected, ...)
7c673cae 1804{
f67539c2
TL
1805 int num_snaps, i, j, max_size = 10;
1806 va_list ap;
1807 rbd_snap_info_t snaps[max_size];
1808 num_snaps = rbd_snap_list(image, snaps, &max_size);
1809 printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected);
7c673cae 1810
f67539c2
TL
1811 for (i = 0; i < num_snaps; i++) {
1812 printf("snap: %s\n", snaps[i].name);
1813 }
7c673cae 1814
f67539c2
TL
1815 va_start(ap, num_expected);
1816 for (i = num_expected; i > 0; i--) {
1817 char *expected = va_arg(ap, char *);
1818 uint64_t expected_size = va_arg(ap, uint64_t);
1819 bool found = false;
1820 for (j = 0; j < num_snaps; j++) {
1821 if (snaps[j].name == NULL)
1822 continue;
1823 if (strcmp(snaps[j].name, expected) == 0) {
1824 printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size);
1825 EXPECT_EQ(expected_size, snaps[j].size);
1826 free((void *) snaps[j].name);
1827 snaps[j].name = NULL;
1828 found = true;
1829 break;
1830 }
1831 }
1832 EXPECT_TRUE(found);
1833 }
1834 va_end(ap);
7c673cae 1835
f67539c2
TL
1836 for (i = 0; i < num_snaps; i++) {
1837 EXPECT_EQ((const char *)0, snaps[i].name);
1838 }
7c673cae 1839
f67539c2 1840 return num_snaps;
7c673cae
FG
1841}
1842
f67539c2 1843TEST_F(TestLibRBD, TestCreateLsDeleteSnap)
7c673cae 1844{
f67539c2
TL
1845 rados_ioctx_t ioctx;
1846 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 1847
f67539c2
TL
1848 rbd_image_t image;
1849 int order = 0;
1850 std::string name = get_temp_image_name();
1851 uint64_t size = 2 << 20;
1852 uint64_t size2 = 4 << 20;
1853
1854 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1855 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 1856
f67539c2
TL
1857 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1858 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1859 ASSERT_EQ(0, rbd_resize(image, size2));
1860 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1861 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1862 ASSERT_EQ(0, rbd_snap_remove(image, "snap1"));
1863 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
1864 ASSERT_EQ(0, rbd_snap_remove(image, "snap2"));
1865 ASSERT_EQ(0, test_ls_snaps(image, 0));
1866
1867 ASSERT_EQ(0, rbd_close(image));
1868
1869 rados_ioctx_destroy(ioctx);
7c673cae
FG
1870}
1871
f67539c2 1872int test_get_snapshot_timestamp(rbd_image_t image, uint64_t snap_id)
7c673cae 1873{
f67539c2
TL
1874 struct timespec timestamp;
1875 EXPECT_EQ(0, rbd_snap_get_timestamp(image, snap_id, &timestamp));
1876 EXPECT_LT(0, timestamp.tv_sec);
1877 return 0;
7c673cae
FG
1878}
1879
f67539c2 1880TEST_F(TestLibRBD, TestGetSnapShotTimeStamp)
7c673cae 1881{
f67539c2 1882 REQUIRE_FORMAT_V2();
7c673cae 1883
f67539c2
TL
1884 rados_ioctx_t ioctx;
1885 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 1886
f67539c2
TL
1887 rbd_image_t image;
1888 int order = 0;
1889 std::string name = get_temp_image_name();
1890 uint64_t size = 2 << 20;
1891 int num_snaps, max_size = 10;
1892 rbd_snap_info_t snaps[max_size];
7c673cae 1893
f67539c2
TL
1894 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1895 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 1896
f67539c2
TL
1897 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1898 num_snaps = rbd_snap_list(image, snaps, &max_size);
1899 ASSERT_EQ(1, num_snaps);
1900 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1901 free((void *)snaps[0].name);
7c673cae 1902
f67539c2
TL
1903 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1904 num_snaps = rbd_snap_list(image, snaps, &max_size);
1905 ASSERT_EQ(2, num_snaps);
1906 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1907 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[1].id));
1908 free((void *)snaps[0].name);
1909 free((void *)snaps[1].name);
7c673cae 1910
f67539c2 1911 ASSERT_EQ(0, rbd_close(image));
7c673cae 1912
f67539c2 1913 rados_ioctx_destroy(ioctx);
7c673cae
FG
1914}
1915
7c673cae 1916
f67539c2 1917int test_ls_snaps(librbd::Image& image, size_t num_expected, ...)
7c673cae 1918{
7c673cae 1919 int r;
f67539c2
TL
1920 size_t i, j;
1921 va_list ap;
1922 vector<librbd::snap_info_t> snaps;
1923 r = image.snap_list(snaps);
1924 EXPECT_TRUE(r >= 0);
1925 cout << "num snaps is: " << snaps.size() << std::endl
1926 << "expected: " << num_expected << std::endl;
7c673cae 1927
f67539c2
TL
1928 for (i = 0; i < snaps.size(); i++) {
1929 cout << "snap: " << snaps[i].name << std::endl;
1930 }
7c673cae 1931
f67539c2
TL
1932 va_start(ap, num_expected);
1933 for (i = num_expected; i > 0; i--) {
1934 char *expected = va_arg(ap, char *);
1935 uint64_t expected_size = va_arg(ap, uint64_t);
1936 int found = 0;
1937 for (j = 0; j < snaps.size(); j++) {
1938 if (snaps[j].name == "")
1939 continue;
1940 if (strcmp(snaps[j].name.c_str(), expected) == 0) {
1941 cout << "found " << snaps[j].name << " with size " << snaps[j].size
1942 << std::endl;
1943 EXPECT_EQ(expected_size, snaps[j].size);
1944 snaps[j].name = "";
1945 found = 1;
1946 break;
1947 }
7c673cae 1948 }
f67539c2 1949 EXPECT_TRUE(found);
7c673cae 1950 }
f67539c2 1951 va_end(ap);
7c673cae 1952
f67539c2
TL
1953 for (i = 0; i < snaps.size(); i++) {
1954 EXPECT_EQ("", snaps[i].name);
1955 }
1956
1957 return snaps.size();
7c673cae
FG
1958}
1959
f67539c2 1960TEST_F(TestLibRBD, TestCreateLsDeleteSnapPP)
7c673cae 1961{
f67539c2
TL
1962 librados::IoCtx ioctx;
1963 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 1964
f67539c2
TL
1965 {
1966 librbd::RBD rbd;
1967 librbd::Image image;
1968 int order = 0;
1969 std::string name = get_temp_image_name();
1970 uint64_t size = 2 << 20;
1971 uint64_t size2 = 4 << 20;
1972
1973 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1974 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1975
1976 bool exists;
1977 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1978 ASSERT_FALSE(exists);
1979 ASSERT_EQ(0, image.snap_create("snap1"));
1980 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1981 ASSERT_TRUE(exists);
1982 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1983 ASSERT_EQ(0, image.resize(size2));
1984 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1985 ASSERT_FALSE(exists);
1986 ASSERT_EQ(0, image.snap_create("snap2"));
1987 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1988 ASSERT_TRUE(exists);
1989 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1990 ASSERT_EQ(0, image.snap_remove("snap1"));
1991 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1992 ASSERT_FALSE(exists);
1993 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
1994 ASSERT_EQ(0, image.snap_remove("snap2"));
1995 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1996 ASSERT_FALSE(exists);
1997 ASSERT_EQ(0, test_ls_snaps(image, 0));
7c673cae 1998 }
7c673cae 1999
f67539c2 2000 ioctx.close();
7c673cae
FG
2001}
2002
f67539c2 2003TEST_F(TestLibRBD, TestGetNameIdSnapPP)
c07f9fc5 2004{
f67539c2
TL
2005 librados::IoCtx ioctx;
2006 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
c07f9fc5 2007
f67539c2
TL
2008 {
2009 librbd::RBD rbd;
2010 librbd::Image image;
2011 int order = 0;
2012 std::string name = get_temp_image_name();
2013 uint64_t size = 2 << 20;
2014
2015 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2016 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2017
2018 ASSERT_EQ(0, image.snap_create("snap1"));
2019 ASSERT_EQ(0, image.snap_create("snap2"));
2020 ASSERT_EQ(0, image.snap_create("snap3"));
2021 vector<librbd::snap_info_t> snaps;
2022 int r = image.snap_list(snaps);
2023 EXPECT_TRUE(r >= 0);
2024
2025 for (size_t i = 0; i < snaps.size(); ++i) {
2026 std::string expected_snap_name;
2027 image.snap_get_name(snaps[i].id, &expected_snap_name);
2028 ASSERT_EQ(expected_snap_name, snaps[i].name);
2029 }
2030
2031 for (size_t i = 0; i < snaps.size(); ++i) {
2032 uint64_t expected_snap_id;
2033 image.snap_get_id(snaps[i].name, &expected_snap_id);
2034 ASSERT_EQ(expected_snap_id, snaps[i].id);
2035 }
2036
2037 ASSERT_EQ(0, image.snap_remove("snap1"));
2038 ASSERT_EQ(0, image.snap_remove("snap2"));
2039 ASSERT_EQ(0, image.snap_remove("snap3"));
2040 ASSERT_EQ(0, test_ls_snaps(image, 0));
2041 }
2042
2043 ioctx.close();
c07f9fc5
FG
2044}
2045
f67539c2 2046TEST_F(TestLibRBD, TestCreateLsRenameSnapPP)
c07f9fc5 2047{
f67539c2
TL
2048 librados::IoCtx ioctx;
2049 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2050
2051 {
2052 librbd::RBD rbd;
2053 librbd::Image image;
2054 int order = 0;
2055 std::string name = get_temp_image_name();
2056 uint64_t size = 2 << 20;
2057 uint64_t size2 = 4 << 20;
2058
2059 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2060 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2061
2062 bool exists;
2063 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
2064 ASSERT_FALSE(exists);
2065 ASSERT_EQ(0, image.snap_create("snap1"));
2066 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
2067 ASSERT_TRUE(exists);
2068 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
2069 ASSERT_EQ(0, image.resize(size2));
2070 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
2071 ASSERT_FALSE(exists);
2072 ASSERT_EQ(0, image.snap_create("snap2"));
2073 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
2074 ASSERT_TRUE(exists);
2075 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
2076 ASSERT_EQ(0, image.snap_rename("snap1","snap1-rename"));
2077 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1-rename", size, "snap2", size2));
2078 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
2079 ASSERT_FALSE(exists);
2080 ASSERT_EQ(0, image.snap_exists2("snap1-rename", &exists));
2081 ASSERT_TRUE(exists);
2082 ASSERT_EQ(0, image.snap_remove("snap1-rename"));
2083 ASSERT_EQ(0, image.snap_rename("snap2","snap2-rename"));
2084 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2-rename", size2));
2085 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
2086 ASSERT_FALSE(exists);
2087 ASSERT_EQ(0, image.snap_exists2("snap2-rename", &exists));
2088 ASSERT_TRUE(exists);
2089 ASSERT_EQ(0, image.snap_remove("snap2-rename"));
2090 ASSERT_EQ(0, test_ls_snaps(image, 0));
2091 }
c07f9fc5 2092
f67539c2
TL
2093 ioctx.close();
2094}
c07f9fc5 2095
a4b75251
TL
2096TEST_F(TestLibRBD, ConcurrentCreatesUnvalidatedPool)
2097{
2098 rados_ioctx_t ioctx;
2099 ASSERT_EQ(0, rados_ioctx_create(_cluster, create_pool(true).c_str(),
2100 &ioctx));
2101
2102 std::vector<std::string> names;
2103 for (int i = 0; i < 4; i++) {
2104 names.push_back(get_temp_image_name());
2105 }
2106 uint64_t size = 2 << 20;
2107
2108 std::vector<std::thread> threads;
2109 for (const auto& name : names) {
2110 threads.emplace_back([ioctx, &name, size]() {
2111 int order = 0;
2112 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2113 });
2114 }
2115 for (auto& thread : threads) {
2116 thread.join();
2117 }
2118
2119 for (const auto& name : names) {
2120 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
2121 }
2122 rados_ioctx_destroy(ioctx);
2123}
2124
20effc67
TL
2125static void remove_full_try(rados_ioctx_t ioctx, const std::string& image_name,
2126 const std::string& data_pool_name)
2127{
2128 int order = 0;
2129 uint64_t quota = 10 << 20;
2130 uint64_t size = 5 * quota;
2131 ASSERT_EQ(0, create_image(ioctx, image_name.c_str(), size, &order));
2132
2133 std::string cmdstr = "{\"prefix\": \"osd pool set-quota\", \"pool\": \"" +
2134 data_pool_name + "\", \"field\": \"max_bytes\", \"val\": \"" +
2135 std::to_string(quota) + "\"}";
2136 char *cmd[1];
2137 cmd[0] = (char *)cmdstr.c_str();
2138 ASSERT_EQ(0, rados_mon_command(rados_ioctx_get_cluster(ioctx),
2139 (const char **)cmd, 1, "", 0, nullptr, 0,
2140 nullptr, 0));
2141
2142 rados_set_pool_full_try(ioctx);
2143
2144 rbd_image_t image;
2145 ASSERT_EQ(0, rbd_open(ioctx, image_name.c_str(), &image, nullptr));
2146
2147 uint64_t off;
2148 size_t len = 1 << 20;
2149 ssize_t ret;
2150 for (off = 0; off < size; off += len) {
2151 ret = rbd_write_zeroes(image, off, len,
2152 RBD_WRITE_ZEROES_FLAG_THICK_PROVISION,
2153 LIBRADOS_OP_FLAG_FADVISE_FUA);
2154 if (ret < 0) {
2155 break;
2156 }
2157 ASSERT_EQ(ret, len);
2158 sleep(1);
2159 }
2160 ASSERT_TRUE(off >= quota && off < size);
2161 ASSERT_EQ(ret, -EDQUOT);
2162
2163 ASSERT_EQ(0, rbd_close(image));
2164
2165 // make sure we have latest map that marked the pool full
2166 ASSERT_EQ(0, rados_wait_for_latest_osdmap(rados_ioctx_get_cluster(ioctx)));
2167 ASSERT_EQ(0, rbd_remove(ioctx, image_name.c_str()));
2168}
2169
2170TEST_F(TestLibRBD, RemoveFullTry)
2171{
2172 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2173 REQUIRE(!is_librados_test_stub(_rados));
2174
2175 rados_ioctx_t ioctx;
2176 auto pool_name = create_pool(true);
2177 ASSERT_EQ(0, rados_ioctx_create(_cluster, pool_name.c_str(), &ioctx));
2178 // cancel out rbd_default_data_pool -- we need an image without
2179 // a separate data pool
2180 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_default_data_pool",
2181 pool_name.c_str()));
2182
2183 int order = 0;
2184 auto image_name = get_temp_image_name();
2185 // FIXME: this is a workaround for rbd_trash object being created
2186 // on the first remove -- pre-create it to avoid bumping into quota
2187 ASSERT_EQ(0, create_image(ioctx, image_name.c_str(), 0, &order));
2188 ASSERT_EQ(0, rbd_remove(ioctx, image_name.c_str()));
2189 remove_full_try(ioctx, image_name, pool_name);
2190
2191 rados_ioctx_destroy(ioctx);
2192}
2193
2194TEST_F(TestLibRBD, RemoveFullTryDataPool)
2195{
2196 REQUIRE_FORMAT_V2();
2197 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2198 REQUIRE(!is_librados_test_stub(_rados));
2199
2200 rados_ioctx_t ioctx;
2201 auto pool_name = create_pool(true);
2202 auto data_pool_name = create_pool(true);
2203 ASSERT_EQ(0, rados_ioctx_create(_cluster, pool_name.c_str(), &ioctx));
2204 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_default_data_pool",
2205 data_pool_name.c_str()));
2206
2207 auto image_name = get_temp_image_name();
2208 remove_full_try(ioctx, image_name, data_pool_name);
2209
2210 rados_ioctx_destroy(ioctx);
2211}
2212
7c673cae
FG
2213TEST_F(TestLibRBD, TestIO)
2214{
2215 rados_ioctx_t ioctx;
2216 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2217
7c673cae
FG
2218 rbd_image_t image;
2219 int order = 0;
2220 std::string name = get_temp_image_name();
11fdf7f2 2221 uint64_t size = 2 << 20;
7c673cae
FG
2222
2223 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9f95a23c 2224 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_read_from_replica_policy", "balance"));
7c673cae 2225 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 2226
f67539c2 2227 test_io(image);
7c673cae 2228
f67539c2 2229 ASSERT_EQ(0, rbd_close(image));
7c673cae 2230
f67539c2
TL
2231 rados_ioctx_destroy(ioctx);
2232}
7c673cae 2233
f67539c2
TL
2234TEST_F(TestLibRBD, TestEncryptionLUKS1)
2235{
2236 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
c07f9fc5 2237
f67539c2
TL
2238 rados_ioctx_t ioctx;
2239 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
c07f9fc5 2240
f67539c2
TL
2241 int order = 0;
2242 std::string name = get_temp_image_name();
2243 uint64_t size = 32 << 20;
7c673cae 2244
f67539c2
TL
2245 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2246 ASSERT_EQ(0, rados_conf_set(
2247 _cluster, "rbd_read_from_replica_policy", "balance"));
7c673cae 2248
f67539c2
TL
2249 rbd_image_t image;
2250 rbd_encryption_luks1_format_options_t opts = {
2251 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2252 .passphrase = "password",
2253 .passphrase_size = 8,
2254 };
2255 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7c673cae 2256
f67539c2
TL
2257#ifndef HAVE_LIBCRYPTSETUP
2258 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2259 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2260 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2261 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2262#else
2263 ASSERT_EQ(0, rbd_encryption_format(
2264 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2265 ASSERT_EQ(-EEXIST, rbd_encryption_load(
2266 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2267
2268 test_io(image);
2269
2270 bool passed;
2271 write_test_data(image, "test", 0, 4, 0, &passed);
2272 ASSERT_TRUE(passed);
2273 ASSERT_EQ(0, rbd_close(image));
7c673cae 2274
f67539c2
TL
2275 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2276 ASSERT_EQ(0, rbd_encryption_load(
2277 image, RBD_ENCRYPTION_FORMAT_LUKS1, &opts, sizeof(opts)));
2278 read_test_data(image, "test", 0, 4, 0, &passed);
2279 ASSERT_TRUE(passed);
2280#endif
7c673cae 2281
f67539c2
TL
2282 ASSERT_EQ(0, rbd_close(image));
2283 rados_ioctx_destroy(ioctx);
2284}
7c673cae 2285
f67539c2
TL
2286TEST_F(TestLibRBD, TestEncryptionLUKS2)
2287{
2288 REQUIRE(!is_feature_enabled(RBD_FEATURE_JOURNALING));
7c673cae 2289
f67539c2
TL
2290 rados_ioctx_t ioctx;
2291 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 2292
f67539c2
TL
2293 int order = 0;
2294 std::string name = get_temp_image_name();
2295 uint64_t size = 32 << 20;
c07f9fc5 2296
f67539c2
TL
2297 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2298 ASSERT_EQ(0, rados_conf_set(
2299 _cluster, "rbd_read_from_replica_policy", "balance"));
2300
2301 rbd_image_t image;
2302 rbd_encryption_luks2_format_options_t opts = {
2303 .alg = RBD_ENCRYPTION_ALGORITHM_AES256,
2304 .passphrase = "password",
2305 .passphrase_size = 8,
2306 };
2307 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2308
2309#ifndef HAVE_LIBCRYPTSETUP
2310 ASSERT_EQ(-ENOTSUP, rbd_encryption_format(
2311 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2312 ASSERT_EQ(-ENOTSUP, rbd_encryption_load(
2313 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2314#else
2315 ASSERT_EQ(0, rbd_encryption_format(
2316 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2317 ASSERT_EQ(-EEXIST, rbd_encryption_load(
2318 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2319
2320 test_io(image);
2321
2322 bool passed;
2323 write_test_data(image, "test", 0, 4, 0, &passed);
2324 ASSERT_TRUE(passed);
7c673cae
FG
2325 ASSERT_EQ(0, rbd_close(image));
2326
f67539c2
TL
2327 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2328 ASSERT_EQ(0, rbd_encryption_load(
2329 image, RBD_ENCRYPTION_FORMAT_LUKS2, &opts, sizeof(opts)));
2330 read_test_data(image, "test", 0, 4, 0, &passed);
2331 ASSERT_TRUE(passed);
2332#endif
2333
2334 ASSERT_EQ(0, rbd_close(image));
7c673cae
FG
2335 rados_ioctx_destroy(ioctx);
2336}
2337
2338TEST_F(TestLibRBD, TestIOWithIOHint)
2339{
2340 rados_ioctx_t ioctx;
2341 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2342
7c673cae
FG
2343 rbd_image_t image;
2344 int order = 0;
2345 std::string name = get_temp_image_name();
2346 uint64_t size = 2 << 20;
2347
2348 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2349 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2350
f67539c2
TL
2351 bool skip_discard = is_skip_partial_discard_enabled(image);
2352
7c673cae
FG
2353 char test_data[TEST_IO_SIZE + 1];
2354 char zero_data[TEST_IO_SIZE + 1];
c07f9fc5 2355 char mismatch_data[TEST_IO_SIZE + 1];
7c673cae 2356 int i;
c07f9fc5 2357 uint64_t mismatch_offset;
7c673cae
FG
2358
2359 for (i = 0; i < TEST_IO_SIZE; ++i) {
2360 test_data[i] = (char) (rand() % (126 - 33) + 33);
2361 }
2362 test_data[TEST_IO_SIZE] = '\0';
2363 memset(zero_data, 0, sizeof(zero_data));
c07f9fc5 2364 memset(mismatch_data, 9, sizeof(mismatch_data));
7c673cae
FG
2365
2366 for (i = 0; i < 5; ++i)
2367 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
2368 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2369
2370 for (i = 5; i < 10; ++i)
2371 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
2372 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2373
c07f9fc5
FG
2374 for (i = 0; i < 5; ++i)
2375 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
2376 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2377
2378 for (i = 5; i < 10; ++i)
2379 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
2380 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2381
7c673cae
FG
2382 for (i = 0; i < 5; ++i)
2383 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE,
2384 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2385
2386 for (i = 5; i < 10; ++i)
2387 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
2388 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2389
2390 // discard 2nd, 4th sections.
2391 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2392 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2393
2394 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE,
2395 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2396 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2397 TEST_IO_SIZE, TEST_IO_SIZE,
2398 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2399 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE,
2400 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2401 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2402 TEST_IO_SIZE*3, TEST_IO_SIZE,
2403 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2404 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2405
2406 for (i = 0; i < 15; ++i) {
2407 if (i % 3 == 2) {
2408 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2409 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2410 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2411 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2412 } else if (i % 3 == 1) {
2413 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2414 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2415 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2416 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2417 } else {
2418 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2419 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2420 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2421 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2422 }
2423 }
2424 for (i = 0; i < 15; ++i) {
2425 if (i % 3 == 2) {
2426 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2427 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2428 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2429 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2430 } else if (i % 3 == 1) {
2431 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2432 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2433 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2434 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2435 } else {
2436 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2437 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2438 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2439 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2440 }
2441 }
2442
2443 rbd_image_info_t info;
2444 rbd_completion_t comp;
2445 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
2446 // can't read or write starting past end
2447 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
2448 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
2449 // reading through end returns amount up to end
2450 ASSERT_EQ(10, rbd_read2(image, info.size - 10, 100, test_data,
2451 LIBRADOS_OP_FLAG_FADVISE_NOCACHE));
2452 // writing through end returns amount up to end
2453 ASSERT_EQ(10, rbd_write2(image, info.size - 10, 100, test_data,
2454 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2455
2456 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2457 ASSERT_EQ(0, rbd_aio_read2(image, info.size, 1, test_data, comp,
2458 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2459 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2460 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2461 rbd_aio_release(comp);
2462
c07f9fc5 2463 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
39ae355f 2464 mismatch_offset = 123;
c07f9fc5
FG
2465 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
2466 &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2467 ASSERT_EQ(0U, mismatch_offset);
2468 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
39ae355f 2469 mismatch_offset = 123;
c07f9fc5
FG
2470 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
2471 comp, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2472 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
39ae355f 2473 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
c07f9fc5
FG
2474 ASSERT_EQ(0U, mismatch_offset);
2475 rbd_aio_release(comp);
2476
7c673cae
FG
2477 ASSERT_PASSED(validate_object_map, image);
2478 ASSERT_EQ(0, rbd_close(image));
2479
2480 rados_ioctx_destroy(ioctx);
2481}
2482
2483TEST_F(TestLibRBD, TestDataPoolIO)
2484{
2485 REQUIRE_FORMAT_V2();
2486
2487 rados_ioctx_t ioctx;
2488 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2489
2490 std::string data_pool_name = create_pool(true);
2491
7c673cae
FG
2492 rbd_image_t image;
2493 std::string name = get_temp_image_name();
2494 uint64_t size = 2 << 20;
2495
2496 bool old_format;
2497 uint64_t features;
2498 ASSERT_EQ(0, get_features(&old_format, &features));
2499 ASSERT_FALSE(old_format);
2500
2501 rbd_image_options_t image_options;
2502 rbd_image_options_create(&image_options);
2503 BOOST_SCOPE_EXIT( (&image_options) ) {
2504 rbd_image_options_destroy(image_options);
2505 } BOOST_SCOPE_EXIT_END;
2506
2507 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
2508 RBD_IMAGE_OPTION_FEATURES,
2509 features));
2510 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
2511 RBD_IMAGE_OPTION_DATA_POOL,
2512 data_pool_name.c_str()));
2513
2514 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
2515 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2516 ASSERT_NE(-1, rbd_get_data_pool_id(image));
2517
f67539c2
TL
2518 bool skip_discard = is_skip_partial_discard_enabled(image);
2519
7c673cae
FG
2520 char test_data[TEST_IO_SIZE + 1];
2521 char zero_data[TEST_IO_SIZE + 1];
2522 int i;
2523
2524 for (i = 0; i < TEST_IO_SIZE; ++i) {
2525 test_data[i] = (char) (rand() % (126 - 33) + 33);
2526 }
2527 test_data[TEST_IO_SIZE] = '\0';
2528 memset(zero_data, 0, sizeof(zero_data));
2529
2530 for (i = 0; i < 5; ++i)
2531 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2532
2533 for (i = 5; i < 10; ++i)
2534 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2535
2536 for (i = 0; i < 5; ++i)
2537 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2538
2539 for (i = 5; i < 10; ++i)
2540 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2541
2542 // discard 2nd, 4th sections.
2543 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2544 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2545
2546 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
2547 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2548 TEST_IO_SIZE, TEST_IO_SIZE, 0);
2549 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
2550 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2551 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
2552 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2553
2554 rbd_image_info_t info;
2555 rbd_completion_t comp;
2556 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
2557 // can't read or write starting past end
2558 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
2559 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
2560 // reading through end returns amount up to end
2561 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
2562 // writing through end returns amount up to end
2563 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
2564
2565 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2566 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
2567 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2568 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2569 rbd_aio_release(comp);
2570
2571 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2572 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
2573 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2574 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2575 rbd_aio_release(comp);
2576
2577 ASSERT_PASSED(validate_object_map, image);
2578 ASSERT_EQ(0, rbd_close(image));
2579
2580 rados_ioctx_destroy(ioctx);
2581}
2582
39ae355f 2583TEST_F(TestLibRBD, TestCompareAndWriteMismatch)
7c673cae
FG
2584{
2585 rados_ioctx_t ioctx;
2586 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2587
2588 rbd_image_t image;
2589 int order = 0;
2590 std::string name = get_temp_image_name();
39ae355f
TL
2591 uint64_t size = 20 << 20; /* 20MiB */
2592 off_t off = 512;
7c673cae
FG
2593
2594 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2595 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2596
39ae355f
TL
2597 // We only support to compare and write the same amount of (len) bytes
2598 std::string cmp_buffer("This is a test");
2599 std::string write_buffer("Write this !!!");
2600 std::string mismatch_buffer("This will fail");
2601 std::string read_buffer(cmp_buffer.length(), '1');
2602
2603 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
2604 cmp_buffer.data());
2605 ASSERT_EQ(cmp_buffer.length(), written);
2606
2607 // Compare should fail because of mismatch
2608 uint64_t mismatch_off = 0;
2609 written = rbd_compare_and_write(image, off, write_buffer.length(),
2610 mismatch_buffer.data(), write_buffer.data(),
2611 &mismatch_off, 0);
2612 ASSERT_EQ(-EILSEQ, written);
2613 ASSERT_EQ(5U, mismatch_off);
2614
2615 // check nothing was written
2616 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
2617 ASSERT_EQ(read_buffer.length(), read);
2618 ASSERT_EQ(cmp_buffer, read_buffer);
7c673cae 2619
39ae355f
TL
2620 ASSERT_PASSED(validate_object_map, image);
2621 ASSERT_EQ(0, rbd_close(image));
7c673cae 2622
39ae355f
TL
2623 rados_ioctx_destroy(ioctx);
2624}
7c673cae 2625
39ae355f
TL
2626TEST_F(TestLibRBD, TestAioCompareAndWriteMismatch)
2627{
2628 rados_ioctx_t ioctx;
2629 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7c673cae 2630
39ae355f
TL
2631 rbd_image_t image;
2632 int order = 0;
2633 std::string name = get_temp_image_name();
2634 uint64_t size = 20 << 20; /* 20MiB */
2635 off_t off = 512;
2636
2637 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2638 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2639
2640 // We only support to compare and write the same amount of (len) bytes
2641 std::string cmp_buffer("This is a test");
2642 std::string write_buffer("Write this !!!");
2643 std::string mismatch_buffer("This will fail");
2644 std::string read_buffer(cmp_buffer.length(), '1');
2645
2646 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
2647 cmp_buffer.data());
2648 ASSERT_EQ(cmp_buffer.length(), written);
2649
2650 // Compare should fail because of mismatch
2651 rbd_completion_t comp;
7c673cae 2652 rbd_aio_create_completion(NULL, NULL, &comp);
39ae355f
TL
2653 uint64_t mismatch_off = 0;
2654 int ret = rbd_aio_compare_and_write(image, off, write_buffer.length(),
2655 mismatch_buffer.data(),
2656 write_buffer.data(), comp,
2657 &mismatch_off, 0);
2658 ASSERT_EQ(0, ret);
7c673cae 2659 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
39ae355f
TL
2660 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
2661 ASSERT_EQ(5U, mismatch_off);
7c673cae 2662 rbd_aio_release(comp);
39ae355f
TL
2663
2664 // check nothing was written
2665 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
2666 ASSERT_EQ(read_buffer.length(), read);
2667 ASSERT_EQ(cmp_buffer, read_buffer);
7c673cae
FG
2668
2669 ASSERT_PASSED(validate_object_map, image);
2670 ASSERT_EQ(0, rbd_close(image));
2671
2672 rados_ioctx_destroy(ioctx);
2673}
2674
39ae355f 2675TEST_F(TestLibRBD, TestCompareAndWriteSuccess)
7c673cae
FG
2676{
2677 rados_ioctx_t ioctx;
2678 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2679
2680 rbd_image_t image;
2681 int order = 0;
2682 std::string name = get_temp_image_name();
39ae355f
TL
2683 uint64_t size = 20 << 20; /* 20MiB */
2684 off_t off = 512;
31f18b77 2685
7c673cae
FG
2686 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2687 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2688
39ae355f
TL
2689 // We only support to compare and write the same amount of (len) bytes
2690 std::string cmp_buffer("This is a test");
2691 std::string write_buffer("Write this !!!");
2692 std::string read_buffer(cmp_buffer.length(), '1');
2693
2694 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
2695 cmp_buffer.data());
2696 ASSERT_EQ(cmp_buffer.length(), written);
2697
2698 /*
2699 * we compare against the written buffer (cmp_buffer) and write the buffer
2700 * We expect: len bytes written
2701 */
2702 uint64_t mismatch_off = 0;
2703 written = rbd_compare_and_write(image, off, write_buffer.length(),
2704 cmp_buffer.data(), write_buffer.data(),
2705 &mismatch_off, 0);
2706 ASSERT_EQ(write_buffer.length(), written);
2707 ASSERT_EQ(0U, mismatch_off);
2708
2709 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
2710 ASSERT_EQ(read_buffer.length(), read);
2711 ASSERT_EQ(write_buffer, read_buffer);
7c673cae
FG
2712
2713 ASSERT_PASSED(validate_object_map, image);
2714 ASSERT_EQ(0, rbd_close(image));
2715
2716 rados_ioctx_destroy(ioctx);
2717}
2718
39ae355f 2719TEST_F(TestLibRBD, TestAioCompareAndWriteSuccess)
11fdf7f2
TL
2720{
2721 rados_ioctx_t ioctx;
2722 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2723
39ae355f 2724 rbd_image_t image;
11fdf7f2
TL
2725 int order = 0;
2726 std::string name = get_temp_image_name();
39ae355f
TL
2727 uint64_t size = 20 << 20; /* 20MiB */
2728 off_t off = 512;
11fdf7f2
TL
2729
2730 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
39ae355f 2731 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
11fdf7f2 2732
39ae355f
TL
2733 // We only support to compare and write the same amount of (len) bytes
2734 std::string cmp_buffer("This is a test");
2735 std::string write_buffer("Write this !!!");
2736 std::string read_buffer(cmp_buffer.length(), '1');
11fdf7f2 2737
39ae355f
TL
2738 ssize_t written = rbd_write(image, off, cmp_buffer.length(),
2739 cmp_buffer.data());
2740 ASSERT_EQ(cmp_buffer.length(), written);
11fdf7f2 2741
39ae355f
TL
2742 /*
2743 * we compare against the written buffer (cmp_buffer) and write the buffer
2744 * We expect: len bytes written
2745 */
2746 rbd_completion_t comp;
2747 rbd_aio_create_completion(NULL, NULL, &comp);
2748 uint64_t mismatch_off = 0;
2749 int ret = rbd_aio_compare_and_write(image, off, write_buffer.length(),
2750 cmp_buffer.data(), write_buffer.data(),
2751 comp, &mismatch_off, 0);
2752 ASSERT_EQ(0, ret);
2753 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2754 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
2755 ASSERT_EQ(0U, mismatch_off);
2756 rbd_aio_release(comp);
11fdf7f2 2757
39ae355f
TL
2758 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
2759 ASSERT_EQ(read_buffer.length(), read);
2760 ASSERT_EQ(write_buffer, read_buffer);
11fdf7f2 2761
39ae355f
TL
2762 ASSERT_PASSED(validate_object_map, image);
2763 ASSERT_EQ(0, rbd_close(image));
11fdf7f2 2764
11fdf7f2
TL
2765 rados_ioctx_destroy(ioctx);
2766}
7c673cae 2767
39ae355f
TL
2768
2769TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitUnaligned)
7c673cae 2770{
39ae355f
TL
2771 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2772
2773 rados_ioctx_t ioctx;
2774 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2775
2776 rbd_image_t image;
2777 int order = 0;
2778 std::string name = get_temp_image_name();
2779 uint64_t size = 20 << 20; /* 20MiB */
2780
2781 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2782 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2783
2784 // large write test => we allow stripe unit size writes (aligned)
2785 uint64_t stripe_unit;
2786 rbd_get_stripe_unit(image, &stripe_unit);
2787 std::string large_write_buffer(stripe_unit, '2');
2788 std::string large_cmp_buffer(stripe_unit * 2, '4');
2789
2790 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
2791 large_cmp_buffer.data());
2792 ASSERT_EQ(large_cmp_buffer.length(), written);
2793
2794 /*
2795 * compare and write at offset stripe_unit + 1 and stripe unit size
2796 * Expect fail because access exceeds stripe (unaligned)
2797 */
2798 uint64_t mismatch_off = 0;
2799 written = rbd_compare_and_write(image, stripe_unit + 1, stripe_unit,
2800 large_cmp_buffer.data(),
2801 large_write_buffer.data(),
2802 &mismatch_off, 0);
2803 ASSERT_EQ(-EINVAL, written);
2804 ASSERT_EQ(0U, mismatch_off);
2805
2806 // check nothing has been written
2807 std::string large_read_buffer(large_cmp_buffer.length(), '5');
2808 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
2809 large_read_buffer.data());
2810 ASSERT_EQ(large_read_buffer.length(), read);
2811 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
2812 large_cmp_buffer.end(),
2813 large_read_buffer.begin());
2814 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
2815
2816 ASSERT_PASSED(validate_object_map, image);
2817 ASSERT_EQ(0, rbd_close(image));
2818
2819 rados_ioctx_destroy(ioctx);
7c673cae
FG
2820}
2821
39ae355f 2822TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitUnaligned)
7c673cae 2823{
39ae355f
TL
2824 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2825
2826 rados_ioctx_t ioctx;
2827 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2828
2829 rbd_image_t image;
2830 int order = 0;
2831 std::string name = get_temp_image_name();
2832 uint64_t size = 20 << 20; /* 20MiB */
2833
2834 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2835 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2836
2837 // large write test => we allow stripe unit size writes (aligned)
2838 uint64_t stripe_unit;
2839 rbd_get_stripe_unit(image, &stripe_unit);
2840 std::string large_write_buffer(stripe_unit, '2');
2841 std::string large_cmp_buffer(stripe_unit * 2, '4');
2842
2843 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
2844 large_cmp_buffer.data());
2845 ASSERT_EQ(large_cmp_buffer.length(), written);
2846
2847 /*
2848 * compare and write at offset stripe_unit + 1 and stripe unit size
2849 * Expect fail because access spans stripe unit boundary (unaligned)
2850 */
2851 rbd_completion_t comp;
2852 rbd_aio_create_completion(NULL, NULL, &comp);
2853 uint64_t mismatch_off = 0;
2854 int ret = rbd_aio_compare_and_write(image, stripe_unit + 1, stripe_unit,
2855 large_cmp_buffer.data(),
2856 large_write_buffer.data(),
2857 comp, &mismatch_off, 0);
2858 ASSERT_EQ(0, ret);
2859 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2860 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2861 ASSERT_EQ(0U, mismatch_off);
2862 rbd_aio_release(comp);
2863
2864 // check nothing has been written
2865 std::string large_read_buffer(large_cmp_buffer.length(), '5');
2866 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
2867 large_read_buffer.data());
2868 ASSERT_EQ(large_read_buffer.length(), read);
2869 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
2870 large_cmp_buffer.end(),
2871 large_read_buffer.begin());
2872 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
2873
2874 ASSERT_PASSED(validate_object_map, image);
2875 ASSERT_EQ(0, rbd_close(image));
2876
2877 rados_ioctx_destroy(ioctx);
7c673cae
FG
2878}
2879
39ae355f 2880TEST_F(TestLibRBD, TestCompareAndWriteTooLarge)
7c673cae 2881{
39ae355f
TL
2882 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2883
2884 rados_ioctx_t ioctx;
2885 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2886
2887 rbd_image_t image;
2888 int order = 0;
2889 std::string name = get_temp_image_name();
2890 uint64_t size = 20 << 20; /* 20MiB */
2891
2892 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2893 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2894
2895 // large write test => we allow stripe unit size writes (aligned)
2896 uint64_t stripe_unit;
2897 rbd_get_stripe_unit(image, &stripe_unit);
2898 std::string large_write_buffer(stripe_unit * 2, '2');
2899 std::string large_cmp_buffer(large_write_buffer.length(), '4');
2900
2901 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
2902 large_cmp_buffer.data());
2903 ASSERT_EQ(large_cmp_buffer.length(), written);
2904
2905 /*
2906 * compare and write at offset stripe_unit and stripe unit size + 1
2907 * Expect fail because access is larger than stripe unit size
2908 */
2909 uint64_t mismatch_off = 0;
2910 written = rbd_compare_and_write(image, stripe_unit, stripe_unit + 1,
2911 large_cmp_buffer.data(),
2912 large_write_buffer.data(),
2913 &mismatch_off, 0);
2914 ASSERT_EQ(-EINVAL, written);
2915 ASSERT_EQ(0U, mismatch_off);
2916
2917 // check nothing has been written
2918 std::string large_read_buffer(large_cmp_buffer.length(), '5');
2919 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
2920 large_read_buffer.data());
2921 ASSERT_EQ(large_read_buffer.length(), read);
2922 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
2923 large_cmp_buffer.end(),
2924 large_read_buffer.begin());
2925 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
2926
2927 ASSERT_PASSED(validate_object_map, image);
2928 ASSERT_EQ(0, rbd_close(image));
2929
2930 rados_ioctx_destroy(ioctx);
7c673cae
FG
2931}
2932
39ae355f 2933TEST_F(TestLibRBD, TestAioCompareAndWriteTooLarge)
7c673cae 2934{
39ae355f
TL
2935 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
2936
2937 rados_ioctx_t ioctx;
2938 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2939
2940 rbd_image_t image;
2941 int order = 0;
2942 std::string name = get_temp_image_name();
2943 uint64_t size = 20 << 20; /* 20MiB */
2944
2945 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2946 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2947
2948 // large write test => we allow stripe unit size writes (aligned)
2949 uint64_t stripe_unit;
2950 rbd_get_stripe_unit(image, &stripe_unit);
2951 std::string large_write_buffer(stripe_unit * 2, '2');
2952 std::string large_cmp_buffer(large_write_buffer.length(), '4');
2953
2954 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
2955 large_cmp_buffer.data());
2956 ASSERT_EQ(large_cmp_buffer.length(), written);
2957
2958 /*
2959 * compare and write at offset stripe_unit and stripe unit size + 1
2960 * Expect fail because access is larger than stripe unit size
2961 */
2962 rbd_completion_t comp;
2963 rbd_aio_create_completion(NULL, NULL, &comp);
2964 uint64_t mismatch_off = 0;
2965 int ret = rbd_aio_compare_and_write(image, stripe_unit, stripe_unit + 1,
2966 large_cmp_buffer.data(),
2967 large_write_buffer.data(),
2968 comp, &mismatch_off, 0);
2969 ASSERT_EQ(0, ret);
2970 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2971 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2972 ASSERT_EQ(0U, mismatch_off);
2973 rbd_aio_release(comp);
2974
2975 // check nothing has been written
2976 std::string large_read_buffer(large_cmp_buffer.length(), '5');
2977 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
2978 large_read_buffer.data());
2979 ASSERT_EQ(large_read_buffer.length(), read);
2980 auto buffer_mismatch = std::mismatch(large_cmp_buffer.begin(),
2981 large_cmp_buffer.end(),
2982 large_read_buffer.begin());
2983 ASSERT_EQ(large_read_buffer.end(), buffer_mismatch.second);
2984
2985 ASSERT_PASSED(validate_object_map, image);
2986 ASSERT_EQ(0, rbd_close(image));
2987
2988 rados_ioctx_destroy(ioctx);
7c673cae
FG
2989}
2990
39ae355f 2991TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitSuccess)
7c673cae 2992{
39ae355f
TL
2993 rados_ioctx_t ioctx;
2994 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2995
2996 rbd_image_t image;
2997 int order = 0;
2998 std::string name = get_temp_image_name();
2999 uint64_t size = 20 << 20; /* 20MiB */
3000
3001 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3002 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3003
3004 // large write test => we allow stripe unit size writes (aligned)
3005 uint64_t stripe_unit;
3006 rbd_get_stripe_unit(image, &stripe_unit);
3007 std::string large_write_buffer(stripe_unit, '2');
3008 std::string large_cmp_buffer(stripe_unit * 2, '4');
3009
3010 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
3011 large_cmp_buffer.data());
3012 ASSERT_EQ(large_cmp_buffer.length(), written);
3013
3014 // aligned stripe unit size access => expect success
3015 uint64_t mismatch_off = 0;
3016 written = rbd_compare_and_write(image, stripe_unit, stripe_unit,
3017 large_cmp_buffer.data(),
3018 large_write_buffer.data(),
3019 &mismatch_off, 0);
3020 ASSERT_EQ(stripe_unit, written);
3021 ASSERT_EQ(0U, mismatch_off);
3022
3023 // check stripe_unit bytes of large_write_buffer were written
3024 std::string large_read_buffer(large_cmp_buffer.length(), '5');
3025 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
3026 large_read_buffer.data());
3027 ASSERT_EQ(large_read_buffer.length(), read);
3028 auto buffer_mismatch = std::mismatch(large_read_buffer.begin(),
3029 large_read_buffer.begin() + stripe_unit,
3030 large_write_buffer.begin());
3031 ASSERT_EQ(large_write_buffer.end(), buffer_mismatch.second);
3032 // check data beyond stripe_unit size was not overwritten
3033 buffer_mismatch = std::mismatch(large_read_buffer.begin() + stripe_unit,
3034 large_read_buffer.end(),
3035 large_cmp_buffer.begin());
3036 ASSERT_EQ(large_cmp_buffer.begin() + stripe_unit, buffer_mismatch.second);
3037
3038 ASSERT_PASSED(validate_object_map, image);
3039 ASSERT_EQ(0, rbd_close(image));
3040
3041 rados_ioctx_destroy(ioctx);
7c673cae
FG
3042}
3043
39ae355f
TL
3044TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitSuccess)
3045{
3046 rados_ioctx_t ioctx;
3047 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3048
3049 rbd_image_t image;
3050 int order = 0;
3051 std::string name = get_temp_image_name();
3052 uint64_t size = 20 << 20; /* 20MiB */
3053
3054 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3055 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3056
3057 // large write test => we allow stripe unit size writes (aligned)
3058 uint64_t stripe_unit;
3059 rbd_get_stripe_unit(image, &stripe_unit);
3060 std::string large_write_buffer(stripe_unit, '2');
3061 std::string large_cmp_buffer(stripe_unit * 2, '4');
3062
3063 ssize_t written = rbd_write(image, stripe_unit, large_cmp_buffer.length(),
3064 large_cmp_buffer.data());
3065 ASSERT_EQ(large_cmp_buffer.length(), written);
3066
3067 // aligned stripe unit size access => expect success
3068 rbd_completion_t comp;
3069 rbd_aio_create_completion(NULL, NULL, &comp);
3070 uint64_t mismatch_off = 0;
3071 int ret = rbd_aio_compare_and_write(image, stripe_unit, stripe_unit,
3072 large_cmp_buffer.data(),
3073 large_write_buffer.data(),
3074 comp, &mismatch_off, 0);
3075 ASSERT_EQ(0, ret);
3076 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3077 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
3078 ASSERT_EQ(0U, mismatch_off);
3079 rbd_aio_release(comp);
3080
3081 // check stripe_unit bytes of large_write_buffer were written
3082 std::string large_read_buffer(large_cmp_buffer.length(), '5');
3083 ssize_t read = rbd_read(image, stripe_unit, large_read_buffer.length(),
3084 large_read_buffer.data());
3085 ASSERT_EQ(large_read_buffer.length(), read);
3086 auto buffer_mismatch = std::mismatch(large_read_buffer.begin(),
3087 large_read_buffer.begin() + stripe_unit,
3088 large_write_buffer.begin());
3089 ASSERT_EQ(large_write_buffer.end(), buffer_mismatch.second);
3090 // check data beyond stripe_unit size was not overwritten
3091 buffer_mismatch = std::mismatch(large_read_buffer.begin() + stripe_unit,
3092 large_read_buffer.end(),
3093 large_cmp_buffer.begin());
3094 ASSERT_EQ(large_cmp_buffer.begin() + stripe_unit, buffer_mismatch.second);
3095
3096 ASSERT_PASSED(validate_object_map, image);
3097 ASSERT_EQ(0, rbd_close(image));
3098
3099 rados_ioctx_destroy(ioctx);
3100}
3101
3102TEST_F(TestLibRBD, TestAioCompareAndWriteVIovecLenDiffers)
3103{
3104 rados_ioctx_t ioctx;
3105 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3106
3107 rbd_image_t image;
3108 int order = 0;
3109 std::string name = get_temp_image_name();
3110 uint64_t size = 20 << 20; /* 20MiB */
3111 off_t off = 512;
3112
3113 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3114 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3115
3116 std::string cmp_buffer("This is a test");
3117 size_t cmp_len = cmp_buffer.length();
3118
3119 std::string write_buffer("Write this !!!");
3120 struct iovec write_iovs[] = {
3121 {.iov_base = &write_buffer[0], .iov_len = 6},
3122 {.iov_base = &write_buffer[6], .iov_len = 5},
3123 {.iov_base = &write_buffer[11], .iov_len = 3}
3124 };
3125
3126 ASSERT_EQ(cmp_len, rbd_write(image, off, cmp_len, cmp_buffer.data()));
3127
3128 // should fail because compare iovec len cannot be different to write iovec len
3129 rbd_completion_t comp;
3130 rbd_aio_create_completion(NULL, NULL, &comp);
3131 uint64_t mismatch_off = 0;
3132 int ret = rbd_aio_compare_and_writev(image, off,
3133 write_iovs /* cmp_iovs */, 1,
3134 write_iovs, std::size(write_iovs),
3135 comp, &mismatch_off, 0);
3136 ASSERT_EQ(-EINVAL, ret);
3137 ASSERT_EQ(0U, mismatch_off);
3138 rbd_aio_release(comp);
3139
3140 // check nothing was written
3141 std::string read_buffer(cmp_buffer.length(), '1');
3142 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
3143 ASSERT_EQ(read_buffer.length(), read);
3144 ASSERT_EQ(cmp_buffer, read_buffer);
3145
3146 ASSERT_PASSED(validate_object_map, image);
3147 ASSERT_EQ(0, rbd_close(image));
3148
3149 rados_ioctx_destroy(ioctx);
3150}
3151
3152TEST_F(TestLibRBD, TestAioCompareAndWriteVMismatch)
3153{
3154 rados_ioctx_t ioctx;
3155 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3156
3157 rbd_image_t image;
3158 int order = 0;
3159 std::string name = get_temp_image_name();
3160 uint64_t size = 20 << 20; /* 20MiB */
3161 off_t off = 512;
3162
3163 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3164 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3165
3166 std::string cmp_buffer("This is a test");
3167 int cmp_len = cmp_buffer.length();
3168
3169 std::string write_buffer("Write this !!!");
3170 struct iovec write_iovs[] = {
3171 {.iov_base = &write_buffer[0], .iov_len = 6},
3172 {.iov_base = &write_buffer[6], .iov_len = 5},
3173 {.iov_base = &write_buffer[11], .iov_len = 3}
3174 };
3175
3176 std::string mismatch_buffer("This will fail");
3177 struct iovec mismatch_iovs[] = {
3178 {.iov_base = &mismatch_buffer[0], .iov_len = 5},
3179 {.iov_base = &mismatch_buffer[5], .iov_len = 5},
3180 {.iov_base = &mismatch_buffer[10], .iov_len = 4}
3181 };
3182
3183 ASSERT_EQ(cmp_len, rbd_write(image, off, cmp_len, cmp_buffer.data()));
3184
3185 // this should execute the compare but fail because of mismatch
3186 rbd_completion_t comp;
3187 rbd_aio_create_completion(NULL, NULL, &comp);
3188 uint64_t mismatch_off = 0;
3189 int ret = rbd_aio_compare_and_writev(image, off,
3190 mismatch_iovs /* cmp_iovs */,
3191 std::size(mismatch_iovs),
3192 write_iovs, std::size(write_iovs),
3193 comp, &mismatch_off, 0);
3194 ASSERT_EQ(0, ret);
3195 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3196 ASSERT_EQ(-EILSEQ, rbd_aio_get_return_value(comp));
3197 ASSERT_EQ(5U, mismatch_off);
3198 rbd_aio_release(comp);
3199
3200 // check nothing was written
3201 std::string read_buffer(cmp_buffer.length(), '1');
3202 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
3203 ASSERT_EQ(read_buffer.length(), read);
3204 ASSERT_EQ(cmp_buffer, read_buffer);
3205
3206 ASSERT_PASSED(validate_object_map, image);
3207 ASSERT_EQ(0, rbd_close(image));
3208
3209 rados_ioctx_destroy(ioctx);
3210}
3211
3212TEST_F(TestLibRBD, TestAioCompareAndWriteVSuccess)
3213{
3214 rados_ioctx_t ioctx;
3215 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3216
3217 rbd_image_t image;
3218 int order = 0;
3219 std::string name = get_temp_image_name();
3220 uint64_t size = 20 << 20; /* 20MiB */
3221 off_t off = 512;
3222
3223 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3224 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3225
3226 std::string cmp_buffer("This is a test");
3227 struct iovec cmp_iovs[] = {
3228 {.iov_base = &cmp_buffer[0], .iov_len = 5},
3229 {.iov_base = &cmp_buffer[5], .iov_len = 3},
3230 {.iov_base = &cmp_buffer[8], .iov_len = 2},
3231 {.iov_base = &cmp_buffer[10], .iov_len = 4}
3232 };
3233 size_t cmp_len = cmp_buffer.length();
3234
3235 std::string write_buffer("Write this !!!");
3236 struct iovec write_iovs[] = {
3237 {.iov_base = &write_buffer[0], .iov_len = 6},
3238 {.iov_base = &write_buffer[6], .iov_len = 5},
3239 {.iov_base = &write_buffer[11], .iov_len = 3}
3240 };
3241
3242 ASSERT_EQ(cmp_len, rbd_write(image, off, cmp_len, cmp_buffer.data()));
3243
3244 // compare against the buffer written before => should succeed
3245 rbd_completion_t comp;
3246 rbd_aio_create_completion(NULL, NULL, &comp);
3247 uint64_t mismatch_off = 0;
3248 int ret = rbd_aio_compare_and_writev(image, off,
3249 cmp_iovs, std::size(cmp_iovs),
3250 write_iovs, std::size(write_iovs),
3251 comp, &mismatch_off, 0);
3252 ASSERT_EQ(0, ret);
3253 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3254 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
3255 ASSERT_EQ(0U, mismatch_off);
3256 rbd_aio_release(comp);
3257
3258 // check data was successfully written
3259 std::string read_buffer(cmp_buffer.length(), '1');
3260 ssize_t read = rbd_read(image, off, read_buffer.length(), read_buffer.data());
3261 ASSERT_EQ(read_buffer.length(), read);
3262 ASSERT_EQ(write_buffer, read_buffer);
3263
3264 ASSERT_PASSED(validate_object_map, image);
3265 ASSERT_EQ(0, rbd_close(image));
3266
3267 rados_ioctx_destroy(ioctx);
3268}
3269
3270TEST_F(TestLibRBD, TestScatterGatherIO)
3271{
3272 rados_ioctx_t ioctx;
3273 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3274
3275 rbd_image_t image;
3276 int order = 0;
3277 std::string name = get_temp_image_name();
3278 uint64_t size = 20 << 20;
3279
3280 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3281 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3282
3283 std::string write_buffer("This is a test");
3284 // These iovecs should produce a length overflow
3285 struct iovec bad_iovs[] = {
3286 {.iov_base = &write_buffer[0], .iov_len = 5},
3287 {.iov_base = NULL, .iov_len = std::numeric_limits<size_t>::max()}
3288 };
3289 struct iovec write_iovs[] = {
3290 {.iov_base = &write_buffer[0], .iov_len = 5},
3291 {.iov_base = &write_buffer[5], .iov_len = 3},
3292 {.iov_base = &write_buffer[8], .iov_len = 2},
3293 {.iov_base = &write_buffer[10], .iov_len = 4}
3294 };
3295
3296 rbd_completion_t comp;
3297 rbd_aio_create_completion(NULL, NULL, &comp);
3298 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, write_iovs, 0, 0, comp));
3299 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 2, 0, comp));
3300 ASSERT_EQ(0, rbd_aio_writev(image, write_iovs,
3301 sizeof(write_iovs) / sizeof(struct iovec),
3302 1<<order, comp));
3303 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3304 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
3305 rbd_aio_release(comp);
3306
3307 std::string read_buffer(write_buffer.size(), '1');
3308 struct iovec read_iovs[] = {
3309 {.iov_base = &read_buffer[0], .iov_len = 4},
3310 {.iov_base = &read_buffer[8], .iov_len = 4},
3311 {.iov_base = &read_buffer[12], .iov_len = 2}
3312 };
3313
3314 rbd_aio_create_completion(NULL, NULL, &comp);
3315 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, read_iovs, 0, 0, comp));
3316 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 2, 0, comp));
3317 ASSERT_EQ(0, rbd_aio_readv(image, read_iovs,
3318 sizeof(read_iovs) / sizeof(struct iovec),
3319 1<<order, comp));
3320 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3321 ASSERT_EQ(10, rbd_aio_get_return_value(comp));
3322 rbd_aio_release(comp);
3323 ASSERT_EQ("This1111 is a ", read_buffer);
3324
3325 std::string linear_buffer(write_buffer.size(), '1');
3326 struct iovec linear_iovs[] = {
3327 {.iov_base = &linear_buffer[4], .iov_len = 4}
3328 };
3329 rbd_aio_create_completion(NULL, NULL, &comp);
3330 ASSERT_EQ(0, rbd_aio_readv(image, linear_iovs,
3331 sizeof(linear_iovs) / sizeof(struct iovec),
3332 1<<order, comp));
3333 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
3334 ASSERT_EQ(4, rbd_aio_get_return_value(comp));
3335 rbd_aio_release(comp);
3336 ASSERT_EQ("1111This111111", linear_buffer);
3337
3338 ASSERT_PASSED(validate_object_map, image);
3339 ASSERT_EQ(0, rbd_close(image));
3340
3341 rados_ioctx_destroy(ioctx);
3342}
3343
3344TEST_F(TestLibRBD, TestEmptyDiscard)
3345{
3346 rados_ioctx_t ioctx;
3347 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3348
3349 rbd_image_t image;
3350 int order = 0;
3351 std::string name = get_temp_image_name();
3352 uint64_t size = 20 << 20;
3353
3354 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3355 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3356
3357 ASSERT_PASSED(aio_discard_test_data, image, 0, 1*1024*1024);
3358 ASSERT_PASSED(aio_discard_test_data, image, 0, 4*1024*1024);
3359 ASSERT_PASSED(aio_discard_test_data, image, 3*1024*1024, 1*1024*1024);
3360
3361 ASSERT_PASSED(validate_object_map, image);
3362 ASSERT_EQ(0, rbd_close(image));
3363
3364 rados_ioctx_destroy(ioctx);
3365}
3366
3367TEST_F(TestLibRBD, TestFUA)
3368{
3369 rados_ioctx_t ioctx;
3370 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3371
3372 rbd_image_t image_write;
3373 rbd_image_t image_read;
3374 int order = 0;
3375 std::string name = get_temp_image_name();
3376 uint64_t size = 2 << 20;
3377
3378 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3379 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_write, NULL));
3380 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_read, NULL));
3381
3382 // enable writeback cache
3383 rbd_flush(image_write);
3384
3385 char test_data[TEST_IO_SIZE + 1];
3386 int i;
3387
3388 for (i = 0; i < TEST_IO_SIZE; ++i) {
3389 test_data[i] = (char) (rand() % (126 - 33) + 33);
3390 }
3391 test_data[TEST_IO_SIZE] = '\0';
3392 for (i = 0; i < 5; ++i)
3393 ASSERT_PASSED(write_test_data, image_write, test_data,
3394 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
3395
3396 for (i = 0; i < 5; ++i)
3397 ASSERT_PASSED(read_test_data, image_read, test_data,
3398 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
3399
3400 for (i = 5; i < 10; ++i)
3401 ASSERT_PASSED(aio_write_test_data, image_write, test_data,
3402 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
3403
3404 for (i = 5; i < 10; ++i)
3405 ASSERT_PASSED(aio_read_test_data, image_read, test_data,
3406 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
3407
3408 ASSERT_PASSED(validate_object_map, image_write);
3409 ASSERT_PASSED(validate_object_map, image_read);
3410 ASSERT_EQ(0, rbd_close(image_write));
3411 ASSERT_EQ(0, rbd_close(image_read));
3412 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
3413 rados_ioctx_destroy(ioctx);
3414}
3415
3416void simple_write_cb_pp(librbd::completion_t cb, void *arg)
3417{
3418 cout << "write completion cb called!" << std::endl;
3419}
3420
3421void simple_read_cb_pp(librbd::completion_t cb, void *arg)
3422{
3423 cout << "read completion cb called!" << std::endl;
3424}
3425
3426void aio_write_test_data(librbd::Image& image, const char *test_data,
3427 off_t off, uint32_t iohint, bool *passed)
3428{
3429 ceph::bufferlist bl;
3430 bl.append(test_data, strlen(test_data));
3431 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
3432 printf("created completion\n");
3433 if (iohint)
3434 image.aio_write2(off, strlen(test_data), bl, comp, iohint);
3435 else
3436 image.aio_write(off, strlen(test_data), bl, comp);
3437 printf("started write\n");
3438 comp->wait_for_complete();
3439 int r = comp->get_return_value();
3440 printf("return value is: %d\n", r);
3441 ASSERT_EQ(0, r);
3442 printf("finished write\n");
3443 comp->release();
3444 *passed = true;
3445}
3446
3447void aio_discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
3448{
3449 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
3450 image.aio_discard(off, len, comp);
3451 comp->wait_for_complete();
3452 int r = comp->get_return_value();
3453 ASSERT_EQ(0, r);
3454 comp->release();
3455 *passed = true;
3456}
3457
3458void write_test_data(librbd::Image& image, const char *test_data, off_t off, uint32_t iohint, bool *passed)
3459{
3460 size_t written;
3461 size_t len = strlen(test_data);
3462 ceph::bufferlist bl;
3463 bl.append(test_data, len);
3464 if (iohint)
3465 written = image.write2(off, len, bl, iohint);
3466 else
3467 written = image.write(off, len, bl);
3468 printf("wrote: %u\n", (unsigned int) written);
3469 ASSERT_EQ(bl.length(), written);
3470 *passed = true;
3471}
3472
3473void discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
7c673cae
FG
3474{
3475 size_t written;
3476 written = image.discard(off, len);
3477 printf("discard: %u~%u\n", (unsigned)off, (unsigned)len);
3478 ASSERT_EQ(len, written);
3479 *passed = true;
3480}
3481
39ae355f
TL
3482void aio_read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
3483{
3484 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_read_cb_pp);
3485 ceph::bufferlist bl;
3486 printf("created completion\n");
3487 if (iohint)
3488 image.aio_read2(off, expected_len, bl, comp, iohint);
3489 else
3490 image.aio_read(off, expected_len, bl, comp);
3491 printf("started read\n");
3492 comp->wait_for_complete();
3493 int r = comp->get_return_value();
3494 printf("return value is: %d\n", r);
3495 ASSERT_EQ(TEST_IO_SIZE, r);
3496 ASSERT_EQ(0, memcmp(expected, bl.c_str(), TEST_IO_SIZE));
3497 printf("finished read\n");
3498 comp->release();
3499 *passed = true;
3500}
3501
3502void read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
3503{
3504 int read;
3505 size_t len = expected_len;
3506 ceph::bufferlist bl;
3507 if (iohint)
3508 read = image.read2(off, len, bl, iohint);
3509 else
3510 read = image.read(off, len, bl);
3511 ASSERT_TRUE(read >= 0);
3512 std::string bl_str(bl.c_str(), read);
3513
3514 printf("read: %u\n", (unsigned int) read);
3515 int result = memcmp(bl_str.c_str(), expected, expected_len);
3516 if (result != 0) {
3517 printf("read: %s\nexpected: %s\n", bl_str.c_str(), expected);
3518 ASSERT_EQ(0, result);
3519 }
3520 *passed = true;
3521}
3522
3523void aio_writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
3524 size_t len, size_t data_len, uint32_t iohint, bool *passed)
3525{
3526 ceph::bufferlist bl;
3527 bl.append(test_data, data_len);
3528 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
3529 printf("created completion\n");
3530 int r;
3531 r = image.aio_writesame(off, len, bl, comp, iohint);
3532 printf("started writesame\n");
3533 if (len % data_len) {
3534 ASSERT_EQ(-EINVAL, r);
3535 printf("expected fail, finished writesame\n");
3536 comp->release();
3537 *passed = true;
3538 return;
3539 }
3540
3541 comp->wait_for_complete();
3542 r = comp->get_return_value();
3543 printf("return value is: %d\n", r);
3544 ASSERT_EQ(0, r);
3545 printf("finished writesame\n");
3546 comp->release();
3547
3548 //verify data
3549 printf("to verify the data\n");
3550 int read;
3551 uint64_t left = len;
3552 while (left > 0) {
3553 ceph::bufferlist bl;
3554 read = image.read(off, data_len, bl);
3555 ASSERT_EQ(data_len, static_cast<size_t>(read));
3556 std::string bl_str(bl.c_str(), read);
3557 int result = memcmp(bl_str.c_str(), test_data, data_len);
3558 if (result !=0 ) {
3559 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
3560 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
3561 ASSERT_EQ(0, result);
3562 }
3563 off += data_len;
3564 left -= data_len;
3565 }
3566 ASSERT_EQ(0U, left);
3567 printf("verified\n");
3568
3569 *passed = true;
3570}
3571
3572void writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
3573 ssize_t len, size_t data_len, uint32_t iohint,
3574 bool *passed)
3575{
3576 ssize_t written;
3577 ceph::bufferlist bl;
3578 bl.append(test_data, data_len);
3579 written = image.writesame(off, len, bl, iohint);
3580 if (len % data_len) {
3581 ASSERT_EQ(-EINVAL, written);
3582 printf("expected fail, finished writesame\n");
3583 *passed = true;
3584 return;
3585 }
3586 ASSERT_EQ(len, written);
3587 printf("wrote: %u\n", (unsigned int) written);
3588 *passed = true;
3589
3590 //verify data
3591 printf("to verify the data\n");
3592 int read;
3593 uint64_t left = len;
3594 while (left > 0) {
3595 ceph::bufferlist bl;
3596 read = image.read(off, data_len, bl);
3597 ASSERT_EQ(data_len, static_cast<size_t>(read));
3598 std::string bl_str(bl.c_str(), read);
3599 int result = memcmp(bl_str.c_str(), test_data, data_len);
3600 if (result !=0 ) {
3601 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
3602 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
3603 ASSERT_EQ(0, result);
3604 }
3605 off += data_len;
3606 left -= data_len;
3607 }
3608 ASSERT_EQ(0U, left);
3609 printf("verified\n");
3610
3611 *passed = true;
3612}
3613
3614void aio_compare_and_write_test_data(librbd::Image& image, const char *cmp_data,
3615 const char *test_data, off_t off, ssize_t len,
3616 uint32_t iohint, bool *passed)
3617{
3618 ceph::bufferlist cmp_bl;
3619 cmp_bl.append(cmp_data, strlen(cmp_data));
3620 ceph::bufferlist test_bl;
3621 test_bl.append(test_data, strlen(test_data));
3622 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
3623 printf("created completion\n");
3624
3625 uint64_t mismatch_offset;
3626 image.aio_compare_and_write(off, len, cmp_bl, test_bl, comp, &mismatch_offset, iohint);
3627 printf("started aio compare and write\n");
3628 comp->wait_for_complete();
3629 int r = comp->get_return_value();
3630 printf("return value is: %d\n", r);
3631 ASSERT_EQ(0, r);
3632 printf("finished aio compare and write\n");
3633 comp->release();
3634 *passed = true;
3635}
3636
3637void compare_and_write_test_data(librbd::Image& image, const char *cmp_data, const char *test_data,
3638 off_t off, ssize_t len, uint64_t *mismatch_off, uint32_t iohint, bool *passed)
3639{
3640 size_t written;
3641 ceph::bufferlist cmp_bl;
3642 cmp_bl.append(cmp_data, strlen(cmp_data));
3643 ceph::bufferlist test_bl;
3644 test_bl.append(test_data, strlen(test_data));
3645 printf("start compare and write\n");
3646 written = image.compare_and_write(off, len, cmp_bl, test_bl, mismatch_off, iohint);
3647 printf("compare and wrote: %d\n", (int) written);
3648 ASSERT_EQ(len, static_cast<ssize_t>(written));
3649 *passed = true;
3650}
3651
3652TEST_F(TestLibRBD, TestIOPP)
3653{
3654 librados::IoCtx ioctx;
3655 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3656
3657 {
3658 librbd::RBD rbd;
3659 librbd::Image image;
3660 int order = 0;
3661 std::string name = get_temp_image_name();
3662 uint64_t size = 2 << 20;
3663
3664 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3665 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3666
3667 bool skip_discard = this->is_skip_partial_discard_enabled(image);
3668
3669 char test_data[TEST_IO_SIZE + 1];
3670 char zero_data[TEST_IO_SIZE + 1];
3671 int i;
3672 uint64_t mismatch_offset;
3673
3674 for (i = 0; i < TEST_IO_SIZE; ++i) {
3675 test_data[i] = (char) (rand() % (126 - 33) + 33);
3676 }
3677 test_data[TEST_IO_SIZE] = '\0';
3678 memset(zero_data, 0, sizeof(zero_data));
3679
3680 for (i = 0; i < 5; ++i)
3681 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i, 0);
3682
3683 for (i = 5; i < 10; ++i)
3684 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i, 0);
3685
3686 for (i = 0; i < 5; ++i)
3687 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
3688 TEST_IO_SIZE, &mismatch_offset, 0);
3689
3690 for (i = 5; i < 10; ++i)
3691 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
3692 TEST_IO_SIZE, 0);
3693
3694 for (i = 0; i < 5; ++i)
3695 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
3696
3697 for (i = 5; i < 10; ++i)
3698 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
3699
3700 // discard 2nd, 4th sections.
3701 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
3702 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
3703
3704 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
3705 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
3706 TEST_IO_SIZE, TEST_IO_SIZE, 0);
3707 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
3708 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
3709 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
3710 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
3711
3712 for (i = 0; i < 15; ++i) {
3713 if (i % 3 == 2) {
3714 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
3715 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
3716 } else if (i % 3 == 1) {
3717 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3718 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3719 } else {
3720 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3721 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3722 }
3723 }
3724 for (i = 0; i < 15; ++i) {
3725 if (i % 3 == 2) {
3726 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
3727 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
3728 } else if (i % 3 == 1) {
3729 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3730 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3731 } else {
3732 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3733 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
3734 }
3735 }
3736
3737 ASSERT_PASSED(validate_object_map, image);
3738 }
3739
3740 ioctx.close();
3741}
3742
3743static void compare_written(librbd::Image& image, off_t off, size_t len,
3744 const std::string& buffer, bool *passed)
3745{
3746 bufferlist read_bl;
3747 ssize_t read = image.read(off, len, read_bl);
3748 ASSERT_EQ(len, read);
3749 std::string read_buffer(read_bl.c_str(), read);
3750 ASSERT_EQ(buffer.substr(0, len), read_buffer);
3751 *passed = true;
3752}
3753
3754TEST_F(TestLibRBD, TestCompareAndWriteCompareTooSmallPP)
3755{
3756 librados::IoCtx ioctx;
3757 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3758
3759 {
3760 librbd::RBD rbd;
3761 librbd::Image image;
3762 int order = 0;
3763 std::string name = get_temp_image_name();
3764 uint64_t size = 20 << 20; /* 20MiB */
3765 off_t off = 512;
3766
3767 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3768 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3769
3770 std::string cmp_buffer("This is a test");
3771 ceph::bufferlist cmp_bl;
3772 cmp_bl.append(&cmp_buffer[0], 5);
3773 cmp_bl.append(&cmp_buffer[5], 3);
3774 cmp_bl.append(&cmp_buffer[8], 2);
3775 cmp_bl.append(&cmp_buffer[10], 4);
3776
3777 std::string write_buffer("Write this !!!");
3778 ceph::bufferlist write_bl;
3779 write_bl.append(&write_buffer[0], 6);
3780 write_bl.append(&write_buffer[6], 5);
3781 write_bl.append(&write_buffer[11], 3);
3782
3783 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
3784 ASSERT_EQ(cmp_bl.length(), written);
3785
3786 std::string small_buffer("Too small");
3787 ceph::bufferlist small_bl;
3788 small_bl.append(&small_buffer[0], 4);
3789 small_bl.append(&small_buffer[4], 4);
3790
3791 // should fail because compare bufferlist cannot be smaller than len
3792 uint64_t mismatch_off = 0;
3793 written = image.compare_and_write(off, cmp_bl.length(),
3794 small_bl, /* cmp_bl */
3795 write_bl,
3796 &mismatch_off, 0);
3797 ASSERT_EQ(-EINVAL, written);
3798 ASSERT_EQ(0U, mismatch_off);
3799
3800 ASSERT_PASSED(validate_object_map, image);
3801 }
3802
3803 ioctx.close();
3804}
3805
3806TEST_F(TestLibRBD, TestAioCompareAndWriteCompareTooSmallPP)
7c673cae 3807{
39ae355f
TL
3808 librados::IoCtx ioctx;
3809 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3810
3811 {
3812 librbd::RBD rbd;
3813 librbd::Image image;
3814 int order = 0;
3815 std::string name = get_temp_image_name();
3816 uint64_t size = 20 << 20; /* 20MiB */
3817 off_t off = 512;
3818
3819 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3820 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3821
3822 std::string cmp_buffer("This is a test");
3823 ceph::bufferlist cmp_bl;
3824 cmp_bl.append(&cmp_buffer[0], 5);
3825 cmp_bl.append(&cmp_buffer[5], 3);
3826 cmp_bl.append(&cmp_buffer[8], 2);
3827 cmp_bl.append(&cmp_buffer[10], 4);
3828
3829 std::string write_buffer("Write this !!!");
3830 ceph::bufferlist write_bl;
3831 write_bl.append(&write_buffer[0], 6);
3832 write_bl.append(&write_buffer[6], 5);
3833 write_bl.append(&write_buffer[11], 3);
3834
3835 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
3836 ASSERT_EQ(cmp_bl.length(), written);
3837
3838 std::string small_buffer("Too small");
3839 ceph::bufferlist small_bl;
3840 small_bl.append(&small_buffer[0], 4);
3841 small_bl.append(&small_buffer[4], 4);
3842
3843 // should fail because compare bufferlist cannot be smaller than len
3844 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
3845 NULL, (librbd::callback_t) simple_write_cb_pp);
3846 uint64_t mismatch_off = 0;
3847 int ret = image.aio_compare_and_write(off, cmp_bl.length(),
3848 small_bl, /* cmp_bl */
3849 write_bl,
3850 comp, &mismatch_off, 0);
3851 ASSERT_EQ(-EINVAL, ret);
3852 ASSERT_EQ(0U, mismatch_off);
3853 comp->release();
3854
3855 ASSERT_PASSED(validate_object_map, image);
3856 }
3857
3858 ioctx.close();
7c673cae
FG
3859}
3860
39ae355f 3861TEST_F(TestLibRBD, TestCompareAndWriteWriteTooSmallPP)
7c673cae 3862{
39ae355f
TL
3863 librados::IoCtx ioctx;
3864 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 3865
39ae355f
TL
3866 {
3867 librbd::RBD rbd;
3868 librbd::Image image;
3869 int order = 0;
3870 std::string name = get_temp_image_name();
3871 uint64_t size = 20 << 20; /* 20MiB */
3872 off_t off = 512;
3873
3874 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3875 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3876
3877 std::string cmp_buffer("This is a test");
3878 ceph::bufferlist cmp_bl;
3879 cmp_bl.append(&cmp_buffer[0], 5);
3880 cmp_bl.append(&cmp_buffer[5], 3);
3881 cmp_bl.append(&cmp_buffer[8], 2);
3882 cmp_bl.append(&cmp_buffer[10], 4);
3883
3884 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
3885 ASSERT_EQ(cmp_bl.length(), written);
3886
3887 std::string small_buffer("Too small");
3888 ceph::bufferlist small_bl;
3889 small_bl.append(&small_buffer[0], 4);
3890 small_bl.append(&small_buffer[4], 4);
3891
3892 // should fail because write bufferlist cannot be smaller than len
3893 uint64_t mismatch_off = 0;
3894 written = image.compare_and_write(off, cmp_bl.length(),
3895 cmp_bl,
3896 small_bl, /* write_bl */
3897 &mismatch_off, 0);
3898 ASSERT_EQ(-EINVAL, written);
3899 ASSERT_EQ(0U, mismatch_off);
3900
3901 ASSERT_PASSED(validate_object_map, image);
7c673cae 3902 }
39ae355f
TL
3903
3904 ioctx.close();
7c673cae
FG
3905}
3906
39ae355f 3907TEST_F(TestLibRBD, TestAioCompareAndWriteWriteTooSmallPP)
7c673cae 3908{
39ae355f
TL
3909 librados::IoCtx ioctx;
3910 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3911
3912 {
3913 librbd::RBD rbd;
3914 librbd::Image image;
3915 int order = 0;
3916 std::string name = get_temp_image_name();
3917 uint64_t size = 20 << 20; /* 20MiB */
3918 off_t off = 512;
3919
3920 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3921 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3922
3923 std::string cmp_buffer("This is a test");
3924 ceph::bufferlist cmp_bl;
3925 cmp_bl.append(&cmp_buffer[0], 5);
3926 cmp_bl.append(&cmp_buffer[5], 3);
3927 cmp_bl.append(&cmp_buffer[8], 2);
3928 cmp_bl.append(&cmp_buffer[10], 4);
3929
3930 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
3931 ASSERT_EQ(cmp_bl.length(), written);
3932
3933 std::string small_buffer("Too small");
3934 ceph::bufferlist small_bl;
3935 small_bl.append(&small_buffer[0], 4);
3936 small_bl.append(&small_buffer[4], 4);
3937
3938 // should fail because write bufferlist cannot be smaller than len
3939 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
3940 NULL, (librbd::callback_t) simple_write_cb_pp);
3941 uint64_t mismatch_off = 0;
3942 int ret = image.aio_compare_and_write(off, cmp_bl.length(),
3943 cmp_bl,
3944 small_bl, /* write_bl */
3945 comp, &mismatch_off, 0);
3946 ASSERT_EQ(-EINVAL, ret);
3947 ASSERT_EQ(0U, mismatch_off);
3948 comp->release();
3949
3950 ASSERT_PASSED(validate_object_map, image);
3951 }
3952
3953 ioctx.close();
3954}
3955
3956TEST_F(TestLibRBD, TestCompareAndWriteMismatchPP)
3957{
3958 librados::IoCtx ioctx;
3959 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3960
3961 {
3962 librbd::RBD rbd;
3963 librbd::Image image;
3964 int order = 0;
3965 std::string name = get_temp_image_name();
3966 uint64_t size = 20 << 20; /* 20MiB */
3967 off_t off = 512;
3968
3969 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3970 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3971
3972 std::string cmp_buffer("This is a test");
3973 ceph::bufferlist cmp_bl;
3974 cmp_bl.append(&cmp_buffer[0], 5);
3975 cmp_bl.append(&cmp_buffer[5], 3);
3976 cmp_bl.append(&cmp_buffer[8], 2);
3977 cmp_bl.append(&cmp_buffer[10], 4);
3978
3979 std::string write_buffer("Write this !!!");
3980 ceph::bufferlist write_bl;
3981 write_bl.append(&write_buffer[0], 6);
3982 write_bl.append(&write_buffer[6], 5);
3983 write_bl.append(&write_buffer[11], 3);
3984
3985 std::string mismatch_buffer("This will fail");
3986 ceph::bufferlist mismatch_bl;
3987 mismatch_bl.append(&mismatch_buffer[0], 5);
3988 mismatch_bl.append(&mismatch_buffer[5], 5);
3989 mismatch_bl.append(&mismatch_buffer[10], 4);
3990
3991 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
3992 ASSERT_EQ(cmp_bl.length(), written);
3993
3994 // this should execute the compare but fail because of mismatch
3995 uint64_t mismatch_off = 0;
3996 written = image.compare_and_write(off, write_bl.length(),
3997 mismatch_bl, /* cmp_bl */
3998 write_bl,
3999 &mismatch_off, 0);
4000 ASSERT_EQ(-EILSEQ, written);
4001 ASSERT_EQ(5U, mismatch_off);
4002
4003 // check that nothing was written
4004 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
4005
4006 ASSERT_PASSED(validate_object_map, image);
4007 }
4008
4009 ioctx.close();
4010}
4011
4012TEST_F(TestLibRBD, TestAioCompareAndWriteMismatchPP)
4013{
4014 librados::IoCtx ioctx;
4015 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4016
4017 {
4018 librbd::RBD rbd;
4019 librbd::Image image;
4020 int order = 0;
4021 std::string name = get_temp_image_name();
4022 uint64_t size = 20 << 20; /* 20MiB */
4023 off_t off = 512;
4024
4025 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4026 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4027
4028 std::string cmp_buffer("This is a test");
4029 ceph::bufferlist cmp_bl;
4030 cmp_bl.append(&cmp_buffer[0], 5);
4031 cmp_bl.append(&cmp_buffer[5], 3);
4032 cmp_bl.append(&cmp_buffer[8], 2);
4033 cmp_bl.append(&cmp_buffer[10], 4);
4034
4035 std::string write_buffer("Write this !!!");
4036 ceph::bufferlist write_bl;
4037 write_bl.append(&write_buffer[0], 6);
4038 write_bl.append(&write_buffer[6], 5);
4039 write_bl.append(&write_buffer[11], 3);
4040
4041 std::string mismatch_buffer("This will fail");
4042 ceph::bufferlist mismatch_bl;
4043 mismatch_bl.append(&mismatch_buffer[0], 5);
4044 mismatch_bl.append(&mismatch_buffer[5], 5);
4045 mismatch_bl.append(&mismatch_buffer[10], 4);
4046
4047 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
4048 ASSERT_EQ(cmp_bl.length(), written);
4049
4050 // this should execute the compare but fail because of mismatch
4051 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
4052 NULL, (librbd::callback_t) simple_write_cb_pp);
4053 uint64_t mismatch_off = 0;
4054 int ret = image.aio_compare_and_write(off, write_bl.length(),
4055 mismatch_bl, /* cmp_bl */
4056 write_bl,
4057 comp, &mismatch_off, 0);
4058 ASSERT_EQ(0, ret);
4059 comp->wait_for_complete();
4060 ssize_t aio_ret = comp->get_return_value();
4061 ASSERT_EQ(-EILSEQ, aio_ret);
4062 ASSERT_EQ(5U, mismatch_off);
4063 comp->release();
4064
4065 // check that nothing was written
4066 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
4067
4068 ASSERT_PASSED(validate_object_map, image);
4069 }
4070
4071 ioctx.close();
4072}
4073
4074TEST_F(TestLibRBD, TestCompareAndWriteMismatchBufferlistGreaterLenPP)
4075{
4076 librados::IoCtx ioctx;
4077 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4078
4079 {
4080 librbd::RBD rbd;
4081 librbd::Image image;
4082 int order = 0;
4083 std::string name = get_temp_image_name();
4084 uint64_t size = 20 << 20; /* 20MiB */
4085 off_t off = 512;
4086
4087 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4088 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4089
4090 std::string cmp_buffer("This is a test");
4091 ceph::bufferlist cmp_bl;
4092 cmp_bl.append(&cmp_buffer[0], 5);
4093 cmp_bl.append(&cmp_buffer[5], 3);
4094 cmp_bl.append(&cmp_buffer[8], 2);
4095 cmp_bl.append(&cmp_buffer[10], 4);
4096
4097 std::string write_buffer("Write this !!!");
4098 ceph::bufferlist write_bl;
4099 write_bl.append(&write_buffer[0], 6);
4100 write_bl.append(&write_buffer[6], 5);
4101 write_bl.append(&write_buffer[11], 3);
4102
4103 std::string mismatch_buffer("This will fail");
4104 ceph::bufferlist mismatch_bl;
4105 mismatch_bl.append(&mismatch_buffer[0], 5);
4106 mismatch_bl.append(&mismatch_buffer[5], 5);
4107 mismatch_bl.append(&mismatch_buffer[10], 4);
4108
4109 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
4110 ASSERT_EQ(cmp_bl.length(), written);
4111
4112 /*
4113 * we allow cmp_bl and write_bl to be greater than len so this
4114 * should execute the compare but fail because of mismatch
4115 */
4116 uint64_t mismatch_off = 0;
4117 written = image.compare_and_write(off, cmp_bl.length() - 1,
4118 mismatch_bl, /* cmp_bl */
4119 write_bl,
4120 &mismatch_off, 0);
4121 ASSERT_EQ(-EILSEQ, written);
4122 ASSERT_EQ(5U, mismatch_off);
4123
4124 // check that nothing was written
4125 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
4126
4127 ASSERT_PASSED(validate_object_map, image);
4128 }
4129
4130 ioctx.close();
4131}
4132
4133TEST_F(TestLibRBD, TestAioCompareAndWriteMismatchBufferlistGreaterLenPP)
4134{
4135 librados::IoCtx ioctx;
4136 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4137
4138 {
4139 librbd::RBD rbd;
4140 librbd::Image image;
4141 int order = 0;
4142 std::string name = get_temp_image_name();
4143 uint64_t size = 20 << 20; /* 20MiB */
4144 off_t off = 512;
4145
4146 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4147 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4148
4149 std::string cmp_buffer("This is a test");
4150 ceph::bufferlist cmp_bl;
4151 cmp_bl.append(&cmp_buffer[0], 5);
4152 cmp_bl.append(&cmp_buffer[5], 3);
4153 cmp_bl.append(&cmp_buffer[8], 2);
4154 cmp_bl.append(&cmp_buffer[10], 4);
4155
4156 std::string write_buffer("Write this !!!");
4157 ceph::bufferlist write_bl;
4158 write_bl.append(&write_buffer[0], 6);
4159 write_bl.append(&write_buffer[6], 5);
4160 write_bl.append(&write_buffer[11], 3);
4161
4162 std::string mismatch_buffer("This will fail");
4163 ceph::bufferlist mismatch_bl;
4164 mismatch_bl.append(&mismatch_buffer[0], 5);
4165 mismatch_bl.append(&mismatch_buffer[5], 5);
4166 mismatch_bl.append(&mismatch_buffer[10], 4);
4167
4168 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
4169 ASSERT_EQ(cmp_bl.length(), written);
4170
4171 /*
4172 * we allow cmp_bl and write_bl to be greater than len so this
4173 * should execute the compare but fail because of mismatch
4174 */
4175 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
4176 NULL, (librbd::callback_t) simple_write_cb_pp);
4177 uint64_t mismatch_off = 0;
4178 int ret = image.aio_compare_and_write(off, cmp_bl.length() - 1,
4179 mismatch_bl, /* cmp_bl */
4180 write_bl,
4181 comp, &mismatch_off, 0);
4182 ASSERT_EQ(0, ret);
4183 comp->wait_for_complete();
4184 ssize_t aio_ret = comp->get_return_value();
4185 ASSERT_EQ(-EILSEQ, aio_ret);
4186 ASSERT_EQ(5U, mismatch_off);
4187 comp->release();
4188
4189 // check that nothing was written
4190 ASSERT_PASSED(compare_written, image, off, cmp_bl.length(), cmp_buffer);
4191
4192 ASSERT_PASSED(validate_object_map, image);
4193 }
4194
4195 ioctx.close();
4196}
4197
4198TEST_F(TestLibRBD, TestCompareAndWriteSuccessPP)
4199{
4200 librados::IoCtx ioctx;
4201 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4202
4203 {
4204 librbd::RBD rbd;
4205 librbd::Image image;
4206 int order = 0;
4207 std::string name = get_temp_image_name();
4208 uint64_t size = 20 << 20; /* 20MiB */
4209 off_t off = 512;
4210
4211 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4212 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4213
4214 std::string cmp_buffer("This is a test");
4215 ceph::bufferlist cmp_bl;
4216 cmp_bl.append(&cmp_buffer[0], 5);
4217 cmp_bl.append(&cmp_buffer[5], 3);
4218 cmp_bl.append(&cmp_buffer[8], 2);
4219 cmp_bl.append(&cmp_buffer[10], 4);
4220
4221 std::string write_buffer("Write this !!!");
4222 ceph::bufferlist write_bl;
4223 write_bl.append(&write_buffer[0], 6);
4224 write_bl.append(&write_buffer[6], 5);
4225 write_bl.append(&write_buffer[11], 3);
4226
4227 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
4228 ASSERT_EQ(cmp_bl.length(), written);
4229
4230 // compare against the buffer written before => should succeed
4231 uint64_t mismatch_off = 0;
4232 written = image.compare_and_write(off, cmp_bl.length(),
4233 cmp_bl,
4234 write_bl,
4235 &mismatch_off, 0);
4236 ASSERT_EQ(write_bl.length(), written);
4237 ASSERT_EQ(0U, mismatch_off);
4238
4239 // check write_bl was written
4240 ASSERT_PASSED(compare_written, image, off, write_bl.length(), write_buffer);
4241
4242 ASSERT_PASSED(validate_object_map, image);
4243 }
4244
4245 ioctx.close();
4246}
4247
4248TEST_F(TestLibRBD, TestAioCompareAndWriteSuccessPP)
4249{
4250 librados::IoCtx ioctx;
4251 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4252
4253 {
4254 librbd::RBD rbd;
4255 librbd::Image image;
4256 int order = 0;
4257 std::string name = get_temp_image_name();
4258 uint64_t size = 20 << 20; /* 20MiB */
4259 off_t off = 512;
4260
4261 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4262 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4263
4264 std::string cmp_buffer("This is a test");
4265 ceph::bufferlist cmp_bl;
4266 cmp_bl.append(&cmp_buffer[0], 5);
4267 cmp_bl.append(&cmp_buffer[5], 3);
4268 cmp_bl.append(&cmp_buffer[8], 2);
4269 cmp_bl.append(&cmp_buffer[10], 4);
4270
4271 std::string write_buffer("Write this !!!");
4272 ceph::bufferlist write_bl;
4273 write_bl.append(&write_buffer[0], 6);
4274 write_bl.append(&write_buffer[6], 5);
4275 write_bl.append(&write_buffer[11], 3);
4276
4277 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
4278 ASSERT_EQ(cmp_bl.length(), written);
4279
4280 // compare against the buffer written before => should succeed
4281 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
4282 NULL, (librbd::callback_t) simple_write_cb_pp);
4283 uint64_t mismatch_off = 0;
4284 int ret = image.aio_compare_and_write(off, write_bl.length(),
4285 cmp_bl,
4286 write_bl,
4287 comp, &mismatch_off, 0);
4288 ASSERT_EQ(0, ret);
4289 comp->wait_for_complete();
4290 ssize_t aio_ret = comp->get_return_value();
4291 ASSERT_EQ(0, aio_ret);
4292 ASSERT_EQ(0U, mismatch_off);
4293 comp->release();
4294
4295 // check write_bl was written
4296 ASSERT_PASSED(compare_written, image, off, write_bl.length(), write_buffer);
4297
4298 ASSERT_PASSED(validate_object_map, image);
4299 }
4300
4301 ioctx.close();
4302}
4303
4304TEST_F(TestLibRBD, TestCompareAndWriteSuccessBufferlistGreaterLenPP)
4305{
4306 librados::IoCtx ioctx;
4307 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4308
4309 {
4310 librbd::RBD rbd;
4311 librbd::Image image;
4312 int order = 0;
4313 std::string name = get_temp_image_name();
4314 uint64_t size = 20 << 20; /* 20MiB */
4315 off_t off = 512;
4316
4317 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4318 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4319
4320 std::string cmp_buffer("This is a test");
4321 ceph::bufferlist cmp_bl;
4322 cmp_bl.append(&cmp_buffer[0], 5);
4323 cmp_bl.append(&cmp_buffer[5], 3);
4324 cmp_bl.append(&cmp_buffer[8], 2);
4325 cmp_bl.append(&cmp_buffer[10], 4);
4326
4327 std::string write_buffer("Write this !!!");
4328 ceph::bufferlist write_bl;
4329 write_bl.append(&write_buffer[0], 6);
4330 write_bl.append(&write_buffer[6], 5);
4331 write_bl.append(&write_buffer[11], 3);
4332
4333 std::string mismatch_buffer("This will fail");
4334 ceph::bufferlist mismatch_bl;
4335 mismatch_bl.append(&mismatch_buffer[0], 5);
4336 mismatch_bl.append(&mismatch_buffer[5], 5);
4337 mismatch_bl.append(&mismatch_buffer[10], 4);
4338
4339 /*
4340 * Test len < cmp_bl & write_bl => should succeed but only compare
4341 * len bytes resp. only write len bytes
4342 */
4343 ssize_t written = image.write(off, mismatch_bl.length(), mismatch_bl);
4344 ASSERT_EQ(mismatch_bl.length(), written);
4345
4346 size_t len_m1 = cmp_bl.length() - 1;
4347 written = image.write(off, len_m1, cmp_bl);
4348 ASSERT_EQ(len_m1, written);
4349 // the content of the image at off should now be "This is a tesl"
4350
4351 uint64_t mismatch_off = 0;
4352 written = image.compare_and_write(off, len_m1,
4353 cmp_bl,
4354 write_bl,
4355 &mismatch_off, 0);
4356 ASSERT_EQ(len_m1, written);
4357 ASSERT_EQ(0U, mismatch_off);
4358
4359 // check that only write_bl.length() - 1 bytes were written
4360 ASSERT_PASSED(compare_written, image, off, len_m1, write_buffer);
4361 ASSERT_PASSED(compare_written, image, off + len_m1, 1, std::string("l"));
4362
4363 ASSERT_PASSED(validate_object_map, image);
4364 }
4365
4366 ioctx.close();
4367}
4368
4369TEST_F(TestLibRBD, TestAioCompareAndWriteSuccessBufferlistGreaterLenPP)
4370{
4371 librados::IoCtx ioctx;
4372 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4373
4374 {
4375 librbd::RBD rbd;
4376 librbd::Image image;
4377 int order = 0;
4378 std::string name = get_temp_image_name();
4379 uint64_t size = 20 << 20; /* 20MiB */
4380 off_t off = 512;
4381
4382 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4383 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4384
4385 std::string cmp_buffer("This is a test");
4386 ceph::bufferlist cmp_bl;
4387 cmp_bl.append(&cmp_buffer[0], 5);
4388 cmp_bl.append(&cmp_buffer[5], 3);
4389 cmp_bl.append(&cmp_buffer[8], 2);
4390 cmp_bl.append(&cmp_buffer[10], 4);
4391
4392 std::string write_buffer("Write this !!!");
4393 ceph::bufferlist write_bl;
4394 write_bl.append(&write_buffer[0], 6);
4395 write_bl.append(&write_buffer[6], 5);
4396 write_bl.append(&write_buffer[11], 3);
4397
4398 std::string mismatch_buffer("This will fail");
4399 ceph::bufferlist mismatch_bl;
4400 mismatch_bl.append(&mismatch_buffer[0], 5);
4401 mismatch_bl.append(&mismatch_buffer[5], 5);
4402 mismatch_bl.append(&mismatch_buffer[10], 4);
4403
4404 ssize_t written = image.write(off, cmp_bl.length(), cmp_bl);
4405 ASSERT_EQ(cmp_bl.length(), written);
4406
4407 /*
4408 * Test len < cmp_bl & write_bl => should succeed but only compare
4409 * len bytes resp. only write len bytes
4410 */
4411 written = image.write(off, mismatch_bl.length(), mismatch_bl);
4412 ASSERT_EQ(mismatch_bl.length(), written);
4413
4414 size_t len_m1 = cmp_bl.length() - 1;
4415 written = image.write(off, len_m1, cmp_bl);
4416 ASSERT_EQ(len_m1, written);
4417 // the content of the image at off should now be "This is a tesl"
4418
4419 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
4420 NULL, (librbd::callback_t) simple_write_cb_pp);
4421 uint64_t mismatch_off = 0;
4422 int ret = image.aio_compare_and_write(off, len_m1,
4423 cmp_bl,
4424 write_bl,
4425 comp, &mismatch_off, 0);
4426 ASSERT_EQ(0, ret);
4427 comp->wait_for_complete();
4428 ssize_t aio_ret = comp->get_return_value();
4429 ASSERT_EQ(0, aio_ret);
4430 ASSERT_EQ(0U, mismatch_off);
7c673cae 4431 comp->release();
7c673cae 4432
39ae355f
TL
4433 // check that only write_bl.length() - 1 bytes were written
4434 ASSERT_PASSED(compare_written, image, off, len_m1, write_buffer);
4435 ASSERT_PASSED(compare_written, image, off + len_m1, 1, std::string("l"));
7c673cae 4436
39ae355f 4437 ASSERT_PASSED(validate_object_map, image);
7c673cae 4438 }
7c673cae 4439
39ae355f 4440 ioctx.close();
7c673cae
FG
4441}
4442
39ae355f 4443TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitUnalignedPP)
7c673cae 4444{
39ae355f
TL
4445 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
4446
4447 librados::IoCtx ioctx;
4448 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4449
4450 {
4451 librbd::RBD rbd;
4452 librbd::Image image;
4453 int order = 0;
4454 std::string name = get_temp_image_name();
4455 uint64_t size = 20 << 20; /* 20MiB */
4456
4457 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4458 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4459
4460 // large write test => we allow stripe unit size writes (aligned)
4461 uint64_t stripe_unit = image.get_stripe_unit();
4462 std::string large_write_buffer(stripe_unit, '2');
4463 ceph::bufferlist large_write_bl;
4464 large_write_bl.append(large_write_buffer.data(),
4465 large_write_buffer.length());
4466
4467 std::string large_cmp_buffer(stripe_unit * 2, '3');
4468 ceph::bufferlist large_cmp_bl;
4469 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
4470
4471 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
4472 large_cmp_bl);
4473 ASSERT_EQ(large_cmp_bl.length(), written);
4474
4475 /*
4476 * compare and write at offset stripe_unit + 1 and stripe unit size
4477 * Expect fail because access exceeds stripe
4478 */
4479 uint64_t mismatch_off = 0;
4480 written = image.compare_and_write(stripe_unit + 1, stripe_unit,
4481 large_cmp_bl,
4482 large_write_bl,
4483 &mismatch_off, 0);
7c673cae 4484 ASSERT_EQ(-EINVAL, written);
39ae355f 4485 ASSERT_EQ(0U, mismatch_off);
7c673cae 4486
39ae355f
TL
4487 // check nothing has been written
4488 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
4489 large_cmp_buffer);
4490
4491 ASSERT_PASSED(validate_object_map, image);
7c673cae 4492 }
7c673cae 4493
39ae355f 4494 ioctx.close();
7c673cae
FG
4495}
4496
39ae355f 4497TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitUnalignedPP)
c07f9fc5 4498{
39ae355f 4499 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
c07f9fc5 4500
39ae355f
TL
4501 librados::IoCtx ioctx;
4502 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4503
4504 {
4505 librbd::RBD rbd;
4506 librbd::Image image;
4507 int order = 0;
4508 std::string name = get_temp_image_name();
4509 uint64_t size = 20 << 20; /* 20MiB */
4510
4511 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4512 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4513
4514 // large write test => we allow stripe unit size writes (aligned)
4515 uint64_t stripe_unit = image.get_stripe_unit();
4516 std::string large_write_buffer(stripe_unit, '2');
4517 ceph::bufferlist large_write_bl;
4518 large_write_bl.append(large_write_buffer.data(),
4519 large_write_buffer.length());
4520
4521 std::string large_cmp_buffer(stripe_unit * 2, '3');
4522 ceph::bufferlist large_cmp_bl;
4523 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
4524
4525 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
4526 large_cmp_bl);
4527 ASSERT_EQ(large_cmp_bl.length(), written);
4528
4529 /*
4530 * compare and write at offset stripe_unit + 1 and stripe unit size
4531 * Expect fail because access exceeds stripe
4532 */
4533 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
4534 NULL, (librbd::callback_t) simple_write_cb_pp);
4535 uint64_t mismatch_off = 0;
4536 int ret = image.aio_compare_and_write(stripe_unit + 1, stripe_unit,
4537 large_cmp_bl,
4538 large_write_bl,
4539 comp, &mismatch_off, 0);
4540 ASSERT_EQ(0, ret);
4541 comp->wait_for_complete();
4542 ssize_t aio_ret = comp->get_return_value();
4543 ASSERT_EQ(-EINVAL, aio_ret);
4544 ASSERT_EQ(0U, mismatch_off);
4545 comp->release();
4546
4547 // check nothing has been written
4548 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
4549 large_cmp_buffer);
4550
4551 ASSERT_PASSED(validate_object_map, image);
4552 }
4553
4554 ioctx.close();
c07f9fc5
FG
4555}
4556
39ae355f 4557TEST_F(TestLibRBD, TestCompareAndWriteTooLargePP)
c07f9fc5 4558{
39ae355f
TL
4559 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
4560
4561 librados::IoCtx ioctx;
4562 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4563
4564 {
4565 librbd::RBD rbd;
4566 librbd::Image image;
4567 int order = 0;
4568 std::string name = get_temp_image_name();
4569 uint64_t size = 20 << 20; /* 20MiB */
4570
4571 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4572 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4573
4574 // large write test => we allow stripe unit size writes (aligned)
4575 uint64_t stripe_unit = image.get_stripe_unit();
4576 std::string large_write_buffer(stripe_unit * 2, '2');
4577 ceph::bufferlist large_write_bl;
4578 large_write_bl.append(large_write_buffer.data(),
4579 large_write_buffer.length());
4580
4581 std::string large_cmp_buffer(stripe_unit * 2, '3');
4582 ceph::bufferlist large_cmp_bl;
4583 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
4584
4585 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
4586 large_cmp_bl);
4587 ASSERT_EQ(large_cmp_bl.length(), written);
4588
4589 /*
4590 * compare and write at offset stripe_unit and stripe unit size + 1
4591 * Expect fail because access is larger than stripe unit size
4592 */
4593 uint64_t mismatch_off = 0;
4594 written = image.compare_and_write(stripe_unit, stripe_unit + 1,
4595 large_cmp_bl,
4596 large_write_bl,
4597 &mismatch_off, 0);
4598 ASSERT_EQ(-EINVAL, written);
4599 ASSERT_EQ(0U, mismatch_off);
4600
4601 // check nothing has been written
4602 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
4603 large_cmp_buffer);
4604
4605 ASSERT_PASSED(validate_object_map, image);
4606 }
4607
4608 ioctx.close();
c07f9fc5
FG
4609}
4610
39ae355f 4611TEST_F(TestLibRBD, TestAioCompareAndWriteTooLargePP)
7c673cae 4612{
39ae355f
TL
4613 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
4614
7c673cae
FG
4615 librados::IoCtx ioctx;
4616 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4617
7c673cae
FG
4618 {
4619 librbd::RBD rbd;
4620 librbd::Image image;
4621 int order = 0;
4622 std::string name = get_temp_image_name();
39ae355f 4623 uint64_t size = 20 << 20; /* 20MiB */
7c673cae
FG
4624
4625 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4626 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4627
39ae355f
TL
4628 // large write test => we allow stripe unit size writes (aligned)
4629 uint64_t stripe_unit = image.get_stripe_unit();
4630 std::string large_write_buffer(stripe_unit * 2, '2');
4631 ceph::bufferlist large_write_bl;
4632 large_write_bl.append(large_write_buffer.data(),
4633 large_write_buffer.length());
4634
4635 std::string large_cmp_buffer(stripe_unit * 2, '3');
4636 ceph::bufferlist large_cmp_bl;
4637 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
4638
4639 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
4640 large_cmp_bl);
4641 ASSERT_EQ(large_cmp_bl.length(), written);
4642
4643 /*
4644 * compare and write at offset stripe_unit and stripe unit size + 1
4645 * Expect fail because access is larger than stripe unit size
4646 */
4647 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
4648 NULL, (librbd::callback_t) simple_write_cb_pp);
4649 uint64_t mismatch_off = 0;
4650 int ret = image.aio_compare_and_write(stripe_unit, stripe_unit + 1,
4651 large_cmp_bl,
4652 large_write_bl,
4653 comp, &mismatch_off, 0);
4654 ASSERT_EQ(0, ret);
4655 comp->wait_for_complete();
4656 ssize_t aio_ret = comp->get_return_value();
4657 ASSERT_EQ(-EINVAL, aio_ret);
4658 ASSERT_EQ(0U, mismatch_off);
4659 comp->release();
f67539c2 4660
39ae355f
TL
4661 // check nothing has been written
4662 ASSERT_PASSED(compare_written, image, stripe_unit, large_cmp_bl.length(),
4663 large_cmp_buffer);
7c673cae 4664
39ae355f
TL
4665 ASSERT_PASSED(validate_object_map, image);
4666 }
7c673cae 4667
39ae355f
TL
4668 ioctx.close();
4669}
7c673cae 4670
39ae355f
TL
4671TEST_F(TestLibRBD, TestCompareAndWriteStripeUnitSuccessPP)
4672{
4673 librados::IoCtx ioctx;
4674 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 4675
39ae355f
TL
4676 {
4677 librbd::RBD rbd;
4678 librbd::Image image;
4679 int order = 0;
4680 std::string name = get_temp_image_name();
4681 uint64_t size = 20 << 20; /* 20MiB */
c07f9fc5 4682
39ae355f
TL
4683 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4684 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
c07f9fc5 4685
39ae355f
TL
4686 // large write test => we allow stripe unit size writes (aligned)
4687 uint64_t stripe_unit = image.get_stripe_unit();
4688 std::string large_write_buffer(stripe_unit * 2, '2');
4689 ceph::bufferlist large_write_bl;
4690 large_write_bl.append(large_write_buffer.data(),
4691 large_write_buffer.length());
4692
4693 std::string large_cmp_buffer(stripe_unit * 2, '3');
4694 ceph::bufferlist large_cmp_bl;
4695 large_cmp_bl.append(large_cmp_buffer.data(), large_cmp_buffer.length());
4696
4697 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
4698 large_cmp_bl);
4699 ASSERT_EQ(large_cmp_bl.length(), written);
4700
4701 // aligned stripe unit size access => expect success
4702 uint64_t mismatch_off = 0;
4703 written = image.compare_and_write(stripe_unit, stripe_unit,
4704 large_cmp_bl,
4705 large_write_bl,
4706 &mismatch_off, 0);
4707 ASSERT_EQ(stripe_unit, written);
4708 ASSERT_EQ(0U, mismatch_off);
4709
4710 // check large_write_bl was written and nothing beyond
4711 ASSERT_PASSED(compare_written, image, stripe_unit, stripe_unit,
4712 large_write_buffer);
4713 ASSERT_PASSED(compare_written, image, stripe_unit * 2, stripe_unit,
4714 large_cmp_buffer);
7c673cae 4715
39ae355f
TL
4716 ASSERT_PASSED(validate_object_map, image);
4717 }
7c673cae 4718
39ae355f
TL
4719 ioctx.close();
4720}
7c673cae 4721
39ae355f
TL
4722TEST_F(TestLibRBD, TestAioCompareAndWriteStripeUnitSuccessPP)
4723{
4724 librados::IoCtx ioctx;
4725 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7c673cae 4726
39ae355f
TL
4727 {
4728 librbd::RBD rbd;
4729 librbd::Image image;
4730 int order = 0;
4731 std::string name = get_temp_image_name();
4732 uint64_t size = 20 << 20; /* 20MiB */
4733
4734 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4735 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4736
4737 // large write test => we allow stripe unit size writes (aligned)
4738 uint64_t stripe_unit = image.get_stripe_unit();
4739 std::string large_write_buffer(stripe_unit * 2, '2');
4740 ceph::bufferlist large_write_bl;
4741 large_write_bl.append(large_write_buffer.data(),
4742 large_write_buffer.length());
4743
4744 std::string large_cmp_buffer(stripe_unit * 2, '3');
4745 ceph::bufferlist large_cmp_bl;
4746 large_cmp_bl.append(large_cmp_buffer.data(),
4747 large_cmp_buffer.length());
4748
4749 ssize_t written = image.write(stripe_unit, large_cmp_bl.length(),
4750 large_cmp_bl);
4751 ASSERT_EQ(large_cmp_bl.length(), written);
4752
4753 // aligned stripe unit size access => expect success
4754 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(
4755 NULL, (librbd::callback_t) simple_write_cb_pp);
4756 uint64_t mismatch_off = 0;
4757 int ret = image.aio_compare_and_write(stripe_unit, stripe_unit,
4758 large_cmp_bl,
4759 large_write_bl,
4760 comp, &mismatch_off, 0);
4761 ASSERT_EQ(0, ret);
4762 comp->wait_for_complete();
4763 ssize_t aio_ret = comp->get_return_value();
4764 ASSERT_EQ(0, aio_ret);
4765 ASSERT_EQ(0U, mismatch_off);
4766 comp->release();
4767
4768 // check large_write_bl was written and nothing beyond
4769 ASSERT_PASSED(compare_written, image, stripe_unit, stripe_unit,
4770 large_write_buffer);
4771 ASSERT_PASSED(compare_written, image, stripe_unit * 2, stripe_unit,
4772 large_cmp_buffer);
7c673cae
FG
4773
4774 ASSERT_PASSED(validate_object_map, image);
4775 }
4776
4777 ioctx.close();
4778}
4779
4780TEST_F(TestLibRBD, TestIOPPWithIOHint)
4781{
4782 librados::IoCtx ioctx;
4783 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4784
4785 {
4786 librbd::RBD rbd;
4787 librbd::Image image;
4788 int order = 0;
4789 std::string name = get_temp_image_name();
4790 uint64_t size = 2 << 20;
4791
4792 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4793 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4794
4795 char test_data[TEST_IO_SIZE + 1];
4796 char zero_data[TEST_IO_SIZE + 1];
4797 test_data[TEST_IO_SIZE] = '\0';
4798 int i;
4799
4800 for (i = 0; i < TEST_IO_SIZE; ++i) {
4801 test_data[i] = (char) (rand() % (126 - 33) + 33);
4802 }
4803 memset(zero_data, 0, sizeof(zero_data));
4804
4805 for (i = 0; i < 5; ++i)
4806 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i,
4807 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
4808
4809 for (i = 5; i < 10; ++i)
4810 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i,
4811 LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4812
4813 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data),
4814 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_RANDOM);
4815
4816 for (i = 5; i < 10; ++i)
4817 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i,
4818 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4819
4820 for (i = 0; i < 15; ++i) {
4821 if (i % 3 == 2) {
4822 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
4823 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
4824 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
4825 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
4826 } else if (i % 3 == 1) {
4827 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
4828 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
4829 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
4830 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
4831 } else {
4832 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
4833 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
4834 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
4835 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
4836 }
4837 }
4838 for (i = 0; i < 15; ++i) {
4839 if (i % 3 == 2) {
4840 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
4841 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4842 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
4843 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4844 } else if (i % 3 == 1) {
4845 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i,
4846 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4847 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
4848 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4849 } else {
4850 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
4851 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4852 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
4853 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
4854 }
4855 }
4856
4857 ASSERT_PASSED(validate_object_map, image);
4858 }
4859
4860 ioctx.close();
4861}
4862
4863
4864
4865TEST_F(TestLibRBD, TestIOToSnapshot)
4866{
4867 rados_ioctx_t ioctx;
4868 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4869
4870 rbd_image_t image;
4871 int order = 0;
4872 std::string name = get_temp_image_name();
4873 uint64_t isize = 2 << 20;
4874
4875 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
4876 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4877
4878 int i, r;
4879 rbd_image_t image_at_snap;
4880 char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
4881 char test_data[TEST_IO_TO_SNAP_SIZE + 1];
4882
4883 for (i = 0; i < TEST_IO_TO_SNAP_SIZE; ++i)
4884 test_data[i] = (char) (i + 48);
4885 test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
4886 orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
4887
4888 r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
4889 ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE);
4890
4891 ASSERT_EQ(0, test_ls_snaps(image, 0));
4892 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
4893 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
4894 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4895
4896 printf("write test data!\n");
4897 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4898 ASSERT_EQ(0, rbd_snap_create(image, "written"));
4899 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
4900
4901 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4902
4903 rbd_snap_set(image, "orig");
4904 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4905
4906 rbd_snap_set(image, "written");
4907 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4908
4909 rbd_snap_set(image, "orig");
4910
4911 r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
4912 printf("write to snapshot returned %d\n", r);
4913 ASSERT_LT(r, 0);
31f18b77 4914 cout << strerror(-r) << std::endl;
7c673cae
FG
4915
4916 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4917 rbd_snap_set(image, "written");
4918 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4919
4920 r = rbd_snap_rollback(image, "orig");
4921 ASSERT_EQ(r, -EROFS);
4922
4923 r = rbd_snap_set(image, NULL);
4924 ASSERT_EQ(r, 0);
4925 r = rbd_snap_rollback(image, "orig");
4926 ASSERT_EQ(r, 0);
4927
4928 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4929
4930 rbd_flush(image);
4931
4932 printf("opening testimg@orig\n");
4933 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_at_snap, "orig"));
4934 ASSERT_PASSED(read_test_data, image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
4935 r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
4936 printf("write to snapshot returned %d\n", r);
4937 ASSERT_LT(r, 0);
31f18b77 4938 cout << strerror(-r) << std::endl;
7c673cae
FG
4939 ASSERT_EQ(0, rbd_close(image_at_snap));
4940
f67539c2
TL
4941 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
4942 ASSERT_EQ(0, rbd_snap_remove(image, "written"));
4943 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
4944 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
4945 ASSERT_EQ(0, test_ls_snaps(image, 0));
4946
4947 ASSERT_PASSED(validate_object_map, image);
4948 ASSERT_EQ(0, rbd_close(image));
4949
4950 rados_ioctx_destroy(ioctx);
4951}
4952
4953TEST_F(TestLibRBD, TestSnapshotDeletedIo)
4954{
4955 rados_ioctx_t ioctx;
4956 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4957
4958 rbd_image_t image;
4959 int order = 0;
4960 std::string name = get_temp_image_name();
4961 uint64_t isize = 2 << 20;
4962
4963 int r;
4964
4965 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
4966 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4967 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
4968
4969 r = rbd_snap_set(image, "orig");
4970 ASSERT_EQ(r, 0);
4971
7c673cae 4972 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
f67539c2
TL
4973 char test[20];
4974 ASSERT_EQ(-ENOENT, rbd_read(image, 20, 20, test));
7c673cae 4975
f67539c2
TL
4976 r = rbd_snap_set(image, NULL);
4977 ASSERT_EQ(r, 0);
7c673cae 4978
f67539c2 4979 ASSERT_EQ(0, rbd_close(image));
7c673cae
FG
4980 rados_ioctx_destroy(ioctx);
4981}
4982
4983TEST_F(TestLibRBD, TestClone)
4984{
4985 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11fdf7f2
TL
4986 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "1"));
4987 BOOST_SCOPE_EXIT_ALL(&) {
4988 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
4989 };
7c673cae
FG
4990
4991 rados_ioctx_t ioctx;
4992 rbd_image_info_t pinfo, cinfo;
4993 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4994
4995 bool old_format;
4996 uint64_t features;
4997 rbd_image_t parent, child;
4998 int order = 0;
4999
5000 ASSERT_EQ(0, get_features(&old_format, &features));
5001 ASSERT_FALSE(old_format);
5002
5003 std::string parent_name = get_temp_image_name();
5004 std::string child_name = get_temp_image_name();
5005
5006 // make a parent to clone from
5007 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
5008 false, features));
5009 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
5010 printf("made parent image \"parent\"\n");
5011
5012 char *data = (char *)"testdata";
5013 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
5014
5015 // can't clone a non-snapshot, expect failure
5016 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
5017 child_name.c_str(), features, &order));
5018
5019 // verify that there is no parent info on "parent"
5020 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
5021 printf("parent has no parent info\n");
5022
b32b8144
FG
5023 // create 70 metadatas to verify we can clone all key/value pairs
5024 std::string key;
5025 std::string val;
5026 size_t sum_key_len = 0;
5027 size_t sum_value_len = 0;
5028 for (int i = 1; i <= 70; i++) {
5029 key = "key" + stringify(i);
5030 val = "value" + stringify(i);
5031 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
5032
5033 sum_key_len += (key.size() + 1);
5034 sum_value_len += (val.size() + 1);
5035 }
5036
5037 char keys[1024];
5038 char vals[1024];
5039 size_t keys_len = sizeof(keys);
5040 size_t vals_len = sizeof(vals);
5041
5042 char value[1024];
5043 size_t value_len = sizeof(value);
5044
7c673cae
FG
5045 // create a snapshot, reopen as the parent we're interested in
5046 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
5047 printf("made snapshot \"parent@parent_snap\"\n");
5048 ASSERT_EQ(0, rbd_close(parent));
5049 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
5050
5051 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
5052 ioctx, child_name.c_str(), features, &order));
5053
5054 // unprotected image should fail unprotect
5055 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
5056 printf("can't unprotect an unprotected snap\n");
5057
5058 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
5059 // protecting again should fail
5060 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
5061 printf("can't protect a protected snap\n");
5062
5063 // This clone and open should work
5064 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
5065 ioctx, child_name.c_str(), features, &order));
5066 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
5067 printf("made and opened clone \"child\"\n");
5068
5069 // check read
5070 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
5071
5072 // check write
5073 ASSERT_EQ((ssize_t)strlen(data), rbd_write(child, 20, strlen(data), data));
5074 ASSERT_PASSED(read_test_data, child, data, 20, strlen(data), 0);
5075 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
5076
5077 // check attributes
5078 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
5079 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
5080 EXPECT_EQ(cinfo.size, pinfo.size);
5081 uint64_t overlap;
5082 rbd_get_overlap(child, &overlap);
5083 EXPECT_EQ(overlap, pinfo.size);
5084 EXPECT_EQ(cinfo.obj_size, pinfo.obj_size);
5085 EXPECT_EQ(cinfo.order, pinfo.order);
5086 printf("sizes and overlaps are good between parent and child\n");
5087
b32b8144 5088 // check key/value pairs in child image
f67539c2 5089 ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
b32b8144
FG
5090 &vals_len));
5091 ASSERT_EQ(sum_key_len, keys_len);
5092 ASSERT_EQ(sum_value_len, vals_len);
5093
5094 for (int i = 1; i <= 70; i++) {
5095 key = "key" + stringify(i);
5096 val = "value" + stringify(i);
5097 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
5098 ASSERT_STREQ(val.c_str(), value);
5099
5100 value_len = sizeof(value);
5101 }
5102 printf("child image successfully cloned all image-meta pairs\n");
5103
7c673cae
FG
5104 // sizing down child results in changing overlap and size, not parent size
5105 ASSERT_EQ(0, rbd_resize(child, 2UL<<20));
5106 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
5107 rbd_get_overlap(child, &overlap);
5108 ASSERT_EQ(overlap, 2UL<<20);
5109 ASSERT_EQ(cinfo.size, 2UL<<20);
5110 ASSERT_EQ(0, rbd_resize(child, 4UL<<20));
5111 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
5112 rbd_get_overlap(child, &overlap);
5113 ASSERT_EQ(overlap, 2UL<<20);
5114 ASSERT_EQ(cinfo.size, 4UL<<20);
5115 printf("sized down clone, changed overlap\n");
5116
5117 // sizing back up doesn't change that
5118 ASSERT_EQ(0, rbd_resize(child, 5UL<<20));
5119 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
5120 rbd_get_overlap(child, &overlap);
5121 ASSERT_EQ(overlap, 2UL<<20);
5122 ASSERT_EQ(cinfo.size, 5UL<<20);
5123 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
11fdf7f2 5124 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
7c673cae
FG
5125 (unsigned long long)pinfo.size, (unsigned long long)pinfo.obj_size,
5126 (unsigned long long)pinfo.parent_pool);
5127 ASSERT_EQ(pinfo.size, 4UL<<20);
5128 printf("sized up clone, changed size but not overlap or parent's size\n");
5129
5130 ASSERT_PASSED(validate_object_map, child);
5131 ASSERT_EQ(0, rbd_close(child));
5132
5133 ASSERT_PASSED(validate_object_map, parent);
5134 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
5135 printf("can't remove parent while child still exists\n");
5136 ASSERT_EQ(0, rbd_remove(ioctx, child_name.c_str()));
5137 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
5138 printf("can't remove parent while still protected\n");
5139 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
5140 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
5141 printf("removed parent snap after unprotecting\n");
5142
5143 ASSERT_EQ(0, rbd_close(parent));
5144 rados_ioctx_destroy(ioctx);
5145}
5146
5147TEST_F(TestLibRBD, TestClone2)
5148{
5149 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
11fdf7f2
TL
5150 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
5151 BOOST_SCOPE_EXIT_ALL(&) {
5152 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
5153 };
7c673cae
FG
5154
5155 rados_ioctx_t ioctx;
5156 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5157
5158 bool old_format;
5159 uint64_t features;
5160 rbd_image_t parent, child;
5161 int order = 0;
5162
5163 ASSERT_EQ(0, get_features(&old_format, &features));
5164 ASSERT_FALSE(old_format);
5165
5166 std::string parent_name = get_temp_image_name();
5167 std::string child_name = get_temp_image_name();
5168
5169 // make a parent to clone from
5170 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
5171 false, features));
5172 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
5173 printf("made parent image \"parent\"\n");
5174
5175 char *data = (char *)"testdata";
5176 char *childata = (char *)"childata";
5177 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
5178 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
5179
5180 // can't clone a non-snapshot, expect failure
5181 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
5182 child_name.c_str(), features, &order));
5183
5184 // verify that there is no parent info on "parent"
5185 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
5186 printf("parent has no parent info\n");
5187
b32b8144
FG
5188 // create 70 metadatas to verify we can clone all key/value pairs
5189 std::string key;
5190 std::string val;
5191 size_t sum_key_len = 0;
5192 size_t sum_value_len = 0;
5193 for (int i = 1; i <= 70; i++) {
5194 key = "key" + stringify(i);
5195 val = "value" + stringify(i);
5196 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
5197
5198 sum_key_len += (key.size() + 1);
5199 sum_value_len += (val.size() + 1);
5200 }
5201
5202 char keys[1024];
5203 char vals[1024];
5204 size_t keys_len = sizeof(keys);
5205 size_t vals_len = sizeof(vals);
5206
5207 char value[1024];
5208 size_t value_len = sizeof(value);
5209
7c673cae
FG
5210 // create a snapshot, reopen as the parent we're interested in
5211 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
5212 printf("made snapshot \"parent@parent_snap\"\n");
5213 ASSERT_EQ(0, rbd_close(parent));
5214 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
5215
7c673cae
FG
5216 // This clone and open should work
5217 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
5218 ioctx, child_name.c_str(), features, &order));
5219 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
5220 printf("made and opened clone \"child\"\n");
5221
b32b8144 5222 // check key/value pairs in child image
f67539c2 5223 ASSERT_EQ(0, rbd_metadata_list(child, "key", 70, keys, &keys_len, vals,
b32b8144
FG
5224 &vals_len));
5225 ASSERT_EQ(sum_key_len, keys_len);
5226 ASSERT_EQ(sum_value_len, vals_len);
5227
5228 for (int i = 1; i <= 70; i++) {
5229 key = "key" + stringify(i);
5230 val = "value" + stringify(i);
5231 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
5232 ASSERT_STREQ(val.c_str(), value);
5233
5234 value_len = sizeof(value);
5235 }
5236 printf("child image successfully cloned all image-meta pairs\n");
5237
7c673cae
FG
5238 // write something in
5239 ASSERT_EQ((ssize_t)strlen(childata), rbd_write(child, 20, strlen(childata), childata));
5240
5241 char test[strlen(data) * 2];
5242 ASSERT_EQ((ssize_t)strlen(data), rbd_read(child, 20, strlen(data), test));
5243 ASSERT_EQ(0, memcmp(test, childata, strlen(childata)));
5244
5245 // overlap
5246 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 20 - strlen(data), sizeof(test), test));
5247 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
5248 ASSERT_EQ(0, memcmp(test + strlen(data), childata, strlen(childata)));
5249
5250 // all parent
5251 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 0, sizeof(test), test));
5252 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
5253
5254 ASSERT_PASSED(validate_object_map, child);
5255 ASSERT_PASSED(validate_object_map, parent);
5256
11fdf7f2
TL
5257 rbd_snap_info_t snaps[2];
5258 int max_snaps = 2;
5259 ASSERT_EQ(1, rbd_snap_list(parent, snaps, &max_snaps));
5260 rbd_snap_list_end(snaps);
5261
5262 ASSERT_EQ(0, rbd_snap_remove_by_id(parent, snaps[0].id));
5263
5264 rbd_snap_namespace_type_t snap_namespace_type;
5265 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent, snaps[0].id,
5266 &snap_namespace_type));
5267 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH, snap_namespace_type);
5268
5269 char original_name[32];
5270 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent, snaps[0].id,
5271 original_name,
5272 sizeof(original_name)));
5273 ASSERT_EQ(0, strcmp("parent_snap", original_name));
5274
7c673cae
FG
5275 ASSERT_EQ(0, rbd_close(child));
5276 ASSERT_EQ(0, rbd_close(parent));
5277 rados_ioctx_destroy(ioctx);
5278}
5279
5280static void test_list_children(rbd_image_t image, ssize_t num_expected, ...)
5281{
5282 va_list ap;
5283 va_start(ap, num_expected);
5284 size_t pools_len = 100;
5285 size_t children_len = 100;
5286 char *pools = NULL;
5287 char *children = NULL;
5288 ssize_t num_children;
5289
5290 do {
5291 free(pools);
5292 free(children);
5293 pools = (char *) malloc(pools_len);
5294 children = (char *) malloc(children_len);
5295 num_children = rbd_list_children(image, pools, &pools_len,
5296 children, &children_len);
5297 } while (num_children == -ERANGE);
5298
5299 ASSERT_EQ(num_expected, num_children);
5300 for (ssize_t i = num_expected; i > 0; --i) {
5301 char *expected_pool = va_arg(ap, char *);
5302 char *expected_image = va_arg(ap, char *);
5303 char *pool = pools;
5304 char *image = children;
5305 bool found = 0;
5306 printf("\ntrying to find %s/%s\n", expected_pool, expected_image);
5307 for (ssize_t j = 0; j < num_children; ++j) {
5308 printf("checking %s/%s\n", pool, image);
5309 if (strcmp(expected_pool, pool) == 0 &&
5310 strcmp(expected_image, image) == 0) {
5311 printf("found child %s/%s\n\n", pool, image);
5312 found = 1;
5313 break;
5314 }
5315 pool += strlen(pool) + 1;
5316 image += strlen(image) + 1;
5317 if (j == num_children - 1) {
5318 ASSERT_EQ(pool - pools - 1, (ssize_t) pools_len);
5319 ASSERT_EQ(image - children - 1, (ssize_t) children_len);
5320 }
5321 }
5322 ASSERT_TRUE(found);
5323 }
5324 va_end(ap);
5325
5326 if (pools)
5327 free(pools);
5328 if (children)
5329 free(children);
5330}
5331
11fdf7f2 5332static void test_list_children2(rbd_image_t image, int num_expected, ...)
7c673cae 5333{
11fdf7f2
TL
5334 int num_children, i, j, max_size = 10;
5335 va_list ap;
5336 rbd_child_info_t children[max_size];
5337 num_children = rbd_list_children2(image, children, &max_size);
5338 printf("num children is: %d\nexpected: %d\n", num_children, num_expected);
7c673cae 5339
11fdf7f2
TL
5340 for (i = 0; i < num_children; i++) {
5341 printf("child: %s\n", children[i].image_name);
5342 }
7c673cae 5343
11fdf7f2
TL
5344 va_start(ap, num_expected);
5345 for (i = num_expected; i > 0; i--) {
5346 char *expected_id = va_arg(ap, char *);
5347 char *expected_pool = va_arg(ap, char *);
5348 char *expected_image = va_arg(ap, char *);
5349 bool expected_trash = va_arg(ap, int);
5350 bool found = false;
5351 for (j = 0; j < num_children; j++) {
5352 if (children[j].pool_name == NULL ||
5353 children[j].image_name == NULL ||
5354 children[j].image_id == NULL)
5355 continue;
5356 if (strcmp(children[j].image_id, expected_id) == 0 &&
5357 strcmp(children[j].pool_name, expected_pool) == 0 &&
5358 strcmp(children[j].image_name, expected_image) == 0 &&
5359 children[j].trash == expected_trash) {
5360 printf("found child %s/%s/%s\n\n", children[j].pool_name, children[j].image_name, children[j].image_id);
5361 rbd_list_child_cleanup(&children[j]);
5362 children[j].pool_name = NULL;
5363 children[j].image_name = NULL;
5364 children[j].image_id = NULL;
5365 found = true;
5366 break;
5367 }
5368 }
5369 EXPECT_TRUE(found);
5370 }
5371 va_end(ap);
5372
5373 for (i = 0; i < num_children; i++) {
5374 EXPECT_EQ((const char *)0, children[i].pool_name);
5375 EXPECT_EQ((const char *)0, children[i].image_name);
5376 EXPECT_EQ((const char *)0, children[i].image_id);
5377 }
5378}
5379
5380TEST_F(TestLibRBD, ListChildren)
5381{
5382 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5383
5384 librbd::RBD rbd;
5385 rados_ioctx_t ioctx1, ioctx2;
5386 string pool_name1 = create_pool(true);
5387 string pool_name2 = create_pool(true);
5388 ASSERT_NE("", pool_name2);
5389
5390 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
5391 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
5392
5393 rbd_image_t image1;
5394 rbd_image_t image2;
5395 rbd_image_t image3;
5396 rbd_image_t image4;
5397
5398 bool old_format;
5399 uint64_t features;
5400 rbd_image_t parent;
5401 int order = 0;
5402
5403 ASSERT_EQ(0, get_features(&old_format, &features));
5404 ASSERT_FALSE(old_format);
7c673cae
FG
5405
5406 std::string parent_name = get_temp_image_name();
5407 std::string child_name1 = get_temp_image_name();
5408 std::string child_name2 = get_temp_image_name();
5409 std::string child_name3 = get_temp_image_name();
5410 std::string child_name4 = get_temp_image_name();
5411
11fdf7f2
TL
5412 char child_id1[4096];
5413 char child_id2[4096];
5414 char child_id3[4096];
5415 char child_id4[4096];
5416
7c673cae
FG
5417 // make a parent to clone from
5418 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
5419 false, features));
5420 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
5421 // create a snapshot, reopen as the parent we're interested in
5422 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
5423 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
5424 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
5425
5426 ASSERT_EQ(0, rbd_close(parent));
5427 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
5428
5429 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5430 ioctx2, child_name1.c_str(), features, &order));
11fdf7f2
TL
5431 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
5432 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
7c673cae 5433 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
11fdf7f2
TL
5434 test_list_children2(parent, 1,
5435 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
7c673cae
FG
5436
5437 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5438 ioctx1, child_name2.c_str(), features, &order));
11fdf7f2
TL
5439 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
5440 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
7c673cae
FG
5441 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
5442 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
5443 test_list_children2(parent, 2,
5444 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5445 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae
FG
5446
5447 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5448 ioctx2, child_name3.c_str(), features, &order));
11fdf7f2
TL
5449 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
5450 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
7c673cae
FG
5451 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
5452 pool_name1.c_str(), child_name2.c_str(),
5453 pool_name2.c_str(), child_name3.c_str());
11fdf7f2
TL
5454 test_list_children2(parent, 3,
5455 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5456 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5457 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
5458
5459 librados::IoCtx ioctx3;
5460 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
5461 ASSERT_EQ(0, rbd_close(image3));
5462 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
5463 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
5464 pool_name1.c_str(), child_name2.c_str());
5465 test_list_children2(parent, 3,
5466 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5467 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5468 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
7c673cae
FG
5469
5470 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5471 ioctx2, child_name4.c_str(), features, &order));
11fdf7f2
TL
5472 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
5473 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
5474 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
5475 pool_name1.c_str(), child_name2.c_str(),
5476 pool_name2.c_str(), child_name4.c_str());
5477 test_list_children2(parent, 4,
5478 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5479 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5480 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
5481 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
5482
5483 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
7c673cae
FG
5484 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
5485 pool_name1.c_str(), child_name2.c_str(),
5486 pool_name2.c_str(), child_name3.c_str(),
5487 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
5488 test_list_children2(parent, 4,
5489 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5490 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5491 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
5492 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 5493
11fdf7f2 5494 ASSERT_EQ(0, rbd_close(image1));
7c673cae
FG
5495 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
5496 test_list_children(parent, 3,
5497 pool_name1.c_str(), child_name2.c_str(),
5498 pool_name2.c_str(), child_name3.c_str(),
5499 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
5500 test_list_children2(parent, 3,
5501 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5502 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
5503 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae
FG
5504
5505 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
5506 test_list_children(parent, 2,
5507 pool_name1.c_str(), child_name2.c_str(),
5508 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
5509 test_list_children2(parent, 2,
5510 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5511 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 5512
11fdf7f2 5513 ASSERT_EQ(0, rbd_close(image4));
7c673cae
FG
5514 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
5515 test_list_children(parent, 1,
5516 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
5517 test_list_children2(parent, 1,
5518 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
5519
7c673cae 5520
11fdf7f2 5521 ASSERT_EQ(0, rbd_close(image2));
7c673cae
FG
5522 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
5523 test_list_children(parent, 0);
11fdf7f2 5524 test_list_children2(parent, 0);
7c673cae
FG
5525
5526 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
5527 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
5528 ASSERT_EQ(0, rbd_close(parent));
5529 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
5530 rados_ioctx_destroy(ioctx1);
5531 rados_ioctx_destroy(ioctx2);
5532}
5533
5534TEST_F(TestLibRBD, ListChildrenTiered)
5535{
5536 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5537
11fdf7f2 5538 librbd::RBD rbd;
94b18763 5539 string pool_name1 = create_pool(true);
7c673cae
FG
5540 string pool_name2 = create_pool(true);
5541 string pool_name3 = create_pool(true);
94b18763 5542 ASSERT_NE("", pool_name1);
7c673cae
FG
5543 ASSERT_NE("", pool_name2);
5544 ASSERT_NE("", pool_name3);
5545
5546 std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" +
5547 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\", \"force_nonempty\":\"\"}";
5548 char *cmd[1];
5549 cmd[0] = (char *)cmdstr.c_str();
5550 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
5551
5552 cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
5553 pool_name3 + "\", \"mode\":\"writeback\"}";
5554 cmd[0] = (char *)cmdstr.c_str();
5555 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
5556
5557 cmdstr = "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
5558 pool_name1 + "\", \"overlaypool\":\"" + pool_name3 + "\"}";
5559 cmd[0] = (char *)cmdstr.c_str();
5560 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
5561
5562 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
5563
5564 string parent_name = get_temp_image_name();
5565 string child_name1 = get_temp_image_name();
5566 string child_name2 = get_temp_image_name();
5567 string child_name3 = get_temp_image_name();
5568 string child_name4 = get_temp_image_name();
5569
11fdf7f2
TL
5570 char child_id1[4096];
5571 char child_id2[4096];
5572 char child_id3[4096];
5573 char child_id4[4096];
5574
5575 rbd_image_t image1;
5576 rbd_image_t image2;
5577 rbd_image_t image3;
5578 rbd_image_t image4;
5579
7c673cae
FG
5580 rados_ioctx_t ioctx1, ioctx2;
5581 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
5582 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
5583
5584 bool old_format;
5585 uint64_t features;
5586 rbd_image_t parent;
5587 int order = 0;
5588
5589 ASSERT_EQ(0, get_features(&old_format, &features));
5590 ASSERT_FALSE(old_format);
5591
5592 // make a parent to clone from
5593 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
5594 false, features));
5595 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
5596 // create a snapshot, reopen as the parent we're interested in
5597 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
5598 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
5599 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
5600
5601 ASSERT_EQ(0, rbd_close(parent));
5602 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
5603
5604 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5605 ioctx2, child_name1.c_str(), features, &order));
11fdf7f2
TL
5606 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
5607 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
7c673cae 5608 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
11fdf7f2
TL
5609 test_list_children2(parent, 1,
5610 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
7c673cae
FG
5611
5612 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5613 ioctx1, child_name2.c_str(), features, &order));
11fdf7f2
TL
5614 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
5615 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
7c673cae
FG
5616 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
5617 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
5618 test_list_children2(parent, 2,
5619 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5620 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae
FG
5621
5622 // read from the cache to populate it
5623 rbd_image_t tier_image;
5624 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &tier_image, NULL));
5625 size_t len = 4 * 1024 * 1024;
5626 char* buf = (char*)malloc(len);
5627 ssize_t size = rbd_read(tier_image, 0, len, buf);
5628 ASSERT_GT(size, 0);
5629 free(buf);
5630 ASSERT_EQ(0, rbd_close(tier_image));
5631
5632 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5633 ioctx2, child_name3.c_str(), features, &order));
11fdf7f2
TL
5634 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
5635 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
7c673cae
FG
5636 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
5637 pool_name1.c_str(), child_name2.c_str(),
5638 pool_name2.c_str(), child_name3.c_str());
11fdf7f2
TL
5639 test_list_children2(parent, 3,
5640 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5641 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5642 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
5643
5644 librados::IoCtx ioctx3;
5645 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
5646 ASSERT_EQ(0, rbd_close(image3));
5647 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
5648 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
5649 pool_name1.c_str(), child_name2.c_str());
5650 test_list_children2(parent, 3,
5651 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5652 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5653 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
7c673cae
FG
5654
5655 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
5656 ioctx2, child_name4.c_str(), features, &order));
11fdf7f2
TL
5657 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
5658 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
5659 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
5660 pool_name1.c_str(), child_name2.c_str(),
5661 pool_name2.c_str(), child_name4.c_str());
5662 test_list_children2(parent, 4,
5663 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5664 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5665 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
5666 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
5667
5668 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
7c673cae
FG
5669 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
5670 pool_name1.c_str(), child_name2.c_str(),
5671 pool_name2.c_str(), child_name3.c_str(),
5672 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
5673 test_list_children2(parent, 4,
5674 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
5675 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5676 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
5677 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 5678
11fdf7f2 5679 ASSERT_EQ(0, rbd_close(image1));
7c673cae
FG
5680 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
5681 test_list_children(parent, 3,
5682 pool_name1.c_str(), child_name2.c_str(),
5683 pool_name2.c_str(), child_name3.c_str(),
5684 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
5685 test_list_children2(parent, 3,
5686 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5687 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
5688 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae
FG
5689
5690 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
5691 test_list_children(parent, 2,
5692 pool_name1.c_str(), child_name2.c_str(),
5693 pool_name2.c_str(), child_name4.c_str());
11fdf7f2
TL
5694 test_list_children2(parent, 2,
5695 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
5696 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
7c673cae 5697
11fdf7f2 5698 ASSERT_EQ(0, rbd_close(image4));
7c673cae
FG
5699 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
5700 test_list_children(parent, 1,
5701 pool_name1.c_str(), child_name2.c_str());
11fdf7f2
TL
5702 test_list_children2(parent, 1,
5703 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
7c673cae 5704
11fdf7f2 5705 ASSERT_EQ(0, rbd_close(image2));
7c673cae
FG
5706 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
5707 test_list_children(parent, 0);
11fdf7f2 5708 test_list_children2(parent, 0);
7c673cae
FG
5709
5710 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
5711 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
5712 ASSERT_EQ(0, rbd_close(parent));
5713 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
5714 rados_ioctx_destroy(ioctx1);
5715 rados_ioctx_destroy(ioctx2);
5716 cmdstr = "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
5717 pool_name1 + "\"}";
5718 cmd[0] = (char *)cmdstr.c_str();
5719 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
5720 cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
5721 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\"}";
5722 cmd[0] = (char *)cmdstr.c_str();
5723 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
5724}
5725
5726TEST_F(TestLibRBD, LockingPP)
5727{
5728 librados::IoCtx ioctx;
5729 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5730
5731 {
5732 librbd::RBD rbd;
5733 librbd::Image image;
5734 int order = 0;
5735 std::string name = get_temp_image_name();
5736 uint64_t size = 2 << 20;
5737 std::string cookie1 = "foo";
5738 std::string cookie2 = "bar";
5739
5740 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5741 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5742
5743 // no lockers initially
5744 std::list<librbd::locker_t> lockers;
5745 std::string tag;
5746 bool exclusive;
5747 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
5748 ASSERT_EQ(0u, lockers.size());
5749 ASSERT_EQ("", tag);
5750
5751 // exclusive lock is exclusive
5752 ASSERT_EQ(0, image.lock_exclusive(cookie1));
5753 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
5754 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
5755 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
5756 ASSERT_EQ(-EBUSY, image.lock_shared(cookie1, "test"));
5757 ASSERT_EQ(-EBUSY, image.lock_shared("", "test"));
5758 ASSERT_EQ(-EBUSY, image.lock_shared("", ""));
5759
5760 // list exclusive
5761 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
5762 ASSERT_TRUE(exclusive);
5763 ASSERT_EQ("", tag);
5764 ASSERT_EQ(1u, lockers.size());
5765 ASSERT_EQ(cookie1, lockers.front().cookie);
5766
5767 // unlock
5768 ASSERT_EQ(-ENOENT, image.unlock(""));
5769 ASSERT_EQ(-ENOENT, image.unlock(cookie2));
5770 ASSERT_EQ(0, image.unlock(cookie1));
5771 ASSERT_EQ(-ENOENT, image.unlock(cookie1));
5772 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
5773 ASSERT_EQ(0u, lockers.size());
5774
5775 ASSERT_EQ(0, image.lock_shared(cookie1, ""));
5776 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
5777 ASSERT_EQ(0, image.lock_shared(cookie2, ""));
5778 ASSERT_EQ(-EEXIST, image.lock_shared(cookie2, ""));
5779 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
5780 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie2));
5781 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
5782 ASSERT_EQ(-EBUSY, image.lock_exclusive("test"));
5783
5784 // list shared
5785 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
5786 ASSERT_EQ(2u, lockers.size());
5787 }
5788
5789 ioctx.close();
5790}
5791
5792TEST_F(TestLibRBD, FlushAio)
5793{
5794 rados_ioctx_t ioctx;
5795 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5796
5797 rbd_image_t image;
5798 int order = 0;
5799 std::string name = get_temp_image_name();
5800 uint64_t size = 2 << 20;
5801 size_t num_aios = 256;
5802
5803 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5804 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5805
5806 char test_data[TEST_IO_SIZE + 1];
5807 size_t i;
5808 for (i = 0; i < TEST_IO_SIZE; ++i) {
5809 test_data[i] = (char) (rand() % (126 - 33) + 33);
5810 }
5811
5812 rbd_completion_t write_comps[num_aios];
5813 for (i = 0; i < num_aios; ++i) {
5814 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &write_comps[i]));
5815 uint64_t offset = rand() % (size - TEST_IO_SIZE);
5816 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
5817 write_comps[i]));
5818 }
5819
5820 rbd_completion_t flush_comp;
5821 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &flush_comp));
5822 ASSERT_EQ(0, rbd_aio_flush(image, flush_comp));
5823 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp));
5824 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp));
5825 rbd_aio_release(flush_comp);
5826
5827 for (i = 0; i < num_aios; ++i) {
5828 ASSERT_EQ(1, rbd_aio_is_complete(write_comps[i]));
5829 rbd_aio_release(write_comps[i]);
5830 }
5831
5832 ASSERT_PASSED(validate_object_map, image);
5833 ASSERT_EQ(0, rbd_close(image));
5834 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
5835 rados_ioctx_destroy(ioctx);
5836}
5837
5838TEST_F(TestLibRBD, FlushAioPP)
5839{
5840 librados::IoCtx ioctx;
5841 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5842
5843 {
5844 librbd::RBD rbd;
5845 librbd::Image image;
5846 int order = 0;
5847 std::string name = get_temp_image_name();
5848 uint64_t size = 2 << 20;
5849 const size_t num_aios = 256;
5850
5851 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5852 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5853
5854 char test_data[TEST_IO_SIZE + 1];
5855 size_t i;
5856 for (i = 0; i < TEST_IO_SIZE; ++i) {
5857 test_data[i] = (char) (rand() % (126 - 33) + 33);
5858 }
5859 test_data[TEST_IO_SIZE] = '\0';
5860
5861 librbd::RBD::AioCompletion *write_comps[num_aios];
5862 ceph::bufferlist bls[num_aios];
5863 for (i = 0; i < num_aios; ++i) {
5864 bls[i].append(test_data, strlen(test_data));
5865 write_comps[i] = new librbd::RBD::AioCompletion(NULL, NULL);
5866 uint64_t offset = rand() % (size - TEST_IO_SIZE);
5867 ASSERT_EQ(0, image.aio_write(offset, TEST_IO_SIZE, bls[i],
5868 write_comps[i]));
5869 }
5870
5871 librbd::RBD::AioCompletion *flush_comp =
5872 new librbd::RBD::AioCompletion(NULL, NULL);
5873 ASSERT_EQ(0, image.aio_flush(flush_comp));
5874 ASSERT_EQ(0, flush_comp->wait_for_complete());
5875 ASSERT_EQ(1, flush_comp->is_complete());
5876 flush_comp->release();
5877
5878 for (i = 0; i < num_aios; ++i) {
5879 librbd::RBD::AioCompletion *comp = write_comps[i];
5880 ASSERT_EQ(1, comp->is_complete());
5881 comp->release();
5882 }
5883 ASSERT_PASSED(validate_object_map, image);
5884 }
5885
5886 ioctx.close();
5887}
5888
5889
5890int iterate_cb(uint64_t off, size_t len, int exists, void *arg)
5891{
5892 //cout << "iterate_cb " << off << "~" << len << std::endl;
5893 interval_set<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
5894 diff->insert(off, len);
5895 return 0;
5896}
5897
5898static int iterate_error_cb(uint64_t off, size_t len, int exists, void *arg)
5899{
5900 return -EINVAL;
5901}
5902
5903void scribble(librbd::Image& image, int n, int max, bool skip_discard,
5904 interval_set<uint64_t> *exists,
5905 interval_set<uint64_t> *what)
5906{
5907 uint64_t size;
5908 image.size(&size);
5909 interval_set<uint64_t> exists_at_start = *exists;
5910
5911 for (int i=0; i<n; i++) {
5912 uint64_t off = rand() % (size - max + 1);
5913 uint64_t len = 1 + rand() % max;
5914 if (!skip_discard && rand() % 4 == 0) {
5915 ASSERT_EQ((int)len, image.discard(off, len));
5916 interval_set<uint64_t> w;
5917 w.insert(off, len);
5918
5919 // the zeroed bit no longer exists...
5920 w.intersection_of(*exists);
5921 exists->subtract(w);
5922
5923 // the bits we discarded are no long written...
5924 interval_set<uint64_t> w2 = w;
5925 w2.intersection_of(*what);
5926 what->subtract(w2);
5927
5928 // except for the extents that existed at the start that we overwrote.
5929 interval_set<uint64_t> w3;
5930 w3.insert(off, len);
5931 w3.intersection_of(exists_at_start);
5932 what->union_of(w3);
5933
5934 } else {
5935 bufferlist bl;
5936 bl.append(buffer::create(len));
5937 bl.zero();
5938 ASSERT_EQ((int)len, image.write(off, len, bl));
5939 interval_set<uint64_t> w;
5940 w.insert(off, len);
5941 what->union_of(w);
5942 exists->union_of(w);
5943 }
5944 }
5945}
5946
5947interval_set<uint64_t> round_diff_interval(const interval_set<uint64_t>& diff,
5948 uint64_t object_size)
5949{
5950 if (object_size == 0) {
5951 return diff;
5952 }
5953
5954 interval_set<uint64_t> rounded_diff;
5955 for (interval_set<uint64_t>::const_iterator it = diff.begin();
5956 it != diff.end(); ++it) {
5957 uint64_t off = it.get_start();
5958 uint64_t len = it.get_len();
5959 off -= off % object_size;
5960 len += (object_size - (len % object_size));
5961 interval_set<uint64_t> interval;
5962 interval.insert(off, len);
5963 rounded_diff.union_of(interval);
5964 }
5965 return rounded_diff;
5966}
5967
1d09f67e
TL
5968TEST_F(TestLibRBD, SnapDiff)
5969{
5970 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
5971
5972 rados_ioctx_t ioctx;
5973 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5974
5975 rbd_image_t image;
5976 int order = 0;
5977 std::string image_name = get_temp_image_name();
5978 uint64_t size = 100 << 20;
5979 ASSERT_EQ(0, create_image(ioctx, image_name.c_str(), size, &order));
5980 ASSERT_EQ(0, rbd_open(ioctx, image_name.c_str(), &image, nullptr));
5981
5982 char test_data[TEST_IO_SIZE + 1];
5983 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
5984 test_data[i] = (char) (rand() % (126 - 33) + 33);
5985 }
5986 test_data[TEST_IO_SIZE] = '\0';
5987
5988 ASSERT_PASSED(write_test_data, image, test_data, 0,
5989 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
5990
5991 interval_set<uint64_t> diff;
5992 ASSERT_EQ(0, rbd_diff_iterate2(image, nullptr, 0, size, true, true,
5993 iterate_cb, &diff));
5994 EXPECT_EQ(1 << order, diff.size());
5995
5996 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
5997 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
5998
5999 diff.clear();
6000 ASSERT_EQ(0, rbd_diff_iterate2(image, nullptr, 0, size, true, true,
6001 iterate_cb, &diff));
6002 EXPECT_EQ(1 << order, diff.size());
6003
6004 diff.clear();
6005 ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, true,
6006 iterate_cb, &diff));
6007 EXPECT_EQ(0, diff.size());
6008
6009 diff.clear();
6010 ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, true,
6011 iterate_cb, &diff));
6012 EXPECT_EQ(0, diff.size());
6013
6014 ASSERT_EQ(0, rbd_snap_remove(image, "snap1"));
6015 ASSERT_EQ(0, rbd_snap_remove(image, "snap2"));
6016
6017 ASSERT_EQ(0, rbd_close(image));
6018 ASSERT_EQ(0, rbd_remove(ioctx, image_name.c_str()));
6019
6020 rados_ioctx_destroy(ioctx);
6021}
6022
7c673cae
FG
6023template <typename T>
6024class DiffIterateTest : public TestLibRBD {
6025public:
6026 static const uint8_t whole_object = T::whole_object;
6027};
6028
6029template <bool _whole_object>
6030class DiffIterateParams {
6031public:
6032 static const uint8_t whole_object = _whole_object;
6033};
6034
6035typedef ::testing::Types<DiffIterateParams<false>,
6036 DiffIterateParams<true> > DiffIterateTypes;
9f95a23c 6037TYPED_TEST_SUITE(DiffIterateTest, DiffIterateTypes);
7c673cae
FG
6038
6039TYPED_TEST(DiffIterateTest, DiffIterate)
6040{
6041 librados::IoCtx ioctx;
6042 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6043
7c673cae
FG
6044 {
6045 librbd::RBD rbd;
6046 librbd::Image image;
6047 int order = 0;
6048 std::string name = this->get_temp_image_name();
6049 uint64_t size = 20 << 20;
6050
6051 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6052 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6053
f67539c2
TL
6054 bool skip_discard = this->is_skip_partial_discard_enabled(image);
6055
7c673cae
FG
6056 uint64_t object_size = 0;
6057 if (this->whole_object) {
6058 object_size = 1 << order;
6059 }
6060
6061 interval_set<uint64_t> exists;
6062 interval_set<uint64_t> one, two;
6063 scribble(image, 10, 102400, skip_discard, &exists, &one);
6064 cout << " wrote " << one << std::endl;
6065 ASSERT_EQ(0, image.snap_create("one"));
6066 scribble(image, 10, 102400, skip_discard, &exists, &two);
6067
6068 two = round_diff_interval(two, object_size);
6069 cout << " wrote " << two << std::endl;
6070
6071 interval_set<uint64_t> diff;
6072 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
6073 iterate_cb, (void *)&diff));
6074 cout << " diff was " << diff << std::endl;
6075 if (!two.subset_of(diff)) {
6076 interval_set<uint64_t> i;
6077 i.intersection_of(two, diff);
6078 interval_set<uint64_t> l = two;
6079 l.subtract(i);
6080 cout << " ... two - (two*diff) = " << l << std::endl;
6081 }
6082 ASSERT_TRUE(two.subset_of(diff));
6083 }
6084 ioctx.close();
6085}
6086
6087struct diff_extent {
6088 diff_extent(uint64_t _offset, uint64_t _length, bool _exists,
6089 uint64_t object_size) :
6090 offset(_offset), length(_length), exists(_exists)
6091 {
6092 if (object_size != 0) {
6093 offset -= offset % object_size;
6094 length = object_size;
6095 }
6096 }
6097 uint64_t offset;
6098 uint64_t length;
6099 bool exists;
6100 bool operator==(const diff_extent& o) const {
6101 return offset == o.offset && length == o.length && exists == o.exists;
6102 }
6103};
6104
6105ostream& operator<<(ostream & o, const diff_extent& e) {
6106 return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')';
6107}
6108
6109int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg)
6110{
6111 cout << "iterate_cb " << off << "~" << len << std::endl;
6112 vector<diff_extent> *diff = static_cast<vector<diff_extent> *>(arg);
6113 diff->push_back(diff_extent(off, len, exists, 0));
6114 return 0;
6115}
6116
6117TYPED_TEST(DiffIterateTest, DiffIterateDiscard)
6118{
6119 librados::IoCtx ioctx;
6120 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6121
6122 librbd::RBD rbd;
6123 librbd::Image image;
6124 int order = 0;
6125 std::string name = this->get_temp_image_name();
6126 uint64_t size = 20 << 20;
6127
6128 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6129 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6130
6131 uint64_t object_size = 0;
6132 if (this->whole_object) {
6133 object_size = 1 << order;
6134 }
6135 vector<diff_extent> extents;
6136 ceph::bufferlist bl;
6137
6138 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6139 vector_iterate_cb, (void *) &extents));
6140 ASSERT_EQ(0u, extents.size());
6141
6142 char data[256];
6143 memset(data, 1, sizeof(data));
6144 bl.append(data, 256);
6145 ASSERT_EQ(256, image.write(0, 256, bl));
6146 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6147 vector_iterate_cb, (void *) &extents));
6148 ASSERT_EQ(1u, extents.size());
6149 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
6150
6151 int obj_ofs = 256;
6152 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
6153
6154 extents.clear();
6155 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6156 vector_iterate_cb, (void *) &extents));
6157 ASSERT_EQ(0u, extents.size());
6158
6159 ASSERT_EQ(0, image.snap_create("snap1"));
6160 ASSERT_EQ(256, image.write(0, 256, bl));
6161 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6162 vector_iterate_cb, (void *) &extents));
6163 ASSERT_EQ(1u, extents.size());
6164 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
6165 ASSERT_EQ(0, image.snap_create("snap2"));
6166
6167 ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs));
6168
6169 extents.clear();
6170 ASSERT_EQ(0, image.snap_set("snap2"));
6171 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
6172 vector_iterate_cb, (void *) &extents));
6173 ASSERT_EQ(1u, extents.size());
6174 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
6175
6176 ASSERT_EQ(0, image.snap_set(NULL));
6177 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
6178 ASSERT_EQ(0, image.snap_create("snap3"));
6179 ASSERT_EQ(0, image.snap_set("snap3"));
6180
6181 extents.clear();
6182 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
6183 vector_iterate_cb, (void *) &extents));
6184 ASSERT_EQ(1u, extents.size());
6185 ASSERT_EQ(diff_extent(0, 256, false, object_size), extents[0]);
6186 ASSERT_PASSED(this->validate_object_map, image);
6187}
6188
6189TYPED_TEST(DiffIterateTest, DiffIterateStress)
6190{
f67539c2 6191 REQUIRE(!is_rbd_pwl_enabled((CephContext *)this->_rados.cct()));
7c673cae
FG
6192 librados::IoCtx ioctx;
6193 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6194
7c673cae
FG
6195 librbd::RBD rbd;
6196 librbd::Image image;
6197 int order = 0;
6198 std::string name = this->get_temp_image_name();
6199 uint64_t size = 400 << 20;
6200
6201 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6202 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6203
f67539c2
TL
6204 bool skip_discard = this->is_skip_partial_discard_enabled(image);
6205
7c673cae
FG
6206 uint64_t object_size = 0;
6207 if (this->whole_object) {
6208 object_size = 1 << order;
6209 }
6210
6211 interval_set<uint64_t> curexists;
6212 vector<interval_set<uint64_t> > wrote;
6213 vector<interval_set<uint64_t> > exists;
6214 vector<string> snap;
6215 int n = 20;
6216 for (int i=0; i<n; i++) {
6217 interval_set<uint64_t> w;
6218 scribble(image, 10, 8192000, skip_discard, &curexists, &w);
6219 cout << " i=" << i << " exists " << curexists << " wrote " << w << std::endl;
6220 string s = "snap" + stringify(i);
6221 ASSERT_EQ(0, image.snap_create(s.c_str()));
6222 wrote.push_back(w);
6223 exists.push_back(curexists);
6224 snap.push_back(s);
6225 }
6226
6227 for (int h=0; h<n-1; h++) {
6228 for (int i=0; i<n-h-1; i++) {
6229 for (int j=(h==0 ? i+1 : n-1); j<n; j++) {
6230 interval_set<uint64_t> diff, actual, uex;
6231 for (int k=i+1; k<=j; k++)
6232 diff.union_of(wrote[k]);
6233 cout << "from " << i << " to "
6234 << (h != 0 ? string("HEAD") : stringify(j)) << " diff "
6235 << round_diff_interval(diff, object_size) << std::endl;
6236
6237 // limit to extents that exists both at the beginning and at the end
6238 uex.union_of(exists[i], exists[j]);
6239 diff.intersection_of(uex);
6240 diff = round_diff_interval(diff, object_size);
6241 cout << " limited diff " << diff << std::endl;
6242
6243 ASSERT_EQ(0, image.snap_set(h==0 ? snap[j].c_str() : NULL));
6244 ASSERT_EQ(0, image.diff_iterate2(snap[i].c_str(), 0, size, true,
6245 this->whole_object, iterate_cb,
6246 (void *)&actual));
6247 cout << " actual was " << actual << std::endl;
6248 if (!diff.subset_of(actual)) {
6249 interval_set<uint64_t> i;
6250 i.intersection_of(diff, actual);
6251 interval_set<uint64_t> l = diff;
6252 l.subtract(i);
6253 cout << " ... diff - (actual*diff) = " << l << std::endl;
6254 }
6255 ASSERT_TRUE(diff.subset_of(actual));
6256 }
6257 }
6258 ASSERT_EQ(0, image.snap_set(NULL));
6259 ASSERT_EQ(0, image.snap_remove(snap[n-h-1].c_str()));
6260 }
6261
6262 ASSERT_PASSED(this->validate_object_map, image);
6263}
6264
6265TYPED_TEST(DiffIterateTest, DiffIterateRegression6926)
6266{
6267 librados::IoCtx ioctx;
6268 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6269
6270 librbd::RBD rbd;
6271 librbd::Image image;
6272 int order = 0;
6273 std::string name = this->get_temp_image_name();
6274 uint64_t size = 20 << 20;
6275
6276 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6277 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6278
6279 uint64_t object_size = 0;
6280 if (this->whole_object) {
6281 object_size = 1 << order;
6282 }
6283 vector<diff_extent> extents;
6284 ceph::bufferlist bl;
6285
6286 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6287 vector_iterate_cb, (void *) &extents));
6288 ASSERT_EQ(0u, extents.size());
6289
6290 ASSERT_EQ(0, image.snap_create("snap1"));
6291 char data[256];
6292 memset(data, 1, sizeof(data));
6293 bl.append(data, 256);
6294 ASSERT_EQ(256, image.write(0, 256, bl));
6295
6296 extents.clear();
6297 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6298 vector_iterate_cb, (void *) &extents));
6299 ASSERT_EQ(1u, extents.size());
6300 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
6301
6302 ASSERT_EQ(0, image.snap_set("snap1"));
6303 extents.clear();
6304 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6305 vector_iterate_cb, (void *) &extents));
6306 ASSERT_EQ(static_cast<size_t>(0), extents.size());
6307}
6308
20effc67
TL
6309TYPED_TEST(DiffIterateTest, DiffIterateParent)
6310{
6311 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6312
6313 librados::IoCtx ioctx;
6314 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6315
6316 {
6317 librbd::RBD rbd;
6318 librbd::Image image;
6319 int order = 22;
6320 std::string name = this->get_temp_image_name();
6321 ssize_t size = 20 << 20;
6322
6323 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6324 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6325
6326 uint64_t features;
6327 ASSERT_EQ(0, image.features(&features));
6328 uint64_t object_size = 0;
6329 if (this->whole_object) {
6330 object_size = 1 << order;
6331 }
6332
6333 ceph::bufferlist bl;
6334 bl.append(std::string(size, '1'));
6335 ASSERT_EQ(size, image.write(0, size, bl));
6336 ASSERT_EQ(0, image.snap_create("snap"));
6337 ASSERT_EQ(0, image.snap_protect("snap"));
6338
6339 std::string clone_name = this->get_temp_image_name();
6340 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx,
6341 clone_name.c_str(), features, &order));
6342 librbd::Image clone;
6343 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
6344
6345 std::vector<diff_extent> extents;
6346 ASSERT_EQ(0, clone.diff_iterate2(NULL, 0, size, true, this->whole_object,
6347 vector_iterate_cb, &extents));
6348 ASSERT_EQ(5u, extents.size());
6349 ASSERT_EQ(diff_extent(0, 4194304, true, object_size), extents[0]);
6350 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size), extents[1]);
6351 ASSERT_EQ(diff_extent(8388608, 4194304, true, object_size), extents[2]);
6352 ASSERT_EQ(diff_extent(12582912, 4194304, true, object_size), extents[3]);
6353 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size), extents[4]);
6354 extents.clear();
6355
6356 ASSERT_EQ(0, clone.resize(size / 2));
6357 ASSERT_EQ(0, clone.resize(size));
6358 ASSERT_EQ(1, clone.write(size - 1, 1, bl));
6359
6360 ASSERT_EQ(0, clone.diff_iterate2(NULL, 0, size, true, this->whole_object,
6361 vector_iterate_cb, &extents));
6362 ASSERT_EQ(4u, extents.size());
6363 ASSERT_EQ(diff_extent(0, 4194304, true, object_size), extents[0]);
6364 ASSERT_EQ(diff_extent(4194304, 4194304, true, object_size), extents[1]);
6365 ASSERT_EQ(diff_extent(8388608, 2097152, true, object_size), extents[2]);
6366 // hole (parent overlap = 10M) followed by copyup'ed object
6367 ASSERT_EQ(diff_extent(16777216, 4194304, true, object_size), extents[3]);
6368
6369 ASSERT_PASSED(this->validate_object_map, image);
6370 ASSERT_PASSED(this->validate_object_map, clone);
6371 }
6372
6373 ioctx.close();
6374}
6375
7c673cae
FG
6376TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
6377{
6378 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6379
6380 librados::IoCtx ioctx;
6381 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6382
7c673cae
FG
6383 librbd::RBD rbd;
6384 librbd::Image image;
6385 std::string name = this->get_temp_image_name();
6386 uint64_t size = 20 << 20;
6387 int order = 0;
6388
6389 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6390 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6391
f67539c2
TL
6392 bool skip_discard = this->is_skip_partial_discard_enabled(image);
6393
20effc67
TL
6394 uint64_t features;
6395 ASSERT_EQ(0, image.features(&features));
7c673cae
FG
6396 uint64_t object_size = 0;
6397 if (this->whole_object) {
6398 object_size = 1 << order;
6399 }
6400
6401 bufferlist bl;
6402 bl.append(buffer::create(size));
6403 bl.zero();
6404 interval_set<uint64_t> one;
6405 one.insert(0, size);
6406 ASSERT_EQ((int)size, image.write(0, size, bl));
6407 ASSERT_EQ(0, image.snap_create("one"));
6408 ASSERT_EQ(0, image.snap_protect("one"));
6409
6410 std::string clone_name = this->get_temp_image_name();
6411 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
20effc67 6412 features, &order));
7c673cae
FG
6413 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
6414
6415 interval_set<uint64_t> exists;
6416 interval_set<uint64_t> two;
6417 scribble(image, 10, 102400, skip_discard, &exists, &two);
6418 two = round_diff_interval(two, object_size);
6419 cout << " wrote " << two << " to clone" << std::endl;
6420
6421 interval_set<uint64_t> diff;
6422 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, false, this->whole_object,
6423 iterate_cb, (void *)&diff));
6424 cout << " diff was " << diff << std::endl;
6425 if (!this->whole_object) {
6426 ASSERT_FALSE(one.subset_of(diff));
6427 }
6428 ASSERT_TRUE(two.subset_of(diff));
6429}
6430
6431TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
6432{
6433 librados::IoCtx ioctx;
6434 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6435
7c673cae
FG
6436 {
6437 librbd::RBD rbd;
6438 librbd::Image image;
6439 int order = 0;
6440 std::string name = this->get_temp_image_name();
6441 uint64_t size = 20 << 20;
6442
6443 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6444 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6445
f67539c2
TL
6446 bool skip_discard = this->is_skip_partial_discard_enabled(image);
6447
7c673cae
FG
6448 interval_set<uint64_t> exists;
6449 interval_set<uint64_t> one;
6450 scribble(image, 10, 102400, skip_discard, &exists, &one);
6451 cout << " wrote " << one << std::endl;
6452
6453 interval_set<uint64_t> diff;
6454 ASSERT_EQ(-EINVAL, image.diff_iterate2(NULL, 0, size, true,
6455 this->whole_object,
6456 iterate_error_cb, NULL));
6457 }
6458 ioctx.close();
6459}
6460
6461TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
6462{
6463 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6464
6465 librados::IoCtx ioctx;
6466 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6467
7c673cae
FG
6468 librbd::RBD rbd;
6469 librbd::Image image;
6470 std::string name = this->get_temp_image_name();
6471 uint64_t size = 20 << 20;
6472 int order = 0;
6473
6474 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6475 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6476
f67539c2
TL
6477 bool skip_discard = this->is_skip_partial_discard_enabled(image);
6478
20effc67
TL
6479 uint64_t features;
6480 ASSERT_EQ(0, image.features(&features));
7c673cae
FG
6481 uint64_t object_size = 0;
6482 if (this->whole_object) {
6483 object_size = 1 << order;
6484 }
6485
6486 interval_set<uint64_t> exists;
6487 interval_set<uint64_t> one;
6488 scribble(image, 10, 102400, skip_discard, &exists, &one);
6489 ASSERT_EQ(0, image.snap_create("one"));
6490
6491 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
6492 ASSERT_EQ(0, image.snap_create("two"));
6493 ASSERT_EQ(0, image.snap_protect("two"));
6494 exists.clear();
6495 one.clear();
6496
6497 std::string clone_name = this->get_temp_image_name();
6498 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "two", ioctx,
20effc67 6499 clone_name.c_str(), features, &order));
7c673cae
FG
6500 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
6501
6502 interval_set<uint64_t> two;
6503 scribble(image, 10, 102400, skip_discard, &exists, &two);
6504 two = round_diff_interval(two, object_size);
6505
6506 interval_set<uint64_t> diff;
6507 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6508 iterate_cb, (void *)&diff));
6509 ASSERT_TRUE(two.subset_of(diff));
6510}
6511
20effc67
TL
6512TYPED_TEST(DiffIterateTest, DiffIterateUnalignedSmall)
6513{
6514 librados::IoCtx ioctx;
6515 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6516
6517 {
6518 librbd::RBD rbd;
6519 librbd::Image image;
6520 int order = 0;
6521 std::string name = this->get_temp_image_name();
6522 ssize_t size = 10 << 20;
6523
6524 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6525 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6526
6527 ceph::bufferlist bl;
6528 bl.append(std::string(size, '1'));
6529 ASSERT_EQ(size, image.write(0, size, bl));
6530
6531 std::vector<diff_extent> extents;
6532 ASSERT_EQ(0, image.diff_iterate2(NULL, 5000005, 1234, true,
6533 this->whole_object, vector_iterate_cb,
6534 &extents));
6535 ASSERT_EQ(1u, extents.size());
6536 ASSERT_EQ(diff_extent(5000005, 1234, true, 0), extents[0]);
6537
6538 ASSERT_PASSED(this->validate_object_map, image);
6539 }
6540
6541 ioctx.close();
6542}
6543
6544TYPED_TEST(DiffIterateTest, DiffIterateUnaligned)
6545{
6546 librados::IoCtx ioctx;
6547 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6548
6549 {
6550 librbd::RBD rbd;
6551 librbd::Image image;
6552 int order = 22;
6553 std::string name = this->get_temp_image_name();
6554 ssize_t size = 20 << 20;
6555
6556 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6557 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6558
6559 ceph::bufferlist bl;
6560 bl.append(std::string(size, '1'));
6561 ASSERT_EQ(size, image.write(0, size, bl));
6562
6563 std::vector<diff_extent> extents;
6564 ASSERT_EQ(0, image.diff_iterate2(NULL, 8376263, 4260970, true,
6565 this->whole_object, vector_iterate_cb,
6566 &extents));
6567 ASSERT_EQ(3u, extents.size());
6568 ASSERT_EQ(diff_extent(8376263, 12345, true, 0), extents[0]);
6569 ASSERT_EQ(diff_extent(8388608, 4194304, true, 0), extents[1]);
6570 ASSERT_EQ(diff_extent(12582912, 54321, true, 0), extents[2]);
6571
6572 ASSERT_PASSED(this->validate_object_map, image);
6573 }
6574
6575 ioctx.close();
6576}
6577
1d09f67e
TL
6578TYPED_TEST(DiffIterateTest, DiffIterateStriping)
6579{
6580 REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2);
6581
6582 librados::IoCtx ioctx;
6583 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
6584
6585 bool old_format;
6586 uint64_t features;
6587 ASSERT_EQ(0, get_features(&old_format, &features));
6588 ASSERT_FALSE(old_format);
6589
6590 {
6591 librbd::RBD rbd;
6592 librbd::Image image;
6593 int order = 22;
6594 std::string name = this->get_temp_image_name();
6595 ssize_t size = 24 << 20;
6596
6597 ASSERT_EQ(0, rbd.create3(ioctx, name.c_str(), size, features, &order,
6598 1 << 20, 3));
6599 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6600
6601 ceph::bufferlist bl;
6602 bl.append(std::string(size, '1'));
6603 ASSERT_EQ(size, image.write(0, size, bl));
6604
6605 std::vector<diff_extent> extents;
6606 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
6607 vector_iterate_cb, &extents));
6608 ASSERT_EQ(2u, extents.size());
6609 ASSERT_EQ(diff_extent(0, 12 << 20, true, 0), extents[0]);
6610 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents[1]);
6611 extents.clear();
6612
6613 ASSERT_EQ(0, image.snap_create("one"));
6614 ASSERT_EQ(size, image.discard(0, size));
6615
6616 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
6617 vector_iterate_cb, &extents));
6618 ASSERT_EQ(2u, extents.size());
6619 ASSERT_EQ(diff_extent(0, 12 << 20, false, 0), extents[0]);
6620 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, false, 0), extents[1]);
6621 extents.clear();
6622
6623 ASSERT_EQ(1 << 20, image.write(0, 1 << 20, bl));
6624 ASSERT_EQ(2 << 20, image.write(2 << 20, 2 << 20, bl));
6625 ASSERT_EQ(2 << 20, image.write(5 << 20, 2 << 20, bl));
6626 ASSERT_EQ(2 << 20, image.write(8 << 20, 2 << 20, bl));
6627 ASSERT_EQ(13 << 20, image.write(11 << 20, 13 << 20, bl));
6628
6629 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
6630 vector_iterate_cb, &extents));
6631 ASSERT_EQ(10u, extents.size());
6632 ASSERT_EQ(diff_extent(0, 1 << 20, true, 0), extents[0]);
6633 ASSERT_EQ(diff_extent(1 << 20, 1 << 20, false, 0), extents[1]);
6634 ASSERT_EQ(diff_extent(2 << 20, 2 << 20, true, 0), extents[2]);
6635 ASSERT_EQ(diff_extent(4 << 20, 1 << 20, false, 0), extents[3]);
6636 ASSERT_EQ(diff_extent(5 << 20, 2 << 20, true, 0), extents[4]);
6637 ASSERT_EQ(diff_extent(7 << 20, 1 << 20, false, 0), extents[5]);
6638 ASSERT_EQ(diff_extent(8 << 20, 2 << 20, true, 0), extents[6]);
6639 ASSERT_EQ(diff_extent(10 << 20, 1 << 20, false, 0), extents[7]);
6640 ASSERT_EQ(diff_extent(11 << 20, 1 << 20, true, 0), extents[8]);
6641 ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents[9]);
6642
6643 ASSERT_PASSED(this->validate_object_map, image);
6644 }
6645
6646 ioctx.close();
6647}
6648
7c673cae
FG
6649TEST_F(TestLibRBD, ZeroLengthWrite)
6650{
6651 rados_ioctx_t ioctx;
6652 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6653
6654 rbd_image_t image;
6655 int order = 0;
6656 std::string name = get_temp_image_name();
6657 uint64_t size = 2 << 20;
6658
6659 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6660 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6661
6662 char read_data[1];
6663 ASSERT_EQ(0, rbd_write(image, 0, 0, NULL));
6664 ASSERT_EQ(1, rbd_read(image, 0, 1, read_data));
6665 ASSERT_EQ('\0', read_data[0]);
6666
6667 ASSERT_PASSED(validate_object_map, image);
6668 ASSERT_EQ(0, rbd_close(image));
6669
6670 rados_ioctx_destroy(ioctx);
6671}
6672
6673
6674TEST_F(TestLibRBD, ZeroLengthDiscard)
6675{
6676 rados_ioctx_t ioctx;
6677 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6678
6679 rbd_image_t image;
6680 int order = 0;
6681 std::string name = get_temp_image_name();
6682 uint64_t size = 2 << 20;
6683
6684 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6685 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6686
6687 const char data[] = "blah";
6688 char read_data[sizeof(data)];
6689 ASSERT_EQ((int)strlen(data), rbd_write(image, 0, strlen(data), data));
6690 ASSERT_EQ(0, rbd_discard(image, 0, 0));
6691 ASSERT_EQ((int)strlen(data), rbd_read(image, 0, strlen(data), read_data));
6692 ASSERT_EQ(0, memcmp(data, read_data, strlen(data)));
6693
6694 ASSERT_PASSED(validate_object_map, image);
6695 ASSERT_EQ(0, rbd_close(image));
6696
6697 rados_ioctx_destroy(ioctx);
6698}
6699
6700TEST_F(TestLibRBD, ZeroLengthRead)
6701{
6702 rados_ioctx_t ioctx;
6703 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6704
6705 rbd_image_t image;
6706 int order = 0;
6707 std::string name = get_temp_image_name();
6708 uint64_t size = 2 << 20;
6709
6710 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6711 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6712
6713 char read_data[1];
6714 ASSERT_EQ(0, rbd_read(image, 0, 0, read_data));
6715
6716 ASSERT_EQ(0, rbd_close(image));
6717
6718 rados_ioctx_destroy(ioctx);
6719}
6720
6721TEST_F(TestLibRBD, LargeCacheRead)
6722{
6723 std::string config_value;
6724 ASSERT_EQ(0, _rados.conf_get("rbd_cache", config_value));
6725 if (config_value == "false") {
6726 std::cout << "SKIPPING due to disabled cache" << std::endl;
6727 return;
6728 }
6729
6730 rados_ioctx_t ioctx;
6731 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6732
6733 uint32_t new_cache_size = 1 << 20;
6734 std::string orig_cache_size;
6735 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", orig_cache_size));
6736 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size",
6737 stringify(new_cache_size).c_str()));
6738 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", config_value));
6739 ASSERT_EQ(stringify(new_cache_size), config_value);
6740 BOOST_SCOPE_EXIT( (orig_cache_size) ) {
6741 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size", orig_cache_size.c_str()));
6742 } BOOST_SCOPE_EXIT_END;
6743
6744 rbd_image_t image;
6745 int order = 21;
6746 std::string name = get_temp_image_name();
6747 uint64_t size = 1 << order;
6748
6749 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6750 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6751
6752 std::string buffer(1 << order, '1');
6753
6754 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
6755 rbd_write(image, 0, buffer.size(), buffer.c_str()));
6756
6757 ASSERT_EQ(0, rbd_invalidate_cache(image));
6758
6759 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
6760 rbd_read(image, 0, buffer.size(), &buffer[0]));
6761
6762 ASSERT_EQ(0, rbd_close(image));
6763
6764 rados_ioctx_destroy(ioctx);
6765}
6766
6767TEST_F(TestLibRBD, TestPendingAio)
6768{
6769 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6770
6771 rados_ioctx_t ioctx;
6772 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6773
6774 bool old_format;
6775 uint64_t features;
6776 rbd_image_t image;
6777 int order = 0;
6778
6779 ASSERT_EQ(0, get_features(&old_format, &features));
6780 ASSERT_FALSE(old_format);
6781
6782 std::string name = get_temp_image_name();
6783
6784 uint64_t size = 4 << 20;
6785 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
6786 false, features));
6787 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6788
f67539c2
TL
6789 ASSERT_EQ(0, rbd_invalidate_cache(image));
6790
7c673cae
FG
6791 char test_data[TEST_IO_SIZE];
6792 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
6793 test_data[i] = (char) (rand() % (126 - 33) + 33);
6794 }
6795
6796 size_t num_aios = 256;
6797 rbd_completion_t comps[num_aios];
6798 for (size_t i = 0; i < num_aios; ++i) {
6799 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
6800 uint64_t offset = rand() % (size - TEST_IO_SIZE);
6801 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
6802 comps[i]));
6803 }
6804 for (size_t i = 0; i < num_aios; ++i) {
6805 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps[i]));
6806 rbd_aio_release(comps[i]);
6807 }
6808 ASSERT_EQ(0, rbd_invalidate_cache(image));
6809
6810 for (size_t i = 0; i < num_aios; ++i) {
6811 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
6812 uint64_t offset = rand() % (size - TEST_IO_SIZE);
6813 ASSERT_LE(0, rbd_aio_read(image, offset, TEST_IO_SIZE, test_data,
6814 comps[i]));
6815 }
6816
6817 ASSERT_PASSED(validate_object_map, image);
6818 ASSERT_EQ(0, rbd_close(image));
6819 for (size_t i = 0; i < num_aios; ++i) {
6820 ASSERT_EQ(1, rbd_aio_is_complete(comps[i]));
6821 rbd_aio_release(comps[i]);
6822 }
6823
6824 rados_ioctx_destroy(ioctx);
6825}
6826
11fdf7f2
TL
6827void compare_and_write_copyup(librados::IoCtx &ioctx, bool deep_copyup,
6828 bool *passed)
6829{
6830 librbd::RBD rbd;
6831 std::string parent_name = TestLibRBD::get_temp_image_name();
6832 uint64_t size = 2 << 20;
6833 int order = 0;
6834 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
6835
6836 librbd::Image parent_image;
6837 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
6838
6839 bufferlist bl;
6840 bl.append(std::string(4096, '1'));
6841 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
6842
6843 ASSERT_EQ(0, parent_image.snap_create("snap1"));
6844 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
6845
6846 uint64_t features;
6847 ASSERT_EQ(0, parent_image.features(&features));
6848
6849 std::string clone_name = TestLibRBD::get_temp_image_name();
6850 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
6851 clone_name.c_str(), features, &order));
6852
6853 librbd::Image clone_image;
6854 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
6855 if (deep_copyup) {
6856 ASSERT_EQ(0, clone_image.snap_create("snap1"));
6857 }
6858
6859 bufferlist cmp_bl;
39ae355f 6860 cmp_bl.append(std::string(512, '1'));
11fdf7f2
TL
6861 bufferlist write_bl;
6862 write_bl.append(std::string(512, '2'));
39ae355f 6863 uint64_t mismatch_off = 0;
11fdf7f2
TL
6864 ASSERT_EQ((ssize_t)write_bl.length(),
6865 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
6866 write_bl, &mismatch_off, 0));
39ae355f 6867 ASSERT_EQ(0U, mismatch_off);
11fdf7f2
TL
6868 bufferlist read_bl;
6869 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
6870
6871 bufferlist expected_bl;
6872 expected_bl.append(std::string(512, '1'));
6873 expected_bl.append(std::string(512, '2'));
6874 expected_bl.append(std::string(3072, '1'));
6875 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
6876 *passed = true;
6877}
6878
6879TEST_F(TestLibRBD, CompareAndWriteCopyup)
6880{
6881 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6882
6883 librados::IoCtx ioctx;
6884 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6885
6886 ASSERT_PASSED(compare_and_write_copyup, ioctx, false);
6887 ASSERT_PASSED(compare_and_write_copyup, ioctx, true);
6888}
6889
6890void compare_and_write_copyup_mismatch(librados::IoCtx &ioctx,
6891 bool deep_copyup, bool *passed)
6892{
6893 librbd::RBD rbd;
6894 std::string parent_name = TestLibRBD::get_temp_image_name();
6895 uint64_t size = 2 << 20;
6896 int order = 0;
6897 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
6898
6899 librbd::Image parent_image;
6900 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
6901
6902 bufferlist bl;
6903 bl.append(std::string(4096, '1'));
6904 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
6905
6906 ASSERT_EQ(0, parent_image.snap_create("snap1"));
6907 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
6908
6909 uint64_t features;
6910 ASSERT_EQ(0, parent_image.features(&features));
6911
6912 std::string clone_name = TestLibRBD::get_temp_image_name();
6913 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
6914 clone_name.c_str(), features, &order));
6915
6916 librbd::Image clone_image;
6917 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
6918 if (deep_copyup) {
6919 ASSERT_EQ(0, clone_image.snap_create("snap1"));
6920 }
6921
6922 bufferlist cmp_bl;
6923 cmp_bl.append(std::string(48, '1'));
39ae355f 6924 cmp_bl.append(std::string(464, '3'));
11fdf7f2
TL
6925 bufferlist write_bl;
6926 write_bl.append(std::string(512, '2'));
39ae355f 6927 uint64_t mismatch_off = 0;
11fdf7f2
TL
6928 ASSERT_EQ(-EILSEQ,
6929 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
6930 write_bl, &mismatch_off, 0));
6931 ASSERT_EQ(48U, mismatch_off);
6932
6933 bufferlist read_bl;
6934 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
6935
6936 ASSERT_TRUE(bl.contents_equal(read_bl));
6937 *passed = true;
6938}
6939
6940TEST_F(TestLibRBD, CompareAndWriteCopyupMismatch)
6941{
6942 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6943
6944 librados::IoCtx ioctx;
6945 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6946
6947 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, false);
6948 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, true);
6949}
6950
7c673cae
FG
6951TEST_F(TestLibRBD, Flatten)
6952{
6953 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6954
6955 librados::IoCtx ioctx;
6956 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6957
6958 librbd::RBD rbd;
6959 std::string parent_name = get_temp_image_name();
6960 uint64_t size = 2 << 20;
6961 int order = 0;
6962 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
6963
6964 librbd::Image parent_image;
6965 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
6966
6967 bufferlist bl;
6968 bl.append(std::string(4096, '1'));
6969 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
6970
6971 ASSERT_EQ(0, parent_image.snap_create("snap1"));
6972 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
6973
6974 uint64_t features;
6975 ASSERT_EQ(0, parent_image.features(&features));
6976
6977 std::string clone_name = get_temp_image_name();
6978 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
6979 clone_name.c_str(), features, &order));
6980
6981 librbd::Image clone_image;
6982 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
6983 ASSERT_EQ(0, clone_image.flatten());
6984
6985 librbd::RBD::AioCompletion *read_comp =
6986 new librbd::RBD::AioCompletion(NULL, NULL);
6987 bufferlist read_bl;
6988 clone_image.aio_read(0, bl.length(), read_bl, read_comp);
6989 ASSERT_EQ(0, read_comp->wait_for_complete());
6990 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
6991 read_comp->release();
6992 ASSERT_TRUE(bl.contents_equal(read_bl));
6993
6994 ASSERT_PASSED(validate_object_map, clone_image);
6995}
6996
11fdf7f2
TL
6997TEST_F(TestLibRBD, Sparsify)
6998{
6999 rados_ioctx_t ioctx;
7000 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
7001 BOOST_SCOPE_EXIT_ALL(&ioctx) {
7002 rados_ioctx_destroy(ioctx);
7003 };
7004
7005 const size_t CHUNK_SIZE = 4096 * 2;
7006 rbd_image_t image;
7007 int order = 0;
7008 std::string name = get_temp_image_name();
7009 uint64_t size = CHUNK_SIZE * 1024;
7010
7011 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7012 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7013 BOOST_SCOPE_EXIT_ALL(&image) {
7014 rbd_close(image);
7015 };
7016
7017 char test_data[4 * CHUNK_SIZE + 1];
7018 for (size_t i = 0; i < 4 ; ++i) {
7019 for (size_t j = 0; j < CHUNK_SIZE; j++) {
7020 if (i % 2) {
7021 test_data[i * CHUNK_SIZE + j] = (char)(rand() % (126 - 33) + 33);
7022 } else {
7023 test_data[i * CHUNK_SIZE + j] = '\0';
7024 }
7025 }
7026 }
7027 test_data[4 * CHUNK_SIZE] = '\0';
7028
7029 ASSERT_PASSED(write_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
7030 ASSERT_EQ(0, rbd_flush(image));
7031
7032 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 16));
7033 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 1 << (order + 1)));
7034 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 4096 + 1));
7035 ASSERT_EQ(0, rbd_sparsify(image, 4096));
7036
7037 ASSERT_PASSED(read_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
7038}
7039
7040TEST_F(TestLibRBD, SparsifyPP)
7041{
7042 librados::IoCtx ioctx;
7043 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7044
7045 librbd::RBD rbd;
7046 std::string name = get_temp_image_name();
7047 uint64_t size = 12 * 1024 * 1024;
7048 int order = 0;
7049 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7050
7051 librbd::Image image;
7052 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7053
7054 bufferlist bl;
7055 bl.append(std::string(4096, '\0'));
7056 bl.append(std::string(4096, '1'));
7057 bl.append(std::string(4096, '\0'));
7058 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
7059 ASSERT_EQ(0, image.flush());
7060
7061 ASSERT_EQ(-EINVAL, image.sparsify(16));
7062 ASSERT_EQ(-EINVAL, image.sparsify(1 << (order + 1)));
7063 ASSERT_EQ(-EINVAL, image.sparsify(4096 + 1));
7064 ASSERT_EQ(0, image.sparsify(4096));
7065
7066 bufferlist read_bl;
7067 ASSERT_EQ((ssize_t)bl.length(), image.read(0, bl.length(), read_bl));
7068 ASSERT_TRUE(bl.contents_equal(read_bl));
7069
7070 ASSERT_PASSED(validate_object_map, image);
7071}
7072
7c673cae
FG
7073TEST_F(TestLibRBD, SnapshotLimit)
7074{
7075 rados_ioctx_t ioctx;
7076 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7077
7078 rbd_image_t image;
7079 int order = 0;
7080 std::string name = get_temp_image_name();
7081 uint64_t size = 2 << 20;
7082 uint64_t limit;
7083
7084 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7085 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7086
7087 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
7088 ASSERT_EQ(UINT64_MAX, limit);
7089 ASSERT_EQ(0, rbd_snap_set_limit(image, 2));
7090 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
7091 ASSERT_EQ(2U, limit);
7092
7093 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
11fdf7f2 7094 ASSERT_EQ(-ERANGE, rbd_snap_set_limit(image, 0));
7c673cae
FG
7095 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
7096 ASSERT_EQ(-EDQUOT, rbd_snap_create(image, "snap3"));
7097 ASSERT_EQ(0, rbd_snap_set_limit(image, UINT64_MAX));
7098 ASSERT_EQ(0, rbd_snap_create(image, "snap3"));
7099 ASSERT_EQ(0, rbd_close(image));
7100
7101 rados_ioctx_destroy(ioctx);
7102}
7103
7104
7105TEST_F(TestLibRBD, SnapshotLimitPP)
7106{
7107 librados::IoCtx ioctx;
7108 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7109
7110 {
7111 librbd::RBD rbd;
7112 librbd::Image image;
7113 std::string name = get_temp_image_name();
7114 uint64_t size = 2 << 20;
7115 int order = 0;
7116 uint64_t limit;
7117
7118 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7119 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7120
7121 ASSERT_EQ(0, image.snap_get_limit(&limit));
7122 ASSERT_EQ(UINT64_MAX, limit);
7123 ASSERT_EQ(0, image.snap_set_limit(2));
7124 ASSERT_EQ(0, image.snap_get_limit(&limit));
7125 ASSERT_EQ(2U, limit);
7126
7127 ASSERT_EQ(0, image.snap_create("snap1"));
11fdf7f2 7128 ASSERT_EQ(-ERANGE, image.snap_set_limit(0));
7c673cae
FG
7129 ASSERT_EQ(0, image.snap_create("snap2"));
7130 ASSERT_EQ(-EDQUOT, image.snap_create("snap3"));
7131 ASSERT_EQ(0, image.snap_set_limit(UINT64_MAX));
7132 ASSERT_EQ(0, image.snap_create("snap3"));
7133 }
7134
7135 ioctx.close();
7136}
7137
7138TEST_F(TestLibRBD, RebuildObjectMapViaLockOwner)
7139{
7140 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
7141
7142 librados::IoCtx ioctx;
7143 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7144
7145 librbd::RBD rbd;
7146 std::string name = get_temp_image_name();
7147 uint64_t size = 2 << 20;
7148 int order = 0;
7149 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7150
7151 std::string object_map_oid;
7152 {
7153 librbd::Image image;
7154 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7155
7156 std::string image_id;
7157 ASSERT_EQ(0, get_image_id(image, &image_id));
7158 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
7159 }
7160
7161 // corrupt the object map
7162 bufferlist bl;
7163 bl.append("foo");
7164 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
7165
7166 librbd::Image image1;
7167 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7168
7169 bool lock_owner;
7170 bl.clear();
7171 ASSERT_EQ(0, image1.write(0, 0, bl));
7172 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7173 ASSERT_TRUE(lock_owner);
7174
7175 uint64_t flags;
7176 ASSERT_EQ(0, image1.get_flags(&flags));
7177 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
7178
7179 librbd::Image image2;
7180 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7181 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7182 ASSERT_FALSE(lock_owner);
7183
7184 PrintProgress prog_ctx;
7185 ASSERT_EQ(0, image2.rebuild_object_map(prog_ctx));
7186 ASSERT_PASSED(validate_object_map, image1);
7187 ASSERT_PASSED(validate_object_map, image2);
7188}
7189
7190TEST_F(TestLibRBD, RenameViaLockOwner)
7191{
cd265ab1 7192 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7c673cae
FG
7193
7194 librados::IoCtx ioctx;
7195 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7196
7197 librbd::RBD rbd;
7198 std::string name = get_temp_image_name();
7199 uint64_t size = 2 << 20;
7200 int order = 0;
7201 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7202
7203 librbd::Image image1;
7204 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7205
cd265ab1
TL
7206 bool lock_owner;
7207 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7208 ASSERT_FALSE(lock_owner);
7209
7210 std::string new_name = get_temp_image_name();
7211 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
7212 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7213 ASSERT_FALSE(lock_owner);
7214
7c673cae
FG
7215 bufferlist bl;
7216 ASSERT_EQ(0, image1.write(0, 0, bl));
7c673cae
FG
7217 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7218 ASSERT_TRUE(lock_owner);
7219
cd265ab1
TL
7220 name = new_name;
7221 new_name = get_temp_image_name();
7c673cae
FG
7222 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
7223 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7224 ASSERT_TRUE(lock_owner);
7225
7226 librbd::Image image2;
7227 ASSERT_EQ(0, rbd.open(ioctx, image2, new_name.c_str(), NULL));
7228}
7229
7230TEST_F(TestLibRBD, SnapCreateViaLockOwner)
7231{
94b18763 7232 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7c673cae
FG
7233
7234 librados::IoCtx ioctx;
7235 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7236
7237 librbd::RBD rbd;
7238 std::string name = get_temp_image_name();
7239 uint64_t size = 2 << 20;
7240 int order = 0;
7241 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7242
7243 librbd::Image image1;
7244 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7245
7246 // switch to writeback cache
7247 ASSERT_EQ(0, image1.flush());
7248
7249 bufferlist bl;
7250 bl.append(std::string(4096, '1'));
7251 ASSERT_EQ((ssize_t)bl.length(), image1.write(0, bl.length(), bl));
7252
7253 bool lock_owner;
7254 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7255 ASSERT_TRUE(lock_owner);
7256
7257 librbd::Image image2;
7258 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7259
7260 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7261 ASSERT_FALSE(lock_owner);
7262
7263 ASSERT_EQ(0, image2.snap_create("snap1"));
7264 bool exists;
7265 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
7266 ASSERT_TRUE(exists);
7267 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
7268 ASSERT_TRUE(exists);
7269
7270 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7271 ASSERT_TRUE(lock_owner);
7272}
7273
7274TEST_F(TestLibRBD, SnapRemoveViaLockOwner)
7275{
94b18763 7276 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
7c673cae
FG
7277
7278 librados::IoCtx ioctx;
7279 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7280
7281 librbd::RBD rbd;
7282 std::string name = get_temp_image_name();
7283 uint64_t size = 2 << 20;
7284 int order = 0;
7285 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7286
7287 librbd::Image image1;
7288 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7289
7290 bufferlist bl;
7291 ASSERT_EQ(0, image1.write(0, 0, bl));
7292 ASSERT_EQ(0, image1.snap_create("snap1"));
7293
7294 bool lock_owner;
7295 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7296 ASSERT_TRUE(lock_owner);
7297
7298 librbd::Image image2;
7299 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7300
7301 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7302 ASSERT_FALSE(lock_owner);
7303
7304 ASSERT_EQ(0, image2.snap_remove("snap1"));
7305 bool exists;
7306 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
7307 ASSERT_FALSE(exists);
7308 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
7309 ASSERT_FALSE(exists);
7310
7311 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7312 ASSERT_TRUE(lock_owner);
7313}
7314
20effc67
TL
7315TEST_F(TestLibRBD, UpdateFeaturesViaLockOwner) {
7316
7317 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7318
7319 librados::IoCtx ioctx;
7320 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7321
7322 std::string name = get_temp_image_name();
7323 uint64_t size = 2 << 20;
7324 librbd::RBD rbd;
7325 int order = 0;
7326 //creates full with rbd default features
7327 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7328
7329 bool lock_owner;
7330 librbd::Image image1;
7331 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7332 bufferlist bl;
7333 ASSERT_EQ(0, image1.write(0, 0, bl));
7334 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7335 ASSERT_TRUE(lock_owner);
7336
7337 librbd::Image image2;
7338 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7339 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7340 ASSERT_FALSE(lock_owner);
7341
7342 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_OBJECT_MAP, false));
7343 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7344 ASSERT_FALSE(lock_owner);
7345
7346 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_OBJECT_MAP, true));
7347 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7348 ASSERT_FALSE(lock_owner);
7349
7350}
7351
91327a77
AA
7352TEST_F(TestLibRBD, EnableJournalingViaLockOwner)
7353{
7354 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
7355
7356 librados::IoCtx ioctx;
7357 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7358
7359 librbd::RBD rbd;
7360 std::string name = get_temp_image_name();
7361 uint64_t size = 2 << 20;
7362 int order = 0;
7363 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7364
7365 librbd::Image image1;
7366 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7367
7368 bufferlist bl;
7369 ASSERT_EQ(0, image1.write(0, 0, bl));
7370
7371 bool lock_owner;
7372 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7373 ASSERT_TRUE(lock_owner);
7374
7375 librbd::Image image2;
7376 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7377
7378 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, false));
7379
7380 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7381 ASSERT_TRUE(lock_owner);
7382 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7383 ASSERT_FALSE(lock_owner);
7384
7385 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, true));
7386
7387 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7388 ASSERT_FALSE(lock_owner);
7389 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7390 ASSERT_TRUE(lock_owner);
7391}
7392
7c673cae
FG
7393TEST_F(TestLibRBD, SnapRemove2)
7394{
7395 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7396
7397 librados::IoCtx ioctx;
7398 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7399
7400 librbd::RBD rbd;
7401 std::string name = get_temp_image_name();
7402 uint64_t size = 2 << 20;
7403 int order = 0;
7404 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7405
7406 librbd::Image image1;
7407 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7408
7409 bufferlist bl;
7410 ASSERT_EQ(0, image1.write(0, 0, bl));
7411 ASSERT_EQ(0, image1.snap_create("snap1"));
7412 bool exists;
7413 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
7414 ASSERT_TRUE(exists);
7415 ASSERT_EQ(0, image1.snap_protect("snap1"));
7416 bool is_protected;
7417 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
7418 ASSERT_TRUE(is_protected);
7419
7420 uint64_t features;
7421 ASSERT_EQ(0, image1.features(&features));
7422
7423 std::string child_name = get_temp_image_name();
7424 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
7425 child_name.c_str(), features, &order));
7426
7427 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
7428 ASSERT_TRUE(exists);
7429 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
7430 ASSERT_TRUE(is_protected);
7431
7432 ASSERT_EQ(-EBUSY, image1.snap_remove("snap1"));
7433 PrintProgress pp;
7434 ASSERT_EQ(0, image1.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE, pp));
7435 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
7436 ASSERT_FALSE(exists);
7437}
7438
7439TEST_F(TestLibRBD, SnapRenameViaLockOwner)
7440{
7441 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
7442
7443 librados::IoCtx ioctx;
7444 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7445
7446 librbd::RBD rbd;
7447 std::string name = get_temp_image_name();
7448 uint64_t size = 2 << 20;
7449 int order = 0;
7450 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7451
7452 librbd::Image image1;
7453 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7454
7455 bufferlist bl;
7456 ASSERT_EQ(0, image1.write(0, 0, bl));
7457 ASSERT_EQ(0, image1.snap_create("snap1"));
7458
7459 bool lock_owner;
7460 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7461 ASSERT_TRUE(lock_owner);
7462
7463 librbd::Image image2;
7464 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7465
7466 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7467 ASSERT_FALSE(lock_owner);
7468
7469 ASSERT_EQ(0, image2.snap_rename("snap1", "snap1-rename"));
7470 bool exists;
7471 ASSERT_EQ(0, image1.snap_exists2("snap1-rename", &exists));
7472 ASSERT_TRUE(exists);
7473 ASSERT_EQ(0, image2.snap_exists2("snap1-rename", &exists));
7474 ASSERT_TRUE(exists);
7475
7476 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7477 ASSERT_TRUE(lock_owner);
7478}
7479
7480TEST_F(TestLibRBD, SnapProtectViaLockOwner)
7481{
7482 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
7483
7484 librados::IoCtx ioctx;
7485 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7486
7487 librbd::RBD rbd;
7488 std::string name = get_temp_image_name();
7489 uint64_t size = 2 << 20;
7490 int order = 0;
7491 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7492
7493 librbd::Image image1;
7494 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7495
7496 bufferlist bl;
7497 ASSERT_EQ(0, image1.write(0, 0, bl));
7498
7499 bool lock_owner;
7500 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7501 ASSERT_TRUE(lock_owner);
7502 ASSERT_EQ(0, image1.snap_create("snap1"));
7503
7504 librbd::Image image2;
7505 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7506
7507 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7508 ASSERT_FALSE(lock_owner);
7509
7510 ASSERT_EQ(0, image2.snap_protect("snap1"));
7511 bool is_protected;
7512 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
7513 ASSERT_TRUE(is_protected);
7514 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
7515 ASSERT_TRUE(is_protected);
7516
7517 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7518 ASSERT_TRUE(lock_owner);
7519}
7520
7521TEST_F(TestLibRBD, SnapUnprotectViaLockOwner)
7522{
7523 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
7524
7525 librados::IoCtx ioctx;
7526 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7527
7528 librbd::RBD rbd;
7529 std::string name = get_temp_image_name();
7530 uint64_t size = 2 << 20;
7531 int order = 0;
7532 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7533
7534 librbd::Image image1;
7535 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7536
7537 bufferlist bl;
7538 ASSERT_EQ(0, image1.write(0, 0, bl));
7539
7540 bool lock_owner;
7541 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7542 ASSERT_TRUE(lock_owner);
7543 ASSERT_EQ(0, image1.snap_create("snap1"));
7544 ASSERT_EQ(0, image1.snap_protect("snap1"));
7545 bool is_protected;
7546 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
7547 ASSERT_TRUE(is_protected);
7548
7549 librbd::Image image2;
7550 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7551
7552 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7553 ASSERT_FALSE(lock_owner);
7554
7555 ASSERT_EQ(0, image2.snap_unprotect("snap1"));
7556 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
7557 ASSERT_FALSE(is_protected);
7558 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
7559 ASSERT_FALSE(is_protected);
7560
7561 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7562 ASSERT_TRUE(lock_owner);
7563}
7564
7565TEST_F(TestLibRBD, FlattenViaLockOwner)
7566{
7567 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7568
7569 librados::IoCtx ioctx;
7570 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7571
7572 librbd::RBD rbd;
7573 std::string parent_name = get_temp_image_name();
7574 uint64_t size = 2 << 20;
7575 int order = 0;
7576 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
7577
7578 librbd::Image parent_image;
7579 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
7580 ASSERT_EQ(0, parent_image.snap_create("snap1"));
7581 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
7582
7583 uint64_t features;
7584 ASSERT_EQ(0, parent_image.features(&features));
7585
7586 std::string name = get_temp_image_name();
7587 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
7588 name.c_str(), features, &order));
7589
7590 librbd::Image image1;
7591 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7592
7593 bufferlist bl;
7594 ASSERT_EQ(0, image1.write(0, 0, bl));
7595
7596 bool lock_owner;
7597 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7598 ASSERT_TRUE(lock_owner);
7599
7600 librbd::Image image2;
7601 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7602
7603 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7604 ASSERT_FALSE(lock_owner);
7605
7606 ASSERT_EQ(0, image2.flatten());
7607
7608 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7609 ASSERT_TRUE(lock_owner);
7610 ASSERT_PASSED(validate_object_map, image1);
7611}
7612
7613TEST_F(TestLibRBD, ResizeViaLockOwner)
7614{
7615 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7616
7617 librados::IoCtx ioctx;
7618 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7619
7620 librbd::RBD rbd;
7621 std::string name = get_temp_image_name();
7622 uint64_t size = 2 << 20;
7623 int order = 0;
7624 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7625
7626 librbd::Image image1;
7627 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7628
7629 bufferlist bl;
7630 ASSERT_EQ(0, image1.write(0, 0, bl));
7631
7632 bool lock_owner;
7633 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7634 ASSERT_TRUE(lock_owner);
7635
7636 librbd::Image image2;
7637 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7638
7639 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7640 ASSERT_FALSE(lock_owner);
7641
7642 ASSERT_EQ(0, image2.resize(0));
7643
7644 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7645 ASSERT_TRUE(lock_owner);
7646 ASSERT_PASSED(validate_object_map, image1);
7647}
7648
11fdf7f2
TL
7649TEST_F(TestLibRBD, SparsifyViaLockOwner)
7650{
7651 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
7652
7653 librados::IoCtx ioctx;
7654 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7655
7656 librbd::RBD rbd;
7657 std::string name = get_temp_image_name();
7658 uint64_t size = 2 << 20;
7659 int order = 0;
7660 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7661
7662 librbd::Image image1;
7663 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7664
7665 bufferlist bl;
7666 ASSERT_EQ(0, image1.write(0, 0, bl));
7667
7668 bool lock_owner;
7669 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7670 ASSERT_TRUE(lock_owner);
7671
7672 librbd::Image image2;
7673 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
7674
7675 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
7676 ASSERT_FALSE(lock_owner);
7677
7678 ASSERT_EQ(0, image2.sparsify(4096));
7679
7680 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
7681 ASSERT_TRUE(lock_owner);
7682 ASSERT_PASSED(validate_object_map, image1);
7683}
7684
7c673cae
FG
7685TEST_F(TestLibRBD, ObjectMapConsistentSnap)
7686{
7687 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
7688
7689 librados::IoCtx ioctx;
7690 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7691
7692 librbd::RBD rbd;
7693 std::string name = get_temp_image_name();
7694 uint64_t size = 1 << 20;
7695 int order = 12;
7696 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7697
7698 librbd::Image image1;
7699 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7700
7c673cae
FG
7701 int num_snaps = 10;
7702 for (int i = 0; i < num_snaps; ++i) {
7703 std::string snap_name = "snap" + stringify(i);
7704 ASSERT_EQ(0, image1.snap_create(snap_name.c_str()));
7705 }
7706
31f18b77
FG
7707
7708 thread writer([&image1](){
7709 librbd::image_info_t info;
7710 int r = image1.stat(info, sizeof(info));
11fdf7f2 7711 ceph_assert(r == 0);
31f18b77
FG
7712 bufferlist bl;
7713 bl.append("foo");
7714 for (unsigned i = 0; i < info.num_objs; ++i) {
7715 r = image1.write((1 << info.order) * i, bl.length(), bl);
11fdf7f2 7716 ceph_assert(r == (int) bl.length());
31f18b77
FG
7717 }
7718 });
7c673cae
FG
7719 writer.join();
7720
7721 for (int i = 0; i < num_snaps; ++i) {
7722 std::string snap_name = "snap" + stringify(i);
7723 ASSERT_EQ(0, image1.snap_set(snap_name.c_str()));
7724 ASSERT_PASSED(validate_object_map, image1);
7725 }
7726
7727 ASSERT_EQ(0, image1.snap_set(NULL));
7728 ASSERT_PASSED(validate_object_map, image1);
7729}
7730
7731void memset_rand(char *buf, size_t len) {
7732 for (size_t i = 0; i < len; ++i) {
7733 buf[i] = (char) (rand() % (126 - 33) + 33);
7734 }
7735}
7736
7737TEST_F(TestLibRBD, Metadata)
7738{
7739 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7740
7741 rados_ioctx_t ioctx;
7742 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7743
7744 std::string name = get_temp_image_name();
7745 uint64_t size = 2 << 20;
7746 int order = 0;
7747 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7748
7749 rbd_image_t image;
7750 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7751
7752 rbd_image_t image1;
7753 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
7754
7755 char keys[1024];
7756 char vals[1024];
7757 size_t keys_len = sizeof(keys);
7758 size_t vals_len = sizeof(vals);
7759
7760 memset_rand(keys, keys_len);
7761 memset_rand(vals, vals_len);
7762
f67539c2 7763 ASSERT_EQ(0, rbd_metadata_list(image, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7764 &vals_len));
7765 ASSERT_EQ(0U, keys_len);
7766 ASSERT_EQ(0U, vals_len);
7767
7768 char value[1024];
7769 size_t value_len = sizeof(value);
7770 memset_rand(value, value_len);
7771
7772 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
7773 ASSERT_EQ(0, rbd_metadata_set(image1, "key2", "value2"));
7774 ASSERT_EQ(0, rbd_metadata_get(image1, "key1", value, &value_len));
7775 ASSERT_STREQ(value, "value1");
7776 value_len = 1;
7777 ASSERT_EQ(-ERANGE, rbd_metadata_get(image1, "key1", value, &value_len));
7778 ASSERT_EQ(value_len, strlen("value1") + 1);
7779
f67539c2 7780 ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7781 &vals_len));
7782 keys_len = sizeof(keys);
7783 vals_len = sizeof(vals);
7784 memset_rand(keys, keys_len);
7785 memset_rand(vals, vals_len);
f67539c2 7786 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7787 &vals_len));
7788 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
7789 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
7790 ASSERT_STREQ(keys, "key1");
7791 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
7792 ASSERT_STREQ(vals, "value1");
7793 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
7794
7795 ASSERT_EQ(0, rbd_metadata_remove(image1, "key1"));
d2e6a577 7796 ASSERT_EQ(-ENOENT, rbd_metadata_remove(image1, "key3"));
7c673cae
FG
7797 value_len = sizeof(value);
7798 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key3", value, &value_len));
f67539c2 7799 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7800 &vals_len));
7801 ASSERT_EQ(keys_len, strlen("key2") + 1);
7802 ASSERT_EQ(vals_len, strlen("value2") + 1);
7803 ASSERT_STREQ(keys, "key2");
7804 ASSERT_STREQ(vals, "value2");
7805
7806 // test config setting
7807 ASSERT_EQ(0, rbd_metadata_set(image1, "conf_rbd_cache", "false"));
7808 ASSERT_EQ(-EINVAL, rbd_metadata_set(image1, "conf_rbd_cache", "INVALID_VAL"));
7809 ASSERT_EQ(0, rbd_metadata_remove(image1, "conf_rbd_cache"));
7810
7811 // test metadata with snapshot adding
7812 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
7813 ASSERT_EQ(0, rbd_snap_protect(image1, "snap1"));
7814 ASSERT_EQ(0, rbd_snap_set(image1, "snap1"));
7815
f67539c2
TL
7816 ASSERT_EQ(-EROFS, rbd_metadata_set(image1, "key1", "value1"));
7817 ASSERT_EQ(-EROFS, rbd_metadata_remove(image1, "key2"));
7c673cae
FG
7818
7819 keys_len = sizeof(keys);
7820 vals_len = sizeof(vals);
7821 memset_rand(keys, keys_len);
7822 memset_rand(vals, vals_len);
f67539c2 7823 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae 7824 &vals_len));
f67539c2
TL
7825 ASSERT_EQ(keys_len, strlen("key2") + 1);
7826 ASSERT_EQ(vals_len, strlen("value2") + 1);
7827 ASSERT_STREQ(keys, "key2");
7828 ASSERT_STREQ(vals, "value2");
7c673cae
FG
7829
7830 ASSERT_EQ(0, rbd_snap_set(image1, NULL));
f67539c2
TL
7831 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
7832 ASSERT_EQ(0, rbd_metadata_set(image1, "key3", "value3"));
7c673cae
FG
7833 keys_len = sizeof(keys);
7834 vals_len = sizeof(vals);
7835 memset_rand(keys, keys_len);
7836 memset_rand(vals, vals_len);
f67539c2 7837 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7838 &vals_len));
7839 ASSERT_EQ(keys_len,
7840 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
7841 ASSERT_EQ(vals_len,
7842 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
7843 ASSERT_STREQ(keys, "key1");
7844 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
7845 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
7846 ASSERT_STREQ(vals, "value1");
7847 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
7848 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
7849
7850 // test metadata with cloning
7851 uint64_t features;
7852 ASSERT_EQ(0, rbd_get_features(image1, &features));
7853
7854 string cname = get_temp_image_name();
7855 EXPECT_EQ(0, rbd_clone(ioctx, name.c_str(), "snap1", ioctx,
7856 cname.c_str(), features, &order));
7857 rbd_image_t image2;
7858 ASSERT_EQ(0, rbd_open(ioctx, cname.c_str(), &image2, NULL));
7859 ASSERT_EQ(0, rbd_metadata_set(image2, "key4", "value4"));
7860
7861 keys_len = sizeof(keys);
7862 vals_len = sizeof(vals);
7863 memset_rand(keys, keys_len);
7864 memset_rand(vals, vals_len);
f67539c2 7865 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7866 &vals_len));
7867 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
7868 1 + strlen("key4") + 1);
7869 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
7870 strlen("value3") + 1 + strlen("value4") + 1);
7871 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
7872 1, "key4");
7873 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1 +
7874 strlen("value3") + 1, "value4");
7875
f67539c2 7876 ASSERT_EQ(0, rbd_metadata_list(image1, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7877 &vals_len));
7878 ASSERT_EQ(keys_len,
7879 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
7880 ASSERT_EQ(vals_len,
7881 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
7882 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key4", value, &value_len));
7883
7884 // test short buffer cases
7885 keys_len = strlen("key1") + 1;
7886 vals_len = strlen("value1") + 1;
7887 memset_rand(keys, keys_len);
7888 memset_rand(vals, vals_len);
f67539c2 7889 ASSERT_EQ(0, rbd_metadata_list(image2, "key", 1, keys, &keys_len, vals,
7c673cae
FG
7890 &vals_len));
7891 ASSERT_EQ(keys_len, strlen("key1") + 1);
7892 ASSERT_EQ(vals_len, strlen("value1") + 1);
7893 ASSERT_STREQ(keys, "key1");
7894 ASSERT_STREQ(vals, "value1");
7895
f67539c2 7896 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 2, keys, &keys_len, vals,
7c673cae
FG
7897 &vals_len));
7898 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
7899 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
7900
f67539c2 7901 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "key", 0, keys, &keys_len, vals,
7c673cae
FG
7902 &vals_len));
7903 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
7904 1 + strlen("key4") + 1);
7905 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
7906 strlen("value3") + 1 + strlen("value4") + 1);
7907
7908 // test `start` param
7909 keys_len = sizeof(keys);
7910 vals_len = sizeof(vals);
7911 memset_rand(keys, keys_len);
7912 memset_rand(vals, vals_len);
7913 ASSERT_EQ(0, rbd_metadata_list(image2, "key2", 0, keys, &keys_len, vals,
7914 &vals_len));
7915 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
7916 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
7917 ASSERT_STREQ(keys, "key3");
7918 ASSERT_STREQ(vals, "value3");
7919
7920 ASSERT_EQ(0, rbd_close(image));
7921 ASSERT_EQ(0, rbd_close(image1));
7922 ASSERT_EQ(0, rbd_close(image2));
31f18b77 7923 rados_ioctx_destroy(ioctx);
7c673cae
FG
7924}
7925
7926TEST_F(TestLibRBD, MetadataPP)
7927{
7928 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7929
7930 librados::IoCtx ioctx;
7931 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7932
7933 librbd::RBD rbd;
7934 string name = get_temp_image_name();
7935 uint64_t size = 2 << 20;
7936 int order = 0;
7937 uint64_t features;
7938 string value;
7939 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7940
7941 librbd::Image image1;
7942 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
7943 map<string, bufferlist> pairs;
f67539c2 7944 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
7945 ASSERT_TRUE(pairs.empty());
7946
7947 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
7948 ASSERT_EQ(0, image1.metadata_set("key2", "value2"));
7949 ASSERT_EQ(0, image1.metadata_get("key1", &value));
7950 ASSERT_EQ(0, strcmp("value1", value.c_str()));
f67539c2 7951 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
7952 ASSERT_EQ(2U, pairs.size());
7953 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
7954 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7955
7956 pairs.clear();
7957 ASSERT_EQ(0, image1.metadata_remove("key1"));
d2e6a577 7958 ASSERT_EQ(-ENOENT, image1.metadata_remove("key3"));
7c673cae 7959 ASSERT_TRUE(image1.metadata_get("key3", &value) < 0);
f67539c2 7960 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
7961 ASSERT_EQ(1U, pairs.size());
7962 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7963
7964 // test config setting
7965 ASSERT_EQ(0, image1.metadata_set("conf_rbd_cache", "false"));
7966 ASSERT_EQ(-EINVAL, image1.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
7967 ASSERT_EQ(0, image1.metadata_remove("conf_rbd_cache"));
7968
7969 // test metadata with snapshot adding
7970 ASSERT_EQ(0, image1.snap_create("snap1"));
7971 ASSERT_EQ(0, image1.snap_protect("snap1"));
7972 ASSERT_EQ(0, image1.snap_set("snap1"));
7973
7974 pairs.clear();
f67539c2
TL
7975 ASSERT_EQ(-EROFS, image1.metadata_set("key1", "value1"));
7976 ASSERT_EQ(-EROFS, image1.metadata_remove("key2"));
7977 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7978 ASSERT_EQ(1U, pairs.size());
7c673cae 7979 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7c673cae
FG
7980
7981 ASSERT_EQ(0, image1.snap_set(NULL));
f67539c2
TL
7982 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
7983 ASSERT_EQ(0, image1.metadata_set("key3", "value3"));
7984 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
7985 ASSERT_EQ(3U, pairs.size());
7986 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
7987 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7988 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
7989
7990 // test metadata with cloning
7991 string cname = get_temp_image_name();
7992 librbd::Image image2;
7993 ASSERT_EQ(0, image1.features(&features));
7994 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
7995 cname.c_str(), features, &order));
7996 ASSERT_EQ(0, rbd.open(ioctx, image2, cname.c_str(), NULL));
7997 ASSERT_EQ(0, image2.metadata_set("key4", "value4"));
7998 pairs.clear();
f67539c2 7999 ASSERT_EQ(0, image2.metadata_list("key", 0, &pairs));
7c673cae
FG
8000 ASSERT_EQ(4U, pairs.size());
8001 pairs.clear();
f67539c2 8002 ASSERT_EQ(0, image1.metadata_list("key", 0, &pairs));
7c673cae
FG
8003 ASSERT_EQ(3U, pairs.size());
8004 ASSERT_EQ(-ENOENT, image1.metadata_get("key4", &value));
8005}
8006
8007TEST_F(TestLibRBD, UpdateFeatures)
8008{
8009 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8010
8011 librados::IoCtx ioctx;
8012 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8013
8014 librbd::RBD rbd;
8015 std::string name = get_temp_image_name();
8016 uint64_t size = 1 << 20;
8017 int order = 0;
8018 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8019
8020 librbd::Image image;
8021 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8022
8023 uint8_t old_format;
8024 ASSERT_EQ(0, image.old_format(&old_format));
8025 if (old_format) {
8026 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
8027 return;
8028 }
8029
8030 uint64_t features;
8031 ASSERT_EQ(0, image.features(&features));
8032
8033 // must provide a single feature
8034 ASSERT_EQ(-EINVAL, image.update_features(0, true));
8035
8036 uint64_t disable_features;
8037 disable_features = features & (RBD_FEATURE_EXCLUSIVE_LOCK |
8038 RBD_FEATURE_OBJECT_MAP |
8039 RBD_FEATURE_FAST_DIFF |
8040 RBD_FEATURE_JOURNALING);
8041 if (disable_features != 0) {
8042 ASSERT_EQ(0, image.update_features(disable_features, false));
8043 }
8044
8045 ASSERT_EQ(0, image.features(&features));
8046 ASSERT_EQ(0U, features & disable_features);
8047
8048 // cannot enable object map nor journaling w/o exclusive lock
8049 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
8050 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_JOURNALING, true));
8051 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
8052
8053 ASSERT_EQ(0, image.features(&features));
8054 ASSERT_NE(0U, features & RBD_FEATURE_EXCLUSIVE_LOCK);
8055
11fdf7f2
TL
8056 // can enable fast diff w/o object map
8057 ASSERT_EQ(0, image.update_features(RBD_FEATURE_FAST_DIFF, true));
8058 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
7c673cae
FG
8059 ASSERT_EQ(0, image.features(&features));
8060 ASSERT_NE(0U, features & RBD_FEATURE_OBJECT_MAP);
8061
11fdf7f2
TL
8062 uint64_t expected_flags = RBD_FLAG_OBJECT_MAP_INVALID |
8063 RBD_FLAG_FAST_DIFF_INVALID;
7c673cae
FG
8064 uint64_t flags;
8065 ASSERT_EQ(0, image.get_flags(&flags));
8066 ASSERT_EQ(expected_flags, flags);
8067
8068 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
8069 ASSERT_EQ(0, image.features(&features));
8070 ASSERT_EQ(0U, features & RBD_FEATURE_OBJECT_MAP);
8071
11fdf7f2
TL
8072 // can disable object map w/ fast diff
8073 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
8074 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
8075 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_FAST_DIFF, false));
7c673cae
FG
8076 ASSERT_EQ(0, image.features(&features));
8077 ASSERT_EQ(0U, features & RBD_FEATURE_FAST_DIFF);
8078
7c673cae 8079 ASSERT_EQ(0, image.get_flags(&flags));
11fdf7f2 8080 ASSERT_EQ(0U, flags);
7c673cae
FG
8081
8082 // cannot disable exclusive lock w/ object map
11fdf7f2 8083 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
7c673cae
FG
8084 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
8085 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
8086
8087 // cannot disable exclusive lock w/ journaling
11fdf7f2 8088 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, true));
7c673cae
FG
8089 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
8090 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, false));
8091
8092 ASSERT_EQ(0, image.get_flags(&flags));
8093 ASSERT_EQ(0U, flags);
8094
8095 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
8096
8097 ASSERT_EQ(0, image.features(&features));
8098 if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0) {
8099 ASSERT_EQ(0, image.update_features(RBD_FEATURE_DEEP_FLATTEN, false));
8100 }
8101 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_DEEP_FLATTEN, true));
8102}
8103
9f95a23c
TL
8104TEST_F(TestLibRBD, FeaturesBitmaskString)
8105{
8106 librbd::RBD rbd;
8107 uint64_t features = RBD_FEATURES_DEFAULT;
8108
8109 std::string features_str;
8110 std::string expected_str = "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
8111 rbd.features_to_string(features, &features_str);
8112 ASSERT_EQ(expected_str, features_str);
8113
8114 features = RBD_FEATURE_LAYERING;
8115 features_str = "";
8116 expected_str = "layering";
8117 rbd.features_to_string(features, &features_str);
8118 ASSERT_EQ(expected_str, features_str);
8119
8120 uint64_t features_bitmask;
8121 features_str = "deep-flatten,exclusive-lock,fast-diff,layering,object-map";
8122 rbd.features_from_string(features_str, &features_bitmask);
8123 ASSERT_EQ(features_bitmask, RBD_FEATURES_DEFAULT);
8124
8125 features_str = "layering";
8126 features_bitmask = 0;
8127 rbd.features_from_string(features_str, &features_bitmask);
8128 ASSERT_EQ(features_bitmask, RBD_FEATURE_LAYERING);
8129}
8130
7c673cae
FG
8131TEST_F(TestLibRBD, RebuildObjectMap)
8132{
8133 librados::IoCtx ioctx;
8134 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8135
8136 librbd::RBD rbd;
8137 std::string name = get_temp_image_name();
8138 uint64_t size = 1 << 20;
8139 int order = 18;
8140 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8141
8142 PrintProgress prog_ctx;
8143 std::string object_map_oid;
8144 bufferlist bl;
8145 bl.append("foo");
8146 {
8147 librbd::Image image;
8148 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8149
8150 uint64_t features;
8151 ASSERT_EQ(0, image.features(&features));
8152 if ((features & RBD_FEATURE_OBJECT_MAP) == 0) {
8153 ASSERT_EQ(-EINVAL, image.rebuild_object_map(prog_ctx));
8154 return;
8155 }
8156
8157 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
8158
8159 ASSERT_EQ(0, image.snap_create("snap1"));
8160 ASSERT_EQ((ssize_t)bl.length(), image.write(1<<order, bl.length(), bl));
8161
8162 std::string image_id;
8163 ASSERT_EQ(0, get_image_id(image, &image_id));
8164 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
8165 }
8166
8167 // corrupt the object map
8168 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
8169
8170 librbd::Image image1;
8171 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8172
8173 bool lock_owner;
8174 bl.clear();
8175 ASSERT_EQ(0, image1.write(0, 0, bl));
8176 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8177 ASSERT_TRUE(lock_owner);
8178
8179 uint64_t flags;
8180 ASSERT_EQ(0, image1.get_flags(&flags));
8181 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
8182
8183 ASSERT_EQ(0, image1.rebuild_object_map(prog_ctx));
8184
8185 librbd::Image image2;
8186 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8187
8188 bufferlist read_bl;
8189 ASSERT_EQ((ssize_t)bl.length(), image2.read(0, bl.length(), read_bl));
8190 ASSERT_TRUE(bl.contents_equal(read_bl));
8191
8192 read_bl.clear();
8193 ASSERT_EQ((ssize_t)bl.length(), image2.read(1<<order, bl.length(), read_bl));
8194 ASSERT_TRUE(bl.contents_equal(read_bl));
8195
8196 ASSERT_PASSED(validate_object_map, image1);
8197 ASSERT_PASSED(validate_object_map, image2);
8198}
8199
8200TEST_F(TestLibRBD, RebuildNewObjectMap)
8201{
8202 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
8203
8204 rados_ioctx_t ioctx;
8205 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8206
8207 std::string name = get_temp_image_name();
8208 uint64_t size = 1 << 20;
8209 int order = 18;
8210 uint64_t features = RBD_FEATURE_EXCLUSIVE_LOCK;
8211 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
8212 false, features));
8213
8214 rbd_image_t image;
8215 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8216 ASSERT_EQ(0, rbd_update_features(image, RBD_FEATURE_OBJECT_MAP, true));
8217 ASSERT_EQ(0, rbd_rebuild_object_map(image, print_progress_percent, NULL));
8218
8219 ASSERT_PASSED(validate_object_map, image);
8220
8221 ASSERT_EQ(0, rbd_close(image));
8222 rados_ioctx_destroy(ioctx);
8223}
8224
8225TEST_F(TestLibRBD, CheckObjectMap)
8226{
8227 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
8228
8229 librados::IoCtx ioctx;
8230 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8231
8232 librbd::RBD rbd;
8233 std::string name = get_temp_image_name();
8234 uint64_t size = 1 << 20;
8235 int order = 18;
8236 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8237
8238 PrintProgress prog_ctx;
8239 bufferlist bl1;
8240 bufferlist bl2;
8241 bl1.append("foo");
8242 {
8243 librbd::Image image;
8244 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8245
8246 uint64_t features;
8247 ASSERT_EQ(0, image.features(&features));
8248
8249 ASSERT_EQ((ssize_t)bl1.length(), image.write(0, bl1.length(), bl1));
8250
8251 ASSERT_EQ(0, image.snap_create("snap1"));
8252 ASSERT_EQ((ssize_t)bl1.length(), image.write(1<<order, bl1.length(), bl1));
8253 }
8254
8255 librbd::Image image1;
8256 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8257
8258 std::string image_id;
8259 ASSERT_EQ(0, get_image_id(image1, &image_id));
8260
8261 std::string object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
8262
8263 ASSERT_LT(0, ioctx.read(object_map_oid, bl2, 1024, 0));
8264
8265 bool lock_owner;
8266 ASSERT_EQ((ssize_t)bl1.length(), image1.write(3 * (1 << 18), bl1.length(), bl1));
8267 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8268 ASSERT_TRUE(lock_owner);
8269
8270 //reopen image to reread now corrupt object map from disk
8271 image1.close();
8272
8273 bl1.clear();
8274 ASSERT_LT(0, ioctx.read(object_map_oid, bl1, 1024, 0));
8275 ASSERT_FALSE(bl1.contents_equal(bl2));
8276
8277 ASSERT_EQ(0, ioctx.write_full(object_map_oid, bl2));
8278 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8279
8280 uint64_t flags;
8281 ASSERT_EQ(0, image1.get_flags(&flags));
8282 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
8283
8284 ASSERT_EQ(0, image1.check_object_map(prog_ctx));
8285
8286 ASSERT_EQ(0, image1.get_flags(&flags));
8287 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
8288}
8289
8290TEST_F(TestLibRBD, BlockingAIO)
8291{
8292 librados::IoCtx ioctx;
8293 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8294
7c673cae
FG
8295 librbd::RBD rbd;
8296 std::string name = get_temp_image_name();
8297 uint64_t size = 1 << 20;
8298 int order = 18;
8299 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8300
8301 std::string non_blocking_aio;
8302 ASSERT_EQ(0, _rados.conf_get("rbd_non_blocking_aio", non_blocking_aio));
8303 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio", "0"));
8304 BOOST_SCOPE_EXIT( (non_blocking_aio) ) {
8305 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio",
8306 non_blocking_aio.c_str()));
8307 } BOOST_SCOPE_EXIT_END;
8308
8309 librbd::Image image;
8310 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8311
f67539c2
TL
8312 bool skip_discard = this->is_skip_partial_discard_enabled(image);
8313
7c673cae
FG
8314 bufferlist bl;
8315 ASSERT_EQ(0, image.write(0, bl.length(), bl));
8316
8317 bl.append(std::string(256, '1'));
8318 librbd::RBD::AioCompletion *write_comp =
8319 new librbd::RBD::AioCompletion(NULL, NULL);
8320 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
8321
8322 librbd::RBD::AioCompletion *flush_comp =
8323 new librbd::RBD::AioCompletion(NULL, NULL);
8324 ASSERT_EQ(0, image.aio_flush(flush_comp));
8325 ASSERT_EQ(0, flush_comp->wait_for_complete());
8326 ASSERT_EQ(0, flush_comp->get_return_value());
8327 flush_comp->release();
8328
8329 ASSERT_EQ(1, write_comp->is_complete());
8330 ASSERT_EQ(0, write_comp->get_return_value());
8331 write_comp->release();
8332
8333 librbd::RBD::AioCompletion *discard_comp =
8334 new librbd::RBD::AioCompletion(NULL, NULL);
8335 ASSERT_EQ(0, image.aio_discard(128, 128, discard_comp));
8336 ASSERT_EQ(0, discard_comp->wait_for_complete());
8337 discard_comp->release();
8338
8339 librbd::RBD::AioCompletion *read_comp =
8340 new librbd::RBD::AioCompletion(NULL, NULL);
8341 bufferlist read_bl;
8342 image.aio_read(0, bl.length(), read_bl, read_comp);
8343 ASSERT_EQ(0, read_comp->wait_for_complete());
8344 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
8345 read_comp->release();
8346
8347 bufferlist expected_bl;
8348 expected_bl.append(std::string(128, '1'));
8349 expected_bl.append(std::string(128, skip_discard ? '1' : '\0'));
8350 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
8351}
8352
8353TEST_F(TestLibRBD, ExclusiveLockTransition)
8354{
8355 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
8356
8357 librados::IoCtx ioctx;
8358 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8359
8360 librbd::RBD rbd;
8361 std::string name = get_temp_image_name();
8362
8363 uint64_t size = 1 << 18;
8364 int order = 12;
8365 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8366
8367 librbd::Image image1;
8368 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8369
8370 librbd::Image image2;
8371 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8372
8373 std::list<librbd::RBD::AioCompletion *> comps;
8374 ceph::bufferlist bl;
8375 bl.append(std::string(1 << order, '1'));
8376 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
8377 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
8378 NULL);
8379 comps.push_back(comp);
8380 if (object_no % 2 == 0) {
8381 ASSERT_EQ(0, image1.aio_write(object_no << order, bl.length(), bl, comp));
8382 } else {
8383 ASSERT_EQ(0, image2.aio_write(object_no << order, bl.length(), bl, comp));
8384 }
8385 }
8386
8387 while (!comps.empty()) {
8388 librbd::RBD::AioCompletion *comp = comps.front();
8389 comps.pop_front();
8390 ASSERT_EQ(0, comp->wait_for_complete());
8391 ASSERT_EQ(1, comp->is_complete());
8392 comp->release();
8393 }
8394
8395 librbd::Image image3;
8396 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
8397 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
8398 bufferlist read_bl;
8399 ASSERT_EQ((ssize_t)bl.length(), image3.read(object_no << order, bl.length(),
8400 read_bl));
8401 ASSERT_TRUE(bl.contents_equal(read_bl));
8402 }
8403
8404 ASSERT_PASSED(validate_object_map, image1);
8405 ASSERT_PASSED(validate_object_map, image2);
8406 ASSERT_PASSED(validate_object_map, image3);
8407}
8408
8409TEST_F(TestLibRBD, ExclusiveLockReadTransition)
8410{
8411 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
8412
8413 librados::IoCtx ioctx;
8414 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8415
8416 librbd::RBD rbd;
8417 std::string name = get_temp_image_name();
8418
8419 uint64_t size = 1 << 18;
8420 int order = 12;
8421 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8422
8423 librbd::Image image1;
8424 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8425
8426 bool lock_owner;
8427 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8428 ASSERT_FALSE(lock_owner);
8429
8430 // journaling should force read ops to acquire the lock
8431 bufferlist read_bl;
8432 ASSERT_EQ(0, image1.read(0, 0, read_bl));
8433
8434 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
8435 ASSERT_TRUE(lock_owner);
8436
8437 librbd::Image image2;
8438 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8439
8440 std::list<librbd::RBD::AioCompletion *> comps;
8441 std::list<bufferlist> read_bls;
8442 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
8443 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
8444 NULL);
8445 comps.push_back(comp);
8446 read_bls.emplace_back();
8447 if (object_no % 2 == 0) {
8448 ASSERT_EQ(0, image1.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
8449 } else {
8450 ASSERT_EQ(0, image2.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
8451 }
8452 }
8453
8454 while (!comps.empty()) {
8455 librbd::RBD::AioCompletion *comp = comps.front();
8456 comps.pop_front();
8457 ASSERT_EQ(0, comp->wait_for_complete());
8458 ASSERT_EQ(1, comp->is_complete());
8459 comp->release();
8460 }
8461}
8462
8463TEST_F(TestLibRBD, CacheMayCopyOnWrite) {
8464 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8465
8466 librados::IoCtx ioctx;
8467 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8468
8469 librbd::RBD rbd;
8470 std::string name = get_temp_image_name();
8471
8472 uint64_t size = 1 << 18;
8473 int order = 12;
8474 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8475
8476 librbd::Image image;
8477 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8478 ASSERT_EQ(0, image.snap_create("one"));
8479 ASSERT_EQ(0, image.snap_protect("one"));
8480
8481 std::string clone_name = this->get_temp_image_name();
8482 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
8483 RBD_FEATURE_LAYERING, &order));
8484
8485 librbd::Image clone;
8486 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
8487 ASSERT_EQ(0, clone.flush());
8488
8489 bufferlist expect_bl;
8490 expect_bl.append(std::string(1024, '\0'));
8491
8492 // test double read path
8493 bufferlist read_bl;
8494 uint64_t offset = 0;
8495 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
8496 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
8497
8498 bufferlist write_bl;
8499 write_bl.append(std::string(1024, '1'));
8500 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
8501
8502 read_bl.clear();
8503 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
8504 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
8505
8506 // test read retry path
8507 offset = 1 << order;
8508 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
8509
8510 read_bl.clear();
8511 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
8512 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
8513}
8514
8515TEST_F(TestLibRBD, FlushEmptyOpsOnExternalSnapshot) {
8516 std::string cache_enabled;
8517 ASSERT_EQ(0, _rados.conf_get("rbd_cache", cache_enabled));
8518 ASSERT_EQ(0, _rados.conf_set("rbd_cache", "false"));
8519 BOOST_SCOPE_EXIT( (cache_enabled) ) {
8520 ASSERT_EQ(0, _rados.conf_set("rbd_cache", cache_enabled.c_str()));
8521 } BOOST_SCOPE_EXIT_END;
8522
8523 librados::IoCtx ioctx;
8524 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8525
8526 librbd::RBD rbd;
8527 std::string name = get_temp_image_name();
8528 uint64_t size = 1 << 18;
8529 int order = 0;
8530 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8531
8532 librbd::Image image1;
8533 librbd::Image image2;
8534 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
8535 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
8536 ASSERT_EQ(0, image1.snap_create("snap1"));
8537
8538 librbd::RBD::AioCompletion *read_comp =
8539 new librbd::RBD::AioCompletion(NULL, NULL);
8540 bufferlist read_bl;
8541 image2.aio_read(0, 1024, read_bl, read_comp);
8542 ASSERT_EQ(0, read_comp->wait_for_complete());
8543 read_comp->release();
8544}
8545
8546TEST_F(TestLibRBD, TestImageOptions)
8547{
8548 rados_ioctx_t ioctx;
8549 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8550
8551 //make create image options
8552 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
8553 uint64_t order = 0;
8554 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
8555 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
8556 rbd_image_options_t opts;
8557 rbd_image_options_create(&opts);
8558
8559 bool is_set;
8560 ASSERT_EQ(-EINVAL, rbd_image_options_is_set(opts, 12345, &is_set));
8561 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
8562 &is_set));
8563 ASSERT_FALSE(is_set);
8564
8565 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
8566 2));
8567 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
8568 features));
8569 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
8570 order));
8571 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
8572 stripe_unit));
8573 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
8574 stripe_count));
8575
8576 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
8577 &is_set));
8578 ASSERT_TRUE(is_set);
8579
8580 std::string parent_name = get_temp_image_name();
8581
8582 // make parent
8583 ASSERT_EQ(0, rbd_create4(ioctx, parent_name.c_str(), 4<<20, opts));
8584
8585 // check order is returned in opts
8586 ASSERT_EQ(0, rbd_image_options_get_uint64(opts, RBD_IMAGE_OPTION_ORDER,
8587 &order));
8588 ASSERT_NE((uint64_t)0, order);
8589
8590 // write some data to parent
8591 rbd_image_t parent;
8592 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
8593 char *data = (char *)"testdata";
8594 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
8595 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
8596
8597 // create a snapshot, reopen as the parent we're interested in
8598 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
8599 ASSERT_EQ(0, rbd_close(parent));
8600 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
8601
8602 // clone
8603 std::string child_name = get_temp_image_name();
8604 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
8605 ASSERT_EQ(0, rbd_clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
8606 child_name.c_str(), opts));
8607
8608 // copy
8609 std::string copy1_name = get_temp_image_name();
8610 ASSERT_EQ(0, rbd_copy3(parent, ioctx, copy1_name.c_str(), opts));
8611 std::string copy2_name = get_temp_image_name();
8612 ASSERT_EQ(0, rbd_copy_with_progress3(parent, ioctx, copy2_name.c_str(), opts,
8613 print_progress_percent, NULL));
8614
8615 ASSERT_EQ(0, rbd_close(parent));
8616
8617 rbd_image_options_destroy(opts);
8618
8619 rados_ioctx_destroy(ioctx);
8620}
8621
8622TEST_F(TestLibRBD, TestImageOptionsPP)
8623{
8624 librados::IoCtx ioctx;
8625 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8626
8627 //make create image options
8628 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
8629 uint64_t order = 0;
8630 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
8631 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
8632 librbd::ImageOptions opts;
8633 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2)));
8634 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FEATURES, features));
8635 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_ORDER, order));
8636 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
8637 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
8638
8639 librbd::RBD rbd;
8640 std::string parent_name = get_temp_image_name();
8641
8642 // make parent
8643 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 4<<20, opts));
8644
8645 // check order is returned in opts
8646 ASSERT_EQ(0, opts.get(RBD_IMAGE_OPTION_ORDER, &order));
8647 ASSERT_NE((uint64_t)0, order);
8648
8649 // write some data to parent
8650 librbd::Image parent;
8651 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
8652
8653 ssize_t len = 1024;
8654 bufferlist bl;
8655 bl.append(buffer::create(len));
8656 bl.zero();
8657 ASSERT_EQ(len, parent.write(0, len, bl));
8658 ASSERT_EQ(len, parent.write(len, len, bl));
8659
8660 // create a snapshot, reopen as the parent we're interested in
8661 ASSERT_EQ(0, parent.snap_create("parent_snap"));
8662 ASSERT_EQ(0, parent.close());
8663 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
8664
8665 // clone
8666 std::string child_name = get_temp_image_name();
8667 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
8668 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
8669 child_name.c_str(), opts));
8670
8671 // copy
8672 std::string copy1_name = get_temp_image_name();
8673 ASSERT_EQ(0, parent.copy3(ioctx, copy1_name.c_str(), opts));
8674 std::string copy2_name = get_temp_image_name();
8675 PrintProgress pp;
8676 ASSERT_EQ(0, parent.copy_with_progress3(ioctx, copy2_name.c_str(), opts, pp));
8677
8678 ASSERT_EQ(0, parent.close());
8679}
8680
8681TEST_F(TestLibRBD, EventSocketPipe)
8682{
8683 EventSocket event_sock;
8684 int pipe_fd[2]; // read and write fd
8685 char buf[32];
8686
8687 ASSERT_EQ(0, pipe(pipe_fd));
8688
8689 ASSERT_FALSE(event_sock.is_valid());
8690
8691 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_NONE));
8692 ASSERT_FALSE(event_sock.is_valid());
8693
8694 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], 44));
8695 ASSERT_FALSE(event_sock.is_valid());
8696
8697#ifndef HAVE_EVENTFD
8698 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_EVENTFD));
8699 ASSERT_FALSE(event_sock.is_valid());
8700#endif
8701
8702 ASSERT_EQ(0, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_PIPE));
8703 ASSERT_TRUE(event_sock.is_valid());
8704 ASSERT_EQ(0, event_sock.notify());
8705 ASSERT_EQ(1, read(pipe_fd[0], buf, 32));
8706 ASSERT_EQ('i', buf[0]);
8707
8708 close(pipe_fd[0]);
8709 close(pipe_fd[1]);
8710}
8711
8712TEST_F(TestLibRBD, EventSocketEventfd)
8713{
8714#ifdef HAVE_EVENTFD
8715 EventSocket event_sock;
8716 int event_fd;
8717 struct pollfd poll_fd;
8718 char buf[32];
8719
8720 event_fd = eventfd(0, EFD_NONBLOCK);
8721 ASSERT_NE(-1, event_fd);
8722
8723 ASSERT_FALSE(event_sock.is_valid());
8724
8725 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, EVENT_SOCKET_TYPE_NONE));
8726 ASSERT_FALSE(event_sock.is_valid());
8727
8728 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, 44));
8729 ASSERT_FALSE(event_sock.is_valid());
8730
8731 ASSERT_EQ(0, event_sock.init(event_fd, EVENT_SOCKET_TYPE_EVENTFD));
8732 ASSERT_TRUE(event_sock.is_valid());
8733 ASSERT_EQ(0, event_sock.notify());
8734
8735 poll_fd.fd = event_fd;
8736 poll_fd.events = POLLIN;
8737 ASSERT_EQ(1, poll(&poll_fd, 1, -1));
8738 ASSERT_TRUE(poll_fd.revents & POLLIN);
8739
8740 ASSERT_EQ(static_cast<ssize_t>(sizeof(uint64_t)), read(event_fd, buf, 32));
8741 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf));
8742
8743 close(event_fd);
8744#endif
8745}
8746
8747TEST_F(TestLibRBD, ImagePollIO)
8748{
8749#ifdef HAVE_EVENTFD
8750 rados_ioctx_t ioctx;
8751 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
8752
8753 rbd_image_t image;
8754 int order = 0;
8755 std::string name = get_temp_image_name();
8756 uint64_t size = 2 << 20;
8757 int fd = eventfd(0, EFD_NONBLOCK);
8758
8759 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
8760 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
8761
8762 ASSERT_EQ(0, rbd_set_image_notification(image, fd, EVENT_SOCKET_TYPE_EVENTFD));
8763
8764 char test_data[TEST_IO_SIZE + 1];
8765 char zero_data[TEST_IO_SIZE + 1];
8766 int i;
8767
8768 for (i = 0; i < TEST_IO_SIZE; ++i)
8769 test_data[i] = (char) (rand() % (126 - 33) + 33);
8770 test_data[TEST_IO_SIZE] = '\0';
8771 memset(zero_data, 0, sizeof(zero_data));
8772
8773 for (i = 0; i < 5; ++i)
8774 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
8775
8776 for (i = 5; i < 10; ++i)
8777 ASSERT_PASSED(aio_write_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
8778
8779 for (i = 5; i < 10; ++i)
8780 ASSERT_PASSED(aio_read_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
8781
8782 ASSERT_EQ(0, rbd_close(image));
8783 rados_ioctx_destroy(ioctx);
8784#endif
8785}
8786
8787namespace librbd {
8788
11fdf7f2
TL
8789static bool operator==(const image_spec_t &lhs, const image_spec_t &rhs) {
8790 return (lhs.id == rhs.id && lhs.name == rhs.name);
8791}
8792
8793static bool operator==(const linked_image_spec_t &lhs,
8794 const linked_image_spec_t &rhs) {
8795 return (lhs.pool_id == rhs.pool_id &&
8796 lhs.pool_name == rhs.pool_name &&
8797 lhs.pool_namespace == rhs.pool_namespace &&
8798 lhs.image_id == rhs.image_id &&
8799 lhs.image_name == rhs.image_name &&
8800 lhs.trash == rhs.trash);
8801}
8802
7c673cae
FG
8803static bool operator==(const mirror_peer_t &lhs, const mirror_peer_t &rhs) {
8804 return (lhs.uuid == rhs.uuid &&
8805 lhs.cluster_name == rhs.cluster_name &&
8806 lhs.client_name == rhs.client_name);
8807}
8808
8809static std::ostream& operator<<(std::ostream &os, const mirror_peer_t &peer) {
8810 os << "uuid=" << peer.uuid << ", "
8811 << "cluster=" << peer.cluster_name << ", "
8812 << "client=" << peer.client_name;
8813 return os;
8814}
8815
8816} // namespace librbd
8817
8818TEST_F(TestLibRBD, Mirror) {
8819 librados::IoCtx ioctx;
8820 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8821
8822 librbd::RBD rbd;
8823
8824 std::vector<librbd::mirror_peer_t> expected_peers;
8825 std::vector<librbd::mirror_peer_t> peers;
8826 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
8827 ASSERT_EQ(expected_peers, peers);
8828
8829 std::string uuid1;
8830 ASSERT_EQ(-EINVAL, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
8831
8832 rbd_mirror_mode_t mirror_mode;
8833 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
8834 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED, mirror_mode);
8835
8836 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
8837 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
8838
8839 // Add some images to the pool
8840 int order = 0;
8841 std::string parent_name = get_temp_image_name();
8842 std::string child_name = get_temp_image_name();
8843 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), 2 << 20,
8844 &order));
8845 bool old_format;
8846 uint64_t features;
8847 ASSERT_EQ(0, get_features(&old_format, &features));
8848 if ((features & RBD_FEATURE_LAYERING) != 0) {
8849 librbd::Image parent;
8850 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
8851 ASSERT_EQ(0, parent.snap_create("parent_snap"));
8852 ASSERT_EQ(0, parent.close());
8853 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
8854 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
8855 ASSERT_EQ(0, parent.close());
8856 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "parent_snap", ioctx,
8857 child_name.c_str(), features, &order));
8858 }
8859
8860 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE, mirror_mode);
8861
8862 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_POOL));
8863 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
8864 ASSERT_EQ(RBD_MIRROR_MODE_POOL, mirror_mode);
8865
8866 std::string uuid2;
8867 std::string uuid3;
8868 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
8869 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid2, "cluster2", "admin"));
8870 ASSERT_EQ(-EEXIST, rbd.mirror_peer_add(ioctx, &uuid3, "cluster1", "foo"));
8871 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid3, "cluster3", "admin"));
8872
8873 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
8874 auto sort_peers = [](const librbd::mirror_peer_t &lhs,
8875 const librbd::mirror_peer_t &rhs) {
8876 return lhs.uuid < rhs.uuid;
8877 };
8878 expected_peers = {
8879 {uuid1, "cluster1", "client"},
8880 {uuid2, "cluster2", "admin"},
8881 {uuid3, "cluster3", "admin"}};
8882 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
8883 ASSERT_EQ(expected_peers, peers);
8884
8885 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, "uuid4"));
8886 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid2));
8887
8888 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_client(ioctx, "uuid4", "new client"));
8889 ASSERT_EQ(0, rbd.mirror_peer_set_client(ioctx, uuid1, "new client"));
8890
8891 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_cluster(ioctx, "uuid4",
8892 "new cluster"));
8893 ASSERT_EQ(0, rbd.mirror_peer_set_cluster(ioctx, uuid3, "new cluster"));
8894
8895 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
8896 expected_peers = {
8897 {uuid1, "cluster1", "new client"},
8898 {uuid3, "new cluster", "admin"}};
8899 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
8900 ASSERT_EQ(expected_peers, peers);
8901
8902 ASSERT_EQ(-EBUSY, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
11fdf7f2
TL
8903 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid1));
8904 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid3));
8905 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
7c673cae
FG
8906}
8907
11fdf7f2
TL
8908TEST_F(TestLibRBD, MirrorPeerAttributes) {
8909 REQUIRE(!is_librados_test_stub(_rados));
7c673cae
FG
8910
8911 librados::IoCtx ioctx;
8912 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8913
8914 librbd::RBD rbd;
11fdf7f2 8915 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
7c673cae 8916
11fdf7f2
TL
8917 std::string uuid;
8918 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid, "remote_cluster", "client"));
7c673cae 8919
11fdf7f2
TL
8920 std::map<std::string, std::string> attributes;
8921 ASSERT_EQ(-ENOENT, rbd.mirror_peer_get_attributes(ioctx, uuid, &attributes));
8922 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_attributes(ioctx, "missing uuid",
8923 attributes));
7c673cae 8924
11fdf7f2
TL
8925 std::map<std::string, std::string> expected_attributes{
8926 {"mon_host", "1.2.3.4"},
8927 {"key", "ABC"}};
8928 ASSERT_EQ(0, rbd.mirror_peer_set_attributes(ioctx, uuid,
8929 expected_attributes));
8930
8931 ASSERT_EQ(0, rbd.mirror_peer_get_attributes(ioctx, uuid,
8932 &attributes));
8933 ASSERT_EQ(expected_attributes, attributes);
8934
8935 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid));
8936 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
8937}
8938
1911f103
TL
8939TEST_F(TestLibRBD, CreateWithMirrorEnabled) {
8940 REQUIRE_FORMAT_V2();
8941
8942 librados::IoCtx ioctx;
8943 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8944
8945 librbd::RBD rbd;
8946 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
8947
8948 librbd::ImageOptions image_options;
8949 ASSERT_EQ(0, image_options.set(
8950 RBD_IMAGE_OPTION_MIRROR_IMAGE_MODE,
8951 static_cast<uint64_t>(RBD_MIRROR_IMAGE_MODE_SNAPSHOT)));
8952
8953 std::string parent_name = get_temp_image_name();
8954 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 2<<20, image_options));
8955
8956 librbd::Image parent_image;
8957 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
8958
8959 librbd::mirror_image_mode_t mirror_image_mode;
8960 ASSERT_EQ(0, parent_image.mirror_image_get_mode(&mirror_image_mode));
8961 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mirror_image_mode);
8962
8963 ASSERT_EQ(0, parent_image.snap_create("parent_snap"));
8964 ASSERT_EQ(0, parent_image.snap_protect("parent_snap"));
8965
8966 std::string child_name = get_temp_image_name();
8967 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
8968 child_name.c_str(), image_options));
8969
8970 librbd::Image child_image;
8971 ASSERT_EQ(0, rbd.open(ioctx, child_image, child_name.c_str(), NULL));
8972
8973 ASSERT_EQ(0, child_image.mirror_image_get_mode(&mirror_image_mode));
8974 ASSERT_EQ(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mirror_image_mode);
8975
8976 ASSERT_EQ(0, child_image.mirror_image_disable(true));
8977 ASSERT_EQ(0, parent_image.mirror_image_disable(true));
8978 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
8979}
8980
11fdf7f2
TL
8981TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {
8982 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
8983
8984 librados::IoCtx ioctx;
8985 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
8986
8987 librbd::RBD rbd;
8988 librbd::Image image;
8989 std::string name = get_temp_image_name();
8990
8991 uint64_t size = 1 << 18;
8992 int order = 0;
8993
8994 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
8995 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
8996
8997 bufferlist bl;
8998 bl.append(std::string(size, '1'));
7c673cae
FG
8999 ASSERT_EQ((int)size, image.write(0, size, bl));
9000 ASSERT_EQ(0, image.snap_create("one"));
9001 ASSERT_EQ(0, image.snap_protect("one"));
9002
9003 std::string clone_name = this->get_temp_image_name();
9004 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
9005 RBD_FEATURE_LAYERING, &order));
9006 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
9007
9008 librbd::Image image2;
9009 ASSERT_EQ(0, rbd.open(ioctx, image2, clone_name.c_str(), NULL));
9010
9011 // prepare CoW writeback that will be flushed on next op
9012 bl.clear();
9013 bl.append(std::string(1, '1'));
9014 ASSERT_EQ(0, image.flush());
9015 ASSERT_EQ(1, image.write(0, 1, bl));
9016 ASSERT_EQ(0, image2.snap_create("snap1"));
9017
9018 librbd::RBD::AioCompletion *read_comp =
9019 new librbd::RBD::AioCompletion(NULL, NULL);
9020 bufferlist read_bl;
9021 image.aio_read(0, 1024, read_bl, read_comp);
9022 ASSERT_EQ(0, read_comp->wait_for_complete());
9023 read_comp->release();
9024}
9025
9026TEST_F(TestLibRBD, ExclusiveLock)
9027{
9028 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
9029
9030 static char buf[10];
9031
9032 rados_ioctx_t ioctx;
9033 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9034
9035 std::string name = get_temp_image_name();
9036 uint64_t size = 2 << 20;
9037 int order = 0;
9038 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9039
9040 rbd_image_t image1;
9041 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
9042
9043 int lock_owner;
9044 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
9045 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
9046 ASSERT_TRUE(lock_owner);
9047
9048 rbd_lock_mode_t lock_mode;
9049 char *lock_owners[1];
9050 size_t max_lock_owners = 0;
9051 ASSERT_EQ(-ERANGE, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
9052 &max_lock_owners));
9053 ASSERT_EQ(1U, max_lock_owners);
9054
7c673cae
FG
9055 ASSERT_EQ(0, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
9056 &max_lock_owners));
9057 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
9058 ASSERT_STRNE("", lock_owners[0]);
9059 ASSERT_EQ(1U, max_lock_owners);
9060
9061 rbd_image_t image2;
9062 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
9063
9064 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
9065 ASSERT_FALSE(lock_owner);
9066
9067 ASSERT_EQ(-EOPNOTSUPP, rbd_lock_break(image1, RBD_LOCK_MODE_SHARED, ""));
9068 ASSERT_EQ(-EBUSY, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
9069 "not the owner"));
9070
9071 ASSERT_EQ(0, rbd_lock_release(image1));
9072 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
9073 ASSERT_FALSE(lock_owner);
9074
9075 ASSERT_EQ(-ENOENT, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
9076 lock_owners[0]));
9077 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
9078
9079 ASSERT_EQ(-EROFS, rbd_write(image1, 0, sizeof(buf), buf));
9080 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image2, 0, sizeof(buf), buf));
9081
9082 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
9083 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
9084 ASSERT_TRUE(lock_owner);
9085
9086 ASSERT_EQ(0, rbd_lock_release(image2));
9087 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
9088 ASSERT_FALSE(lock_owner);
9089
9090 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
9091 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
9092 ASSERT_TRUE(lock_owner);
9093
9094 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image1, 0, sizeof(buf), buf));
9095 ASSERT_EQ(-EROFS, rbd_write(image2, 0, sizeof(buf), buf));
9096
9097 ASSERT_EQ(0, rbd_lock_release(image1));
9098 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
9099 ASSERT_FALSE(lock_owner);
9100
9101 int owner_id = -1;
f67539c2 9102 std::mutex lock;
11fdf7f2 9103 const auto pingpong = [&](int m_id, rbd_image_t &m_image) {
7c673cae
FG
9104 for (int i = 0; i < 10; i++) {
9105 {
f67539c2 9106 std::lock_guard<std::mutex> locker(lock);
31f18b77 9107 if (owner_id == m_id) {
7c673cae
FG
9108 std::cout << m_id << ": releasing exclusive lock" << std::endl;
9109 EXPECT_EQ(0, rbd_lock_release(m_image));
9110 int lock_owner;
9111 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
9112 EXPECT_FALSE(lock_owner);
31f18b77 9113 owner_id = -1;
7c673cae
FG
9114 std::cout << m_id << ": exclusive lock released" << std::endl;
9115 continue;
9116 }
9117 }
9118
9119 std::cout << m_id << ": acquiring exclusive lock" << std::endl;
9120 int r;
9121 do {
9122 r = rbd_lock_acquire(m_image, RBD_LOCK_MODE_EXCLUSIVE);
9123 if (r == -EROFS) {
9124 usleep(1000);
9125 }
9126 } while (r == -EROFS);
9127 EXPECT_EQ(0, r);
9128
9129 int lock_owner;
9130 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
9131 EXPECT_TRUE(lock_owner);
9132 std::cout << m_id << ": exclusive lock acquired" << std::endl;
9133 {
f67539c2 9134 std::lock_guard<std::mutex> locker(lock);
31f18b77 9135 owner_id = m_id;
7c673cae
FG
9136 }
9137 usleep(rand() % 50000);
9138 }
9139
f67539c2 9140 std::lock_guard<std::mutex> locker(lock);
31f18b77 9141 if (owner_id == m_id) {
7c673cae
FG
9142 EXPECT_EQ(0, rbd_lock_release(m_image));
9143 int lock_owner;
9144 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
9145 EXPECT_FALSE(lock_owner);
31f18b77 9146 owner_id = -1;
7c673cae 9147 }
31f18b77
FG
9148 };
9149 thread ping(bind(pingpong, 1, ref(image1)));
9150 thread pong(bind(pingpong, 2, ref(image2)));
7c673cae 9151
7c673cae
FG
9152 ping.join();
9153 pong.join();
9154
9155 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
9156 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
9157 ASSERT_TRUE(lock_owner);
9158
9159 ASSERT_EQ(0, rbd_close(image2));
9160
9161 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
9162 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
9163 ASSERT_TRUE(lock_owner);
9164
9165 ASSERT_EQ(0, rbd_close(image1));
9166 rados_ioctx_destroy(ioctx);
9167}
9168
9169TEST_F(TestLibRBD, BreakLock)
9170{
9171 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
f67539c2 9172 REQUIRE(!is_rbd_pwl_enabled((CephContext *)_rados.cct()));
7c673cae
FG
9173
9174 static char buf[10];
9175
f67539c2
TL
9176 rados_t blocklist_cluster;
9177 ASSERT_EQ("", connect_cluster(&blocklist_cluster));
7c673cae 9178
f67539c2 9179 rados_ioctx_t ioctx, blocklist_ioctx;
7c673cae 9180 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
f67539c2
TL
9181 ASSERT_EQ(0, rados_ioctx_create(blocklist_cluster, m_pool_name.c_str(),
9182 &blocklist_ioctx));
7c673cae
FG
9183
9184 std::string name = get_temp_image_name();
9185 uint64_t size = 2 << 20;
9186 int order = 0;
9187 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9188
f67539c2 9189 rbd_image_t image, blocklist_image;
7c673cae 9190 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
f67539c2 9191 ASSERT_EQ(0, rbd_open(blocklist_ioctx, name.c_str(), &blocklist_image, NULL));
7c673cae 9192
f67539c2
TL
9193 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_blocklist_on_break_lock", "true"));
9194 ASSERT_EQ(0, rbd_lock_acquire(blocklist_image, RBD_LOCK_MODE_EXCLUSIVE));
7c673cae
FG
9195
9196 rbd_lock_mode_t lock_mode;
9197 char *lock_owners[1];
9198 size_t max_lock_owners = 1;
9199 ASSERT_EQ(0, rbd_lock_get_owners(image, &lock_mode, lock_owners,
9200 &max_lock_owners));
9201 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
9202 ASSERT_STRNE("", lock_owners[0]);
9203 ASSERT_EQ(1U, max_lock_owners);
9204
9205 ASSERT_EQ(0, rbd_lock_break(image, RBD_LOCK_MODE_EXCLUSIVE, lock_owners[0]));
9206 ASSERT_EQ(0, rbd_lock_acquire(image, RBD_LOCK_MODE_EXCLUSIVE));
f67539c2 9207 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blocklist_cluster));
7c673cae
FG
9208
9209 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image, 0, sizeof(buf), buf));
f67539c2 9210 ASSERT_EQ(-EBLOCKLISTED, rbd_write(blocklist_image, 0, sizeof(buf), buf));
7c673cae
FG
9211
9212 ASSERT_EQ(0, rbd_close(image));
f67539c2 9213 ASSERT_EQ(0, rbd_close(blocklist_image));
7c673cae
FG
9214
9215 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
9216
9217 rados_ioctx_destroy(ioctx);
f67539c2
TL
9218 rados_ioctx_destroy(blocklist_ioctx);
9219 rados_shutdown(blocklist_cluster);
7c673cae
FG
9220}
9221
9222TEST_F(TestLibRBD, DiscardAfterWrite)
9223{
7c673cae
FG
9224 librados::IoCtx ioctx;
9225 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9226
9227 librbd::RBD rbd;
9228 std::string name = get_temp_image_name();
9229 uint64_t size = 1 << 20;
9230 int order = 18;
9231 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9232
9233 librbd::Image image;
9234 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9235
f67539c2
TL
9236 if (this->is_skip_partial_discard_enabled(image)) {
9237 return;
9238 }
9239
7c673cae
FG
9240 // enable writeback cache
9241 ASSERT_EQ(0, image.flush());
9242
9243 bufferlist bl;
9244 bl.append(std::string(256, '1'));
9245
9246 librbd::RBD::AioCompletion *write_comp =
9247 new librbd::RBD::AioCompletion(NULL, NULL);
9248 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
9249 ASSERT_EQ(0, write_comp->wait_for_complete());
9250 write_comp->release();
9251
9252 librbd::RBD::AioCompletion *discard_comp =
9253 new librbd::RBD::AioCompletion(NULL, NULL);
9254 ASSERT_EQ(0, image.aio_discard(0, 256, discard_comp));
9255 ASSERT_EQ(0, discard_comp->wait_for_complete());
9256 discard_comp->release();
9257
9258 librbd::RBD::AioCompletion *read_comp =
9259 new librbd::RBD::AioCompletion(NULL, NULL);
9260 bufferlist read_bl;
9261 image.aio_read(0, bl.length(), read_bl, read_comp);
9262 ASSERT_EQ(0, read_comp->wait_for_complete());
9263 ASSERT_EQ(bl.length(), read_comp->get_return_value());
9264 ASSERT_TRUE(read_bl.is_zero());
9265 read_comp->release();
9266}
9267
9268TEST_F(TestLibRBD, DefaultFeatures) {
9269 std::string orig_default_features;
9270 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", orig_default_features));
9271 BOOST_SCOPE_EXIT_ALL(orig_default_features) {
9272 ASSERT_EQ(0, _rados.conf_set("rbd_default_features",
9273 orig_default_features.c_str()));
9274 };
9275
9276 std::list<std::pair<std::string, std::string> > feature_names_to_bitmask = {
9277 {"", orig_default_features},
9278 {"layering", "1"},
9279 {"layering, exclusive-lock", "5"},
9280 {"exclusive-lock,journaling", "68"},
9281 {"125", "125"}
9282 };
9283
9284 for (auto &pair : feature_names_to_bitmask) {
9285 ASSERT_EQ(0, _rados.conf_set("rbd_default_features", pair.first.c_str()));
9286 std::string features;
9287 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", features));
9288 ASSERT_EQ(pair.second, features);
9289 }
9290}
9291
9292TEST_F(TestLibRBD, TestTrashMoveAndPurge) {
11fdf7f2
TL
9293 REQUIRE_FORMAT_V2();
9294
7c673cae
FG
9295 librados::IoCtx ioctx;
9296 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9297
9298 librbd::RBD rbd;
9299 std::string name = get_temp_image_name();
9300
9301 uint64_t size = 1 << 18;
9302 int order = 12;
9303 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9304
9305 librbd::Image image;
9306 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 9307
7c673cae
FG
9308 std::string image_id;
9309 ASSERT_EQ(0, image.get_id(&image_id));
9310 image.close();
9311
9312 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 0));
9313
9314 std::vector<std::string> images;
9315 ASSERT_EQ(0, rbd.list(ioctx, images));
9316 for (const auto& image : images) {
9317 ASSERT_TRUE(image != name);
9318 }
9319
9320 librbd::trash_image_info_t info;
9321 ASSERT_EQ(-ENOENT, rbd.trash_get(ioctx, "dummy image id", &info));
9322 ASSERT_EQ(0, rbd.trash_get(ioctx, image_id.c_str(), &info));
9323 ASSERT_EQ(image_id, info.id);
9324
9325 std::vector<librbd::trash_image_info_t> entries;
9326 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
9327 ASSERT_FALSE(entries.empty());
9328 ASSERT_EQ(entries.begin()->id, image_id);
9329
9330 entries.clear();
9331 PrintProgress pp;
9332 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
9333 false, pp));
9334 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
9335 ASSERT_TRUE(entries.empty());
9336}
9337
9338TEST_F(TestLibRBD, TestTrashMoveAndPurgeNonExpiredDelay) {
11fdf7f2
TL
9339 REQUIRE_FORMAT_V2();
9340
7c673cae
FG
9341 librados::IoCtx ioctx;
9342 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9343
9344 librbd::RBD rbd;
9345 std::string name = get_temp_image_name();
9346
9347 uint64_t size = 1 << 18;
9348 int order = 12;
9349 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9350
9351 librbd::Image image;
9352 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 9353
7c673cae
FG
9354 std::string image_id;
9355 ASSERT_EQ(0, image.get_id(&image_id));
9356 image.close();
9357
9358 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 100));
9359
9360 PrintProgress pp;
9361 ASSERT_EQ(-EPERM, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
9362 false, pp));
9363
9364 PrintProgress pp2;
9365 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
9366 true, pp2));
9367}
9368
11fdf7f2
TL
9369TEST_F(TestLibRBD, TestTrashPurge) {
9370 REQUIRE_FORMAT_V2();
9371
9372 librados::IoCtx ioctx;
9373 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9374
9375 librbd::RBD rbd;
9376 std::string name1 = get_temp_image_name();
9377 std::string name2 = get_temp_image_name();
9378
9379 uint64_t size = 1 << 18;
9380 int order = 12;
9381 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name1.c_str(), size, &order));
9382 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
9383
9384 librbd::Image image1;
9385 ASSERT_EQ(0, rbd.open(ioctx, image1, name1.c_str(), nullptr));
9386
9387 std::string image_id1;
9388 ASSERT_EQ(0, image1.get_id(&image_id1));
9389 image1.close();
9390
9391 ASSERT_EQ(0, rbd.trash_move(ioctx, name1.c_str(), 0));
9392
9393 librbd::Image image2;
9394 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), nullptr));
9395 ceph::bufferlist bl;
9396 bl.append(std::string(1024, '0'));
9397 ASSERT_EQ(1024, image2.write(0, 1024, bl));
9398
9399 std::string image_id2;
9400 ASSERT_EQ(0, image2.get_id(&image_id2));
9401 image2.close();
9402
9403 ASSERT_EQ(0, rbd.trash_move(ioctx, name2.c_str(), 100));
9404 ASSERT_EQ(0, rbd.trash_purge(ioctx, 0, -1));
9405
9406 std::vector<librbd::trash_image_info_t> entries;
9407 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
9408 ASSERT_EQ(1U, entries.size());
9409 ASSERT_EQ(image_id2, entries[0].id);
9410 ASSERT_EQ(name2, entries[0].name);
9411 entries.clear();
9412
9413 struct timespec now;
9414 clock_gettime(CLOCK_REALTIME, &now);
9415 float threshold = 0.0;
9416 if (!is_librados_test_stub(_rados)) {
9417 // real cluster usage reports have a long latency to update
9418 threshold = -1.0;
9419 }
9420
9421 ASSERT_EQ(0, rbd.trash_purge(ioctx, now.tv_sec+1000, threshold));
9422 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
9423 ASSERT_EQ(0U, entries.size());
9424}
9425
7c673cae 9426TEST_F(TestLibRBD, TestTrashMoveAndRestore) {
11fdf7f2
TL
9427 REQUIRE_FORMAT_V2();
9428
7c673cae
FG
9429 librados::IoCtx ioctx;
9430 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9431
9432 librbd::RBD rbd;
9433 std::string name = get_temp_image_name();
9434
9435 uint64_t size = 1 << 18;
9436 int order = 12;
9437 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9438
9439 librbd::Image image;
9440 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7c673cae 9441
7c673cae
FG
9442 std::string image_id;
9443 ASSERT_EQ(0, image.get_id(&image_id));
9444 image.close();
9445
9446 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 10));
9447
9448 std::vector<std::string> images;
9449 ASSERT_EQ(0, rbd.list(ioctx, images));
9450 for (const auto& image : images) {
9451 ASSERT_TRUE(image != name);
9452 }
9453
9454 std::vector<librbd::trash_image_info_t> entries;
9455 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
9456 ASSERT_FALSE(entries.empty());
9457 ASSERT_EQ(entries.begin()->id, image_id);
9458
9459 images.clear();
9460 ASSERT_EQ(0, rbd.trash_restore(ioctx, image_id.c_str(), ""));
9461 ASSERT_EQ(0, rbd.list(ioctx, images));
9462 ASSERT_FALSE(images.empty());
9463 bool found = false;
9464 for (const auto& image : images) {
9465 if (image == name) {
9466 found = true;
9467 break;
9468 }
9469 }
9470 ASSERT_TRUE(found);
9471}
31f18b77 9472
11fdf7f2
TL
9473TEST_F(TestLibRBD, TestListWatchers) {
9474 librados::IoCtx ioctx;
9475 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9476
9477 librbd::RBD rbd;
9478 std::string name = get_temp_image_name();
9479
9480 uint64_t size = 1 << 18;
9481 int order = 12;
9482 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9483
9484 librbd::Image image;
9485 std::list<librbd::image_watcher_t> watchers;
9486
9487 // No watchers
9488 ASSERT_EQ(0, rbd.open_read_only(ioctx, image, name.c_str(), nullptr));
9489 ASSERT_EQ(0, image.list_watchers(watchers));
9490 ASSERT_EQ(0U, watchers.size());
9491 ASSERT_EQ(0, image.close());
9492
9493 // One watcher
9494 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
9495 ASSERT_EQ(0, image.list_watchers(watchers));
9496 ASSERT_EQ(1U, watchers.size());
9497 ASSERT_EQ(0, image.close());
9498}
9499
9500TEST_F(TestLibRBD, TestSetSnapById) {
9501 librados::IoCtx ioctx;
9502 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9503
9504 librbd::RBD rbd;
9505 std::string name = get_temp_image_name();
9506
9507 uint64_t size = 1 << 18;
9508 int order = 12;
9509 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9510
9511 librbd::Image image;
9512 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
9513 ASSERT_EQ(0, image.snap_create("snap"));
9514
9515 vector<librbd::snap_info_t> snaps;
9516 ASSERT_EQ(0, image.snap_list(snaps));
9517 ASSERT_EQ(1U, snaps.size());
9518
9519 ASSERT_EQ(0, image.snap_set_by_id(snaps[0].id));
9520 ASSERT_EQ(0, image.snap_set_by_id(CEPH_NOSNAP));
9521}
9522
9523TEST_F(TestLibRBD, Namespaces) {
9524 rados_ioctx_t ioctx;
9525 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
9526 rados_remove(ioctx, RBD_NAMESPACE);
9527
9528 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name1"));
9529 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name2"));
9530 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name3"));
9531 ASSERT_EQ(0, rbd_namespace_remove(ioctx, "name2"));
9532
9533 char names[1024];
9534 size_t max_size = sizeof(names);
9535 int len = rbd_namespace_list(ioctx, names, &max_size);
9536
9537 std::vector<std::string> cpp_names;
9538 for (char* cur_name = names; cur_name < names + len; ) {
9539 cpp_names.push_back(cur_name);
9540 cur_name += strlen(cur_name) + 1;
9541 }
9542 ASSERT_EQ(2U, cpp_names.size());
9543 ASSERT_EQ("name1", cpp_names[0]);
9544 ASSERT_EQ("name3", cpp_names[1]);
9545 bool exists;
9546 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name2", &exists));
9547 ASSERT_FALSE(exists);
9548 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name3", &exists));
9549 ASSERT_TRUE(exists);
9550 rados_ioctx_destroy(ioctx);
9551}
9552
9553TEST_F(TestLibRBD, NamespacesPP) {
9554 librados::IoCtx ioctx;
9555 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9556 ioctx.remove(RBD_NAMESPACE);
9557
9558 librbd::RBD rbd;
9559 ASSERT_EQ(-EINVAL, rbd.namespace_create(ioctx, ""));
9560 ASSERT_EQ(-EINVAL, rbd.namespace_remove(ioctx, ""));
9561
9562 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name1"));
9563 ASSERT_EQ(-EEXIST, rbd.namespace_create(ioctx, "name1"));
9564 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name2"));
9565 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name3"));
9566 ASSERT_EQ(0, rbd.namespace_remove(ioctx, "name2"));
9567 ASSERT_EQ(-ENOENT, rbd.namespace_remove(ioctx, "name2"));
9568
9569 std::vector<std::string> names;
9570 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
9571 ASSERT_EQ(2U, names.size());
9572 ASSERT_EQ("name1", names[0]);
9573 ASSERT_EQ("name3", names[1]);
9574 bool exists;
9575 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name2", &exists));
9576 ASSERT_FALSE(exists);
9577 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name3", &exists));
9578 ASSERT_TRUE(exists);
9579
9580 librados::IoCtx ns_io_ctx;
9581 ns_io_ctx.dup(ioctx);
9582
9583 std::string name = get_temp_image_name();
9584 int order = 0;
9585 uint64_t features = 0;
9586 if (!get_features(&features)) {
9587 // old format doesn't support namespaces
9588 ns_io_ctx.set_namespace("name1");
9589 ASSERT_EQ(-EINVAL, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0,
9590 &order));
9591 return;
9592 }
9593
9594 ns_io_ctx.set_namespace("missing");
9595 ASSERT_EQ(-ENOENT, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
9596
9597 ns_io_ctx.set_namespace("name1");
9598 ASSERT_EQ(0, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
9599 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
9600
9601 std::string image_id;
9602 {
9603 librbd::Image image;
9604 ASSERT_EQ(-ENOENT, rbd.open(ioctx, image, name.c_str(), NULL));
9605 ASSERT_EQ(0, rbd.open(ns_io_ctx, image, name.c_str(), NULL));
9606 ASSERT_EQ(0, get_image_id(image, &image_id));
9607 }
9608
9609 ASSERT_EQ(-ENOENT, rbd.trash_move(ioctx, name.c_str(), 0));
9610 ASSERT_EQ(0, rbd.trash_move(ns_io_ctx, name.c_str(), 0));
9611 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
9612
9613 PrintProgress pp;
9614 ASSERT_EQ(-ENOENT, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
9615 false, pp));
9616 ASSERT_EQ(0, rbd.trash_remove_with_progress(ns_io_ctx, image_id.c_str(),
9617 false, pp));
9618 ASSERT_EQ(0, rbd.namespace_remove(ns_io_ctx, "name1"));
9619
9620 names.clear();
9621 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
9622 ASSERT_EQ(1U, names.size());
9623 ASSERT_EQ("name3", names[0]);
9624}
9625
9626TEST_F(TestLibRBD, Migration) {
9627 bool old_format;
9628 uint64_t features;
9629 ASSERT_EQ(0, get_features(&old_format, &features));
9630
9631 rados_ioctx_t ioctx;
9632 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9633 BOOST_SCOPE_EXIT(&ioctx) {
9634 rados_ioctx_destroy(ioctx);
9635 } BOOST_SCOPE_EXIT_END;
9636
9637 int order = 0;
9638 std::string name = get_temp_image_name();
9639 uint64_t size = 2 << 20;
9640 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9641
9642 rbd_image_options_t image_options;
9643 rbd_image_options_create(&image_options);
9644 BOOST_SCOPE_EXIT(&image_options) {
9645 rbd_image_options_destroy(image_options);
9646 } BOOST_SCOPE_EXIT_END;
9647
9648 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
9649 image_options));
9650
9651 rbd_image_migration_status_t status;
9652 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
9653 sizeof(status)));
9654 ASSERT_EQ(status.source_pool_id, rados_ioctx_get_id(ioctx));
9655 ASSERT_EQ(status.source_image_name, name);
9656 if (old_format) {
9657 ASSERT_EQ(status.source_image_id, string());
9658 } else {
9659 ASSERT_NE(status.source_image_id, string());
9660 ASSERT_EQ(-EROFS, rbd_trash_remove(ioctx, status.source_image_id, false));
9661 ASSERT_EQ(-EINVAL, rbd_trash_restore(ioctx, status.source_image_id, name.c_str()));
9662 }
9663 ASSERT_EQ(status.dest_pool_id, rados_ioctx_get_id(ioctx));
9664 ASSERT_EQ(status.dest_image_name, name);
9665 ASSERT_NE(status.dest_image_id, string());
9666 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
9667 rbd_migration_status_cleanup(&status);
9668
f67539c2
TL
9669 rbd_image_t image;
9670 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
9671 char source_spec[2048];
9672 size_t source_spec_length = sizeof(source_spec);
9673 ASSERT_EQ(0, rbd_get_migration_source_spec(image, source_spec,
9674 &source_spec_length));
9675 json_spirit::mValue json_source_spec;
9676 json_spirit::read(source_spec, json_source_spec);
9677 EXPECT_EQ(0, rbd_close(image));
9678
11fdf7f2
TL
9679 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, name.c_str()));
9680 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, name.c_str(), 0));
9681
9682 ASSERT_EQ(0, rbd_migration_execute(ioctx, name.c_str()));
9683
9684 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
9685 sizeof(status)));
9686 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
9687 rbd_migration_status_cleanup(&status);
9688
9689 ASSERT_EQ(0, rbd_migration_commit(ioctx, name.c_str()));
9690
9691 std::string new_name = get_temp_image_name();
9692
9693 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx,
9694 new_name.c_str(), image_options));
9695
9696 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, new_name.c_str()));
9697 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, new_name.c_str(), 0));
9698
9699 ASSERT_EQ(0, rbd_migration_abort(ioctx, name.c_str()));
9700
11fdf7f2
TL
9701 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
9702 EXPECT_EQ(0, rbd_close(image));
9703}
9704
9705TEST_F(TestLibRBD, MigrationPP) {
9706 bool old_format;
9707 uint64_t features;
9708 ASSERT_EQ(0, get_features(&old_format, &features));
9709
9710 librados::IoCtx ioctx;
9711 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9712
9713 int order = 0;
9714 std::string name = get_temp_image_name();
9715 uint64_t size = 2 << 20;
9716 librbd::RBD rbd;
9717 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9718
9719 librbd::ImageOptions image_options;
9720
9721 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
9722 image_options));
9723
9724 librbd::image_migration_status_t status;
9725 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
9726 sizeof(status)));
9727 ASSERT_EQ(status.source_pool_id, ioctx.get_id());
9728 ASSERT_EQ(status.source_image_name, name);
9729 if (old_format) {
9730 ASSERT_EQ(status.source_image_id, "");
9731 } else {
9732 ASSERT_NE(status.source_image_id, "");
9733 ASSERT_EQ(-EROFS, rbd.trash_remove(ioctx, status.source_image_id.c_str(), false));
9734 ASSERT_EQ(-EINVAL, rbd.trash_restore(ioctx, status.source_image_id.c_str(), name.c_str()));
9735 }
9736 ASSERT_EQ(status.dest_pool_id, ioctx.get_id());
9737 ASSERT_EQ(status.dest_image_name, name);
9738 ASSERT_NE(status.dest_image_id, "");
9739 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
9740
f67539c2
TL
9741 librbd::Image image;
9742 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9743 std::string source_spec;
9744 ASSERT_EQ(0, image.get_migration_source_spec(&source_spec));
9745 json_spirit::mValue json_source_spec;
9746 json_spirit::read(source_spec, json_source_spec);
9747 json_spirit::mObject json_source_spec_obj = json_source_spec.get_obj();
9748 ASSERT_EQ("native", json_source_spec_obj["type"].get_str());
9749 ASSERT_EQ(ioctx.get_id(), json_source_spec_obj["pool_id"].get_int64());
9750 ASSERT_EQ("", json_source_spec_obj["pool_namespace"].get_str());
9751 ASSERT_EQ(1, json_source_spec_obj.count("image_name"));
9752 if (!old_format) {
9753 ASSERT_EQ(1, json_source_spec_obj.count("image_id"));
9754 }
9755 ASSERT_EQ(0, image.close());
9756
11fdf7f2
TL
9757 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, name.c_str()));
9758 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, name.c_str(), 0));
9759
9760 ASSERT_EQ(0, rbd.migration_execute(ioctx, name.c_str()));
9761
9762 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
9763 sizeof(status)));
9764 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
9765
9766 ASSERT_EQ(0, rbd.migration_commit(ioctx, name.c_str()));
9767
9768 std::string new_name = get_temp_image_name();
9769
9770 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx,
9771 new_name.c_str(), image_options));
9772
9773 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, new_name.c_str()));
9774 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, new_name.c_str(), 0));
9775
9776 ASSERT_EQ(0, rbd.migration_abort(ioctx, name.c_str()));
9777
11fdf7f2
TL
9778 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
9779}
9780
9781TEST_F(TestLibRBD, TestGetAccessTimestamp)
9782{
9783 REQUIRE_FORMAT_V2();
9784
9785 rados_ioctx_t ioctx;
9786 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9787
9788 rbd_image_t image;
9789 int order = 0;
9790 std::string name = get_temp_image_name();
9791 uint64_t size = 2 << 20;
9792 struct timespec timestamp;
9793
9794 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9795 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
9796
9797 ASSERT_EQ(0, rbd_get_access_timestamp(image, &timestamp));
9798 ASSERT_LT(0, timestamp.tv_sec);
9799
9800 ASSERT_PASSED(validate_object_map, image);
9801 ASSERT_EQ(0, rbd_close(image));
9802
9803 rados_ioctx_destroy(ioctx);
9804}
9805
9806TEST_F(TestLibRBD, TestGetModifyTimestamp)
9807{
9808 REQUIRE_FORMAT_V2();
9809
9810 rados_ioctx_t ioctx;
9811 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9812
9813 rbd_image_t image;
9814 int order = 0;
9815 std::string name = get_temp_image_name();
9816 uint64_t size = 2 << 20;
9817 struct timespec timestamp;
9818
9819 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
9820 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
9821 ASSERT_EQ(0, rbd_get_modify_timestamp(image, &timestamp));
9822 ASSERT_LT(0, timestamp.tv_sec);
9823
9824 ASSERT_PASSED(validate_object_map, image);
9825 ASSERT_EQ(0, rbd_close(image));
9826
9827 rados_ioctx_destroy(ioctx);
9828}
9829
91327a77
AA
9830TEST_F(TestLibRBD, ZeroOverlapFlatten) {
9831 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
9832
9833 librados::IoCtx ioctx;
9834 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9835
9836 librbd::RBD rbd;
9837 librbd::Image parent_image;
9838 std::string name = get_temp_image_name();
9839
9840 uint64_t size = 1;
9841 int order = 0;
9842
9843 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
9844 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
9845
9846 uint64_t features;
9847 ASSERT_EQ(0, parent_image.features(&features));
9848
9849 ASSERT_EQ(0, parent_image.snap_create("snap"));
9850 ASSERT_EQ(0, parent_image.snap_protect("snap"));
9851
9852 std::string clone_name = this->get_temp_image_name();
9853 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
9854 features, &order));
9855
9856 librbd::Image clone_image;
9857 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
9858 ASSERT_EQ(0, clone_image.resize(0));
9859 ASSERT_EQ(0, clone_image.flatten());
9860}
9861
11fdf7f2
TL
9862TEST_F(TestLibRBD, PoolMetadata)
9863{
9864 REQUIRE_FORMAT_V2();
9865
9866 rados_ioctx_t ioctx;
9867 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
9868
9869 char keys[1024];
9870 char vals[1024];
9871 size_t keys_len = sizeof(keys);
9872 size_t vals_len = sizeof(vals);
9873
9874 memset_rand(keys, keys_len);
9875 memset_rand(vals, vals_len);
9876
9877 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
9878 &vals_len));
9879 ASSERT_EQ(0U, keys_len);
9880 ASSERT_EQ(0U, vals_len);
9881
9882 char value[1024];
9883 size_t value_len = sizeof(value);
9884 memset_rand(value, value_len);
9885
9886 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
9887 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key2", "value2"));
9888 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
9889 ASSERT_STREQ(value, "value1");
9890 value_len = 1;
9891 ASSERT_EQ(-ERANGE, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
9892 ASSERT_EQ(value_len, strlen("value1") + 1);
9893
9894 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
9895 &vals_len));
9896 keys_len = sizeof(keys);
9897 vals_len = sizeof(vals);
9898 memset_rand(keys, keys_len);
9899 memset_rand(vals, vals_len);
9900 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
9901 &vals_len));
9902 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
9903 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
9904 ASSERT_STREQ(keys, "key1");
9905 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
9906 ASSERT_STREQ(vals, "value1");
9907 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
9908
9909 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
9910 ASSERT_EQ(-ENOENT, rbd_pool_metadata_remove(ioctx, "key3"));
9911 value_len = sizeof(value);
9912 ASSERT_EQ(-ENOENT, rbd_pool_metadata_get(ioctx, "key3", value, &value_len));
9913 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
9914 &vals_len));
9915 ASSERT_EQ(keys_len, strlen("key2") + 1);
9916 ASSERT_EQ(vals_len, strlen("value2") + 1);
9917 ASSERT_STREQ(keys, "key2");
9918 ASSERT_STREQ(vals, "value2");
9919
9920 // test config setting
9921 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
9922 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
9923 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
9924 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
9925
9926 // test short buffer cases
9927 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
9928 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key3", "value3"));
9929 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key4", "value4"));
9930
9931 keys_len = strlen("key1") + 1;
9932 vals_len = strlen("value1") + 1;
9933 memset_rand(keys, keys_len);
9934 memset_rand(vals, vals_len);
9935 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 1, keys, &keys_len, vals,
9936 &vals_len));
9937 ASSERT_EQ(keys_len, strlen("key1") + 1);
9938 ASSERT_EQ(vals_len, strlen("value1") + 1);
9939 ASSERT_STREQ(keys, "key1");
9940 ASSERT_STREQ(vals, "value1");
9941
9942 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 2, keys, &keys_len, vals,
9943 &vals_len));
9944 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
9945 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
9946
9947 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
9948 &vals_len));
9949 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
9950 1 + strlen("key4") + 1);
9951 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
9952 strlen("value3") + 1 + strlen("value4") + 1);
9953
9954 // test `start` param
9955 keys_len = sizeof(keys);
9956 vals_len = sizeof(vals);
9957 memset_rand(keys, keys_len);
9958 memset_rand(vals, vals_len);
9959 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "key2", 0, keys, &keys_len, vals,
9960 &vals_len));
9961 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
9962 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
9963 ASSERT_STREQ(keys, "key3");
9964 ASSERT_STREQ(vals, "value3");
9965
9966 //cleanup
9967 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
9968 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key2"));
9969 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key3"));
9970 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key4"));
9971 rados_ioctx_destroy(ioctx);
9972}
9973
9974TEST_F(TestLibRBD, PoolMetadataPP)
9975{
9976 REQUIRE_FORMAT_V2();
9977
9978 librbd::RBD rbd;
9979 string value;
9980 map<string, bufferlist> pairs;
9981
9982 librados::IoCtx ioctx;
9983 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
9984
9985 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
9986 ASSERT_TRUE(pairs.empty());
9987
9988 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
9989 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key2", "value2"));
9990 ASSERT_EQ(0, rbd.pool_metadata_get(ioctx, "key1", &value));
9991 ASSERT_EQ(value, "value1");
9992 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
9993 ASSERT_EQ(2U, pairs.size());
9994 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
9995 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
9996
9997 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
9998 ASSERT_EQ(-ENOENT, rbd.pool_metadata_remove(ioctx, "key3"));
9999 ASSERT_EQ(-ENOENT, rbd.pool_metadata_get(ioctx, "key3", &value));
10000 pairs.clear();
10001 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
10002 ASSERT_EQ(1U, pairs.size());
10003 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
10004
10005 // test `start` param
10006 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
10007 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key3", "value3"));
10008
10009 pairs.clear();
10010 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "key2", 0, &pairs));
10011 ASSERT_EQ(1U, pairs.size());
10012 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
10013
10014 // test config setting
10015 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
10016 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
10017 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
10018 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
10019
10020 // cleanup
10021 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
10022 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key2"));
10023 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key3"));
10024}
10025
10026TEST_F(TestLibRBD, Config)
10027{
10028 REQUIRE_FORMAT_V2();
10029
10030 rados_ioctx_t ioctx;
10031 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
10032
10033 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
10034
10035 rbd_config_option_t options[1024];
10036 int max_options = 0;
10037 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
10038 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
10039 ASSERT_GT(max_options, 0);
10040 ASSERT_LT(max_options, 1024);
10041 for (int i = 0; i < max_options; i++) {
10042 if (options[i].name == std::string("rbd_cache")) {
10043 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
10044 ASSERT_STREQ("false", options[i].value);
10045 } else {
10046 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
10047 }
10048 }
10049 rbd_config_pool_list_cleanup(options, max_options);
10050
10051 rbd_image_t image;
10052 int order = 0;
10053 std::string name = get_temp_image_name();
10054 uint64_t size = 2 << 20;
10055
10056 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
10057 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
10058
10059 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
10060 for (int i = 0; i < max_options; i++) {
10061 if (options[i].name == std::string("rbd_cache")) {
10062 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
10063 ASSERT_STREQ("false", options[i].value);
10064 } else {
10065 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
10066 }
10067 }
10068 rbd_config_image_list_cleanup(options, max_options);
10069
10070 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_cache", "true"));
10071
10072 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
10073 for (int i = 0; i < max_options; i++) {
10074 if (options[i].name == std::string("rbd_cache")) {
10075 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_IMAGE);
10076 ASSERT_STREQ("true", options[i].value);
10077 } else {
10078 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
10079 }
10080 }
10081 rbd_config_image_list_cleanup(options, max_options);
10082
10083 ASSERT_EQ(0, rbd_metadata_remove(image, "conf_rbd_cache"));
10084
10085 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
10086 for (int i = 0; i < max_options; i++) {
10087 if (options[i].name == std::string("rbd_cache")) {
10088 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
10089 ASSERT_STREQ("false", options[i].value);
10090 } else {
10091 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
10092 }
10093 }
10094 rbd_config_image_list_cleanup(options, max_options);
10095
10096 ASSERT_EQ(0, rbd_close(image));
10097
10098 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
10099
10100 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
10101 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
10102 for (int i = 0; i < max_options; i++) {
10103 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
10104 }
10105 rbd_config_pool_list_cleanup(options, max_options);
10106
10107 rados_ioctx_destroy(ioctx);
10108}
10109
10110TEST_F(TestLibRBD, ConfigPP)
10111{
10112 REQUIRE_FORMAT_V2();
10113
10114 librbd::RBD rbd;
10115 string value;
10116
10117 librados::IoCtx ioctx;
10118 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10119
10120 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
10121
10122 std::vector<librbd::config_option_t> options;
10123 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
10124 for (auto &option : options) {
10125 if (option.name == std::string("rbd_cache")) {
10126 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
10127 ASSERT_EQ("false", option.value);
10128 } else {
10129 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
10130 }
10131 }
10132
10133 int order = 0;
10134 std::string name = get_temp_image_name();
10135 uint64_t size = 2 << 20;
10136 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10137
10138 librbd::Image image;
10139 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
10140
10141 options.clear();
10142 ASSERT_EQ(0, image.config_list(&options));
10143 for (auto &option : options) {
10144 if (option.name == std::string("rbd_cache")) {
10145 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
10146 ASSERT_EQ("false", option.value);
10147 } else {
10148 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
10149 }
10150 }
10151
10152 ASSERT_EQ(0, image.metadata_set("conf_rbd_cache", "true"));
10153
10154 options.clear();
10155 ASSERT_EQ(0, image.config_list(&options));
10156 for (auto &option : options) {
10157 if (option.name == std::string("rbd_cache")) {
10158 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_IMAGE);
10159 ASSERT_EQ("true", option.value);
10160 } else {
10161 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
10162 }
10163 }
10164
10165 ASSERT_EQ(0, image.metadata_remove("conf_rbd_cache"));
10166
10167 options.clear();
10168 ASSERT_EQ(0, image.config_list(&options));
10169 for (auto &option : options) {
10170 if (option.name == std::string("rbd_cache")) {
10171 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
10172 ASSERT_EQ("false", option.value);
10173 } else {
10174 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
10175 }
10176 }
10177
10178 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
10179
10180 options.clear();
10181 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
10182 for (auto &option : options) {
10183 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
10184 }
10185}
10186
10187TEST_F(TestLibRBD, PoolStatsPP)
10188{
10189 REQUIRE_FORMAT_V2();
10190
10191 librados::IoCtx ioctx;
10192 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
10193
10194 librbd::RBD rbd;
10195 std::string image_name;
10196 uint64_t size = 2 << 20;
10197 uint64_t expected_size = 0;
10198 for (size_t idx = 0; idx < 4; ++idx) {
10199 image_name = get_temp_image_name();
10200
10201 int order = 0;
10202 ASSERT_EQ(0, create_image_pp(rbd, ioctx, image_name.c_str(), size, &order));
10203 expected_size += size;
10204 }
10205
10206 librbd::Image image;
10207 ASSERT_EQ(0, rbd.open(ioctx, image, image_name.c_str(), NULL));
10208 ASSERT_EQ(0, image.snap_create("snap1"));
10209 ASSERT_EQ(0, image.resize(0));
10210 ASSERT_EQ(0, image.close());
10211 uint64_t expect_head_size = (expected_size - size);
10212
10213 uint64_t image_count;
10214 uint64_t provisioned_bytes;
10215 uint64_t max_provisioned_bytes;
10216 uint64_t snap_count;
10217 uint64_t trash_image_count;
10218 uint64_t trash_provisioned_bytes;
10219 uint64_t trash_max_provisioned_bytes;
10220 uint64_t trash_snap_count;
10221
10222 librbd::PoolStats pool_stats1;
10223 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGES, &image_count);
10224 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
10225 &provisioned_bytes);
10226 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
10227
10228 ASSERT_EQ(4U, image_count);
10229 ASSERT_EQ(expect_head_size, provisioned_bytes);
10230
10231 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
10232 &max_provisioned_bytes);
10233 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
10234 ASSERT_EQ(4U, image_count);
10235 ASSERT_EQ(expect_head_size, provisioned_bytes);
10236 ASSERT_EQ(expected_size, max_provisioned_bytes);
10237
10238 librbd::PoolStats pool_stats2;
10239 pool_stats2.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snap_count);
10240 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
10241 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
10242 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats2));
10243 ASSERT_EQ(1U, snap_count);
10244 ASSERT_EQ(0U, trash_image_count);
10245 ASSERT_EQ(0U, trash_snap_count);
10246
10247 ASSERT_EQ(0, rbd.trash_move(ioctx, image_name.c_str(), 0));
10248
10249 librbd::PoolStats pool_stats3;
10250 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
10251 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
10252 &trash_provisioned_bytes);
10253 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
10254 &trash_max_provisioned_bytes);
10255 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
10256 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats3));
10257 ASSERT_EQ(1U, trash_image_count);
10258 ASSERT_EQ(0U, trash_provisioned_bytes);
10259 ASSERT_EQ(size, trash_max_provisioned_bytes);
10260 ASSERT_EQ(1U, trash_snap_count);
10261}
10262
10263TEST_F(TestLibRBD, ImageSpec) {
10264 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
10265
10266 librados::IoCtx ioctx;
10267 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
10268
10269 librbd::RBD rbd;
10270 librbd::Image parent_image;
10271 std::string name = get_temp_image_name();
10272
10273 uint64_t size = 1;
10274 int order = 0;
10275
10276 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10277 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
10278
10279 std::string parent_id;
10280 ASSERT_EQ(0, parent_image.get_id(&parent_id));
10281
10282 uint64_t features;
10283 ASSERT_EQ(0, parent_image.features(&features));
10284
10285 ASSERT_EQ(0, parent_image.snap_create("snap"));
10286 ASSERT_EQ(0, parent_image.snap_protect("snap"));
10287
10288 std::string clone_name = this->get_temp_image_name();
10289 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
10290 features, &order));
10291
10292 librbd::Image clone_image;
10293 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
10294
10295 std::string clone_id;
10296 ASSERT_EQ(0, clone_image.get_id(&clone_id));
10297
10298 std::vector<librbd::image_spec_t> images;
10299 ASSERT_EQ(0, rbd.list2(ioctx, &images));
10300
10301 std::vector<librbd::image_spec_t> expected_images{
10302 {.id = parent_id, .name = name},
10303 {.id = clone_id, .name = clone_name}
10304 };
10305 std::sort(expected_images.begin(), expected_images.end(),
10306 [](const librbd::image_spec_t& lhs, const librbd::image_spec_t &rhs) {
10307 return lhs.name < rhs.name;
10308 });
10309 ASSERT_EQ(expected_images, images);
10310
10311 librbd::linked_image_spec_t parent_image_spec;
10312 librbd::snap_spec_t parent_snap_spec;
10313 ASSERT_EQ(0, clone_image.get_parent(&parent_image_spec, &parent_snap_spec));
10314
10315 librbd::linked_image_spec_t expected_parent_image_spec{
10316 .pool_id = ioctx.get_id(),
10317 .pool_name = ioctx.get_pool_name(),
10318 .pool_namespace = ioctx.get_namespace(),
10319 .image_id = parent_id,
10320 .image_name = name,
10321 .trash = false
10322 };
10323 ASSERT_EQ(expected_parent_image_spec, parent_image_spec);
10324 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER, parent_snap_spec.namespace_type);
10325 ASSERT_EQ("snap", parent_snap_spec.name);
10326
10327 std::vector<librbd::linked_image_spec_t> children;
10328 ASSERT_EQ(0, parent_image.list_children3(&children));
10329
10330 std::vector<librbd::linked_image_spec_t> expected_children{
10331 {
10332 .pool_id = ioctx.get_id(),
10333 .pool_name = ioctx.get_pool_name(),
10334 .pool_namespace = ioctx.get_namespace(),
10335 .image_id = clone_id,
10336 .image_name = clone_name,
10337 .trash = false
10338 }
10339 };
10340 ASSERT_EQ(expected_children, children);
10341
10342 children.clear();
10343 ASSERT_EQ(0, parent_image.list_descendants(&children));
10344 ASSERT_EQ(expected_children, children);
10345
10346 ASSERT_EQ(0, clone_image.snap_create("snap"));
10347 ASSERT_EQ(0, clone_image.snap_protect("snap"));
10348
10349 auto grand_clone_name = this->get_temp_image_name();
10350 ASSERT_EQ(0, rbd.clone(ioctx, clone_name.c_str(), "snap", ioctx,
10351 grand_clone_name.c_str(), features, &order));
10352 librbd::Image grand_clone_image;
10353 ASSERT_EQ(0, rbd.open(ioctx, grand_clone_image, grand_clone_name.c_str(),
10354 nullptr));
10355 std::string grand_clone_id;
10356 ASSERT_EQ(0, grand_clone_image.get_id(&grand_clone_id));
10357
10358 children.clear();
10359 ASSERT_EQ(0, parent_image.list_children3(&children));
10360 ASSERT_EQ(expected_children, children);
10361
10362 children.clear();
10363 ASSERT_EQ(0, parent_image.list_descendants(&children));
10364 expected_children.push_back(
10365 {
10366 .pool_id = ioctx.get_id(),
10367 .pool_name = ioctx.get_pool_name(),
10368 .pool_namespace = ioctx.get_namespace(),
10369 .image_id = grand_clone_id,
10370 .image_name = grand_clone_name,
10371 .trash = false
10372 }
10373 );
10374 ASSERT_EQ(expected_children, children);
10375}
10376
9f95a23c
TL
10377void super_simple_write_cb_pp(librbd::completion_t cb, void *arg)
10378{
10379}
10380
10381TEST_F(TestLibRBD, DISABLED_TestSeqWriteAIOPP)
10382{
10383 librados::IoCtx ioctx;
10384 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10385
10386 {
10387 librbd::RBD rbd;
10388 librbd::Image image;
10389 int order = 21;
10390 std::string name = get_temp_image_name();
10391 uint64_t size = 5 * (1 << order);
10392
10393 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10394 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
10395
10396 char test_data[(TEST_IO_SIZE + 1) * 10];
10397
10398 for (int i = 0; i < 10; i++) {
10399 for (uint64_t j = 0; j < TEST_IO_SIZE; j++) {
10400 test_data[(TEST_IO_SIZE + 1) * i + j] = (char)(rand() % (126 - 33) + 33);
10401 }
10402 test_data[(TEST_IO_SIZE + 1) * i + TEST_IO_SIZE] = '\0';
10403 }
10404
10405 struct timespec start_time;
10406 clock_gettime(CLOCK_REALTIME, &start_time);
10407
10408 std::list<librbd::RBD::AioCompletion *> comps;
10409 for (uint64_t i = 0; i < size / TEST_IO_SIZE; ++i) {
10410 char *p = test_data + (TEST_IO_SIZE + 1) * (i % 10);
10411 ceph::bufferlist bl;
10412 bl.append(p, strlen(p));
10413 auto comp = new librbd::RBD::AioCompletion(
10414 NULL, (librbd::callback_t) super_simple_write_cb_pp);
10415 image.aio_write(strlen(p) * i, strlen(p), bl, comp);
10416 comps.push_back(comp);
10417 if (i % 1000 == 0) {
10418 cout << i << " reqs sent" << std::endl;
10419 image.flush();
10420 for (auto comp : comps) {
10421 comp->wait_for_complete();
10422 ASSERT_EQ(0, comp->get_return_value());
10423 comp->release();
10424 }
10425 comps.clear();
10426 }
10427 }
10428 int i = 0;
10429 for (auto comp : comps) {
10430 comp->wait_for_complete();
10431 ASSERT_EQ(0, comp->get_return_value());
10432 comp->release();
10433 if (i % 1000 == 0) {
10434 std::cout << i << " reqs completed" << std::endl;
10435 }
10436 i++;
10437 }
10438 comps.clear();
10439
f67539c2
TL
10440 struct timespec end_time;
10441 clock_gettime(CLOCK_REALTIME, &end_time);
10442 int duration = end_time.tv_sec * 1000 + end_time.tv_nsec / 1000000 -
10443 start_time.tv_sec * 1000 - start_time.tv_nsec / 1000000;
10444 std::cout << "duration: " << duration << " msec" << std::endl;
10445
10446 for (uint64_t i = 0; i < size / TEST_IO_SIZE; ++i) {
10447 char *p = test_data + (TEST_IO_SIZE + 1) * (i % 10);
10448 ASSERT_PASSED(read_test_data, image, p, strlen(p) * i, TEST_IO_SIZE, 0);
10449 }
10450
10451 ASSERT_PASSED(validate_object_map, image);
10452 }
10453
10454 ioctx.close();
10455}
10456
10457TEST_F(TestLibRBD, SnapRemoveWithChildMissing)
10458{
10459 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
10460 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
10461 BOOST_SCOPE_EXIT_ALL(&) {
10462 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
10463 };
10464
10465 librbd::RBD rbd;
10466 rados_ioctx_t ioctx1, ioctx2;
10467 string pool_name1 = create_pool(true);
10468 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
10469 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx2));
10470
10471 bool old_format;
10472 uint64_t features;
10473 rbd_image_t parent, child1, child2, child3;
10474 int order = 0;
10475 char child_id1[4096];
10476 char child_id2[4096];
10477 char child_id3[4096];
10478
10479 ASSERT_EQ(0, get_features(&old_format, &features));
10480 ASSERT_FALSE(old_format);
10481 std::string parent_name = get_temp_image_name();
10482 std::string child_name1 = get_temp_image_name();
10483 std::string child_name2 = get_temp_image_name();
10484 std::string child_name3 = get_temp_image_name();
10485 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
10486 false, features));
10487 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
10488 ASSERT_EQ(0, rbd_snap_create(parent, "snap1"));
10489 ASSERT_EQ(0, rbd_snap_create(parent, "snap2"));
10490
10491 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap1",
10492 ioctx2, child_name1.c_str(), features, &order));
10493 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
10494 ioctx1, child_name2.c_str(), features, &order));
10495 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
10496 ioctx2, child_name3.c_str(), features, &order));
10497
10498 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &child1, NULL));
10499 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &child2, NULL));
10500 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &child3, NULL));
10501 ASSERT_EQ(0, rbd_get_id(child1, child_id1, sizeof(child_id1)));
10502 ASSERT_EQ(0, rbd_get_id(child2, child_id2, sizeof(child_id2)));
10503 ASSERT_EQ(0, rbd_get_id(child3, child_id3, sizeof(child_id3)));
10504 test_list_children2(parent, 3,
10505 child_id1, m_pool_name.c_str(), child_name1.c_str(), false,
10506 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
10507 child_id3, m_pool_name.c_str(), child_name3.c_str(), false);
10508
10509 size_t max_size = 10;
10510 rbd_linked_image_spec_t children[max_size];
10511 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
10512 ASSERT_EQ(3, static_cast<int>(max_size));
10513 rbd_linked_image_spec_list_cleanup(children, max_size);
10514
10515 ASSERT_EQ(0, rbd_close(child1));
10516 ASSERT_EQ(0, rbd_close(child2));
10517 ASSERT_EQ(0, rbd_close(child3));
10518 rados_ioctx_destroy(ioctx2);
10519 ASSERT_EQ(0, rados_pool_delete(_cluster, m_pool_name.c_str()));
10520 _pool_names.erase(std::remove(_pool_names.begin(),
10521 _pool_names.end(), m_pool_name),
10522 _pool_names.end());
10523 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
10524
10525 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
10526 ASSERT_EQ(3, static_cast<int>(max_size));
10527 rbd_linked_image_spec_list_cleanup(children, max_size);
10528 ASSERT_EQ(0, rbd_snap_remove(parent, "snap1"));
10529 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
10530 ASSERT_EQ(2, static_cast<int>(max_size));
10531 rbd_linked_image_spec_list_cleanup(children, max_size);
10532
10533 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
10534 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
10535 ASSERT_EQ(1, static_cast<int>(max_size));
10536 rbd_linked_image_spec_list_cleanup(children, max_size);
10537
10538 ASSERT_EQ(0, rbd_snap_remove(parent, "snap2"));
10539 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
10540 ASSERT_EQ(0, static_cast<int>(max_size));
10541 rbd_linked_image_spec_list_cleanup(children, max_size);
10542 test_list_children2(parent, 0);
10543 ASSERT_EQ(0, test_ls_snaps(parent, 0));
10544
10545 ASSERT_EQ(0, rbd_close(parent));
10546 rados_ioctx_destroy(ioctx1);
10547}
10548
10549TEST_F(TestLibRBD, QuiesceWatch)
10550{
10551 rados_ioctx_t ioctx;
10552 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
10553
10554 int order = 0;
10555 std::string name = get_temp_image_name();
10556 uint64_t size = 2 << 20;
10557 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
10558
10559 rbd_image_t image1, image2;
10560 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
10561 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
10562
10563 struct Watcher {
10564 static void quiesce_cb(void *arg) {
10565 Watcher *watcher = static_cast<Watcher *>(arg);
10566 watcher->handle_quiesce();
10567 }
10568 static void unquiesce_cb(void *arg) {
10569 Watcher *watcher = static_cast<Watcher *>(arg);
10570 watcher->handle_unquiesce();
10571 }
10572
10573 rbd_image_t &image;
10574 uint64_t handle = 0;
10575 size_t quiesce_count = 0;
10576 size_t unquiesce_count = 0;
10577
10578 ceph::mutex lock = ceph::make_mutex("lock");
10579 ceph::condition_variable cv;
10580
10581 Watcher(rbd_image_t &image) : image(image) {
10582 }
10583
10584 void handle_quiesce() {
10585 ASSERT_EQ(quiesce_count, unquiesce_count);
10586 quiesce_count++;
10587 rbd_quiesce_complete(image, handle, 0);
10588 }
10589 void handle_unquiesce() {
10590 std::unique_lock locker(lock);
10591 unquiesce_count++;
10592 ASSERT_EQ(quiesce_count, unquiesce_count);
10593 cv.notify_one();
10594 }
10595 bool wait_for_unquiesce(size_t c) {
10596 std::unique_lock locker(lock);
10597 return cv.wait_for(locker, seconds(60),
10598 [this, c]() { return unquiesce_count >= c; });
10599 }
10600 } watcher1(image1), watcher2(image2);
10601
10602 ASSERT_EQ(0, rbd_quiesce_watch(image1, Watcher::quiesce_cb,
10603 Watcher::unquiesce_cb, &watcher1,
10604 &watcher1.handle));
10605 ASSERT_EQ(0, rbd_quiesce_watch(image2, Watcher::quiesce_cb,
10606 Watcher::unquiesce_cb, &watcher2,
10607 &watcher2.handle));
10608
10609 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
10610 ASSERT_EQ(1U, watcher1.quiesce_count);
10611 ASSERT_TRUE(watcher1.wait_for_unquiesce(1U));
10612 ASSERT_EQ(1U, watcher2.quiesce_count);
10613 ASSERT_TRUE(watcher2.wait_for_unquiesce(1U));
10614
10615 ASSERT_EQ(0, rbd_snap_create(image2, "snap2"));
10616 ASSERT_EQ(2U, watcher1.quiesce_count);
10617 ASSERT_TRUE(watcher1.wait_for_unquiesce(2U));
10618 ASSERT_EQ(2U, watcher2.quiesce_count);
10619 ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
10620
10621 ASSERT_EQ(0, rbd_quiesce_unwatch(image1, watcher1.handle));
10622
10623 ASSERT_EQ(0, rbd_snap_create(image1, "snap3"));
10624 ASSERT_EQ(2U, watcher1.quiesce_count);
10625 ASSERT_EQ(2U, watcher1.unquiesce_count);
10626 ASSERT_EQ(3U, watcher2.quiesce_count);
10627 ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
10628
10629 ASSERT_EQ(0, rbd_quiesce_unwatch(image2, watcher2.handle));
10630
10631 ASSERT_EQ(0, rbd_snap_remove(image1, "snap1"));
10632 ASSERT_EQ(0, rbd_snap_remove(image1, "snap2"));
10633 ASSERT_EQ(0, rbd_snap_remove(image1, "snap3"));
10634 ASSERT_EQ(0, rbd_close(image1));
10635 ASSERT_EQ(0, rbd_close(image2));
10636 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
10637 rados_ioctx_destroy(ioctx);
10638}
10639
10640TEST_F(TestLibRBD, QuiesceWatchPP)
10641{
10642 librbd::RBD rbd;
10643 librados::IoCtx ioctx;
10644 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10645 std::string name = get_temp_image_name();
10646 int order = 0;
10647 uint64_t size = 2 << 20;
10648 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10649
10650 {
10651 librbd::Image image1, image2;
10652 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
10653 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
10654
10655 struct Watcher : public librbd::QuiesceWatchCtx {
10656 librbd::Image &image;
10657 uint64_t handle = 0;
10658 size_t quiesce_count = 0;
10659 size_t unquiesce_count = 0;
10660
10661 ceph::mutex lock = ceph::make_mutex("lock");
10662 ceph::condition_variable cv;
10663
10664 Watcher(librbd::Image &image) : image(image) {
10665 }
10666
10667 void handle_quiesce() override {
10668 ASSERT_EQ(quiesce_count, unquiesce_count);
10669 quiesce_count++;
10670 image.quiesce_complete(handle, 0);
10671 }
10672 void handle_unquiesce() override {
10673 std::unique_lock locker(lock);
10674 unquiesce_count++;
10675 ASSERT_EQ(quiesce_count, unquiesce_count);
10676 cv.notify_one();
10677 }
10678 bool wait_for_unquiesce(size_t c) {
10679 std::unique_lock locker(lock);
10680 return cv.wait_for(locker, seconds(60),
10681 [this, c]() { return unquiesce_count >= c; });
10682 }
10683 } watcher1(image1), watcher2(image2);
10684
10685 ASSERT_EQ(0, image1.quiesce_watch(&watcher1, &watcher1.handle));
10686 ASSERT_EQ(0, image2.quiesce_watch(&watcher2, &watcher2.handle));
10687
10688 ASSERT_EQ(0, image1.snap_create("snap1"));
10689 ASSERT_EQ(1U, watcher1.quiesce_count);
10690 ASSERT_TRUE(watcher1.wait_for_unquiesce(1U));
10691 ASSERT_EQ(1U, watcher2.quiesce_count);
10692 ASSERT_TRUE(watcher2.wait_for_unquiesce(1U));
10693
10694 ASSERT_EQ(0, image2.snap_create("snap2"));
10695 ASSERT_EQ(2U, watcher1.quiesce_count);
10696 ASSERT_TRUE(watcher1.wait_for_unquiesce(2U));
10697 ASSERT_EQ(2U, watcher2.quiesce_count);
10698 ASSERT_TRUE(watcher2.wait_for_unquiesce(2U));
10699
10700 ASSERT_EQ(0, image1.quiesce_unwatch(watcher1.handle));
10701
10702 ASSERT_EQ(0, image1.snap_create("snap3"));
10703 ASSERT_EQ(2U, watcher1.quiesce_count);
10704 ASSERT_EQ(2U, watcher1.unquiesce_count);
10705 ASSERT_EQ(3U, watcher2.quiesce_count);
10706 ASSERT_TRUE(watcher2.wait_for_unquiesce(3U));
10707
10708 ASSERT_EQ(0, image2.quiesce_unwatch(watcher2.handle));
10709
10710 ASSERT_EQ(0, image1.snap_remove("snap1"));
10711 ASSERT_EQ(0, image1.snap_remove("snap2"));
10712 ASSERT_EQ(0, image1.snap_remove("snap3"));
10713 }
10714
10715 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
10716 ioctx.close();
10717}
10718
10719TEST_F(TestLibRBD, QuiesceWatchError)
10720{
10721 librbd::RBD rbd;
10722 librados::IoCtx ioctx;
10723 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10724 std::string name = get_temp_image_name();
10725 int order = 0;
10726 uint64_t size = 2 << 20;
10727 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10728
10729 {
10730 librbd::Image image1, image2;
10731 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
10732 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
10733
10734 struct Watcher : public librbd::QuiesceWatchCtx {
10735 librbd::Image &image;
10736 int r;
10737 uint64_t handle;
10738 size_t quiesce_count = 0;
10739 size_t unquiesce_count = 0;
10740
10741 ceph::mutex lock = ceph::make_mutex("lock");
10742 ceph::condition_variable cv;
10743
10744 Watcher(librbd::Image &image, int r) : image(image), r(r) {
10745 }
10746
10747 void reset_counters() {
10748 quiesce_count = 0;
10749 unquiesce_count = 0;
10750 }
9f95a23c 10751
f67539c2
TL
10752 void handle_quiesce() override {
10753 quiesce_count++;
10754 image.quiesce_complete(handle, r);
10755 }
9f95a23c 10756
f67539c2
TL
10757 void handle_unquiesce() override {
10758 std::unique_lock locker(lock);
10759 unquiesce_count++;
10760 cv.notify_one();
10761 }
9f95a23c 10762
f67539c2
TL
10763 bool wait_for_unquiesce() {
10764 std::unique_lock locker(lock);
10765 return cv.wait_for(locker, seconds(60),
10766 [this]() {
10767 return quiesce_count == unquiesce_count;
10768 });
10769 }
10770 } watcher10(image1, -EINVAL), watcher11(image1, 0), watcher20(image2, 0);
10771
10772 ASSERT_EQ(0, image1.quiesce_watch(&watcher10, &watcher10.handle));
10773 ASSERT_EQ(0, image1.quiesce_watch(&watcher11, &watcher11.handle));
10774 ASSERT_EQ(0, image2.quiesce_watch(&watcher20, &watcher20.handle));
10775
10776 ASSERT_EQ(-EINVAL, image1.snap_create("snap1"));
10777 ASSERT_GT(watcher10.quiesce_count, 0U);
10778 ASSERT_EQ(watcher10.unquiesce_count, 0U);
10779 ASSERT_GT(watcher11.quiesce_count, 0U);
10780 ASSERT_TRUE(watcher11.wait_for_unquiesce());
10781 ASSERT_GT(watcher20.quiesce_count, 0U);
10782 ASSERT_TRUE(watcher20.wait_for_unquiesce());
10783
10784 PrintProgress prog_ctx;
10785 watcher10.reset_counters();
10786 watcher11.reset_counters();
10787 watcher20.reset_counters();
10788 ASSERT_EQ(0, image2.snap_create2("snap2",
10789 RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
10790 prog_ctx));
10791 ASSERT_GT(watcher10.quiesce_count, 0U);
10792 ASSERT_EQ(watcher10.unquiesce_count, 0U);
10793 ASSERT_GT(watcher11.quiesce_count, 0U);
10794 ASSERT_TRUE(watcher11.wait_for_unquiesce());
10795 ASSERT_GT(watcher20.quiesce_count, 0U);
10796 ASSERT_TRUE(watcher20.wait_for_unquiesce());
10797
10798 ASSERT_EQ(0, image1.quiesce_unwatch(watcher10.handle));
10799
10800 watcher11.reset_counters();
10801 watcher20.reset_counters();
10802 ASSERT_EQ(0, image1.snap_create("snap3"));
10803 ASSERT_GT(watcher11.quiesce_count, 0U);
10804 ASSERT_TRUE(watcher11.wait_for_unquiesce());
10805 ASSERT_GT(watcher20.quiesce_count, 0U);
10806 ASSERT_TRUE(watcher20.wait_for_unquiesce());
10807
10808 ASSERT_EQ(0, image1.quiesce_unwatch(watcher11.handle));
10809
10810 watcher20.reset_counters();
10811 ASSERT_EQ(0, image2.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE,
10812 prog_ctx));
10813 ASSERT_EQ(watcher20.quiesce_count, 0U);
10814 ASSERT_EQ(watcher20.unquiesce_count, 0U);
10815
10816 ASSERT_EQ(0, image2.quiesce_unwatch(watcher20.handle));
10817
10818 ASSERT_EQ(0, image1.snap_remove("snap2"));
10819 ASSERT_EQ(0, image1.snap_remove("snap3"));
10820 ASSERT_EQ(0, image1.snap_remove("snap4"));
10821 }
10822
10823 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
9f95a23c
TL
10824 ioctx.close();
10825}
10826
f67539c2 10827TEST_F(TestLibRBD, QuiesceWatchTimeout)
92f5a8d4 10828{
f67539c2 10829 REQUIRE(!is_librados_test_stub(_rados));
92f5a8d4 10830
f67539c2 10831 ASSERT_EQ(0, _rados.conf_set("rbd_quiesce_notification_attempts", "2"));
92f5a8d4 10832
f67539c2
TL
10833 librbd::RBD rbd;
10834 librados::IoCtx ioctx;
10835 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10836 std::string name = get_temp_image_name();
92f5a8d4 10837 int order = 0;
f67539c2
TL
10838 uint64_t size = 2 << 20;
10839 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
92f5a8d4 10840
f67539c2
TL
10841 {
10842 librbd::Image image;
10843 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
92f5a8d4 10844
f67539c2
TL
10845 struct Watcher : public librbd::QuiesceWatchCtx {
10846 librbd::Image &image;
10847 std::mutex m_lock;
10848 std::condition_variable m_cond;
10849 size_t quiesce_count = 0;
10850 size_t unquiesce_count = 0;
92f5a8d4 10851
f67539c2
TL
10852 Watcher(librbd::Image &image) : image(image) {
10853 }
92f5a8d4 10854
f67539c2
TL
10855 void handle_quiesce() override {
10856 std::lock_guard<std::mutex> locker(m_lock);
10857 quiesce_count++;
10858 m_cond.notify_one();
10859 }
92f5a8d4 10860
f67539c2
TL
10861 void handle_unquiesce() override {
10862 std::lock_guard<std::mutex> locker(m_lock);
10863 unquiesce_count++;
10864 m_cond.notify_one();
10865 }
92f5a8d4 10866
f67539c2
TL
10867 void wait_for_quiesce() {
10868 std::unique_lock<std::mutex> locker(m_lock);
10869 ASSERT_TRUE(m_cond.wait_for(locker, seconds(60),
10870 [this] {
10871 return quiesce_count >= 1;
10872 }));
10873 }
92f5a8d4 10874
f67539c2
TL
10875 void wait_for_unquiesce() {
10876 std::unique_lock<std::mutex> locker(m_lock);
10877 ASSERT_TRUE(m_cond.wait_for(locker, seconds(60),
10878 [this] {
10879 return quiesce_count == unquiesce_count;
10880 }));
10881 quiesce_count = unquiesce_count = 0;
10882 }
10883 } watcher(image);
10884 uint64_t handle;
92f5a8d4 10885
f67539c2 10886 ASSERT_EQ(0, image.quiesce_watch(&watcher, &handle));
92f5a8d4 10887
f67539c2
TL
10888 std::cerr << "test quiesce is not long enough to time out" << std::endl;
10889
10890 thread quiesce1([&image, &watcher, handle]() {
10891 watcher.wait_for_quiesce();
10892 sleep(8);
10893 image.quiesce_complete(handle, 0);
10894 });
10895
10896 ASSERT_EQ(0, image.snap_create("snap1"));
10897 quiesce1.join();
10898 ASSERT_GE(watcher.quiesce_count, 1U);
10899 watcher.wait_for_unquiesce();
10900
10901 std::cerr << "test quiesce is timed out" << std::endl;
10902
10903 bool timed_out = false;
10904 thread quiesce2([&image, &watcher, handle, &timed_out]() {
10905 watcher.wait_for_quiesce();
10906 for (int i = 0; !timed_out && i < 60; i++) {
10907 std::cerr << "waiting for timed out ... " << i << std::endl;
10908 sleep(1);
10909 }
10910 image.quiesce_complete(handle, 0);
10911 });
10912
10913 ASSERT_EQ(-ETIMEDOUT, image.snap_create("snap2"));
10914 timed_out = true;
10915 quiesce2.join();
10916 ASSERT_GE(watcher.quiesce_count, 1U);
10917 watcher.wait_for_unquiesce();
10918
10919 thread quiesce3([&image, handle, &watcher]() {
10920 watcher.wait_for_quiesce();
10921 image.quiesce_complete(handle, 0);
10922 });
10923
10924 std::cerr << "test retry succeeds" << std::endl;
10925
10926 ASSERT_EQ(0, image.snap_create("snap2"));
10927 quiesce3.join();
10928 ASSERT_GE(watcher.quiesce_count, 1U);
10929 watcher.wait_for_unquiesce();
10930
10931 ASSERT_EQ(0, image.snap_remove("snap1"));
10932 ASSERT_EQ(0, image.snap_remove("snap2"));
10933 }
10934
10935 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
10936 ioctx.close();
92f5a8d4
TL
10937}
10938
f6b5b4d7
TL
10939TEST_F(TestLibRBD, WriteZeroes) {
10940 librbd::RBD rbd;
10941 librados::IoCtx ioctx;
10942 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
10943 std::string name = get_temp_image_name();
10944 int order = 0;
10945 uint64_t size = 2 << 20;
10946 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
10947
10948 librbd::Image image;
10949 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
10950
10951 // 1s from [0, 256) / length 256
10952 char data[256];
10953 memset(data, 1, sizeof(data));
10954 bufferlist bl;
10955 bl.append(data, 256);
10956 ASSERT_EQ(256, image.write(0, 256, bl));
10957
10958 interval_set<uint64_t> diff;
10959 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
10960 iterate_cb, (void *)&diff));
10961 auto expected_diff = interval_set<uint64_t>{{{0, 256}}};
10962 ASSERT_EQ(expected_diff, diff);
10963
10964 // writes zero passed the current end extents.
10965 // Now 1s from [0, 192) / length 192
10966 ASSERT_EQ(size - 192,
10967 image.write_zeroes(192, size - 192, 0U, 0));
10968 diff.clear();
10969 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
10970 iterate_cb, (void *)&diff));
10971 expected_diff = interval_set<uint64_t>{{{0, 192}}};
10972 ASSERT_EQ(expected_diff, diff);
10973
10974 // zero an existing extent and truncate some off the end
10975 // Now 1s from [64, 192) / length 192
10976 ASSERT_EQ(64, image.write_zeroes(0, 64, 0U, 0));
10977
10978 diff.clear();
10979 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
10980 iterate_cb, (void *)&diff));
10981 expected_diff = interval_set<uint64_t>{{{0, 192}}};
10982 ASSERT_EQ(expected_diff, diff);
10983
10984 bufferlist expected_bl;
10985 expected_bl.append_zero(64);
10986 bufferlist sub_bl;
10987 sub_bl.substr_of(bl, 0, 128);
10988 expected_bl.claim_append(sub_bl);
10989 expected_bl.append_zero(size - 192);
10990
10991 bufferlist read_bl;
10992 EXPECT_EQ(size, image.read(0, size, read_bl));
10993 EXPECT_EQ(expected_bl, read_bl);
10994
10995 ASSERT_EQ(0, image.close());
10996}
10997
f67539c2
TL
10998TEST_F(TestLibRBD, WriteZeroesThickProvision) {
10999 librbd::RBD rbd;
11000 librados::IoCtx ioctx;
11001 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
11002 std::string name = get_temp_image_name();
11003 int order = 0;
11004 uint64_t size = 2 << 20;
11005 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
11006
11007 librbd::Image image;
11008 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
11009
11010 interval_set<uint64_t> diff;
11011 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
11012 iterate_cb, (void *)&diff));
11013 auto expected_diff = interval_set<uint64_t>{{}};
11014 ASSERT_EQ(expected_diff, diff);
11015
11016 // writes unaligned zeroes as a prepend
11017 ASSERT_EQ(128, image.write_zeroes(
11018 0, 128, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
11019 diff.clear();
11020 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
11021 iterate_cb, (void *)&diff));
11022 expected_diff = interval_set<uint64_t>{{{0, 128}}};
11023 ASSERT_EQ(expected_diff, diff);
11024
11025 ASSERT_EQ(512, image.write_zeroes(
11026 384, 512, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
11027 diff.clear();
11028 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
11029 iterate_cb, (void *)&diff));
11030 expected_diff = interval_set<uint64_t>{{{0, 896}}};
11031 ASSERT_EQ(expected_diff, diff);
11032
11033 // prepend with write-same
11034 ASSERT_EQ(640, image.write_zeroes(
11035 896, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
11036 diff.clear();
11037 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
11038 iterate_cb, (void *)&diff));
11039 expected_diff = interval_set<uint64_t>{{{0, 1536}}};
11040 ASSERT_EQ(expected_diff, diff);
11041
11042 // write-same with append
11043 ASSERT_EQ(640, image.write_zeroes(
11044 1536, 640, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
11045 diff.clear();
11046 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
11047 iterate_cb, (void *)&diff));
11048 expected_diff = interval_set<uint64_t>{{{0, 2176}}};
11049 ASSERT_EQ(expected_diff, diff);
11050
11051 // prepend + write-same + append
11052 ASSERT_EQ(768, image.write_zeroes(
11053 2176, 768, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
11054 diff.clear();
11055 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
11056 iterate_cb, (void *)&diff));
11057 expected_diff = interval_set<uint64_t>{{{0, 2944}}};
11058
11059 // write-same
11060 ASSERT_EQ(1024, image.write_zeroes(
11061 3072, 1024, RBD_WRITE_ZEROES_FLAG_THICK_PROVISION, 0));
11062 diff.clear();
11063 ASSERT_EQ(0, image.diff_iterate2(nullptr, 0, size, false, false,
11064 iterate_cb, (void *)&diff));
11065 expected_diff = interval_set<uint64_t>{{{0, 4096}}};
11066
11067 bufferlist expected_bl;
11068 expected_bl.append_zero(size);
11069
11070 bufferlist read_bl;
11071 EXPECT_EQ(size, image.read(0, size, read_bl));
11072 EXPECT_EQ(expected_bl, read_bl);
11073
11074 ASSERT_EQ(0, image.close());
11075}
11076
11077TEST_F(TestLibRBD, ConcurentOperations)
11078{
11079 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
11080
11081 librbd::RBD rbd;
11082 librados::IoCtx ioctx;
11083 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
11084 std::string name = get_temp_image_name();
11085 int order = 0;
11086 uint64_t size = 2 << 20;
11087 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
11088
11089 // Test creating/removing many snapshots simultaneously
11090
11091 std::vector<librbd::Image> images(10);
11092 std::vector<librbd::RBD::AioCompletion *> comps;
11093
11094 for (auto &image : images) {
11095 auto comp = new librbd::RBD::AioCompletion(NULL, NULL);
11096 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, comp));
11097 comps.push_back(comp);
11098 }
11099
11100 for (auto &comp : comps) {
11101 ASSERT_EQ(0, comp->wait_for_complete());
11102 ASSERT_EQ(1, comp->is_complete());
11103 ASSERT_EQ(0, comp->get_return_value());
11104 comp->release();
11105 }
11106 comps.clear();
11107
11108 std::vector<std::thread> threads;
11109 int i = 0;
11110 for (auto &image : images) {
11111 std::string snap_name = "snap" + stringify(i++);
11112 threads.emplace_back([&image, snap_name]() {
11113 int r = image.snap_create(snap_name.c_str());
11114 ceph_assert(r == 0);
11115 });
11116 }
11117
11118 for (auto &t : threads) {
11119 t.join();
11120 }
11121 threads.clear();
11122
11123 i = 0;
11124 for (auto &image : images) {
11125 std::string snap_name = "snap" + stringify(i++);
11126 threads.emplace_back([&image, snap_name](){
11127 int r = image.snap_remove(snap_name.c_str());
11128 ceph_assert(r == 0);
11129 });
11130 }
11131
11132 for (auto &t : threads) {
11133 t.join();
11134 }
11135 threads.clear();
11136
11137 for (auto &image : images) {
11138 auto comp = new librbd::RBD::AioCompletion(NULL, NULL);
11139 ASSERT_EQ(0, image.aio_close(comp));
11140 comps.push_back(comp);
11141 }
11142
11143 for (auto &comp : comps) {
11144 ASSERT_EQ(0, comp->wait_for_complete());
11145 ASSERT_EQ(1, comp->is_complete());
11146 ASSERT_EQ(0, comp->get_return_value());
11147 comp->release();
11148 }
11149 comps.clear();
11150
11151 // Test shutdown
11152 {
11153 librbd::Image image1, image2, image3;
11154 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
11155 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
11156 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
11157
11158 ASSERT_EQ(0, image1.lock_acquire(RBD_LOCK_MODE_EXCLUSIVE));
11159
11160 struct Watcher : public librbd::QuiesceWatchCtx {
11161 size_t count = 0;
11162
11163 ceph::mutex lock = ceph::make_mutex("lock");
11164 ceph::condition_variable cv;
11165
11166 void handle_quiesce() override {
11167 std::unique_lock locker(lock);
11168 count++;
11169 cv.notify_one();
11170 }
11171
11172 void handle_unquiesce() override {
11173 }
11174
11175 bool wait_for_quiesce(size_t c) {
11176 std::unique_lock locker(lock);
11177 return cv.wait_for(locker, seconds(60),
11178 [this, c]() { return count >= c; });
11179 }
11180 } watcher;
11181 uint64_t handle;
11182 ASSERT_EQ(0, image2.quiesce_watch(&watcher, &handle));
11183
11184 auto close1_comp = new librbd::RBD::AioCompletion(NULL, NULL);
11185
11186 std::thread create_snap1([&image1, close1_comp]() {
11187 int r = image1.snap_create("snap1");
11188 ceph_assert(r == 0);
11189 r = image1.aio_close(close1_comp);
11190 ceph_assert(r == 0);
11191 });
11192
11193 ASSERT_TRUE(watcher.wait_for_quiesce(1));
11194
11195 std::thread create_snap2([&image2]() {
11196 int r = image2.snap_create("snap2");
11197 ceph_assert(r == 0);
11198 });
11199
11200 std::thread create_snap3([&image3]() {
11201 int r = image3.snap_create("snap3");
11202 ceph_assert(r == 0);
11203 });
11204
11205 image2.quiesce_complete(handle, 0);
11206 create_snap1.join();
11207
11208 ASSERT_TRUE(watcher.wait_for_quiesce(2));
11209 image2.quiesce_complete(handle, 0);
11210
11211 ASSERT_TRUE(watcher.wait_for_quiesce(3));
11212 image2.quiesce_complete(handle, 0);
11213
11214 ASSERT_EQ(0, close1_comp->wait_for_complete());
11215 ASSERT_EQ(1, close1_comp->is_complete());
11216 ASSERT_EQ(0, close1_comp->get_return_value());
11217 close1_comp->release();
11218
11219 create_snap2.join();
11220 create_snap3.join();
11221
11222 ASSERT_EQ(0, image2.quiesce_unwatch(handle));
11223 ASSERT_EQ(0, image2.snap_remove("snap1"));
11224 ASSERT_EQ(0, image2.snap_remove("snap2"));
11225 ASSERT_EQ(0, image2.snap_remove("snap3"));
11226 }
11227
11228 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
11229 ioctx.close();
11230}
11231
11232
11fdf7f2 11233// poorman's ceph_assert()
31f18b77
FG
11234namespace ceph {
11235 void __ceph_assert_fail(const char *assertion, const char *file, int line,
11236 const char *func) {
11fdf7f2 11237 ceph_abort();
31f18b77
FG
11238 }
11239}
11fdf7f2
TL
11240
11241#pragma GCC diagnostic pop
11242#pragma GCC diagnostic warning "-Wpragmas"