]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/test_librbd.cc
update sources to 12.2.10
[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/librbd/test_support.h"
45 #include "common/event_socket.h"
46 #include "include/interval_set.h"
47 #include "include/stringify.h"
48
49 #include <boost/assign/list_of.hpp>
50 #include <boost/scope_exit.hpp>
51
52 #ifdef HAVE_EVENTFD
53 #include <sys/eventfd.h>
54 #endif
55
56 using namespace std;
57
58 using std::chrono::seconds;
59
60 #define ASSERT_PASSED(x, args...) \
61 do { \
62 bool passed = false; \
63 x(args, &passed); \
64 ASSERT_TRUE(passed); \
65 } while(0)
66
67 void register_test_librbd() {
68 }
69
70 static int get_features(bool *old_format, uint64_t *features)
71 {
72 const char *c = getenv("RBD_FEATURES");
73 if (c) {
74 stringstream ss;
75 ss << c;
76 ss >> *features;
77 if (ss.fail())
78 return -EINVAL;
79 *old_format = false;
80 cout << "using new format!" << std::endl;
81 } else {
82 *old_format = true;
83 *features = 0;
84 cout << "using old format" << std::endl;
85 }
86
87 return 0;
88 }
89
90 static int create_image_full(rados_ioctx_t ioctx, const char *name,
91 uint64_t size, int *order, int old_format,
92 uint64_t features)
93 {
94 if (old_format) {
95 // ensure old-format tests actually use the old format
96 int r = rados_conf_set(rados_ioctx_get_cluster(ioctx),
97 "rbd_default_format", "1");
98 if (r < 0) {
99 return r;
100 }
101 return rbd_create(ioctx, name, size, order);
102 } else if ((features & RBD_FEATURE_STRIPINGV2) != 0) {
103 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
104 if (*order) {
105 // use a conservative stripe_unit for non default order
106 stripe_unit = (1ull << (*order-1));
107 }
108
109 printf("creating image with stripe unit: %" PRIu64 ", "
110 "stripe count: %" PRIu64 "\n",
111 stripe_unit, IMAGE_STRIPE_COUNT);
112 return rbd_create3(ioctx, name, size, features, order,
113 stripe_unit, IMAGE_STRIPE_COUNT);
114 } else {
115 return rbd_create2(ioctx, name, size, features, order);
116 }
117 }
118
119 static int clone_image(rados_ioctx_t p_ioctx,
120 rbd_image_t p_image, const char *p_name,
121 const char *p_snap_name, rados_ioctx_t c_ioctx,
122 const char *c_name, uint64_t features, int *c_order)
123 {
124 uint64_t stripe_unit, stripe_count;
125
126 int r;
127 r = rbd_get_stripe_unit(p_image, &stripe_unit);
128 if (r != 0) {
129 return r;
130 }
131
132 r = rbd_get_stripe_count(p_image, &stripe_count);
133 if (r != 0) {
134 return r;
135 }
136
137 return rbd_clone2(p_ioctx, p_name, p_snap_name, c_ioctx,
138 c_name, features, c_order, stripe_unit, stripe_count);
139 }
140
141
142 static int create_image(rados_ioctx_t ioctx, const char *name,
143 uint64_t size, int *order)
144 {
145 bool old_format;
146 uint64_t features;
147
148 int r = get_features(&old_format, &features);
149 if (r < 0)
150 return r;
151 return create_image_full(ioctx, name, size, order, old_format, features);
152 }
153
154 static int create_image_pp(librbd::RBD &rbd,
155 librados::IoCtx &ioctx,
156 const char *name,
157 uint64_t size, int *order) {
158 bool old_format;
159 uint64_t features;
160 int r = get_features(&old_format, &features);
161 if (r < 0)
162 return r;
163 if (old_format) {
164 librados::Rados rados(ioctx);
165 int r = rados.conf_set("rbd_default_format", "1");
166 if (r < 0) {
167 return r;
168 }
169 return rbd.create(ioctx, name, size, order);
170 } else {
171 return rbd.create2(ioctx, name, size, features, order);
172 }
173 }
174
175 class TestLibRBD : public ::testing::Test {
176 public:
177
178 TestLibRBD() : m_pool_number() {
179 }
180
181 static void SetUpTestCase() {
182 static bool seeded = false;
183 if (!seeded) {
184 seeded = true;
185 int seed = getpid();
186 cout << "seed " << seed << std::endl;
187 srand(seed);
188 }
189
190 _pool_names.clear();
191 _unique_pool_names.clear();
192 _image_number = 0;
193 ASSERT_EQ("", connect_cluster(&_cluster));
194 ASSERT_EQ("", connect_cluster_pp(_rados));
195
196 create_optional_data_pool();
197 }
198
199 static void TearDownTestCase() {
200 rados_shutdown(_cluster);
201 _rados.wait_for_latest_osdmap();
202 _pool_names.insert(_pool_names.end(), _unique_pool_names.begin(),
203 _unique_pool_names.end());
204 for (size_t i = 1; i < _pool_names.size(); ++i) {
205 ASSERT_EQ(0, _rados.pool_delete(_pool_names[i].c_str()));
206 }
207 if (!_pool_names.empty()) {
208 ASSERT_EQ(0, destroy_one_pool_pp(_pool_names[0], _rados));
209 }
210 }
211
212 void SetUp() override {
213 ASSERT_NE("", m_pool_name = create_pool());
214 }
215
216 bool is_skip_partial_discard_enabled() {
217 std::string value;
218 EXPECT_EQ(0, _rados.conf_get("rbd_skip_partial_discard", value));
219 return value == "true";
220 }
221
222 void validate_object_map(rbd_image_t image, bool *passed) {
223 uint64_t flags;
224 ASSERT_EQ(0, rbd_get_flags(image, &flags));
225 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
226 }
227
228 void validate_object_map(librbd::Image &image, bool *passed) {
229 uint64_t flags;
230 ASSERT_EQ(0, image.get_flags(&flags));
231 *passed = ((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
232 }
233
234 std::string get_temp_image_name() {
235 ++_image_number;
236 return "image" + stringify(_image_number);
237 }
238
239 static void create_optional_data_pool() {
240 bool created = false;
241 std::string data_pool;
242 ASSERT_EQ(0, create_image_data_pool(_rados, data_pool, &created));
243 if (!data_pool.empty()) {
244 printf("using image data pool: %s\n", data_pool.c_str());
245 if (created) {
246 _unique_pool_names.push_back(data_pool);
247 }
248 }
249 }
250
251 std::string create_pool(bool unique = false) {
252 librados::Rados rados;
253 std::string pool_name;
254 if (unique) {
255 pool_name = get_temp_pool_name("test-librbd-");
256 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
257 _unique_pool_names.push_back(pool_name);
258 } else if (m_pool_number < _pool_names.size()) {
259 pool_name = _pool_names[m_pool_number];
260 } else {
261 pool_name = get_temp_pool_name("test-librbd-");
262 EXPECT_EQ("", create_one_pool_pp(pool_name, rados));
263 _pool_names.push_back(pool_name);
264 }
265 ++m_pool_number;
266 return pool_name;
267 }
268
269 static std::vector<std::string> _pool_names;
270 static std::vector<std::string> _unique_pool_names;
271 static rados_t _cluster;
272 static librados::Rados _rados;
273 static uint64_t _image_number;
274
275 std::string m_pool_name;
276 uint32_t m_pool_number;
277
278 };
279
280 std::vector<std::string> TestLibRBD::_pool_names;
281 std::vector<std::string> TestLibRBD::_unique_pool_names;
282 rados_t TestLibRBD::_cluster;
283 librados::Rados TestLibRBD::_rados;
284 uint64_t TestLibRBD::_image_number = 0;
285
286 TEST_F(TestLibRBD, CreateAndStat)
287 {
288 rados_ioctx_t ioctx;
289 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
290
291 rbd_image_info_t info;
292 rbd_image_t image;
293 int order = 0;
294 std::string name = get_temp_image_name();
295 uint64_t size = 2 << 20;
296
297 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
298 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
299 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
300 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
301 ASSERT_EQ(info.size, size);
302 ASSERT_EQ(info.order, order);
303 ASSERT_EQ(0, rbd_close(image));
304
305 rados_ioctx_destroy(ioctx);
306 }
307
308 TEST_F(TestLibRBD, CreateWithSameDataPool)
309 {
310 REQUIRE_FORMAT_V2();
311
312 rados_ioctx_t ioctx;
313 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
314
315 rbd_image_t image;
316 std::string name = get_temp_image_name();
317 uint64_t size = 2 << 20;
318
319 bool old_format;
320 uint64_t features;
321 ASSERT_EQ(0, get_features(&old_format, &features));
322 ASSERT_FALSE(old_format);
323
324 rbd_image_options_t image_options;
325 rbd_image_options_create(&image_options);
326 BOOST_SCOPE_EXIT( (&image_options) ) {
327 rbd_image_options_destroy(image_options);
328 } BOOST_SCOPE_EXIT_END;
329
330 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
331 RBD_IMAGE_OPTION_FEATURES,
332 features));
333 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
334 RBD_IMAGE_OPTION_DATA_POOL,
335 m_pool_name.c_str()));
336
337 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
338 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
339
340 ASSERT_EQ(0, rbd_close(image));
341
342 rados_ioctx_destroy(ioctx);
343 }
344
345 TEST_F(TestLibRBD, CreateAndStatPP)
346 {
347 librados::IoCtx ioctx;
348 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
349
350 {
351 librbd::RBD rbd;
352 librbd::image_info_t info;
353 librbd::Image image;
354 int order = 0;
355 std::string name = get_temp_image_name();
356 uint64_t size = 2 << 20;
357
358 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
359 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
360 ASSERT_EQ(0, image.stat(info, sizeof(info)));
361 ASSERT_EQ(info.size, size);
362 ASSERT_EQ(info.order, order);
363 }
364
365 ioctx.close();
366 }
367
368 TEST_F(TestLibRBD, GetId)
369 {
370 rados_ioctx_t ioctx;
371 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
372
373 rbd_image_t image;
374 int order = 0;
375 std::string name = get_temp_image_name();
376
377 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
378 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
379
380 char id[4096];
381 if (!is_feature_enabled(0)) {
382 // V1 image
383 ASSERT_EQ(-EINVAL, rbd_get_id(image, id, sizeof(id)));
384 } else {
385 ASSERT_EQ(-ERANGE, rbd_get_id(image, id, 0));
386 ASSERT_EQ(0, rbd_get_id(image, id, sizeof(id)));
387 ASSERT_LT(0U, strlen(id));
388 }
389
390 ASSERT_EQ(0, rbd_close(image));
391 rados_ioctx_destroy(ioctx);
392 }
393
394 TEST_F(TestLibRBD, GetIdPP)
395 {
396 librados::IoCtx ioctx;
397 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
398
399 librbd::RBD rbd;
400 librbd::Image image;
401 int order = 0;
402 std::string name = get_temp_image_name();
403
404 std::string id;
405 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
406 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
407 if (!is_feature_enabled(0)) {
408 // V1 image
409 ASSERT_EQ(-EINVAL, image.get_id(&id));
410 } else {
411 ASSERT_EQ(0, image.get_id(&id));
412 ASSERT_LT(0U, id.size());
413 }
414 }
415
416 TEST_F(TestLibRBD, GetBlockNamePrefix)
417 {
418 rados_ioctx_t ioctx;
419 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
420
421 rbd_image_t image;
422 int order = 0;
423 std::string name = get_temp_image_name();
424
425 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
426 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
427
428 char prefix[4096];
429 ASSERT_EQ(-ERANGE, rbd_get_block_name_prefix(image, prefix, 0));
430 ASSERT_EQ(0, rbd_get_block_name_prefix(image, prefix, sizeof(prefix)));
431 ASSERT_LT(0U, strlen(prefix));
432
433 ASSERT_EQ(0, rbd_close(image));
434 rados_ioctx_destroy(ioctx);
435 }
436
437 TEST_F(TestLibRBD, GetBlockNamePrefixPP)
438 {
439 librados::IoCtx ioctx;
440 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
441
442 librbd::RBD rbd;
443 librbd::Image image;
444 int order = 0;
445 std::string name = get_temp_image_name();
446
447 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
448 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
449 ASSERT_LT(0U, image.get_block_name_prefix().size());
450 }
451
452 TEST_F(TestLibRBD, TestGetCreateTimestamp)
453 {
454 REQUIRE_FORMAT_V2();
455
456 rados_ioctx_t ioctx;
457 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
458
459 rbd_image_t image;
460 int order = 0;
461 std::string name = get_temp_image_name();
462
463 ASSERT_EQ(0, create_image(ioctx, name.c_str(), 0, &order));
464 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
465
466 struct timespec timestamp;
467 ASSERT_EQ(0, rbd_get_create_timestamp(image, &timestamp));
468 ASSERT_LT(0, timestamp.tv_sec);
469
470 ASSERT_EQ(0, rbd_close(image));
471
472 rados_ioctx_destroy(ioctx);
473 }
474
475 TEST_F(TestLibRBD, GetCreateTimestampPP)
476 {
477 REQUIRE_FORMAT_V2();
478
479 librados::IoCtx ioctx;
480 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
481
482 librbd::RBD rbd;
483 librbd::Image image;
484 int order = 0;
485 std::string name = get_temp_image_name();
486
487 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 0, &order));
488 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
489
490 struct timespec timestamp;
491 ASSERT_EQ(0, image.get_create_timestamp(&timestamp));
492 ASSERT_LT(0, timestamp.tv_sec);
493 }
494
495 TEST_F(TestLibRBD, OpenAio)
496 {
497 rados_ioctx_t ioctx;
498 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
499
500 rbd_image_info_t info;
501 rbd_image_t image;
502 int order = 0;
503 std::string name = get_temp_image_name();
504 uint64_t size = 2 << 20;
505
506 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
507
508 rbd_completion_t open_comp;
509 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
510 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
511 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
512 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
513 ASSERT_EQ(0, rbd_aio_get_return_value(open_comp));
514 rbd_aio_release(open_comp);
515
516 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
517 printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
518 ASSERT_EQ(info.size, size);
519 ASSERT_EQ(info.order, order);
520
521 rbd_completion_t close_comp;
522 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &close_comp));
523 ASSERT_EQ(0, rbd_aio_close(image, close_comp));
524 ASSERT_EQ(0, rbd_aio_wait_for_complete(close_comp));
525 ASSERT_EQ(1, rbd_aio_is_complete(close_comp));
526 ASSERT_EQ(0, rbd_aio_get_return_value(close_comp));
527 rbd_aio_release(close_comp);
528
529 rados_ioctx_destroy(ioctx);
530 }
531
532 TEST_F(TestLibRBD, OpenAioFail)
533 {
534 rados_ioctx_t ioctx;
535 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
536
537 std::string name = get_temp_image_name();
538 rbd_image_t image;
539 rbd_completion_t open_comp;
540 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &open_comp));
541 ASSERT_EQ(0, rbd_aio_open(ioctx, name.c_str(), &image, NULL, open_comp));
542 ASSERT_EQ(0, rbd_aio_wait_for_complete(open_comp));
543 ASSERT_EQ(1, rbd_aio_is_complete(open_comp));
544 ASSERT_EQ(-ENOENT, rbd_aio_get_return_value(open_comp));
545 rbd_aio_release(open_comp);
546
547 rados_ioctx_destroy(ioctx);
548 }
549
550 TEST_F(TestLibRBD, OpenAioPP)
551 {
552 librados::IoCtx ioctx;
553 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
554
555 librbd::RBD rbd;
556 librbd::image_info_t info;
557 librbd::Image image;
558 int order = 0;
559 std::string name = get_temp_image_name();
560 uint64_t size = 2 << 20;
561
562 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
563
564 librbd::RBD::AioCompletion *open_comp =
565 new librbd::RBD::AioCompletion(NULL, NULL);
566 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
567 ASSERT_EQ(0, open_comp->wait_for_complete());
568 ASSERT_EQ(1, open_comp->is_complete());
569 ASSERT_EQ(0, open_comp->get_return_value());
570 open_comp->release();
571
572 ASSERT_EQ(0, image.stat(info, sizeof(info)));
573 ASSERT_EQ(info.size, size);
574 ASSERT_EQ(info.order, order);
575
576 // reopen
577 open_comp = 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 // close
585 librbd::RBD::AioCompletion *close_comp =
586 new librbd::RBD::AioCompletion(NULL, NULL);
587 ASSERT_EQ(0, image.aio_close(close_comp));
588 ASSERT_EQ(0, close_comp->wait_for_complete());
589 ASSERT_EQ(1, close_comp->is_complete());
590 ASSERT_EQ(0, close_comp->get_return_value());
591 close_comp->release();
592
593 // close closed image
594 close_comp = new librbd::RBD::AioCompletion(NULL, NULL);
595 ASSERT_EQ(-EINVAL, image.aio_close(close_comp));
596 close_comp->release();
597
598 ioctx.close();
599 }
600
601 TEST_F(TestLibRBD, OpenAioFailPP)
602 {
603 librados::IoCtx ioctx;
604 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
605
606 {
607 librbd::RBD rbd;
608 librbd::Image image;
609 std::string name = get_temp_image_name();
610
611 librbd::RBD::AioCompletion *open_comp =
612 new librbd::RBD::AioCompletion(NULL, NULL);
613 ASSERT_EQ(0, rbd.aio_open(ioctx, image, name.c_str(), NULL, open_comp));
614 ASSERT_EQ(0, open_comp->wait_for_complete());
615 ASSERT_EQ(1, open_comp->is_complete());
616 ASSERT_EQ(-ENOENT, open_comp->get_return_value());
617 open_comp->release();
618 }
619
620 ioctx.close();
621 }
622
623 TEST_F(TestLibRBD, ResizeAndStat)
624 {
625 rados_ioctx_t ioctx;
626 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
627
628 rbd_image_info_t info;
629 rbd_image_t image;
630 int order = 0;
631 std::string name = get_temp_image_name();
632 uint64_t size = 2 << 20;
633
634 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
635 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
636
637 ASSERT_EQ(0, rbd_resize(image, size * 4));
638 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
639 ASSERT_EQ(info.size, size * 4);
640
641 ASSERT_EQ(0, rbd_resize(image, size / 2));
642 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
643 ASSERT_EQ(info.size, size / 2);
644
645 // downsizing without allowing shrink should fail
646 // and image size should not change
647 ASSERT_EQ(-EINVAL, rbd_resize2(image, size / 4, false, NULL, NULL));
648 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
649 ASSERT_EQ(info.size, size / 2);
650
651 ASSERT_EQ(0, rbd_resize2(image, size / 4, true, NULL, NULL));
652 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
653 ASSERT_EQ(info.size, size / 4);
654
655 ASSERT_PASSED(validate_object_map, image);
656 ASSERT_EQ(0, rbd_close(image));
657
658 rados_ioctx_destroy(ioctx);
659 }
660
661 TEST_F(TestLibRBD, ResizeAndStatPP)
662 {
663 librados::IoCtx ioctx;
664 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
665
666 {
667 librbd::RBD rbd;
668 librbd::image_info_t info;
669 librbd::Image image;
670 int order = 0;
671 std::string name = get_temp_image_name();
672 uint64_t size = 2 << 20;
673
674 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
675 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
676
677 ASSERT_EQ(0, image.resize(size * 4));
678 ASSERT_EQ(0, image.stat(info, sizeof(info)));
679 ASSERT_EQ(info.size, size * 4);
680
681 ASSERT_EQ(0, image.resize(size / 2));
682 ASSERT_EQ(0, image.stat(info, sizeof(info)));
683 ASSERT_EQ(info.size, size / 2);
684 ASSERT_PASSED(validate_object_map, image);
685 }
686
687 ioctx.close();
688 }
689
690 TEST_F(TestLibRBD, UpdateWatchAndResize)
691 {
692 rados_ioctx_t ioctx;
693 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
694
695 rbd_image_t image;
696 int order = 0;
697 std::string name = get_temp_image_name();
698 uint64_t size = 2 << 20;
699 struct Watcher {
700 rbd_image_t &m_image;
701 mutex m_lock;
702 condition_variable m_cond;
703 size_t m_size = 0;
704 static void cb(void *arg) {
705 Watcher *watcher = static_cast<Watcher *>(arg);
706 watcher->handle_notify();
707 }
708 Watcher(rbd_image_t &image) : m_image(image) {}
709 void handle_notify() {
710 rbd_image_info_t info;
711 ASSERT_EQ(0, rbd_stat(m_image, &info, sizeof(info)));
712 lock_guard<mutex> locker(m_lock);
713 m_size = info.size;
714 m_cond.notify_one();
715 }
716 void wait_for_size(size_t size) {
717 unique_lock<mutex> locker(m_lock);
718 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
719 [size, this] {
720 return this->m_size == size;}));
721 }
722 } watcher(image);
723 uint64_t handle;
724
725 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
726 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
727
728 ASSERT_EQ(0, rbd_update_watch(image, &handle, Watcher::cb, &watcher));
729
730 ASSERT_EQ(0, rbd_resize(image, size * 4));
731 watcher.wait_for_size(size * 4);
732
733 ASSERT_EQ(0, rbd_resize(image, size / 2));
734 watcher.wait_for_size(size / 2);
735
736 ASSERT_EQ(0, rbd_update_unwatch(image, handle));
737
738 ASSERT_EQ(0, rbd_close(image));
739 rados_ioctx_destroy(ioctx);
740 }
741
742 TEST_F(TestLibRBD, UpdateWatchAndResizePP)
743 {
744 librados::IoCtx ioctx;
745 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
746
747 {
748 librbd::RBD rbd;
749 librbd::Image image;
750 int order = 0;
751 std::string name = get_temp_image_name();
752 uint64_t size = 2 << 20;
753 struct Watcher : public librbd::UpdateWatchCtx {
754 Watcher(librbd::Image &image) : m_image(image) {
755 }
756 void handle_notify() override {
757 librbd::image_info_t info;
758 ASSERT_EQ(0, m_image.stat(info, sizeof(info)));
759 lock_guard<mutex> locker(m_lock);
760 m_size = info.size;
761 m_cond.notify_one();
762 }
763 void wait_for_size(size_t size) {
764 unique_lock<mutex> locker(m_lock);
765 ASSERT_TRUE(m_cond.wait_for(locker, seconds(5),
766 [size, this] {
767 return this->m_size == size;}));
768 }
769 librbd::Image &m_image;
770 mutex m_lock;
771 condition_variable m_cond;
772 size_t m_size = 0;
773 } watcher(image);
774 uint64_t handle;
775
776 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
777 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
778
779 ASSERT_EQ(0, image.update_watch(&watcher, &handle));
780
781 ASSERT_EQ(0, image.resize(size * 4));
782 watcher.wait_for_size(size * 4);
783
784 ASSERT_EQ(0, image.resize(size / 2));
785 watcher.wait_for_size(size / 2);
786
787 ASSERT_EQ(0, image.update_unwatch(handle));
788 }
789
790 ioctx.close();
791 }
792
793 int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
794 {
795 int num_images, i;
796 char *names, *cur_name;
797 va_list ap;
798 size_t max_size = 1024;
799
800 names = (char *) malloc(sizeof(char) * 1024);
801 int len = rbd_list(io_ctx, names, &max_size);
802
803 std::set<std::string> image_names;
804 for (i = 0, num_images = 0, cur_name = names; cur_name < names + len; i++) {
805 printf("image: %s\n", cur_name);
806 image_names.insert(cur_name);
807 cur_name += strlen(cur_name) + 1;
808 num_images++;
809 }
810 free(names);
811
812 va_start(ap, num_expected);
813 for (i = num_expected; i > 0; i--) {
814 char *expected = va_arg(ap, char *);
815 printf("expected = %s\n", expected);
816 std::set<std::string>::iterator it = image_names.find(expected);
817 if (it != image_names.end()) {
818 printf("found %s\n", expected);
819 image_names.erase(it);
820 printf("erased %s\n", expected);
821 } else {
822 ADD_FAILURE() << "Unable to find image " << expected;
823 va_end(ap);
824 return -ENOENT;
825 }
826 }
827 va_end(ap);
828
829 if (!image_names.empty()) {
830 ADD_FAILURE() << "Unexpected images discovered";
831 return -EINVAL;
832 }
833 return num_images;
834 }
835
836 TEST_F(TestLibRBD, TestCreateLsDelete)
837 {
838 rados_ioctx_t ioctx;
839 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
840
841 int order = 0;
842 std::string name = get_temp_image_name();
843 std::string name2 = get_temp_image_name();
844 uint64_t size = 2 << 20;
845
846 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
847 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
848 ASSERT_EQ(0, create_image(ioctx, name2.c_str(), size, &order));
849 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
850 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
851 ASSERT_EQ(1, test_ls(ioctx, 1, name2.c_str()));
852
853 ASSERT_EQ(-ENOENT, rbd_remove(ioctx, name.c_str()));
854
855 rados_ioctx_destroy(ioctx);
856 }
857
858 int test_ls_pp(librbd::RBD& rbd, librados::IoCtx& io_ctx, size_t num_expected, ...)
859 {
860 int r;
861 size_t i;
862 va_list ap;
863 vector<string> names;
864 r = rbd.list(io_ctx, names);
865 if (r == -ENOENT)
866 r = 0;
867 EXPECT_TRUE(r >= 0);
868 cout << "num images is: " << names.size() << std::endl
869 << "expected: " << num_expected << std::endl;
870 int num = names.size();
871
872 for (i = 0; i < names.size(); i++) {
873 cout << "image: " << names[i] << std::endl;
874 }
875
876 va_start(ap, num_expected);
877 for (i = num_expected; i > 0; i--) {
878 char *expected = va_arg(ap, char *);
879 cout << "expected = " << expected << std::endl;
880 vector<string>::iterator listed_name = find(names.begin(), names.end(), string(expected));
881 if (listed_name == names.end()) {
882 ADD_FAILURE() << "Unable to find image " << expected;
883 va_end(ap);
884 return -ENOENT;
885 }
886 names.erase(listed_name);
887 }
888 va_end(ap);
889
890 if (!names.empty()) {
891 ADD_FAILURE() << "Unexpected images discovered";
892 return -EINVAL;
893 }
894 return num;
895 }
896
897 TEST_F(TestLibRBD, TestCreateLsDeletePP)
898 {
899 librados::IoCtx ioctx;
900 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
901
902 {
903 librbd::RBD rbd;
904 librbd::Image image;
905 int order = 0;
906 std::string name = get_temp_image_name();
907 std::string name2 = get_temp_image_name();
908 uint64_t size = 2 << 20;
909
910 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
911 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
912 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name2.c_str(), size, &order));
913 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
914 ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
915 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name2.c_str()));
916 }
917
918 ioctx.close();
919 }
920
921
922 static int print_progress_percent(uint64_t offset, uint64_t src_size,
923 void *data)
924 {
925 float percent = ((float)offset * 100) / src_size;
926 printf("%3.2f%% done\n", percent);
927 return 0;
928 }
929
930 TEST_F(TestLibRBD, TestCopy)
931 {
932 rados_ioctx_t ioctx;
933 rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
934
935 rbd_image_t image;
936 rbd_image_t image2;
937 rbd_image_t image3;
938 int order = 0;
939 std::string name = get_temp_image_name();
940 std::string name2 = get_temp_image_name();
941 std::string name3 = get_temp_image_name();
942
943 uint64_t size = 2 << 20;
944
945 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
946 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
947 ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
948
949 size_t sum_key_len = 0;
950 size_t sum_value_len = 0;
951 std::string key;
952 std::string val;
953 for (int i = 1; i <= 70; i++) {
954 key = "key" + stringify(i);
955 val = "value" + stringify(i);
956 ASSERT_EQ(0, rbd_metadata_set(image, key.c_str(), val.c_str()));
957
958 sum_key_len += (key.size() + 1);
959 sum_value_len += (val.size() + 1);
960 }
961
962 char keys[1024];
963 char vals[1024];
964 size_t keys_len = sizeof(keys);
965 size_t vals_len = sizeof(vals);
966
967 char value[1024];
968 size_t value_len = sizeof(value);
969
970 ASSERT_EQ(0, rbd_copy(image, ioctx, name2.c_str()));
971 ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
972 ASSERT_EQ(0, rbd_open(ioctx, name2.c_str(), &image2, NULL));
973 ASSERT_EQ(0, rbd_metadata_list(image2, "", 70, keys, &keys_len, vals,
974 &vals_len));
975 ASSERT_EQ(keys_len, sum_key_len);
976 ASSERT_EQ(vals_len, sum_value_len);
977
978 for (int i = 1; i <= 70; i++) {
979 key = "key" + stringify(i);
980 val = "value" + stringify(i);
981 ASSERT_EQ(0, rbd_metadata_get(image2, key.c_str(), value, &value_len));
982 ASSERT_STREQ(val.c_str(), value);
983
984 value_len = sizeof(value);
985 }
986
987 ASSERT_EQ(0, rbd_copy_with_progress(image, ioctx, name3.c_str(),
988 print_progress_percent, NULL));
989 ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
990
991 keys_len = sizeof(keys);
992 vals_len = sizeof(vals);
993 ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
994 ASSERT_EQ(0, rbd_metadata_list(image3, "", 70, keys, &keys_len, vals,
995 &vals_len));
996 ASSERT_EQ(keys_len, sum_key_len);
997 ASSERT_EQ(vals_len, sum_value_len);
998
999 for (int i = 1; i <= 70; i++) {
1000 key = "key" + stringify(i);
1001 val = "value" + stringify(i);
1002 ASSERT_EQ(0, rbd_metadata_get(image3, key.c_str(), value, &value_len));
1003 ASSERT_STREQ(val.c_str(), value);
1004
1005 value_len = sizeof(value);
1006 }
1007
1008 ASSERT_EQ(0, rbd_close(image));
1009 ASSERT_EQ(0, rbd_close(image2));
1010 ASSERT_EQ(0, rbd_close(image3));
1011 rados_ioctx_destroy(ioctx);
1012 }
1013
1014 class PrintProgress : public librbd::ProgressContext
1015 {
1016 public:
1017 int update_progress(uint64_t offset, uint64_t src_size) override
1018 {
1019 float percent = ((float)offset * 100) / src_size;
1020 printf("%3.2f%% done\n", percent);
1021 return 0;
1022 }
1023 };
1024
1025 TEST_F(TestLibRBD, TestCopyPP)
1026 {
1027 librados::IoCtx ioctx;
1028 ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
1029
1030 {
1031 librbd::RBD rbd;
1032 librbd::Image image;
1033 librbd::Image image2;
1034 librbd::Image image3;
1035 int order = 0;
1036 std::string name = get_temp_image_name();
1037 std::string name2 = get_temp_image_name();
1038 std::string name3 = get_temp_image_name();
1039 uint64_t size = 2 << 20;
1040 PrintProgress pp;
1041
1042 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1043 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1044
1045 std::string key;
1046 std::string val;
1047 for (int i = 1; i <= 70; i++) {
1048 key = "key" + stringify(i);
1049 val = "value" + stringify(i);
1050 ASSERT_EQ(0, image.metadata_set(key, val));
1051 }
1052
1053 ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
1054 ASSERT_EQ(0, image.copy(ioctx, name2.c_str()));
1055 ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
1056 ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), NULL));
1057
1058 map<string, bufferlist> pairs;
1059 std::string value;
1060 ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
1061 ASSERT_EQ(70U, pairs.size());
1062
1063 for (int i = 1; i <= 70; i++) {
1064 key = "key" + stringify(i);
1065 val = "value" + stringify(i);
1066 ASSERT_EQ(0, image2.metadata_get(key.c_str(), &value));
1067 ASSERT_STREQ(val.c_str(), value.c_str());
1068 }
1069
1070 ASSERT_EQ(0, image.copy_with_progress(ioctx, name3.c_str(), pp));
1071 ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name.c_str(), name2.c_str(),
1072 name3.c_str()));
1073 ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
1074
1075 pairs.clear();
1076 ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
1077 ASSERT_EQ(70U, pairs.size());
1078
1079 for (int i = 1; i <= 70; i++) {
1080 key = "key" + stringify(i);
1081 val = "value" + stringify(i);
1082 ASSERT_EQ(0, image3.metadata_get(key.c_str(), &value));
1083 ASSERT_STREQ(val.c_str(), value.c_str());
1084 }
1085 }
1086
1087 ioctx.close();
1088 }
1089
1090 int test_ls_snaps(rbd_image_t image, int num_expected, ...)
1091 {
1092 int num_snaps, i, j, max_size = 10;
1093 va_list ap;
1094 rbd_snap_info_t snaps[max_size];
1095 num_snaps = rbd_snap_list(image, snaps, &max_size);
1096 printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected);
1097
1098 for (i = 0; i < num_snaps; i++) {
1099 printf("snap: %s\n", snaps[i].name);
1100 }
1101
1102 va_start(ap, num_expected);
1103 for (i = num_expected; i > 0; i--) {
1104 char *expected = va_arg(ap, char *);
1105 uint64_t expected_size = va_arg(ap, uint64_t);
1106 bool found = false;
1107 for (j = 0; j < num_snaps; j++) {
1108 if (snaps[j].name == NULL)
1109 continue;
1110 if (strcmp(snaps[j].name, expected) == 0) {
1111 printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size);
1112 EXPECT_EQ(expected_size, snaps[j].size);
1113 free((void *) snaps[j].name);
1114 snaps[j].name = NULL;
1115 found = true;
1116 break;
1117 }
1118 }
1119 EXPECT_TRUE(found);
1120 }
1121 va_end(ap);
1122
1123 for (i = 0; i < num_snaps; i++) {
1124 EXPECT_EQ((const char *)0, snaps[i].name);
1125 }
1126
1127 return num_snaps;
1128 }
1129
1130 TEST_F(TestLibRBD, TestCreateLsDeleteSnap)
1131 {
1132 rados_ioctx_t ioctx;
1133 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1134
1135 rbd_image_t image;
1136 int order = 0;
1137 std::string name = get_temp_image_name();
1138 uint64_t size = 2 << 20;
1139 uint64_t size2 = 4 << 20;
1140
1141 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1142 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1143
1144 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1145 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1146 ASSERT_EQ(0, rbd_resize(image, size2));
1147 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1148 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1149 ASSERT_EQ(0, rbd_snap_remove(image, "snap1"));
1150 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
1151 ASSERT_EQ(0, rbd_snap_remove(image, "snap2"));
1152 ASSERT_EQ(0, test_ls_snaps(image, 0));
1153
1154 ASSERT_EQ(0, rbd_close(image));
1155
1156 rados_ioctx_destroy(ioctx);
1157 }
1158
1159 int test_get_snapshot_timestamp(rbd_image_t image, uint64_t snap_id)
1160 {
1161 struct timespec timestamp;
1162 EXPECT_EQ(0, rbd_snap_get_timestamp(image, snap_id, &timestamp));
1163 EXPECT_LT(0, timestamp.tv_sec);
1164 return 0;
1165 }
1166
1167 TEST_F(TestLibRBD, TestGetSnapShotTimeStamp)
1168 {
1169 REQUIRE_FORMAT_V2();
1170
1171 rados_ioctx_t ioctx;
1172 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1173
1174 rbd_image_t image;
1175 int order = 0;
1176 std::string name = get_temp_image_name();
1177 uint64_t size = 2 << 20;
1178 int num_snaps, max_size = 10;
1179 rbd_snap_info_t snaps[max_size];
1180
1181 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1182 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1183
1184 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
1185 num_snaps = rbd_snap_list(image, snaps, &max_size);
1186 ASSERT_EQ(1, num_snaps);
1187 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1188 free((void *)snaps[0].name);
1189
1190 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
1191 num_snaps = rbd_snap_list(image, snaps, &max_size);
1192 ASSERT_EQ(2, num_snaps);
1193 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[0].id));
1194 ASSERT_EQ(0, test_get_snapshot_timestamp(image, snaps[1].id));
1195 free((void *)snaps[0].name);
1196 free((void *)snaps[1].name);
1197
1198 ASSERT_EQ(0, rbd_close(image));
1199
1200 rados_ioctx_destroy(ioctx);
1201 }
1202
1203
1204 int test_ls_snaps(librbd::Image& image, size_t num_expected, ...)
1205 {
1206 int r;
1207 size_t i, j;
1208 va_list ap;
1209 vector<librbd::snap_info_t> snaps;
1210 r = image.snap_list(snaps);
1211 EXPECT_TRUE(r >= 0);
1212 cout << "num snaps is: " << snaps.size() << std::endl
1213 << "expected: " << num_expected << std::endl;
1214
1215 for (i = 0; i < snaps.size(); i++) {
1216 cout << "snap: " << snaps[i].name << std::endl;
1217 }
1218
1219 va_start(ap, num_expected);
1220 for (i = num_expected; i > 0; i--) {
1221 char *expected = va_arg(ap, char *);
1222 uint64_t expected_size = va_arg(ap, uint64_t);
1223 int found = 0;
1224 for (j = 0; j < snaps.size(); j++) {
1225 if (snaps[j].name == "")
1226 continue;
1227 if (strcmp(snaps[j].name.c_str(), expected) == 0) {
1228 cout << "found " << snaps[j].name << " with size " << snaps[j].size
1229 << std::endl;
1230 EXPECT_EQ(expected_size, snaps[j].size);
1231 snaps[j].name = "";
1232 found = 1;
1233 break;
1234 }
1235 }
1236 EXPECT_TRUE(found);
1237 }
1238 va_end(ap);
1239
1240 for (i = 0; i < snaps.size(); i++) {
1241 EXPECT_EQ("", snaps[i].name);
1242 }
1243
1244 return snaps.size();
1245 }
1246
1247 TEST_F(TestLibRBD, TestCreateLsDeleteSnapPP)
1248 {
1249 librados::IoCtx ioctx;
1250 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1251
1252 {
1253 librbd::RBD rbd;
1254 librbd::Image image;
1255 int order = 0;
1256 std::string name = get_temp_image_name();
1257 uint64_t size = 2 << 20;
1258 uint64_t size2 = 4 << 20;
1259
1260 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1261 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1262
1263 bool exists;
1264 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1265 ASSERT_FALSE(exists);
1266 ASSERT_EQ(0, image.snap_create("snap1"));
1267 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1268 ASSERT_TRUE(exists);
1269 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1270 ASSERT_EQ(0, image.resize(size2));
1271 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1272 ASSERT_FALSE(exists);
1273 ASSERT_EQ(0, image.snap_create("snap2"));
1274 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1275 ASSERT_TRUE(exists);
1276 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1277 ASSERT_EQ(0, image.snap_remove("snap1"));
1278 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1279 ASSERT_FALSE(exists);
1280 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2));
1281 ASSERT_EQ(0, image.snap_remove("snap2"));
1282 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1283 ASSERT_FALSE(exists);
1284 ASSERT_EQ(0, test_ls_snaps(image, 0));
1285 }
1286
1287 ioctx.close();
1288 }
1289
1290 TEST_F(TestLibRBD, TestCreateLsRenameSnapPP)
1291 {
1292 librados::IoCtx ioctx;
1293 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
1294
1295 {
1296 librbd::RBD rbd;
1297 librbd::Image image;
1298 int order = 0;
1299 std::string name = get_temp_image_name();
1300 uint64_t size = 2 << 20;
1301 uint64_t size2 = 4 << 20;
1302
1303 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
1304 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
1305
1306 bool exists;
1307 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1308 ASSERT_FALSE(exists);
1309 ASSERT_EQ(0, image.snap_create("snap1"));
1310 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1311 ASSERT_TRUE(exists);
1312 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size));
1313 ASSERT_EQ(0, image.resize(size2));
1314 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1315 ASSERT_FALSE(exists);
1316 ASSERT_EQ(0, image.snap_create("snap2"));
1317 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1318 ASSERT_TRUE(exists);
1319 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2));
1320 ASSERT_EQ(0, image.snap_rename("snap1","snap1-rename"));
1321 ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1-rename", size, "snap2", size2));
1322 ASSERT_EQ(0, image.snap_exists2("snap1", &exists));
1323 ASSERT_FALSE(exists);
1324 ASSERT_EQ(0, image.snap_exists2("snap1-rename", &exists));
1325 ASSERT_TRUE(exists);
1326 ASSERT_EQ(0, image.snap_remove("snap1-rename"));
1327 ASSERT_EQ(0, image.snap_rename("snap2","snap2-rename"));
1328 ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2-rename", size2));
1329 ASSERT_EQ(0, image.snap_exists2("snap2", &exists));
1330 ASSERT_FALSE(exists);
1331 ASSERT_EQ(0, image.snap_exists2("snap2-rename", &exists));
1332 ASSERT_TRUE(exists);
1333 ASSERT_EQ(0, image.snap_remove("snap2-rename"));
1334 ASSERT_EQ(0, test_ls_snaps(image, 0));
1335 }
1336
1337 ioctx.close();
1338 }
1339
1340 void simple_write_cb(rbd_completion_t cb, void *arg)
1341 {
1342 printf("write completion cb called!\n");
1343 }
1344
1345 void simple_read_cb(rbd_completion_t cb, void *arg)
1346 {
1347 printf("read completion cb called!\n");
1348 }
1349
1350 void aio_write_test_data_and_poll(rbd_image_t image, int fd, const char *test_data,
1351 uint64_t off, size_t len, uint32_t iohint, bool *passed)
1352 {
1353 rbd_completion_t comp;
1354 uint64_t data = 0x123;
1355 rbd_aio_create_completion((void*)&data, (rbd_callback_t) simple_write_cb, &comp);
1356 printf("created completion\n");
1357 printf("started write\n");
1358 if (iohint)
1359 rbd_aio_write2(image, off, len, test_data, comp, iohint);
1360 else
1361 rbd_aio_write(image, off, len, test_data, comp);
1362
1363 struct pollfd pfd;
1364 pfd.fd = fd;
1365 pfd.events = POLLIN;
1366
1367 ASSERT_EQ(1, poll(&pfd, 1, -1));
1368 ASSERT_TRUE(pfd.revents & POLLIN);
1369
1370 rbd_completion_t comps[1];
1371 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
1372 uint64_t count;
1373 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
1374 read(fd, &count, sizeof(count)));
1375 int r = rbd_aio_get_return_value(comps[0]);
1376 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
1377 ASSERT_TRUE(*(uint64_t*)rbd_aio_get_arg(comps[0]) == data);
1378 printf("return value is: %d\n", r);
1379 ASSERT_EQ(0, r);
1380 printf("finished write\n");
1381 rbd_aio_release(comps[0]);
1382 *passed = true;
1383 }
1384
1385 void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1386 {
1387 rbd_completion_t comp;
1388 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1389 printf("created completion\n");
1390 if (iohint)
1391 rbd_aio_write2(image, off, len, test_data, comp, iohint);
1392 else
1393 rbd_aio_write(image, off, len, test_data, comp);
1394 printf("started write\n");
1395 rbd_aio_wait_for_complete(comp);
1396 int r = rbd_aio_get_return_value(comp);
1397 printf("return value is: %d\n", r);
1398 ASSERT_EQ(0, r);
1399 printf("finished write\n");
1400 rbd_aio_release(comp);
1401 *passed = true;
1402 }
1403
1404 void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1405 {
1406 ssize_t written;
1407 if (iohint)
1408 written = rbd_write2(image, off, len, test_data, iohint);
1409 else
1410 written = rbd_write(image, off, len, test_data);
1411 printf("wrote: %d\n", (int) written);
1412 ASSERT_EQ(len, static_cast<size_t>(written));
1413 *passed = true;
1414 }
1415
1416 void aio_discard_test_data(rbd_image_t image, uint64_t off, uint64_t len, bool *passed)
1417 {
1418 rbd_completion_t comp;
1419 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1420 rbd_aio_discard(image, off, len, comp);
1421 rbd_aio_wait_for_complete(comp);
1422 int r = rbd_aio_get_return_value(comp);
1423 ASSERT_EQ(0, r);
1424 printf("aio discard: %d~%d = %d\n", (int)off, (int)len, (int)r);
1425 rbd_aio_release(comp);
1426 *passed = true;
1427 }
1428
1429 void discard_test_data(rbd_image_t image, uint64_t off, size_t len, bool *passed)
1430 {
1431 ssize_t written;
1432 written = rbd_discard(image, off, len);
1433 printf("discard: %d~%d = %d\n", (int)off, (int)len, (int)written);
1434 ASSERT_EQ(len, static_cast<size_t>(written));
1435 *passed = true;
1436 }
1437
1438 void aio_read_test_data_and_poll(rbd_image_t image, int fd, const char *expected,
1439 uint64_t off, size_t len, uint32_t iohint, bool *passed)
1440 {
1441 rbd_completion_t comp;
1442 char *result = (char *)malloc(len + 1);
1443
1444 ASSERT_NE(static_cast<char *>(NULL), result);
1445 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1446 printf("created completion\n");
1447 printf("started read\n");
1448 if (iohint)
1449 rbd_aio_read2(image, off, len, result, comp, iohint);
1450 else
1451 rbd_aio_read(image, off, len, result, comp);
1452
1453 struct pollfd pfd;
1454 pfd.fd = fd;
1455 pfd.events = POLLIN;
1456
1457 ASSERT_EQ(1, poll(&pfd, 1, -1));
1458 ASSERT_TRUE(pfd.revents & POLLIN);
1459
1460 rbd_completion_t comps[1];
1461 ASSERT_EQ(1, rbd_poll_io_events(image, comps, 1));
1462 uint64_t count;
1463 ASSERT_EQ(static_cast<ssize_t>(sizeof(count)),
1464 read(fd, &count, sizeof(count)));
1465
1466 int r = rbd_aio_get_return_value(comps[0]);
1467 ASSERT_TRUE(rbd_aio_is_complete(comps[0]));
1468 printf("return value is: %d\n", r);
1469 ASSERT_EQ(len, static_cast<size_t>(r));
1470 rbd_aio_release(comps[0]);
1471 if (memcmp(result, expected, len)) {
1472 printf("read: %s\nexpected: %s\n", result, expected);
1473 ASSERT_EQ(0, memcmp(result, expected, len));
1474 }
1475 free(result);
1476 *passed = true;
1477 }
1478
1479 void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1480 {
1481 rbd_completion_t comp;
1482 char *result = (char *)malloc(len + 1);
1483
1484 ASSERT_NE(static_cast<char *>(NULL), result);
1485 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1486 printf("created completion\n");
1487 if (iohint)
1488 rbd_aio_read2(image, off, len, result, comp, iohint);
1489 else
1490 rbd_aio_read(image, off, len, result, comp);
1491 printf("started read\n");
1492 rbd_aio_wait_for_complete(comp);
1493 int r = rbd_aio_get_return_value(comp);
1494 printf("return value is: %d\n", r);
1495 ASSERT_EQ(len, static_cast<size_t>(r));
1496 rbd_aio_release(comp);
1497 if (memcmp(result, expected, len)) {
1498 printf("read: %s\nexpected: %s\n", result, expected);
1499 ASSERT_EQ(0, memcmp(result, expected, len));
1500 }
1501 free(result);
1502 *passed = true;
1503 }
1504
1505 void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len, uint32_t iohint, bool *passed)
1506 {
1507 ssize_t read;
1508 char *result = (char *)malloc(len + 1);
1509
1510 ASSERT_NE(static_cast<char *>(NULL), result);
1511 if (iohint)
1512 read = rbd_read2(image, off, len, result, iohint);
1513 else
1514 read = rbd_read(image, off, len, result);
1515 printf("read: %d\n", (int) read);
1516 ASSERT_EQ(len, static_cast<size_t>(read));
1517 result[len] = '\0';
1518 if (memcmp(result, expected, len)) {
1519 printf("read: %s\nexpected: %s\n", result, expected);
1520 ASSERT_EQ(0, memcmp(result, expected, len));
1521 }
1522 free(result);
1523 *passed = true;
1524 }
1525
1526 void aio_writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
1527 uint64_t data_len, uint32_t iohint, bool *passed)
1528 {
1529 rbd_completion_t comp;
1530 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1531 printf("created completion\n");
1532 int r;
1533 r = rbd_aio_writesame(image, off, len, test_data, data_len, comp, iohint);
1534 printf("started writesame\n");
1535 if (len % data_len) {
1536 ASSERT_EQ(-EINVAL, r);
1537 printf("expected fail, finished writesame\n");
1538 rbd_aio_release(comp);
1539 *passed = true;
1540 return;
1541 }
1542
1543 rbd_aio_wait_for_complete(comp);
1544 r = rbd_aio_get_return_value(comp);
1545 printf("return value is: %d\n", r);
1546 ASSERT_EQ(0, r);
1547 printf("finished writesame\n");
1548 rbd_aio_release(comp);
1549
1550 //verify data
1551 printf("to verify the data\n");
1552 ssize_t read;
1553 char *result = (char *)malloc(data_len+ 1);
1554 ASSERT_NE(static_cast<char *>(NULL), result);
1555 uint64_t left = len;
1556 while (left > 0) {
1557 read = rbd_read(image, off, data_len, result);
1558 ASSERT_EQ(data_len, static_cast<size_t>(read));
1559 result[data_len] = '\0';
1560 if (memcmp(result, test_data, data_len)) {
1561 printf("read: %d ~ %d\n", (int) off, (int) read);
1562 printf("read: %s\nexpected: %s\n", result, test_data);
1563 ASSERT_EQ(0, memcmp(result, test_data, data_len));
1564 }
1565 off += data_len;
1566 left -= data_len;
1567 }
1568 ASSERT_EQ(0U, left);
1569 free(result);
1570 printf("verified\n");
1571
1572 *passed = true;
1573 }
1574
1575 void writesame_test_data(rbd_image_t image, const char *test_data, uint64_t off, uint64_t len,
1576 uint64_t data_len, uint32_t iohint, bool *passed)
1577 {
1578 ssize_t written;
1579 written = rbd_writesame(image, off, len, test_data, data_len, iohint);
1580 if (len % data_len) {
1581 ASSERT_EQ(-EINVAL, written);
1582 printf("expected fail, finished writesame\n");
1583 *passed = true;
1584 return;
1585 }
1586 ASSERT_EQ(len, static_cast<size_t>(written));
1587 printf("wrote: %d\n", (int) written);
1588
1589 //verify data
1590 printf("to verify the data\n");
1591 ssize_t read;
1592 char *result = (char *)malloc(data_len+ 1);
1593 ASSERT_NE(static_cast<char *>(NULL), result);
1594 uint64_t left = len;
1595 while (left > 0) {
1596 read = rbd_read(image, off, data_len, result);
1597 ASSERT_EQ(data_len, static_cast<size_t>(read));
1598 result[data_len] = '\0';
1599 if (memcmp(result, test_data, data_len)) {
1600 printf("read: %d ~ %d\n", (int) off, (int) read);
1601 printf("read: %s\nexpected: %s\n", result, test_data);
1602 ASSERT_EQ(0, memcmp(result, test_data, data_len));
1603 }
1604 off += data_len;
1605 left -= data_len;
1606 }
1607 ASSERT_EQ(0U, left);
1608 free(result);
1609 printf("verified\n");
1610
1611 *passed = true;
1612 }
1613
1614 void aio_compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
1615 const char *test_data, uint64_t off,
1616 size_t len, uint32_t iohint, bool *passed)
1617 {
1618 rbd_completion_t comp;
1619 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
1620 printf("created completion\n");
1621
1622 uint64_t mismatch_offset;
1623 rbd_aio_compare_and_write(image, off, len, cmp_data, test_data, comp, &mismatch_offset, iohint);
1624 printf("started aio compare and write\n");
1625 rbd_aio_wait_for_complete(comp);
1626 int r = rbd_aio_get_return_value(comp);
1627 printf("return value is: %d\n", r);
1628 ASSERT_EQ(0, r);
1629 printf("finished aio compare and write\n");
1630 rbd_aio_release(comp);
1631 *passed = true;
1632 }
1633
1634 void compare_and_write_test_data(rbd_image_t image, const char *cmp_data,
1635 const char *test_data, uint64_t off, size_t len,
1636 uint64_t *mismatch_off, uint32_t iohint, bool *passed)
1637 {
1638 printf("start compare and write\n");
1639 ssize_t written;
1640 written = rbd_compare_and_write(image, off, len, cmp_data, test_data, mismatch_off, iohint);
1641 printf("compare and wrote: %d\n", (int) written);
1642 ASSERT_EQ(len, static_cast<size_t>(written));
1643 *passed = true;
1644 }
1645
1646
1647 TEST_F(TestLibRBD, TestIO)
1648 {
1649 rados_ioctx_t ioctx;
1650 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1651
1652 bool skip_discard = is_skip_partial_discard_enabled();
1653
1654 rbd_image_t image;
1655 int order = 0;
1656 std::string name = get_temp_image_name();
1657 uint64_t size = 2 << 20;
1658
1659 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1660 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1661
1662 char test_data[TEST_IO_SIZE + 1];
1663 char zero_data[TEST_IO_SIZE + 1];
1664 char mismatch_data[TEST_IO_SIZE + 1];
1665 int i;
1666 uint64_t mismatch_offset;
1667
1668 for (i = 0; i < TEST_IO_SIZE; ++i) {
1669 test_data[i] = (char) (rand() % (126 - 33) + 33);
1670 }
1671 test_data[TEST_IO_SIZE] = '\0';
1672 memset(zero_data, 0, sizeof(zero_data));
1673 memset(mismatch_data, 9, sizeof(mismatch_data));
1674
1675 for (i = 0; i < 5; ++i)
1676 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1677
1678 for (i = 5; i < 10; ++i)
1679 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1680
1681 for (i = 0; i < 5; ++i)
1682 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, 0);
1683
1684 for (i = 5; i < 10; ++i)
1685 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1686
1687 for (i = 0; i < 5; ++i)
1688 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1689
1690 for (i = 5; i < 10; ++i)
1691 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1692
1693 // discard 2nd, 4th sections.
1694 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
1695 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
1696
1697 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
1698 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1699 TEST_IO_SIZE, TEST_IO_SIZE, 0);
1700 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
1701 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1702 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
1703 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
1704
1705 for (i = 0; i < 15; ++i) {
1706 if (i % 3 == 2) {
1707 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1708 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1709 } else if (i % 3 == 1) {
1710 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1711 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1712 } else {
1713 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1714 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1715 }
1716 }
1717 for (i = 0; i < 15; ++i) {
1718 if (i % 3 == 2) {
1719 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1720 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
1721 } else if (i % 3 == 1) {
1722 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1723 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1724 } else {
1725 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1726 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
1727 }
1728 }
1729
1730 rbd_image_info_t info;
1731 rbd_completion_t comp;
1732 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1733 // can't read or write starting past end
1734 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
1735 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
1736 // reading through end returns amount up to end
1737 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
1738 // writing through end returns amount up to end
1739 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
1740
1741 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1742 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
1743 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1744 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1745 rbd_aio_release(comp);
1746
1747 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1748 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
1749 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1750 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1751 rbd_aio_release(comp);
1752
1753 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1754 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data, &mismatch_offset, 0));
1755 ASSERT_EQ(0U, mismatch_offset);
1756 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1757 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data, comp, &mismatch_offset, 0));
1758 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1759 ASSERT_EQ(0U, mismatch_offset);
1760 rbd_aio_release(comp);
1761
1762 ASSERT_PASSED(validate_object_map, image);
1763 ASSERT_EQ(0, rbd_close(image));
1764
1765 rados_ioctx_destroy(ioctx);
1766 }
1767
1768 TEST_F(TestLibRBD, TestIOWithIOHint)
1769 {
1770 rados_ioctx_t ioctx;
1771 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1772
1773 bool skip_discard = is_skip_partial_discard_enabled();
1774
1775 rbd_image_t image;
1776 int order = 0;
1777 std::string name = get_temp_image_name();
1778 uint64_t size = 2 << 20;
1779
1780 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
1781 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1782
1783 char test_data[TEST_IO_SIZE + 1];
1784 char zero_data[TEST_IO_SIZE + 1];
1785 char mismatch_data[TEST_IO_SIZE + 1];
1786 int i;
1787 uint64_t mismatch_offset;
1788
1789 for (i = 0; i < TEST_IO_SIZE; ++i) {
1790 test_data[i] = (char) (rand() % (126 - 33) + 33);
1791 }
1792 test_data[TEST_IO_SIZE] = '\0';
1793 memset(zero_data, 0, sizeof(zero_data));
1794 memset(mismatch_data, 9, sizeof(mismatch_data));
1795
1796 for (i = 0; i < 5; ++i)
1797 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i,
1798 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1799
1800 for (i = 5; i < 10; ++i)
1801 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i,
1802 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1803
1804 for (i = 0; i < 5; ++i)
1805 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data,
1806 TEST_IO_SIZE * i, TEST_IO_SIZE, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1807
1808 for (i = 5; i < 10; ++i)
1809 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data,
1810 TEST_IO_SIZE * i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1811
1812 for (i = 0; i < 5; ++i)
1813 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE,
1814 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1815
1816 for (i = 5; i < 10; ++i)
1817 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i,
1818 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1819
1820 // discard 2nd, 4th sections.
1821 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
1822 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
1823
1824 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE,
1825 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1826 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1827 TEST_IO_SIZE, TEST_IO_SIZE,
1828 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1829 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE,
1830 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1831 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1832 TEST_IO_SIZE*3, TEST_IO_SIZE,
1833 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
1834 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
1835
1836 for (i = 0; i < 15; ++i) {
1837 if (i % 3 == 2) {
1838 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1839 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1840 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1841 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1842 } else if (i % 3 == 1) {
1843 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1844 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1845 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1846 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1847 } else {
1848 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1849 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1850 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1851 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1852 }
1853 }
1854 for (i = 0; i < 15; ++i) {
1855 if (i % 3 == 2) {
1856 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1857 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1858 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i,
1859 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1860 } else if (i % 3 == 1) {
1861 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1862 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1863 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32,
1864 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1865 } else {
1866 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1867 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1868 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32,
1869 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
1870 }
1871 }
1872
1873 rbd_image_info_t info;
1874 rbd_completion_t comp;
1875 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1876 // can't read or write starting past end
1877 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
1878 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
1879 // reading through end returns amount up to end
1880 ASSERT_EQ(10, rbd_read2(image, info.size - 10, 100, test_data,
1881 LIBRADOS_OP_FLAG_FADVISE_NOCACHE));
1882 // writing through end returns amount up to end
1883 ASSERT_EQ(10, rbd_write2(image, info.size - 10, 100, test_data,
1884 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1885
1886 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1887 ASSERT_EQ(0, rbd_aio_read2(image, info.size, 1, test_data, comp,
1888 LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1889 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1890 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1891 rbd_aio_release(comp);
1892
1893 ASSERT_PASSED(write_test_data, image, zero_data, 0, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
1894 ASSERT_EQ(-EILSEQ, rbd_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
1895 &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1896 ASSERT_EQ(0U, mismatch_offset);
1897 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1898 ASSERT_EQ(0, rbd_aio_compare_and_write(image, 0, TEST_IO_SIZE, mismatch_data, mismatch_data,
1899 comp, &mismatch_offset, LIBRADOS_OP_FLAG_FADVISE_DONTNEED));
1900 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1901 ASSERT_EQ(0U, mismatch_offset);
1902 rbd_aio_release(comp);
1903
1904 ASSERT_PASSED(validate_object_map, image);
1905 ASSERT_EQ(0, rbd_close(image));
1906
1907 rados_ioctx_destroy(ioctx);
1908 }
1909
1910 TEST_F(TestLibRBD, TestDataPoolIO)
1911 {
1912 REQUIRE_FORMAT_V2();
1913
1914 rados_ioctx_t ioctx;
1915 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
1916
1917 std::string data_pool_name = create_pool(true);
1918
1919 bool skip_discard = is_skip_partial_discard_enabled();
1920
1921 rbd_image_t image;
1922 std::string name = get_temp_image_name();
1923 uint64_t size = 2 << 20;
1924
1925 bool old_format;
1926 uint64_t features;
1927 ASSERT_EQ(0, get_features(&old_format, &features));
1928 ASSERT_FALSE(old_format);
1929
1930 rbd_image_options_t image_options;
1931 rbd_image_options_create(&image_options);
1932 BOOST_SCOPE_EXIT( (&image_options) ) {
1933 rbd_image_options_destroy(image_options);
1934 } BOOST_SCOPE_EXIT_END;
1935
1936 ASSERT_EQ(0, rbd_image_options_set_uint64(image_options,
1937 RBD_IMAGE_OPTION_FEATURES,
1938 features));
1939 ASSERT_EQ(0, rbd_image_options_set_string(image_options,
1940 RBD_IMAGE_OPTION_DATA_POOL,
1941 data_pool_name.c_str()));
1942
1943 ASSERT_EQ(0, rbd_create4(ioctx, name.c_str(), size, image_options));
1944 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
1945 ASSERT_NE(-1, rbd_get_data_pool_id(image));
1946
1947 char test_data[TEST_IO_SIZE + 1];
1948 char zero_data[TEST_IO_SIZE + 1];
1949 int i;
1950
1951 for (i = 0; i < TEST_IO_SIZE; ++i) {
1952 test_data[i] = (char) (rand() % (126 - 33) + 33);
1953 }
1954 test_data[TEST_IO_SIZE] = '\0';
1955 memset(zero_data, 0, sizeof(zero_data));
1956
1957 for (i = 0; i < 5; ++i)
1958 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1959
1960 for (i = 5; i < 10; ++i)
1961 ASSERT_PASSED(aio_write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1962
1963 for (i = 0; i < 5; ++i)
1964 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1965
1966 for (i = 5; i < 10; ++i)
1967 ASSERT_PASSED(aio_read_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
1968
1969 // discard 2nd, 4th sections.
1970 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
1971 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
1972
1973 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
1974 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1975 TEST_IO_SIZE, TEST_IO_SIZE, 0);
1976 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
1977 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
1978 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
1979 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
1980
1981 rbd_image_info_t info;
1982 rbd_completion_t comp;
1983 ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
1984 // can't read or write starting past end
1985 ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
1986 ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
1987 // reading through end returns amount up to end
1988 ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
1989 // writing through end returns amount up to end
1990 ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
1991
1992 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1993 ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp));
1994 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
1995 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
1996 rbd_aio_release(comp);
1997
1998 rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
1999 ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp));
2000 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2001 ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp));
2002 rbd_aio_release(comp);
2003
2004 ASSERT_PASSED(validate_object_map, image);
2005 ASSERT_EQ(0, rbd_close(image));
2006
2007 rados_ioctx_destroy(ioctx);
2008 }
2009
2010 TEST_F(TestLibRBD, TestScatterGatherIO)
2011 {
2012 rados_ioctx_t ioctx;
2013 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2014
2015 rbd_image_t image;
2016 int order = 0;
2017 std::string name = get_temp_image_name();
2018 uint64_t size = 20 << 20;
2019
2020 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2021 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2022
2023 std::string write_buffer("This is a test");
2024 struct iovec bad_iovs[] = {
2025 {.iov_base = NULL, .iov_len = static_cast<size_t>(-1)}
2026 };
2027 struct iovec write_iovs[] = {
2028 {.iov_base = &write_buffer[0], .iov_len = 5},
2029 {.iov_base = &write_buffer[5], .iov_len = 3},
2030 {.iov_base = &write_buffer[8], .iov_len = 2},
2031 {.iov_base = &write_buffer[10], .iov_len = 4}
2032 };
2033
2034 rbd_completion_t comp;
2035 rbd_aio_create_completion(NULL, NULL, &comp);
2036 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, write_iovs, 0, 0, comp));
2037 ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 1, 0, comp));
2038 ASSERT_EQ(0, rbd_aio_writev(image, write_iovs,
2039 sizeof(write_iovs) / sizeof(struct iovec),
2040 1<<order, comp));
2041 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2042 ASSERT_EQ(0, rbd_aio_get_return_value(comp));
2043 rbd_aio_release(comp);
2044
2045 std::string read_buffer(write_buffer.size(), '1');
2046 struct iovec read_iovs[] = {
2047 {.iov_base = &read_buffer[0], .iov_len = 4},
2048 {.iov_base = &read_buffer[8], .iov_len = 4},
2049 {.iov_base = &read_buffer[12], .iov_len = 2}
2050 };
2051
2052 rbd_aio_create_completion(NULL, NULL, &comp);
2053 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, read_iovs, 0, 0, comp));
2054 ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 1, 0, comp));
2055 ASSERT_EQ(0, rbd_aio_readv(image, read_iovs,
2056 sizeof(read_iovs) / sizeof(struct iovec),
2057 1<<order, comp));
2058 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2059 ASSERT_EQ(10, rbd_aio_get_return_value(comp));
2060 rbd_aio_release(comp);
2061 ASSERT_EQ("This1111 is a ", read_buffer);
2062
2063 std::string linear_buffer(write_buffer.size(), '1');
2064 struct iovec linear_iovs[] = {
2065 {.iov_base = &linear_buffer[4], .iov_len = 4}
2066 };
2067 rbd_aio_create_completion(NULL, NULL, &comp);
2068 ASSERT_EQ(0, rbd_aio_readv(image, linear_iovs,
2069 sizeof(linear_iovs) / sizeof(struct iovec),
2070 1<<order, comp));
2071 ASSERT_EQ(0, rbd_aio_wait_for_complete(comp));
2072 ASSERT_EQ(4, rbd_aio_get_return_value(comp));
2073 rbd_aio_release(comp);
2074 ASSERT_EQ("1111This111111", linear_buffer);
2075
2076 ASSERT_PASSED(validate_object_map, image);
2077 ASSERT_EQ(0, rbd_close(image));
2078
2079 rados_ioctx_destroy(ioctx);
2080 }
2081
2082 TEST_F(TestLibRBD, TestEmptyDiscard)
2083 {
2084 rados_ioctx_t ioctx;
2085 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2086
2087 rbd_image_t image;
2088 int order = 0;
2089 std::string name = get_temp_image_name();
2090 uint64_t size = 20 << 20;
2091
2092 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
2093 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2094
2095 ASSERT_PASSED(aio_discard_test_data, image, 0, 1*1024*1024);
2096 ASSERT_PASSED(aio_discard_test_data, image, 0, 4*1024*1024);
2097 ASSERT_PASSED(aio_discard_test_data, image, 3*1024*1024, 1*1024*1024);
2098
2099 ASSERT_PASSED(validate_object_map, image);
2100 ASSERT_EQ(0, rbd_close(image));
2101
2102 rados_ioctx_destroy(ioctx);
2103 }
2104
2105
2106 void simple_write_cb_pp(librbd::completion_t cb, void *arg)
2107 {
2108 cout << "write completion cb called!" << std::endl;
2109 }
2110
2111 void simple_read_cb_pp(librbd::completion_t cb, void *arg)
2112 {
2113 cout << "read completion cb called!" << std::endl;
2114 }
2115
2116 void aio_write_test_data(librbd::Image& image, const char *test_data,
2117 off_t off, uint32_t iohint, bool *passed)
2118 {
2119 ceph::bufferlist bl;
2120 bl.append(test_data, strlen(test_data));
2121 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2122 printf("created completion\n");
2123 if (iohint)
2124 image.aio_write2(off, strlen(test_data), bl, comp, iohint);
2125 else
2126 image.aio_write(off, strlen(test_data), bl, comp);
2127 printf("started write\n");
2128 comp->wait_for_complete();
2129 int r = comp->get_return_value();
2130 printf("return value is: %d\n", r);
2131 ASSERT_EQ(0, r);
2132 printf("finished write\n");
2133 comp->release();
2134 *passed = true;
2135 }
2136
2137 void aio_discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2138 {
2139 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2140 image.aio_discard(off, len, comp);
2141 comp->wait_for_complete();
2142 int r = comp->get_return_value();
2143 ASSERT_EQ(0, r);
2144 comp->release();
2145 *passed = true;
2146 }
2147
2148 void write_test_data(librbd::Image& image, const char *test_data, off_t off, uint32_t iohint, bool *passed)
2149 {
2150 size_t written;
2151 size_t len = strlen(test_data);
2152 ceph::bufferlist bl;
2153 bl.append(test_data, len);
2154 if (iohint)
2155 written = image.write2(off, len, bl, iohint);
2156 else
2157 written = image.write(off, len, bl);
2158 printf("wrote: %u\n", (unsigned int) written);
2159 ASSERT_EQ(bl.length(), written);
2160 *passed = true;
2161 }
2162
2163 void discard_test_data(librbd::Image& image, off_t off, size_t len, bool *passed)
2164 {
2165 size_t written;
2166 written = image.discard(off, len);
2167 printf("discard: %u~%u\n", (unsigned)off, (unsigned)len);
2168 ASSERT_EQ(len, written);
2169 *passed = true;
2170 }
2171
2172 void aio_read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2173 {
2174 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_read_cb_pp);
2175 ceph::bufferlist bl;
2176 printf("created completion\n");
2177 if (iohint)
2178 image.aio_read2(off, expected_len, bl, comp, iohint);
2179 else
2180 image.aio_read(off, expected_len, bl, comp);
2181 printf("started read\n");
2182 comp->wait_for_complete();
2183 int r = comp->get_return_value();
2184 printf("return value is: %d\n", r);
2185 ASSERT_EQ(TEST_IO_SIZE, r);
2186 ASSERT_EQ(0, memcmp(expected, bl.c_str(), TEST_IO_SIZE));
2187 printf("finished read\n");
2188 comp->release();
2189 *passed = true;
2190 }
2191
2192 void read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len, uint32_t iohint, bool *passed)
2193 {
2194 int read;
2195 size_t len = expected_len;
2196 ceph::bufferlist bl;
2197 if (iohint)
2198 read = image.read2(off, len, bl, iohint);
2199 else
2200 read = image.read(off, len, bl);
2201 ASSERT_TRUE(read >= 0);
2202 std::string bl_str(bl.c_str(), read);
2203
2204 printf("read: %u\n", (unsigned int) read);
2205 int result = memcmp(bl_str.c_str(), expected, expected_len);
2206 if (result != 0) {
2207 printf("read: %s\nexpected: %s\n", bl_str.c_str(), expected);
2208 ASSERT_EQ(0, result);
2209 }
2210 *passed = true;
2211 }
2212
2213 void aio_writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2214 size_t len, size_t data_len, uint32_t iohint, bool *passed)
2215 {
2216 ceph::bufferlist bl;
2217 bl.append(test_data, data_len);
2218 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2219 printf("created completion\n");
2220 int r;
2221 r = image.aio_writesame(off, len, bl, comp, iohint);
2222 printf("started writesame\n");
2223 if (len % data_len) {
2224 ASSERT_EQ(-EINVAL, r);
2225 printf("expected fail, finished writesame\n");
2226 comp->release();
2227 *passed = true;
2228 return;
2229 }
2230
2231 comp->wait_for_complete();
2232 r = comp->get_return_value();
2233 printf("return value is: %d\n", r);
2234 ASSERT_EQ(0, r);
2235 printf("finished writesame\n");
2236 comp->release();
2237
2238 //verify data
2239 printf("to verify the data\n");
2240 int read;
2241 uint64_t left = len;
2242 while (left > 0) {
2243 ceph::bufferlist bl;
2244 read = image.read(off, data_len, bl);
2245 ASSERT_EQ(data_len, static_cast<size_t>(read));
2246 std::string bl_str(bl.c_str(), read);
2247 int result = memcmp(bl_str.c_str(), test_data, data_len);
2248 if (result !=0 ) {
2249 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2250 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2251 ASSERT_EQ(0, result);
2252 }
2253 off += data_len;
2254 left -= data_len;
2255 }
2256 ASSERT_EQ(0U, left);
2257 printf("verified\n");
2258
2259 *passed = true;
2260 }
2261
2262 void writesame_test_data(librbd::Image& image, const char *test_data, off_t off,
2263 ssize_t len, size_t data_len, uint32_t iohint,
2264 bool *passed)
2265 {
2266 ssize_t written;
2267 ceph::bufferlist bl;
2268 bl.append(test_data, data_len);
2269 written = image.writesame(off, len, bl, iohint);
2270 if (len % data_len) {
2271 ASSERT_EQ(-EINVAL, written);
2272 printf("expected fail, finished writesame\n");
2273 *passed = true;
2274 return;
2275 }
2276 ASSERT_EQ(len, written);
2277 printf("wrote: %u\n", (unsigned int) written);
2278 *passed = true;
2279
2280 //verify data
2281 printf("to verify the data\n");
2282 int read;
2283 uint64_t left = len;
2284 while (left > 0) {
2285 ceph::bufferlist bl;
2286 read = image.read(off, data_len, bl);
2287 ASSERT_EQ(data_len, static_cast<size_t>(read));
2288 std::string bl_str(bl.c_str(), read);
2289 int result = memcmp(bl_str.c_str(), test_data, data_len);
2290 if (result !=0 ) {
2291 printf("read: %u ~ %u\n", (unsigned int) off, (unsigned int) read);
2292 printf("read: %s\nexpected: %s\n", bl_str.c_str(), test_data);
2293 ASSERT_EQ(0, result);
2294 }
2295 off += data_len;
2296 left -= data_len;
2297 }
2298 ASSERT_EQ(0U, left);
2299 printf("verified\n");
2300
2301 *passed = true;
2302 }
2303
2304 void aio_compare_and_write_test_data(librbd::Image& image, const char *cmp_data,
2305 const char *test_data, off_t off, ssize_t len,
2306 uint32_t iohint, bool *passed)
2307 {
2308 ceph::bufferlist cmp_bl;
2309 cmp_bl.append(cmp_data, strlen(cmp_data));
2310 ceph::bufferlist test_bl;
2311 test_bl.append(test_data, strlen(test_data));
2312 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp);
2313 printf("created completion\n");
2314
2315 uint64_t mismatch_offset;
2316 image.aio_compare_and_write(off, len, cmp_bl, test_bl, comp, &mismatch_offset, iohint);
2317 printf("started aio compare and write\n");
2318 comp->wait_for_complete();
2319 int r = comp->get_return_value();
2320 printf("return value is: %d\n", r);
2321 ASSERT_EQ(0, r);
2322 printf("finished aio compare and write\n");
2323 comp->release();
2324 *passed = true;
2325 }
2326
2327 void compare_and_write_test_data(librbd::Image& image, const char *cmp_data, const char *test_data,
2328 off_t off, ssize_t len, uint64_t *mismatch_off, uint32_t iohint, bool *passed)
2329 {
2330 size_t written;
2331 ceph::bufferlist cmp_bl;
2332 cmp_bl.append(cmp_data, strlen(cmp_data));
2333 ceph::bufferlist test_bl;
2334 test_bl.append(test_data, strlen(test_data));
2335 printf("start compare and write\n");
2336 written = image.compare_and_write(off, len, cmp_bl, test_bl, mismatch_off, iohint);
2337 printf("compare and wrote: %d\n", (int) written);
2338 ASSERT_EQ(len, static_cast<ssize_t>(written));
2339 *passed = true;
2340 }
2341
2342 TEST_F(TestLibRBD, TestIOPP)
2343 {
2344 librados::IoCtx ioctx;
2345 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2346
2347 bool skip_discard = is_skip_partial_discard_enabled();
2348
2349 {
2350 librbd::RBD rbd;
2351 librbd::Image image;
2352 int order = 0;
2353 std::string name = get_temp_image_name();
2354 uint64_t size = 2 << 20;
2355
2356 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2357 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2358
2359 char test_data[TEST_IO_SIZE + 1];
2360 char zero_data[TEST_IO_SIZE + 1];
2361 int i;
2362 uint64_t mismatch_offset;
2363
2364 for (i = 0; i < TEST_IO_SIZE; ++i) {
2365 test_data[i] = (char) (rand() % (126 - 33) + 33);
2366 }
2367 test_data[TEST_IO_SIZE] = '\0';
2368 memset(zero_data, 0, sizeof(zero_data));
2369
2370 for (i = 0; i < 5; ++i)
2371 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i, 0);
2372
2373 for (i = 5; i < 10; ++i)
2374 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i, 0);
2375
2376 for (i = 0; i < 5; ++i)
2377 ASSERT_PASSED(compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2378 TEST_IO_SIZE, &mismatch_offset, 0);
2379
2380 for (i = 5; i < 10; ++i)
2381 ASSERT_PASSED(aio_compare_and_write_test_data, image, test_data, test_data, TEST_IO_SIZE * i,
2382 TEST_IO_SIZE, 0);
2383
2384 for (i = 0; i < 5; ++i)
2385 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2386
2387 for (i = 5; i < 10; ++i)
2388 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i, TEST_IO_SIZE, 0);
2389
2390 // discard 2nd, 4th sections.
2391 ASSERT_PASSED(discard_test_data, image, TEST_IO_SIZE, TEST_IO_SIZE);
2392 ASSERT_PASSED(aio_discard_test_data, image, TEST_IO_SIZE*3, TEST_IO_SIZE);
2393
2394 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_SIZE, 0);
2395 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2396 TEST_IO_SIZE, TEST_IO_SIZE, 0);
2397 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE, 0);
2398 ASSERT_PASSED(read_test_data, image, skip_discard ? test_data : zero_data,
2399 TEST_IO_SIZE*3, TEST_IO_SIZE, 0);
2400 ASSERT_PASSED(read_test_data, image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE, 0);
2401
2402 for (i = 0; i < 15; ++i) {
2403 if (i % 3 == 2) {
2404 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2405 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2406 } else if (i % 3 == 1) {
2407 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2408 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2409 } else {
2410 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2411 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2412 }
2413 }
2414 for (i = 0; i < 15; ++i) {
2415 if (i % 3 == 2) {
2416 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2417 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, 0);
2418 } else if (i % 3 == 1) {
2419 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2420 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2421 } else {
2422 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2423 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i, TEST_IO_SIZE * i * 32, TEST_IO_SIZE, 0);
2424 }
2425 }
2426
2427 ASSERT_PASSED(validate_object_map, image);
2428 }
2429
2430 ioctx.close();
2431 }
2432
2433 TEST_F(TestLibRBD, TestIOPPWithIOHint)
2434 {
2435 librados::IoCtx ioctx;
2436 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
2437
2438 {
2439 librbd::RBD rbd;
2440 librbd::Image image;
2441 int order = 0;
2442 std::string name = get_temp_image_name();
2443 uint64_t size = 2 << 20;
2444
2445 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
2446 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
2447
2448 char test_data[TEST_IO_SIZE + 1];
2449 char zero_data[TEST_IO_SIZE + 1];
2450 test_data[TEST_IO_SIZE] = '\0';
2451 int i;
2452
2453 for (i = 0; i < TEST_IO_SIZE; ++i) {
2454 test_data[i] = (char) (rand() % (126 - 33) + 33);
2455 }
2456 memset(zero_data, 0, sizeof(zero_data));
2457
2458 for (i = 0; i < 5; ++i)
2459 ASSERT_PASSED(write_test_data, image, test_data, strlen(test_data) * i,
2460 LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2461
2462 for (i = 5; i < 10; ++i)
2463 ASSERT_PASSED(aio_write_test_data, image, test_data, strlen(test_data) * i,
2464 LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2465
2466 ASSERT_PASSED(read_test_data, image, test_data, strlen(test_data),
2467 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_RANDOM);
2468
2469 for (i = 5; i < 10; ++i)
2470 ASSERT_PASSED(aio_read_test_data, image, test_data, strlen(test_data) * i,
2471 TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL|LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2472
2473 for (i = 0; i < 15; ++i) {
2474 if (i % 3 == 2) {
2475 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2476 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2477 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2478 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2479 } else if (i % 3 == 1) {
2480 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2481 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2482 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2483 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2484 } else {
2485 ASSERT_PASSED(writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2486 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2487 ASSERT_PASSED(writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2488 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
2489 }
2490 }
2491 for (i = 0; i < 15; ++i) {
2492 if (i % 3 == 2) {
2493 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2494 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2495 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2496 TEST_IO_SIZE * i * 32 + i, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2497 } else if (i % 3 == 1) {
2498 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE + i,
2499 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2500 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE + i,
2501 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2502 } else {
2503 ASSERT_PASSED(aio_writesame_test_data, image, test_data, TEST_IO_SIZE * i,
2504 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2505 ASSERT_PASSED(aio_writesame_test_data, image, zero_data, TEST_IO_SIZE * i,
2506 TEST_IO_SIZE * i * 32, TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
2507 }
2508 }
2509
2510 ASSERT_PASSED(validate_object_map, image);
2511 }
2512
2513 ioctx.close();
2514 }
2515
2516
2517
2518 TEST_F(TestLibRBD, TestIOToSnapshot)
2519 {
2520 rados_ioctx_t ioctx;
2521 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2522
2523 rbd_image_t image;
2524 int order = 0;
2525 std::string name = get_temp_image_name();
2526 uint64_t isize = 2 << 20;
2527
2528 ASSERT_EQ(0, create_image(ioctx, name.c_str(), isize, &order));
2529 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
2530
2531 int i, r;
2532 rbd_image_t image_at_snap;
2533 char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
2534 char test_data[TEST_IO_TO_SNAP_SIZE + 1];
2535
2536 for (i = 0; i < TEST_IO_TO_SNAP_SIZE; ++i)
2537 test_data[i] = (char) (i + 48);
2538 test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
2539 orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
2540
2541 r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
2542 ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE);
2543
2544 ASSERT_EQ(0, test_ls_snaps(image, 0));
2545 ASSERT_EQ(0, rbd_snap_create(image, "orig"));
2546 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
2547 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2548
2549 printf("write test data!\n");
2550 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2551 ASSERT_EQ(0, rbd_snap_create(image, "written"));
2552 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
2553
2554 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2555
2556 rbd_snap_set(image, "orig");
2557 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2558
2559 rbd_snap_set(image, "written");
2560 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2561
2562 rbd_snap_set(image, "orig");
2563
2564 r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
2565 printf("write to snapshot returned %d\n", r);
2566 ASSERT_LT(r, 0);
2567 cout << strerror(-r) << std::endl;
2568
2569 ASSERT_PASSED(read_test_data, image, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2570 rbd_snap_set(image, "written");
2571 ASSERT_PASSED(read_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2572
2573 r = rbd_snap_rollback(image, "orig");
2574 ASSERT_EQ(r, -EROFS);
2575
2576 r = rbd_snap_set(image, NULL);
2577 ASSERT_EQ(r, 0);
2578 r = rbd_snap_rollback(image, "orig");
2579 ASSERT_EQ(r, 0);
2580
2581 ASSERT_PASSED(write_test_data, image, test_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2582
2583 rbd_flush(image);
2584
2585 printf("opening testimg@orig\n");
2586 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image_at_snap, "orig"));
2587 ASSERT_PASSED(read_test_data, image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE, 0);
2588 r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
2589 printf("write to snapshot returned %d\n", r);
2590 ASSERT_LT(r, 0);
2591 cout << strerror(-r) << std::endl;
2592 ASSERT_EQ(0, rbd_close(image_at_snap));
2593
2594 ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize));
2595 ASSERT_EQ(0, rbd_snap_remove(image, "written"));
2596 ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize));
2597 ASSERT_EQ(0, rbd_snap_remove(image, "orig"));
2598 ASSERT_EQ(0, test_ls_snaps(image, 0));
2599
2600 ASSERT_PASSED(validate_object_map, image);
2601 ASSERT_EQ(0, rbd_close(image));
2602
2603 rados_ioctx_destroy(ioctx);
2604 }
2605
2606 TEST_F(TestLibRBD, TestClone)
2607 {
2608 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2609
2610 rados_ioctx_t ioctx;
2611 rbd_image_info_t pinfo, cinfo;
2612 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2613
2614 bool old_format;
2615 uint64_t features;
2616 rbd_image_t parent, child;
2617 int order = 0;
2618
2619 ASSERT_EQ(0, get_features(&old_format, &features));
2620 ASSERT_FALSE(old_format);
2621
2622 std::string parent_name = get_temp_image_name();
2623 std::string child_name = get_temp_image_name();
2624
2625 // make a parent to clone from
2626 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
2627 false, features));
2628 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
2629 printf("made parent image \"parent\"\n");
2630
2631 char *data = (char *)"testdata";
2632 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
2633
2634 // can't clone a non-snapshot, expect failure
2635 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
2636 child_name.c_str(), features, &order));
2637
2638 // verify that there is no parent info on "parent"
2639 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
2640 printf("parent has no parent info\n");
2641
2642 // create 70 metadatas to verify we can clone all key/value pairs
2643 std::string key;
2644 std::string val;
2645 size_t sum_key_len = 0;
2646 size_t sum_value_len = 0;
2647 for (int i = 1; i <= 70; i++) {
2648 key = "key" + stringify(i);
2649 val = "value" + stringify(i);
2650 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
2651
2652 sum_key_len += (key.size() + 1);
2653 sum_value_len += (val.size() + 1);
2654 }
2655
2656 char keys[1024];
2657 char vals[1024];
2658 size_t keys_len = sizeof(keys);
2659 size_t vals_len = sizeof(vals);
2660
2661 char value[1024];
2662 size_t value_len = sizeof(value);
2663
2664 // create a snapshot, reopen as the parent we're interested in
2665 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2666 printf("made snapshot \"parent@parent_snap\"\n");
2667 ASSERT_EQ(0, rbd_close(parent));
2668 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
2669
2670 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2671 ioctx, child_name.c_str(), features, &order));
2672
2673 // unprotected image should fail unprotect
2674 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
2675 printf("can't unprotect an unprotected snap\n");
2676
2677 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2678 // protecting again should fail
2679 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
2680 printf("can't protect a protected snap\n");
2681
2682 // This clone and open should work
2683 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2684 ioctx, child_name.c_str(), features, &order));
2685 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
2686 printf("made and opened clone \"child\"\n");
2687
2688 // check read
2689 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
2690
2691 // check write
2692 ASSERT_EQ((ssize_t)strlen(data), rbd_write(child, 20, strlen(data), data));
2693 ASSERT_PASSED(read_test_data, child, data, 20, strlen(data), 0);
2694 ASSERT_PASSED(read_test_data, child, data, 0, strlen(data), 0);
2695
2696 // check attributes
2697 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
2698 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2699 EXPECT_EQ(cinfo.size, pinfo.size);
2700 uint64_t overlap;
2701 rbd_get_overlap(child, &overlap);
2702 EXPECT_EQ(overlap, pinfo.size);
2703 EXPECT_EQ(cinfo.obj_size, pinfo.obj_size);
2704 EXPECT_EQ(cinfo.order, pinfo.order);
2705 printf("sizes and overlaps are good between parent and child\n");
2706
2707 // check key/value pairs in child image
2708 ASSERT_EQ(0, rbd_metadata_list(child, "", 70, keys, &keys_len, vals,
2709 &vals_len));
2710 ASSERT_EQ(sum_key_len, keys_len);
2711 ASSERT_EQ(sum_value_len, vals_len);
2712
2713 for (int i = 1; i <= 70; i++) {
2714 key = "key" + stringify(i);
2715 val = "value" + stringify(i);
2716 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
2717 ASSERT_STREQ(val.c_str(), value);
2718
2719 value_len = sizeof(value);
2720 }
2721 printf("child image successfully cloned all image-meta pairs\n");
2722
2723 // sizing down child results in changing overlap and size, not parent size
2724 ASSERT_EQ(0, rbd_resize(child, 2UL<<20));
2725 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2726 rbd_get_overlap(child, &overlap);
2727 ASSERT_EQ(overlap, 2UL<<20);
2728 ASSERT_EQ(cinfo.size, 2UL<<20);
2729 ASSERT_EQ(0, rbd_resize(child, 4UL<<20));
2730 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2731 rbd_get_overlap(child, &overlap);
2732 ASSERT_EQ(overlap, 2UL<<20);
2733 ASSERT_EQ(cinfo.size, 4UL<<20);
2734 printf("sized down clone, changed overlap\n");
2735
2736 // sizing back up doesn't change that
2737 ASSERT_EQ(0, rbd_resize(child, 5UL<<20));
2738 ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
2739 rbd_get_overlap(child, &overlap);
2740 ASSERT_EQ(overlap, 2UL<<20);
2741 ASSERT_EQ(cinfo.size, 5UL<<20);
2742 ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
2743 printf("parent info: size %lld obj_size %lld parent_pool %lld\n",
2744 (unsigned long long)pinfo.size, (unsigned long long)pinfo.obj_size,
2745 (unsigned long long)pinfo.parent_pool);
2746 ASSERT_EQ(pinfo.size, 4UL<<20);
2747 printf("sized up clone, changed size but not overlap or parent's size\n");
2748
2749 ASSERT_PASSED(validate_object_map, child);
2750 ASSERT_EQ(0, rbd_close(child));
2751
2752 ASSERT_PASSED(validate_object_map, parent);
2753 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
2754 printf("can't remove parent while child still exists\n");
2755 ASSERT_EQ(0, rbd_remove(ioctx, child_name.c_str()));
2756 ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap"));
2757 printf("can't remove parent while still protected\n");
2758 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
2759 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
2760 printf("removed parent snap after unprotecting\n");
2761
2762 ASSERT_EQ(0, rbd_close(parent));
2763 rados_ioctx_destroy(ioctx);
2764 }
2765
2766 TEST_F(TestLibRBD, TestClone2)
2767 {
2768 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2769
2770 rados_ioctx_t ioctx;
2771 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
2772
2773 bool old_format;
2774 uint64_t features;
2775 rbd_image_t parent, child;
2776 int order = 0;
2777
2778 ASSERT_EQ(0, get_features(&old_format, &features));
2779 ASSERT_FALSE(old_format);
2780
2781 std::string parent_name = get_temp_image_name();
2782 std::string child_name = get_temp_image_name();
2783
2784 // make a parent to clone from
2785 ASSERT_EQ(0, create_image_full(ioctx, parent_name.c_str(), 4<<20, &order,
2786 false, features));
2787 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
2788 printf("made parent image \"parent\"\n");
2789
2790 char *data = (char *)"testdata";
2791 char *childata = (char *)"childata";
2792 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
2793 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
2794
2795 // can't clone a non-snapshot, expect failure
2796 EXPECT_NE(0, clone_image(ioctx, parent, parent_name.c_str(), NULL, ioctx,
2797 child_name.c_str(), features, &order));
2798
2799 // verify that there is no parent info on "parent"
2800 ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, NULL, 0, NULL, 0, NULL, 0));
2801 printf("parent has no parent info\n");
2802
2803 // create 70 metadatas to verify we can clone all key/value pairs
2804 std::string key;
2805 std::string val;
2806 size_t sum_key_len = 0;
2807 size_t sum_value_len = 0;
2808 for (int i = 1; i <= 70; i++) {
2809 key = "key" + stringify(i);
2810 val = "value" + stringify(i);
2811 ASSERT_EQ(0, rbd_metadata_set(parent, key.c_str(), val.c_str()));
2812
2813 sum_key_len += (key.size() + 1);
2814 sum_value_len += (val.size() + 1);
2815 }
2816
2817 char keys[1024];
2818 char vals[1024];
2819 size_t keys_len = sizeof(keys);
2820 size_t vals_len = sizeof(vals);
2821
2822 char value[1024];
2823 size_t value_len = sizeof(value);
2824
2825 // create a snapshot, reopen as the parent we're interested in
2826 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2827 printf("made snapshot \"parent@parent_snap\"\n");
2828 ASSERT_EQ(0, rbd_close(parent));
2829 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
2830
2831 ASSERT_EQ(-EINVAL, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2832 ioctx, child_name.c_str(), features, &order));
2833
2834 // unprotected image should fail unprotect
2835 ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap"));
2836 printf("can't unprotect an unprotected snap\n");
2837
2838 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2839 // protecting again should fail
2840 ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap"));
2841 printf("can't protect a protected snap\n");
2842
2843 // This clone and open should work
2844 ASSERT_EQ(0, clone_image(ioctx, parent, parent_name.c_str(), "parent_snap",
2845 ioctx, child_name.c_str(), features, &order));
2846 ASSERT_EQ(0, rbd_open(ioctx, child_name.c_str(), &child, NULL));
2847 printf("made and opened clone \"child\"\n");
2848
2849 // check key/value pairs in child image
2850 ASSERT_EQ(0, rbd_metadata_list(child, "", 70, keys, &keys_len, vals,
2851 &vals_len));
2852 ASSERT_EQ(sum_key_len, keys_len);
2853 ASSERT_EQ(sum_value_len, vals_len);
2854
2855 for (int i = 1; i <= 70; i++) {
2856 key = "key" + stringify(i);
2857 val = "value" + stringify(i);
2858 ASSERT_EQ(0, rbd_metadata_get(child, key.c_str(), value, &value_len));
2859 ASSERT_STREQ(val.c_str(), value);
2860
2861 value_len = sizeof(value);
2862 }
2863 printf("child image successfully cloned all image-meta pairs\n");
2864
2865 // write something in
2866 ASSERT_EQ((ssize_t)strlen(childata), rbd_write(child, 20, strlen(childata), childata));
2867
2868 char test[strlen(data) * 2];
2869 ASSERT_EQ((ssize_t)strlen(data), rbd_read(child, 20, strlen(data), test));
2870 ASSERT_EQ(0, memcmp(test, childata, strlen(childata)));
2871
2872 // overlap
2873 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 20 - strlen(data), sizeof(test), test));
2874 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
2875 ASSERT_EQ(0, memcmp(test + strlen(data), childata, strlen(childata)));
2876
2877 // all parent
2878 ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 0, sizeof(test), test));
2879 ASSERT_EQ(0, memcmp(test, data, strlen(data)));
2880
2881 ASSERT_PASSED(validate_object_map, child);
2882 ASSERT_PASSED(validate_object_map, parent);
2883
2884 ASSERT_EQ(0, rbd_close(child));
2885 ASSERT_EQ(0, rbd_close(parent));
2886 rados_ioctx_destroy(ioctx);
2887 }
2888
2889 static void test_list_children(rbd_image_t image, ssize_t num_expected, ...)
2890 {
2891 va_list ap;
2892 va_start(ap, num_expected);
2893 size_t pools_len = 100;
2894 size_t children_len = 100;
2895 char *pools = NULL;
2896 char *children = NULL;
2897 ssize_t num_children;
2898
2899 do {
2900 free(pools);
2901 free(children);
2902 pools = (char *) malloc(pools_len);
2903 children = (char *) malloc(children_len);
2904 num_children = rbd_list_children(image, pools, &pools_len,
2905 children, &children_len);
2906 } while (num_children == -ERANGE);
2907
2908 ASSERT_EQ(num_expected, num_children);
2909 for (ssize_t i = num_expected; i > 0; --i) {
2910 char *expected_pool = va_arg(ap, char *);
2911 char *expected_image = va_arg(ap, char *);
2912 char *pool = pools;
2913 char *image = children;
2914 bool found = 0;
2915 printf("\ntrying to find %s/%s\n", expected_pool, expected_image);
2916 for (ssize_t j = 0; j < num_children; ++j) {
2917 printf("checking %s/%s\n", pool, image);
2918 if (strcmp(expected_pool, pool) == 0 &&
2919 strcmp(expected_image, image) == 0) {
2920 printf("found child %s/%s\n\n", pool, image);
2921 found = 1;
2922 break;
2923 }
2924 pool += strlen(pool) + 1;
2925 image += strlen(image) + 1;
2926 if (j == num_children - 1) {
2927 ASSERT_EQ(pool - pools - 1, (ssize_t) pools_len);
2928 ASSERT_EQ(image - children - 1, (ssize_t) children_len);
2929 }
2930 }
2931 ASSERT_TRUE(found);
2932 }
2933 va_end(ap);
2934
2935 if (pools)
2936 free(pools);
2937 if (children)
2938 free(children);
2939 }
2940
2941 TEST_F(TestLibRBD, ListChildren)
2942 {
2943 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
2944
2945 rados_ioctx_t ioctx1, ioctx2;
2946 string pool_name1 = create_pool(true);
2947 string pool_name2 = create_pool(true);
2948 ASSERT_NE("", pool_name2);
2949
2950 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
2951 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
2952
2953 bool old_format;
2954 uint64_t features;
2955 rbd_image_t parent;
2956 int order = 0;
2957
2958 ASSERT_EQ(0, get_features(&old_format, &features));
2959 ASSERT_FALSE(old_format);
2960
2961 std::string parent_name = get_temp_image_name();
2962 std::string child_name1 = get_temp_image_name();
2963 std::string child_name2 = get_temp_image_name();
2964 std::string child_name3 = get_temp_image_name();
2965 std::string child_name4 = get_temp_image_name();
2966
2967 // make a parent to clone from
2968 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
2969 false, features));
2970 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
2971 // create a snapshot, reopen as the parent we're interested in
2972 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
2973 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
2974 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
2975
2976 ASSERT_EQ(0, rbd_close(parent));
2977 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
2978
2979 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2980 ioctx2, child_name1.c_str(), features, &order));
2981 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
2982
2983 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2984 ioctx1, child_name2.c_str(), features, &order));
2985 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
2986 pool_name1.c_str(), child_name2.c_str());
2987
2988 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2989 ioctx2, child_name3.c_str(), features, &order));
2990 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
2991 pool_name1.c_str(), child_name2.c_str(),
2992 pool_name2.c_str(), child_name3.c_str());
2993
2994 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
2995 ioctx2, child_name4.c_str(), features, &order));
2996 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
2997 pool_name1.c_str(), child_name2.c_str(),
2998 pool_name2.c_str(), child_name3.c_str(),
2999 pool_name2.c_str(), child_name4.c_str());
3000
3001 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
3002 test_list_children(parent, 3,
3003 pool_name1.c_str(), child_name2.c_str(),
3004 pool_name2.c_str(), child_name3.c_str(),
3005 pool_name2.c_str(), child_name4.c_str());
3006
3007 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
3008 test_list_children(parent, 2,
3009 pool_name1.c_str(), child_name2.c_str(),
3010 pool_name2.c_str(), child_name4.c_str());
3011
3012 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
3013 test_list_children(parent, 1,
3014 pool_name1.c_str(), child_name2.c_str());
3015
3016 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
3017 test_list_children(parent, 0);
3018
3019 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3020 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3021 ASSERT_EQ(0, rbd_close(parent));
3022 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
3023 rados_ioctx_destroy(ioctx1);
3024 rados_ioctx_destroy(ioctx2);
3025 }
3026
3027 TEST_F(TestLibRBD, ListChildrenTiered)
3028 {
3029 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3030
3031 string pool_name1 = create_pool(true);
3032 string pool_name2 = create_pool(true);
3033 string pool_name3 = create_pool(true);
3034 ASSERT_NE("", pool_name1);
3035 ASSERT_NE("", pool_name2);
3036 ASSERT_NE("", pool_name3);
3037
3038 std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" +
3039 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\", \"force_nonempty\":\"\"}";
3040 char *cmd[1];
3041 cmd[0] = (char *)cmdstr.c_str();
3042 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3043
3044 cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" +
3045 pool_name3 + "\", \"mode\":\"writeback\"}";
3046 cmd[0] = (char *)cmdstr.c_str();
3047 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3048
3049 cmdstr = "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" +
3050 pool_name1 + "\", \"overlaypool\":\"" + pool_name3 + "\"}";
3051 cmd[0] = (char *)cmdstr.c_str();
3052 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3053
3054 EXPECT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
3055
3056 string parent_name = get_temp_image_name();
3057 string child_name1 = get_temp_image_name();
3058 string child_name2 = get_temp_image_name();
3059 string child_name3 = get_temp_image_name();
3060 string child_name4 = get_temp_image_name();
3061
3062 rados_ioctx_t ioctx1, ioctx2;
3063 rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
3064 rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
3065
3066 bool old_format;
3067 uint64_t features;
3068 rbd_image_t parent;
3069 int order = 0;
3070
3071 ASSERT_EQ(0, get_features(&old_format, &features));
3072 ASSERT_FALSE(old_format);
3073
3074 // make a parent to clone from
3075 ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
3076 false, features));
3077 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, NULL));
3078 // create a snapshot, reopen as the parent we're interested in
3079 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
3080 ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap"));
3081 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
3082
3083 ASSERT_EQ(0, rbd_close(parent));
3084 ASSERT_EQ(0, rbd_open(ioctx1, parent_name.c_str(), &parent, "parent_snap"));
3085
3086 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3087 ioctx2, child_name1.c_str(), features, &order));
3088 test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
3089
3090 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3091 ioctx1, child_name2.c_str(), features, &order));
3092 test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
3093 pool_name1.c_str(), child_name2.c_str());
3094
3095 // read from the cache to populate it
3096 rbd_image_t tier_image;
3097 ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &tier_image, NULL));
3098 size_t len = 4 * 1024 * 1024;
3099 char* buf = (char*)malloc(len);
3100 ssize_t size = rbd_read(tier_image, 0, len, buf);
3101 ASSERT_GT(size, 0);
3102 free(buf);
3103 ASSERT_EQ(0, rbd_close(tier_image));
3104
3105 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3106 ioctx2, child_name3.c_str(), features, &order));
3107 test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
3108 pool_name1.c_str(), child_name2.c_str(),
3109 pool_name2.c_str(), child_name3.c_str());
3110
3111 ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
3112 ioctx2, child_name4.c_str(), features, &order));
3113 test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
3114 pool_name1.c_str(), child_name2.c_str(),
3115 pool_name2.c_str(), child_name3.c_str(),
3116 pool_name2.c_str(), child_name4.c_str());
3117
3118 ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
3119 test_list_children(parent, 3,
3120 pool_name1.c_str(), child_name2.c_str(),
3121 pool_name2.c_str(), child_name3.c_str(),
3122 pool_name2.c_str(), child_name4.c_str());
3123
3124 ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
3125 test_list_children(parent, 2,
3126 pool_name1.c_str(), child_name2.c_str(),
3127 pool_name2.c_str(), child_name4.c_str());
3128
3129 ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
3130 test_list_children(parent, 1,
3131 pool_name1.c_str(), child_name2.c_str());
3132
3133 ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
3134 test_list_children(parent, 0);
3135
3136 ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
3137 ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
3138 ASSERT_EQ(0, rbd_close(parent));
3139 ASSERT_EQ(0, rbd_remove(ioctx1, parent_name.c_str()));
3140 rados_ioctx_destroy(ioctx1);
3141 rados_ioctx_destroy(ioctx2);
3142 cmdstr = "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" +
3143 pool_name1 + "\"}";
3144 cmd[0] = (char *)cmdstr.c_str();
3145 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3146 cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" +
3147 pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\"}";
3148 cmd[0] = (char *)cmdstr.c_str();
3149 ASSERT_EQ(0, rados_mon_command(_cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0));
3150 }
3151
3152 TEST_F(TestLibRBD, LockingPP)
3153 {
3154 librados::IoCtx ioctx;
3155 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3156
3157 {
3158 librbd::RBD rbd;
3159 librbd::Image image;
3160 int order = 0;
3161 std::string name = get_temp_image_name();
3162 uint64_t size = 2 << 20;
3163 std::string cookie1 = "foo";
3164 std::string cookie2 = "bar";
3165
3166 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3167 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3168
3169 // no lockers initially
3170 std::list<librbd::locker_t> lockers;
3171 std::string tag;
3172 bool exclusive;
3173 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3174 ASSERT_EQ(0u, lockers.size());
3175 ASSERT_EQ("", tag);
3176
3177 // exclusive lock is exclusive
3178 ASSERT_EQ(0, image.lock_exclusive(cookie1));
3179 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3180 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3181 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3182 ASSERT_EQ(-EBUSY, image.lock_shared(cookie1, "test"));
3183 ASSERT_EQ(-EBUSY, image.lock_shared("", "test"));
3184 ASSERT_EQ(-EBUSY, image.lock_shared("", ""));
3185
3186 // list exclusive
3187 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3188 ASSERT_TRUE(exclusive);
3189 ASSERT_EQ("", tag);
3190 ASSERT_EQ(1u, lockers.size());
3191 ASSERT_EQ(cookie1, lockers.front().cookie);
3192
3193 // unlock
3194 ASSERT_EQ(-ENOENT, image.unlock(""));
3195 ASSERT_EQ(-ENOENT, image.unlock(cookie2));
3196 ASSERT_EQ(0, image.unlock(cookie1));
3197 ASSERT_EQ(-ENOENT, image.unlock(cookie1));
3198 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3199 ASSERT_EQ(0u, lockers.size());
3200
3201 ASSERT_EQ(0, image.lock_shared(cookie1, ""));
3202 ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, ""));
3203 ASSERT_EQ(0, image.lock_shared(cookie2, ""));
3204 ASSERT_EQ(-EEXIST, image.lock_shared(cookie2, ""));
3205 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1));
3206 ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie2));
3207 ASSERT_EQ(-EBUSY, image.lock_exclusive(""));
3208 ASSERT_EQ(-EBUSY, image.lock_exclusive("test"));
3209
3210 // list shared
3211 ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag));
3212 ASSERT_EQ(2u, lockers.size());
3213 }
3214
3215 ioctx.close();
3216 }
3217
3218 TEST_F(TestLibRBD, FlushAio)
3219 {
3220 rados_ioctx_t ioctx;
3221 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3222
3223 rbd_image_t image;
3224 int order = 0;
3225 std::string name = get_temp_image_name();
3226 uint64_t size = 2 << 20;
3227 size_t num_aios = 256;
3228
3229 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3230 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3231
3232 char test_data[TEST_IO_SIZE + 1];
3233 size_t i;
3234 for (i = 0; i < TEST_IO_SIZE; ++i) {
3235 test_data[i] = (char) (rand() % (126 - 33) + 33);
3236 }
3237
3238 rbd_completion_t write_comps[num_aios];
3239 for (i = 0; i < num_aios; ++i) {
3240 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &write_comps[i]));
3241 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3242 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
3243 write_comps[i]));
3244 }
3245
3246 rbd_completion_t flush_comp;
3247 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &flush_comp));
3248 ASSERT_EQ(0, rbd_aio_flush(image, flush_comp));
3249 ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp));
3250 ASSERT_EQ(1, rbd_aio_is_complete(flush_comp));
3251 rbd_aio_release(flush_comp);
3252
3253 for (i = 0; i < num_aios; ++i) {
3254 ASSERT_EQ(1, rbd_aio_is_complete(write_comps[i]));
3255 rbd_aio_release(write_comps[i]);
3256 }
3257
3258 ASSERT_PASSED(validate_object_map, image);
3259 ASSERT_EQ(0, rbd_close(image));
3260 ASSERT_EQ(0, rbd_remove(ioctx, name.c_str()));
3261 rados_ioctx_destroy(ioctx);
3262 }
3263
3264 TEST_F(TestLibRBD, FlushAioPP)
3265 {
3266 librados::IoCtx ioctx;
3267 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3268
3269 {
3270 librbd::RBD rbd;
3271 librbd::Image image;
3272 int order = 0;
3273 std::string name = get_temp_image_name();
3274 uint64_t size = 2 << 20;
3275 const size_t num_aios = 256;
3276
3277 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3278 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3279
3280 char test_data[TEST_IO_SIZE + 1];
3281 size_t i;
3282 for (i = 0; i < TEST_IO_SIZE; ++i) {
3283 test_data[i] = (char) (rand() % (126 - 33) + 33);
3284 }
3285 test_data[TEST_IO_SIZE] = '\0';
3286
3287 librbd::RBD::AioCompletion *write_comps[num_aios];
3288 ceph::bufferlist bls[num_aios];
3289 for (i = 0; i < num_aios; ++i) {
3290 bls[i].append(test_data, strlen(test_data));
3291 write_comps[i] = new librbd::RBD::AioCompletion(NULL, NULL);
3292 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3293 ASSERT_EQ(0, image.aio_write(offset, TEST_IO_SIZE, bls[i],
3294 write_comps[i]));
3295 }
3296
3297 librbd::RBD::AioCompletion *flush_comp =
3298 new librbd::RBD::AioCompletion(NULL, NULL);
3299 ASSERT_EQ(0, image.aio_flush(flush_comp));
3300 ASSERT_EQ(0, flush_comp->wait_for_complete());
3301 ASSERT_EQ(1, flush_comp->is_complete());
3302 flush_comp->release();
3303
3304 for (i = 0; i < num_aios; ++i) {
3305 librbd::RBD::AioCompletion *comp = write_comps[i];
3306 ASSERT_EQ(1, comp->is_complete());
3307 comp->release();
3308 }
3309 ASSERT_PASSED(validate_object_map, image);
3310 }
3311
3312 ioctx.close();
3313 }
3314
3315
3316 int iterate_cb(uint64_t off, size_t len, int exists, void *arg)
3317 {
3318 //cout << "iterate_cb " << off << "~" << len << std::endl;
3319 interval_set<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
3320 diff->insert(off, len);
3321 return 0;
3322 }
3323
3324 static int iterate_error_cb(uint64_t off, size_t len, int exists, void *arg)
3325 {
3326 return -EINVAL;
3327 }
3328
3329 void scribble(librbd::Image& image, int n, int max, bool skip_discard,
3330 interval_set<uint64_t> *exists,
3331 interval_set<uint64_t> *what)
3332 {
3333 uint64_t size;
3334 image.size(&size);
3335 interval_set<uint64_t> exists_at_start = *exists;
3336
3337 for (int i=0; i<n; i++) {
3338 uint64_t off = rand() % (size - max + 1);
3339 uint64_t len = 1 + rand() % max;
3340 if (!skip_discard && rand() % 4 == 0) {
3341 ASSERT_EQ((int)len, image.discard(off, len));
3342 interval_set<uint64_t> w;
3343 w.insert(off, len);
3344
3345 // the zeroed bit no longer exists...
3346 w.intersection_of(*exists);
3347 exists->subtract(w);
3348
3349 // the bits we discarded are no long written...
3350 interval_set<uint64_t> w2 = w;
3351 w2.intersection_of(*what);
3352 what->subtract(w2);
3353
3354 // except for the extents that existed at the start that we overwrote.
3355 interval_set<uint64_t> w3;
3356 w3.insert(off, len);
3357 w3.intersection_of(exists_at_start);
3358 what->union_of(w3);
3359
3360 } else {
3361 bufferlist bl;
3362 bl.append(buffer::create(len));
3363 bl.zero();
3364 ASSERT_EQ((int)len, image.write(off, len, bl));
3365 interval_set<uint64_t> w;
3366 w.insert(off, len);
3367 what->union_of(w);
3368 exists->union_of(w);
3369 }
3370 }
3371 }
3372
3373 interval_set<uint64_t> round_diff_interval(const interval_set<uint64_t>& diff,
3374 uint64_t object_size)
3375 {
3376 if (object_size == 0) {
3377 return diff;
3378 }
3379
3380 interval_set<uint64_t> rounded_diff;
3381 for (interval_set<uint64_t>::const_iterator it = diff.begin();
3382 it != diff.end(); ++it) {
3383 uint64_t off = it.get_start();
3384 uint64_t len = it.get_len();
3385 off -= off % object_size;
3386 len += (object_size - (len % object_size));
3387 interval_set<uint64_t> interval;
3388 interval.insert(off, len);
3389 rounded_diff.union_of(interval);
3390 }
3391 return rounded_diff;
3392 }
3393
3394 template <typename T>
3395 class DiffIterateTest : public TestLibRBD {
3396 public:
3397 static const uint8_t whole_object = T::whole_object;
3398 };
3399
3400 template <bool _whole_object>
3401 class DiffIterateParams {
3402 public:
3403 static const uint8_t whole_object = _whole_object;
3404 };
3405
3406 typedef ::testing::Types<DiffIterateParams<false>,
3407 DiffIterateParams<true> > DiffIterateTypes;
3408 TYPED_TEST_CASE(DiffIterateTest, DiffIterateTypes);
3409
3410 TYPED_TEST(DiffIterateTest, DiffIterate)
3411 {
3412 librados::IoCtx ioctx;
3413 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3414
3415 bool skip_discard = this->is_skip_partial_discard_enabled();
3416
3417 {
3418 librbd::RBD rbd;
3419 librbd::Image image;
3420 int order = 0;
3421 std::string name = this->get_temp_image_name();
3422 uint64_t size = 20 << 20;
3423
3424 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3425 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3426
3427 uint64_t object_size = 0;
3428 if (this->whole_object) {
3429 object_size = 1 << order;
3430 }
3431
3432 interval_set<uint64_t> exists;
3433 interval_set<uint64_t> one, two;
3434 scribble(image, 10, 102400, skip_discard, &exists, &one);
3435 cout << " wrote " << one << std::endl;
3436 ASSERT_EQ(0, image.snap_create("one"));
3437 scribble(image, 10, 102400, skip_discard, &exists, &two);
3438
3439 two = round_diff_interval(two, object_size);
3440 cout << " wrote " << two << std::endl;
3441
3442 interval_set<uint64_t> diff;
3443 ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
3444 iterate_cb, (void *)&diff));
3445 cout << " diff was " << diff << std::endl;
3446 if (!two.subset_of(diff)) {
3447 interval_set<uint64_t> i;
3448 i.intersection_of(two, diff);
3449 interval_set<uint64_t> l = two;
3450 l.subtract(i);
3451 cout << " ... two - (two*diff) = " << l << std::endl;
3452 }
3453 ASSERT_TRUE(two.subset_of(diff));
3454 }
3455 ioctx.close();
3456 }
3457
3458 struct diff_extent {
3459 diff_extent(uint64_t _offset, uint64_t _length, bool _exists,
3460 uint64_t object_size) :
3461 offset(_offset), length(_length), exists(_exists)
3462 {
3463 if (object_size != 0) {
3464 offset -= offset % object_size;
3465 length = object_size;
3466 }
3467 }
3468 uint64_t offset;
3469 uint64_t length;
3470 bool exists;
3471 bool operator==(const diff_extent& o) const {
3472 return offset == o.offset && length == o.length && exists == o.exists;
3473 }
3474 };
3475
3476 ostream& operator<<(ostream & o, const diff_extent& e) {
3477 return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')';
3478 }
3479
3480 int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg)
3481 {
3482 cout << "iterate_cb " << off << "~" << len << std::endl;
3483 vector<diff_extent> *diff = static_cast<vector<diff_extent> *>(arg);
3484 diff->push_back(diff_extent(off, len, exists, 0));
3485 return 0;
3486 }
3487
3488 TYPED_TEST(DiffIterateTest, DiffIterateDiscard)
3489 {
3490 librados::IoCtx ioctx;
3491 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3492
3493 librbd::RBD rbd;
3494 librbd::Image image;
3495 int order = 0;
3496 std::string name = this->get_temp_image_name();
3497 uint64_t size = 20 << 20;
3498
3499 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3500 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3501
3502 uint64_t object_size = 0;
3503 if (this->whole_object) {
3504 object_size = 1 << order;
3505 }
3506 vector<diff_extent> extents;
3507 ceph::bufferlist bl;
3508
3509 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3510 vector_iterate_cb, (void *) &extents));
3511 ASSERT_EQ(0u, extents.size());
3512
3513 char data[256];
3514 memset(data, 1, sizeof(data));
3515 bl.append(data, 256);
3516 ASSERT_EQ(256, image.write(0, 256, bl));
3517 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3518 vector_iterate_cb, (void *) &extents));
3519 ASSERT_EQ(1u, extents.size());
3520 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3521
3522 int obj_ofs = 256;
3523 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
3524
3525 extents.clear();
3526 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3527 vector_iterate_cb, (void *) &extents));
3528 ASSERT_EQ(0u, extents.size());
3529
3530 ASSERT_EQ(0, image.snap_create("snap1"));
3531 ASSERT_EQ(256, image.write(0, 256, bl));
3532 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3533 vector_iterate_cb, (void *) &extents));
3534 ASSERT_EQ(1u, extents.size());
3535 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3536 ASSERT_EQ(0, image.snap_create("snap2"));
3537
3538 ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs));
3539
3540 extents.clear();
3541 ASSERT_EQ(0, image.snap_set("snap2"));
3542 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
3543 vector_iterate_cb, (void *) &extents));
3544 ASSERT_EQ(1u, extents.size());
3545 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3546
3547 ASSERT_EQ(0, image.snap_set(NULL));
3548 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
3549 ASSERT_EQ(0, image.snap_create("snap3"));
3550 ASSERT_EQ(0, image.snap_set("snap3"));
3551
3552 extents.clear();
3553 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object,
3554 vector_iterate_cb, (void *) &extents));
3555 ASSERT_EQ(1u, extents.size());
3556 ASSERT_EQ(diff_extent(0, 256, false, object_size), extents[0]);
3557 ASSERT_PASSED(this->validate_object_map, image);
3558 }
3559
3560 TYPED_TEST(DiffIterateTest, DiffIterateStress)
3561 {
3562 librados::IoCtx ioctx;
3563 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3564
3565 bool skip_discard = this->is_skip_partial_discard_enabled();
3566
3567 librbd::RBD rbd;
3568 librbd::Image image;
3569 int order = 0;
3570 std::string name = this->get_temp_image_name();
3571 uint64_t size = 400 << 20;
3572
3573 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3574 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3575
3576 uint64_t object_size = 0;
3577 if (this->whole_object) {
3578 object_size = 1 << order;
3579 }
3580
3581 interval_set<uint64_t> curexists;
3582 vector<interval_set<uint64_t> > wrote;
3583 vector<interval_set<uint64_t> > exists;
3584 vector<string> snap;
3585 int n = 20;
3586 for (int i=0; i<n; i++) {
3587 interval_set<uint64_t> w;
3588 scribble(image, 10, 8192000, skip_discard, &curexists, &w);
3589 cout << " i=" << i << " exists " << curexists << " wrote " << w << std::endl;
3590 string s = "snap" + stringify(i);
3591 ASSERT_EQ(0, image.snap_create(s.c_str()));
3592 wrote.push_back(w);
3593 exists.push_back(curexists);
3594 snap.push_back(s);
3595 }
3596
3597 for (int h=0; h<n-1; h++) {
3598 for (int i=0; i<n-h-1; i++) {
3599 for (int j=(h==0 ? i+1 : n-1); j<n; j++) {
3600 interval_set<uint64_t> diff, actual, uex;
3601 for (int k=i+1; k<=j; k++)
3602 diff.union_of(wrote[k]);
3603 cout << "from " << i << " to "
3604 << (h != 0 ? string("HEAD") : stringify(j)) << " diff "
3605 << round_diff_interval(diff, object_size) << std::endl;
3606
3607 // limit to extents that exists both at the beginning and at the end
3608 uex.union_of(exists[i], exists[j]);
3609 diff.intersection_of(uex);
3610 diff = round_diff_interval(diff, object_size);
3611 cout << " limited diff " << diff << std::endl;
3612
3613 ASSERT_EQ(0, image.snap_set(h==0 ? snap[j].c_str() : NULL));
3614 ASSERT_EQ(0, image.diff_iterate2(snap[i].c_str(), 0, size, true,
3615 this->whole_object, iterate_cb,
3616 (void *)&actual));
3617 cout << " actual was " << actual << std::endl;
3618 if (!diff.subset_of(actual)) {
3619 interval_set<uint64_t> i;
3620 i.intersection_of(diff, actual);
3621 interval_set<uint64_t> l = diff;
3622 l.subtract(i);
3623 cout << " ... diff - (actual*diff) = " << l << std::endl;
3624 }
3625 ASSERT_TRUE(diff.subset_of(actual));
3626 }
3627 }
3628 ASSERT_EQ(0, image.snap_set(NULL));
3629 ASSERT_EQ(0, image.snap_remove(snap[n-h-1].c_str()));
3630 }
3631
3632 ASSERT_PASSED(this->validate_object_map, image);
3633 }
3634
3635 TYPED_TEST(DiffIterateTest, DiffIterateRegression6926)
3636 {
3637 librados::IoCtx ioctx;
3638 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3639
3640 librbd::RBD rbd;
3641 librbd::Image image;
3642 int order = 0;
3643 std::string name = this->get_temp_image_name();
3644 uint64_t size = 20 << 20;
3645
3646 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3647 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3648
3649 uint64_t object_size = 0;
3650 if (this->whole_object) {
3651 object_size = 1 << order;
3652 }
3653 vector<diff_extent> extents;
3654 ceph::bufferlist bl;
3655
3656 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3657 vector_iterate_cb, (void *) &extents));
3658 ASSERT_EQ(0u, extents.size());
3659
3660 ASSERT_EQ(0, image.snap_create("snap1"));
3661 char data[256];
3662 memset(data, 1, sizeof(data));
3663 bl.append(data, 256);
3664 ASSERT_EQ(256, image.write(0, 256, bl));
3665
3666 extents.clear();
3667 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3668 vector_iterate_cb, (void *) &extents));
3669 ASSERT_EQ(1u, extents.size());
3670 ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
3671
3672 ASSERT_EQ(0, image.snap_set("snap1"));
3673 extents.clear();
3674 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3675 vector_iterate_cb, (void *) &extents));
3676 ASSERT_EQ(static_cast<size_t>(0), extents.size());
3677 }
3678
3679 TYPED_TEST(DiffIterateTest, DiffIterateIgnoreParent)
3680 {
3681 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3682
3683 librados::IoCtx ioctx;
3684 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3685
3686 bool skip_discard = this->is_skip_partial_discard_enabled();
3687
3688 librbd::RBD rbd;
3689 librbd::Image image;
3690 std::string name = this->get_temp_image_name();
3691 uint64_t size = 20 << 20;
3692 int order = 0;
3693
3694 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3695 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3696
3697 uint64_t object_size = 0;
3698 if (this->whole_object) {
3699 object_size = 1 << order;
3700 }
3701
3702 bufferlist bl;
3703 bl.append(buffer::create(size));
3704 bl.zero();
3705 interval_set<uint64_t> one;
3706 one.insert(0, size);
3707 ASSERT_EQ((int)size, image.write(0, size, bl));
3708 ASSERT_EQ(0, image.snap_create("one"));
3709 ASSERT_EQ(0, image.snap_protect("one"));
3710
3711 std::string clone_name = this->get_temp_image_name();
3712 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
3713 RBD_FEATURE_LAYERING, &order));
3714 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
3715
3716 interval_set<uint64_t> exists;
3717 interval_set<uint64_t> two;
3718 scribble(image, 10, 102400, skip_discard, &exists, &two);
3719 two = round_diff_interval(two, object_size);
3720 cout << " wrote " << two << " to clone" << std::endl;
3721
3722 interval_set<uint64_t> diff;
3723 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, false, this->whole_object,
3724 iterate_cb, (void *)&diff));
3725 cout << " diff was " << diff << std::endl;
3726 if (!this->whole_object) {
3727 ASSERT_FALSE(one.subset_of(diff));
3728 }
3729 ASSERT_TRUE(two.subset_of(diff));
3730 }
3731
3732 TYPED_TEST(DiffIterateTest, DiffIterateCallbackError)
3733 {
3734 librados::IoCtx ioctx;
3735 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3736
3737 bool skip_discard = this->is_skip_partial_discard_enabled();
3738
3739 {
3740 librbd::RBD rbd;
3741 librbd::Image image;
3742 int order = 0;
3743 std::string name = this->get_temp_image_name();
3744 uint64_t size = 20 << 20;
3745
3746 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3747 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3748
3749 interval_set<uint64_t> exists;
3750 interval_set<uint64_t> one;
3751 scribble(image, 10, 102400, skip_discard, &exists, &one);
3752 cout << " wrote " << one << std::endl;
3753
3754 interval_set<uint64_t> diff;
3755 ASSERT_EQ(-EINVAL, image.diff_iterate2(NULL, 0, size, true,
3756 this->whole_object,
3757 iterate_error_cb, NULL));
3758 }
3759 ioctx.close();
3760 }
3761
3762 TYPED_TEST(DiffIterateTest, DiffIterateParentDiscard)
3763 {
3764 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3765
3766 librados::IoCtx ioctx;
3767 ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
3768
3769 bool skip_discard = this->is_skip_partial_discard_enabled();
3770
3771 librbd::RBD rbd;
3772 librbd::Image image;
3773 std::string name = this->get_temp_image_name();
3774 uint64_t size = 20 << 20;
3775 int order = 0;
3776
3777 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
3778 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
3779
3780 uint64_t object_size = 0;
3781 if (this->whole_object) {
3782 object_size = 1 << order;
3783 }
3784
3785 interval_set<uint64_t> exists;
3786 interval_set<uint64_t> one;
3787 scribble(image, 10, 102400, skip_discard, &exists, &one);
3788 ASSERT_EQ(0, image.snap_create("one"));
3789
3790 ASSERT_EQ(1 << order, image.discard(0, 1 << order));
3791 ASSERT_EQ(0, image.snap_create("two"));
3792 ASSERT_EQ(0, image.snap_protect("two"));
3793 exists.clear();
3794 one.clear();
3795
3796 std::string clone_name = this->get_temp_image_name();
3797 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "two", ioctx,
3798 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
3799 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
3800
3801 interval_set<uint64_t> two;
3802 scribble(image, 10, 102400, skip_discard, &exists, &two);
3803 two = round_diff_interval(two, object_size);
3804
3805 interval_set<uint64_t> diff;
3806 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object,
3807 iterate_cb, (void *)&diff));
3808 ASSERT_TRUE(two.subset_of(diff));
3809 }
3810
3811 TEST_F(TestLibRBD, ZeroLengthWrite)
3812 {
3813 rados_ioctx_t ioctx;
3814 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3815
3816 rbd_image_t image;
3817 int order = 0;
3818 std::string name = get_temp_image_name();
3819 uint64_t size = 2 << 20;
3820
3821 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3822 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3823
3824 char read_data[1];
3825 ASSERT_EQ(0, rbd_write(image, 0, 0, NULL));
3826 ASSERT_EQ(1, rbd_read(image, 0, 1, read_data));
3827 ASSERT_EQ('\0', read_data[0]);
3828
3829 ASSERT_PASSED(validate_object_map, image);
3830 ASSERT_EQ(0, rbd_close(image));
3831
3832 rados_ioctx_destroy(ioctx);
3833 }
3834
3835
3836 TEST_F(TestLibRBD, ZeroLengthDiscard)
3837 {
3838 rados_ioctx_t ioctx;
3839 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3840
3841 rbd_image_t image;
3842 int order = 0;
3843 std::string name = get_temp_image_name();
3844 uint64_t size = 2 << 20;
3845
3846 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3847 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3848
3849 const char data[] = "blah";
3850 char read_data[sizeof(data)];
3851 ASSERT_EQ((int)strlen(data), rbd_write(image, 0, strlen(data), data));
3852 ASSERT_EQ(0, rbd_discard(image, 0, 0));
3853 ASSERT_EQ((int)strlen(data), rbd_read(image, 0, strlen(data), read_data));
3854 ASSERT_EQ(0, memcmp(data, read_data, strlen(data)));
3855
3856 ASSERT_PASSED(validate_object_map, image);
3857 ASSERT_EQ(0, rbd_close(image));
3858
3859 rados_ioctx_destroy(ioctx);
3860 }
3861
3862 TEST_F(TestLibRBD, ZeroLengthRead)
3863 {
3864 rados_ioctx_t ioctx;
3865 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3866
3867 rbd_image_t image;
3868 int order = 0;
3869 std::string name = get_temp_image_name();
3870 uint64_t size = 2 << 20;
3871
3872 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3873 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3874
3875 char read_data[1];
3876 ASSERT_EQ(0, rbd_read(image, 0, 0, read_data));
3877
3878 ASSERT_EQ(0, rbd_close(image));
3879
3880 rados_ioctx_destroy(ioctx);
3881 }
3882
3883 TEST_F(TestLibRBD, LargeCacheRead)
3884 {
3885 std::string config_value;
3886 ASSERT_EQ(0, _rados.conf_get("rbd_cache", config_value));
3887 if (config_value == "false") {
3888 std::cout << "SKIPPING due to disabled cache" << std::endl;
3889 return;
3890 }
3891
3892 rados_ioctx_t ioctx;
3893 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3894
3895 uint32_t new_cache_size = 1 << 20;
3896 std::string orig_cache_size;
3897 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", orig_cache_size));
3898 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size",
3899 stringify(new_cache_size).c_str()));
3900 ASSERT_EQ(0, _rados.conf_get("rbd_cache_size", config_value));
3901 ASSERT_EQ(stringify(new_cache_size), config_value);
3902 BOOST_SCOPE_EXIT( (orig_cache_size) ) {
3903 ASSERT_EQ(0, _rados.conf_set("rbd_cache_size", orig_cache_size.c_str()));
3904 } BOOST_SCOPE_EXIT_END;
3905
3906 rbd_image_t image;
3907 int order = 21;
3908 std::string name = get_temp_image_name();
3909 uint64_t size = 1 << order;
3910
3911 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
3912 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3913
3914 std::string buffer(1 << order, '1');
3915
3916 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
3917 rbd_write(image, 0, buffer.size(), buffer.c_str()));
3918
3919 ASSERT_EQ(0, rbd_invalidate_cache(image));
3920
3921 ASSERT_EQ(static_cast<ssize_t>(buffer.size()),
3922 rbd_read(image, 0, buffer.size(), &buffer[0]));
3923
3924 ASSERT_EQ(0, rbd_close(image));
3925
3926 rados_ioctx_destroy(ioctx);
3927 }
3928
3929 TEST_F(TestLibRBD, TestPendingAio)
3930 {
3931 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3932
3933 rados_ioctx_t ioctx;
3934 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
3935
3936 bool old_format;
3937 uint64_t features;
3938 rbd_image_t image;
3939 int order = 0;
3940
3941 ASSERT_EQ(0, get_features(&old_format, &features));
3942 ASSERT_FALSE(old_format);
3943
3944 std::string name = get_temp_image_name();
3945
3946 uint64_t size = 4 << 20;
3947 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
3948 false, features));
3949 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
3950
3951 char test_data[TEST_IO_SIZE];
3952 for (size_t i = 0; i < TEST_IO_SIZE; ++i) {
3953 test_data[i] = (char) (rand() % (126 - 33) + 33);
3954 }
3955
3956 size_t num_aios = 256;
3957 rbd_completion_t comps[num_aios];
3958 for (size_t i = 0; i < num_aios; ++i) {
3959 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
3960 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3961 ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data,
3962 comps[i]));
3963 }
3964 for (size_t i = 0; i < num_aios; ++i) {
3965 ASSERT_EQ(0, rbd_aio_wait_for_complete(comps[i]));
3966 rbd_aio_release(comps[i]);
3967 }
3968 ASSERT_EQ(0, rbd_invalidate_cache(image));
3969
3970 for (size_t i = 0; i < num_aios; ++i) {
3971 ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i]));
3972 uint64_t offset = rand() % (size - TEST_IO_SIZE);
3973 ASSERT_LE(0, rbd_aio_read(image, offset, TEST_IO_SIZE, test_data,
3974 comps[i]));
3975 }
3976
3977 ASSERT_PASSED(validate_object_map, image);
3978 ASSERT_EQ(0, rbd_close(image));
3979 for (size_t i = 0; i < num_aios; ++i) {
3980 ASSERT_EQ(1, rbd_aio_is_complete(comps[i]));
3981 rbd_aio_release(comps[i]);
3982 }
3983
3984 rados_ioctx_destroy(ioctx);
3985 }
3986
3987 TEST_F(TestLibRBD, Flatten)
3988 {
3989 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
3990
3991 librados::IoCtx ioctx;
3992 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
3993
3994 librbd::RBD rbd;
3995 std::string parent_name = get_temp_image_name();
3996 uint64_t size = 2 << 20;
3997 int order = 0;
3998 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
3999
4000 librbd::Image parent_image;
4001 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4002
4003 bufferlist bl;
4004 bl.append(std::string(4096, '1'));
4005 ASSERT_EQ((ssize_t)bl.length(), parent_image.write(0, bl.length(), bl));
4006
4007 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4008 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4009
4010 uint64_t features;
4011 ASSERT_EQ(0, parent_image.features(&features));
4012
4013 std::string clone_name = get_temp_image_name();
4014 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4015 clone_name.c_str(), features, &order));
4016
4017 librbd::Image clone_image;
4018 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
4019 ASSERT_EQ(0, clone_image.flatten());
4020
4021 librbd::RBD::AioCompletion *read_comp =
4022 new librbd::RBD::AioCompletion(NULL, NULL);
4023 bufferlist read_bl;
4024 clone_image.aio_read(0, bl.length(), read_bl, read_comp);
4025 ASSERT_EQ(0, read_comp->wait_for_complete());
4026 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
4027 read_comp->release();
4028 ASSERT_TRUE(bl.contents_equal(read_bl));
4029
4030 ASSERT_PASSED(validate_object_map, clone_image);
4031 }
4032
4033 TEST_F(TestLibRBD, SnapshotLimit)
4034 {
4035 rados_ioctx_t ioctx;
4036 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4037
4038 rbd_image_t image;
4039 int order = 0;
4040 std::string name = get_temp_image_name();
4041 uint64_t size = 2 << 20;
4042 uint64_t limit;
4043
4044 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4045 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4046
4047 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
4048 ASSERT_EQ(UINT64_MAX, limit);
4049 ASSERT_EQ(0, rbd_snap_set_limit(image, 2));
4050 ASSERT_EQ(0, rbd_snap_get_limit(image, &limit));
4051 ASSERT_EQ(2U, limit);
4052
4053 ASSERT_EQ(0, rbd_snap_create(image, "snap1"));
4054 ASSERT_EQ(0, rbd_snap_create(image, "snap2"));
4055 ASSERT_EQ(-EDQUOT, rbd_snap_create(image, "snap3"));
4056 ASSERT_EQ(0, rbd_snap_set_limit(image, UINT64_MAX));
4057 ASSERT_EQ(0, rbd_snap_create(image, "snap3"));
4058 ASSERT_EQ(0, rbd_close(image));
4059
4060 rados_ioctx_destroy(ioctx);
4061 }
4062
4063
4064 TEST_F(TestLibRBD, SnapshotLimitPP)
4065 {
4066 librados::IoCtx ioctx;
4067 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4068
4069 {
4070 librbd::RBD rbd;
4071 librbd::Image image;
4072 std::string name = get_temp_image_name();
4073 uint64_t size = 2 << 20;
4074 int order = 0;
4075 uint64_t limit;
4076
4077 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4078 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4079
4080 ASSERT_EQ(0, image.snap_get_limit(&limit));
4081 ASSERT_EQ(UINT64_MAX, limit);
4082 ASSERT_EQ(0, image.snap_set_limit(2));
4083 ASSERT_EQ(0, image.snap_get_limit(&limit));
4084 ASSERT_EQ(2U, limit);
4085
4086 ASSERT_EQ(0, image.snap_create("snap1"));
4087 ASSERT_EQ(0, image.snap_create("snap2"));
4088 ASSERT_EQ(-EDQUOT, image.snap_create("snap3"));
4089 ASSERT_EQ(0, image.snap_set_limit(UINT64_MAX));
4090 ASSERT_EQ(0, image.snap_create("snap3"));
4091 }
4092
4093 ioctx.close();
4094 }
4095
4096 TEST_F(TestLibRBD, RebuildObjectMapViaLockOwner)
4097 {
4098 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
4099
4100 librados::IoCtx ioctx;
4101 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4102
4103 librbd::RBD rbd;
4104 std::string name = get_temp_image_name();
4105 uint64_t size = 2 << 20;
4106 int order = 0;
4107 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4108
4109 std::string object_map_oid;
4110 {
4111 librbd::Image image;
4112 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4113
4114 std::string image_id;
4115 ASSERT_EQ(0, get_image_id(image, &image_id));
4116 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
4117 }
4118
4119 // corrupt the object map
4120 bufferlist bl;
4121 bl.append("foo");
4122 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
4123
4124 librbd::Image image1;
4125 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4126
4127 bool lock_owner;
4128 bl.clear();
4129 ASSERT_EQ(0, image1.write(0, 0, bl));
4130 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4131 ASSERT_TRUE(lock_owner);
4132
4133 uint64_t flags;
4134 ASSERT_EQ(0, image1.get_flags(&flags));
4135 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
4136
4137 librbd::Image image2;
4138 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4139 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4140 ASSERT_FALSE(lock_owner);
4141
4142 PrintProgress prog_ctx;
4143 ASSERT_EQ(0, image2.rebuild_object_map(prog_ctx));
4144 ASSERT_PASSED(validate_object_map, image1);
4145 ASSERT_PASSED(validate_object_map, image2);
4146 }
4147
4148 TEST_F(TestLibRBD, RenameViaLockOwner)
4149 {
4150 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
4151
4152 librados::IoCtx ioctx;
4153 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4154
4155 librbd::RBD rbd;
4156 std::string name = get_temp_image_name();
4157 uint64_t size = 2 << 20;
4158 int order = 0;
4159 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4160
4161 librbd::Image image1;
4162 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4163
4164 bufferlist bl;
4165 ASSERT_EQ(0, image1.write(0, 0, bl));
4166
4167 bool lock_owner;
4168 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4169 ASSERT_TRUE(lock_owner);
4170
4171 std::string new_name = get_temp_image_name();
4172 ASSERT_EQ(0, rbd.rename(ioctx, name.c_str(), new_name.c_str()));
4173 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4174 ASSERT_TRUE(lock_owner);
4175
4176 librbd::Image image2;
4177 ASSERT_EQ(0, rbd.open(ioctx, image2, new_name.c_str(), NULL));
4178 }
4179
4180 TEST_F(TestLibRBD, SnapCreateViaLockOwner)
4181 {
4182 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
4183
4184 librados::IoCtx ioctx;
4185 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4186
4187 librbd::RBD rbd;
4188 std::string name = get_temp_image_name();
4189 uint64_t size = 2 << 20;
4190 int order = 0;
4191 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4192
4193 librbd::Image image1;
4194 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4195
4196 // switch to writeback cache
4197 ASSERT_EQ(0, image1.flush());
4198
4199 bufferlist bl;
4200 bl.append(std::string(4096, '1'));
4201 ASSERT_EQ((ssize_t)bl.length(), image1.write(0, bl.length(), bl));
4202
4203 bool lock_owner;
4204 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4205 ASSERT_TRUE(lock_owner);
4206
4207 librbd::Image image2;
4208 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4209
4210 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4211 ASSERT_FALSE(lock_owner);
4212
4213 ASSERT_EQ(0, image2.snap_create("snap1"));
4214 bool exists;
4215 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4216 ASSERT_TRUE(exists);
4217 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
4218 ASSERT_TRUE(exists);
4219
4220 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4221 ASSERT_TRUE(lock_owner);
4222 }
4223
4224 TEST_F(TestLibRBD, SnapRemoveViaLockOwner)
4225 {
4226 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
4227
4228 librados::IoCtx ioctx;
4229 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4230
4231 librbd::RBD rbd;
4232 std::string name = get_temp_image_name();
4233 uint64_t size = 2 << 20;
4234 int order = 0;
4235 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4236
4237 librbd::Image image1;
4238 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4239
4240 bufferlist bl;
4241 ASSERT_EQ(0, image1.write(0, 0, bl));
4242 ASSERT_EQ(0, image1.snap_create("snap1"));
4243
4244 bool lock_owner;
4245 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4246 ASSERT_TRUE(lock_owner);
4247
4248 librbd::Image image2;
4249 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4250
4251 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4252 ASSERT_FALSE(lock_owner);
4253
4254 ASSERT_EQ(0, image2.snap_remove("snap1"));
4255 bool exists;
4256 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4257 ASSERT_FALSE(exists);
4258 ASSERT_EQ(0, image2.snap_exists2("snap1", &exists));
4259 ASSERT_FALSE(exists);
4260
4261 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4262 ASSERT_TRUE(lock_owner);
4263 }
4264
4265 TEST_F(TestLibRBD, EnableJournalingViaLockOwner)
4266 {
4267 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
4268
4269 librados::IoCtx ioctx;
4270 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4271
4272 librbd::RBD rbd;
4273 std::string name = get_temp_image_name();
4274 uint64_t size = 2 << 20;
4275 int order = 0;
4276 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4277
4278 librbd::Image image1;
4279 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4280
4281 bufferlist bl;
4282 ASSERT_EQ(0, image1.write(0, 0, bl));
4283
4284 bool lock_owner;
4285 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4286 ASSERT_TRUE(lock_owner);
4287
4288 librbd::Image image2;
4289 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4290
4291 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, false));
4292
4293 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4294 ASSERT_TRUE(lock_owner);
4295 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4296 ASSERT_FALSE(lock_owner);
4297
4298 ASSERT_EQ(0, image2.update_features(RBD_FEATURE_JOURNALING, true));
4299
4300 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4301 ASSERT_FALSE(lock_owner);
4302 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4303 ASSERT_TRUE(lock_owner);
4304 }
4305
4306 TEST_F(TestLibRBD, SnapRemove2)
4307 {
4308 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4309
4310 librados::IoCtx ioctx;
4311 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4312
4313 librbd::RBD rbd;
4314 std::string name = get_temp_image_name();
4315 uint64_t size = 2 << 20;
4316 int order = 0;
4317 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4318
4319 librbd::Image image1;
4320 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4321
4322 bufferlist bl;
4323 ASSERT_EQ(0, image1.write(0, 0, bl));
4324 ASSERT_EQ(0, image1.snap_create("snap1"));
4325 bool exists;
4326 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4327 ASSERT_TRUE(exists);
4328 ASSERT_EQ(0, image1.snap_protect("snap1"));
4329 bool is_protected;
4330 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4331 ASSERT_TRUE(is_protected);
4332
4333 uint64_t features;
4334 ASSERT_EQ(0, image1.features(&features));
4335
4336 std::string child_name = get_temp_image_name();
4337 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
4338 child_name.c_str(), features, &order));
4339
4340 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4341 ASSERT_TRUE(exists);
4342 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4343 ASSERT_TRUE(is_protected);
4344
4345 ASSERT_EQ(-EBUSY, image1.snap_remove("snap1"));
4346 PrintProgress pp;
4347 ASSERT_EQ(0, image1.snap_remove2("snap1", RBD_SNAP_REMOVE_FORCE, pp));
4348 ASSERT_EQ(0, image1.snap_exists2("snap1", &exists));
4349 ASSERT_FALSE(exists);
4350 }
4351
4352 TEST_F(TestLibRBD, SnapRenameViaLockOwner)
4353 {
4354 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4355
4356 librados::IoCtx ioctx;
4357 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4358
4359 librbd::RBD rbd;
4360 std::string name = get_temp_image_name();
4361 uint64_t size = 2 << 20;
4362 int order = 0;
4363 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4364
4365 librbd::Image image1;
4366 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4367
4368 bufferlist bl;
4369 ASSERT_EQ(0, image1.write(0, 0, bl));
4370 ASSERT_EQ(0, image1.snap_create("snap1"));
4371
4372 bool lock_owner;
4373 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4374 ASSERT_TRUE(lock_owner);
4375
4376 librbd::Image image2;
4377 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4378
4379 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4380 ASSERT_FALSE(lock_owner);
4381
4382 ASSERT_EQ(0, image2.snap_rename("snap1", "snap1-rename"));
4383 bool exists;
4384 ASSERT_EQ(0, image1.snap_exists2("snap1-rename", &exists));
4385 ASSERT_TRUE(exists);
4386 ASSERT_EQ(0, image2.snap_exists2("snap1-rename", &exists));
4387 ASSERT_TRUE(exists);
4388
4389 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4390 ASSERT_TRUE(lock_owner);
4391 }
4392
4393 TEST_F(TestLibRBD, SnapProtectViaLockOwner)
4394 {
4395 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4396
4397 librados::IoCtx ioctx;
4398 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4399
4400 librbd::RBD rbd;
4401 std::string name = get_temp_image_name();
4402 uint64_t size = 2 << 20;
4403 int order = 0;
4404 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4405
4406 librbd::Image image1;
4407 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4408
4409 bufferlist bl;
4410 ASSERT_EQ(0, image1.write(0, 0, bl));
4411
4412 bool lock_owner;
4413 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4414 ASSERT_TRUE(lock_owner);
4415 ASSERT_EQ(0, image1.snap_create("snap1"));
4416
4417 librbd::Image image2;
4418 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4419
4420 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4421 ASSERT_FALSE(lock_owner);
4422
4423 ASSERT_EQ(0, image2.snap_protect("snap1"));
4424 bool is_protected;
4425 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
4426 ASSERT_TRUE(is_protected);
4427 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4428 ASSERT_TRUE(is_protected);
4429
4430 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4431 ASSERT_TRUE(lock_owner);
4432 }
4433
4434 TEST_F(TestLibRBD, SnapUnprotectViaLockOwner)
4435 {
4436 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_EXCLUSIVE_LOCK);
4437
4438 librados::IoCtx ioctx;
4439 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4440
4441 librbd::RBD rbd;
4442 std::string name = get_temp_image_name();
4443 uint64_t size = 2 << 20;
4444 int order = 0;
4445 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4446
4447 librbd::Image image1;
4448 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4449
4450 bufferlist bl;
4451 ASSERT_EQ(0, image1.write(0, 0, bl));
4452
4453 bool lock_owner;
4454 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4455 ASSERT_TRUE(lock_owner);
4456 ASSERT_EQ(0, image1.snap_create("snap1"));
4457 ASSERT_EQ(0, image1.snap_protect("snap1"));
4458 bool is_protected;
4459 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4460 ASSERT_TRUE(is_protected);
4461
4462 librbd::Image image2;
4463 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4464
4465 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4466 ASSERT_FALSE(lock_owner);
4467
4468 ASSERT_EQ(0, image2.snap_unprotect("snap1"));
4469 ASSERT_EQ(0, image2.snap_is_protected("snap1", &is_protected));
4470 ASSERT_FALSE(is_protected);
4471 ASSERT_EQ(0, image1.snap_is_protected("snap1", &is_protected));
4472 ASSERT_FALSE(is_protected);
4473
4474 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4475 ASSERT_TRUE(lock_owner);
4476 }
4477
4478 TEST_F(TestLibRBD, FlattenViaLockOwner)
4479 {
4480 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
4481
4482 librados::IoCtx ioctx;
4483 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4484
4485 librbd::RBD rbd;
4486 std::string parent_name = get_temp_image_name();
4487 uint64_t size = 2 << 20;
4488 int order = 0;
4489 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), size, &order));
4490
4491 librbd::Image parent_image;
4492 ASSERT_EQ(0, rbd.open(ioctx, parent_image, parent_name.c_str(), NULL));
4493 ASSERT_EQ(0, parent_image.snap_create("snap1"));
4494 ASSERT_EQ(0, parent_image.snap_protect("snap1"));
4495
4496 uint64_t features;
4497 ASSERT_EQ(0, parent_image.features(&features));
4498
4499 std::string name = get_temp_image_name();
4500 EXPECT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "snap1", ioctx,
4501 name.c_str(), features, &order));
4502
4503 librbd::Image image1;
4504 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4505
4506 bufferlist bl;
4507 ASSERT_EQ(0, image1.write(0, 0, bl));
4508
4509 bool lock_owner;
4510 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4511 ASSERT_TRUE(lock_owner);
4512
4513 librbd::Image image2;
4514 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4515
4516 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4517 ASSERT_FALSE(lock_owner);
4518
4519 ASSERT_EQ(0, image2.flatten());
4520
4521 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4522 ASSERT_TRUE(lock_owner);
4523 ASSERT_PASSED(validate_object_map, image1);
4524 }
4525
4526 TEST_F(TestLibRBD, ResizeViaLockOwner)
4527 {
4528 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
4529
4530 librados::IoCtx ioctx;
4531 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4532
4533 librbd::RBD rbd;
4534 std::string name = get_temp_image_name();
4535 uint64_t size = 2 << 20;
4536 int order = 0;
4537 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4538
4539 librbd::Image image1;
4540 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4541
4542 bufferlist bl;
4543 ASSERT_EQ(0, image1.write(0, 0, bl));
4544
4545 bool lock_owner;
4546 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4547 ASSERT_TRUE(lock_owner);
4548
4549 librbd::Image image2;
4550 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
4551
4552 ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
4553 ASSERT_FALSE(lock_owner);
4554
4555 ASSERT_EQ(0, image2.resize(0));
4556
4557 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
4558 ASSERT_TRUE(lock_owner);
4559 ASSERT_PASSED(validate_object_map, image1);
4560 }
4561
4562 TEST_F(TestLibRBD, ObjectMapConsistentSnap)
4563 {
4564 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
4565
4566 librados::IoCtx ioctx;
4567 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4568
4569 librbd::RBD rbd;
4570 std::string name = get_temp_image_name();
4571 uint64_t size = 1 << 20;
4572 int order = 12;
4573 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4574
4575 librbd::Image image1;
4576 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4577
4578 int num_snaps = 10;
4579 for (int i = 0; i < num_snaps; ++i) {
4580 std::string snap_name = "snap" + stringify(i);
4581 ASSERT_EQ(0, image1.snap_create(snap_name.c_str()));
4582 }
4583
4584
4585 thread writer([&image1](){
4586 librbd::image_info_t info;
4587 int r = image1.stat(info, sizeof(info));
4588 assert(r == 0);
4589 bufferlist bl;
4590 bl.append("foo");
4591 for (unsigned i = 0; i < info.num_objs; ++i) {
4592 r = image1.write((1 << info.order) * i, bl.length(), bl);
4593 assert(r == (int) bl.length());
4594 }
4595 });
4596 writer.join();
4597
4598 for (int i = 0; i < num_snaps; ++i) {
4599 std::string snap_name = "snap" + stringify(i);
4600 ASSERT_EQ(0, image1.snap_set(snap_name.c_str()));
4601 ASSERT_PASSED(validate_object_map, image1);
4602 }
4603
4604 ASSERT_EQ(0, image1.snap_set(NULL));
4605 ASSERT_PASSED(validate_object_map, image1);
4606 }
4607
4608 void memset_rand(char *buf, size_t len) {
4609 for (size_t i = 0; i < len; ++i) {
4610 buf[i] = (char) (rand() % (126 - 33) + 33);
4611 }
4612 }
4613
4614 TEST_F(TestLibRBD, Metadata)
4615 {
4616 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4617
4618 rados_ioctx_t ioctx;
4619 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
4620
4621 std::string name = get_temp_image_name();
4622 uint64_t size = 2 << 20;
4623 int order = 0;
4624 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
4625
4626 rbd_image_t image;
4627 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
4628
4629 rbd_image_t image1;
4630 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
4631
4632 char keys[1024];
4633 char vals[1024];
4634 size_t keys_len = sizeof(keys);
4635 size_t vals_len = sizeof(vals);
4636
4637 memset_rand(keys, keys_len);
4638 memset_rand(vals, vals_len);
4639
4640 ASSERT_EQ(0, rbd_metadata_list(image, "", 0, keys, &keys_len, vals,
4641 &vals_len));
4642 ASSERT_EQ(0U, keys_len);
4643 ASSERT_EQ(0U, vals_len);
4644
4645 char value[1024];
4646 size_t value_len = sizeof(value);
4647 memset_rand(value, value_len);
4648
4649 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
4650 ASSERT_EQ(0, rbd_metadata_set(image1, "key2", "value2"));
4651 ASSERT_EQ(0, rbd_metadata_get(image1, "key1", value, &value_len));
4652 ASSERT_STREQ(value, "value1");
4653 value_len = 1;
4654 ASSERT_EQ(-ERANGE, rbd_metadata_get(image1, "key1", value, &value_len));
4655 ASSERT_EQ(value_len, strlen("value1") + 1);
4656
4657 ASSERT_EQ(-ERANGE, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4658 &vals_len));
4659 keys_len = sizeof(keys);
4660 vals_len = sizeof(vals);
4661 memset_rand(keys, keys_len);
4662 memset_rand(vals, vals_len);
4663 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4664 &vals_len));
4665 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
4666 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
4667 ASSERT_STREQ(keys, "key1");
4668 ASSERT_STREQ(keys + strlen(keys) + 1, "key2");
4669 ASSERT_STREQ(vals, "value1");
4670 ASSERT_STREQ(vals + strlen(vals) + 1, "value2");
4671
4672 ASSERT_EQ(0, rbd_metadata_remove(image1, "key1"));
4673 ASSERT_EQ(-ENOENT, rbd_metadata_remove(image1, "key3"));
4674 value_len = sizeof(value);
4675 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key3", value, &value_len));
4676 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4677 &vals_len));
4678 ASSERT_EQ(keys_len, strlen("key2") + 1);
4679 ASSERT_EQ(vals_len, strlen("value2") + 1);
4680 ASSERT_STREQ(keys, "key2");
4681 ASSERT_STREQ(vals, "value2");
4682
4683 // test config setting
4684 ASSERT_EQ(0, rbd_metadata_set(image1, "conf_rbd_cache", "false"));
4685 ASSERT_EQ(-EINVAL, rbd_metadata_set(image1, "conf_rbd_cache", "INVALID_VAL"));
4686 ASSERT_EQ(0, rbd_metadata_remove(image1, "conf_rbd_cache"));
4687
4688 // test metadata with snapshot adding
4689 ASSERT_EQ(0, rbd_snap_create(image1, "snap1"));
4690 ASSERT_EQ(0, rbd_snap_protect(image1, "snap1"));
4691 ASSERT_EQ(0, rbd_snap_set(image1, "snap1"));
4692
4693 ASSERT_EQ(0, rbd_metadata_set(image1, "key1", "value1"));
4694 ASSERT_EQ(0, rbd_metadata_set(image1, "key3", "value3"));
4695
4696 keys_len = sizeof(keys);
4697 vals_len = sizeof(vals);
4698 memset_rand(keys, keys_len);
4699 memset_rand(vals, vals_len);
4700 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4701 &vals_len));
4702 ASSERT_EQ(keys_len,
4703 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4704 ASSERT_EQ(vals_len,
4705 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4706 ASSERT_STREQ(keys, "key1");
4707 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
4708 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
4709 ASSERT_STREQ(vals, "value1");
4710 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
4711 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
4712
4713 ASSERT_EQ(0, rbd_snap_set(image1, NULL));
4714 keys_len = sizeof(keys);
4715 vals_len = sizeof(vals);
4716 memset_rand(keys, keys_len);
4717 memset_rand(vals, vals_len);
4718 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4719 &vals_len));
4720 ASSERT_EQ(keys_len,
4721 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4722 ASSERT_EQ(vals_len,
4723 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4724 ASSERT_STREQ(keys, "key1");
4725 ASSERT_STREQ(keys + strlen("key1") + 1, "key2");
4726 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1, "key3");
4727 ASSERT_STREQ(vals, "value1");
4728 ASSERT_STREQ(vals + strlen("value1") + 1, "value2");
4729 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1, "value3");
4730
4731 // test metadata with cloning
4732 uint64_t features;
4733 ASSERT_EQ(0, rbd_get_features(image1, &features));
4734
4735 string cname = get_temp_image_name();
4736 EXPECT_EQ(0, rbd_clone(ioctx, name.c_str(), "snap1", ioctx,
4737 cname.c_str(), features, &order));
4738 rbd_image_t image2;
4739 ASSERT_EQ(0, rbd_open(ioctx, cname.c_str(), &image2, NULL));
4740 ASSERT_EQ(0, rbd_metadata_set(image2, "key4", "value4"));
4741
4742 keys_len = sizeof(keys);
4743 vals_len = sizeof(vals);
4744 memset_rand(keys, keys_len);
4745 memset_rand(vals, vals_len);
4746 ASSERT_EQ(0, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
4747 &vals_len));
4748 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4749 1 + strlen("key4") + 1);
4750 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
4751 strlen("value3") + 1 + strlen("value4") + 1);
4752 ASSERT_STREQ(keys + strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4753 1, "key4");
4754 ASSERT_STREQ(vals + strlen("value1") + 1 + strlen("value2") + 1 +
4755 strlen("value3") + 1, "value4");
4756
4757 ASSERT_EQ(0, rbd_metadata_list(image1, "", 0, keys, &keys_len, vals,
4758 &vals_len));
4759 ASSERT_EQ(keys_len,
4760 strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") + 1);
4761 ASSERT_EQ(vals_len,
4762 strlen("value1") + 1 + strlen("value2") + 1 + strlen("value3") + 1);
4763 ASSERT_EQ(-ENOENT, rbd_metadata_get(image1, "key4", value, &value_len));
4764
4765 // test short buffer cases
4766 keys_len = strlen("key1") + 1;
4767 vals_len = strlen("value1") + 1;
4768 memset_rand(keys, keys_len);
4769 memset_rand(vals, vals_len);
4770 ASSERT_EQ(0, rbd_metadata_list(image2, "", 1, keys, &keys_len, vals,
4771 &vals_len));
4772 ASSERT_EQ(keys_len, strlen("key1") + 1);
4773 ASSERT_EQ(vals_len, strlen("value1") + 1);
4774 ASSERT_STREQ(keys, "key1");
4775 ASSERT_STREQ(vals, "value1");
4776
4777 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 2, keys, &keys_len, vals,
4778 &vals_len));
4779 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1);
4780 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1);
4781
4782 ASSERT_EQ(-ERANGE, rbd_metadata_list(image2, "", 0, keys, &keys_len, vals,
4783 &vals_len));
4784 ASSERT_EQ(keys_len, strlen("key1") + 1 + strlen("key2") + 1 + strlen("key3") +
4785 1 + strlen("key4") + 1);
4786 ASSERT_EQ(vals_len, strlen("value1") + 1 + strlen("value2") + 1 +
4787 strlen("value3") + 1 + strlen("value4") + 1);
4788
4789 // test `start` param
4790 keys_len = sizeof(keys);
4791 vals_len = sizeof(vals);
4792 memset_rand(keys, keys_len);
4793 memset_rand(vals, vals_len);
4794 ASSERT_EQ(0, rbd_metadata_list(image2, "key2", 0, keys, &keys_len, vals,
4795 &vals_len));
4796 ASSERT_EQ(keys_len, strlen("key3") + 1 + strlen("key4") + 1);
4797 ASSERT_EQ(vals_len, strlen("value3") + 1 + strlen("value4") + 1);
4798 ASSERT_STREQ(keys, "key3");
4799 ASSERT_STREQ(vals, "value3");
4800
4801 ASSERT_EQ(0, rbd_close(image));
4802 ASSERT_EQ(0, rbd_close(image1));
4803 ASSERT_EQ(0, rbd_close(image2));
4804 rados_ioctx_destroy(ioctx);
4805 }
4806
4807 TEST_F(TestLibRBD, MetadataPP)
4808 {
4809 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4810
4811 librados::IoCtx ioctx;
4812 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4813
4814 librbd::RBD rbd;
4815 string name = get_temp_image_name();
4816 uint64_t size = 2 << 20;
4817 int order = 0;
4818 uint64_t features;
4819 string value;
4820 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4821
4822 librbd::Image image1;
4823 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
4824 map<string, bufferlist> pairs;
4825 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4826 ASSERT_TRUE(pairs.empty());
4827
4828 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
4829 ASSERT_EQ(0, image1.metadata_set("key2", "value2"));
4830 ASSERT_EQ(0, image1.metadata_get("key1", &value));
4831 ASSERT_EQ(0, strcmp("value1", value.c_str()));
4832 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4833 ASSERT_EQ(2U, pairs.size());
4834 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
4835 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4836
4837 pairs.clear();
4838 ASSERT_EQ(0, image1.metadata_remove("key1"));
4839 ASSERT_EQ(-ENOENT, image1.metadata_remove("key3"));
4840 ASSERT_TRUE(image1.metadata_get("key3", &value) < 0);
4841 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4842 ASSERT_EQ(1U, pairs.size());
4843 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4844
4845 // test config setting
4846 ASSERT_EQ(0, image1.metadata_set("conf_rbd_cache", "false"));
4847 ASSERT_EQ(-EINVAL, image1.metadata_set("conf_rbd_cache", "INVALID_VALUE"));
4848 ASSERT_EQ(0, image1.metadata_remove("conf_rbd_cache"));
4849
4850 // test metadata with snapshot adding
4851 ASSERT_EQ(0, image1.snap_create("snap1"));
4852 ASSERT_EQ(0, image1.snap_protect("snap1"));
4853 ASSERT_EQ(0, image1.snap_set("snap1"));
4854
4855 pairs.clear();
4856 ASSERT_EQ(0, image1.metadata_set("key1", "value1"));
4857 ASSERT_EQ(0, image1.metadata_set("key3", "value3"));
4858 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4859 ASSERT_EQ(3U, pairs.size());
4860 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
4861 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4862 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
4863
4864 ASSERT_EQ(0, image1.snap_set(NULL));
4865 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4866 ASSERT_EQ(3U, pairs.size());
4867 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
4868 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
4869 ASSERT_EQ(0, strncmp("value3", pairs["key3"].c_str(), 6));
4870
4871 // test metadata with cloning
4872 string cname = get_temp_image_name();
4873 librbd::Image image2;
4874 ASSERT_EQ(0, image1.features(&features));
4875 EXPECT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap1", ioctx,
4876 cname.c_str(), features, &order));
4877 ASSERT_EQ(0, rbd.open(ioctx, image2, cname.c_str(), NULL));
4878 ASSERT_EQ(0, image2.metadata_set("key4", "value4"));
4879 pairs.clear();
4880 ASSERT_EQ(0, image2.metadata_list("", 0, &pairs));
4881 ASSERT_EQ(4U, pairs.size());
4882 pairs.clear();
4883 ASSERT_EQ(0, image1.metadata_list("", 0, &pairs));
4884 ASSERT_EQ(3U, pairs.size());
4885 ASSERT_EQ(-ENOENT, image1.metadata_get("key4", &value));
4886 }
4887
4888 TEST_F(TestLibRBD, UpdateFeatures)
4889 {
4890 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
4891
4892 librados::IoCtx ioctx;
4893 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4894
4895 librbd::RBD rbd;
4896 std::string name = get_temp_image_name();
4897 uint64_t size = 1 << 20;
4898 int order = 0;
4899 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
4900
4901 librbd::Image image;
4902 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
4903
4904 uint8_t old_format;
4905 ASSERT_EQ(0, image.old_format(&old_format));
4906 if (old_format) {
4907 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
4908 return;
4909 }
4910
4911 uint64_t features;
4912 ASSERT_EQ(0, image.features(&features));
4913
4914 // must provide a single feature
4915 ASSERT_EQ(-EINVAL, image.update_features(0, true));
4916
4917 uint64_t disable_features;
4918 disable_features = features & (RBD_FEATURE_EXCLUSIVE_LOCK |
4919 RBD_FEATURE_OBJECT_MAP |
4920 RBD_FEATURE_FAST_DIFF |
4921 RBD_FEATURE_JOURNALING);
4922 if (disable_features != 0) {
4923 ASSERT_EQ(0, image.update_features(disable_features, false));
4924 }
4925
4926 ASSERT_EQ(0, image.features(&features));
4927 ASSERT_EQ(0U, features & disable_features);
4928
4929 // cannot enable object map nor journaling w/o exclusive lock
4930 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
4931 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_JOURNALING, true));
4932 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, true));
4933
4934 ASSERT_EQ(0, image.features(&features));
4935 ASSERT_NE(0U, features & RBD_FEATURE_EXCLUSIVE_LOCK);
4936
4937 // cannot enable fast diff w/o object map
4938 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_FAST_DIFF, true));
4939 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, true));
4940 ASSERT_EQ(0, image.features(&features));
4941 ASSERT_NE(0U, features & RBD_FEATURE_OBJECT_MAP);
4942
4943 uint64_t expected_flags = RBD_FLAG_OBJECT_MAP_INVALID;
4944 uint64_t flags;
4945 ASSERT_EQ(0, image.get_flags(&flags));
4946 ASSERT_EQ(expected_flags, flags);
4947
4948 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
4949 ASSERT_EQ(0, image.features(&features));
4950 ASSERT_EQ(0U, features & RBD_FEATURE_OBJECT_MAP);
4951
4952 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP |
4953 RBD_FEATURE_FAST_DIFF |
4954 RBD_FEATURE_JOURNALING, true));
4955
4956 expected_flags = RBD_FLAG_OBJECT_MAP_INVALID | RBD_FLAG_FAST_DIFF_INVALID;
4957 ASSERT_EQ(0, image.get_flags(&flags));
4958 ASSERT_EQ(expected_flags, flags);
4959
4960 // cannot disable object map w/ fast diff
4961 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
4962 ASSERT_EQ(0, image.update_features(RBD_FEATURE_FAST_DIFF, false));
4963 ASSERT_EQ(0, image.features(&features));
4964 ASSERT_EQ(0U, features & RBD_FEATURE_FAST_DIFF);
4965
4966 expected_flags = RBD_FLAG_OBJECT_MAP_INVALID;
4967 ASSERT_EQ(0, image.get_flags(&flags));
4968 ASSERT_EQ(expected_flags, flags);
4969
4970 // cannot disable exclusive lock w/ object map
4971 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
4972 ASSERT_EQ(0, image.update_features(RBD_FEATURE_OBJECT_MAP, false));
4973
4974 // cannot disable exclusive lock w/ journaling
4975 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
4976 ASSERT_EQ(0, image.update_features(RBD_FEATURE_JOURNALING, false));
4977
4978 ASSERT_EQ(0, image.get_flags(&flags));
4979 ASSERT_EQ(0U, flags);
4980
4981 ASSERT_EQ(0, image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, false));
4982
4983 ASSERT_EQ(0, image.features(&features));
4984 if ((features & RBD_FEATURE_DEEP_FLATTEN) != 0) {
4985 ASSERT_EQ(0, image.update_features(RBD_FEATURE_DEEP_FLATTEN, false));
4986 }
4987 ASSERT_EQ(-EINVAL, image.update_features(RBD_FEATURE_DEEP_FLATTEN, true));
4988 }
4989
4990 TEST_F(TestLibRBD, RebuildObjectMap)
4991 {
4992 librados::IoCtx ioctx;
4993 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
4994
4995 librbd::RBD rbd;
4996 std::string name = get_temp_image_name();
4997 uint64_t size = 1 << 20;
4998 int order = 18;
4999 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5000
5001 PrintProgress prog_ctx;
5002 std::string object_map_oid;
5003 bufferlist bl;
5004 bl.append("foo");
5005 {
5006 librbd::Image image;
5007 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5008
5009 uint64_t features;
5010 ASSERT_EQ(0, image.features(&features));
5011 if ((features & RBD_FEATURE_OBJECT_MAP) == 0) {
5012 ASSERT_EQ(-EINVAL, image.rebuild_object_map(prog_ctx));
5013 return;
5014 }
5015
5016 ASSERT_EQ((ssize_t)bl.length(), image.write(0, bl.length(), bl));
5017
5018 ASSERT_EQ(0, image.snap_create("snap1"));
5019 ASSERT_EQ((ssize_t)bl.length(), image.write(1<<order, bl.length(), bl));
5020
5021 std::string image_id;
5022 ASSERT_EQ(0, get_image_id(image, &image_id));
5023 object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
5024 }
5025
5026 // corrupt the object map
5027 ASSERT_EQ(0, ioctx.write(object_map_oid, bl, bl.length(), 0));
5028
5029 librbd::Image image1;
5030 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5031
5032 bool lock_owner;
5033 bl.clear();
5034 ASSERT_EQ(0, image1.write(0, 0, bl));
5035 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5036 ASSERT_TRUE(lock_owner);
5037
5038 uint64_t flags;
5039 ASSERT_EQ(0, image1.get_flags(&flags));
5040 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
5041
5042 ASSERT_EQ(0, image1.rebuild_object_map(prog_ctx));
5043
5044 librbd::Image image2;
5045 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5046
5047 bufferlist read_bl;
5048 ASSERT_EQ((ssize_t)bl.length(), image2.read(0, bl.length(), read_bl));
5049 ASSERT_TRUE(bl.contents_equal(read_bl));
5050
5051 read_bl.clear();
5052 ASSERT_EQ((ssize_t)bl.length(), image2.read(1<<order, bl.length(), read_bl));
5053 ASSERT_TRUE(bl.contents_equal(read_bl));
5054
5055 ASSERT_PASSED(validate_object_map, image1);
5056 ASSERT_PASSED(validate_object_map, image2);
5057 }
5058
5059 TEST_F(TestLibRBD, RebuildNewObjectMap)
5060 {
5061 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
5062
5063 rados_ioctx_t ioctx;
5064 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5065
5066 std::string name = get_temp_image_name();
5067 uint64_t size = 1 << 20;
5068 int order = 18;
5069 uint64_t features = RBD_FEATURE_EXCLUSIVE_LOCK;
5070 ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order,
5071 false, features));
5072
5073 rbd_image_t image;
5074 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5075 ASSERT_EQ(0, rbd_update_features(image, RBD_FEATURE_OBJECT_MAP, true));
5076 ASSERT_EQ(0, rbd_rebuild_object_map(image, print_progress_percent, NULL));
5077
5078 ASSERT_PASSED(validate_object_map, image);
5079
5080 ASSERT_EQ(0, rbd_close(image));
5081 rados_ioctx_destroy(ioctx);
5082 }
5083
5084 TEST_F(TestLibRBD, CheckObjectMap)
5085 {
5086 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
5087
5088 librados::IoCtx ioctx;
5089 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5090
5091 librbd::RBD rbd;
5092 std::string name = get_temp_image_name();
5093 uint64_t size = 1 << 20;
5094 int order = 18;
5095 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5096
5097 PrintProgress prog_ctx;
5098 bufferlist bl1;
5099 bufferlist bl2;
5100 bl1.append("foo");
5101 {
5102 librbd::Image image;
5103 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5104
5105 uint64_t features;
5106 ASSERT_EQ(0, image.features(&features));
5107
5108 ASSERT_EQ((ssize_t)bl1.length(), image.write(0, bl1.length(), bl1));
5109
5110 ASSERT_EQ(0, image.snap_create("snap1"));
5111 ASSERT_EQ((ssize_t)bl1.length(), image.write(1<<order, bl1.length(), bl1));
5112 }
5113
5114 librbd::Image image1;
5115 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5116
5117 std::string image_id;
5118 ASSERT_EQ(0, get_image_id(image1, &image_id));
5119
5120 std::string object_map_oid = RBD_OBJECT_MAP_PREFIX + image_id;
5121
5122 ASSERT_LT(0, ioctx.read(object_map_oid, bl2, 1024, 0));
5123
5124 bool lock_owner;
5125 ASSERT_EQ((ssize_t)bl1.length(), image1.write(3 * (1 << 18), bl1.length(), bl1));
5126 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5127 ASSERT_TRUE(lock_owner);
5128
5129 //reopen image to reread now corrupt object map from disk
5130 image1.close();
5131
5132 bl1.clear();
5133 ASSERT_LT(0, ioctx.read(object_map_oid, bl1, 1024, 0));
5134 ASSERT_FALSE(bl1.contents_equal(bl2));
5135
5136 ASSERT_EQ(0, ioctx.write_full(object_map_oid, bl2));
5137 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5138
5139 uint64_t flags;
5140 ASSERT_EQ(0, image1.get_flags(&flags));
5141 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) == 0);
5142
5143 ASSERT_EQ(0, image1.check_object_map(prog_ctx));
5144
5145 ASSERT_EQ(0, image1.get_flags(&flags));
5146 ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
5147 }
5148
5149 TEST_F(TestLibRBD, BlockingAIO)
5150 {
5151 librados::IoCtx ioctx;
5152 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5153
5154 bool skip_discard = is_skip_partial_discard_enabled();
5155
5156 librbd::RBD rbd;
5157 std::string name = get_temp_image_name();
5158 uint64_t size = 1 << 20;
5159 int order = 18;
5160 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5161
5162 std::string non_blocking_aio;
5163 ASSERT_EQ(0, _rados.conf_get("rbd_non_blocking_aio", non_blocking_aio));
5164 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio", "0"));
5165 BOOST_SCOPE_EXIT( (non_blocking_aio) ) {
5166 ASSERT_EQ(0, _rados.conf_set("rbd_non_blocking_aio",
5167 non_blocking_aio.c_str()));
5168 } BOOST_SCOPE_EXIT_END;
5169
5170 librbd::Image image;
5171 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5172
5173 bufferlist bl;
5174 ASSERT_EQ(0, image.write(0, bl.length(), bl));
5175
5176 bl.append(std::string(256, '1'));
5177 librbd::RBD::AioCompletion *write_comp =
5178 new librbd::RBD::AioCompletion(NULL, NULL);
5179 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
5180
5181 librbd::RBD::AioCompletion *flush_comp =
5182 new librbd::RBD::AioCompletion(NULL, NULL);
5183 ASSERT_EQ(0, image.aio_flush(flush_comp));
5184 ASSERT_EQ(0, flush_comp->wait_for_complete());
5185 ASSERT_EQ(0, flush_comp->get_return_value());
5186 flush_comp->release();
5187
5188 ASSERT_EQ(1, write_comp->is_complete());
5189 ASSERT_EQ(0, write_comp->get_return_value());
5190 write_comp->release();
5191
5192 librbd::RBD::AioCompletion *discard_comp =
5193 new librbd::RBD::AioCompletion(NULL, NULL);
5194 ASSERT_EQ(0, image.aio_discard(128, 128, discard_comp));
5195 ASSERT_EQ(0, discard_comp->wait_for_complete());
5196 discard_comp->release();
5197
5198 librbd::RBD::AioCompletion *read_comp =
5199 new librbd::RBD::AioCompletion(NULL, NULL);
5200 bufferlist read_bl;
5201 image.aio_read(0, bl.length(), read_bl, read_comp);
5202 ASSERT_EQ(0, read_comp->wait_for_complete());
5203 ASSERT_EQ((ssize_t)bl.length(), read_comp->get_return_value());
5204 read_comp->release();
5205
5206 bufferlist expected_bl;
5207 expected_bl.append(std::string(128, '1'));
5208 expected_bl.append(std::string(128, skip_discard ? '1' : '\0'));
5209 ASSERT_TRUE(expected_bl.contents_equal(read_bl));
5210 }
5211
5212 TEST_F(TestLibRBD, ExclusiveLockTransition)
5213 {
5214 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5215
5216 librados::IoCtx ioctx;
5217 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5218
5219 librbd::RBD rbd;
5220 std::string name = get_temp_image_name();
5221
5222 uint64_t size = 1 << 18;
5223 int order = 12;
5224 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5225
5226 librbd::Image image1;
5227 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5228
5229 librbd::Image image2;
5230 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5231
5232 std::list<librbd::RBD::AioCompletion *> comps;
5233 ceph::bufferlist bl;
5234 bl.append(std::string(1 << order, '1'));
5235 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5236 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
5237 NULL);
5238 comps.push_back(comp);
5239 if (object_no % 2 == 0) {
5240 ASSERT_EQ(0, image1.aio_write(object_no << order, bl.length(), bl, comp));
5241 } else {
5242 ASSERT_EQ(0, image2.aio_write(object_no << order, bl.length(), bl, comp));
5243 }
5244 }
5245
5246 while (!comps.empty()) {
5247 librbd::RBD::AioCompletion *comp = comps.front();
5248 comps.pop_front();
5249 ASSERT_EQ(0, comp->wait_for_complete());
5250 ASSERT_EQ(1, comp->is_complete());
5251 comp->release();
5252 }
5253
5254 librbd::Image image3;
5255 ASSERT_EQ(0, rbd.open(ioctx, image3, name.c_str(), NULL));
5256 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5257 bufferlist read_bl;
5258 ASSERT_EQ((ssize_t)bl.length(), image3.read(object_no << order, bl.length(),
5259 read_bl));
5260 ASSERT_TRUE(bl.contents_equal(read_bl));
5261 }
5262
5263 ASSERT_PASSED(validate_object_map, image1);
5264 ASSERT_PASSED(validate_object_map, image2);
5265 ASSERT_PASSED(validate_object_map, image3);
5266 }
5267
5268 TEST_F(TestLibRBD, ExclusiveLockReadTransition)
5269 {
5270 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
5271
5272 librados::IoCtx ioctx;
5273 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5274
5275 librbd::RBD rbd;
5276 std::string name = get_temp_image_name();
5277
5278 uint64_t size = 1 << 18;
5279 int order = 12;
5280 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5281
5282 librbd::Image image1;
5283 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5284
5285 bool lock_owner;
5286 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5287 ASSERT_FALSE(lock_owner);
5288
5289 // journaling should force read ops to acquire the lock
5290 bufferlist read_bl;
5291 ASSERT_EQ(0, image1.read(0, 0, read_bl));
5292
5293 ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
5294 ASSERT_TRUE(lock_owner);
5295
5296 librbd::Image image2;
5297 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5298
5299 std::list<librbd::RBD::AioCompletion *> comps;
5300 std::list<bufferlist> read_bls;
5301 for (size_t object_no = 0; object_no < (size >> 12); ++object_no) {
5302 librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL,
5303 NULL);
5304 comps.push_back(comp);
5305 read_bls.emplace_back();
5306 if (object_no % 2 == 0) {
5307 ASSERT_EQ(0, image1.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
5308 } else {
5309 ASSERT_EQ(0, image2.aio_read(object_no << order, 1 << order, read_bls.back(), comp));
5310 }
5311 }
5312
5313 while (!comps.empty()) {
5314 librbd::RBD::AioCompletion *comp = comps.front();
5315 comps.pop_front();
5316 ASSERT_EQ(0, comp->wait_for_complete());
5317 ASSERT_EQ(1, comp->is_complete());
5318 comp->release();
5319 }
5320 }
5321
5322 TEST_F(TestLibRBD, CacheMayCopyOnWrite) {
5323 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5324
5325 librados::IoCtx ioctx;
5326 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5327
5328 librbd::RBD rbd;
5329 std::string name = get_temp_image_name();
5330
5331 uint64_t size = 1 << 18;
5332 int order = 12;
5333 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5334
5335 librbd::Image image;
5336 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5337 ASSERT_EQ(0, image.snap_create("one"));
5338 ASSERT_EQ(0, image.snap_protect("one"));
5339
5340 std::string clone_name = this->get_temp_image_name();
5341 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
5342 RBD_FEATURE_LAYERING, &order));
5343
5344 librbd::Image clone;
5345 ASSERT_EQ(0, rbd.open(ioctx, clone, clone_name.c_str(), NULL));
5346 ASSERT_EQ(0, clone.flush());
5347
5348 bufferlist expect_bl;
5349 expect_bl.append(std::string(1024, '\0'));
5350
5351 // test double read path
5352 bufferlist read_bl;
5353 uint64_t offset = 0;
5354 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
5355 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
5356
5357 bufferlist write_bl;
5358 write_bl.append(std::string(1024, '1'));
5359 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
5360
5361 read_bl.clear();
5362 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
5363 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
5364
5365 // test read retry path
5366 offset = 1 << order;
5367 ASSERT_EQ(1024, clone.write(offset, write_bl.length(), write_bl));
5368
5369 read_bl.clear();
5370 ASSERT_EQ(1024, clone.read(offset + 2048, 1024, read_bl));
5371 ASSERT_TRUE(expect_bl.contents_equal(read_bl));
5372 }
5373
5374 TEST_F(TestLibRBD, FlushEmptyOpsOnExternalSnapshot) {
5375 std::string cache_enabled;
5376 ASSERT_EQ(0, _rados.conf_get("rbd_cache", cache_enabled));
5377 ASSERT_EQ(0, _rados.conf_set("rbd_cache", "false"));
5378 BOOST_SCOPE_EXIT( (cache_enabled) ) {
5379 ASSERT_EQ(0, _rados.conf_set("rbd_cache", cache_enabled.c_str()));
5380 } BOOST_SCOPE_EXIT_END;
5381
5382 librados::IoCtx ioctx;
5383 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5384
5385 librbd::RBD rbd;
5386 std::string name = get_temp_image_name();
5387 uint64_t size = 1 << 18;
5388 int order = 0;
5389 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5390
5391 librbd::Image image1;
5392 librbd::Image image2;
5393 ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
5394 ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
5395 ASSERT_EQ(0, image1.snap_create("snap1"));
5396
5397 librbd::RBD::AioCompletion *read_comp =
5398 new librbd::RBD::AioCompletion(NULL, NULL);
5399 bufferlist read_bl;
5400 image2.aio_read(0, 1024, read_bl, read_comp);
5401 ASSERT_EQ(0, read_comp->wait_for_complete());
5402 read_comp->release();
5403 }
5404
5405 TEST_F(TestLibRBD, TestImageOptions)
5406 {
5407 rados_ioctx_t ioctx;
5408 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5409
5410 //make create image options
5411 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
5412 uint64_t order = 0;
5413 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
5414 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
5415 rbd_image_options_t opts;
5416 rbd_image_options_create(&opts);
5417
5418 bool is_set;
5419 ASSERT_EQ(-EINVAL, rbd_image_options_is_set(opts, 12345, &is_set));
5420 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
5421 &is_set));
5422 ASSERT_FALSE(is_set);
5423
5424 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
5425 2));
5426 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
5427 features));
5428 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
5429 order));
5430 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
5431 stripe_unit));
5432 ASSERT_EQ(0, rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
5433 stripe_count));
5434
5435 ASSERT_EQ(0, rbd_image_options_is_set(opts, RBD_IMAGE_OPTION_FORMAT,
5436 &is_set));
5437 ASSERT_TRUE(is_set);
5438
5439 std::string parent_name = get_temp_image_name();
5440
5441 // make parent
5442 ASSERT_EQ(0, rbd_create4(ioctx, parent_name.c_str(), 4<<20, opts));
5443
5444 // check order is returned in opts
5445 ASSERT_EQ(0, rbd_image_options_get_uint64(opts, RBD_IMAGE_OPTION_ORDER,
5446 &order));
5447 ASSERT_NE((uint64_t)0, order);
5448
5449 // write some data to parent
5450 rbd_image_t parent;
5451 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, NULL));
5452 char *data = (char *)"testdata";
5453 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data));
5454 ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data));
5455
5456 // create a snapshot, reopen as the parent we're interested in
5457 ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
5458 ASSERT_EQ(0, rbd_close(parent));
5459 ASSERT_EQ(0, rbd_open(ioctx, parent_name.c_str(), &parent, "parent_snap"));
5460
5461 // clone
5462 std::string child_name = get_temp_image_name();
5463 ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap"));
5464 ASSERT_EQ(0, rbd_clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
5465 child_name.c_str(), opts));
5466
5467 // copy
5468 std::string copy1_name = get_temp_image_name();
5469 ASSERT_EQ(0, rbd_copy3(parent, ioctx, copy1_name.c_str(), opts));
5470 std::string copy2_name = get_temp_image_name();
5471 ASSERT_EQ(0, rbd_copy_with_progress3(parent, ioctx, copy2_name.c_str(), opts,
5472 print_progress_percent, NULL));
5473
5474 ASSERT_EQ(0, rbd_close(parent));
5475
5476 rbd_image_options_destroy(opts);
5477
5478 rados_ioctx_destroy(ioctx);
5479 }
5480
5481 TEST_F(TestLibRBD, TestImageOptionsPP)
5482 {
5483 librados::IoCtx ioctx;
5484 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5485
5486 //make create image options
5487 uint64_t features = RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2 ;
5488 uint64_t order = 0;
5489 uint64_t stripe_unit = IMAGE_STRIPE_UNIT;
5490 uint64_t stripe_count = IMAGE_STRIPE_COUNT;
5491 librbd::ImageOptions opts;
5492 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2)));
5493 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_FEATURES, features));
5494 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_ORDER, order));
5495 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit));
5496 ASSERT_EQ(0, opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count));
5497
5498 librbd::RBD rbd;
5499 std::string parent_name = get_temp_image_name();
5500
5501 // make parent
5502 ASSERT_EQ(0, rbd.create4(ioctx, parent_name.c_str(), 4<<20, opts));
5503
5504 // check order is returned in opts
5505 ASSERT_EQ(0, opts.get(RBD_IMAGE_OPTION_ORDER, &order));
5506 ASSERT_NE((uint64_t)0, order);
5507
5508 // write some data to parent
5509 librbd::Image parent;
5510 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
5511
5512 ssize_t len = 1024;
5513 bufferlist bl;
5514 bl.append(buffer::create(len));
5515 bl.zero();
5516 ASSERT_EQ(len, parent.write(0, len, bl));
5517 ASSERT_EQ(len, parent.write(len, len, bl));
5518
5519 // create a snapshot, reopen as the parent we're interested in
5520 ASSERT_EQ(0, parent.snap_create("parent_snap"));
5521 ASSERT_EQ(0, parent.close());
5522 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
5523
5524 // clone
5525 std::string child_name = get_temp_image_name();
5526 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
5527 ASSERT_EQ(0, rbd.clone3(ioctx, parent_name.c_str(), "parent_snap", ioctx,
5528 child_name.c_str(), opts));
5529
5530 // copy
5531 std::string copy1_name = get_temp_image_name();
5532 ASSERT_EQ(0, parent.copy3(ioctx, copy1_name.c_str(), opts));
5533 std::string copy2_name = get_temp_image_name();
5534 PrintProgress pp;
5535 ASSERT_EQ(0, parent.copy_with_progress3(ioctx, copy2_name.c_str(), opts, pp));
5536
5537 ASSERT_EQ(0, parent.close());
5538 }
5539
5540 TEST_F(TestLibRBD, EventSocketPipe)
5541 {
5542 EventSocket event_sock;
5543 int pipe_fd[2]; // read and write fd
5544 char buf[32];
5545
5546 ASSERT_EQ(0, pipe(pipe_fd));
5547
5548 ASSERT_FALSE(event_sock.is_valid());
5549
5550 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_NONE));
5551 ASSERT_FALSE(event_sock.is_valid());
5552
5553 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], 44));
5554 ASSERT_FALSE(event_sock.is_valid());
5555
5556 #ifndef HAVE_EVENTFD
5557 ASSERT_EQ(-EINVAL, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_EVENTFD));
5558 ASSERT_FALSE(event_sock.is_valid());
5559 #endif
5560
5561 ASSERT_EQ(0, event_sock.init(pipe_fd[1], EVENT_SOCKET_TYPE_PIPE));
5562 ASSERT_TRUE(event_sock.is_valid());
5563 ASSERT_EQ(0, event_sock.notify());
5564 ASSERT_EQ(1, read(pipe_fd[0], buf, 32));
5565 ASSERT_EQ('i', buf[0]);
5566
5567 close(pipe_fd[0]);
5568 close(pipe_fd[1]);
5569 }
5570
5571 TEST_F(TestLibRBD, EventSocketEventfd)
5572 {
5573 #ifdef HAVE_EVENTFD
5574 EventSocket event_sock;
5575 int event_fd;
5576 struct pollfd poll_fd;
5577 char buf[32];
5578
5579 event_fd = eventfd(0, EFD_NONBLOCK);
5580 ASSERT_NE(-1, event_fd);
5581
5582 ASSERT_FALSE(event_sock.is_valid());
5583
5584 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, EVENT_SOCKET_TYPE_NONE));
5585 ASSERT_FALSE(event_sock.is_valid());
5586
5587 ASSERT_EQ(-EINVAL, event_sock.init(event_fd, 44));
5588 ASSERT_FALSE(event_sock.is_valid());
5589
5590 ASSERT_EQ(0, event_sock.init(event_fd, EVENT_SOCKET_TYPE_EVENTFD));
5591 ASSERT_TRUE(event_sock.is_valid());
5592 ASSERT_EQ(0, event_sock.notify());
5593
5594 poll_fd.fd = event_fd;
5595 poll_fd.events = POLLIN;
5596 ASSERT_EQ(1, poll(&poll_fd, 1, -1));
5597 ASSERT_TRUE(poll_fd.revents & POLLIN);
5598
5599 ASSERT_EQ(static_cast<ssize_t>(sizeof(uint64_t)), read(event_fd, buf, 32));
5600 ASSERT_EQ(1U, *reinterpret_cast<uint64_t *>(buf));
5601
5602 close(event_fd);
5603 #endif
5604 }
5605
5606 TEST_F(TestLibRBD, ImagePollIO)
5607 {
5608 #ifdef HAVE_EVENTFD
5609 rados_ioctx_t ioctx;
5610 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5611
5612 rbd_image_t image;
5613 int order = 0;
5614 std::string name = get_temp_image_name();
5615 uint64_t size = 2 << 20;
5616 int fd = eventfd(0, EFD_NONBLOCK);
5617
5618 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5619 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5620
5621 ASSERT_EQ(0, rbd_set_image_notification(image, fd, EVENT_SOCKET_TYPE_EVENTFD));
5622
5623 char test_data[TEST_IO_SIZE + 1];
5624 char zero_data[TEST_IO_SIZE + 1];
5625 int i;
5626
5627 for (i = 0; i < TEST_IO_SIZE; ++i)
5628 test_data[i] = (char) (rand() % (126 - 33) + 33);
5629 test_data[TEST_IO_SIZE] = '\0';
5630 memset(zero_data, 0, sizeof(zero_data));
5631
5632 for (i = 0; i < 5; ++i)
5633 ASSERT_PASSED(write_test_data, image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
5634
5635 for (i = 5; i < 10; ++i)
5636 ASSERT_PASSED(aio_write_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
5637
5638 for (i = 5; i < 10; ++i)
5639 ASSERT_PASSED(aio_read_test_data_and_poll, image, fd, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE, 0);
5640
5641 ASSERT_EQ(0, rbd_close(image));
5642 rados_ioctx_destroy(ioctx);
5643 #endif
5644 }
5645
5646 namespace librbd {
5647
5648 static bool operator==(const mirror_peer_t &lhs, const mirror_peer_t &rhs) {
5649 return (lhs.uuid == rhs.uuid &&
5650 lhs.cluster_name == rhs.cluster_name &&
5651 lhs.client_name == rhs.client_name);
5652 }
5653
5654 static std::ostream& operator<<(std::ostream &os, const mirror_peer_t &peer) {
5655 os << "uuid=" << peer.uuid << ", "
5656 << "cluster=" << peer.cluster_name << ", "
5657 << "client=" << peer.client_name;
5658 return os;
5659 }
5660
5661 } // namespace librbd
5662
5663 TEST_F(TestLibRBD, Mirror) {
5664 librados::IoCtx ioctx;
5665 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5666
5667 librbd::RBD rbd;
5668
5669 std::vector<librbd::mirror_peer_t> expected_peers;
5670 std::vector<librbd::mirror_peer_t> peers;
5671 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
5672 ASSERT_EQ(expected_peers, peers);
5673
5674 std::string uuid1;
5675 ASSERT_EQ(-EINVAL, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
5676
5677 rbd_mirror_mode_t mirror_mode;
5678 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
5679 ASSERT_EQ(RBD_MIRROR_MODE_DISABLED, mirror_mode);
5680
5681 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE));
5682 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
5683
5684 // Add some images to the pool
5685 int order = 0;
5686 std::string parent_name = get_temp_image_name();
5687 std::string child_name = get_temp_image_name();
5688 ASSERT_EQ(0, create_image_pp(rbd, ioctx, parent_name.c_str(), 2 << 20,
5689 &order));
5690 bool old_format;
5691 uint64_t features;
5692 ASSERT_EQ(0, get_features(&old_format, &features));
5693 if ((features & RBD_FEATURE_LAYERING) != 0) {
5694 librbd::Image parent;
5695 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), NULL));
5696 ASSERT_EQ(0, parent.snap_create("parent_snap"));
5697 ASSERT_EQ(0, parent.close());
5698 ASSERT_EQ(0, rbd.open(ioctx, parent, parent_name.c_str(), "parent_snap"));
5699 ASSERT_EQ(0, parent.snap_protect("parent_snap"));
5700 ASSERT_EQ(0, parent.close());
5701 ASSERT_EQ(0, rbd.clone(ioctx, parent_name.c_str(), "parent_snap", ioctx,
5702 child_name.c_str(), features, &order));
5703 }
5704
5705 ASSERT_EQ(RBD_MIRROR_MODE_IMAGE, mirror_mode);
5706
5707 ASSERT_EQ(0, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_POOL));
5708 ASSERT_EQ(0, rbd.mirror_mode_get(ioctx, &mirror_mode));
5709 ASSERT_EQ(RBD_MIRROR_MODE_POOL, mirror_mode);
5710
5711 std::string uuid2;
5712 std::string uuid3;
5713 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid1, "cluster1", "client"));
5714 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid2, "cluster2", "admin"));
5715 ASSERT_EQ(-EEXIST, rbd.mirror_peer_add(ioctx, &uuid3, "cluster1", "foo"));
5716 ASSERT_EQ(0, rbd.mirror_peer_add(ioctx, &uuid3, "cluster3", "admin"));
5717
5718 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
5719 auto sort_peers = [](const librbd::mirror_peer_t &lhs,
5720 const librbd::mirror_peer_t &rhs) {
5721 return lhs.uuid < rhs.uuid;
5722 };
5723 expected_peers = {
5724 {uuid1, "cluster1", "client"},
5725 {uuid2, "cluster2", "admin"},
5726 {uuid3, "cluster3", "admin"}};
5727 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
5728 ASSERT_EQ(expected_peers, peers);
5729
5730 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, "uuid4"));
5731 ASSERT_EQ(0, rbd.mirror_peer_remove(ioctx, uuid2));
5732
5733 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_client(ioctx, "uuid4", "new client"));
5734 ASSERT_EQ(0, rbd.mirror_peer_set_client(ioctx, uuid1, "new client"));
5735
5736 ASSERT_EQ(-ENOENT, rbd.mirror_peer_set_cluster(ioctx, "uuid4",
5737 "new cluster"));
5738 ASSERT_EQ(0, rbd.mirror_peer_set_cluster(ioctx, uuid3, "new cluster"));
5739
5740 ASSERT_EQ(0, rbd.mirror_peer_list(ioctx, &peers));
5741 expected_peers = {
5742 {uuid1, "cluster1", "new client"},
5743 {uuid3, "new cluster", "admin"}};
5744 std::sort(expected_peers.begin(), expected_peers.end(), sort_peers);
5745 ASSERT_EQ(expected_peers, peers);
5746
5747 ASSERT_EQ(-EBUSY, rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED));
5748 }
5749
5750 TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {
5751 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
5752
5753 librados::IoCtx ioctx;
5754 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5755
5756 librbd::RBD rbd;
5757 librbd::Image image;
5758 std::string name = get_temp_image_name();
5759
5760 uint64_t size = 1 << 18;
5761 int order = 0;
5762
5763 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
5764 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
5765
5766 bufferlist bl;
5767 bl.append(std::string(size, '1'));
5768 ASSERT_EQ((int)size, image.write(0, size, bl));
5769 ASSERT_EQ(0, image.snap_create("one"));
5770 ASSERT_EQ(0, image.snap_protect("one"));
5771
5772 std::string clone_name = this->get_temp_image_name();
5773 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "one", ioctx, clone_name.c_str(),
5774 RBD_FEATURE_LAYERING, &order));
5775 ASSERT_EQ(0, rbd.open(ioctx, image, clone_name.c_str(), NULL));
5776
5777 librbd::Image image2;
5778 ASSERT_EQ(0, rbd.open(ioctx, image2, clone_name.c_str(), NULL));
5779
5780 // prepare CoW writeback that will be flushed on next op
5781 bl.clear();
5782 bl.append(std::string(1, '1'));
5783 ASSERT_EQ(0, image.flush());
5784 ASSERT_EQ(1, image.write(0, 1, bl));
5785 ASSERT_EQ(0, image2.snap_create("snap1"));
5786
5787 librbd::RBD::AioCompletion *read_comp =
5788 new librbd::RBD::AioCompletion(NULL, NULL);
5789 bufferlist read_bl;
5790 image.aio_read(0, 1024, read_bl, read_comp);
5791 ASSERT_EQ(0, read_comp->wait_for_complete());
5792 read_comp->release();
5793 }
5794
5795 TEST_F(TestLibRBD, ExclusiveLock)
5796 {
5797 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5798
5799 static char buf[10];
5800
5801 rados_ioctx_t ioctx;
5802 rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
5803
5804 std::string name = get_temp_image_name();
5805 uint64_t size = 2 << 20;
5806 int order = 0;
5807 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5808
5809 rbd_image_t image1;
5810 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
5811
5812 int lock_owner;
5813 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
5814 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5815 ASSERT_TRUE(lock_owner);
5816
5817 rbd_lock_mode_t lock_mode;
5818 char *lock_owners[1];
5819 size_t max_lock_owners = 0;
5820 ASSERT_EQ(-ERANGE, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
5821 &max_lock_owners));
5822 ASSERT_EQ(1U, max_lock_owners);
5823
5824 max_lock_owners = 2;
5825 ASSERT_EQ(0, rbd_lock_get_owners(image1, &lock_mode, lock_owners,
5826 &max_lock_owners));
5827 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
5828 ASSERT_STRNE("", lock_owners[0]);
5829 ASSERT_EQ(1U, max_lock_owners);
5830
5831 rbd_image_t image2;
5832 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
5833
5834 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5835 ASSERT_FALSE(lock_owner);
5836
5837 ASSERT_EQ(-EOPNOTSUPP, rbd_lock_break(image1, RBD_LOCK_MODE_SHARED, ""));
5838 ASSERT_EQ(-EBUSY, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
5839 "not the owner"));
5840
5841 ASSERT_EQ(0, rbd_lock_release(image1));
5842 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5843 ASSERT_FALSE(lock_owner);
5844
5845 ASSERT_EQ(-ENOENT, rbd_lock_break(image1, RBD_LOCK_MODE_EXCLUSIVE,
5846 lock_owners[0]));
5847 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
5848
5849 ASSERT_EQ(-EROFS, rbd_write(image1, 0, sizeof(buf), buf));
5850 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image2, 0, sizeof(buf), buf));
5851
5852 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
5853 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5854 ASSERT_TRUE(lock_owner);
5855
5856 ASSERT_EQ(0, rbd_lock_release(image2));
5857 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5858 ASSERT_FALSE(lock_owner);
5859
5860 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
5861 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5862 ASSERT_TRUE(lock_owner);
5863
5864 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image1, 0, sizeof(buf), buf));
5865 ASSERT_EQ(-EROFS, rbd_write(image2, 0, sizeof(buf), buf));
5866
5867 ASSERT_EQ(0, rbd_lock_release(image1));
5868 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5869 ASSERT_FALSE(lock_owner);
5870
5871 int owner_id = -1;
5872 mutex lock;
5873 const auto pingpong = [&,this](int m_id, rbd_image_t &m_image) {
5874 for (int i = 0; i < 10; i++) {
5875 {
5876 lock_guard<mutex> locker(lock);
5877 if (owner_id == m_id) {
5878 std::cout << m_id << ": releasing exclusive lock" << std::endl;
5879 EXPECT_EQ(0, rbd_lock_release(m_image));
5880 int lock_owner;
5881 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
5882 EXPECT_FALSE(lock_owner);
5883 owner_id = -1;
5884 std::cout << m_id << ": exclusive lock released" << std::endl;
5885 continue;
5886 }
5887 }
5888
5889 std::cout << m_id << ": acquiring exclusive lock" << std::endl;
5890 int r;
5891 do {
5892 r = rbd_lock_acquire(m_image, RBD_LOCK_MODE_EXCLUSIVE);
5893 if (r == -EROFS) {
5894 usleep(1000);
5895 }
5896 } while (r == -EROFS);
5897 EXPECT_EQ(0, r);
5898
5899 int lock_owner;
5900 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
5901 EXPECT_TRUE(lock_owner);
5902 std::cout << m_id << ": exclusive lock acquired" << std::endl;
5903 {
5904 lock_guard<mutex> locker(lock);
5905 owner_id = m_id;
5906 }
5907 usleep(rand() % 50000);
5908 }
5909
5910 lock_guard<mutex> locker(lock);
5911 if (owner_id == m_id) {
5912 EXPECT_EQ(0, rbd_lock_release(m_image));
5913 int lock_owner;
5914 EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
5915 EXPECT_FALSE(lock_owner);
5916 owner_id = -1;
5917 }
5918 };
5919 thread ping(bind(pingpong, 1, ref(image1)));
5920 thread pong(bind(pingpong, 2, ref(image2)));
5921
5922 ping.join();
5923 pong.join();
5924
5925 ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
5926 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
5927 ASSERT_TRUE(lock_owner);
5928
5929 ASSERT_EQ(0, rbd_close(image2));
5930
5931 ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
5932 ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
5933 ASSERT_TRUE(lock_owner);
5934
5935 ASSERT_EQ(0, rbd_close(image1));
5936 rados_ioctx_destroy(ioctx);
5937 }
5938
5939 TEST_F(TestLibRBD, BreakLock)
5940 {
5941 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
5942
5943 static char buf[10];
5944
5945 rados_t blacklist_cluster;
5946 ASSERT_EQ("", connect_cluster(&blacklist_cluster));
5947
5948 rados_ioctx_t ioctx, blacklist_ioctx;
5949 ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
5950 ASSERT_EQ(0, rados_ioctx_create(blacklist_cluster, m_pool_name.c_str(),
5951 &blacklist_ioctx));
5952
5953 std::string name = get_temp_image_name();
5954 uint64_t size = 2 << 20;
5955 int order = 0;
5956 ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
5957
5958 rbd_image_t image, blacklist_image;
5959 ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
5960 ASSERT_EQ(0, rbd_open(blacklist_ioctx, name.c_str(), &blacklist_image, NULL));
5961
5962 ASSERT_EQ(0, rbd_metadata_set(image, "rbd_blacklist_on_break_lock", "true"));
5963 ASSERT_EQ(0, rbd_lock_acquire(blacklist_image, RBD_LOCK_MODE_EXCLUSIVE));
5964
5965 rbd_lock_mode_t lock_mode;
5966 char *lock_owners[1];
5967 size_t max_lock_owners = 1;
5968 ASSERT_EQ(0, rbd_lock_get_owners(image, &lock_mode, lock_owners,
5969 &max_lock_owners));
5970 ASSERT_EQ(RBD_LOCK_MODE_EXCLUSIVE, lock_mode);
5971 ASSERT_STRNE("", lock_owners[0]);
5972 ASSERT_EQ(1U, max_lock_owners);
5973
5974 ASSERT_EQ(0, rbd_lock_break(image, RBD_LOCK_MODE_EXCLUSIVE, lock_owners[0]));
5975 ASSERT_EQ(0, rbd_lock_acquire(image, RBD_LOCK_MODE_EXCLUSIVE));
5976 EXPECT_EQ(0, rados_wait_for_latest_osdmap(blacklist_cluster));
5977
5978 ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image, 0, sizeof(buf), buf));
5979 ASSERT_EQ(-EBLACKLISTED, rbd_write(blacklist_image, 0, sizeof(buf), buf));
5980
5981 ASSERT_EQ(0, rbd_close(image));
5982 ASSERT_EQ(0, rbd_close(blacklist_image));
5983
5984 rbd_lock_get_owners_cleanup(lock_owners, max_lock_owners);
5985
5986 rados_ioctx_destroy(ioctx);
5987 rados_ioctx_destroy(blacklist_ioctx);
5988 rados_shutdown(blacklist_cluster);
5989 }
5990
5991 TEST_F(TestLibRBD, DiscardAfterWrite)
5992 {
5993 REQUIRE(!is_skip_partial_discard_enabled());
5994
5995 librados::IoCtx ioctx;
5996 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
5997
5998 librbd::RBD rbd;
5999 std::string name = get_temp_image_name();
6000 uint64_t size = 1 << 20;
6001 int order = 18;
6002 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6003
6004 librbd::Image image;
6005 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
6006
6007 // enable writeback cache
6008 ASSERT_EQ(0, image.flush());
6009
6010 bufferlist bl;
6011 bl.append(std::string(256, '1'));
6012
6013 librbd::RBD::AioCompletion *write_comp =
6014 new librbd::RBD::AioCompletion(NULL, NULL);
6015 ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp));
6016 ASSERT_EQ(0, write_comp->wait_for_complete());
6017 write_comp->release();
6018
6019 librbd::RBD::AioCompletion *discard_comp =
6020 new librbd::RBD::AioCompletion(NULL, NULL);
6021 ASSERT_EQ(0, image.aio_discard(0, 256, discard_comp));
6022 ASSERT_EQ(0, discard_comp->wait_for_complete());
6023 discard_comp->release();
6024
6025 librbd::RBD::AioCompletion *read_comp =
6026 new librbd::RBD::AioCompletion(NULL, NULL);
6027 bufferlist read_bl;
6028 image.aio_read(0, bl.length(), read_bl, read_comp);
6029 ASSERT_EQ(0, read_comp->wait_for_complete());
6030 ASSERT_EQ(bl.length(), read_comp->get_return_value());
6031 ASSERT_TRUE(read_bl.is_zero());
6032 read_comp->release();
6033 }
6034
6035 TEST_F(TestLibRBD, DefaultFeatures) {
6036 std::string orig_default_features;
6037 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", orig_default_features));
6038 BOOST_SCOPE_EXIT_ALL(orig_default_features) {
6039 ASSERT_EQ(0, _rados.conf_set("rbd_default_features",
6040 orig_default_features.c_str()));
6041 };
6042
6043 std::list<std::pair<std::string, std::string> > feature_names_to_bitmask = {
6044 {"", orig_default_features},
6045 {"layering", "1"},
6046 {"layering, exclusive-lock", "5"},
6047 {"exclusive-lock,journaling", "68"},
6048 {"125", "125"}
6049 };
6050
6051 for (auto &pair : feature_names_to_bitmask) {
6052 ASSERT_EQ(0, _rados.conf_set("rbd_default_features", pair.first.c_str()));
6053 std::string features;
6054 ASSERT_EQ(0, _rados.conf_get("rbd_default_features", features));
6055 ASSERT_EQ(pair.second, features);
6056 }
6057 }
6058
6059 TEST_F(TestLibRBD, TestTrashMoveAndPurge) {
6060 librados::IoCtx ioctx;
6061 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6062
6063 librbd::RBD rbd;
6064 std::string name = get_temp_image_name();
6065
6066 uint64_t size = 1 << 18;
6067 int order = 12;
6068 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6069
6070 librbd::Image image;
6071 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
6072 uint8_t old_format;
6073 ASSERT_EQ(0, image.old_format(&old_format));
6074
6075 if (old_format) {
6076 ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
6077 image.close();
6078 return;
6079 }
6080 std::string image_id;
6081 ASSERT_EQ(0, image.get_id(&image_id));
6082 image.close();
6083
6084 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 0));
6085
6086 std::vector<std::string> images;
6087 ASSERT_EQ(0, rbd.list(ioctx, images));
6088 for (const auto& image : images) {
6089 ASSERT_TRUE(image != name);
6090 }
6091
6092 librbd::trash_image_info_t info;
6093 ASSERT_EQ(-ENOENT, rbd.trash_get(ioctx, "dummy image id", &info));
6094 ASSERT_EQ(0, rbd.trash_get(ioctx, image_id.c_str(), &info));
6095 ASSERT_EQ(image_id, info.id);
6096
6097 std::vector<librbd::trash_image_info_t> entries;
6098 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6099 ASSERT_FALSE(entries.empty());
6100 ASSERT_EQ(entries.begin()->id, image_id);
6101
6102 entries.clear();
6103 PrintProgress pp;
6104 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
6105 false, pp));
6106 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6107 ASSERT_TRUE(entries.empty());
6108 }
6109
6110 TEST_F(TestLibRBD, TestTrashMoveAndPurgeNonExpiredDelay) {
6111 librados::IoCtx ioctx;
6112 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6113
6114 librbd::RBD rbd;
6115 std::string name = get_temp_image_name();
6116
6117 uint64_t size = 1 << 18;
6118 int order = 12;
6119 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6120
6121 librbd::Image image;
6122 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
6123 uint8_t old_format;
6124 ASSERT_EQ(0, image.old_format(&old_format));
6125
6126 if (old_format) {
6127 ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
6128 image.close();
6129 return;
6130 }
6131 std::string image_id;
6132 ASSERT_EQ(0, image.get_id(&image_id));
6133 image.close();
6134
6135 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 100));
6136
6137 PrintProgress pp;
6138 ASSERT_EQ(-EPERM, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
6139 false, pp));
6140
6141 PrintProgress pp2;
6142 ASSERT_EQ(0, rbd.trash_remove_with_progress(ioctx, image_id.c_str(),
6143 true, pp2));
6144 }
6145
6146 TEST_F(TestLibRBD, TestTrashMoveAndRestore) {
6147 librados::IoCtx ioctx;
6148 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6149
6150 librbd::RBD rbd;
6151 std::string name = get_temp_image_name();
6152
6153 uint64_t size = 1 << 18;
6154 int order = 12;
6155 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6156
6157 librbd::Image image;
6158 ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
6159 uint8_t old_format;
6160 ASSERT_EQ(0, image.old_format(&old_format));
6161
6162 if (old_format) {
6163 ASSERT_EQ(-EOPNOTSUPP, rbd.trash_move(ioctx, name.c_str(), 0));
6164 image.close();
6165 return;
6166 }
6167 std::string image_id;
6168 ASSERT_EQ(0, image.get_id(&image_id));
6169 image.close();
6170
6171 ASSERT_EQ(0, rbd.trash_move(ioctx, name.c_str(), 10));
6172
6173 std::vector<std::string> images;
6174 ASSERT_EQ(0, rbd.list(ioctx, images));
6175 for (const auto& image : images) {
6176 ASSERT_TRUE(image != name);
6177 }
6178
6179 std::vector<librbd::trash_image_info_t> entries;
6180 ASSERT_EQ(0, rbd.trash_list(ioctx, entries));
6181 ASSERT_FALSE(entries.empty());
6182 ASSERT_EQ(entries.begin()->id, image_id);
6183
6184 images.clear();
6185 ASSERT_EQ(0, rbd.trash_restore(ioctx, image_id.c_str(), ""));
6186 ASSERT_EQ(0, rbd.list(ioctx, images));
6187 ASSERT_FALSE(images.empty());
6188 bool found = false;
6189 for (const auto& image : images) {
6190 if (image == name) {
6191 found = true;
6192 break;
6193 }
6194 }
6195 ASSERT_TRUE(found);
6196 }
6197
6198 TEST_F(TestLibRBD, ZeroOverlapFlatten) {
6199 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
6200
6201 librados::IoCtx ioctx;
6202 ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
6203
6204 librbd::RBD rbd;
6205 librbd::Image parent_image;
6206 std::string name = get_temp_image_name();
6207
6208 uint64_t size = 1;
6209 int order = 0;
6210
6211 ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
6212 ASSERT_EQ(0, rbd.open(ioctx, parent_image, name.c_str(), NULL));
6213
6214 uint64_t features;
6215 ASSERT_EQ(0, parent_image.features(&features));
6216
6217 ASSERT_EQ(0, parent_image.snap_create("snap"));
6218 ASSERT_EQ(0, parent_image.snap_protect("snap"));
6219
6220 std::string clone_name = this->get_temp_image_name();
6221 ASSERT_EQ(0, rbd.clone(ioctx, name.c_str(), "snap", ioctx, clone_name.c_str(),
6222 features, &order));
6223
6224 librbd::Image clone_image;
6225 ASSERT_EQ(0, rbd.open(ioctx, clone_image, clone_name.c_str(), NULL));
6226 ASSERT_EQ(0, clone_image.resize(0));
6227 ASSERT_EQ(0, clone_image.flatten());
6228 }
6229
6230 // poorman's assert()
6231 namespace ceph {
6232 void __ceph_assert_fail(const char *assertion, const char *file, int line,
6233 const char *func) {
6234 assert(false);
6235 }
6236 }