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