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