]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/test_librbd.cc
import new upstream nautilus stable release 14.2.8
[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, TestCreateLsRenameSnapPP)
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 uint64_t size2 = 4 << 20;
1550
1551 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1552 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1553
1554 bool exists;
1555 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1556 ASSERT_FALSE(exists);
1557 ASSERT_EQ(0, image.snap_create("snap1"));
1558 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1559 ASSERT_TRUE(exists);
1560 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1561 ASSERT_EQ(0, image.resize(size2));
1562 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1563 ASSERT_FALSE(exists);
1564 ASSERT_EQ(0, image.snap_create("snap2"));
1565 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1566 ASSERT_TRUE(exists);
1567 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1568 ASSERT_EQ(0, image.snap_rename("snap1","snap1-rename"));
1569 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1-rename", size, "snap2", size2));
1570 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1571 ASSERT_FALSE(exists);
1572 ASSERT_EQ(0, image.snap_exists2("snap1-rename", &exists));
1573 ASSERT_TRUE(exists);
1574 ASSERT_EQ(0, image.snap_remove("snap1-rename"));
1575 ASSERT_EQ(0, image.snap_rename("snap2","snap2-rename"));
1576 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2-rename", size2));
1577 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1578 ASSERT_FALSE(exists);
1579 ASSERT_EQ(0, image.snap_exists2("snap2-rename", &exists));
1580 ASSERT_TRUE(exists);
1581 ASSERT_EQ(0, image.snap_remove("snap2-rename"));
1582 ASSERT_EQ(0, test_ls_snaps(image, 0));
1583 }
1584
1585 ioctx.close();
1586 }
1587
1588 void simple_write_cb(rbd_completion_t cb, void *arg)
1589 {
1590 printf("write completion cb called!\n");
1591 }
1592
1593 void simple_read_cb(rbd_completion_t cb, void *arg)
1594 {
1595 printf("read completion cb called!\n");
1596 }
1597
1598 void aio_write_test_data_and_poll(rbd_image_t image, int fd, const char *test_data,
1599 uint64_t off, size_t len, uint32_t iohint, bool *passed)
1600 {
1601 rbd_completion_t comp;
1602 uint64_t data = 0x123;
1603 rbd_aio_create_completion((void*)&data, (rbd_callback_t) simple_write_cb, &comp);
1604 printf("created completion\n");
1605 printf("started write\n");
1606 if (iohint)
1607 rbd_aio_write2(image, off, len, test_data, comp, iohint);
1608 else
1609 rbd_aio_write(image, off, len, test_data, comp);
1610
1611 struct pollfd pfd;
1612 pfd.fd = fd;
1613 pfd.events = POLLIN;
1614
1615 ASSERT_EQ(1, poll(&pfd, 1, -1));
1616 ASSERT_TRUE(pfd.revents & POLLIN);
1617
1618 rbd_completion_t comps[1];
1619 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
1620 uint64_t count;
1621 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
1622 read(fd, &count, sizeof(count)));
1623 int r = rbd_aio_get_return_value(comps[0]);
1624 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
1625 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps[0]) == data);
1626 printf("return value is: %d\n", r);
1627 ASSERT_EQ(0, r);
1628 printf("finished write\n");
1629 rbd_aio_release(comps[0]);
1630 *passed = true;
1631 }
1632
1633 void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1634 {
1635 rbd_completion_t comp;
1636 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1637 printf("created completion\n");
1638 if (iohint)
1639 rbd_aio_write2(image, off, len, test_data, comp, iohint);
1640 else
1641 rbd_aio_write(image, off, len, test_data, comp);
1642 printf("started write\n");
1643 rbd_aio_wait_for_complete(comp);
1644 int r = rbd_aio_get_return_value(comp);
1645 printf("return value is: %d\n", r);
1646 ASSERT_EQ(0, r);
1647 printf("finished write\n");
1648 rbd_aio_release(comp);
1649 *passed = true;
1650 }
1651
1652 void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1653 {
1654 ssize_t written;
1655 if (iohint)
1656 written = rbd_write2(image, off, len, test_data, iohint);
1657 else
1658 written = rbd_write(image, off, len, test_data);
1659 printf("wrote: %d\n", (int) written);
1660 ASSERT_EQ(len, static_cast<size_t>(written));
1661 *passed = true;
1662 }
1663
1664 void aio_discard_test_data(rbd_image_t image, uint64_t off, uint64_t len, bool *passed)
1665 {
1666 rbd_completion_t comp;
1667 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1668 rbd_aio_discard(image, off, len, comp);
1669 rbd_aio_wait_for_complete(comp);
1670 int r = rbd_aio_get_return_value(comp);
1671 ASSERT_EQ(0, r);
1672 printf("aio discard: %d~%d = %d\n", (int)off, (int)len, (int)r);
1673 rbd_aio_release(comp);
1674 *passed = true;
1675 }
1676
1677 void discard_test_data(rbd_image_t image, uint64_t off, size_t len, bool *passed)
1678 {
1679 ssize_t written;
1680 written = rbd_discard(image, off, len);
1681 printf("discard: %d~%d = %d\n", (int)off, (int)len, (int)written);
1682 ASSERT_EQ(len, static_cast<size_t>(written));
1683 *passed = true;
1684 }
1685
1686 void aio_read_test_data_and_poll(rbd_image_t image, int fd, const char *expected,
1687 uint64_t off, size_t len, uint32_t iohint, bool *passed)
1688 {
1689 rbd_completion_t comp;
1690 char *result = (char *)malloc(len + 1);
1691
1692 ASSERT_NE(static_cast<char *>(NULL), result);
1693 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1694 printf("created completion\n");
1695 printf("started read\n");
1696 if (iohint)
1697 rbd_aio_read2(image, off, len, result, comp, iohint);
1698 else
1699 rbd_aio_read(image, off, len, result, comp);
1700
1701 struct pollfd pfd;
1702 pfd.fd = fd;
1703 pfd.events = POLLIN;
1704
1705 ASSERT_EQ(1, poll(&pfd, 1, -1));
1706 ASSERT_TRUE(pfd.revents & POLLIN);
1707
1708 rbd_completion_t comps[1];
1709 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
1710 uint64_t count;
1711 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
1712 read(fd, &count, sizeof(count)));
1713
1714 int r = rbd_aio_get_return_value(comps[0]);
1715 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
1716 printf("return value is: %d\n", r);
1717 ASSERT_EQ(len, static_cast<size_t>(r));
1718 rbd_aio_release(comps[0]);
1719 if (memcmp(result, expected, len)) {
1720 printf("read: %s\nexpected: %s\n", result, expected);
1721 ASSERT_EQ(0, memcmp(result, expected, len));
1722 }
1723 free(result);
1724 *passed = true;
1725 }
1726
1727 void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1728 {
1729 rbd_completion_t comp;
1730 char *result = (char *)malloc(len + 1);
1731
1732 ASSERT_NE(static_cast<char *>(NULL), result);
1733 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1734 printf("created completion\n");
1735 if (iohint)
1736 rbd_aio_read2(image, off, len, result, comp, iohint);
1737 else
1738 rbd_aio_read(image, off, len, result, comp);
1739 printf("started read\n");
1740 rbd_aio_wait_for_complete(comp);
1741 int r = rbd_aio_get_return_value(comp);
1742 printf("return value is: %d\n", r);
1743 ASSERT_EQ(len, static_cast<size_t>(r));
1744 rbd_aio_release(comp);
1745 if (memcmp(result, expected, len)) {
1746 printf("read: %s\nexpected: %s\n", result, expected);
1747 ASSERT_EQ(0, memcmp(result, expected, len));
1748 }
1749 free(result);
1750 *passed = true;
1751 }
1752
1753 void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1754 {
1755 ssize_t read;
1756 char *result = (char *)malloc(len + 1);
1757
1758 ASSERT_NE(static_cast<char *>(NULL), result);
1759 if (iohint)
1760 read = rbd_read2(image, off, len, result, iohint);
1761 else
1762 read = rbd_read(image, off, len, result);
1763 printf("read: %d\n", (int) read);
1764 ASSERT_EQ(len, static_cast<size_t>(read));
1765 result[len] = '\0';
1766 if (memcmp(result, expected, len)) {
1767 printf("read: %s\nexpected: %s\n", result, expected);
1768 ASSERT_EQ(0, memcmp(result, expected, len));
1769 }
1770 free(result);
1771 *passed = true;
1772 }
1773
1774 void aio_writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
1775 uint64_t data_len, uint32_t iohint, bool *passed)
1776 {
1777 rbd_completion_t comp;
1778 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1779 printf("created completion\n");
1780 int r;
1781 r = rbd_aio_writesame(image, off, len, test_data, data_len, comp, iohint);
1782 printf("started writesame\n");
1783 if (len % data_len) {
1784 ASSERT_EQ(-EINVAL, r);
1785 printf("expected fail, finished writesame\n");
1786 rbd_aio_release(comp);
1787 *passed = true;
1788 return;
1789 }
1790
1791 rbd_aio_wait_for_complete(comp);
1792 r = rbd_aio_get_return_value(comp);
1793 printf("return value is: %d\n", r);
1794 ASSERT_EQ(0, r);
1795 printf("finished writesame\n");
1796 rbd_aio_release(comp);
1797
1798 //verify data
1799 printf("to verify the data\n");
1800 ssize_t read;
1801 char *result = (char *)malloc(data_len+ 1);
1802 ASSERT_NE(static_cast<char *>(NULL), result);
1803 uint64_t left = len;
1804 while (left > 0) {
1805 read = rbd_read(image, off, data_len, result);
1806 ASSERT_EQ(data_len, static_cast<size_t>(read));
1807 result[data_len] = '\0';
1808 if (memcmp(result, test_data, data_len)) {
1809 printf("read: %d ~ %d\n", (int) off, (int) read);
1810 printf("read: %s\nexpected: %s\n", result, test_data);
1811 ASSERT_EQ(0, memcmp(result, test_data, data_len));
1812 }
1813 off += data_len;
1814 left -= data_len;
1815 }
1816 ASSERT_EQ(0U, left);
1817 free(result);
1818 printf("verified\n");
1819
1820 *passed = true;
1821 }
1822
1823 void writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
1824 uint64_t data_len, uint32_t iohint, bool *passed)
1825 {
1826 ssize_t written;
1827 written = rbd_writesame(image, off, len, test_data, data_len, iohint);
1828 if (len % data_len) {
1829 ASSERT_EQ(-EINVAL, written);
1830 printf("expected fail, finished writesame\n");
1831 *passed = true;
1832 return;
1833 }
1834 ASSERT_EQ(len, static_cast<size_t>(written));
1835 printf("wrote: %d\n", (int) written);
1836
1837 //verify data
1838 printf("to verify the data\n");
1839 ssize_t read;
1840 char *result = (char *)malloc(data_len+ 1);
1841 ASSERT_NE(static_cast<char *>(NULL), result);
1842 uint64_t left = len;
1843 while (left > 0) {
1844 read = rbd_read(image, off, data_len, result);
1845 ASSERT_EQ(data_len, static_cast<size_t>(read));
1846 result[data_len] = '\0';
1847 if (memcmp(result, test_data, data_len)) {
1848 printf("read: %d ~ %d\n", (int) off, (int) read);
1849 printf("read: %s\nexpected: %s\n", result, test_data);
1850 ASSERT_EQ(0, memcmp(result, test_data, data_len));
1851 }
1852 off += data_len;
1853 left -= data_len;
1854 }
1855 ASSERT_EQ(0U, left);
1856 free(result);
1857 printf("verified\n");
1858
1859 *passed = true;
1860 }
1861
1862 void aio_compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
1863 const char *test_data, uint64_t off,
1864 size_t len, uint32_t iohint, bool *passed)
1865 {
1866 rbd_completion_t comp;
1867 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1868 printf("created completion\n");
1869
1870 uint64_t mismatch_offset;
1871 rbd_aio_compare_and_write(image, off, len, cmp_data, test_data, comp, &mismatch_offset, iohint);
1872 printf("started aio compare and write\n");
1873 rbd_aio_wait_for_complete(comp);
1874 int r = rbd_aio_get_return_value(comp);
1875 printf("return value is: %d\n", r);
1876 ASSERT_EQ(0, r);
1877 printf("finished aio compare and write\n");
1878 rbd_aio_release(comp);
1879 *passed = true;
1880 }
1881
1882 void compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
1883 const char *test_data, uint64_t off, size_t len,
1884 uint64_t *mismatch_off, uint32_t iohint, bool *passed)
1885 {
1886 printf("start compare and write\n");
1887 ssize_t written;
1888 written = rbd_compare_and_write(image, off, len, cmp_data, test_data, mismatch_off, iohint);
1889 printf("compare and wrote: %d\n", (int) written);
1890 ASSERT_EQ(len, static_cast<size_t>(written));
1891 *passed = true;
1892 }
1893
1894
1895 TEST_F(TestLibRBD, TestIO)
1896 {
1897 rados_ioctx_t ioctx;
1898 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1899
1900 bool skip_discard = is_skip_partial_discard_enabled();
1901
1902 rbd_image_t image;
1903 int order = 0;
1904 std::string name = get_temp_image_name();
1905 uint64_t size = 2 << 20;
1906
1907 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1908 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1909
1910 char test_data[TEST_IO_SIZE + 1];
1911 char zero_data[TEST_IO_SIZE + 1];
1912 char mismatch_data[TEST_IO_SIZE + 1];
1913 int i;
1914 uint64_t mismatch_offset;
1915
1916 for (i = 0; i < TEST_IO_SIZE; ++i) {
1917 test_data[i] = (char) (rand() % (126 - 33) + 33);
1918 }
1919 test_data[TEST_IO_SIZE] = '\0';
1920 memset(zero_data, 0, sizeof(zero_data));
1921 memset(mismatch_data, 9, sizeof(mismatch_data));
1922
1923 for (i = 0; i < 5; ++i)
1924 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1925
1926 for (i = 5; i < 10; ++i)
1927 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1928
1929 for (i = 0; i < 5; ++i)
1930 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, 0);
1931
1932 for (i = 5; i < 10; ++i)
1933 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1934
1935 for (i = 0; i < 5; ++i)
1936 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1937
1938 for (i = 5; i < 10; ++i)
1939 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1940
1941 // discard 2nd, 4th sections.
1942 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
1943 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
1944
1945 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
1946 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1947 TEST_IO_SIZE, TEST_IO_SIZE, 0);
1948 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
1949 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1950 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
1951 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
1952
1953 for (i = 0; i < 15; ++i) {
1954 if (i % 3 == 2) {
1955 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1956 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1957 } else if (i % 3 == 1) {
1958 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1959 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1960 } else {
1961 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1962 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1963 }
1964 }
1965 for (i = 0; i < 15; ++i) {
1966 if (i % 3 == 2) {
1967 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1968 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1969 } else if (i % 3 == 1) {
1970 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1971 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1972 } else {
1973 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1974 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1975 }
1976 }
1977
1978 rbd_image_info_t info;
1979 rbd_completion_t comp;
1980 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1981 // can't read or write starting past end
1982 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
1983 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
1984 // reading through end returns amount up to end
1985 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
1986 // writing through end returns amount up to end
1987 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
1988
1989 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1990 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
1991 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1992 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1993 rbd_aio_release(comp);
1994
1995 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1996 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
1997 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1998 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1999 rbd_aio_release(comp);
2000
2001 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2002 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data, &mismatch_offset, 0));
2003 ASSERT_EQ(0U, mismatch_offset);
2004 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2005 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data, comp, &mismatch_offset, 0));
2006 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2007 ASSERT_EQ(0U, mismatch_offset);
2008 rbd_aio_release(comp);
2009
2010 ASSERT_PASSED(validate_object_map, image);
2011 ASSERT_EQ(0, rbd_close(image));
2012
2013 rados_ioctx_destroy(ioctx);
2014 }
2015
2016 TEST_F(TestLibRBD, TestIOWithIOHint)
2017 {
2018 rados_ioctx_t ioctx;
2019 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2020
2021 bool skip_discard = is_skip_partial_discard_enabled();
2022
2023 rbd_image_t image;
2024 int order = 0;
2025 std::string name = get_temp_image_name();
2026 uint64_t size = 2 << 20;
2027
2028 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2029 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2030
2031 char test_data[TEST_IO_SIZE + 1];
2032 char zero_data[TEST_IO_SIZE + 1];
2033 char mismatch_data[TEST_IO_SIZE + 1];
2034 int i;
2035 uint64_t mismatch_offset;
2036
2037 for (i = 0; i < TEST_IO_SIZE; ++i) {
2038 test_data[i] = (char) (rand() % (126 - 33) + 33);
2039 }
2040 test_data[TEST_IO_SIZE] = '\0';
2041 memset(zero_data, 0, sizeof(zero_data));
2042 memset(mismatch_data, 9, sizeof(mismatch_data));
2043
2044 for (i = 0; i < 5; ++i)
2045 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
2046 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2047
2048 for (i = 5; i < 10; ++i)
2049 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
2050 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2051
2052 for (i = 0; i < 5; ++i)
2053 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
2054 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2055
2056 for (i = 5; i < 10; ++i)
2057 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
2058 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2059
2060 for (i = 0; i < 5; ++i)
2061 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE,
2062 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2063
2064 for (i = 5; i < 10; ++i)
2065 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
2066 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2067
2068 // discard 2nd, 4th sections.
2069 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2070 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2071
2072 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE,
2073 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2074 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2075 TEST_IO_SIZE, TEST_IO_SIZE,
2076 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2077 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE,
2078 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2079 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2080 TEST_IO_SIZE*3, TEST_IO_SIZE,
2081 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
2082 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2083
2084 for (i = 0; i < 15; ++i) {
2085 if (i % 3 == 2) {
2086 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2087 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2088 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2089 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2090 } else if (i % 3 == 1) {
2091 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2092 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2093 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2094 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2095 } else {
2096 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2097 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2098 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2099 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2100 }
2101 }
2102 for (i = 0; i < 15; ++i) {
2103 if (i % 3 == 2) {
2104 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2105 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2106 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
2107 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2108 } else if (i % 3 == 1) {
2109 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2110 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2111 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
2112 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2113 } else {
2114 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2115 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2116 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
2117 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2118 }
2119 }
2120
2121 rbd_image_info_t info;
2122 rbd_completion_t comp;
2123 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
2124 // can't read or write starting past end
2125 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
2126 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
2127 // reading through end returns amount up to end
2128 ASSERT_EQ(10, rbd_read2(image, info.size - 10, 100, test_data,
2129 LIBRADOS_OP_FLAG_FADVISE_NOCACHE));
2130 // writing through end returns amount up to end
2131 ASSERT_EQ(10, rbd_write2(image, info.size - 10, 100, test_data,
2132 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2133
2134 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2135 ASSERT_EQ(0, rbd_aio_read2(image, info.size, 1, test_data, comp,
2136 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2137 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2138 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2139 rbd_aio_release(comp);
2140
2141 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2142 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
2143 &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2144 ASSERT_EQ(0U, mismatch_offset);
2145 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2146 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
2147 comp, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
2148 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2149 ASSERT_EQ(0U, mismatch_offset);
2150 rbd_aio_release(comp);
2151
2152 ASSERT_PASSED(validate_object_map, image);
2153 ASSERT_EQ(0, rbd_close(image));
2154
2155 rados_ioctx_destroy(ioctx);
2156 }
2157
2158 TEST_F(TestLibRBD, TestDataPoolIO)
2159 {
2160 REQUIRE_FORMAT_V2();
2161
2162 rados_ioctx_t ioctx;
2163 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2164
2165 std::string data_pool_name = create_pool(true);
2166
2167 bool skip_discard = is_skip_partial_discard_enabled();
2168
2169 rbd_image_t image;
2170 std::string name = get_temp_image_name();
2171 uint64_t size = 2 << 20;
2172
2173 bool old_format;
2174 uint64_t features;
2175 ASSERT_EQ(0, get_features(&old_format, &features));
2176 ASSERT_FALSE(old_format);
2177
2178 rbd_image_options_t image_options;
2179 rbd_image_options_create(&image_options);
2180 BOOST_SCOPE_EXIT( (&image_options) ) {
2181 rbd_image_options_destroy(image_options);
2182 } BOOST_SCOPE_EXIT_END;
2183
2184 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
2185 RBD_IMAGE_OPTION_FEATURES,
2186 features));
2187 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
2188 RBD_IMAGE_OPTION_DATA_POOL,
2189 data_pool_name.c_str()));
2190
2191 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
2192 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2193 ASSERT_NE(-1, rbd_get_data_pool_id(image));
2194
2195 char test_data[TEST_IO_SIZE + 1];
2196 char zero_data[TEST_IO_SIZE + 1];
2197 int i;
2198
2199 for (i = 0; i < TEST_IO_SIZE; ++i) {
2200 test_data[i] = (char) (rand() % (126 - 33) + 33);
2201 }
2202 test_data[TEST_IO_SIZE] = '\0';
2203 memset(zero_data, 0, sizeof(zero_data));
2204
2205 for (i = 0; i < 5; ++i)
2206 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2207
2208 for (i = 5; i < 10; ++i)
2209 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2210
2211 for (i = 0; i < 5; ++i)
2212 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2213
2214 for (i = 5; i < 10; ++i)
2215 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2216
2217 // discard 2nd, 4th sections.
2218 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2219 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2220
2221 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
2222 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2223 TEST_IO_SIZE, TEST_IO_SIZE, 0);
2224 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
2225 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2226 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
2227 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2228
2229 rbd_image_info_t info;
2230 rbd_completion_t comp;
2231 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
2232 // can't read or write starting past end
2233 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
2234 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
2235 // reading through end returns amount up to end
2236 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
2237 // writing through end returns amount up to end
2238 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
2239
2240 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2241 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
2242 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2243 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2244 rbd_aio_release(comp);
2245
2246 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
2247 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
2248 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2249 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2250 rbd_aio_release(comp);
2251
2252 ASSERT_PASSED(validate_object_map, image);
2253 ASSERT_EQ(0, rbd_close(image));
2254
2255 rados_ioctx_destroy(ioctx);
2256 }
2257
2258 TEST_F(TestLibRBD, TestScatterGatherIO)
2259 {
2260 rados_ioctx_t ioctx;
2261 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2262
2263 rbd_image_t image;
2264 int order = 0;
2265 std::string name = get_temp_image_name();
2266 uint64_t size = 20 << 20;
2267
2268 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2269 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2270
2271 std::string write_buffer("This is a test");
2272 struct iovec bad_iovs[] = {
2273 {.iov_base = NULL, .iov_len = static_cast<size_t>(-1)}
2274 };
2275 struct iovec write_iovs[] = {
2276 {.iov_base = &write_buffer[0], .iov_len = 5},
2277 {.iov_base = &write_buffer[5], .iov_len = 3},
2278 {.iov_base = &write_buffer[8], .iov_len = 2},
2279 {.iov_base = &write_buffer[10], .iov_len = 4}
2280 };
2281
2282 rbd_completion_t comp;
2283 rbd_aio_create_completion(NULL, NULL, &comp);
2284 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, write_iovs, 0, 0, comp));
2285 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 1, 0, comp));
2286 ASSERT_EQ(0, rbd_aio_writev(image, write_iovs,
2287 sizeof(write_iovs) / sizeof(struct iovec),
2288 1<<order, comp));
2289 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2290 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
2291 rbd_aio_release(comp);
2292
2293 std::string read_buffer(write_buffer.size(), '1');
2294 struct iovec read_iovs[] = {
2295 {.iov_base = &read_buffer[0], .iov_len = 4},
2296 {.iov_base = &read_buffer[8], .iov_len = 4},
2297 {.iov_base = &read_buffer[12], .iov_len = 2}
2298 };
2299
2300 rbd_aio_create_completion(NULL, NULL, &comp);
2301 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, read_iovs, 0, 0, comp));
2302 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 1, 0, comp));
2303 ASSERT_EQ(0, rbd_aio_readv(image, read_iovs,
2304 sizeof(read_iovs) / sizeof(struct iovec),
2305 1<<order, comp));
2306 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2307 ASSERT_EQ(10, rbd_aio_get_return_value(comp));
2308 rbd_aio_release(comp);
2309 ASSERT_EQ("This1111 is a ", read_buffer);
2310
2311 std::string linear_buffer(write_buffer.size(), '1');
2312 struct iovec linear_iovs[] = {
2313 {.iov_base = &linear_buffer[4], .iov_len = 4}
2314 };
2315 rbd_aio_create_completion(NULL, NULL, &comp);
2316 ASSERT_EQ(0, rbd_aio_readv(image, linear_iovs,
2317 sizeof(linear_iovs) / sizeof(struct iovec),
2318 1<<order, comp));
2319 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2320 ASSERT_EQ(4, rbd_aio_get_return_value(comp));
2321 rbd_aio_release(comp);
2322 ASSERT_EQ("1111This111111", linear_buffer);
2323
2324 ASSERT_PASSED(validate_object_map, image);
2325 ASSERT_EQ(0, rbd_close(image));
2326
2327 rados_ioctx_destroy(ioctx);
2328 }
2329
2330 TEST_F(TestLibRBD, TestEmptyDiscard)
2331 {
2332 rados_ioctx_t ioctx;
2333 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2334
2335 rbd_image_t image;
2336 int order = 0;
2337 std::string name = get_temp_image_name();
2338 uint64_t size = 20 << 20;
2339
2340 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2341 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2342
2343 ASSERT_PASSED(aio_discard_test_data, image, 0, 1*1024*1024);
2344 ASSERT_PASSED(aio_discard_test_data, image, 0, 4*1024*1024);
2345 ASSERT_PASSED(aio_discard_test_data, image, 3*1024*1024, 1*1024*1024);
2346
2347 ASSERT_PASSED(validate_object_map, image);
2348 ASSERT_EQ(0, rbd_close(image));
2349
2350 rados_ioctx_destroy(ioctx);
2351 }
2352
2353 TEST_F(TestLibRBD, TestFUA)
2354 {
2355 rados_ioctx_t ioctx;
2356 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2357
2358 rbd_image_t image_write;
2359 rbd_image_t image_read;
2360 int order = 0;
2361 std::string name = get_temp_image_name();
2362 uint64_t size = 2 << 20;
2363
2364 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2365 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_write, NULL));
2366 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_read, NULL));
2367
2368 // enable writeback cache
2369 rbd_flush(image_write);
2370
2371 char test_data[TEST_IO_SIZE + 1];
2372 int i;
2373
2374 for (i = 0; i < TEST_IO_SIZE; ++i) {
2375 test_data[i] = (char) (rand() % (126 - 33) + 33);
2376 }
2377 test_data[TEST_IO_SIZE] = '\0';
2378 for (i = 0; i < 5; ++i)
2379 ASSERT_PASSED(write_test_data, image_write, test_data,
2380 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
2381
2382 for (i = 0; i < 5; ++i)
2383 ASSERT_PASSED(read_test_data, image_read, test_data,
2384 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2385
2386 for (i = 5; i < 10; ++i)
2387 ASSERT_PASSED(aio_write_test_data, image_write, test_data,
2388 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_FUA);
2389
2390 for (i = 5; i < 10; ++i)
2391 ASSERT_PASSED(aio_read_test_data, image_read, test_data,
2392 TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
2393
2394 ASSERT_PASSED(validate_object_map, image_write);
2395 ASSERT_PASSED(validate_object_map, image_read);
2396 ASSERT_EQ(0, rbd_close(image_write));
2397 ASSERT_EQ(0, rbd_close(image_read));
2398 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
2399 rados_ioctx_destroy(ioctx);
2400 }
2401
2402 void simple_write_cb_pp(librbd::completion_t cb, void *arg)
2403 {
2404 cout << "write completion cb called!" << std::endl;
2405 }
2406
2407 void simple_read_cb_pp(librbd::completion_t cb, void *arg)
2408 {
2409 cout << "read completion cb called!" << std::endl;
2410 }
2411
2412 void aio_write_test_data(librbd::Image& image, const char *test_data,
2413 off_t off, uint32_t iohint, bool *passed)
2414 {
2415 ceph::bufferlist bl;
2416 bl.append(test_data, strlen(test_data));
2417 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2418 printf("created completion\n");
2419 if (iohint)
2420 image.aio_write2(off, strlen(test_data), bl, comp, iohint);
2421 else
2422 image.aio_write(off, strlen(test_data), bl, comp);
2423 printf("started write\n");
2424 comp->wait_for_complete();
2425 int r = comp->get_return_value();
2426 printf("return value is: %d\n", r);
2427 ASSERT_EQ(0, r);
2428 printf("finished write\n");
2429 comp->release();
2430 *passed = true;
2431 }
2432
2433 void aio_discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2434 {
2435 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2436 image.aio_discard(off, len, comp);
2437 comp->wait_for_complete();
2438 int r = comp->get_return_value();
2439 ASSERT_EQ(0, r);
2440 comp->release();
2441 *passed = true;
2442 }
2443
2444 void write_test_data(librbd::Image& image, const char *test_data, off_t off, uint32_t iohint, bool *passed)
2445 {
2446 size_t written;
2447 size_t len = strlen(test_data);
2448 ceph::bufferlist bl;
2449 bl.append(test_data, len);
2450 if (iohint)
2451 written = image.write2(off, len, bl, iohint);
2452 else
2453 written = image.write(off, len, bl);
2454 printf("wrote: %u\n", (unsigned int) written);
2455 ASSERT_EQ(bl.length(), written);
2456 *passed = true;
2457 }
2458
2459 void discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2460 {
2461 size_t written;
2462 written = image.discard(off, len);
2463 printf("discard: %u~%u\n", (unsigned)off, (unsigned)len);
2464 ASSERT_EQ(len, written);
2465 *passed = true;
2466 }
2467
2468 void aio_read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2469 {
2470 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_read_cb_pp);
2471 ceph::bufferlist bl;
2472 printf("created completion\n");
2473 if (iohint)
2474 image.aio_read2(off, expected_len, bl, comp, iohint);
2475 else
2476 image.aio_read(off, expected_len, bl, comp);
2477 printf("started read\n");
2478 comp->wait_for_complete();
2479 int r = comp->get_return_value();
2480 printf("return value is: %d\n", r);
2481 ASSERT_EQ(TEST_IO_SIZE, r);
2482 ASSERT_EQ(0, memcmp(expected, bl.c_str(), TEST_IO_SIZE));
2483 printf("finished read\n");
2484 comp->release();
2485 *passed = true;
2486 }
2487
2488 void read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2489 {
2490 int read;
2491 size_t len = expected_len;
2492 ceph::bufferlist bl;
2493 if (iohint)
2494 read = image.read2(off, len, bl, iohint);
2495 else
2496 read = image.read(off, len, bl);
2497 ASSERT_TRUE(read >= 0);
2498 std::string bl_str(bl.c_str(), read);
2499
2500 printf("read: %u\n", (unsigned int) read);
2501 int result = memcmp(bl_str.c_str(), expected, expected_len);
2502 if (result != 0) {
2503 printf("read: %s\nexpected: %s\n", bl_str.c_str(), expected);
2504 ASSERT_EQ(0, result);
2505 }
2506 *passed = true;
2507 }
2508
2509 void aio_writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2510 size_t len, size_t data_len, uint32_t iohint, bool *passed)
2511 {
2512 ceph::bufferlist bl;
2513 bl.append(test_data, data_len);
2514 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2515 printf("created completion\n");
2516 int r;
2517 r = image.aio_writesame(off, len, bl, comp, iohint);
2518 printf("started writesame\n");
2519 if (len % data_len) {
2520 ASSERT_EQ(-EINVAL, r);
2521 printf("expected fail, finished writesame\n");
2522 comp->release();
2523 *passed = true;
2524 return;
2525 }
2526
2527 comp->wait_for_complete();
2528 r = comp->get_return_value();
2529 printf("return value is: %d\n", r);
2530 ASSERT_EQ(0, r);
2531 printf("finished writesame\n");
2532 comp->release();
2533
2534 //verify data
2535 printf("to verify the data\n");
2536 int read;
2537 uint64_t left = len;
2538 while (left > 0) {
2539 ceph::bufferlist bl;
2540 read = image.read(off, data_len, bl);
2541 ASSERT_EQ(data_len, static_cast<size_t>(read));
2542 std::string bl_str(bl.c_str(), read);
2543 int result = memcmp(bl_str.c_str(), test_data, data_len);
2544 if (result !=0 ) {
2545 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2546 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2547 ASSERT_EQ(0, result);
2548 }
2549 off += data_len;
2550 left -= data_len;
2551 }
2552 ASSERT_EQ(0U, left);
2553 printf("verified\n");
2554
2555 *passed = true;
2556 }
2557
2558 void writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2559 ssize_t len, size_t data_len, uint32_t iohint,
2560 bool *passed)
2561 {
2562 ssize_t written;
2563 ceph::bufferlist bl;
2564 bl.append(test_data, data_len);
2565 written = image.writesame(off, len, bl, iohint);
2566 if (len % data_len) {
2567 ASSERT_EQ(-EINVAL, written);
2568 printf("expected fail, finished writesame\n");
2569 *passed = true;
2570 return;
2571 }
2572 ASSERT_EQ(len, written);
2573 printf("wrote: %u\n", (unsigned int) written);
2574 *passed = true;
2575
2576 //verify data
2577 printf("to verify the data\n");
2578 int read;
2579 uint64_t left = len;
2580 while (left > 0) {
2581 ceph::bufferlist bl;
2582 read = image.read(off, data_len, bl);
2583 ASSERT_EQ(data_len, static_cast<size_t>(read));
2584 std::string bl_str(bl.c_str(), read);
2585 int result = memcmp(bl_str.c_str(), test_data, data_len);
2586 if (result !=0 ) {
2587 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2588 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2589 ASSERT_EQ(0, result);
2590 }
2591 off += data_len;
2592 left -= data_len;
2593 }
2594 ASSERT_EQ(0U, left);
2595 printf("verified\n");
2596
2597 *passed = true;
2598 }
2599
2600 void aio_compare_and_write_test_data(librbd::Image& image, const char *cmp_data,
2601 const char *test_data, off_t off, ssize_t len,
2602 uint32_t iohint, bool *passed)
2603 {
2604 ceph::bufferlist cmp_bl;
2605 cmp_bl.append(cmp_data, strlen(cmp_data));
2606 ceph::bufferlist test_bl;
2607 test_bl.append(test_data, strlen(test_data));
2608 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2609 printf("created completion\n");
2610
2611 uint64_t mismatch_offset;
2612 image.aio_compare_and_write(off, len, cmp_bl, test_bl, comp, &mismatch_offset, iohint);
2613 printf("started aio compare and write\n");
2614 comp->wait_for_complete();
2615 int r = comp->get_return_value();
2616 printf("return value is: %d\n", r);
2617 ASSERT_EQ(0, r);
2618 printf("finished aio compare and write\n");
2619 comp->release();
2620 *passed = true;
2621 }
2622
2623 void compare_and_write_test_data(librbd::Image& image, const char *cmp_data, const char *test_data,
2624 off_t off, ssize_t len, uint64_t *mismatch_off, uint32_t iohint, bool *passed)
2625 {
2626 size_t written;
2627 ceph::bufferlist cmp_bl;
2628 cmp_bl.append(cmp_data, strlen(cmp_data));
2629 ceph::bufferlist test_bl;
2630 test_bl.append(test_data, strlen(test_data));
2631 printf("start compare and write\n");
2632 written = image.compare_and_write(off, len, cmp_bl, test_bl, mismatch_off, iohint);
2633 printf("compare and wrote: %d\n", (int) written);
2634 ASSERT_EQ(len, static_cast<ssize_t>(written));
2635 *passed = true;
2636 }
2637
2638 TEST_F(TestLibRBD, TestIOPP)
2639 {
2640 librados::IoCtx ioctx;
2641 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2642
2643 bool skip_discard = is_skip_partial_discard_enabled();
2644
2645 {
2646 librbd::RBD rbd;
2647 librbd::Image image;
2648 int order = 0;
2649 std::string name = get_temp_image_name();
2650 uint64_t size = 2 << 20;
2651
2652 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2653 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2654
2655 char test_data[TEST_IO_SIZE + 1];
2656 char zero_data[TEST_IO_SIZE + 1];
2657 int i;
2658 uint64_t mismatch_offset;
2659
2660 for (i = 0; i < TEST_IO_SIZE; ++i) {
2661 test_data[i] = (char) (rand() % (126 - 33) + 33);
2662 }
2663 test_data[TEST_IO_SIZE] = '\0';
2664 memset(zero_data, 0, sizeof(zero_data));
2665
2666 for (i = 0; i < 5; ++i)
2667 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i, 0);
2668
2669 for (i = 5; i < 10; ++i)
2670 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i, 0);
2671
2672 for (i = 0; i < 5; ++i)
2673 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2674 TEST_IO_SIZE, &mismatch_offset, 0);
2675
2676 for (i = 5; i < 10; ++i)
2677 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2678 TEST_IO_SIZE, 0);
2679
2680 for (i = 0; i < 5; ++i)
2681 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2682
2683 for (i = 5; i < 10; ++i)
2684 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2685
2686 // discard 2nd, 4th sections.
2687 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2688 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2689
2690 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
2691 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2692 TEST_IO_SIZE, TEST_IO_SIZE, 0);
2693 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
2694 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2695 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
2696 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2697
2698 for (i = 0; i < 15; ++i) {
2699 if (i % 3 == 2) {
2700 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2701 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2702 } else if (i % 3 == 1) {
2703 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2704 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2705 } else {
2706 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2707 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2708 }
2709 }
2710 for (i = 0; i < 15; ++i) {
2711 if (i % 3 == 2) {
2712 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2713 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2714 } else if (i % 3 == 1) {
2715 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2716 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2717 } else {
2718 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2719 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2720 }
2721 }
2722
2723 ASSERT_PASSED(validate_object_map, image);
2724 }
2725
2726 ioctx.close();
2727 }
2728
2729 TEST_F(TestLibRBD, TestIOPPWithIOHint)
2730 {
2731 librados::IoCtx ioctx;
2732 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2733
2734 {
2735 librbd::RBD rbd;
2736 librbd::Image image;
2737 int order = 0;
2738 std::string name = get_temp_image_name();
2739 uint64_t size = 2 << 20;
2740
2741 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2742 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2743
2744 char test_data[TEST_IO_SIZE + 1];
2745 char zero_data[TEST_IO_SIZE + 1];
2746 test_data[TEST_IO_SIZE] = '\0';
2747 int i;
2748
2749 for (i = 0; i < TEST_IO_SIZE; ++i) {
2750 test_data[i] = (char) (rand() % (126 - 33) + 33);
2751 }
2752 memset(zero_data, 0, sizeof(zero_data));
2753
2754 for (i = 0; i < 5; ++i)
2755 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i,
2756 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2757
2758 for (i = 5; i < 10; ++i)
2759 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i,
2760 LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2761
2762 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data),
2763 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_RANDOM);
2764
2765 for (i = 5; i < 10; ++i)
2766 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i,
2767 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2768
2769 for (i = 0; i < 15; ++i) {
2770 if (i % 3 == 2) {
2771 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2772 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2773 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2774 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2775 } else if (i % 3 == 1) {
2776 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2777 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2778 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2779 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2780 } else {
2781 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2782 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2783 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2784 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2785 }
2786 }
2787 for (i = 0; i < 15; ++i) {
2788 if (i % 3 == 2) {
2789 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2790 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2791 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2792 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2793 } else if (i % 3 == 1) {
2794 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2795 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2796 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2797 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2798 } else {
2799 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2800 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2801 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2802 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2803 }
2804 }
2805
2806 ASSERT_PASSED(validate_object_map, image);
2807 }
2808
2809 ioctx.close();
2810 }
2811
2812
2813
2814 TEST_F(TestLibRBD, TestIOToSnapshot)
2815 {
2816 rados_ioctx_t ioctx;
2817 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2818
2819 rbd_image_t image;
2820 int order = 0;
2821 std::string name = get_temp_image_name();
2822 uint64_t isize = 2 << 20;
2823
2824 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
2825 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2826
2827 int i, r;
2828 rbd_image_t image_at_snap;
2829 char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
2830 char test_data[TEST_IO_TO_SNAP_SIZE + 1];
2831
2832 for (i = 0; i < TEST_IO_TO_SNAP_SIZE; ++i)
2833 test_data[i] = (char) (i + 48);
2834 test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
2835 orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
2836
2837 r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
2838 ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE);
2839
2840 ASSERT_EQ(0, test_ls_snaps(image, 0));
2841 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
2842 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
2843 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2844
2845 printf("write test data!\n");
2846 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2847 ASSERT_EQ(0, rbd_snap_create(image, "written"));
2848 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
2849
2850 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2851
2852 rbd_snap_set(image, "orig");
2853 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2854
2855 rbd_snap_set(image, "written");
2856 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2857
2858 rbd_snap_set(image, "orig");
2859
2860 r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
2861 printf("write to snapshot returned %d\n", r);
2862 ASSERT_LT(r, 0);
2863 cout << strerror(-r) << std::endl;
2864
2865 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2866 rbd_snap_set(image, "written");
2867 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2868
2869 r = rbd_snap_rollback(image, "orig");
2870 ASSERT_EQ(r, -EROFS);
2871
2872 r = rbd_snap_set(image, NULL);
2873 ASSERT_EQ(r, 0);
2874 r = rbd_snap_rollback(image, "orig");
2875 ASSERT_EQ(r, 0);
2876
2877 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2878
2879 rbd_flush(image);
2880
2881 printf("opening testimg@orig\n");
2882 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_at_snap, "orig"));
2883 ASSERT_PASSED(read_test_data, image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2884 r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
2885 printf("write to snapshot returned %d\n", r);
2886 ASSERT_LT(r, 0);
2887 cout << strerror(-r) << std::endl;
2888 ASSERT_EQ(0, rbd_close(image_at_snap));
2889
2890 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
2891 ASSERT_EQ(0, rbd_snap_remove(image, "written"));
2892 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
2893 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
2894 ASSERT_EQ(0, test_ls_snaps(image, 0));
2895
2896 ASSERT_PASSED(validate_object_map, image);
2897 ASSERT_EQ(0, rbd_close(image));
2898
2899 rados_ioctx_destroy(ioctx);
2900 }
2901
2902 TEST_F(TestLibRBD, TestClone)
2903 {
2904 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2905 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "1"));
2906 BOOST_SCOPE_EXIT_ALL(&) {
2907 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
2908 };
2909
2910 rados_ioctx_t ioctx;
2911 rbd_image_info_t pinfo, cinfo;
2912 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2913
2914 bool old_format;
2915 uint64_t features;
2916 rbd_image_t parent, child;
2917 int order = 0;
2918
2919 ASSERT_EQ(0, get_features(&old_format, &features));
2920 ASSERT_FALSE(old_format);
2921
2922 std::string parent_name = get_temp_image_name();
2923 std::string child_name = get_temp_image_name();
2924
2925 // make a parent to clone from
2926 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
2927 false, features));
2928 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
2929 printf("made parent image \"parent\"\n");
2930
2931 char *data = (char *)"testdata";
2932 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
2933
2934 // can't clone a non-snapshot, expect failure
2935 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
2936 child_name.c_str(), features, &order));
2937
2938 // verify that there is no parent info on "parent"
2939 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
2940 printf("parent has no parent info\n");
2941
2942 // create 70 metadatas to verify we can clone all key/value pairs
2943 std::string key;
2944 std::string val;
2945 size_t sum_key_len = 0;
2946 size_t sum_value_len = 0;
2947 for (int i = 1; i <= 70; i++) {
2948 key = "key" + stringify(i);
2949 val = "value" + stringify(i);
2950 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
2951
2952 sum_key_len += (key.size() + 1);
2953 sum_value_len += (val.size() + 1);
2954 }
2955
2956 char keys[1024];
2957 char vals[1024];
2958 size_t keys_len = sizeof(keys);
2959 size_t vals_len = sizeof(vals);
2960
2961 char value[1024];
2962 size_t value_len = sizeof(value);
2963
2964 // create a snapshot, reopen as the parent we're interested in
2965 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2966 printf("made snapshot \"parent@parent_snap\"\n");
2967 ASSERT_EQ(0, rbd_close(parent));
2968 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
2969
2970 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2971 ioctx, child_name.c_str(), features, &order));
2972
2973 // unprotected image should fail unprotect
2974 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
2975 printf("can't unprotect an unprotected snap\n");
2976
2977 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2978 // protecting again should fail
2979 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
2980 printf("can't protect a protected snap\n");
2981
2982 // This clone and open should work
2983 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2984 ioctx, child_name.c_str(), features, &order));
2985 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
2986 printf("made and opened clone \"child\"\n");
2987
2988 // check read
2989 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
2990
2991 // check write
2992 ASSERT_EQ((ssize_t)strlen(data), rbd_write(child, 20, strlen(data), data));
2993 ASSERT_PASSED(read_test_data, child, data, 20, strlen(data), 0);
2994 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
2995
2996 // check attributes
2997 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
2998 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2999 EXPECT_EQ(cinfo.size, pinfo.size);
3000 uint64_t overlap;
3001 rbd_get_overlap(child, &overlap);
3002 EXPECT_EQ(overlap, pinfo.size);
3003 EXPECT_EQ(cinfo.obj_size, pinfo.obj_size);
3004 EXPECT_EQ(cinfo.order, pinfo.order);
3005 printf("sizes and overlaps are good between parent and child\n");
3006
3007 // check key/value pairs in child image
3008 ASSERT_EQ(0, rbd_metadata_list(child, "", 70, keys, &keys_len, vals,
3009 &vals_len));
3010 ASSERT_EQ(sum_key_len, keys_len);
3011 ASSERT_EQ(sum_value_len, vals_len);
3012
3013 for (int i = 1; i <= 70; i++) {
3014 key = "key" + stringify(i);
3015 val = "value" + stringify(i);
3016 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
3017 ASSERT_STREQ(val.c_str(), value);
3018
3019 value_len = sizeof(value);
3020 }
3021 printf("child image successfully cloned all image-meta pairs\n");
3022
3023 // sizing down child results in changing overlap and size, not parent size
3024 ASSERT_EQ(0, rbd_resize(child, 2UL<<20));
3025 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
3026 rbd_get_overlap(child, &overlap);
3027 ASSERT_EQ(overlap, 2UL<<20);
3028 ASSERT_EQ(cinfo.size, 2UL<<20);
3029 ASSERT_EQ(0, rbd_resize(child, 4UL<<20));
3030 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
3031 rbd_get_overlap(child, &overlap);
3032 ASSERT_EQ(overlap, 2UL<<20);
3033 ASSERT_EQ(cinfo.size, 4UL<<20);
3034 printf("sized down clone, changed overlap\n");
3035
3036 // sizing back up doesn't change that
3037 ASSERT_EQ(0, rbd_resize(child, 5UL<<20));
3038 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
3039 rbd_get_overlap(child, &overlap);
3040 ASSERT_EQ(overlap, 2UL<<20);
3041 ASSERT_EQ(cinfo.size, 5UL<<20);
3042 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
3043 printf("parent info: size %llu obj_size %llu parent_pool %llu\n",
3044 (unsigned long long)pinfo.size, (unsigned long long)pinfo.obj_size,
3045 (unsigned long long)pinfo.parent_pool);
3046 ASSERT_EQ(pinfo.size, 4UL<<20);
3047 printf("sized up clone, changed size but not overlap or parent's size\n");
3048
3049 ASSERT_PASSED(validate_object_map, child);
3050 ASSERT_EQ(0, rbd_close(child));
3051
3052 ASSERT_PASSED(validate_object_map, parent);
3053 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
3054 printf("can't remove parent while child still exists\n");
3055 ASSERT_EQ(0, rbd_remove(ioctx, child_name.c_str()));
3056 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
3057 printf("can't remove parent while still protected\n");
3058 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3059 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3060 printf("removed parent snap after unprotecting\n");
3061
3062 ASSERT_EQ(0, rbd_close(parent));
3063 rados_ioctx_destroy(ioctx);
3064 }
3065
3066 TEST_F(TestLibRBD, TestClone2)
3067 {
3068 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3069 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
3070 BOOST_SCOPE_EXIT_ALL(&) {
3071 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
3072 };
3073
3074 rados_ioctx_t ioctx;
3075 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3076
3077 bool old_format;
3078 uint64_t features;
3079 rbd_image_t parent, child;
3080 int order = 0;
3081
3082 ASSERT_EQ(0, get_features(&old_format, &features));
3083 ASSERT_FALSE(old_format);
3084
3085 std::string parent_name = get_temp_image_name();
3086 std::string child_name = get_temp_image_name();
3087
3088 // make a parent to clone from
3089 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
3090 false, features));
3091 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
3092 printf("made parent image \"parent\"\n");
3093
3094 char *data = (char *)"testdata";
3095 char *childata = (char *)"childata";
3096 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
3097 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
3098
3099 // can't clone a non-snapshot, expect failure
3100 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
3101 child_name.c_str(), features, &order));
3102
3103 // verify that there is no parent info on "parent"
3104 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
3105 printf("parent has no parent info\n");
3106
3107 // create 70 metadatas to verify we can clone all key/value pairs
3108 std::string key;
3109 std::string val;
3110 size_t sum_key_len = 0;
3111 size_t sum_value_len = 0;
3112 for (int i = 1; i <= 70; i++) {
3113 key = "key" + stringify(i);
3114 val = "value" + stringify(i);
3115 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
3116
3117 sum_key_len += (key.size() + 1);
3118 sum_value_len += (val.size() + 1);
3119 }
3120
3121 char keys[1024];
3122 char vals[1024];
3123 size_t keys_len = sizeof(keys);
3124 size_t vals_len = sizeof(vals);
3125
3126 char value[1024];
3127 size_t value_len = sizeof(value);
3128
3129 // create a snapshot, reopen as the parent we're interested in
3130 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3131 printf("made snapshot \"parent@parent_snap\"\n");
3132 ASSERT_EQ(0, rbd_close(parent));
3133 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
3134
3135 // This clone and open should work
3136 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
3137 ioctx, child_name.c_str(), features, &order));
3138 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
3139 printf("made and opened clone \"child\"\n");
3140
3141 // check key/value pairs in child image
3142 ASSERT_EQ(0, rbd_metadata_list(child, "", 70, keys, &keys_len, vals,
3143 &vals_len));
3144 ASSERT_EQ(sum_key_len, keys_len);
3145 ASSERT_EQ(sum_value_len, vals_len);
3146
3147 for (int i = 1; i <= 70; i++) {
3148 key = "key" + stringify(i);
3149 val = "value" + stringify(i);
3150 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
3151 ASSERT_STREQ(val.c_str(), value);
3152
3153 value_len = sizeof(value);
3154 }
3155 printf("child image successfully cloned all image-meta pairs\n");
3156
3157 // write something in
3158 ASSERT_EQ((ssize_t)strlen(childata), rbd_write(child, 20, strlen(childata), childata));
3159
3160 char test[strlen(data) * 2];
3161 ASSERT_EQ((ssize_t)strlen(data), rbd_read(child, 20, strlen(data), test));
3162 ASSERT_EQ(0, memcmp(test, childata, strlen(childata)));
3163
3164 // overlap
3165 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 20 - strlen(data), sizeof(test), test));
3166 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
3167 ASSERT_EQ(0, memcmp(test + strlen(data), childata, strlen(childata)));
3168
3169 // all parent
3170 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 0, sizeof(test), test));
3171 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
3172
3173 ASSERT_PASSED(validate_object_map, child);
3174 ASSERT_PASSED(validate_object_map, parent);
3175
3176 rbd_snap_info_t snaps[2];
3177 int max_snaps = 2;
3178 ASSERT_EQ(1, rbd_snap_list(parent, snaps, &max_snaps));
3179 rbd_snap_list_end(snaps);
3180
3181 ASSERT_EQ(0, rbd_snap_remove_by_id(parent, snaps[0].id));
3182
3183 rbd_snap_namespace_type_t snap_namespace_type;
3184 ASSERT_EQ(0, rbd_snap_get_namespace_type(parent, snaps[0].id,
3185 &snap_namespace_type));
3186 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_TRASH, snap_namespace_type);
3187
3188 char original_name[32];
3189 ASSERT_EQ(0, rbd_snap_get_trash_namespace(parent, snaps[0].id,
3190 original_name,
3191 sizeof(original_name)));
3192 ASSERT_EQ(0, strcmp("parent_snap", original_name));
3193
3194 ASSERT_EQ(0, rbd_close(child));
3195 ASSERT_EQ(0, rbd_close(parent));
3196 rados_ioctx_destroy(ioctx);
3197 }
3198
3199 static void test_list_children(rbd_image_t image, ssize_t num_expected, ...)
3200 {
3201 va_list ap;
3202 va_start(ap, num_expected);
3203 size_t pools_len = 100;
3204 size_t children_len = 100;
3205 char *pools = NULL;
3206 char *children = NULL;
3207 ssize_t num_children;
3208
3209 do {
3210 free(pools);
3211 free(children);
3212 pools = (char *) malloc(pools_len);
3213 children = (char *) malloc(children_len);
3214 num_children = rbd_list_children(image, pools, &pools_len,
3215 children, &children_len);
3216 } while (num_children == -ERANGE);
3217
3218 ASSERT_EQ(num_expected, num_children);
3219 for (ssize_t i = num_expected; i > 0; --i) {
3220 char *expected_pool = va_arg(ap, char *);
3221 char *expected_image = va_arg(ap, char *);
3222 char *pool = pools;
3223 char *image = children;
3224 bool found = 0;
3225 printf("\ntrying to find %s/%s\n", expected_pool, expected_image);
3226 for (ssize_t j = 0; j < num_children; ++j) {
3227 printf("checking %s/%s\n", pool, image);
3228 if (strcmp(expected_pool, pool) == 0 &&
3229 strcmp(expected_image, image) == 0) {
3230 printf("found child %s/%s\n\n", pool, image);
3231 found = 1;
3232 break;
3233 }
3234 pool += strlen(pool) + 1;
3235 image += strlen(image) + 1;
3236 if (j == num_children - 1) {
3237 ASSERT_EQ(pool - pools - 1, (ssize_t) pools_len);
3238 ASSERT_EQ(image - children - 1, (ssize_t) children_len);
3239 }
3240 }
3241 ASSERT_TRUE(found);
3242 }
3243 va_end(ap);
3244
3245 if (pools)
3246 free(pools);
3247 if (children)
3248 free(children);
3249 }
3250
3251 static void test_list_children2(rbd_image_t image, int num_expected, ...)
3252 {
3253 int num_children, i, j, max_size = 10;
3254 va_list ap;
3255 rbd_child_info_t children[max_size];
3256 num_children = rbd_list_children2(image, children, &max_size);
3257 printf("num children is: %d\nexpected: %d\n", num_children, num_expected);
3258
3259 for (i = 0; i < num_children; i++) {
3260 printf("child: %s\n", children[i].image_name);
3261 }
3262
3263 va_start(ap, num_expected);
3264 for (i = num_expected; i > 0; i--) {
3265 char *expected_id = va_arg(ap, char *);
3266 char *expected_pool = va_arg(ap, char *);
3267 char *expected_image = va_arg(ap, char *);
3268 bool expected_trash = va_arg(ap, int);
3269 bool found = false;
3270 for (j = 0; j < num_children; j++) {
3271 if (children[j].pool_name == NULL ||
3272 children[j].image_name == NULL ||
3273 children[j].image_id == NULL)
3274 continue;
3275 if (strcmp(children[j].image_id, expected_id) == 0 &&
3276 strcmp(children[j].pool_name, expected_pool) == 0 &&
3277 strcmp(children[j].image_name, expected_image) == 0 &&
3278 children[j].trash == expected_trash) {
3279 printf("found child %s/%s/%s\n\n", children[j].pool_name, children[j].image_name, children[j].image_id);
3280 rbd_list_child_cleanup(&children[j]);
3281 children[j].pool_name = NULL;
3282 children[j].image_name = NULL;
3283 children[j].image_id = NULL;
3284 found = true;
3285 break;
3286 }
3287 }
3288 EXPECT_TRUE(found);
3289 }
3290 va_end(ap);
3291
3292 for (i = 0; i < num_children; i++) {
3293 EXPECT_EQ((const char *)0, children[i].pool_name);
3294 EXPECT_EQ((const char *)0, children[i].image_name);
3295 EXPECT_EQ((const char *)0, children[i].image_id);
3296 }
3297 }
3298
3299 TEST_F(TestLibRBD, ListChildren)
3300 {
3301 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3302
3303 librbd::RBD rbd;
3304 rados_ioctx_t ioctx1, ioctx2;
3305 string pool_name1 = create_pool(true);
3306 string pool_name2 = create_pool(true);
3307 ASSERT_NE("", pool_name2);
3308
3309 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
3310 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
3311
3312 rbd_image_t image1;
3313 rbd_image_t image2;
3314 rbd_image_t image3;
3315 rbd_image_t image4;
3316
3317 bool old_format;
3318 uint64_t features;
3319 rbd_image_t parent;
3320 int order = 0;
3321
3322 ASSERT_EQ(0, get_features(&old_format, &features));
3323 ASSERT_FALSE(old_format);
3324
3325 std::string parent_name = get_temp_image_name();
3326 std::string child_name1 = get_temp_image_name();
3327 std::string child_name2 = get_temp_image_name();
3328 std::string child_name3 = get_temp_image_name();
3329 std::string child_name4 = get_temp_image_name();
3330
3331 char child_id1[4096];
3332 char child_id2[4096];
3333 char child_id3[4096];
3334 char child_id4[4096];
3335
3336 // make a parent to clone from
3337 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
3338 false, features));
3339 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
3340 // create a snapshot, reopen as the parent we're interested in
3341 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3342 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
3343 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
3344
3345 ASSERT_EQ(0, rbd_close(parent));
3346 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
3347
3348 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3349 ioctx2, child_name1.c_str(), features, &order));
3350 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
3351 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
3352 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
3353 test_list_children2(parent, 1,
3354 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
3355
3356 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3357 ioctx1, child_name2.c_str(), features, &order));
3358 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
3359 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
3360 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3361 pool_name1.c_str(), child_name2.c_str());
3362 test_list_children2(parent, 2,
3363 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3364 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
3365
3366 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3367 ioctx2, child_name3.c_str(), features, &order));
3368 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
3369 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
3370 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3371 pool_name1.c_str(), child_name2.c_str(),
3372 pool_name2.c_str(), child_name3.c_str());
3373 test_list_children2(parent, 3,
3374 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3375 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3376 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
3377
3378 librados::IoCtx ioctx3;
3379 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
3380 ASSERT_EQ(0, rbd_close(image3));
3381 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
3382 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3383 pool_name1.c_str(), child_name2.c_str());
3384 test_list_children2(parent, 3,
3385 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3386 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3387 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
3388
3389 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3390 ioctx2, child_name4.c_str(), features, &order));
3391 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
3392 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
3393 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3394 pool_name1.c_str(), child_name2.c_str(),
3395 pool_name2.c_str(), child_name4.c_str());
3396 test_list_children2(parent, 4,
3397 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3398 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3399 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
3400 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3401
3402 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
3403 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
3404 pool_name1.c_str(), child_name2.c_str(),
3405 pool_name2.c_str(), child_name3.c_str(),
3406 pool_name2.c_str(), child_name4.c_str());
3407 test_list_children2(parent, 4,
3408 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3409 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3410 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3411 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3412
3413 ASSERT_EQ(0, rbd_close(image1));
3414 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
3415 test_list_children(parent, 3,
3416 pool_name1.c_str(), child_name2.c_str(),
3417 pool_name2.c_str(), child_name3.c_str(),
3418 pool_name2.c_str(), child_name4.c_str());
3419 test_list_children2(parent, 3,
3420 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3421 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3422 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3423
3424 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
3425 test_list_children(parent, 2,
3426 pool_name1.c_str(), child_name2.c_str(),
3427 pool_name2.c_str(), child_name4.c_str());
3428 test_list_children2(parent, 2,
3429 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3430 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3431
3432 ASSERT_EQ(0, rbd_close(image4));
3433 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
3434 test_list_children(parent, 1,
3435 pool_name1.c_str(), child_name2.c_str());
3436 test_list_children2(parent, 1,
3437 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
3438
3439
3440 ASSERT_EQ(0, rbd_close(image2));
3441 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
3442 test_list_children(parent, 0);
3443 test_list_children2(parent, 0);
3444
3445 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3446 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3447 ASSERT_EQ(0, rbd_close(parent));
3448 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
3449 rados_ioctx_destroy(ioctx1);
3450 rados_ioctx_destroy(ioctx2);
3451 }
3452
3453 TEST_F(TestLibRBD, ListChildrenTiered)
3454 {
3455 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3456
3457 librbd::RBD rbd;
3458 string pool_name1 = create_pool(true);
3459 string pool_name2 = create_pool(true);
3460 string pool_name3 = create_pool(true);
3461 ASSERT_NE("", pool_name1);
3462 ASSERT_NE("", pool_name2);
3463 ASSERT_NE("", pool_name3);
3464
3465 std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" +
3466 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\", \"force_nonempty\":\"\"}";
3467 char *cmd[1];
3468 cmd[0] = (char *)cmdstr.c_str();
3469 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3470
3471 cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
3472 pool_name3 + "\", \"mode\":\"writeback\"}";
3473 cmd[0] = (char *)cmdstr.c_str();
3474 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3475
3476 cmdstr = "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
3477 pool_name1 + "\", \"overlaypool\":\"" + pool_name3 + "\"}";
3478 cmd[0] = (char *)cmdstr.c_str();
3479 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3480
3481 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
3482
3483 string parent_name = get_temp_image_name();
3484 string child_name1 = get_temp_image_name();
3485 string child_name2 = get_temp_image_name();
3486 string child_name3 = get_temp_image_name();
3487 string child_name4 = get_temp_image_name();
3488
3489 char child_id1[4096];
3490 char child_id2[4096];
3491 char child_id3[4096];
3492 char child_id4[4096];
3493
3494 rbd_image_t image1;
3495 rbd_image_t image2;
3496 rbd_image_t image3;
3497 rbd_image_t image4;
3498
3499 rados_ioctx_t ioctx1, ioctx2;
3500 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
3501 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
3502
3503 bool old_format;
3504 uint64_t features;
3505 rbd_image_t parent;
3506 int order = 0;
3507
3508 ASSERT_EQ(0, get_features(&old_format, &features));
3509 ASSERT_FALSE(old_format);
3510
3511 // make a parent to clone from
3512 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
3513 false, features));
3514 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
3515 // create a snapshot, reopen as the parent we're interested in
3516 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3517 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
3518 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
3519
3520 ASSERT_EQ(0, rbd_close(parent));
3521 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
3522
3523 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3524 ioctx2, child_name1.c_str(), features, &order));
3525 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
3526 ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
3527 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
3528 test_list_children2(parent, 1,
3529 child_id1, pool_name2.c_str(), child_name1.c_str(), false);
3530
3531 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3532 ioctx1, child_name2.c_str(), features, &order));
3533 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
3534 ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
3535 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3536 pool_name1.c_str(), child_name2.c_str());
3537 test_list_children2(parent, 2,
3538 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3539 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
3540
3541 // read from the cache to populate it
3542 rbd_image_t tier_image;
3543 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &tier_image, NULL));
3544 size_t len = 4 * 1024 * 1024;
3545 char* buf = (char*)malloc(len);
3546 ssize_t size = rbd_read(tier_image, 0, len, buf);
3547 ASSERT_GT(size, 0);
3548 free(buf);
3549 ASSERT_EQ(0, rbd_close(tier_image));
3550
3551 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3552 ioctx2, child_name3.c_str(), features, &order));
3553 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
3554 ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
3555 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3556 pool_name1.c_str(), child_name2.c_str(),
3557 pool_name2.c_str(), child_name3.c_str());
3558 test_list_children2(parent, 3,
3559 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3560 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3561 child_id3, pool_name2.c_str(), child_name3.c_str(), false);
3562
3563 librados::IoCtx ioctx3;
3564 ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
3565 ASSERT_EQ(0, rbd_close(image3));
3566 ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
3567 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3568 pool_name1.c_str(), child_name2.c_str());
3569 test_list_children2(parent, 3,
3570 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3571 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3572 child_id3, pool_name2.c_str(), child_name3.c_str(), true);
3573
3574 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3575 ioctx2, child_name4.c_str(), features, &order));
3576 ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
3577 ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
3578 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3579 pool_name1.c_str(), child_name2.c_str(),
3580 pool_name2.c_str(), child_name4.c_str());
3581 test_list_children2(parent, 4,
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 child_id3, pool_name2.c_str(), child_name3.c_str(), true,
3585 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3586
3587 ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
3588 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
3589 pool_name1.c_str(), child_name2.c_str(),
3590 pool_name2.c_str(), child_name3.c_str(),
3591 pool_name2.c_str(), child_name4.c_str());
3592 test_list_children2(parent, 4,
3593 child_id1, pool_name2.c_str(), child_name1.c_str(), false,
3594 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3595 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3596 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3597
3598 ASSERT_EQ(0, rbd_close(image1));
3599 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
3600 test_list_children(parent, 3,
3601 pool_name1.c_str(), child_name2.c_str(),
3602 pool_name2.c_str(), child_name3.c_str(),
3603 pool_name2.c_str(), child_name4.c_str());
3604 test_list_children2(parent, 3,
3605 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3606 child_id3, pool_name2.c_str(), child_name3.c_str(), false,
3607 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3608
3609 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
3610 test_list_children(parent, 2,
3611 pool_name1.c_str(), child_name2.c_str(),
3612 pool_name2.c_str(), child_name4.c_str());
3613 test_list_children2(parent, 2,
3614 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
3615 child_id4, pool_name2.c_str(), child_name4.c_str(), false);
3616
3617 ASSERT_EQ(0, rbd_close(image4));
3618 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
3619 test_list_children(parent, 1,
3620 pool_name1.c_str(), child_name2.c_str());
3621 test_list_children2(parent, 1,
3622 child_id2, pool_name1.c_str(), child_name2.c_str(), false);
3623
3624 ASSERT_EQ(0, rbd_close(image2));
3625 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
3626 test_list_children(parent, 0);
3627 test_list_children2(parent, 0);
3628
3629 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3630 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3631 ASSERT_EQ(0, rbd_close(parent));
3632 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
3633 rados_ioctx_destroy(ioctx1);
3634 rados_ioctx_destroy(ioctx2);
3635 cmdstr = "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
3636 pool_name1 + "\"}";
3637 cmd[0] = (char *)cmdstr.c_str();
3638 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3639 cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
3640 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\"}";
3641 cmd[0] = (char *)cmdstr.c_str();
3642 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3643 }
3644
3645 TEST_F(TestLibRBD, LockingPP)
3646 {
3647 librados::IoCtx ioctx;
3648 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3649
3650 {
3651 librbd::RBD rbd;
3652 librbd::Image image;
3653 int order = 0;
3654 std::string name = get_temp_image_name();
3655 uint64_t size = 2 << 20;
3656 std::string cookie1 = "foo";
3657 std::string cookie2 = "bar";
3658
3659 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3660 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3661
3662 // no lockers initially
3663 std::list<librbd::locker_t> lockers;
3664 std::string tag;
3665 bool exclusive;
3666 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3667 ASSERT_EQ(0u, lockers.size());
3668 ASSERT_EQ("", tag);
3669
3670 // exclusive lock is exclusive
3671 ASSERT_EQ(0, image.lock_exclusive(cookie1));
3672 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3673 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3674 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3675 ASSERT_EQ(-EBUSY, image.lock_shared(cookie1, "test"));
3676 ASSERT_EQ(-EBUSY, image.lock_shared("", "test"));
3677 ASSERT_EQ(-EBUSY, image.lock_shared("", ""));
3678
3679 // list exclusive
3680 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3681 ASSERT_TRUE(exclusive);
3682 ASSERT_EQ("", tag);
3683 ASSERT_EQ(1u, lockers.size());
3684 ASSERT_EQ(cookie1, lockers.front().cookie);
3685
3686 // unlock
3687 ASSERT_EQ(-ENOENT, image.unlock(""));
3688 ASSERT_EQ(-ENOENT, image.unlock(cookie2));
3689 ASSERT_EQ(0, image.unlock(cookie1));
3690 ASSERT_EQ(-ENOENT, image.unlock(cookie1));
3691 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3692 ASSERT_EQ(0u, lockers.size());
3693
3694 ASSERT_EQ(0, image.lock_shared(cookie1, ""));
3695 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3696 ASSERT_EQ(0, image.lock_shared(cookie2, ""));
3697 ASSERT_EQ(-EEXIST, image.lock_shared(cookie2, ""));
3698 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3699 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie2));
3700 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3701 ASSERT_EQ(-EBUSY, image.lock_exclusive("test"));
3702
3703 // list shared
3704 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3705 ASSERT_EQ(2u, lockers.size());
3706 }
3707
3708 ioctx.close();
3709 }
3710
3711 TEST_F(TestLibRBD, FlushAio)
3712 {
3713 rados_ioctx_t ioctx;
3714 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3715
3716 rbd_image_t image;
3717 int order = 0;
3718 std::string name = get_temp_image_name();
3719 uint64_t size = 2 << 20;
3720 size_t num_aios = 256;
3721
3722 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3723 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3724
3725 char test_data[TEST_IO_SIZE + 1];
3726 size_t i;
3727 for (i = 0; i < TEST_IO_SIZE; ++i) {
3728 test_data[i] = (char) (rand() % (126 - 33) + 33);
3729 }
3730
3731 rbd_completion_t write_comps[num_aios];
3732 for (i = 0; i < num_aios; ++i) {
3733 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &write_comps[i]));
3734 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3735 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
3736 write_comps[i]));
3737 }
3738
3739 rbd_completion_t flush_comp;
3740 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &flush_comp));
3741 ASSERT_EQ(0, rbd_aio_flush(image, flush_comp));
3742 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp));
3743 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp));
3744 rbd_aio_release(flush_comp);
3745
3746 for (i = 0; i < num_aios; ++i) {
3747 ASSERT_EQ(1, rbd_aio_is_complete(write_comps[i]));
3748 rbd_aio_release(write_comps[i]);
3749 }
3750
3751 ASSERT_PASSED(validate_object_map, image);
3752 ASSERT_EQ(0, rbd_close(image));
3753 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
3754 rados_ioctx_destroy(ioctx);
3755 }
3756
3757 TEST_F(TestLibRBD, FlushAioPP)
3758 {
3759 librados::IoCtx ioctx;
3760 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3761
3762 {
3763 librbd::RBD rbd;
3764 librbd::Image image;
3765 int order = 0;
3766 std::string name = get_temp_image_name();
3767 uint64_t size = 2 << 20;
3768 const size_t num_aios = 256;
3769
3770 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3771 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3772
3773 char test_data[TEST_IO_SIZE + 1];
3774 size_t i;
3775 for (i = 0; i < TEST_IO_SIZE; ++i) {
3776 test_data[i] = (char) (rand() % (126 - 33) + 33);
3777 }
3778 test_data[TEST_IO_SIZE] = '\0';
3779
3780 librbd::RBD::AioCompletion *write_comps[num_aios];
3781 ceph::bufferlist bls[num_aios];
3782 for (i = 0; i < num_aios; ++i) {
3783 bls[i].append(test_data, strlen(test_data));
3784 write_comps[i] = new librbd::RBD::AioCompletion(NULL, NULL);
3785 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3786 ASSERT_EQ(0, image.aio_write(offset, TEST_IO_SIZE, bls[i],
3787 write_comps[i]));
3788 }
3789
3790 librbd::RBD::AioCompletion *flush_comp =
3791 new librbd::RBD::AioCompletion(NULL, NULL);
3792 ASSERT_EQ(0, image.aio_flush(flush_comp));
3793 ASSERT_EQ(0, flush_comp->wait_for_complete());
3794 ASSERT_EQ(1, flush_comp->is_complete());
3795 flush_comp->release();
3796
3797 for (i = 0; i < num_aios; ++i) {
3798 librbd::RBD::AioCompletion *comp = write_comps[i];
3799 ASSERT_EQ(1, comp->is_complete());
3800 comp->release();
3801 }
3802 ASSERT_PASSED(validate_object_map, image);
3803 }
3804
3805 ioctx.close();
3806 }
3807
3808
3809 int iterate_cb(uint64_t off, size_t len, int exists, void *arg)
3810 {
3811 //cout << "iterate_cb " << off << "~" << len << std::endl;
3812 interval_set<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
3813 diff->insert(off, len);
3814 return 0;
3815 }
3816
3817 static int iterate_error_cb(uint64_t off, size_t len, int exists, void *arg)
3818 {
3819 return -EINVAL;
3820 }
3821
3822 void scribble(librbd::Image& image, int n, int max, bool skip_discard,
3823 interval_set<uint64_t> *exists,
3824 interval_set<uint64_t> *what)
3825 {
3826 uint64_t size;
3827 image.size(&size);
3828 interval_set<uint64_t> exists_at_start = *exists;
3829
3830 for (int i=0; i<n; i++) {
3831 uint64_t off = rand() % (size - max + 1);
3832 uint64_t len = 1 + rand() % max;
3833 if (!skip_discard && rand() % 4 == 0) {
3834 ASSERT_EQ((int)len, image.discard(off, len));
3835 interval_set<uint64_t> w;
3836 w.insert(off, len);
3837
3838 // the zeroed bit no longer exists...
3839 w.intersection_of(*exists);
3840 exists->subtract(w);
3841
3842 // the bits we discarded are no long written...
3843 interval_set<uint64_t> w2 = w;
3844 w2.intersection_of(*what);
3845 what->subtract(w2);
3846
3847 // except for the extents that existed at the start that we overwrote.
3848 interval_set<uint64_t> w3;
3849 w3.insert(off, len);
3850 w3.intersection_of(exists_at_start);
3851 what->union_of(w3);
3852
3853 } else {
3854 bufferlist bl;
3855 bl.append(buffer::create(len));
3856 bl.zero();
3857 ASSERT_EQ((int)len, image.write(off, len, bl));
3858 interval_set<uint64_t> w;
3859 w.insert(off, len);
3860 what->union_of(w);
3861 exists->union_of(w);
3862 }
3863 }
3864 }
3865
3866 interval_set<uint64_t> round_diff_interval(const interval_set<uint64_t>& diff,
3867 uint64_t object_size)
3868 {
3869 if (object_size == 0) {
3870 return diff;
3871 }
3872
3873 interval_set<uint64_t> rounded_diff;
3874 for (interval_set<uint64_t>::const_iterator it = diff.begin();
3875 it != diff.end(); ++it) {
3876 uint64_t off = it.get_start();
3877 uint64_t len = it.get_len();
3878 off -= off % object_size;
3879 len += (object_size - (len % object_size));
3880 interval_set<uint64_t> interval;
3881 interval.insert(off, len);
3882 rounded_diff.union_of(interval);
3883 }
3884 return rounded_diff;
3885 }
3886
3887 template <typename T>
3888 class DiffIterateTest : public TestLibRBD {
3889 public:
3890 static const uint8_t whole_object = T::whole_object;
3891 };
3892
3893 template <bool _whole_object>
3894 class DiffIterateParams {
3895 public:
3896 static const uint8_t whole_object = _whole_object;
3897 };
3898
3899 typedef ::testing::Types<DiffIterateParams<false>,
3900 DiffIterateParams<true> > DiffIterateTypes;
3901 TYPED_TEST_CASE(DiffIterateTest, DiffIterateTypes);
3902
3903 TYPED_TEST(DiffIterateTest, DiffIterate)
3904 {
3905 librados::IoCtx ioctx;
3906 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3907
3908 bool skip_discard = this->is_skip_partial_discard_enabled();
3909
3910 {
3911 librbd::RBD rbd;
3912 librbd::Image image;
3913 int order = 0;
3914 std::string name = this->get_temp_image_name();
3915 uint64_t size = 20 << 20;
3916
3917 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3918 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3919
3920 uint64_t object_size = 0;
3921 if (this->whole_object) {
3922 object_size = 1 << order;
3923 }
3924
3925 interval_set<uint64_t> exists;
3926 interval_set<uint64_t> one, two;
3927 scribble(image, 10, 102400, skip_discard, &exists, &one);
3928 cout << " wrote " << one << std::endl;
3929 ASSERT_EQ(0, image.snap_create("one"));
3930 scribble(image, 10, 102400, skip_discard, &exists, &two);
3931
3932 two = round_diff_interval(two, object_size);
3933 cout << " wrote " << two << std::endl;
3934
3935 interval_set<uint64_t> diff;
3936 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
3937 iterate_cb, (void *)&diff));
3938 cout << " diff was " << diff << std::endl;
3939 if (!two.subset_of(diff)) {
3940 interval_set<uint64_t> i;
3941 i.intersection_of(two, diff);
3942 interval_set<uint64_t> l = two;
3943 l.subtract(i);
3944 cout << " ... two - (two*diff) = " << l << std::endl;
3945 }
3946 ASSERT_TRUE(two.subset_of(diff));
3947 }
3948 ioctx.close();
3949 }
3950
3951 struct diff_extent {
3952 diff_extent(uint64_t _offset, uint64_t _length, bool _exists,
3953 uint64_t object_size) :
3954 offset(_offset), length(_length), exists(_exists)
3955 {
3956 if (object_size != 0) {
3957 offset -= offset % object_size;
3958 length = object_size;
3959 }
3960 }
3961 uint64_t offset;
3962 uint64_t length;
3963 bool exists;
3964 bool operator==(const diff_extent& o) const {
3965 return offset == o.offset && length == o.length && exists == o.exists;
3966 }
3967 };
3968
3969 ostream& operator<<(ostream & o, const diff_extent& e) {
3970 return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')';
3971 }
3972
3973 int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg)
3974 {
3975 cout << "iterate_cb " << off << "~" << len << std::endl;
3976 vector<diff_extent> *diff = static_cast<vector<diff_extent> *>(arg);
3977 diff->push_back(diff_extent(off, len, exists, 0));
3978 return 0;
3979 }
3980
3981 TYPED_TEST(DiffIterateTest, DiffIterateDiscard)
3982 {
3983 librados::IoCtx ioctx;
3984 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3985
3986 librbd::RBD rbd;
3987 librbd::Image image;
3988 int order = 0;
3989 std::string name = this->get_temp_image_name();
3990 uint64_t size = 20 << 20;
3991
3992 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3993 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3994
3995 uint64_t object_size = 0;
3996 if (this->whole_object) {
3997 object_size = 1 << order;
3998 }
3999 vector<diff_extent> extents;
4000 ceph::bufferlist bl;
4001
4002 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4003 vector_iterate_cb, (void *) &extents));
4004 ASSERT_EQ(0u, extents.size());
4005
4006 char data[256];
4007 memset(data, 1, sizeof(data));
4008 bl.append(data, 256);
4009 ASSERT_EQ(256, image.write(0, 256, bl));
4010 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4011 vector_iterate_cb, (void *) &extents));
4012 ASSERT_EQ(1u, extents.size());
4013 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4014
4015 int obj_ofs = 256;
4016 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
4017
4018 extents.clear();
4019 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4020 vector_iterate_cb, (void *) &extents));
4021 ASSERT_EQ(0u, extents.size());
4022
4023 ASSERT_EQ(0, image.snap_create("snap1"));
4024 ASSERT_EQ(256, image.write(0, 256, bl));
4025 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4026 vector_iterate_cb, (void *) &extents));
4027 ASSERT_EQ(1u, extents.size());
4028 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4029 ASSERT_EQ(0, image.snap_create("snap2"));
4030
4031 ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs));
4032
4033 extents.clear();
4034 ASSERT_EQ(0, image.snap_set("snap2"));
4035 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
4036 vector_iterate_cb, (void *) &extents));
4037 ASSERT_EQ(1u, extents.size());
4038 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4039
4040 ASSERT_EQ(0, image.snap_set(NULL));
4041 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
4042 ASSERT_EQ(0, image.snap_create("snap3"));
4043 ASSERT_EQ(0, image.snap_set("snap3"));
4044
4045 extents.clear();
4046 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
4047 vector_iterate_cb, (void *) &extents));
4048 ASSERT_EQ(1u, extents.size());
4049 ASSERT_EQ(diff_extent(0, 256, false, object_size), extents[0]);
4050 ASSERT_PASSED(this->validate_object_map, image);
4051 }
4052
4053 TYPED_TEST(DiffIterateTest, DiffIterateStress)
4054 {
4055 librados::IoCtx ioctx;
4056 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4057
4058 bool skip_discard = this->is_skip_partial_discard_enabled();
4059
4060 librbd::RBD rbd;
4061 librbd::Image image;
4062 int order = 0;
4063 std::string name = this->get_temp_image_name();
4064 uint64_t size = 400 << 20;
4065
4066 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4067 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4068
4069 uint64_t object_size = 0;
4070 if (this->whole_object) {
4071 object_size = 1 << order;
4072 }
4073
4074 interval_set<uint64_t> curexists;
4075 vector<interval_set<uint64_t> > wrote;
4076 vector<interval_set<uint64_t> > exists;
4077 vector<string> snap;
4078 int n = 20;
4079 for (int i=0; i<n; i++) {
4080 interval_set<uint64_t> w;
4081 scribble(image, 10, 8192000, skip_discard, &curexists, &w);
4082 cout << " i=" << i << " exists " << curexists << " wrote " << w << std::endl;
4083 string s = "snap" + stringify(i);
4084 ASSERT_EQ(0, image.snap_create(s.c_str()));
4085 wrote.push_back(w);
4086 exists.push_back(curexists);
4087 snap.push_back(s);
4088 }
4089
4090 for (int h=0; h<n-1; h++) {
4091 for (int i=0; i<n-h-1; i++) {
4092 for (int j=(h==0 ? i+1 : n-1); j<n; j++) {
4093 interval_set<uint64_t> diff, actual, uex;
4094 for (int k=i+1; k<=j; k++)
4095 diff.union_of(wrote[k]);
4096 cout << "from " << i << " to "
4097 << (h != 0 ? string("HEAD") : stringify(j)) << " diff "
4098 << round_diff_interval(diff, object_size) << std::endl;
4099
4100 // limit to extents that exists both at the beginning and at the end
4101 uex.union_of(exists[i], exists[j]);
4102 diff.intersection_of(uex);
4103 diff = round_diff_interval(diff, object_size);
4104 cout << " limited diff " << diff << std::endl;
4105
4106 ASSERT_EQ(0, image.snap_set(h==0 ? snap[j].c_str() : NULL));
4107 ASSERT_EQ(0, image.diff_iterate2(snap[i].c_str(), 0, size, true,
4108 this->whole_object, iterate_cb,
4109 (void *)&actual));
4110 cout << " actual was " << actual << std::endl;
4111 if (!diff.subset_of(actual)) {
4112 interval_set<uint64_t> i;
4113 i.intersection_of(diff, actual);
4114 interval_set<uint64_t> l = diff;
4115 l.subtract(i);
4116 cout << " ... diff - (actual*diff) = " << l << std::endl;
4117 }
4118 ASSERT_TRUE(diff.subset_of(actual));
4119 }
4120 }
4121 ASSERT_EQ(0, image.snap_set(NULL));
4122 ASSERT_EQ(0, image.snap_remove(snap[n-h-1].c_str()));
4123 }
4124
4125 ASSERT_PASSED(this->validate_object_map, image);
4126 }
4127
4128 TYPED_TEST(DiffIterateTest, DiffIterateRegression6926)
4129 {
4130 librados::IoCtx ioctx;
4131 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4132
4133 librbd::RBD rbd;
4134 librbd::Image image;
4135 int order = 0;
4136 std::string name = this->get_temp_image_name();
4137 uint64_t size = 20 << 20;
4138
4139 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4140 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4141
4142 uint64_t object_size = 0;
4143 if (this->whole_object) {
4144 object_size = 1 << order;
4145 }
4146 vector<diff_extent> extents;
4147 ceph::bufferlist bl;
4148
4149 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4150 vector_iterate_cb, (void *) &extents));
4151 ASSERT_EQ(0u, extents.size());
4152
4153 ASSERT_EQ(0, image.snap_create("snap1"));
4154 char data[256];
4155 memset(data, 1, sizeof(data));
4156 bl.append(data, 256);
4157 ASSERT_EQ(256, image.write(0, 256, bl));
4158
4159 extents.clear();
4160 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4161 vector_iterate_cb, (void *) &extents));
4162 ASSERT_EQ(1u, extents.size());
4163 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
4164
4165 ASSERT_EQ(0, image.snap_set("snap1"));
4166 extents.clear();
4167 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4168 vector_iterate_cb, (void *) &extents));
4169 ASSERT_EQ(static_cast<size_t>(0), extents.size());
4170 }
4171
4172 TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
4173 {
4174 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4175
4176 librados::IoCtx ioctx;
4177 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4178
4179 bool skip_discard = this->is_skip_partial_discard_enabled();
4180
4181 librbd::RBD rbd;
4182 librbd::Image image;
4183 std::string name = this->get_temp_image_name();
4184 uint64_t size = 20 << 20;
4185 int order = 0;
4186
4187 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4188 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4189
4190 uint64_t object_size = 0;
4191 if (this->whole_object) {
4192 object_size = 1 << order;
4193 }
4194
4195 bufferlist bl;
4196 bl.append(buffer::create(size));
4197 bl.zero();
4198 interval_set<uint64_t> one;
4199 one.insert(0, size);
4200 ASSERT_EQ((int)size, image.write(0, size, bl));
4201 ASSERT_EQ(0, image.snap_create("one"));
4202 ASSERT_EQ(0, image.snap_protect("one"));
4203
4204 std::string clone_name = this->get_temp_image_name();
4205 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
4206 RBD_FEATURE_LAYERING, &order));
4207 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
4208
4209 interval_set<uint64_t> exists;
4210 interval_set<uint64_t> two;
4211 scribble(image, 10, 102400, skip_discard, &exists, &two);
4212 two = round_diff_interval(two, object_size);
4213 cout << " wrote " << two << " to clone" << std::endl;
4214
4215 interval_set<uint64_t> diff;
4216 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, false, this->whole_object,
4217 iterate_cb, (void *)&diff));
4218 cout << " diff was " << diff << std::endl;
4219 if (!this->whole_object) {
4220 ASSERT_FALSE(one.subset_of(diff));
4221 }
4222 ASSERT_TRUE(two.subset_of(diff));
4223 }
4224
4225 TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
4226 {
4227 librados::IoCtx ioctx;
4228 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4229
4230 bool skip_discard = this->is_skip_partial_discard_enabled();
4231
4232 {
4233 librbd::RBD rbd;
4234 librbd::Image image;
4235 int order = 0;
4236 std::string name = this->get_temp_image_name();
4237 uint64_t size = 20 << 20;
4238
4239 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4240 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4241
4242 interval_set<uint64_t> exists;
4243 interval_set<uint64_t> one;
4244 scribble(image, 10, 102400, skip_discard, &exists, &one);
4245 cout << " wrote " << one << std::endl;
4246
4247 interval_set<uint64_t> diff;
4248 ASSERT_EQ(-EINVAL, image.diff_iterate2(NULL, 0, size, true,
4249 this->whole_object,
4250 iterate_error_cb, NULL));
4251 }
4252 ioctx.close();
4253 }
4254
4255 TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
4256 {
4257 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4258
4259 librados::IoCtx ioctx;
4260 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
4261
4262 bool skip_discard = this->is_skip_partial_discard_enabled();
4263
4264 librbd::RBD rbd;
4265 librbd::Image image;
4266 std::string name = this->get_temp_image_name();
4267 uint64_t size = 20 << 20;
4268 int order = 0;
4269
4270 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4271 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4272
4273 uint64_t object_size = 0;
4274 if (this->whole_object) {
4275 object_size = 1 << order;
4276 }
4277
4278 interval_set<uint64_t> exists;
4279 interval_set<uint64_t> one;
4280 scribble(image, 10, 102400, skip_discard, &exists, &one);
4281 ASSERT_EQ(0, image.snap_create("one"));
4282
4283 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
4284 ASSERT_EQ(0, image.snap_create("two"));
4285 ASSERT_EQ(0, image.snap_protect("two"));
4286 exists.clear();
4287 one.clear();
4288
4289 std::string clone_name = this->get_temp_image_name();
4290 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "two", ioctx,
4291 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
4292 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
4293
4294 interval_set<uint64_t> two;
4295 scribble(image, 10, 102400, skip_discard, &exists, &two);
4296 two = round_diff_interval(two, object_size);
4297
4298 interval_set<uint64_t> diff;
4299 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
4300 iterate_cb, (void *)&diff));
4301 ASSERT_TRUE(two.subset_of(diff));
4302 }
4303
4304 TEST_F(TestLibRBD, ZeroLengthWrite)
4305 {
4306 rados_ioctx_t ioctx;
4307 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4308
4309 rbd_image_t image;
4310 int order = 0;
4311 std::string name = get_temp_image_name();
4312 uint64_t size = 2 << 20;
4313
4314 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4315 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4316
4317 char read_data[1];
4318 ASSERT_EQ(0, rbd_write(image, 0, 0, NULL));
4319 ASSERT_EQ(1, rbd_read(image, 0, 1, read_data));
4320 ASSERT_EQ('\0', read_data[0]);
4321
4322 ASSERT_PASSED(validate_object_map, image);
4323 ASSERT_EQ(0, rbd_close(image));
4324
4325 rados_ioctx_destroy(ioctx);
4326 }
4327
4328
4329 TEST_F(TestLibRBD, ZeroLengthDiscard)
4330 {
4331 rados_ioctx_t ioctx;
4332 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4333
4334 rbd_image_t image;
4335 int order = 0;
4336 std::string name = get_temp_image_name();
4337 uint64_t size = 2 << 20;
4338
4339 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4340 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4341
4342 const char data[] = "blah";
4343 char read_data[sizeof(data)];
4344 ASSERT_EQ((int)strlen(data), rbd_write(image, 0, strlen(data), data));
4345 ASSERT_EQ(0, rbd_discard(image, 0, 0));
4346 ASSERT_EQ((int)strlen(data), rbd_read(image, 0, strlen(data), read_data));
4347 ASSERT_EQ(0, memcmp(data, read_data, strlen(data)));
4348
4349 ASSERT_PASSED(validate_object_map, image);
4350 ASSERT_EQ(0, rbd_close(image));
4351
4352 rados_ioctx_destroy(ioctx);
4353 }
4354
4355 TEST_F(TestLibRBD, ZeroLengthRead)
4356 {
4357 rados_ioctx_t ioctx;
4358 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4359
4360 rbd_image_t image;
4361 int order = 0;
4362 std::string name = get_temp_image_name();
4363 uint64_t size = 2 << 20;
4364
4365 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4366 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4367
4368 char read_data[1];
4369 ASSERT_EQ(0, rbd_read(image, 0, 0, read_data));
4370
4371 ASSERT_EQ(0, rbd_close(image));
4372
4373 rados_ioctx_destroy(ioctx);
4374 }
4375
4376 TEST_F(TestLibRBD, LargeCacheRead)
4377 {
4378 std::string config_value;
4379 ASSERT_EQ(0, _rados.conf_get("rbd_cache", config_value));
4380 if (config_value == "false") {
4381 std::cout << "SKIPPING due to disabled cache" << std::endl;
4382 return;
4383 }
4384
4385 rados_ioctx_t ioctx;
4386 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4387
4388 uint32_t new_cache_size = 1 << 20;
4389 std::string orig_cache_size;
4390 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", orig_cache_size));
4391 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size",
4392 stringify(new_cache_size).c_str()));
4393 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", config_value));
4394 ASSERT_EQ(stringify(new_cache_size), config_value);
4395 BOOST_SCOPE_EXIT( (orig_cache_size) ) {
4396 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size", orig_cache_size.c_str()));
4397 } BOOST_SCOPE_EXIT_END;
4398
4399 rbd_image_t image;
4400 int order = 21;
4401 std::string name = get_temp_image_name();
4402 uint64_t size = 1 << order;
4403
4404 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4405 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4406
4407 std::string buffer(1 << order, '1');
4408
4409 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
4410 rbd_write(image, 0, buffer.size(), buffer.c_str()));
4411
4412 ASSERT_EQ(0, rbd_invalidate_cache(image));
4413
4414 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
4415 rbd_read(image, 0, buffer.size(), &buffer[0]));
4416
4417 ASSERT_EQ(0, rbd_close(image));
4418
4419 rados_ioctx_destroy(ioctx);
4420 }
4421
4422 TEST_F(TestLibRBD, TestPendingAio)
4423 {
4424 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4425
4426 rados_ioctx_t ioctx;
4427 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4428
4429 bool old_format;
4430 uint64_t features;
4431 rbd_image_t image;
4432 int order = 0;
4433
4434 ASSERT_EQ(0, get_features(&old_format, &features));
4435 ASSERT_FALSE(old_format);
4436
4437 std::string name = get_temp_image_name();
4438
4439 uint64_t size = 4 << 20;
4440 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
4441 false, features));
4442 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4443
4444 char test_data[TEST_IO_SIZE];
4445 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
4446 test_data[i] = (char) (rand() % (126 - 33) + 33);
4447 }
4448
4449 size_t num_aios = 256;
4450 rbd_completion_t comps[num_aios];
4451 for (size_t i = 0; i < num_aios; ++i) {
4452 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
4453 uint64_t offset = rand() % (size - TEST_IO_SIZE);
4454 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
4455 comps[i]));
4456 }
4457 for (size_t i = 0; i < num_aios; ++i) {
4458 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps[i]));
4459 rbd_aio_release(comps[i]);
4460 }
4461 ASSERT_EQ(0, rbd_invalidate_cache(image));
4462
4463 for (size_t i = 0; i < num_aios; ++i) {
4464 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
4465 uint64_t offset = rand() % (size - TEST_IO_SIZE);
4466 ASSERT_LE(0, rbd_aio_read(image, offset, TEST_IO_SIZE, test_data,
4467 comps[i]));
4468 }
4469
4470 ASSERT_PASSED(validate_object_map, image);
4471 ASSERT_EQ(0, rbd_close(image));
4472 for (size_t i = 0; i < num_aios; ++i) {
4473 ASSERT_EQ(1, rbd_aio_is_complete(comps[i]));
4474 rbd_aio_release(comps[i]);
4475 }
4476
4477 rados_ioctx_destroy(ioctx);
4478 }
4479
4480 void compare_and_write_copyup(librados::IoCtx &ioctx, bool deep_copyup,
4481 bool *passed)
4482 {
4483 librbd::RBD rbd;
4484 std::string parent_name = TestLibRBD::get_temp_image_name();
4485 uint64_t size = 2 << 20;
4486 int order = 0;
4487 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4488
4489 librbd::Image parent_image;
4490 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4491
4492 bufferlist bl;
4493 bl.append(std::string(4096, '1'));
4494 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
4495
4496 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4497 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4498
4499 uint64_t features;
4500 ASSERT_EQ(0, parent_image.features(&features));
4501
4502 std::string clone_name = TestLibRBD::get_temp_image_name();
4503 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4504 clone_name.c_str(), features, &order));
4505
4506 librbd::Image clone_image;
4507 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
4508 if (deep_copyup) {
4509 ASSERT_EQ(0, clone_image.snap_create("snap1"));
4510 }
4511
4512 bufferlist cmp_bl;
4513 cmp_bl.append(std::string(96, '1'));
4514 bufferlist write_bl;
4515 write_bl.append(std::string(512, '2'));
4516 uint64_t mismatch_off;
4517 ASSERT_EQ((ssize_t)write_bl.length(),
4518 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
4519 write_bl, &mismatch_off, 0));
4520
4521 bufferlist read_bl;
4522 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
4523
4524 bufferlist expected_bl;
4525 expected_bl.append(std::string(512, '1'));
4526 expected_bl.append(std::string(512, '2'));
4527 expected_bl.append(std::string(3072, '1'));
4528 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
4529 *passed = true;
4530 }
4531
4532 TEST_F(TestLibRBD, CompareAndWriteCopyup)
4533 {
4534 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4535
4536 librados::IoCtx ioctx;
4537 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4538
4539 ASSERT_PASSED(compare_and_write_copyup, ioctx, false);
4540 ASSERT_PASSED(compare_and_write_copyup, ioctx, true);
4541 }
4542
4543 void compare_and_write_copyup_mismatch(librados::IoCtx &ioctx,
4544 bool deep_copyup, bool *passed)
4545 {
4546 librbd::RBD rbd;
4547 std::string parent_name = TestLibRBD::get_temp_image_name();
4548 uint64_t size = 2 << 20;
4549 int order = 0;
4550 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4551
4552 librbd::Image parent_image;
4553 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4554
4555 bufferlist bl;
4556 bl.append(std::string(4096, '1'));
4557 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
4558
4559 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4560 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4561
4562 uint64_t features;
4563 ASSERT_EQ(0, parent_image.features(&features));
4564
4565 std::string clone_name = TestLibRBD::get_temp_image_name();
4566 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4567 clone_name.c_str(), features, &order));
4568
4569 librbd::Image clone_image;
4570 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
4571 if (deep_copyup) {
4572 ASSERT_EQ(0, clone_image.snap_create("snap1"));
4573 }
4574
4575 bufferlist cmp_bl;
4576 cmp_bl.append(std::string(48, '1'));
4577 cmp_bl.append(std::string(48, '3'));
4578 bufferlist write_bl;
4579 write_bl.append(std::string(512, '2'));
4580 uint64_t mismatch_off;
4581 ASSERT_EQ(-EILSEQ,
4582 clone_image.compare_and_write(512, write_bl.length(), cmp_bl,
4583 write_bl, &mismatch_off, 0));
4584 ASSERT_EQ(48U, mismatch_off);
4585
4586 bufferlist read_bl;
4587 ASSERT_EQ(4096, clone_image.read(0, 4096, read_bl));
4588
4589 ASSERT_TRUE(bl.contents_equal(read_bl));
4590 *passed = true;
4591 }
4592
4593 TEST_F(TestLibRBD, CompareAndWriteCopyupMismatch)
4594 {
4595 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4596
4597 librados::IoCtx ioctx;
4598 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4599
4600 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, false);
4601 ASSERT_PASSED(compare_and_write_copyup_mismatch, ioctx, true);
4602 }
4603
4604 TEST_F(TestLibRBD, Flatten)
4605 {
4606 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4607
4608 librados::IoCtx ioctx;
4609 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4610
4611 librbd::RBD rbd;
4612 std::string parent_name = get_temp_image_name();
4613 uint64_t size = 2 << 20;
4614 int order = 0;
4615 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4616
4617 librbd::Image parent_image;
4618 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4619
4620 bufferlist bl;
4621 bl.append(std::string(4096, '1'));
4622 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
4623
4624 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4625 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4626
4627 uint64_t features;
4628 ASSERT_EQ(0, parent_image.features(&features));
4629
4630 std::string clone_name = get_temp_image_name();
4631 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4632 clone_name.c_str(), features, &order));
4633
4634 librbd::Image clone_image;
4635 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
4636 ASSERT_EQ(0, clone_image.flatten());
4637
4638 librbd::RBD::AioCompletion *read_comp =
4639 new librbd::RBD::AioCompletion(NULL, NULL);
4640 bufferlist read_bl;
4641 clone_image.aio_read(0, bl.length(), read_bl, read_comp);
4642 ASSERT_EQ(0, read_comp->wait_for_complete());
4643 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
4644 read_comp->release();
4645 ASSERT_TRUE(bl.contents_equal(read_bl));
4646
4647 ASSERT_PASSED(validate_object_map, clone_image);
4648 }
4649
4650 TEST_F(TestLibRBD, Sparsify)
4651 {
4652 rados_ioctx_t ioctx;
4653 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
4654 BOOST_SCOPE_EXIT_ALL(&ioctx) {
4655 rados_ioctx_destroy(ioctx);
4656 };
4657
4658 const size_t CHUNK_SIZE = 4096 * 2;
4659 rbd_image_t image;
4660 int order = 0;
4661 std::string name = get_temp_image_name();
4662 uint64_t size = CHUNK_SIZE * 1024;
4663
4664 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4665 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4666 BOOST_SCOPE_EXIT_ALL(&image) {
4667 rbd_close(image);
4668 };
4669
4670 char test_data[4 * CHUNK_SIZE + 1];
4671 for (size_t i = 0; i < 4 ; ++i) {
4672 for (size_t j = 0; j < CHUNK_SIZE; j++) {
4673 if (i % 2) {
4674 test_data[i * CHUNK_SIZE + j] = (char)(rand() % (126 - 33) + 33);
4675 } else {
4676 test_data[i * CHUNK_SIZE + j] = '\0';
4677 }
4678 }
4679 }
4680 test_data[4 * CHUNK_SIZE] = '\0';
4681
4682 ASSERT_PASSED(write_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
4683 ASSERT_EQ(0, rbd_flush(image));
4684
4685 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 16));
4686 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 1 << (order + 1)));
4687 ASSERT_EQ(-EINVAL, rbd_sparsify(image, 4096 + 1));
4688 ASSERT_EQ(0, rbd_sparsify(image, 4096));
4689
4690 ASSERT_PASSED(read_test_data, image, test_data, 0, 4 * CHUNK_SIZE, 0);
4691 }
4692
4693 TEST_F(TestLibRBD, SparsifyPP)
4694 {
4695 librados::IoCtx ioctx;
4696 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4697
4698 librbd::RBD rbd;
4699 std::string name = get_temp_image_name();
4700 uint64_t size = 12 * 1024 * 1024;
4701 int order = 0;
4702 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4703
4704 librbd::Image image;
4705 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
4706
4707 bufferlist bl;
4708 bl.append(std::string(4096, '\0'));
4709 bl.append(std::string(4096, '1'));
4710 bl.append(std::string(4096, '\0'));
4711 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
4712 ASSERT_EQ(0, image.flush());
4713
4714 ASSERT_EQ(-EINVAL, image.sparsify(16));
4715 ASSERT_EQ(-EINVAL, image.sparsify(1 << (order + 1)));
4716 ASSERT_EQ(-EINVAL, image.sparsify(4096 + 1));
4717 ASSERT_EQ(0, image.sparsify(4096));
4718
4719 bufferlist read_bl;
4720 ASSERT_EQ((ssize_t)bl.length(), image.read(0, bl.length(), read_bl));
4721 ASSERT_TRUE(bl.contents_equal(read_bl));
4722
4723 ASSERT_PASSED(validate_object_map, image);
4724 }
4725
4726 TEST_F(TestLibRBD, SnapshotLimit)
4727 {
4728 rados_ioctx_t ioctx;
4729 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4730
4731 rbd_image_t image;
4732 int order = 0;
4733 std::string name = get_temp_image_name();
4734 uint64_t size = 2 << 20;
4735 uint64_t limit;
4736
4737 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4738 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4739
4740 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
4741 ASSERT_EQ(UINT64_MAX, limit);
4742 ASSERT_EQ(0, rbd_snap_set_limit(image, 2));
4743 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
4744 ASSERT_EQ(2U, limit);
4745
4746 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
4747 ASSERT_EQ(-ERANGE, rbd_snap_set_limit(image, 0));
4748 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
4749 ASSERT_EQ(-EDQUOT, rbd_snap_create(image, "snap3"));
4750 ASSERT_EQ(0, rbd_snap_set_limit(image, UINT64_MAX));
4751 ASSERT_EQ(0, rbd_snap_create(image, "snap3"));
4752 ASSERT_EQ(0, rbd_close(image));
4753
4754 rados_ioctx_destroy(ioctx);
4755 }
4756
4757
4758 TEST_F(TestLibRBD, SnapshotLimitPP)
4759 {
4760 librados::IoCtx ioctx;
4761 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4762
4763 {
4764 librbd::RBD rbd;
4765 librbd::Image image;
4766 std::string name = get_temp_image_name();
4767 uint64_t size = 2 << 20;
4768 int order = 0;
4769 uint64_t limit;
4770
4771 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4772 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4773
4774 ASSERT_EQ(0, image.snap_get_limit(&limit));
4775 ASSERT_EQ(UINT64_MAX, limit);
4776 ASSERT_EQ(0, image.snap_set_limit(2));
4777 ASSERT_EQ(0, image.snap_get_limit(&limit));
4778 ASSERT_EQ(2U, limit);
4779
4780 ASSERT_EQ(0, image.snap_create("snap1"));
4781 ASSERT_EQ(-ERANGE, image.snap_set_limit(0));
4782 ASSERT_EQ(0, image.snap_create("snap2"));
4783 ASSERT_EQ(-EDQUOT, image.snap_create("snap3"));
4784 ASSERT_EQ(0, image.snap_set_limit(UINT64_MAX));
4785 ASSERT_EQ(0, image.snap_create("snap3"));
4786 }
4787
4788 ioctx.close();
4789 }
4790
4791 TEST_F(TestLibRBD, RebuildObjectMapViaLockOwner)
4792 {
4793 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
4794
4795 librados::IoCtx ioctx;
4796 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4797
4798 librbd::RBD rbd;
4799 std::string name = get_temp_image_name();
4800 uint64_t size = 2 << 20;
4801 int order = 0;
4802 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4803
4804 std::string object_map_oid;
4805 {
4806 librbd::Image image;
4807 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4808
4809 std::string image_id;
4810 ASSERT_EQ(0, get_image_id(image, &image_id));
4811 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
4812 }
4813
4814 // corrupt the object map
4815 bufferlist bl;
4816 bl.append("foo");
4817 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
4818
4819 librbd::Image image1;
4820 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4821
4822 bool lock_owner;
4823 bl.clear();
4824 ASSERT_EQ(0, image1.write(0, 0, bl));
4825 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4826 ASSERT_TRUE(lock_owner);
4827
4828 uint64_t flags;
4829 ASSERT_EQ(0, image1.get_flags(&flags));
4830 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
4831
4832 librbd::Image image2;
4833 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4834 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4835 ASSERT_FALSE(lock_owner);
4836
4837 PrintProgress prog_ctx;
4838 ASSERT_EQ(0, image2.rebuild_object_map(prog_ctx));
4839 ASSERT_PASSED(validate_object_map, image1);
4840 ASSERT_PASSED(validate_object_map, image2);
4841 }
4842
4843 TEST_F(TestLibRBD, RenameViaLockOwner)
4844 {
4845 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
4846
4847 librados::IoCtx ioctx;
4848 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4849
4850 librbd::RBD rbd;
4851 std::string name = get_temp_image_name();
4852 uint64_t size = 2 << 20;
4853 int order = 0;
4854 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4855
4856 librbd::Image image1;
4857 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4858
4859 bufferlist bl;
4860 ASSERT_EQ(0, image1.write(0, 0, bl));
4861
4862 bool lock_owner;
4863 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4864 ASSERT_TRUE(lock_owner);
4865
4866 std::string new_name = get_temp_image_name();
4867 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
4868 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4869 ASSERT_TRUE(lock_owner);
4870
4871 librbd::Image image2;
4872 ASSERT_EQ(0, rbd.open(ioctx, image2, new_name.c_str(), NULL));
4873 }
4874
4875 TEST_F(TestLibRBD, SnapCreateViaLockOwner)
4876 {
4877 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
4878
4879 librados::IoCtx ioctx;
4880 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4881
4882 librbd::RBD rbd;
4883 std::string name = get_temp_image_name();
4884 uint64_t size = 2 << 20;
4885 int order = 0;
4886 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4887
4888 librbd::Image image1;
4889 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4890
4891 // switch to writeback cache
4892 ASSERT_EQ(0, image1.flush());
4893
4894 bufferlist bl;
4895 bl.append(std::string(4096, '1'));
4896 ASSERT_EQ((ssize_t)bl.length(), image1.write(0, bl.length(), bl));
4897
4898 bool lock_owner;
4899 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4900 ASSERT_TRUE(lock_owner);
4901
4902 librbd::Image image2;
4903 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4904
4905 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4906 ASSERT_FALSE(lock_owner);
4907
4908 ASSERT_EQ(0, image2.snap_create("snap1"));
4909 bool exists;
4910 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4911 ASSERT_TRUE(exists);
4912 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
4913 ASSERT_TRUE(exists);
4914
4915 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4916 ASSERT_TRUE(lock_owner);
4917 }
4918
4919 TEST_F(TestLibRBD, SnapRemoveViaLockOwner)
4920 {
4921 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
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 bufferlist bl;
4936 ASSERT_EQ(0, image1.write(0, 0, bl));
4937 ASSERT_EQ(0, image1.snap_create("snap1"));
4938
4939 bool lock_owner;
4940 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4941 ASSERT_TRUE(lock_owner);
4942
4943 librbd::Image image2;
4944 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4945
4946 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4947 ASSERT_FALSE(lock_owner);
4948
4949 ASSERT_EQ(0, image2.snap_remove("snap1"));
4950 bool exists;
4951 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4952 ASSERT_FALSE(exists);
4953 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
4954 ASSERT_FALSE(exists);
4955
4956 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4957 ASSERT_TRUE(lock_owner);
4958 }
4959
4960 TEST_F(TestLibRBD, EnableJournalingViaLockOwner)
4961 {
4962 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
4963
4964 librados::IoCtx ioctx;
4965 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4966
4967 librbd::RBD rbd;
4968 std::string name = get_temp_image_name();
4969 uint64_t size = 2 << 20;
4970 int order = 0;
4971 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4972
4973 librbd::Image image1;
4974 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4975
4976 bufferlist bl;
4977 ASSERT_EQ(0, image1.write(0, 0, bl));
4978
4979 bool lock_owner;
4980 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4981 ASSERT_TRUE(lock_owner);
4982
4983 librbd::Image image2;
4984 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4985
4986 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, false));
4987
4988 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4989 ASSERT_TRUE(lock_owner);
4990 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4991 ASSERT_FALSE(lock_owner);
4992
4993 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, true));
4994
4995 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4996 ASSERT_FALSE(lock_owner);
4997 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4998 ASSERT_TRUE(lock_owner);
4999 }
5000
5001 TEST_F(TestLibRBD, SnapRemove2)
5002 {
5003 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5004
5005 librados::IoCtx ioctx;
5006 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5007
5008 librbd::RBD rbd;
5009 std::string name = get_temp_image_name();
5010 uint64_t size = 2 << 20;
5011 int order = 0;
5012 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5013
5014 librbd::Image image1;
5015 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5016
5017 bufferlist bl;
5018 ASSERT_EQ(0, image1.write(0, 0, bl));
5019 ASSERT_EQ(0, image1.snap_create("snap1"));
5020 bool exists;
5021 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5022 ASSERT_TRUE(exists);
5023 ASSERT_EQ(0, image1.snap_protect("snap1"));
5024 bool is_protected;
5025 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5026 ASSERT_TRUE(is_protected);
5027
5028 uint64_t features;
5029 ASSERT_EQ(0, image1.features(&features));
5030
5031 std::string child_name = get_temp_image_name();
5032 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
5033 child_name.c_str(), features, &order));
5034
5035 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5036 ASSERT_TRUE(exists);
5037 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5038 ASSERT_TRUE(is_protected);
5039
5040 ASSERT_EQ(-EBUSY, image1.snap_remove("snap1"));
5041 PrintProgress pp;
5042 ASSERT_EQ(0, image1.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE, pp));
5043 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
5044 ASSERT_FALSE(exists);
5045 }
5046
5047 TEST_F(TestLibRBD, SnapRenameViaLockOwner)
5048 {
5049 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
5050
5051 librados::IoCtx ioctx;
5052 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5053
5054 librbd::RBD rbd;
5055 std::string name = get_temp_image_name();
5056 uint64_t size = 2 << 20;
5057 int order = 0;
5058 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5059
5060 librbd::Image image1;
5061 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5062
5063 bufferlist bl;
5064 ASSERT_EQ(0, image1.write(0, 0, bl));
5065 ASSERT_EQ(0, image1.snap_create("snap1"));
5066
5067 bool lock_owner;
5068 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5069 ASSERT_TRUE(lock_owner);
5070
5071 librbd::Image image2;
5072 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5073
5074 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5075 ASSERT_FALSE(lock_owner);
5076
5077 ASSERT_EQ(0, image2.snap_rename("snap1", "snap1-rename"));
5078 bool exists;
5079 ASSERT_EQ(0, image1.snap_exists2("snap1-rename", &exists));
5080 ASSERT_TRUE(exists);
5081 ASSERT_EQ(0, image2.snap_exists2("snap1-rename", &exists));
5082 ASSERT_TRUE(exists);
5083
5084 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5085 ASSERT_TRUE(lock_owner);
5086 }
5087
5088 TEST_F(TestLibRBD, SnapProtectViaLockOwner)
5089 {
5090 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
5091
5092 librados::IoCtx ioctx;
5093 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5094
5095 librbd::RBD rbd;
5096 std::string name = get_temp_image_name();
5097 uint64_t size = 2 << 20;
5098 int order = 0;
5099 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5100
5101 librbd::Image image1;
5102 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5103
5104 bufferlist bl;
5105 ASSERT_EQ(0, image1.write(0, 0, bl));
5106
5107 bool lock_owner;
5108 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5109 ASSERT_TRUE(lock_owner);
5110 ASSERT_EQ(0, image1.snap_create("snap1"));
5111
5112 librbd::Image image2;
5113 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5114
5115 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5116 ASSERT_FALSE(lock_owner);
5117
5118 ASSERT_EQ(0, image2.snap_protect("snap1"));
5119 bool is_protected;
5120 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
5121 ASSERT_TRUE(is_protected);
5122 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5123 ASSERT_TRUE(is_protected);
5124
5125 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5126 ASSERT_TRUE(lock_owner);
5127 }
5128
5129 TEST_F(TestLibRBD, SnapUnprotectViaLockOwner)
5130 {
5131 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
5132
5133 librados::IoCtx ioctx;
5134 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5135
5136 librbd::RBD rbd;
5137 std::string name = get_temp_image_name();
5138 uint64_t size = 2 << 20;
5139 int order = 0;
5140 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5141
5142 librbd::Image image1;
5143 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5144
5145 bufferlist bl;
5146 ASSERT_EQ(0, image1.write(0, 0, bl));
5147
5148 bool lock_owner;
5149 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5150 ASSERT_TRUE(lock_owner);
5151 ASSERT_EQ(0, image1.snap_create("snap1"));
5152 ASSERT_EQ(0, image1.snap_protect("snap1"));
5153 bool is_protected;
5154 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5155 ASSERT_TRUE(is_protected);
5156
5157 librbd::Image image2;
5158 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5159
5160 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5161 ASSERT_FALSE(lock_owner);
5162
5163 ASSERT_EQ(0, image2.snap_unprotect("snap1"));
5164 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
5165 ASSERT_FALSE(is_protected);
5166 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
5167 ASSERT_FALSE(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, FlattenViaLockOwner)
5174 {
5175 REQUIRE_FEATURE(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 parent_name = get_temp_image_name();
5182 uint64_t size = 2 << 20;
5183 int order = 0;
5184 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
5185
5186 librbd::Image parent_image;
5187 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
5188 ASSERT_EQ(0, parent_image.snap_create("snap1"));
5189 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
5190
5191 uint64_t features;
5192 ASSERT_EQ(0, parent_image.features(&features));
5193
5194 std::string name = get_temp_image_name();
5195 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
5196 name.c_str(), features, &order));
5197
5198 librbd::Image image1;
5199 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5200
5201 bufferlist bl;
5202 ASSERT_EQ(0, image1.write(0, 0, bl));
5203
5204 bool lock_owner;
5205 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5206 ASSERT_TRUE(lock_owner);
5207
5208 librbd::Image image2;
5209 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5210
5211 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5212 ASSERT_FALSE(lock_owner);
5213
5214 ASSERT_EQ(0, image2.flatten());
5215
5216 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5217 ASSERT_TRUE(lock_owner);
5218 ASSERT_PASSED(validate_object_map, image1);
5219 }
5220
5221 TEST_F(TestLibRBD, ResizeViaLockOwner)
5222 {
5223 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5224
5225 librados::IoCtx ioctx;
5226 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5227
5228 librbd::RBD rbd;
5229 std::string name = get_temp_image_name();
5230 uint64_t size = 2 << 20;
5231 int order = 0;
5232 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5233
5234 librbd::Image image1;
5235 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5236
5237 bufferlist bl;
5238 ASSERT_EQ(0, image1.write(0, 0, bl));
5239
5240 bool lock_owner;
5241 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5242 ASSERT_TRUE(lock_owner);
5243
5244 librbd::Image image2;
5245 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5246
5247 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5248 ASSERT_FALSE(lock_owner);
5249
5250 ASSERT_EQ(0, image2.resize(0));
5251
5252 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5253 ASSERT_TRUE(lock_owner);
5254 ASSERT_PASSED(validate_object_map, image1);
5255 }
5256
5257 TEST_F(TestLibRBD, SparsifyViaLockOwner)
5258 {
5259 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5260
5261 librados::IoCtx ioctx;
5262 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5263
5264 librbd::RBD rbd;
5265 std::string name = get_temp_image_name();
5266 uint64_t size = 2 << 20;
5267 int order = 0;
5268 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5269
5270 librbd::Image image1;
5271 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5272
5273 bufferlist bl;
5274 ASSERT_EQ(0, image1.write(0, 0, bl));
5275
5276 bool lock_owner;
5277 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5278 ASSERT_TRUE(lock_owner);
5279
5280 librbd::Image image2;
5281 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5282
5283 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
5284 ASSERT_FALSE(lock_owner);
5285
5286 ASSERT_EQ(0, image2.sparsify(4096));
5287
5288 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5289 ASSERT_TRUE(lock_owner);
5290 ASSERT_PASSED(validate_object_map, image1);
5291 }
5292
5293 TEST_F(TestLibRBD, ObjectMapConsistentSnap)
5294 {
5295 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
5296
5297 librados::IoCtx ioctx;
5298 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5299
5300 librbd::RBD rbd;
5301 std::string name = get_temp_image_name();
5302 uint64_t size = 1 << 20;
5303 int order = 12;
5304 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5305
5306 librbd::Image image1;
5307 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5308
5309 int num_snaps = 10;
5310 for (int i = 0; i < num_snaps; ++i) {
5311 std::string snap_name = "snap" + stringify(i);
5312 ASSERT_EQ(0, image1.snap_create(snap_name.c_str()));
5313 }
5314
5315
5316 thread writer([&image1](){
5317 librbd::image_info_t info;
5318 int r = image1.stat(info, sizeof(info));
5319 ceph_assert(r == 0);
5320 bufferlist bl;
5321 bl.append("foo");
5322 for (unsigned i = 0; i < info.num_objs; ++i) {
5323 r = image1.write((1 << info.order) * i, bl.length(), bl);
5324 ceph_assert(r == (int) bl.length());
5325 }
5326 });
5327 writer.join();
5328
5329 for (int i = 0; i < num_snaps; ++i) {
5330 std::string snap_name = "snap" + stringify(i);
5331 ASSERT_EQ(0, image1.snap_set(snap_name.c_str()));
5332 ASSERT_PASSED(validate_object_map, image1);
5333 }
5334
5335 ASSERT_EQ(0, image1.snap_set(NULL));
5336 ASSERT_PASSED(validate_object_map, image1);
5337 }
5338
5339 void memset_rand(char *buf, size_t len) {
5340 for (size_t i = 0; i < len; ++i) {
5341 buf[i] = (char) (rand() % (126 - 33) + 33);
5342 }
5343 }
5344
5345 TEST_F(TestLibRBD, Metadata)
5346 {
5347 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5348
5349 rados_ioctx_t ioctx;
5350 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5351
5352 std::string name = get_temp_image_name();
5353 uint64_t size = 2 << 20;
5354 int order = 0;
5355 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5356
5357 rbd_image_t image;
5358 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5359
5360 rbd_image_t image1;
5361 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
5362
5363 char keys[1024];
5364 char vals[1024];
5365 size_t keys_len = sizeof(keys);
5366 size_t vals_len = sizeof(vals);
5367
5368 memset_rand(keys, keys_len);
5369 memset_rand(vals, vals_len);
5370
5371 ASSERT_EQ(0, rbd_metadata_list(image, "", 0, keys, &keys_len, vals,
5372 &vals_len));
5373 ASSERT_EQ(0U, keys_len);
5374 ASSERT_EQ(0U, vals_len);
5375
5376 char value[1024];
5377 size_t value_len = sizeof(value);
5378 memset_rand(value, value_len);
5379
5380 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
5381 ASSERT_EQ(0, rbd_metadata_set(image1, "key2", "value2"));
5382 ASSERT_EQ(0, rbd_metadata_get(image1, "key1", value, &value_len));
5383 ASSERT_STREQ(value, "value1");
5384 value_len = 1;
5385 ASSERT_EQ(-ERANGE, rbd_metadata_get(image1, "key1", value, &value_len));
5386 ASSERT_EQ(value_len, strlen("value1") + 1);
5387
5388 ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
5389 &vals_len));
5390 keys_len = sizeof(keys);
5391 vals_len = sizeof(vals);
5392 memset_rand(keys, keys_len);
5393 memset_rand(vals, vals_len);
5394 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
5395 &vals_len));
5396 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
5397 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
5398 ASSERT_STREQ(keys, "key1");
5399 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
5400 ASSERT_STREQ(vals, "value1");
5401 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
5402
5403 ASSERT_EQ(0, rbd_metadata_remove(image1, "key1"));
5404 ASSERT_EQ(-ENOENT, rbd_metadata_remove(image1, "key3"));
5405 value_len = sizeof(value);
5406 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key3", value, &value_len));
5407 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
5408 &vals_len));
5409 ASSERT_EQ(keys_len, strlen("key2") + 1);
5410 ASSERT_EQ(vals_len, strlen("value2") + 1);
5411 ASSERT_STREQ(keys, "key2");
5412 ASSERT_STREQ(vals, "value2");
5413
5414 // test config setting
5415 ASSERT_EQ(0, rbd_metadata_set(image1, "conf_rbd_cache", "false"));
5416 ASSERT_EQ(-EINVAL, rbd_metadata_set(image1, "conf_rbd_cache", "INVALID_VAL"));
5417 ASSERT_EQ(0, rbd_metadata_remove(image1, "conf_rbd_cache"));
5418
5419 // test metadata with snapshot adding
5420 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
5421 ASSERT_EQ(0, rbd_snap_protect(image1, "snap1"));
5422 ASSERT_EQ(0, rbd_snap_set(image1, "snap1"));
5423
5424 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
5425 ASSERT_EQ(0, rbd_metadata_set(image1, "key3", "value3"));
5426
5427 keys_len = sizeof(keys);
5428 vals_len = sizeof(vals);
5429 memset_rand(keys, keys_len);
5430 memset_rand(vals, vals_len);
5431 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
5432 &vals_len));
5433 ASSERT_EQ(keys_len,
5434 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5435 ASSERT_EQ(vals_len,
5436 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5437 ASSERT_STREQ(keys, "key1");
5438 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
5439 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
5440 ASSERT_STREQ(vals, "value1");
5441 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
5442 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
5443
5444 ASSERT_EQ(0, rbd_snap_set(image1, NULL));
5445 keys_len = sizeof(keys);
5446 vals_len = sizeof(vals);
5447 memset_rand(keys, keys_len);
5448 memset_rand(vals, vals_len);
5449 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
5450 &vals_len));
5451 ASSERT_EQ(keys_len,
5452 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5453 ASSERT_EQ(vals_len,
5454 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5455 ASSERT_STREQ(keys, "key1");
5456 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
5457 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
5458 ASSERT_STREQ(vals, "value1");
5459 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
5460 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
5461
5462 // test metadata with cloning
5463 uint64_t features;
5464 ASSERT_EQ(0, rbd_get_features(image1, &features));
5465
5466 string cname = get_temp_image_name();
5467 EXPECT_EQ(0, rbd_clone(ioctx, name.c_str(), "snap1", ioctx,
5468 cname.c_str(), features, &order));
5469 rbd_image_t image2;
5470 ASSERT_EQ(0, rbd_open(ioctx, cname.c_str(), &image2, NULL));
5471 ASSERT_EQ(0, rbd_metadata_set(image2, "key4", "value4"));
5472
5473 keys_len = sizeof(keys);
5474 vals_len = sizeof(vals);
5475 memset_rand(keys, keys_len);
5476 memset_rand(vals, vals_len);
5477 ASSERT_EQ(0, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
5478 &vals_len));
5479 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5480 1 + strlen("key4") + 1);
5481 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
5482 strlen("value3") + 1 + strlen("value4") + 1);
5483 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5484 1, "key4");
5485 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1 +
5486 strlen("value3") + 1, "value4");
5487
5488 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
5489 &vals_len));
5490 ASSERT_EQ(keys_len,
5491 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
5492 ASSERT_EQ(vals_len,
5493 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
5494 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key4", value, &value_len));
5495
5496 // test short buffer cases
5497 keys_len = strlen("key1") + 1;
5498 vals_len = strlen("value1") + 1;
5499 memset_rand(keys, keys_len);
5500 memset_rand(vals, vals_len);
5501 ASSERT_EQ(0, rbd_metadata_list(image2, "", 1, keys, &keys_len, vals,
5502 &vals_len));
5503 ASSERT_EQ(keys_len, strlen("key1") + 1);
5504 ASSERT_EQ(vals_len, strlen("value1") + 1);
5505 ASSERT_STREQ(keys, "key1");
5506 ASSERT_STREQ(vals, "value1");
5507
5508 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 2, keys, &keys_len, vals,
5509 &vals_len));
5510 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
5511 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
5512
5513 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
5514 &vals_len));
5515 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
5516 1 + strlen("key4") + 1);
5517 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
5518 strlen("value3") + 1 + strlen("value4") + 1);
5519
5520 // test `start` param
5521 keys_len = sizeof(keys);
5522 vals_len = sizeof(vals);
5523 memset_rand(keys, keys_len);
5524 memset_rand(vals, vals_len);
5525 ASSERT_EQ(0, rbd_metadata_list(image2, "key2", 0, keys, &keys_len, vals,
5526 &vals_len));
5527 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
5528 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
5529 ASSERT_STREQ(keys, "key3");
5530 ASSERT_STREQ(vals, "value3");
5531
5532 ASSERT_EQ(0, rbd_close(image));
5533 ASSERT_EQ(0, rbd_close(image1));
5534 ASSERT_EQ(0, rbd_close(image2));
5535 rados_ioctx_destroy(ioctx);
5536 }
5537
5538 TEST_F(TestLibRBD, MetadataPP)
5539 {
5540 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5541
5542 librados::IoCtx ioctx;
5543 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5544
5545 librbd::RBD rbd;
5546 string name = get_temp_image_name();
5547 uint64_t size = 2 << 20;
5548 int order = 0;
5549 uint64_t features;
5550 string value;
5551 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5552
5553 librbd::Image image1;
5554 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5555 map<string, bufferlist> pairs;
5556 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
5557 ASSERT_TRUE(pairs.empty());
5558
5559 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
5560 ASSERT_EQ(0, image1.metadata_set("key2", "value2"));
5561 ASSERT_EQ(0, image1.metadata_get("key1", &value));
5562 ASSERT_EQ(0, strcmp("value1", value.c_str()));
5563 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
5564 ASSERT_EQ(2U, pairs.size());
5565 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
5566 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
5567
5568 pairs.clear();
5569 ASSERT_EQ(0, image1.metadata_remove("key1"));
5570 ASSERT_EQ(-ENOENT, image1.metadata_remove("key3"));
5571 ASSERT_TRUE(image1.metadata_get("key3", &value) < 0);
5572 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
5573 ASSERT_EQ(1U, pairs.size());
5574 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
5575
5576 // test config setting
5577 ASSERT_EQ(0, image1.metadata_set("conf_rbd_cache", "false"));
5578 ASSERT_EQ(-EINVAL, image1.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
5579 ASSERT_EQ(0, image1.metadata_remove("conf_rbd_cache"));
5580
5581 // test metadata with snapshot adding
5582 ASSERT_EQ(0, image1.snap_create("snap1"));
5583 ASSERT_EQ(0, image1.snap_protect("snap1"));
5584 ASSERT_EQ(0, image1.snap_set("snap1"));
5585
5586 pairs.clear();
5587 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
5588 ASSERT_EQ(0, image1.metadata_set("key3", "value3"));
5589 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
5590 ASSERT_EQ(3U, pairs.size());
5591 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
5592 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
5593 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
5594
5595 ASSERT_EQ(0, image1.snap_set(NULL));
5596 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
5597 ASSERT_EQ(3U, pairs.size());
5598 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
5599 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
5600 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
5601
5602 // test metadata with cloning
5603 string cname = get_temp_image_name();
5604 librbd::Image image2;
5605 ASSERT_EQ(0, image1.features(&features));
5606 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
5607 cname.c_str(), features, &order));
5608 ASSERT_EQ(0, rbd.open(ioctx, image2, cname.c_str(), NULL));
5609 ASSERT_EQ(0, image2.metadata_set("key4", "value4"));
5610 pairs.clear();
5611 ASSERT_EQ(0, image2.metadata_list("", 0, &pairs));
5612 ASSERT_EQ(4U, pairs.size());
5613 pairs.clear();
5614 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
5615 ASSERT_EQ(3U, pairs.size());
5616 ASSERT_EQ(-ENOENT, image1.metadata_get("key4", &value));
5617 }
5618
5619 TEST_F(TestLibRBD, UpdateFeatures)
5620 {
5621 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5622
5623 librados::IoCtx ioctx;
5624 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5625
5626 librbd::RBD rbd;
5627 std::string name = get_temp_image_name();
5628 uint64_t size = 1 << 20;
5629 int order = 0;
5630 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5631
5632 librbd::Image image;
5633 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5634
5635 uint8_t old_format;
5636 ASSERT_EQ(0, image.old_format(&old_format));
5637 if (old_format) {
5638 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
5639 return;
5640 }
5641
5642 uint64_t features;
5643 ASSERT_EQ(0, image.features(&features));
5644
5645 // must provide a single feature
5646 ASSERT_EQ(-EINVAL, image.update_features(0, true));
5647
5648 uint64_t disable_features;
5649 disable_features = features & (RBD_FEATURE_EXCLUSIVE_LOCK |
5650 RBD_FEATURE_OBJECT_MAP |
5651 RBD_FEATURE_FAST_DIFF |
5652 RBD_FEATURE_JOURNALING);
5653 if (disable_features != 0) {
5654 ASSERT_EQ(0, image.update_features(disable_features, false));
5655 }
5656
5657 ASSERT_EQ(0, image.features(&features));
5658 ASSERT_EQ(0U, features & disable_features);
5659
5660 // cannot enable object map nor journaling w/o exclusive lock
5661 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
5662 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_JOURNALING, true));
5663 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
5664
5665 ASSERT_EQ(0, image.features(&features));
5666 ASSERT_NE(0U, features & RBD_FEATURE_EXCLUSIVE_LOCK);
5667
5668 // can enable fast diff w/o object map
5669 ASSERT_EQ(0, image.update_features(RBD_FEATURE_FAST_DIFF, true));
5670 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
5671 ASSERT_EQ(0, image.features(&features));
5672 ASSERT_NE(0U, features & RBD_FEATURE_OBJECT_MAP);
5673
5674 uint64_t expected_flags = RBD_FLAG_OBJECT_MAP_INVALID |
5675 RBD_FLAG_FAST_DIFF_INVALID;
5676 uint64_t flags;
5677 ASSERT_EQ(0, image.get_flags(&flags));
5678 ASSERT_EQ(expected_flags, flags);
5679
5680 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
5681 ASSERT_EQ(0, image.features(&features));
5682 ASSERT_EQ(0U, features & RBD_FEATURE_OBJECT_MAP);
5683
5684 // can disable object map w/ fast diff
5685 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
5686 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
5687 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_FAST_DIFF, false));
5688 ASSERT_EQ(0, image.features(&features));
5689 ASSERT_EQ(0U, features & RBD_FEATURE_FAST_DIFF);
5690
5691 ASSERT_EQ(0, image.get_flags(&flags));
5692 ASSERT_EQ(0U, flags);
5693
5694 // cannot disable exclusive lock w/ object map
5695 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
5696 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
5697 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
5698
5699 // cannot disable exclusive lock w/ journaling
5700 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, true));
5701 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
5702 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, false));
5703
5704 ASSERT_EQ(0, image.get_flags(&flags));
5705 ASSERT_EQ(0U, flags);
5706
5707 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
5708
5709 ASSERT_EQ(0, image.features(&features));
5710 if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0) {
5711 ASSERT_EQ(0, image.update_features(RBD_FEATURE_DEEP_FLATTEN, false));
5712 }
5713 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_DEEP_FLATTEN, true));
5714 }
5715
5716 TEST_F(TestLibRBD, RebuildObjectMap)
5717 {
5718 librados::IoCtx ioctx;
5719 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5720
5721 librbd::RBD rbd;
5722 std::string name = get_temp_image_name();
5723 uint64_t size = 1 << 20;
5724 int order = 18;
5725 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5726
5727 PrintProgress prog_ctx;
5728 std::string object_map_oid;
5729 bufferlist bl;
5730 bl.append("foo");
5731 {
5732 librbd::Image image;
5733 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5734
5735 uint64_t features;
5736 ASSERT_EQ(0, image.features(&features));
5737 if ((features & RBD_FEATURE_OBJECT_MAP) == 0) {
5738 ASSERT_EQ(-EINVAL, image.rebuild_object_map(prog_ctx));
5739 return;
5740 }
5741
5742 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
5743
5744 ASSERT_EQ(0, image.snap_create("snap1"));
5745 ASSERT_EQ((ssize_t)bl.length(), image.write(1<<order, bl.length(), bl));
5746
5747 std::string image_id;
5748 ASSERT_EQ(0, get_image_id(image, &image_id));
5749 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
5750 }
5751
5752 // corrupt the object map
5753 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
5754
5755 librbd::Image image1;
5756 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5757
5758 bool lock_owner;
5759 bl.clear();
5760 ASSERT_EQ(0, image1.write(0, 0, bl));
5761 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5762 ASSERT_TRUE(lock_owner);
5763
5764 uint64_t flags;
5765 ASSERT_EQ(0, image1.get_flags(&flags));
5766 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
5767
5768 ASSERT_EQ(0, image1.rebuild_object_map(prog_ctx));
5769
5770 librbd::Image image2;
5771 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5772
5773 bufferlist read_bl;
5774 ASSERT_EQ((ssize_t)bl.length(), image2.read(0, bl.length(), read_bl));
5775 ASSERT_TRUE(bl.contents_equal(read_bl));
5776
5777 read_bl.clear();
5778 ASSERT_EQ((ssize_t)bl.length(), image2.read(1<<order, bl.length(), read_bl));
5779 ASSERT_TRUE(bl.contents_equal(read_bl));
5780
5781 ASSERT_PASSED(validate_object_map, image1);
5782 ASSERT_PASSED(validate_object_map, image2);
5783 }
5784
5785 TEST_F(TestLibRBD, RebuildNewObjectMap)
5786 {
5787 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
5788
5789 rados_ioctx_t ioctx;
5790 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5791
5792 std::string name = get_temp_image_name();
5793 uint64_t size = 1 << 20;
5794 int order = 18;
5795 uint64_t features = RBD_FEATURE_EXCLUSIVE_LOCK;
5796 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
5797 false, features));
5798
5799 rbd_image_t image;
5800 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5801 ASSERT_EQ(0, rbd_update_features(image, RBD_FEATURE_OBJECT_MAP, true));
5802 ASSERT_EQ(0, rbd_rebuild_object_map(image, print_progress_percent, NULL));
5803
5804 ASSERT_PASSED(validate_object_map, image);
5805
5806 ASSERT_EQ(0, rbd_close(image));
5807 rados_ioctx_destroy(ioctx);
5808 }
5809
5810 TEST_F(TestLibRBD, CheckObjectMap)
5811 {
5812 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
5813
5814 librados::IoCtx ioctx;
5815 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5816
5817 librbd::RBD rbd;
5818 std::string name = get_temp_image_name();
5819 uint64_t size = 1 << 20;
5820 int order = 18;
5821 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5822
5823 PrintProgress prog_ctx;
5824 bufferlist bl1;
5825 bufferlist bl2;
5826 bl1.append("foo");
5827 {
5828 librbd::Image image;
5829 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5830
5831 uint64_t features;
5832 ASSERT_EQ(0, image.features(&features));
5833
5834 ASSERT_EQ((ssize_t)bl1.length(), image.write(0, bl1.length(), bl1));
5835
5836 ASSERT_EQ(0, image.snap_create("snap1"));
5837 ASSERT_EQ((ssize_t)bl1.length(), image.write(1<<order, bl1.length(), bl1));
5838 }
5839
5840 librbd::Image image1;
5841 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5842
5843 std::string image_id;
5844 ASSERT_EQ(0, get_image_id(image1, &image_id));
5845
5846 std::string object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
5847
5848 ASSERT_LT(0, ioctx.read(object_map_oid, bl2, 1024, 0));
5849
5850 bool lock_owner;
5851 ASSERT_EQ((ssize_t)bl1.length(), image1.write(3 * (1 << 18), bl1.length(), bl1));
5852 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5853 ASSERT_TRUE(lock_owner);
5854
5855 //reopen image to reread now corrupt object map from disk
5856 image1.close();
5857
5858 bl1.clear();
5859 ASSERT_LT(0, ioctx.read(object_map_oid, bl1, 1024, 0));
5860 ASSERT_FALSE(bl1.contents_equal(bl2));
5861
5862 ASSERT_EQ(0, ioctx.write_full(object_map_oid, bl2));
5863 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5864
5865 uint64_t flags;
5866 ASSERT_EQ(0, image1.get_flags(&flags));
5867 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
5868
5869 ASSERT_EQ(0, image1.check_object_map(prog_ctx));
5870
5871 ASSERT_EQ(0, image1.get_flags(&flags));
5872 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
5873 }
5874
5875 TEST_F(TestLibRBD, BlockingAIO)
5876 {
5877 librados::IoCtx ioctx;
5878 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5879
5880 bool skip_discard = is_skip_partial_discard_enabled();
5881
5882 librbd::RBD rbd;
5883 std::string name = get_temp_image_name();
5884 uint64_t size = 1 << 20;
5885 int order = 18;
5886 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5887
5888 std::string non_blocking_aio;
5889 ASSERT_EQ(0, _rados.conf_get("rbd_non_blocking_aio", non_blocking_aio));
5890 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio", "0"));
5891 BOOST_SCOPE_EXIT( (non_blocking_aio) ) {
5892 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio",
5893 non_blocking_aio.c_str()));
5894 } BOOST_SCOPE_EXIT_END;
5895
5896 librbd::Image image;
5897 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5898
5899 bufferlist bl;
5900 ASSERT_EQ(0, image.write(0, bl.length(), bl));
5901
5902 bl.append(std::string(256, '1'));
5903 librbd::RBD::AioCompletion *write_comp =
5904 new librbd::RBD::AioCompletion(NULL, NULL);
5905 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
5906
5907 librbd::RBD::AioCompletion *flush_comp =
5908 new librbd::RBD::AioCompletion(NULL, NULL);
5909 ASSERT_EQ(0, image.aio_flush(flush_comp));
5910 ASSERT_EQ(0, flush_comp->wait_for_complete());
5911 ASSERT_EQ(0, flush_comp->get_return_value());
5912 flush_comp->release();
5913
5914 ASSERT_EQ(1, write_comp->is_complete());
5915 ASSERT_EQ(0, write_comp->get_return_value());
5916 write_comp->release();
5917
5918 librbd::RBD::AioCompletion *discard_comp =
5919 new librbd::RBD::AioCompletion(NULL, NULL);
5920 ASSERT_EQ(0, image.aio_discard(128, 128, discard_comp));
5921 ASSERT_EQ(0, discard_comp->wait_for_complete());
5922 discard_comp->release();
5923
5924 librbd::RBD::AioCompletion *read_comp =
5925 new librbd::RBD::AioCompletion(NULL, NULL);
5926 bufferlist read_bl;
5927 image.aio_read(0, bl.length(), read_bl, read_comp);
5928 ASSERT_EQ(0, read_comp->wait_for_complete());
5929 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
5930 read_comp->release();
5931
5932 bufferlist expected_bl;
5933 expected_bl.append(std::string(128, '1'));
5934 expected_bl.append(std::string(128, skip_discard ? '1' : '\0'));
5935 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
5936 }
5937
5938 TEST_F(TestLibRBD, ExclusiveLockTransition)
5939 {
5940 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5941
5942 librados::IoCtx ioctx;
5943 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5944
5945 librbd::RBD rbd;
5946 std::string name = get_temp_image_name();
5947
5948 uint64_t size = 1 << 18;
5949 int order = 12;
5950 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5951
5952 librbd::Image image1;
5953 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5954
5955 librbd::Image image2;
5956 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5957
5958 std::list<librbd::RBD::AioCompletion *> comps;
5959 ceph::bufferlist bl;
5960 bl.append(std::string(1 << order, '1'));
5961 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5962 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
5963 NULL);
5964 comps.push_back(comp);
5965 if (object_no % 2 == 0) {
5966 ASSERT_EQ(0, image1.aio_write(object_no << order, bl.length(), bl, comp));
5967 } else {
5968 ASSERT_EQ(0, image2.aio_write(object_no << order, bl.length(), bl, comp));
5969 }
5970 }
5971
5972 while (!comps.empty()) {
5973 librbd::RBD::AioCompletion *comp = comps.front();
5974 comps.pop_front();
5975 ASSERT_EQ(0, comp->wait_for_complete());
5976 ASSERT_EQ(1, comp->is_complete());
5977 comp->release();
5978 }
5979
5980 librbd::Image image3;
5981 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
5982 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5983 bufferlist read_bl;
5984 ASSERT_EQ((ssize_t)bl.length(), image3.read(object_no << order, bl.length(),
5985 read_bl));
5986 ASSERT_TRUE(bl.contents_equal(read_bl));
5987 }
5988
5989 ASSERT_PASSED(validate_object_map, image1);
5990 ASSERT_PASSED(validate_object_map, image2);
5991 ASSERT_PASSED(validate_object_map, image3);
5992 }
5993
5994 TEST_F(TestLibRBD, ExclusiveLockReadTransition)
5995 {
5996 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
5997
5998 librados::IoCtx ioctx;
5999 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6000
6001 librbd::RBD rbd;
6002 std::string name = get_temp_image_name();
6003
6004 uint64_t size = 1 << 18;
6005 int order = 12;
6006 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6007
6008 librbd::Image image1;
6009 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6010
6011 bool lock_owner;
6012 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
6013 ASSERT_FALSE(lock_owner);
6014
6015 // journaling should force read ops to acquire the lock
6016 bufferlist read_bl;
6017 ASSERT_EQ(0, image1.read(0, 0, read_bl));
6018
6019 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
6020 ASSERT_TRUE(lock_owner);
6021
6022 librbd::Image image2;
6023 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
6024
6025 std::list<librbd::RBD::AioCompletion *> comps;
6026 std::list<bufferlist> read_bls;
6027 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
6028 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
6029 NULL);
6030 comps.push_back(comp);
6031 read_bls.emplace_back();
6032 if (object_no % 2 == 0) {
6033 ASSERT_EQ(0, image1.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
6034 } else {
6035 ASSERT_EQ(0, image2.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
6036 }
6037 }
6038
6039 while (!comps.empty()) {
6040 librbd::RBD::AioCompletion *comp = comps.front();
6041 comps.pop_front();
6042 ASSERT_EQ(0, comp->wait_for_complete());
6043 ASSERT_EQ(1, comp->is_complete());
6044 comp->release();
6045 }
6046 }
6047
6048 TEST_F(TestLibRBD, CacheMayCopyOnWrite) {
6049 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6050
6051 librados::IoCtx ioctx;
6052 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6053
6054 librbd::RBD rbd;
6055 std::string name = get_temp_image_name();
6056
6057 uint64_t size = 1 << 18;
6058 int order = 12;
6059 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6060
6061 librbd::Image image;
6062 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6063 ASSERT_EQ(0, image.snap_create("one"));
6064 ASSERT_EQ(0, image.snap_protect("one"));
6065
6066 std::string clone_name = this->get_temp_image_name();
6067 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
6068 RBD_FEATURE_LAYERING, &order));
6069
6070 librbd::Image clone;
6071 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
6072 ASSERT_EQ(0, clone.flush());
6073
6074 bufferlist expect_bl;
6075 expect_bl.append(std::string(1024, '\0'));
6076
6077 // test double read path
6078 bufferlist read_bl;
6079 uint64_t offset = 0;
6080 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
6081 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
6082
6083 bufferlist write_bl;
6084 write_bl.append(std::string(1024, '1'));
6085 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
6086
6087 read_bl.clear();
6088 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
6089 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
6090
6091 // test read retry path
6092 offset = 1 << order;
6093 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
6094
6095 read_bl.clear();
6096 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
6097 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
6098 }
6099
6100 TEST_F(TestLibRBD, FlushEmptyOpsOnExternalSnapshot) {
6101 std::string cache_enabled;
6102 ASSERT_EQ(0, _rados.conf_get("rbd_cache", cache_enabled));
6103 ASSERT_EQ(0, _rados.conf_set("rbd_cache", "false"));
6104 BOOST_SCOPE_EXIT( (cache_enabled) ) {
6105 ASSERT_EQ(0, _rados.conf_set("rbd_cache", cache_enabled.c_str()));
6106 } BOOST_SCOPE_EXIT_END;
6107
6108 librados::IoCtx ioctx;
6109 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6110
6111 librbd::RBD rbd;
6112 std::string name = get_temp_image_name();
6113 uint64_t size = 1 << 18;
6114 int order = 0;
6115 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6116
6117 librbd::Image image1;
6118 librbd::Image image2;
6119 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
6120 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
6121 ASSERT_EQ(0, image1.snap_create("snap1"));
6122
6123 librbd::RBD::AioCompletion *read_comp =
6124 new librbd::RBD::AioCompletion(NULL, NULL);
6125 bufferlist read_bl;
6126 image2.aio_read(0, 1024, read_bl, read_comp);
6127 ASSERT_EQ(0, read_comp->wait_for_complete());
6128 read_comp->release();
6129 }
6130
6131 TEST_F(TestLibRBD, TestImageOptions)
6132 {
6133 rados_ioctx_t ioctx;
6134 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6135
6136 //make create image options
6137 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
6138 uint64_t order = 0;
6139 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
6140 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
6141 rbd_image_options_t opts;
6142 rbd_image_options_create(&opts);
6143
6144 bool is_set;
6145 ASSERT_EQ(-EINVAL, rbd_image_options_is_set(opts, 12345, &is_set));
6146 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
6147 &is_set));
6148 ASSERT_FALSE(is_set);
6149
6150 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
6151 2));
6152 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
6153 features));
6154 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
6155 order));
6156 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
6157 stripe_unit));
6158 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
6159 stripe_count));
6160
6161 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
6162 &is_set));
6163 ASSERT_TRUE(is_set);
6164
6165 std::string parent_name = get_temp_image_name();
6166
6167 // make parent
6168 ASSERT_EQ(0, rbd_create4(ioctx, parent_name.c_str(), 4<<20, opts));
6169
6170 // check order is returned in opts
6171 ASSERT_EQ(0, rbd_image_options_get_uint64(opts, RBD_IMAGE_OPTION_ORDER,
6172 &order));
6173 ASSERT_NE((uint64_t)0, order);
6174
6175 // write some data to parent
6176 rbd_image_t parent;
6177 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
6178 char *data = (char *)"testdata";
6179 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
6180 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
6181
6182 // create a snapshot, reopen as the parent we're interested in
6183 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
6184 ASSERT_EQ(0, rbd_close(parent));
6185 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
6186
6187 // clone
6188 std::string child_name = get_temp_image_name();
6189 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
6190 ASSERT_EQ(0, rbd_clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
6191 child_name.c_str(), opts));
6192
6193 // copy
6194 std::string copy1_name = get_temp_image_name();
6195 ASSERT_EQ(0, rbd_copy3(parent, ioctx, copy1_name.c_str(), opts));
6196 std::string copy2_name = get_temp_image_name();
6197 ASSERT_EQ(0, rbd_copy_with_progress3(parent, ioctx, copy2_name.c_str(), opts,
6198 print_progress_percent, NULL));
6199
6200 ASSERT_EQ(0, rbd_close(parent));
6201
6202 rbd_image_options_destroy(opts);
6203
6204 rados_ioctx_destroy(ioctx);
6205 }
6206
6207 TEST_F(TestLibRBD, TestImageOptionsPP)
6208 {
6209 librados::IoCtx ioctx;
6210 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6211
6212 //make create image options
6213 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
6214 uint64_t order = 0;
6215 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
6216 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
6217 librbd::ImageOptions opts;
6218 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2)));
6219 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FEATURES, features));
6220 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_ORDER, order));
6221 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
6222 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
6223
6224 librbd::RBD rbd;
6225 std::string parent_name = get_temp_image_name();
6226
6227 // make parent
6228 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 4<<20, opts));
6229
6230 // check order is returned in opts
6231 ASSERT_EQ(0, opts.get(RBD_IMAGE_OPTION_ORDER, &order));
6232 ASSERT_NE((uint64_t)0, order);
6233
6234 // write some data to parent
6235 librbd::Image parent;
6236 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
6237
6238 ssize_t len = 1024;
6239 bufferlist bl;
6240 bl.append(buffer::create(len));
6241 bl.zero();
6242 ASSERT_EQ(len, parent.write(0, len, bl));
6243 ASSERT_EQ(len, parent.write(len, len, bl));
6244
6245 // create a snapshot, reopen as the parent we're interested in
6246 ASSERT_EQ(0, parent.snap_create("parent_snap"));
6247 ASSERT_EQ(0, parent.close());
6248 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
6249
6250 // clone
6251 std::string child_name = get_temp_image_name();
6252 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
6253 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
6254 child_name.c_str(), opts));
6255
6256 // copy
6257 std::string copy1_name = get_temp_image_name();
6258 ASSERT_EQ(0, parent.copy3(ioctx, copy1_name.c_str(), opts));
6259 std::string copy2_name = get_temp_image_name();
6260 PrintProgress pp;
6261 ASSERT_EQ(0, parent.copy_with_progress3(ioctx, copy2_name.c_str(), opts, pp));
6262
6263 ASSERT_EQ(0, parent.close());
6264 }
6265
6266 TEST_F(TestLibRBD, EventSocketPipe)
6267 {
6268 EventSocket event_sock;
6269 int pipe_fd[2]; // read and write fd
6270 char buf[32];
6271
6272 ASSERT_EQ(0, pipe(pipe_fd));
6273
6274 ASSERT_FALSE(event_sock.is_valid());
6275
6276 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_NONE));
6277 ASSERT_FALSE(event_sock.is_valid());
6278
6279 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], 44));
6280 ASSERT_FALSE(event_sock.is_valid());
6281
6282 #ifndef HAVE_EVENTFD
6283 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_EVENTFD));
6284 ASSERT_FALSE(event_sock.is_valid());
6285 #endif
6286
6287 ASSERT_EQ(0, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_PIPE));
6288 ASSERT_TRUE(event_sock.is_valid());
6289 ASSERT_EQ(0, event_sock.notify());
6290 ASSERT_EQ(1, read(pipe_fd[0], buf, 32));
6291 ASSERT_EQ('i', buf[0]);
6292
6293 close(pipe_fd[0]);
6294 close(pipe_fd[1]);
6295 }
6296
6297 TEST_F(TestLibRBD, EventSocketEventfd)
6298 {
6299 #ifdef HAVE_EVENTFD
6300 EventSocket event_sock;
6301 int event_fd;
6302 struct pollfd poll_fd;
6303 char buf[32];
6304
6305 event_fd = eventfd(0, EFD_NONBLOCK);
6306 ASSERT_NE(-1, event_fd);
6307
6308 ASSERT_FALSE(event_sock.is_valid());
6309
6310 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, EVENT_SOCKET_TYPE_NONE));
6311 ASSERT_FALSE(event_sock.is_valid());
6312
6313 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, 44));
6314 ASSERT_FALSE(event_sock.is_valid());
6315
6316 ASSERT_EQ(0, event_sock.init(event_fd, EVENT_SOCKET_TYPE_EVENTFD));
6317 ASSERT_TRUE(event_sock.is_valid());
6318 ASSERT_EQ(0, event_sock.notify());
6319
6320 poll_fd.fd = event_fd;
6321 poll_fd.events = POLLIN;
6322 ASSERT_EQ(1, poll(&poll_fd, 1, -1));
6323 ASSERT_TRUE(poll_fd.revents & POLLIN);
6324
6325 ASSERT_EQ(static_cast<ssize_t>(sizeof(uint64_t)), read(event_fd, buf, 32));
6326 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf));
6327
6328 close(event_fd);
6329 #endif
6330 }
6331
6332 TEST_F(TestLibRBD, ImagePollIO)
6333 {
6334 #ifdef HAVE_EVENTFD
6335 rados_ioctx_t ioctx;
6336 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6337
6338 rbd_image_t image;
6339 int order = 0;
6340 std::string name = get_temp_image_name();
6341 uint64_t size = 2 << 20;
6342 int fd = eventfd(0, EFD_NONBLOCK);
6343
6344 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6345 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6346
6347 ASSERT_EQ(0, rbd_set_image_notification(image, fd, EVENT_SOCKET_TYPE_EVENTFD));
6348
6349 char test_data[TEST_IO_SIZE + 1];
6350 char zero_data[TEST_IO_SIZE + 1];
6351 int i;
6352
6353 for (i = 0; i < TEST_IO_SIZE; ++i)
6354 test_data[i] = (char) (rand() % (126 - 33) + 33);
6355 test_data[TEST_IO_SIZE] = '\0';
6356 memset(zero_data, 0, sizeof(zero_data));
6357
6358 for (i = 0; i < 5; ++i)
6359 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
6360
6361 for (i = 5; i < 10; ++i)
6362 ASSERT_PASSED(aio_write_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
6363
6364 for (i = 5; i < 10; ++i)
6365 ASSERT_PASSED(aio_read_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
6366
6367 ASSERT_EQ(0, rbd_close(image));
6368 rados_ioctx_destroy(ioctx);
6369 #endif
6370 }
6371
6372 namespace librbd {
6373
6374 static bool operator==(const image_spec_t &lhs, const image_spec_t &rhs) {
6375 return (lhs.id == rhs.id && lhs.name == rhs.name);
6376 }
6377
6378 static bool operator==(const linked_image_spec_t &lhs,
6379 const linked_image_spec_t &rhs) {
6380 return (lhs.pool_id == rhs.pool_id &&
6381 lhs.pool_name == rhs.pool_name &&
6382 lhs.pool_namespace == rhs.pool_namespace &&
6383 lhs.image_id == rhs.image_id &&
6384 lhs.image_name == rhs.image_name &&
6385 lhs.trash == rhs.trash);
6386 }
6387
6388 static bool operator==(const mirror_peer_t &lhs, const mirror_peer_t &rhs) {
6389 return (lhs.uuid == rhs.uuid &&
6390 lhs.cluster_name == rhs.cluster_name &&
6391 lhs.client_name == rhs.client_name);
6392 }
6393
6394 static std::ostream& operator<<(std::ostream &os, const mirror_peer_t &peer) {
6395 os << "uuid=" << peer.uuid << ", "
6396 << "cluster=" << peer.cluster_name << ", "
6397 << "client=" << peer.client_name;
6398 return os;
6399 }
6400
6401 } // namespace librbd
6402
6403 TEST_F(TestLibRBD, Mirror) {
6404 librados::IoCtx ioctx;
6405 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6406
6407 librbd::RBD rbd;
6408
6409 std::vector<librbd::mirror_peer_t> expected_peers;
6410 std::vector<librbd::mirror_peer_t> peers;
6411 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
6412 ASSERT_EQ(expected_peers, peers);
6413
6414 std::string uuid1;
6415 ASSERT_EQ(-EINVAL, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
6416
6417 rbd_mirror_mode_t mirror_mode;
6418 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
6419 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED, mirror_mode);
6420
6421 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
6422 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
6423
6424 // Add some images to the pool
6425 int order = 0;
6426 std::string parent_name = get_temp_image_name();
6427 std::string child_name = get_temp_image_name();
6428 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), 2 << 20,
6429 &order));
6430 bool old_format;
6431 uint64_t features;
6432 ASSERT_EQ(0, get_features(&old_format, &features));
6433 if ((features & RBD_FEATURE_LAYERING) != 0) {
6434 librbd::Image parent;
6435 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
6436 ASSERT_EQ(0, parent.snap_create("parent_snap"));
6437 ASSERT_EQ(0, parent.close());
6438 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
6439 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
6440 ASSERT_EQ(0, parent.close());
6441 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "parent_snap", ioctx,
6442 child_name.c_str(), features, &order));
6443 }
6444
6445 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE, mirror_mode);
6446
6447 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_POOL));
6448 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
6449 ASSERT_EQ(RBD_MIRROR_MODE_POOL, mirror_mode);
6450
6451 std::string uuid2;
6452 std::string uuid3;
6453 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
6454 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid2, "cluster2", "admin"));
6455 ASSERT_EQ(-EEXIST, rbd.mirror_peer_add(ioctx, &uuid3, "cluster1", "foo"));
6456 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid3, "cluster3", "admin"));
6457
6458 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
6459 auto sort_peers = [](const librbd::mirror_peer_t &lhs,
6460 const librbd::mirror_peer_t &rhs) {
6461 return lhs.uuid < rhs.uuid;
6462 };
6463 expected_peers = {
6464 {uuid1, "cluster1", "client"},
6465 {uuid2, "cluster2", "admin"},
6466 {uuid3, "cluster3", "admin"}};
6467 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
6468 ASSERT_EQ(expected_peers, peers);
6469
6470 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, "uuid4"));
6471 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid2));
6472
6473 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_client(ioctx, "uuid4", "new client"));
6474 ASSERT_EQ(0, rbd.mirror_peer_set_client(ioctx, uuid1, "new client"));
6475
6476 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_cluster(ioctx, "uuid4",
6477 "new cluster"));
6478 ASSERT_EQ(0, rbd.mirror_peer_set_cluster(ioctx, uuid3, "new cluster"));
6479
6480 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
6481 expected_peers = {
6482 {uuid1, "cluster1", "new client"},
6483 {uuid3, "new cluster", "admin"}};
6484 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
6485 ASSERT_EQ(expected_peers, peers);
6486
6487 ASSERT_EQ(-EBUSY, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
6488 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid1));
6489 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid3));
6490 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
6491 }
6492
6493 TEST_F(TestLibRBD, MirrorPeerAttributes) {
6494 REQUIRE(!is_librados_test_stub(_rados));
6495
6496 librados::IoCtx ioctx;
6497 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6498
6499 librbd::RBD rbd;
6500 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
6501
6502 std::string uuid;
6503 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid, "remote_cluster", "client"));
6504
6505 std::map<std::string, std::string> attributes;
6506 ASSERT_EQ(-ENOENT, rbd.mirror_peer_get_attributes(ioctx, uuid, &attributes));
6507 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_attributes(ioctx, "missing uuid",
6508 attributes));
6509
6510 std::map<std::string, std::string> expected_attributes{
6511 {"mon_host", "1.2.3.4"},
6512 {"key", "ABC"}};
6513 ASSERT_EQ(0, rbd.mirror_peer_set_attributes(ioctx, uuid,
6514 expected_attributes));
6515
6516 ASSERT_EQ(0, rbd.mirror_peer_get_attributes(ioctx, uuid,
6517 &attributes));
6518 ASSERT_EQ(expected_attributes, attributes);
6519
6520 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid));
6521 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
6522 }
6523
6524 TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {
6525 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6526
6527 librados::IoCtx ioctx;
6528 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6529
6530 librbd::RBD rbd;
6531 librbd::Image image;
6532 std::string name = get_temp_image_name();
6533
6534 uint64_t size = 1 << 18;
6535 int order = 0;
6536
6537 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6538 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6539
6540 bufferlist bl;
6541 bl.append(std::string(size, '1'));
6542 ASSERT_EQ((int)size, image.write(0, size, bl));
6543 ASSERT_EQ(0, image.snap_create("one"));
6544 ASSERT_EQ(0, image.snap_protect("one"));
6545
6546 std::string clone_name = this->get_temp_image_name();
6547 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
6548 RBD_FEATURE_LAYERING, &order));
6549 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
6550
6551 librbd::Image image2;
6552 ASSERT_EQ(0, rbd.open(ioctx, image2, clone_name.c_str(), NULL));
6553
6554 // prepare CoW writeback that will be flushed on next op
6555 bl.clear();
6556 bl.append(std::string(1, '1'));
6557 ASSERT_EQ(0, image.flush());
6558 ASSERT_EQ(1, image.write(0, 1, bl));
6559 ASSERT_EQ(0, image2.snap_create("snap1"));
6560
6561 librbd::RBD::AioCompletion *read_comp =
6562 new librbd::RBD::AioCompletion(NULL, NULL);
6563 bufferlist read_bl;
6564 image.aio_read(0, 1024, read_bl, read_comp);
6565 ASSERT_EQ(0, read_comp->wait_for_complete());
6566 read_comp->release();
6567 }
6568
6569 TEST_F(TestLibRBD, ExclusiveLock)
6570 {
6571 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
6572
6573 static char buf[10];
6574
6575 rados_ioctx_t ioctx;
6576 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
6577
6578 std::string name = get_temp_image_name();
6579 uint64_t size = 2 << 20;
6580 int order = 0;
6581 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6582
6583 rbd_image_t image1;
6584 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
6585
6586 int lock_owner;
6587 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
6588 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6589 ASSERT_TRUE(lock_owner);
6590
6591 rbd_lock_mode_t lock_mode;
6592 char *lock_owners[1];
6593 size_t max_lock_owners = 0;
6594 ASSERT_EQ(-ERANGE, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
6595 &max_lock_owners));
6596 ASSERT_EQ(1U, max_lock_owners);
6597
6598 ASSERT_EQ(0, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
6599 &max_lock_owners));
6600 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
6601 ASSERT_STRNE("", lock_owners[0]);
6602 ASSERT_EQ(1U, max_lock_owners);
6603
6604 rbd_image_t image2;
6605 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
6606
6607 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
6608 ASSERT_FALSE(lock_owner);
6609
6610 ASSERT_EQ(-EOPNOTSUPP, rbd_lock_break(image1, RBD_LOCK_MODE_SHARED, ""));
6611 ASSERT_EQ(-EBUSY, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
6612 "not the owner"));
6613
6614 ASSERT_EQ(0, rbd_lock_release(image1));
6615 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6616 ASSERT_FALSE(lock_owner);
6617
6618 ASSERT_EQ(-ENOENT, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
6619 lock_owners[0]));
6620 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
6621
6622 ASSERT_EQ(-EROFS, rbd_write(image1, 0, sizeof(buf), buf));
6623 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image2, 0, sizeof(buf), buf));
6624
6625 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
6626 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
6627 ASSERT_TRUE(lock_owner);
6628
6629 ASSERT_EQ(0, rbd_lock_release(image2));
6630 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
6631 ASSERT_FALSE(lock_owner);
6632
6633 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
6634 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6635 ASSERT_TRUE(lock_owner);
6636
6637 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image1, 0, sizeof(buf), buf));
6638 ASSERT_EQ(-EROFS, rbd_write(image2, 0, sizeof(buf), buf));
6639
6640 ASSERT_EQ(0, rbd_lock_release(image1));
6641 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6642 ASSERT_FALSE(lock_owner);
6643
6644 int owner_id = -1;
6645 mutex lock;
6646 const auto pingpong = [&](int m_id, rbd_image_t &m_image) {
6647 for (int i = 0; i < 10; i++) {
6648 {
6649 lock_guard<mutex> locker(lock);
6650 if (owner_id == m_id) {
6651 std::cout << m_id << ": releasing exclusive lock" << std::endl;
6652 EXPECT_EQ(0, rbd_lock_release(m_image));
6653 int lock_owner;
6654 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
6655 EXPECT_FALSE(lock_owner);
6656 owner_id = -1;
6657 std::cout << m_id << ": exclusive lock released" << std::endl;
6658 continue;
6659 }
6660 }
6661
6662 std::cout << m_id << ": acquiring exclusive lock" << std::endl;
6663 int r;
6664 do {
6665 r = rbd_lock_acquire(m_image, RBD_LOCK_MODE_EXCLUSIVE);
6666 if (r == -EROFS) {
6667 usleep(1000);
6668 }
6669 } while (r == -EROFS);
6670 EXPECT_EQ(0, r);
6671
6672 int lock_owner;
6673 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
6674 EXPECT_TRUE(lock_owner);
6675 std::cout << m_id << ": exclusive lock acquired" << std::endl;
6676 {
6677 lock_guard<mutex> locker(lock);
6678 owner_id = m_id;
6679 }
6680 usleep(rand() % 50000);
6681 }
6682
6683 lock_guard<mutex> locker(lock);
6684 if (owner_id == m_id) {
6685 EXPECT_EQ(0, rbd_lock_release(m_image));
6686 int lock_owner;
6687 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
6688 EXPECT_FALSE(lock_owner);
6689 owner_id = -1;
6690 }
6691 };
6692 thread ping(bind(pingpong, 1, ref(image1)));
6693 thread pong(bind(pingpong, 2, ref(image2)));
6694
6695 ping.join();
6696 pong.join();
6697
6698 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
6699 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
6700 ASSERT_TRUE(lock_owner);
6701
6702 ASSERT_EQ(0, rbd_close(image2));
6703
6704 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
6705 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
6706 ASSERT_TRUE(lock_owner);
6707
6708 ASSERT_EQ(0, rbd_close(image1));
6709 rados_ioctx_destroy(ioctx);
6710 }
6711
6712 TEST_F(TestLibRBD, BreakLock)
6713 {
6714 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
6715
6716 static char buf[10];
6717
6718 rados_t blacklist_cluster;
6719 ASSERT_EQ("", connect_cluster(&blacklist_cluster));
6720
6721 rados_ioctx_t ioctx, blacklist_ioctx;
6722 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
6723 ASSERT_EQ(0, rados_ioctx_create(blacklist_cluster, m_pool_name.c_str(),
6724 &blacklist_ioctx));
6725
6726 std::string name = get_temp_image_name();
6727 uint64_t size = 2 << 20;
6728 int order = 0;
6729 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
6730
6731 rbd_image_t image, blacklist_image;
6732 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
6733 ASSERT_EQ(0, rbd_open(blacklist_ioctx, name.c_str(), &blacklist_image, NULL));
6734
6735 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_blacklist_on_break_lock", "true"));
6736 ASSERT_EQ(0, rbd_lock_acquire(blacklist_image, RBD_LOCK_MODE_EXCLUSIVE));
6737
6738 rbd_lock_mode_t lock_mode;
6739 char *lock_owners[1];
6740 size_t max_lock_owners = 1;
6741 ASSERT_EQ(0, rbd_lock_get_owners(image, &lock_mode, lock_owners,
6742 &max_lock_owners));
6743 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
6744 ASSERT_STRNE("", lock_owners[0]);
6745 ASSERT_EQ(1U, max_lock_owners);
6746
6747 ASSERT_EQ(0, rbd_lock_break(image, RBD_LOCK_MODE_EXCLUSIVE, lock_owners[0]));
6748 ASSERT_EQ(0, rbd_lock_acquire(image, RBD_LOCK_MODE_EXCLUSIVE));
6749 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blacklist_cluster));
6750
6751 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image, 0, sizeof(buf), buf));
6752 ASSERT_EQ(-EBLACKLISTED, rbd_write(blacklist_image, 0, sizeof(buf), buf));
6753
6754 ASSERT_EQ(0, rbd_close(image));
6755 ASSERT_EQ(0, rbd_close(blacklist_image));
6756
6757 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
6758
6759 rados_ioctx_destroy(ioctx);
6760 rados_ioctx_destroy(blacklist_ioctx);
6761 rados_shutdown(blacklist_cluster);
6762 }
6763
6764 TEST_F(TestLibRBD, DiscardAfterWrite)
6765 {
6766 REQUIRE(!is_skip_partial_discard_enabled());
6767
6768 librados::IoCtx ioctx;
6769 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6770
6771 librbd::RBD rbd;
6772 std::string name = get_temp_image_name();
6773 uint64_t size = 1 << 20;
6774 int order = 18;
6775 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6776
6777 librbd::Image image;
6778 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6779
6780 // enable writeback cache
6781 ASSERT_EQ(0, image.flush());
6782
6783 bufferlist bl;
6784 bl.append(std::string(256, '1'));
6785
6786 librbd::RBD::AioCompletion *write_comp =
6787 new librbd::RBD::AioCompletion(NULL, NULL);
6788 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
6789 ASSERT_EQ(0, write_comp->wait_for_complete());
6790 write_comp->release();
6791
6792 librbd::RBD::AioCompletion *discard_comp =
6793 new librbd::RBD::AioCompletion(NULL, NULL);
6794 ASSERT_EQ(0, image.aio_discard(0, 256, discard_comp));
6795 ASSERT_EQ(0, discard_comp->wait_for_complete());
6796 discard_comp->release();
6797
6798 librbd::RBD::AioCompletion *read_comp =
6799 new librbd::RBD::AioCompletion(NULL, NULL);
6800 bufferlist read_bl;
6801 image.aio_read(0, bl.length(), read_bl, read_comp);
6802 ASSERT_EQ(0, read_comp->wait_for_complete());
6803 ASSERT_EQ(bl.length(), read_comp->get_return_value());
6804 ASSERT_TRUE(read_bl.is_zero());
6805 read_comp->release();
6806 }
6807
6808 TEST_F(TestLibRBD, DefaultFeatures) {
6809 std::string orig_default_features;
6810 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", orig_default_features));
6811 BOOST_SCOPE_EXIT_ALL(orig_default_features) {
6812 ASSERT_EQ(0, _rados.conf_set("rbd_default_features",
6813 orig_default_features.c_str()));
6814 };
6815
6816 std::list<std::pair<std::string, std::string> > feature_names_to_bitmask = {
6817 {"", orig_default_features},
6818 {"layering", "1"},
6819 {"layering, exclusive-lock", "5"},
6820 {"exclusive-lock,journaling", "68"},
6821 {"125", "125"}
6822 };
6823
6824 for (auto &pair : feature_names_to_bitmask) {
6825 ASSERT_EQ(0, _rados.conf_set("rbd_default_features", pair.first.c_str()));
6826 std::string features;
6827 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", features));
6828 ASSERT_EQ(pair.second, features);
6829 }
6830 }
6831
6832 TEST_F(TestLibRBD, TestTrashMoveAndPurge) {
6833 REQUIRE_FORMAT_V2();
6834
6835 librados::IoCtx ioctx;
6836 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6837
6838 librbd::RBD rbd;
6839 std::string name = get_temp_image_name();
6840
6841 uint64_t size = 1 << 18;
6842 int order = 12;
6843 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6844
6845 librbd::Image image;
6846 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
6847
6848 std::string image_id;
6849 ASSERT_EQ(0, image.get_id(&image_id));
6850 image.close();
6851
6852 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 0));
6853
6854 std::vector<std::string> images;
6855 ASSERT_EQ(0, rbd.list(ioctx, images));
6856 for (const auto& image : images) {
6857 ASSERT_TRUE(image != name);
6858 }
6859
6860 librbd::trash_image_info_t info;
6861 ASSERT_EQ(-ENOENT, rbd.trash_get(ioctx, "dummy image id", &info));
6862 ASSERT_EQ(0, rbd.trash_get(ioctx, image_id.c_str(), &info));
6863 ASSERT_EQ(image_id, info.id);
6864
6865 std::vector<librbd::trash_image_info_t> entries;
6866 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6867 ASSERT_FALSE(entries.empty());
6868 ASSERT_EQ(entries.begin()->id, image_id);
6869
6870 entries.clear();
6871 PrintProgress pp;
6872 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
6873 false, pp));
6874 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6875 ASSERT_TRUE(entries.empty());
6876 }
6877
6878 TEST_F(TestLibRBD, TestTrashMoveAndPurgeNonExpiredDelay) {
6879 REQUIRE_FORMAT_V2();
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
6887 uint64_t size = 1 << 18;
6888 int order = 12;
6889 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6890
6891 librbd::Image image;
6892 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
6893
6894 std::string image_id;
6895 ASSERT_EQ(0, image.get_id(&image_id));
6896 image.close();
6897
6898 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 100));
6899
6900 PrintProgress pp;
6901 ASSERT_EQ(-EPERM, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
6902 false, pp));
6903
6904 PrintProgress pp2;
6905 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
6906 true, pp2));
6907 }
6908
6909 TEST_F(TestLibRBD, TestTrashPurge) {
6910 REQUIRE_FORMAT_V2();
6911
6912 librados::IoCtx ioctx;
6913 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6914
6915 librbd::RBD rbd;
6916 std::string name1 = get_temp_image_name();
6917 std::string name2 = get_temp_image_name();
6918
6919 uint64_t size = 1 << 18;
6920 int order = 12;
6921 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name1.c_str(), size, &order));
6922 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
6923
6924 librbd::Image image1;
6925 ASSERT_EQ(0, rbd.open(ioctx, image1, name1.c_str(), nullptr));
6926
6927 std::string image_id1;
6928 ASSERT_EQ(0, image1.get_id(&image_id1));
6929 image1.close();
6930
6931 ASSERT_EQ(0, rbd.trash_move(ioctx, name1.c_str(), 0));
6932
6933 librbd::Image image2;
6934 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), nullptr));
6935 ceph::bufferlist bl;
6936 bl.append(std::string(1024, '0'));
6937 ASSERT_EQ(1024, image2.write(0, 1024, bl));
6938
6939 std::string image_id2;
6940 ASSERT_EQ(0, image2.get_id(&image_id2));
6941 image2.close();
6942
6943 ASSERT_EQ(0, rbd.trash_move(ioctx, name2.c_str(), 100));
6944 ASSERT_EQ(0, rbd.trash_purge(ioctx, 0, -1));
6945
6946 std::vector<librbd::trash_image_info_t> entries;
6947 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6948 ASSERT_EQ(1U, entries.size());
6949 ASSERT_EQ(image_id2, entries[0].id);
6950 ASSERT_EQ(name2, entries[0].name);
6951 entries.clear();
6952
6953 struct timespec now;
6954 clock_gettime(CLOCK_REALTIME, &now);
6955 float threshold = 0.0;
6956 if (!is_librados_test_stub(_rados)) {
6957 // real cluster usage reports have a long latency to update
6958 threshold = -1.0;
6959 }
6960
6961 ASSERT_EQ(0, rbd.trash_purge(ioctx, now.tv_sec+1000, threshold));
6962 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6963 ASSERT_EQ(0U, entries.size());
6964 }
6965
6966 TEST_F(TestLibRBD, TestTrashMoveAndRestore) {
6967 REQUIRE_FORMAT_V2();
6968
6969 librados::IoCtx ioctx;
6970 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6971
6972 librbd::RBD rbd;
6973 std::string name = get_temp_image_name();
6974
6975 uint64_t size = 1 << 18;
6976 int order = 12;
6977 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6978
6979 librbd::Image image;
6980 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
6981
6982 std::string image_id;
6983 ASSERT_EQ(0, image.get_id(&image_id));
6984 image.close();
6985
6986 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 10));
6987
6988 std::vector<std::string> images;
6989 ASSERT_EQ(0, rbd.list(ioctx, images));
6990 for (const auto& image : images) {
6991 ASSERT_TRUE(image != name);
6992 }
6993
6994 std::vector<librbd::trash_image_info_t> entries;
6995 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6996 ASSERT_FALSE(entries.empty());
6997 ASSERT_EQ(entries.begin()->id, image_id);
6998
6999 images.clear();
7000 ASSERT_EQ(0, rbd.trash_restore(ioctx, image_id.c_str(), ""));
7001 ASSERT_EQ(0, rbd.list(ioctx, images));
7002 ASSERT_FALSE(images.empty());
7003 bool found = false;
7004 for (const auto& image : images) {
7005 if (image == name) {
7006 found = true;
7007 break;
7008 }
7009 }
7010 ASSERT_TRUE(found);
7011 }
7012
7013 TEST_F(TestLibRBD, TestListWatchers) {
7014 librados::IoCtx ioctx;
7015 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7016
7017 librbd::RBD rbd;
7018 std::string name = get_temp_image_name();
7019
7020 uint64_t size = 1 << 18;
7021 int order = 12;
7022 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7023
7024 librbd::Image image;
7025 std::list<librbd::image_watcher_t> watchers;
7026
7027 // No watchers
7028 ASSERT_EQ(0, rbd.open_read_only(ioctx, image, name.c_str(), nullptr));
7029 ASSERT_EQ(0, image.list_watchers(watchers));
7030 ASSERT_EQ(0U, watchers.size());
7031 ASSERT_EQ(0, image.close());
7032
7033 // One watcher
7034 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7035 ASSERT_EQ(0, image.list_watchers(watchers));
7036 ASSERT_EQ(1U, watchers.size());
7037 ASSERT_EQ(0, image.close());
7038 }
7039
7040 TEST_F(TestLibRBD, TestSetSnapById) {
7041 librados::IoCtx ioctx;
7042 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7043
7044 librbd::RBD rbd;
7045 std::string name = get_temp_image_name();
7046
7047 uint64_t size = 1 << 18;
7048 int order = 12;
7049 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7050
7051 librbd::Image image;
7052 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7053 ASSERT_EQ(0, image.snap_create("snap"));
7054
7055 vector<librbd::snap_info_t> snaps;
7056 ASSERT_EQ(0, image.snap_list(snaps));
7057 ASSERT_EQ(1U, snaps.size());
7058
7059 ASSERT_EQ(0, image.snap_set_by_id(snaps[0].id));
7060 ASSERT_EQ(0, image.snap_set_by_id(CEPH_NOSNAP));
7061 }
7062
7063 TEST_F(TestLibRBD, Namespaces) {
7064 rados_ioctx_t ioctx;
7065 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
7066 rados_remove(ioctx, RBD_NAMESPACE);
7067
7068 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name1"));
7069 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name2"));
7070 ASSERT_EQ(0, rbd_namespace_create(ioctx, "name3"));
7071 ASSERT_EQ(0, rbd_namespace_remove(ioctx, "name2"));
7072
7073 char names[1024];
7074 size_t max_size = sizeof(names);
7075 int len = rbd_namespace_list(ioctx, names, &max_size);
7076
7077 std::vector<std::string> cpp_names;
7078 for (char* cur_name = names; cur_name < names + len; ) {
7079 cpp_names.push_back(cur_name);
7080 cur_name += strlen(cur_name) + 1;
7081 }
7082 ASSERT_EQ(2U, cpp_names.size());
7083 ASSERT_EQ("name1", cpp_names[0]);
7084 ASSERT_EQ("name3", cpp_names[1]);
7085 bool exists;
7086 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name2", &exists));
7087 ASSERT_FALSE(exists);
7088 ASSERT_EQ(0, rbd_namespace_exists(ioctx, "name3", &exists));
7089 ASSERT_TRUE(exists);
7090 rados_ioctx_destroy(ioctx);
7091 }
7092
7093 TEST_F(TestLibRBD, NamespacesPP) {
7094 librados::IoCtx ioctx;
7095 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7096 ioctx.remove(RBD_NAMESPACE);
7097
7098 librbd::RBD rbd;
7099 ASSERT_EQ(-EINVAL, rbd.namespace_create(ioctx, ""));
7100 ASSERT_EQ(-EINVAL, rbd.namespace_remove(ioctx, ""));
7101
7102 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name1"));
7103 ASSERT_EQ(-EEXIST, rbd.namespace_create(ioctx, "name1"));
7104 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name2"));
7105 ASSERT_EQ(0, rbd.namespace_create(ioctx, "name3"));
7106 ASSERT_EQ(0, rbd.namespace_remove(ioctx, "name2"));
7107 ASSERT_EQ(-ENOENT, rbd.namespace_remove(ioctx, "name2"));
7108
7109 std::vector<std::string> names;
7110 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
7111 ASSERT_EQ(2U, names.size());
7112 ASSERT_EQ("name1", names[0]);
7113 ASSERT_EQ("name3", names[1]);
7114 bool exists;
7115 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name2", &exists));
7116 ASSERT_FALSE(exists);
7117 ASSERT_EQ(0, rbd.namespace_exists(ioctx, "name3", &exists));
7118 ASSERT_TRUE(exists);
7119
7120 librados::IoCtx ns_io_ctx;
7121 ns_io_ctx.dup(ioctx);
7122
7123 std::string name = get_temp_image_name();
7124 int order = 0;
7125 uint64_t features = 0;
7126 if (!get_features(&features)) {
7127 // old format doesn't support namespaces
7128 ns_io_ctx.set_namespace("name1");
7129 ASSERT_EQ(-EINVAL, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0,
7130 &order));
7131 return;
7132 }
7133
7134 ns_io_ctx.set_namespace("missing");
7135 ASSERT_EQ(-ENOENT, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
7136
7137 ns_io_ctx.set_namespace("name1");
7138 ASSERT_EQ(0, create_image_pp(rbd, ns_io_ctx, name.c_str(), 0, &order));
7139 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
7140
7141 std::string image_id;
7142 {
7143 librbd::Image image;
7144 ASSERT_EQ(-ENOENT, rbd.open(ioctx, image, name.c_str(), NULL));
7145 ASSERT_EQ(0, rbd.open(ns_io_ctx, image, name.c_str(), NULL));
7146 ASSERT_EQ(0, get_image_id(image, &image_id));
7147 }
7148
7149 ASSERT_EQ(-ENOENT, rbd.trash_move(ioctx, name.c_str(), 0));
7150 ASSERT_EQ(0, rbd.trash_move(ns_io_ctx, name.c_str(), 0));
7151 ASSERT_EQ(-EBUSY, rbd.namespace_remove(ns_io_ctx, "name1"));
7152
7153 PrintProgress pp;
7154 ASSERT_EQ(-ENOENT, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
7155 false, pp));
7156 ASSERT_EQ(0, rbd.trash_remove_with_progress(ns_io_ctx, image_id.c_str(),
7157 false, pp));
7158 ASSERT_EQ(0, rbd.namespace_remove(ns_io_ctx, "name1"));
7159
7160 names.clear();
7161 ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
7162 ASSERT_EQ(1U, names.size());
7163 ASSERT_EQ("name3", names[0]);
7164 }
7165
7166 TEST_F(TestLibRBD, Migration) {
7167 bool old_format;
7168 uint64_t features;
7169 ASSERT_EQ(0, get_features(&old_format, &features));
7170
7171 rados_ioctx_t ioctx;
7172 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7173 BOOST_SCOPE_EXIT(&ioctx) {
7174 rados_ioctx_destroy(ioctx);
7175 } BOOST_SCOPE_EXIT_END;
7176
7177 int order = 0;
7178 std::string name = get_temp_image_name();
7179 uint64_t size = 2 << 20;
7180 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7181
7182 rbd_image_options_t image_options;
7183 rbd_image_options_create(&image_options);
7184 BOOST_SCOPE_EXIT(&image_options) {
7185 rbd_image_options_destroy(image_options);
7186 } BOOST_SCOPE_EXIT_END;
7187
7188 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
7189 image_options));
7190
7191 rbd_image_migration_status_t status;
7192 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
7193 sizeof(status)));
7194 ASSERT_EQ(status.source_pool_id, rados_ioctx_get_id(ioctx));
7195 ASSERT_EQ(status.source_image_name, name);
7196 if (old_format) {
7197 ASSERT_EQ(status.source_image_id, string());
7198 } else {
7199 ASSERT_NE(status.source_image_id, string());
7200 ASSERT_EQ(-EROFS, rbd_trash_remove(ioctx, status.source_image_id, false));
7201 ASSERT_EQ(-EINVAL, rbd_trash_restore(ioctx, status.source_image_id, name.c_str()));
7202 }
7203 ASSERT_EQ(status.dest_pool_id, rados_ioctx_get_id(ioctx));
7204 ASSERT_EQ(status.dest_image_name, name);
7205 ASSERT_NE(status.dest_image_id, string());
7206 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
7207 rbd_migration_status_cleanup(&status);
7208
7209 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, name.c_str()));
7210 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, name.c_str(), 0));
7211
7212 ASSERT_EQ(0, rbd_migration_execute(ioctx, name.c_str()));
7213
7214 ASSERT_EQ(0, rbd_migration_status(ioctx, name.c_str(), &status,
7215 sizeof(status)));
7216 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
7217 rbd_migration_status_cleanup(&status);
7218
7219 ASSERT_EQ(0, rbd_migration_commit(ioctx, name.c_str()));
7220
7221 std::string new_name = get_temp_image_name();
7222
7223 ASSERT_EQ(0, rbd_migration_prepare(ioctx, name.c_str(), ioctx,
7224 new_name.c_str(), image_options));
7225
7226 ASSERT_EQ(-EBUSY, rbd_remove(ioctx, new_name.c_str()));
7227 ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, new_name.c_str(), 0));
7228
7229 ASSERT_EQ(0, rbd_migration_abort(ioctx, name.c_str()));
7230
7231 rbd_image_t image;
7232 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7233 EXPECT_EQ(0, rbd_close(image));
7234 }
7235
7236 TEST_F(TestLibRBD, MigrationPP) {
7237 bool old_format;
7238 uint64_t features;
7239 ASSERT_EQ(0, get_features(&old_format, &features));
7240
7241 librados::IoCtx ioctx;
7242 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7243
7244 int order = 0;
7245 std::string name = get_temp_image_name();
7246 uint64_t size = 2 << 20;
7247 librbd::RBD rbd;
7248 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7249
7250 librbd::ImageOptions image_options;
7251
7252 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx, name.c_str(),
7253 image_options));
7254
7255 librbd::image_migration_status_t status;
7256 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
7257 sizeof(status)));
7258 ASSERT_EQ(status.source_pool_id, ioctx.get_id());
7259 ASSERT_EQ(status.source_image_name, name);
7260 if (old_format) {
7261 ASSERT_EQ(status.source_image_id, "");
7262 } else {
7263 ASSERT_NE(status.source_image_id, "");
7264 ASSERT_EQ(-EROFS, rbd.trash_remove(ioctx, status.source_image_id.c_str(), false));
7265 ASSERT_EQ(-EINVAL, rbd.trash_restore(ioctx, status.source_image_id.c_str(), name.c_str()));
7266 }
7267 ASSERT_EQ(status.dest_pool_id, ioctx.get_id());
7268 ASSERT_EQ(status.dest_image_name, name);
7269 ASSERT_NE(status.dest_image_id, "");
7270 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
7271
7272 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, name.c_str()));
7273 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, name.c_str(), 0));
7274
7275 ASSERT_EQ(0, rbd.migration_execute(ioctx, name.c_str()));
7276
7277 ASSERT_EQ(0, rbd.migration_status(ioctx, name.c_str(), &status,
7278 sizeof(status)));
7279 ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_EXECUTED);
7280
7281 ASSERT_EQ(0, rbd.migration_commit(ioctx, name.c_str()));
7282
7283 std::string new_name = get_temp_image_name();
7284
7285 ASSERT_EQ(0, rbd.migration_prepare(ioctx, name.c_str(), ioctx,
7286 new_name.c_str(), image_options));
7287
7288 ASSERT_EQ(-EBUSY, rbd.remove(ioctx, new_name.c_str()));
7289 ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, new_name.c_str(), 0));
7290
7291 ASSERT_EQ(0, rbd.migration_abort(ioctx, name.c_str()));
7292
7293 librbd::Image image;
7294 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
7295 }
7296
7297 TEST_F(TestLibRBD, TestGetAccessTimestamp)
7298 {
7299 REQUIRE_FORMAT_V2();
7300
7301 rados_ioctx_t ioctx;
7302 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7303
7304 rbd_image_t image;
7305 int order = 0;
7306 std::string name = get_temp_image_name();
7307 uint64_t size = 2 << 20;
7308 struct timespec timestamp;
7309
7310 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7311 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7312
7313 ASSERT_EQ(0, rbd_get_access_timestamp(image, &timestamp));
7314 ASSERT_LT(0, timestamp.tv_sec);
7315
7316 ASSERT_PASSED(validate_object_map, image);
7317 ASSERT_EQ(0, rbd_close(image));
7318
7319 rados_ioctx_destroy(ioctx);
7320 }
7321
7322 TEST_F(TestLibRBD, TestGetModifyTimestamp)
7323 {
7324 REQUIRE_FORMAT_V2();
7325
7326 rados_ioctx_t ioctx;
7327 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7328
7329 rbd_image_t image;
7330 int order = 0;
7331 std::string name = get_temp_image_name();
7332 uint64_t size = 2 << 20;
7333 struct timespec timestamp;
7334
7335 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7336 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7337 ASSERT_EQ(0, rbd_get_modify_timestamp(image, &timestamp));
7338 ASSERT_LT(0, timestamp.tv_sec);
7339
7340 ASSERT_PASSED(validate_object_map, image);
7341 ASSERT_EQ(0, rbd_close(image));
7342
7343 rados_ioctx_destroy(ioctx);
7344 }
7345
7346 TEST_F(TestLibRBD, ZeroOverlapFlatten) {
7347 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7348
7349 librados::IoCtx ioctx;
7350 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7351
7352 librbd::RBD rbd;
7353 librbd::Image parent_image;
7354 std::string name = get_temp_image_name();
7355
7356 uint64_t size = 1;
7357 int order = 0;
7358
7359 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7360 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
7361
7362 uint64_t features;
7363 ASSERT_EQ(0, parent_image.features(&features));
7364
7365 ASSERT_EQ(0, parent_image.snap_create("snap"));
7366 ASSERT_EQ(0, parent_image.snap_protect("snap"));
7367
7368 std::string clone_name = this->get_temp_image_name();
7369 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
7370 features, &order));
7371
7372 librbd::Image clone_image;
7373 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
7374 ASSERT_EQ(0, clone_image.resize(0));
7375 ASSERT_EQ(0, clone_image.flatten());
7376 }
7377
7378 TEST_F(TestLibRBD, PoolMetadata)
7379 {
7380 REQUIRE_FORMAT_V2();
7381
7382 rados_ioctx_t ioctx;
7383 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7384
7385 char keys[1024];
7386 char vals[1024];
7387 size_t keys_len = sizeof(keys);
7388 size_t vals_len = sizeof(vals);
7389
7390 memset_rand(keys, keys_len);
7391 memset_rand(vals, vals_len);
7392
7393 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7394 &vals_len));
7395 ASSERT_EQ(0U, keys_len);
7396 ASSERT_EQ(0U, vals_len);
7397
7398 char value[1024];
7399 size_t value_len = sizeof(value);
7400 memset_rand(value, value_len);
7401
7402 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
7403 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key2", "value2"));
7404 ASSERT_EQ(0, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
7405 ASSERT_STREQ(value, "value1");
7406 value_len = 1;
7407 ASSERT_EQ(-ERANGE, rbd_pool_metadata_get(ioctx, "key1", value, &value_len));
7408 ASSERT_EQ(value_len, strlen("value1") + 1);
7409
7410 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7411 &vals_len));
7412 keys_len = sizeof(keys);
7413 vals_len = sizeof(vals);
7414 memset_rand(keys, keys_len);
7415 memset_rand(vals, vals_len);
7416 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7417 &vals_len));
7418 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
7419 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
7420 ASSERT_STREQ(keys, "key1");
7421 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
7422 ASSERT_STREQ(vals, "value1");
7423 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
7424
7425 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
7426 ASSERT_EQ(-ENOENT, rbd_pool_metadata_remove(ioctx, "key3"));
7427 value_len = sizeof(value);
7428 ASSERT_EQ(-ENOENT, rbd_pool_metadata_get(ioctx, "key3", value, &value_len));
7429 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7430 &vals_len));
7431 ASSERT_EQ(keys_len, strlen("key2") + 1);
7432 ASSERT_EQ(vals_len, strlen("value2") + 1);
7433 ASSERT_STREQ(keys, "key2");
7434 ASSERT_STREQ(vals, "value2");
7435
7436 // test config setting
7437 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
7438 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7439 ASSERT_EQ(-EINVAL, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
7440 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
7441
7442 // test short buffer cases
7443 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key1", "value1"));
7444 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key3", "value3"));
7445 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "key4", "value4"));
7446
7447 keys_len = strlen("key1") + 1;
7448 vals_len = strlen("value1") + 1;
7449 memset_rand(keys, keys_len);
7450 memset_rand(vals, vals_len);
7451 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "", 1, keys, &keys_len, vals,
7452 &vals_len));
7453 ASSERT_EQ(keys_len, strlen("key1") + 1);
7454 ASSERT_EQ(vals_len, strlen("value1") + 1);
7455 ASSERT_STREQ(keys, "key1");
7456 ASSERT_STREQ(vals, "value1");
7457
7458 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 2, keys, &keys_len, vals,
7459 &vals_len));
7460 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
7461 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
7462
7463 ASSERT_EQ(-ERANGE, rbd_pool_metadata_list(ioctx, "", 0, keys, &keys_len, vals,
7464 &vals_len));
7465 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
7466 1 + strlen("key4") + 1);
7467 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
7468 strlen("value3") + 1 + strlen("value4") + 1);
7469
7470 // test `start` param
7471 keys_len = sizeof(keys);
7472 vals_len = sizeof(vals);
7473 memset_rand(keys, keys_len);
7474 memset_rand(vals, vals_len);
7475 ASSERT_EQ(0, rbd_pool_metadata_list(ioctx, "key2", 0, keys, &keys_len, vals,
7476 &vals_len));
7477 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
7478 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
7479 ASSERT_STREQ(keys, "key3");
7480 ASSERT_STREQ(vals, "value3");
7481
7482 //cleanup
7483 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key1"));
7484 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key2"));
7485 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key3"));
7486 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "key4"));
7487 rados_ioctx_destroy(ioctx);
7488 }
7489
7490 TEST_F(TestLibRBD, PoolMetadataPP)
7491 {
7492 REQUIRE_FORMAT_V2();
7493
7494 librbd::RBD rbd;
7495 string value;
7496 map<string, bufferlist> pairs;
7497
7498 librados::IoCtx ioctx;
7499 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7500
7501 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
7502 ASSERT_TRUE(pairs.empty());
7503
7504 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
7505 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key2", "value2"));
7506 ASSERT_EQ(0, rbd.pool_metadata_get(ioctx, "key1", &value));
7507 ASSERT_EQ(value, "value1");
7508 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
7509 ASSERT_EQ(2U, pairs.size());
7510 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
7511 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7512
7513 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
7514 ASSERT_EQ(-ENOENT, rbd.pool_metadata_remove(ioctx, "key3"));
7515 ASSERT_EQ(-ENOENT, rbd.pool_metadata_get(ioctx, "key3", &value));
7516 pairs.clear();
7517 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "", 0, &pairs));
7518 ASSERT_EQ(1U, pairs.size());
7519 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
7520
7521 // test `start` param
7522 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key1", "value1"));
7523 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "key3", "value3"));
7524
7525 pairs.clear();
7526 ASSERT_EQ(0, rbd.pool_metadata_list(ioctx, "key2", 0, &pairs));
7527 ASSERT_EQ(1U, pairs.size());
7528 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
7529
7530 // test config setting
7531 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_UNKNOWN", "false"));
7532 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7533 ASSERT_EQ(-EINVAL, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "INVALID"));
7534 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
7535
7536 // cleanup
7537 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key1"));
7538 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key2"));
7539 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "key3"));
7540 }
7541
7542 TEST_F(TestLibRBD, Config)
7543 {
7544 REQUIRE_FORMAT_V2();
7545
7546 rados_ioctx_t ioctx;
7547 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
7548
7549 ASSERT_EQ(0, rbd_pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7550
7551 rbd_config_option_t options[1024];
7552 int max_options = 0;
7553 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
7554 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
7555 ASSERT_GT(max_options, 0);
7556 ASSERT_LT(max_options, 1024);
7557 for (int i = 0; i < max_options; i++) {
7558 if (options[i].name == std::string("rbd_cache")) {
7559 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
7560 ASSERT_STREQ("false", options[i].value);
7561 } else {
7562 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7563 }
7564 }
7565 rbd_config_pool_list_cleanup(options, max_options);
7566
7567 rbd_image_t image;
7568 int order = 0;
7569 std::string name = get_temp_image_name();
7570 uint64_t size = 2 << 20;
7571
7572 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
7573 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
7574
7575 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
7576 for (int i = 0; i < max_options; i++) {
7577 if (options[i].name == std::string("rbd_cache")) {
7578 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
7579 ASSERT_STREQ("false", options[i].value);
7580 } else {
7581 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7582 }
7583 }
7584 rbd_config_image_list_cleanup(options, max_options);
7585
7586 ASSERT_EQ(0, rbd_metadata_set(image, "conf_rbd_cache", "true"));
7587
7588 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
7589 for (int i = 0; i < max_options; i++) {
7590 if (options[i].name == std::string("rbd_cache")) {
7591 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_IMAGE);
7592 ASSERT_STREQ("true", options[i].value);
7593 } else {
7594 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7595 }
7596 }
7597 rbd_config_image_list_cleanup(options, max_options);
7598
7599 ASSERT_EQ(0, rbd_metadata_remove(image, "conf_rbd_cache"));
7600
7601 ASSERT_EQ(0, rbd_config_image_list(image, options, &max_options));
7602 for (int i = 0; i < max_options; i++) {
7603 if (options[i].name == std::string("rbd_cache")) {
7604 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_POOL);
7605 ASSERT_STREQ("false", options[i].value);
7606 } else {
7607 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7608 }
7609 }
7610 rbd_config_image_list_cleanup(options, max_options);
7611
7612 ASSERT_EQ(0, rbd_close(image));
7613
7614 ASSERT_EQ(0, rbd_pool_metadata_remove(ioctx, "conf_rbd_cache"));
7615
7616 ASSERT_EQ(-ERANGE, rbd_config_pool_list(ioctx, options, &max_options));
7617 ASSERT_EQ(0, rbd_config_pool_list(ioctx, options, &max_options));
7618 for (int i = 0; i < max_options; i++) {
7619 ASSERT_EQ(options[i].source, RBD_CONFIG_SOURCE_CONFIG);
7620 }
7621 rbd_config_pool_list_cleanup(options, max_options);
7622
7623 rados_ioctx_destroy(ioctx);
7624 }
7625
7626 TEST_F(TestLibRBD, ConfigPP)
7627 {
7628 REQUIRE_FORMAT_V2();
7629
7630 librbd::RBD rbd;
7631 string value;
7632
7633 librados::IoCtx ioctx;
7634 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
7635
7636 ASSERT_EQ(0, rbd.pool_metadata_set(ioctx, "conf_rbd_cache", "false"));
7637
7638 std::vector<librbd::config_option_t> options;
7639 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
7640 for (auto &option : options) {
7641 if (option.name == std::string("rbd_cache")) {
7642 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
7643 ASSERT_EQ("false", option.value);
7644 } else {
7645 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
7646 }
7647 }
7648
7649 int order = 0;
7650 std::string name = get_temp_image_name();
7651 uint64_t size = 2 << 20;
7652 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7653
7654 librbd::Image image;
7655 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
7656
7657 options.clear();
7658 ASSERT_EQ(0, image.config_list(&options));
7659 for (auto &option : options) {
7660 if (option.name == std::string("rbd_cache")) {
7661 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
7662 ASSERT_EQ("false", option.value);
7663 } else {
7664 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
7665 }
7666 }
7667
7668 ASSERT_EQ(0, image.metadata_set("conf_rbd_cache", "true"));
7669
7670 options.clear();
7671 ASSERT_EQ(0, image.config_list(&options));
7672 for (auto &option : options) {
7673 if (option.name == std::string("rbd_cache")) {
7674 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_IMAGE);
7675 ASSERT_EQ("true", option.value);
7676 } else {
7677 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
7678 }
7679 }
7680
7681 ASSERT_EQ(0, image.metadata_remove("conf_rbd_cache"));
7682
7683 options.clear();
7684 ASSERT_EQ(0, image.config_list(&options));
7685 for (auto &option : options) {
7686 if (option.name == std::string("rbd_cache")) {
7687 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_POOL);
7688 ASSERT_EQ("false", option.value);
7689 } else {
7690 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
7691 }
7692 }
7693
7694 ASSERT_EQ(0, rbd.pool_metadata_remove(ioctx, "conf_rbd_cache"));
7695
7696 options.clear();
7697 ASSERT_EQ(0, rbd.config_list(ioctx, &options));
7698 for (auto &option : options) {
7699 ASSERT_EQ(option.source, RBD_CONFIG_SOURCE_CONFIG);
7700 }
7701 }
7702
7703 TEST_F(TestLibRBD, PoolStatsPP)
7704 {
7705 REQUIRE_FORMAT_V2();
7706
7707 librados::IoCtx ioctx;
7708 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
7709
7710 librbd::RBD rbd;
7711 std::string image_name;
7712 uint64_t size = 2 << 20;
7713 uint64_t expected_size = 0;
7714 for (size_t idx = 0; idx < 4; ++idx) {
7715 image_name = get_temp_image_name();
7716
7717 int order = 0;
7718 ASSERT_EQ(0, create_image_pp(rbd, ioctx, image_name.c_str(), size, &order));
7719 expected_size += size;
7720 }
7721
7722 librbd::Image image;
7723 ASSERT_EQ(0, rbd.open(ioctx, image, image_name.c_str(), NULL));
7724 ASSERT_EQ(0, image.snap_create("snap1"));
7725 ASSERT_EQ(0, image.resize(0));
7726 ASSERT_EQ(0, image.close());
7727 uint64_t expect_head_size = (expected_size - size);
7728
7729 uint64_t image_count;
7730 uint64_t provisioned_bytes;
7731 uint64_t max_provisioned_bytes;
7732 uint64_t snap_count;
7733 uint64_t trash_image_count;
7734 uint64_t trash_provisioned_bytes;
7735 uint64_t trash_max_provisioned_bytes;
7736 uint64_t trash_snap_count;
7737
7738 librbd::PoolStats pool_stats1;
7739 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGES, &image_count);
7740 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
7741 &provisioned_bytes);
7742 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
7743
7744 ASSERT_EQ(4U, image_count);
7745 ASSERT_EQ(expect_head_size, provisioned_bytes);
7746
7747 pool_stats1.add(RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
7748 &max_provisioned_bytes);
7749 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats1));
7750 ASSERT_EQ(4U, image_count);
7751 ASSERT_EQ(expect_head_size, provisioned_bytes);
7752 ASSERT_EQ(expected_size, max_provisioned_bytes);
7753
7754 librbd::PoolStats pool_stats2;
7755 pool_stats2.add(RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snap_count);
7756 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
7757 pool_stats2.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
7758 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats2));
7759 ASSERT_EQ(1U, snap_count);
7760 ASSERT_EQ(0U, trash_image_count);
7761 ASSERT_EQ(0U, trash_snap_count);
7762
7763 ASSERT_EQ(0, rbd.trash_move(ioctx, image_name.c_str(), 0));
7764
7765 librbd::PoolStats pool_stats3;
7766 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_IMAGES, &trash_image_count);
7767 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
7768 &trash_provisioned_bytes);
7769 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
7770 &trash_max_provisioned_bytes);
7771 pool_stats3.add(RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &trash_snap_count);
7772 ASSERT_EQ(0, rbd.pool_stats_get(ioctx, &pool_stats3));
7773 ASSERT_EQ(1U, trash_image_count);
7774 ASSERT_EQ(0U, trash_provisioned_bytes);
7775 ASSERT_EQ(size, trash_max_provisioned_bytes);
7776 ASSERT_EQ(1U, trash_snap_count);
7777 }
7778
7779 TEST_F(TestLibRBD, ImageSpec) {
7780 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7781
7782 librados::IoCtx ioctx;
7783 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
7784
7785 librbd::RBD rbd;
7786 librbd::Image parent_image;
7787 std::string name = get_temp_image_name();
7788
7789 uint64_t size = 1;
7790 int order = 0;
7791
7792 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
7793 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
7794
7795 std::string parent_id;
7796 ASSERT_EQ(0, parent_image.get_id(&parent_id));
7797
7798 uint64_t features;
7799 ASSERT_EQ(0, parent_image.features(&features));
7800
7801 ASSERT_EQ(0, parent_image.snap_create("snap"));
7802 ASSERT_EQ(0, parent_image.snap_protect("snap"));
7803
7804 std::string clone_name = this->get_temp_image_name();
7805 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
7806 features, &order));
7807
7808 librbd::Image clone_image;
7809 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
7810
7811 std::string clone_id;
7812 ASSERT_EQ(0, clone_image.get_id(&clone_id));
7813
7814 std::vector<librbd::image_spec_t> images;
7815 ASSERT_EQ(0, rbd.list2(ioctx, &images));
7816
7817 std::vector<librbd::image_spec_t> expected_images{
7818 {.id = parent_id, .name = name},
7819 {.id = clone_id, .name = clone_name}
7820 };
7821 std::sort(expected_images.begin(), expected_images.end(),
7822 [](const librbd::image_spec_t& lhs, const librbd::image_spec_t &rhs) {
7823 return lhs.name < rhs.name;
7824 });
7825 ASSERT_EQ(expected_images, images);
7826
7827 librbd::linked_image_spec_t parent_image_spec;
7828 librbd::snap_spec_t parent_snap_spec;
7829 ASSERT_EQ(0, clone_image.get_parent(&parent_image_spec, &parent_snap_spec));
7830
7831 librbd::linked_image_spec_t expected_parent_image_spec{
7832 .pool_id = ioctx.get_id(),
7833 .pool_name = ioctx.get_pool_name(),
7834 .pool_namespace = ioctx.get_namespace(),
7835 .image_id = parent_id,
7836 .image_name = name,
7837 .trash = false
7838 };
7839 ASSERT_EQ(expected_parent_image_spec, parent_image_spec);
7840 ASSERT_EQ(RBD_SNAP_NAMESPACE_TYPE_USER, parent_snap_spec.namespace_type);
7841 ASSERT_EQ("snap", parent_snap_spec.name);
7842
7843 std::vector<librbd::linked_image_spec_t> children;
7844 ASSERT_EQ(0, parent_image.list_children3(&children));
7845
7846 std::vector<librbd::linked_image_spec_t> expected_children{
7847 {
7848 .pool_id = ioctx.get_id(),
7849 .pool_name = ioctx.get_pool_name(),
7850 .pool_namespace = ioctx.get_namespace(),
7851 .image_id = clone_id,
7852 .image_name = clone_name,
7853 .trash = false
7854 }
7855 };
7856 ASSERT_EQ(expected_children, children);
7857
7858 children.clear();
7859 ASSERT_EQ(0, parent_image.list_descendants(&children));
7860 ASSERT_EQ(expected_children, children);
7861
7862 ASSERT_EQ(0, clone_image.snap_create("snap"));
7863 ASSERT_EQ(0, clone_image.snap_protect("snap"));
7864
7865 auto grand_clone_name = this->get_temp_image_name();
7866 ASSERT_EQ(0, rbd.clone(ioctx, clone_name.c_str(), "snap", ioctx,
7867 grand_clone_name.c_str(), features, &order));
7868 librbd::Image grand_clone_image;
7869 ASSERT_EQ(0, rbd.open(ioctx, grand_clone_image, grand_clone_name.c_str(),
7870 nullptr));
7871 std::string grand_clone_id;
7872 ASSERT_EQ(0, grand_clone_image.get_id(&grand_clone_id));
7873
7874 children.clear();
7875 ASSERT_EQ(0, parent_image.list_children3(&children));
7876 ASSERT_EQ(expected_children, children);
7877
7878 children.clear();
7879 ASSERT_EQ(0, parent_image.list_descendants(&children));
7880 expected_children.push_back(
7881 {
7882 .pool_id = ioctx.get_id(),
7883 .pool_name = ioctx.get_pool_name(),
7884 .pool_namespace = ioctx.get_namespace(),
7885 .image_id = grand_clone_id,
7886 .image_name = grand_clone_name,
7887 .trash = false
7888 }
7889 );
7890 ASSERT_EQ(expected_children, children);
7891 }
7892
7893 TEST_F(TestLibRBD, SnapRemoveWithChildMissing)
7894 {
7895 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
7896 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "2"));
7897 BOOST_SCOPE_EXIT_ALL(&) {
7898 ASSERT_EQ(0, rados_conf_set(_cluster, "rbd_default_clone_format", "auto"));
7899 };
7900
7901 librbd::RBD rbd;
7902 rados_ioctx_t ioctx1, ioctx2;
7903 string pool_name1 = create_pool(true);
7904 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
7905 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx2));
7906
7907 bool old_format;
7908 uint64_t features;
7909 rbd_image_t parent, child1, child2, child3;
7910 int order = 0;
7911 char child_id1[4096];
7912 char child_id2[4096];
7913 char child_id3[4096];
7914
7915 ASSERT_EQ(0, get_features(&old_format, &features));
7916 ASSERT_FALSE(old_format);
7917 std::string parent_name = get_temp_image_name();
7918 std::string child_name1 = get_temp_image_name();
7919 std::string child_name2 = get_temp_image_name();
7920 std::string child_name3 = get_temp_image_name();
7921 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
7922 false, features));
7923 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
7924 ASSERT_EQ(0, rbd_snap_create(parent, "snap1"));
7925 ASSERT_EQ(0, rbd_snap_create(parent, "snap2"));
7926
7927 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap1",
7928 ioctx2, child_name1.c_str(), features, &order));
7929 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
7930 ioctx1, child_name2.c_str(), features, &order));
7931 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "snap2",
7932 ioctx2, child_name3.c_str(), features, &order));
7933
7934 ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &child1, NULL));
7935 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &child2, NULL));
7936 ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &child3, NULL));
7937 ASSERT_EQ(0, rbd_get_id(child1, child_id1, sizeof(child_id1)));
7938 ASSERT_EQ(0, rbd_get_id(child2, child_id2, sizeof(child_id2)));
7939 ASSERT_EQ(0, rbd_get_id(child3, child_id3, sizeof(child_id3)));
7940 test_list_children2(parent, 3,
7941 child_id1, m_pool_name.c_str(), child_name1.c_str(), false,
7942 child_id2, pool_name1.c_str(), child_name2.c_str(), false,
7943 child_id3, m_pool_name.c_str(), child_name3.c_str(), false);
7944
7945 size_t max_size = 10;
7946 rbd_linked_image_spec_t children[max_size];
7947 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
7948 ASSERT_EQ(3, static_cast<int>(max_size));
7949 rbd_linked_image_spec_list_cleanup(children, max_size);
7950
7951 ASSERT_EQ(0, rbd_close(child1));
7952 ASSERT_EQ(0, rbd_close(child2));
7953 ASSERT_EQ(0, rbd_close(child3));
7954 rados_ioctx_destroy(ioctx2);
7955 ASSERT_EQ(0, rados_pool_delete(_cluster, m_pool_name.c_str()));
7956 _pool_names.erase(std::remove(_pool_names.begin(),
7957 _pool_names.end(), m_pool_name),
7958 _pool_names.end());
7959 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
7960
7961 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
7962 ASSERT_EQ(3, static_cast<int>(max_size));
7963 rbd_linked_image_spec_list_cleanup(children, max_size);
7964 ASSERT_EQ(0, rbd_snap_remove(parent, "snap1"));
7965 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
7966 ASSERT_EQ(2, static_cast<int>(max_size));
7967 rbd_linked_image_spec_list_cleanup(children, max_size);
7968
7969 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
7970 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
7971 ASSERT_EQ(1, static_cast<int>(max_size));
7972 rbd_linked_image_spec_list_cleanup(children, max_size);
7973
7974 ASSERT_EQ(0, rbd_snap_remove(parent, "snap2"));
7975 ASSERT_EQ(0, rbd_list_children3(parent, children, &max_size));
7976 ASSERT_EQ(0, static_cast<int>(max_size));
7977 rbd_linked_image_spec_list_cleanup(children, max_size);
7978 test_list_children2(parent, 0);
7979 ASSERT_EQ(0, test_ls_snaps(parent, 0));
7980
7981 ASSERT_EQ(0, rbd_close(parent));
7982 rados_ioctx_destroy(ioctx1);
7983 }
7984
7985 // poorman's ceph_assert()
7986 namespace ceph {
7987 void __ceph_assert_fail(const char *assertion, const char *file, int line,
7988 const char *func) {
7989 ceph_abort();
7990 }
7991 }
7992
7993 #pragma GCC diagnostic pop
7994 #pragma GCC diagnostic warning "-Wpragmas"