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